summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--LAST_ENTERPRISE_SYNC1
-rw-r--r--Makefile.am.in2
-rw-r--r--NewsLog.txt2147
-rw-r--r--akregator/src/akregator.desktop8
-rw-r--r--akregator/src/akregator_plugin.desktop4
-rw-r--r--akregator/src/akregator_view.cpp50
-rw-r--r--akregator/src/eventsrc13
-rw-r--r--akregator/src/mk4storage/akregator_mk4storage_plugin.desktop5
-rw-r--r--certmanager/certmanager.cpp9
-rw-r--r--certmanager/conf/kleopatra_config_appear.desktop6
-rw-r--r--certmanager/conf/kleopatra_config_dirserv.desktop11
-rw-r--r--certmanager/conf/kleopatra_config_dnorder.desktop3
-rw-r--r--certmanager/lib/backends/qgpgme/qgpgmecryptoconfig.cpp16
-rw-r--r--certmanager/lib/backends/qgpgme/qgpgmedecryptjob.cpp5
-rw-r--r--certmanager/lib/backends/qgpgme/qgpgmedecryptverifyjob.cpp8
-rw-r--r--certmanager/lib/backends/qgpgme/qgpgmedeletejob.cpp1
-rw-r--r--certmanager/lib/backends/qgpgme/qgpgmedownloadjob.cpp4
-rw-r--r--certmanager/lib/backends/qgpgme/qgpgmeencryptjob.cpp5
-rw-r--r--certmanager/lib/backends/qgpgme/qgpgmeexportjob.cpp4
-rw-r--r--certmanager/lib/backends/qgpgme/qgpgmeimportjob.cpp8
-rw-r--r--certmanager/lib/backends/qgpgme/qgpgmejob.cpp16
-rw-r--r--certmanager/lib/backends/qgpgme/qgpgmejob.h7
-rw-r--r--certmanager/lib/backends/qgpgme/qgpgmekeygenerationjob.cpp5
-rw-r--r--certmanager/lib/backends/qgpgme/qgpgmekeylistjob.cpp16
-rw-r--r--certmanager/lib/backends/qgpgme/qgpgmekeylistjob.h1
-rw-r--r--certmanager/lib/backends/qgpgme/qgpgmesignencryptjob.cpp4
-rw-r--r--certmanager/lib/backends/qgpgme/qgpgmesignjob.cpp5
-rw-r--r--certmanager/lib/backends/qgpgme/qgpgmeverifydetachedjob.cpp4
-rw-r--r--certmanager/lib/backends/qgpgme/qgpgmeverifyopaquejob.cpp5
-rw-r--r--certmanager/lib/kleo/job.cpp14
-rw-r--r--certmanager/lib/kleo/job.h6
-rw-r--r--certmanager/lib/libkleopatrarc.desktop9
-rw-r--r--certmanager/lib/tests/test_verify.cpp1
-rw-r--r--certmanager/lib/ui/cryptoconfigdialog.cpp6
-rw-r--r--certmanager/lib/ui/cryptoconfigmodule.cpp30
-rw-r--r--certmanager/lib/ui/cryptoconfigmodule.h2
-rw-r--r--certmanager/lib/ui/keyselectiondialog.cpp57
-rw-r--r--certmanager/lib/ui/keyselectiondialog.h15
-rw-r--r--certmanager/lib/ui/messagebox.cpp69
-rw-r--r--certmanager/lib/ui/messagebox.h3
-rw-r--r--cvs.sh.diff13
-rw-r--r--doc/kleopatra/index.docbook6
-rw-r--r--doc/kmail/configure.docbook205
-rw-r--r--doc/kmail/index.docbook2
-rw-r--r--doc/kmail/using-chiasmus.docbook158
-rw-r--r--doc/kmail/using-kmail.docbook23
-rw-r--r--doc/kontact/index.docbook85
-rw-r--r--doc/korganizer/index.docbook167
-rw-r--r--kabc/kabcdistlistupdater/kabcdistlistupdater.desktop10
-rw-r--r--kaddressbook/addresseeeditorextension.cpp12
-rw-r--r--kaddressbook/addresseeeditorextension.h4
-rw-r--r--kaddressbook/addresseeutil.cpp16
-rw-r--r--kaddressbook/addresseeutil.h11
-rw-r--r--kaddressbook/common/kaddressbook.kcfg2
-rw-r--r--kaddressbook/csv-templates/kaddressbook.desktop1
-rw-r--r--kaddressbook/csv-templates/yahoo.desktop4
-rw-r--r--kaddressbook/customfieldswidget.cpp28
-rw-r--r--kaddressbook/dcopaddressbook.desktop4
-rw-r--r--kaddressbook/distributionlisteditor.cpp49
-rw-r--r--kaddressbook/editors/cryptosettings.desktop1
-rw-r--r--kaddressbook/editors/imaddresseditor.desktop5
-rw-r--r--kaddressbook/editors/imeditorwidget.cpp2
-rw-r--r--kaddressbook/editors/kaddressbookimprotocol.desktop1
-rw-r--r--kaddressbook/editors/protocols/aimprotocol.desktop1
-rw-r--r--kaddressbook/editors/protocols/gaduprotocol.desktop1
-rw-r--r--kaddressbook/editors/protocols/groupwiseprotocol.desktop1
-rw-r--r--kaddressbook/editors/protocols/icqprotocol.desktop1
-rw-r--r--kaddressbook/editors/protocols/ircprotocol.desktop1
-rw-r--r--kaddressbook/editors/protocols/jabberprotocol.desktop1
-rw-r--r--kaddressbook/editors/protocols/meanwhileprotocol.desktop1
-rw-r--r--kaddressbook/editors/protocols/msnprotocol.desktop2
-rw-r--r--kaddressbook/editors/protocols/skypeprotocol.desktop1
-rw-r--r--kaddressbook/editors/protocols/smsprotocol.desktop1
-rw-r--r--kaddressbook/editors/protocols/yahooprotocol.desktop1
-rw-r--r--kaddressbook/features/distributionlist.desktop8
-rw-r--r--kaddressbook/features/distributionlistng.desktop10
-rw-r--r--kaddressbook/features/distributionlistngwidget.cpp10
-rw-r--r--kaddressbook/features/resourceselection.cpp3
-rw-r--r--kaddressbook/features/resourceselection.desktop2
-rw-r--r--kaddressbook/freebusywidget.cpp5
-rw-r--r--kaddressbook/imagewidget.cpp2
-rw-r--r--kaddressbook/interfaces/kaddressbook_contacteditorwidget.desktop1
-rw-r--r--kaddressbook/interfaces/kaddressbook_extension.desktop1
-rw-r--r--kaddressbook/interfaces/kaddressbook_xxport.desktop4
-rw-r--r--kaddressbook/kabcore.cpp173
-rw-r--r--kaddressbook/kabcore.h13
-rw-r--r--kaddressbook/kabtools.cpp7
-rw-r--r--kaddressbook/kaddressbook.desktop1
-rw-r--r--kaddressbook/kaddressbook_view.desktop1
-rw-r--r--kaddressbook/kcmconfigs/kabconfig.desktop12
-rw-r--r--kaddressbook/kcmconfigs/kabcustomfields.desktop3
-rw-r--r--kaddressbook/kcmconfigs/kabldapconfig.desktop9
-rw-r--r--kaddressbook/ldapsearchdialog.cpp18
-rw-r--r--kaddressbook/searchmanager.cpp1
-rw-r--r--kaddressbook/thumbnailcreator/ldifvcardcreator.cpp10
-rw-r--r--kaddressbook/thumbnailcreator/ldifvcardcreator.h1
-rw-r--r--kaddressbook/thumbnailcreator/ldifvcardthumbnail.desktop1
-rw-r--r--kaddressbook/undocmds.cpp182
-rw-r--r--kaddressbook/undocmds.h43
-rw-r--r--kaddressbook/viewmanager.cpp15
-rw-r--r--kaddressbook/views/cardview.desktop1
-rw-r--r--kaddressbook/views/iconview.desktop4
-rw-r--r--kaddressbook/views/tableview.desktop4
-rw-r--r--kaddressbook/xxport/bookmark_xxport.desktop2
-rw-r--r--kaddressbook/xxport/csv_xxport.cpp5
-rw-r--r--kaddressbook/xxport/csv_xxport.desktop2
-rw-r--r--kaddressbook/xxport/csvimportdialog.cpp4
-rw-r--r--kaddressbook/xxport/eudora_xxport.desktop2
-rw-r--r--kaddressbook/xxport/gnokii_xxport.desktop2
-rw-r--r--kaddressbook/xxport/kde2_xxport.cpp5
-rw-r--r--kaddressbook/xxport/kde2_xxport.desktop5
-rw-r--r--kaddressbook/xxport/ldif_xxport.cpp6
-rw-r--r--kaddressbook/xxport/ldif_xxport.desktop2
-rw-r--r--kaddressbook/xxport/opera_xxport.desktop2
-rw-r--r--kaddressbook/xxport/pab_xxport.desktop2
-rw-r--r--kaddressbook/xxport/vcard_xxport.cpp79
-rw-r--r--kaddressbook/xxport/vcard_xxport.desktop2
-rw-r--r--kaddressbook/xxport/vcard_xxport.h10
-rw-r--r--kaddressbook/xxportmanager.cpp2
-rw-r--r--kalarm/Changelog3
-rw-r--r--kalarm/alarmevent.cpp8
-rw-r--r--kalarm/functions.cpp14
-rw-r--r--kalarm/functions.h1
-rw-r--r--kalarm/kalarm.desktop1
-rw-r--r--kalarm/kalarm.tray.desktop3
-rw-r--r--kalarm/kalarmapp.cpp2
-rw-r--r--kalarm/kalarmd/kalarmd.autostart.desktop2
-rw-r--r--kalarm/kalarmd/kalarmd.desktop1
-rw-r--r--kandy/src/kandy.desktop5
-rw-r--r--karm/support/karm.desktop1
-rw-r--r--karm/task.cpp8
-rw-r--r--kfile-plugins/ics/kfile_ics.desktop1
-rw-r--r--kfile-plugins/palm-databases/kfile_palm.desktop1
-rw-r--r--kfile-plugins/rfc822/kfile_rfc822.desktop1
-rw-r--r--kfile-plugins/vcf/kfile_vcf.cpp7
-rw-r--r--kfile-plugins/vcf/kfile_vcf.desktop1
-rw-r--r--kioslaves/imap4/imap4.cc21
-rw-r--r--kioslaves/sieve/sieve.cpp58
-rw-r--r--kioslaves/sieve/sieve.h1
-rw-r--r--kioslaves/sieve/sieve.protocol3
-rw-r--r--kitchensync/src/kitchensync.desktop1
-rw-r--r--kmail/KMail.desktop4
-rw-r--r--kmail/Makefile.am23
-rw-r--r--kmail/accountdialog.cpp2
-rw-r--r--kmail/accountwizard.cpp4
-rw-r--r--kmail/acljobs.cpp2
-rw-r--r--kmail/acljobs.h8
-rw-r--r--kmail/annotationjobs.cpp2
-rw-r--r--kmail/antispamwizard.cpp12
-rw-r--r--kmail/antispamwizard.h4
-rw-r--r--kmail/app_octetstream.cpp2
-rw-r--r--kmail/application_octetstream.desktop2
-rw-r--r--kmail/archivefolderdialog.cpp209
-rw-r--r--kmail/archivefolderdialog.h62
-rw-r--r--kmail/attachmentcollector.h18
-rw-r--r--kmail/attachmentstrategy.cpp87
-rw-r--r--kmail/attachmentstrategy.h3
-rw-r--r--kmail/backupjob.cpp500
-rw-r--r--kmail/backupjob.h109
-rw-r--r--kmail/bodypartformatter.cpp3
-rw-r--r--kmail/cachedimapjob.cpp141
-rw-r--r--kmail/cachedimapjob.h9
-rw-r--r--kmail/callback.cpp82
-rw-r--r--kmail/callback.h4
-rw-r--r--kmail/composer.h13
-rw-r--r--kmail/configuredialog.cpp181
-rw-r--r--kmail/configuredialog.h1
-rw-r--r--kmail/configuredialog_p.h12
-rw-r--r--kmail/customtemplates.cpp120
-rw-r--r--kmail/customtemplates.h20
-rw-r--r--kmail/customtemplates_base.ui478
-rw-r--r--kmail/customtemplates_kfg.kcfg6
-rw-r--r--kmail/dcopimap.desktop1
-rw-r--r--kmail/dcopmail.desktop1
-rw-r--r--kmail/dictionarycombobox.cpp1
-rw-r--r--kmail/distributionlistdialog.cpp47
-rw-r--r--kmail/editorwatcher.cpp13
-rw-r--r--kmail/editorwatcher.h11
-rw-r--r--kmail/encodingdetector.cpp82
-rw-r--r--kmail/eventsrc8
-rw-r--r--kmail/expirypropertiesdialog.cpp51
-rw-r--r--kmail/favoritefolderview.cpp31
-rw-r--r--kmail/filterimporterexporter.cpp166
-rw-r--r--kmail/filterimporterexporter.h33
-rw-r--r--kmail/folderdiaacltab.cpp41
-rw-r--r--kmail/folderdiaacltab.h2
-rw-r--r--kmail/foldersetselector.cpp88
-rw-r--r--kmail/foldersetselector.h45
-rw-r--r--kmail/folderstorage.cpp49
-rw-r--r--kmail/folderstorage.h18
-rw-r--r--kmail/foldertreebase.cpp12
-rw-r--r--kmail/folderutil.cpp113
-rw-r--r--kmail/folderutil.h65
-rw-r--r--kmail/globalsettings_base.kcfgc2
-rw-r--r--kmail/headeritem.cpp38
-rw-r--r--kmail/headeritem.h3
-rw-r--r--kmail/headerlistquicksearch.cpp15
-rw-r--r--kmail/headerstyle.cpp98
-rw-r--r--kmail/identitydialog.cpp46
-rw-r--r--kmail/identitydialog.h2
-rw-r--r--kmail/imapaccountbase.cpp42
-rw-r--r--kmail/imapaccountbase.h20
-rw-r--r--kmail/imapjob.cpp2
-rw-r--r--kmail/importarchivedialog.cpp107
-rw-r--r--kmail/importarchivedialog.h55
-rw-r--r--kmail/importjob.cpp396
-rw-r--r--kmail/importjob.h126
-rw-r--r--kmail/interfaces/bodypartformatter.h6
-rw-r--r--kmail/interfaces/urlhandler.h35
-rw-r--r--kmail/isubject.cpp11
-rw-r--r--kmail/keyresolver.cpp343
-rw-r--r--kmail/khtmlparthtmlwriter.cpp2
-rw-r--r--kmail/kleo_util.h7
-rw-r--r--kmail/kmacctcachedimap.cpp33
-rw-r--r--kmail/kmacctcachedimap.h7
-rw-r--r--kmail/kmacctimap.cpp2
-rw-r--r--kmail/kmacctimap.h2
-rw-r--r--kmail/kmacctlocal.cpp1
-rw-r--r--kmail/kmaddrbook.cpp1
-rw-r--r--kmail/kmail.kcfg66
-rw-r--r--kmail/kmailIface.h16
-rw-r--r--kmail/kmail_config_accounts.desktop6
-rw-r--r--kmail/kmail_config_appearance.desktop6
-rw-r--r--kmail/kmail_config_composer.desktop3
-rw-r--r--kmail/kmail_config_identity.desktop9
-rw-r--r--kmail/kmail_config_misc.desktop9
-rw-r--r--kmail/kmail_config_security.desktop9
-rw-r--r--kmail/kmail_part.rc3
-rw-r--r--kmail/kmailicalIface.h6
-rw-r--r--kmail/kmailicalifaceimpl.cpp167
-rw-r--r--kmail/kmailicalifaceimpl.h8
-rw-r--r--kmail/kmcommands.cpp204
-rw-r--r--kmail/kmcommands.h22
-rw-r--r--kmail/kmcomposewin.cpp360
-rw-r--r--kmail/kmcomposewin.h54
-rw-r--r--kmail/kmedit.cpp264
-rw-r--r--kmail/kmedit.h79
-rw-r--r--kmail/kmfawidgets.cpp7
-rw-r--r--kmail/kmfawidgets.h4
-rw-r--r--kmail/kmfilteraction.cpp214
-rw-r--r--kmail/kmfilterdlg.cpp25
-rw-r--r--kmail/kmfilterdlg.h2
-rw-r--r--kmail/kmfiltermgr.cpp2
-rw-r--r--kmail/kmfolder.cpp58
-rw-r--r--kmail/kmfolder.h23
-rw-r--r--kmail/kmfoldercachedimap.cpp588
-rw-r--r--kmail/kmfoldercachedimap.h92
-rw-r--r--kmail/kmfolderdia.cpp157
-rw-r--r--kmail/kmfolderdia.h2
-rw-r--r--kmail/kmfolderdir.cpp57
-rw-r--r--kmail/kmfolderdir.h19
-rw-r--r--kmail/kmfolderimap.cpp34
-rw-r--r--kmail/kmfolderimap.h19
-rw-r--r--kmail/kmfolderindex.cpp112
-rw-r--r--kmail/kmfolderindex.h24
-rw-r--r--kmail/kmfoldermaildir.cpp13
-rw-r--r--kmail/kmfoldermbox.cpp26
-rw-r--r--kmail/kmfoldersearch.cpp1
-rw-r--r--kmail/kmfolderseldlg.cpp445
-rw-r--r--kmail/kmfolderseldlg.h53
-rw-r--r--kmail/kmfoldertree.cpp95
-rw-r--r--kmail/kmfoldertree.h15
-rw-r--r--kmail/kmgroupware.cpp4
-rw-r--r--kmail/kmheaders.cpp156
-rw-r--r--kmail/kmheaders.h20
-rw-r--r--kmail/kmkernel.cpp182
-rw-r--r--kmail/kmkernel.h22
-rw-r--r--kmail/kmlineeditspell.cpp93
-rw-r--r--kmail/kmmainwidget.cpp276
-rw-r--r--kmail/kmmainwidget.h30
-rw-r--r--kmail/kmmainwin.cpp2
-rw-r--r--kmail/kmmainwin.rc3
-rw-r--r--kmail/kmmessage.cpp439
-rw-r--r--kmail/kmmessage.h143
-rw-r--r--kmail/kmmimeparttree.cpp2
-rw-r--r--kmail/kmmsgbase.cpp51
-rw-r--r--kmail/kmmsgbase.h33
-rw-r--r--kmail/kmmsgdict.cpp15
-rw-r--r--kmail/kmmsginfo.cpp96
-rw-r--r--kmail/kmmsginfo.h4
-rw-r--r--kmail/kmmsgpart.cpp5
-rw-r--r--kmail/kmmsgpartdlg.cpp5
-rw-r--r--kmail/kmpopheaders.cpp3
-rw-r--r--kmail/kmreadermainwin.cpp78
-rw-r--r--kmail/kmreadermainwin.h21
-rw-r--r--kmail/kmreaderwin.cpp735
-rw-r--r--kmail/kmreaderwin.h86
-rw-r--r--kmail/kmsearchpattern.cpp21
-rw-r--r--kmail/kmsearchpattern.h8
-rw-r--r--kmail/kmsearchpatternedit.cpp22
-rw-r--r--kmail/kmsearchpatternedit.h3
-rw-r--r--kmail/kmsender.cpp5
-rw-r--r--kmail/kmsystemtray.cpp9
-rw-r--r--kmail/kmsystemtray.h5
-rw-r--r--kmail/kmversion.h2
-rw-r--r--kmail/managesievescriptsdialog.cpp46
-rw-r--r--kmail/managesievescriptsdialog.h3
-rw-r--r--kmail/managesievescriptsdialog_p.h3
-rw-r--r--kmail/messageactions.cpp18
-rw-r--r--kmail/messageactions.h17
-rw-r--r--kmail/messagecomposer.cpp36
-rw-r--r--kmail/messageproperty.cpp35
-rw-r--r--kmail/messageproperty.h4
-rw-r--r--kmail/newfolderdialog.cpp102
-rw-r--r--kmail/newfolderdialog.h2
-rw-r--r--kmail/objecttreeparser.cpp706
-rw-r--r--kmail/objecttreeparser.h74
-rw-r--r--kmail/objecttreeparser_p.cpp350
-rw-r--r--kmail/objecttreeparser_p.h203
-rw-r--r--kmail/partNode.cpp236
-rw-r--r--kmail/partNode.h69
-rw-r--r--kmail/partmetadata.h4
-rw-r--r--kmail/partnodebodypart.cpp4
-rw-r--r--kmail/pics/Makefile.am2
-rw-r--r--kmail/pics/kmmsginvitation.pngbin0 -> 978 bytes
-rw-r--r--kmail/profiles/profile-default-rc.desktop8
-rw-r--r--kmail/profiles/profile-high-contrast-rc.desktop2
-rw-r--r--kmail/profiles/profile-html-rc.desktop3
-rw-r--r--kmail/profiles/profile-purist-rc.desktop4
-rw-r--r--kmail/profiles/profile-secure-rc.desktop5
-rw-r--r--kmail/recipientseditor.cpp5
-rw-r--r--kmail/recipientspicker.cpp6
-rw-r--r--kmail/redirectdialog.cpp9
-rw-r--r--kmail/redirectdialog.h2
-rw-r--r--kmail/searchwindow.cpp87
-rw-r--r--kmail/searchwindow.h10
-rw-r--r--kmail/sievedebugdialog.cpp65
-rw-r--r--kmail/sievejob.cpp6
-rw-r--r--kmail/sievejob.h2
-rw-r--r--kmail/simplefoldertree.h249
-rw-r--r--kmail/simplestringlisteditor.cpp16
-rw-r--r--kmail/simplestringlisteditor.h1
-rw-r--r--kmail/snippetdlg.cpp23
-rw-r--r--kmail/snippetdlg.h11
-rw-r--r--kmail/snippetdlgbase.ui3
-rw-r--r--kmail/snippetitem.cpp10
-rw-r--r--kmail/snippetwidget.cpp4
-rw-r--r--kmail/stl_util.h17
-rw-r--r--kmail/stringutil.cpp49
-rw-r--r--kmail/stringutil.h43
-rw-r--r--kmail/subscriptiondialog.cpp2
-rw-r--r--kmail/templateparser.cpp187
-rw-r--r--kmail/templateparser.h99
-rw-r--r--kmail/templatesconfiguration.cpp21
-rw-r--r--kmail/templatesinsertcommand.cpp4
-rw-r--r--kmail/templatesinsertcommand.h3
-rw-r--r--kmail/treebase.cpp235
-rw-r--r--kmail/treebase.h83
-rw-r--r--kmail/urlhandlermanager.cpp207
-rw-r--r--kmail/urlhandlermanager.h3
-rw-r--r--kmail/vacation.cpp15
-rw-r--r--kmail/vacationdialog.cpp36
-rw-r--r--kmail/vacationdialog.h7
-rw-r--r--kmail/vcardviewer.cpp10
-rw-r--r--kmail/vcardviewer.h41
-rw-r--r--kmailcvt/Makefile.am5
-rw-r--r--kmailcvt/filter_evolution.cxx1
-rw-r--r--kmailcvt/filter_evolution_v2.cxx2
-rw-r--r--kmailcvt/filter_kmail_archive.cxx35
-rw-r--r--kmailcvt/filter_kmail_archive.hxx32
-rw-r--r--kmailcvt/filter_kmail_maildir.cxx2
-rw-r--r--kmailcvt/filter_lnotes.cxx1
-rw-r--r--kmailcvt/filter_mailapp.cxx1
-rw-r--r--kmailcvt/filter_mbox.cxx1
-rw-r--r--kmailcvt/filter_oe.cxx1
-rw-r--r--kmailcvt/filter_opera.cxx2
-rw-r--r--kmailcvt/filter_outlook.cxx1
-rw-r--r--kmailcvt/filter_plain.cxx1
-rw-r--r--kmailcvt/filter_pmail.cxx2
-rw-r--r--kmailcvt/filter_sylpheed.cxx2
-rw-r--r--kmailcvt/filter_thebat.cxx2
-rw-r--r--kmailcvt/filter_thunderbird.cxx2
-rw-r--r--kmailcvt/filters.cxx27
-rw-r--r--kmailcvt/filters.hxx10
-rw-r--r--kmailcvt/kmailcvt.cpp60
-rw-r--r--kmailcvt/kmailcvt.h3
-rw-r--r--kmailcvt/kselfilterpage.cpp4
-rw-r--r--kmailcvt/main.cpp6
-rw-r--r--kmobile/devices/digicam/libkmobile_digicam.desktop5
-rw-r--r--kmobile/devices/gammu/libkmobile_gammu.desktop7
-rw-r--r--kmobile/devices/gnokii/libkmobile_gnokii.desktop7
-rw-r--r--kmobile/devices/skeleton/libkmobile_skeleton.desktop2
-rw-r--r--kmobile/kioslave/mimetypes/mobile_addressbook.desktop1
-rw-r--r--kmobile/kioslave/mimetypes/mobile_calendar.desktop1
-rw-r--r--kmobile/kioslave/mimetypes/mobile_device.desktop1
-rw-r--r--kmobile/kioslave/mimetypes/mobile_notes.desktop1
-rw-r--r--kmobile/kmobile.desktop2
-rw-r--r--kmobile/libkmobile.desktop1
-rw-r--r--knode/KNode.desktop1
-rw-r--r--knode/articlewidget.cpp45
-rw-r--r--knode/kncomposer.cpp2
-rw-r--r--knode/knglobals.cpp27
-rw-r--r--knode/knglobals.h3
-rw-r--r--knode/knode_config_accounts.desktop5
-rw-r--r--knode/knode_config_appearance.desktop5
-rw-r--r--knode/knode_config_cleanup.desktop2
-rw-r--r--knode/knode_config_identity.desktop5
-rw-r--r--knode/knode_config_post_news.desktop1
-rw-r--r--knode/knode_config_privacy.desktop2
-rw-r--r--knode/knode_config_read_news.desktop4
-rw-r--r--knotes/knote.cpp146
-rw-r--r--knotes/knote.h18
-rw-r--r--knotes/knotealarmdlg.cpp3
-rw-r--r--knotes/knoteedit.cpp82
-rw-r--r--knotes/knoteedit.h16
-rw-r--r--knotes/knoteprinter.cpp9
-rw-r--r--knotes/knotes.desktop1
-rw-r--r--knotes/knotes_manager.desktop4
-rw-r--r--knotes/knotesalarm.cpp5
-rw-r--r--knotes/knotesapp.cpp59
-rw-r--r--knotes/knotesapp.h3
-rw-r--r--knotes/knoteslegacy.cpp7
-rw-r--r--knotes/local.desktop1
-rw-r--r--knotes/resourcelocal.cpp12
-rw-r--r--knotes/resourcemanager.cpp48
-rw-r--r--knotes/resourcemanager.h2
-rw-r--r--konsolekalendar/main.cpp8
-rw-r--r--kontact/interfaces/kontactplugin.desktop4
-rw-r--r--kontact/interfaces/plugin.h4
-rw-r--r--kontact/interfaces/uniqueapphandler.cpp2
-rw-r--r--kontact/plugins/akregator/akregator_plugin.h2
-rw-r--r--kontact/plugins/akregator/akregatorplugin.desktop19
-rw-r--r--kontact/plugins/akregator/akregatorplugin3.2.desktop10
-rw-r--r--kontact/plugins/kaddressbook/kaddressbook_plugin.cpp3
-rw-r--r--kontact/plugins/kaddressbook/kaddressbookplugin.desktop14
-rw-r--r--kontact/plugins/karm/karmplugin.desktop14
-rw-r--r--kontact/plugins/kitchensync/kitchensync.desktop13
-rw-r--r--kontact/plugins/kmail/Makefile.am2
-rw-r--r--kontact/plugins/kmail/kcmkmailsummary.desktop21
-rw-r--r--kontact/plugins/kmail/kmailplugin.desktop17
-rw-r--r--kontact/plugins/knode/knodeplugin.desktop10
-rw-r--r--kontact/plugins/knotes/knotes_part.cpp4
-rw-r--r--kontact/plugins/knotes/knotes_part.h1
-rw-r--r--kontact/plugins/knotes/knotesplugin.desktop10
-rw-r--r--kontact/plugins/korganizer/journalplugin.desktop10
-rw-r--r--kontact/plugins/korganizer/journalplugin.h2
-rw-r--r--kontact/plugins/korganizer/kcmkorgsummary.desktop14
-rw-r--r--kontact/plugins/korganizer/korg_uniqueapp.cpp35
-rw-r--r--kontact/plugins/korganizer/korganizerplugin.cpp47
-rw-r--r--kontact/plugins/korganizer/korganizerplugin.desktop11
-rw-r--r--kontact/plugins/korganizer/summarywidget.cpp57
-rw-r--r--kontact/plugins/korganizer/todoplugin.cpp36
-rw-r--r--kontact/plugins/korganizer/todoplugin.desktop14
-rw-r--r--kontact/plugins/korganizer/todosummarywidget.cpp9
-rw-r--r--kontact/plugins/kpilot/kpilotplugin.desktop9
-rw-r--r--kontact/plugins/newsticker/kcmkontactknt.desktop5
-rw-r--r--kontact/plugins/newsticker/newstickerplugin.desktop12
-rw-r--r--kontact/plugins/specialdates/kcmsdsummary.desktop9
-rw-r--r--kontact/plugins/specialdates/sdsummarywidget.cpp14
-rw-r--r--kontact/plugins/specialdates/sdsummarywidget.h2
-rw-r--r--kontact/plugins/specialdates/specialdates_plugin.cpp2
-rw-r--r--kontact/plugins/specialdates/specialdatesplugin.desktop13
-rw-r--r--kontact/plugins/summary/kcmkontactsummary.cpp4
-rw-r--r--kontact/plugins/summary/kcmkontactsummary.desktop11
-rw-r--r--kontact/plugins/summary/summaryplugin.desktop16
-rw-r--r--kontact/plugins/summary/summaryview_plugin.cpp13
-rw-r--r--kontact/plugins/test/kptestplugin.desktop5
-rw-r--r--kontact/plugins/weather/weatherplugin.desktop10
-rw-r--r--kontact/src/Kontact.desktop4
-rw-r--r--kontact/src/about/kontact.css7
-rw-r--r--kontact/src/iconsidepane.cpp15
-rw-r--r--kontact/src/iconsidepane.h5
-rw-r--r--kontact/src/kontact.setdlg75
-rw-r--r--kontact/src/kontactui.rc5
-rw-r--r--kontact/src/main.cpp31
-rw-r--r--kontact/src/mainwindow.cpp193
-rw-r--r--kontact/src/mainwindow.h16
-rw-r--r--kontact/src/sidepanebase.cpp10
-rw-r--r--kontact/src/sidepanebase.h16
-rw-r--r--korganizer/Makefile.am9
-rw-r--r--korganizer/Todo-info.text18
-rw-r--r--korganizer/aboutdata.cpp5
-rw-r--r--korganizer/actionmanager.cpp323
-rw-r--r--korganizer/actionmanager.h27
-rw-r--r--korganizer/archivedialog.cpp6
-rw-r--r--korganizer/calendarview.cpp1231
-rw-r--r--korganizer/calendarview.h185
-rw-r--r--korganizer/datenavigator.cpp124
-rw-r--r--korganizer/datenavigator.h47
-rw-r--r--korganizer/datenavigatorcontainer.cpp108
-rw-r--r--korganizer/datenavigatorcontainer.h49
-rw-r--r--korganizer/dcopcalendar.desktop1
-rw-r--r--korganizer/eventarchiver.cpp68
-rw-r--r--korganizer/eventarchiver.h16
-rw-r--r--korganizer/exportwebdialog.cpp23
-rw-r--r--korganizer/exportwebdialog.h8
-rw-r--r--korganizer/freebusymanager.cpp167
-rw-r--r--korganizer/freebusymanager.h3
-rw-r--r--korganizer/importdialog.cpp10
-rw-r--r--korganizer/importdialog.h2
-rw-r--r--korganizer/incidencechanger.cpp225
-rw-r--r--korganizer/incidencechanger.h70
-rw-r--r--korganizer/interfaces/calendar/calendardecoration.desktop1
-rw-r--r--korganizer/interfaces/calendar/calendarplugin.desktop4
-rw-r--r--korganizer/interfaces/korganizer/baseview.h95
-rw-r--r--korganizer/interfaces/korganizer/corehelper.h3
-rw-r--r--korganizer/interfaces/korganizer/incidencechangerbase.h39
-rw-r--r--korganizer/interfaces/korganizer/korganizerpart.desktop1
-rw-r--r--korganizer/interfaces/korganizer/korgprintplugin.desktop1
-rw-r--r--korganizer/interfaces/korganizer/mainwindow.h4
-rw-r--r--korganizer/journalentry.cpp19
-rw-r--r--korganizer/journalentry.h7
-rw-r--r--korganizer/kcalendariface.h3
-rw-r--r--korganizer/kdatenavigator.cpp46
-rw-r--r--korganizer/kdatenavigator.h24
-rw-r--r--korganizer/koagenda.cpp431
-rw-r--r--korganizer/koagenda.h52
-rw-r--r--korganizer/koagendaitem.cpp84
-rw-r--r--korganizer/koagendaitem.h20
-rw-r--r--korganizer/koagendaview.cpp765
-rw-r--r--korganizer/koagendaview.h50
-rw-r--r--korganizer/koattendeeeditor.cpp220
-rw-r--r--korganizer/koattendeeeditor.h16
-rw-r--r--korganizer/kocorehelper.cpp8
-rw-r--r--korganizer/kocorehelper.h1
-rw-r--r--korganizer/kocounterdialog.cpp4
-rw-r--r--korganizer/kocounterdialog.h5
-rw-r--r--korganizer/kodaymatrix.cpp41
-rw-r--r--korganizer/kodaymatrix.h9
-rw-r--r--korganizer/kodialogmanager.cpp18
-rw-r--r--korganizer/koeditoralarms.cpp138
-rw-r--r--korganizer/koeditoralarms.h6
-rw-r--r--korganizer/koeditoralarms_base.ui12
-rw-r--r--korganizer/koeditorattachments.cpp831
-rw-r--r--korganizer/koeditorattachments.h98
-rw-r--r--korganizer/koeditordetails.cpp87
-rw-r--r--korganizer/koeditordetails.h7
-rw-r--r--korganizer/koeditorfreebusy.cpp106
-rw-r--r--korganizer/koeditorfreebusy.h4
-rw-r--r--korganizer/koeditorgeneral.cpp360
-rw-r--r--korganizer/koeditorgeneral.h34
-rw-r--r--korganizer/koeditorgeneralevent.cpp76
-rw-r--r--korganizer/koeditorgeneralevent.h5
-rw-r--r--korganizer/koeditorgeneraljournal.cpp23
-rw-r--r--korganizer/koeditorgeneraljournal.h10
-rw-r--r--korganizer/koeditorgeneraltodo.cpp240
-rw-r--r--korganizer/koeditorgeneraltodo.h16
-rw-r--r--korganizer/koeditorrecurrence.cpp225
-rw-r--r--korganizer/koeditorrecurrence.h9
-rw-r--r--korganizer/koeventeditor.cpp95
-rw-r--r--korganizer/koeventeditor.h6
-rw-r--r--korganizer/koeventpopupmenu.cpp14
-rw-r--r--korganizer/koeventpopupmenu.h17
-rw-r--r--korganizer/koeventview.cpp67
-rw-r--r--korganizer/koeventview.h3
-rw-r--r--korganizer/koeventviewer.cpp106
-rw-r--r--korganizer/koeventviewer.h50
-rw-r--r--korganizer/koeventviewerdialog.cpp18
-rw-r--r--korganizer/koeventviewerdialog.h15
-rw-r--r--korganizer/koglobals.h41
-rw-r--r--korganizer/kogroupware.cpp137
-rw-r--r--korganizer/kogroupware.h21
-rw-r--r--korganizer/kogroupwareprefspage.ui20
-rw-r--r--korganizer/kohelper.cpp20
-rw-r--r--korganizer/kohelper.h6
-rw-r--r--korganizer/koincidenceeditor.cpp45
-rw-r--r--korganizer/koincidenceeditor.h38
-rw-r--r--korganizer/koincidencetooltip.cpp19
-rw-r--r--korganizer/koincidencetooltip.h14
-rw-r--r--korganizer/kojournaleditor.cpp27
-rw-r--r--korganizer/kojournaleditor.h6
-rw-r--r--korganizer/kojournalview.cpp57
-rw-r--r--korganizer/kojournalview.h6
-rw-r--r--korganizer/kolistview.cpp374
-rw-r--r--korganizer/kolistview.h30
-rw-r--r--korganizer/komailclient.cpp111
-rw-r--r--korganizer/komailclient.h7
-rw-r--r--korganizer/komonthview.cpp255
-rw-r--r--korganizer/komonthview.h30
-rw-r--r--korganizer/koprefs.cpp35
-rw-r--r--korganizer/koprefs.h1
-rw-r--r--korganizer/koprefsdialog.cpp120
-rw-r--r--korganizer/korgac/alarmdialog.cpp534
-rw-r--r--korganizer/korgac/alarmdialog.h49
-rw-r--r--korganizer/korgac/koalarmclient.cpp22
-rw-r--r--korganizer/korgac/koalarmclient.h3
-rw-r--r--korganizer/korgac/korgac.desktop2
-rw-r--r--korganizer/korgac/testalarmdlg.cpp61
-rw-r--r--korganizer/korganizer.cpp6
-rw-r--r--korganizer/korganizer.desktop8
-rw-r--r--korganizer/korganizer.h2
-rw-r--r--korganizer/korganizer.kcfg81
-rw-r--r--korganizer/korganizer_configcolors.desktop11
-rw-r--r--korganizer/korganizer_configdesignerfields.desktop5
-rw-r--r--korganizer/korganizer_configfonts.desktop11
-rw-r--r--korganizer/korganizer_configfreebusy.desktop8
-rw-r--r--korganizer/korganizer_configgroupautomation.desktop5
-rw-r--r--korganizer/korganizer_configgroupscheduling.desktop5
-rw-r--r--korganizer/korganizer_configmain.desktop11
-rw-r--r--korganizer/korganizer_configplugins.desktop8
-rw-r--r--korganizer/korganizer_configtime.desktop11
-rw-r--r--korganizer/korganizer_configviews.desktop13
-rw-r--r--korganizer/korganizer_part.cpp17
-rw-r--r--korganizer/korganizer_part.h6
-rw-r--r--korganizer/korganizeriface.h10
-rw-r--r--korganizer/korganizerifaceimpl.cpp13
-rw-r--r--korganizer/korganizerifaceimpl.h5
-rw-r--r--korganizer/kotimelineview.cpp25
-rw-r--r--korganizer/kotimelineview.h4
-rw-r--r--korganizer/kotodoeditor.cpp113
-rw-r--r--korganizer/kotodoeditor.h9
-rw-r--r--korganizer/kotodoview.cpp148
-rw-r--r--korganizer/kotodoview.h12
-rw-r--r--korganizer/kotodoviewitem.cpp95
-rw-r--r--korganizer/koviewmanager.cpp204
-rw-r--r--korganizer/koviewmanager.h35
-rw-r--r--korganizer/kowhatsnextview.cpp11
-rw-r--r--korganizer/kowhatsnextview.h8
-rw-r--r--korganizer/multiagendaview.cpp271
-rw-r--r--korganizer/multiagendaview.h15
-rw-r--r--korganizer/navigatorbar.cpp114
-rw-r--r--korganizer/navigatorbar.h15
-rw-r--r--korganizer/plugins/datenums/datenums.desktop2
-rw-r--r--korganizer/plugins/exchange/exchange.desktop2
-rw-r--r--korganizer/plugins/hebrew/hebrew.cpp8
-rw-r--r--korganizer/plugins/hebrew/hebrew.desktop2
-rw-r--r--korganizer/plugins/printing/journal/journalprint.cpp8
-rw-r--r--korganizer/plugins/printing/journal/journalprint.desktop2
-rw-r--r--korganizer/plugins/printing/list/listprint.desktop2
-rw-r--r--korganizer/plugins/printing/whatsnext/whatsnextprint.desktop4
-rw-r--r--korganizer/plugins/printing/year/yearprint.cpp9
-rw-r--r--korganizer/plugins/printing/year/yearprint.desktop2
-rw-r--r--korganizer/plugins/timespanview/timespanview.desktop2
-rw-r--r--korganizer/previewdialog.cpp163
-rw-r--r--korganizer/previewdialog.h69
-rw-r--r--korganizer/printing/calprintdefaultplugins.cpp372
-rw-r--r--korganizer/printing/calprintdefaultplugins.h136
-rw-r--r--korganizer/printing/calprintpluginbase.cpp276
-rw-r--r--korganizer/printing/calprintpluginbase.h70
-rw-r--r--korganizer/publishdialog.cpp3
-rw-r--r--korganizer/resourceview.cpp391
-rw-r--r--korganizer/resourceview.h61
-rw-r--r--korganizer/searchdialog.cpp16
-rw-r--r--korganizer/searchdialog.h6
-rw-r--r--korganizer/timelabels.cpp12
-rw-r--r--korganizer/timelineitem.cpp12
-rw-r--r--korganizer/timelineitem.h5
-rw-r--r--korganizer/tips2
-rw-r--r--korganizer/urihandler.cpp70
-rw-r--r--korganizer/urihandler.h9
-rw-r--r--korganizer/version.h2
-rw-r--r--korn/KOrn.desktop4
-rw-r--r--kpilot/conduits/abbrowserconduit/abbrowser_conduit.desktop5
-rw-r--r--kpilot/conduits/docconduit/doc_conduit.desktop1
-rw-r--r--kpilot/conduits/docconduit/kpalmdoc.desktop1
-rw-r--r--kpilot/conduits/knotes/knotes-conduit.desktop2
-rw-r--r--kpilot/conduits/malconduit/mal_conduit.desktop2
-rw-r--r--kpilot/conduits/memofileconduit/memofile-conduit.desktop2
-rw-r--r--kpilot/conduits/notepadconduit/notepad-conduit.desktop3
-rw-r--r--kpilot/conduits/null/null-conduit.desktop1
-rw-r--r--kpilot/conduits/popmail/popmail-conduit.desktop5
-rw-r--r--kpilot/conduits/recordconduit/record-conduit.desktop2
-rw-r--r--kpilot/conduits/sysinfoconduit/sysinfo_conduit.desktop5
-rw-r--r--kpilot/conduits/timeconduit/time_conduit.desktop2
-rw-r--r--kpilot/conduits/vcalconduit/todo-conduit.desktop2
-rw-r--r--kpilot/conduits/vcalconduit/vcal-conduit.desktop2
-rw-r--r--kpilot/kpilot/kpilot.desktop1
-rw-r--r--kpilot/kpilot/kpilot_config.desktop3
-rw-r--r--kpilot/kpilot/kpilotconduit.desktop1
-rw-r--r--kpilot/kpilot/kpilotdaemon.desktop1
-rw-r--r--kresources/Makefile.am2
-rw-r--r--kresources/birthdays/kabc.desktop1
-rw-r--r--kresources/birthdays/resourcekabc.cpp60
-rw-r--r--kresources/birthdays/resourcekabc.h10
-rw-r--r--kresources/blogging/blogging.desktop1
-rw-r--r--kresources/blogging/kcal_resourceblogging.cpp6
-rw-r--r--kresources/caldav/config.cpp38
-rw-r--r--kresources/caldav/config.h3
-rw-r--r--kresources/caldav/job.cpp31
-rw-r--r--kresources/caldav/job.h64
-rw-r--r--kresources/caldav/preferences.cpp29
-rw-r--r--kresources/caldav/preferences.h5
-rw-r--r--kresources/caldav/prefsskel.kcfg10
-rw-r--r--kresources/caldav/reader.cpp39
-rw-r--r--kresources/caldav/reader.h10
-rw-r--r--kresources/caldav/resource.cpp142
-rw-r--r--kresources/caldav/resource.h23
-rw-r--r--kresources/caldav/writer.cpp37
-rw-r--r--kresources/caldav/writer.h46
-rw-r--r--kresources/egroupware/kabc_resourcexmlrpc.cpp5
-rw-r--r--kresources/egroupware/kabc_xmlrpc.desktop1
-rw-r--r--kresources/egroupware/kcal_resourcexmlrpc.cpp5
-rw-r--r--kresources/egroupware/kcal_xmlrpc.desktop1
-rw-r--r--kresources/egroupware/knotes_resourcexmlrpc.cpp5
-rw-r--r--kresources/egroupware/knotes_xmlrpc.desktop1
-rw-r--r--kresources/exchange/exchange.desktop1
-rw-r--r--kresources/exchange/exchange_deprecated.desktop1
-rw-r--r--kresources/exchange/resourceexchange.cpp36
-rw-r--r--kresources/exchange/resourceexchange.h10
-rw-r--r--kresources/groupware/kabc_groupware.desktop1
-rw-r--r--kresources/groupware/kabc_resourcegroupware.cpp2
-rw-r--r--kresources/groupware/kcal_groupware.desktop1
-rw-r--r--kresources/groupware/kcal_resourcegroupware.cpp6
-rw-r--r--kresources/kolab/kabc/contact.cpp72
-rw-r--r--kresources/kolab/kabc/contact.h7
-rw-r--r--kresources/kolab/kabc/kolab.desktop1
-rw-r--r--kresources/kolab/kabc/resourcekolab.cpp64
-rw-r--r--kresources/kolab/kabc/resourcekolab.h3
-rw-r--r--kresources/kolab/kcal/event.cpp7
-rw-r--r--kresources/kolab/kcal/incidence.cpp248
-rw-r--r--kresources/kolab/kcal/incidence.h9
-rw-r--r--kresources/kolab/kcal/kolab.desktop1
-rw-r--r--kresources/kolab/kcal/resourcekolab.cpp437
-rw-r--r--kresources/kolab/kcal/resourcekolab.h64
-rw-r--r--kresources/kolab/kcal/task.cpp171
-rw-r--r--kresources/kolab/kcal/task.h16
-rw-r--r--kresources/kolab/knotes/kolabresource.desktop1
-rw-r--r--kresources/kolab/knotes/note.cpp41
-rw-r--r--kresources/kolab/knotes/resourcekolab.cpp92
-rw-r--r--kresources/kolab/knotes/resourcekolab.h3
-rw-r--r--kresources/kolab/shared/kmailconnection.cpp40
-rw-r--r--kresources/kolab/shared/kolabbase.cpp19
-rw-r--r--kresources/kolab/shared/resourcekolabbase.cpp38
-rw-r--r--kresources/kolab/shared/resourcekolabbase.h12
-rw-r--r--kresources/lib/addressbookadaptor.cpp16
-rw-r--r--kresources/lib/folderselectdialog.cpp7
-rw-r--r--kresources/lib/folderselectdialog.h1
-rw-r--r--kresources/lib/kcal_resourcegroupwarebase.cpp40
-rw-r--r--kresources/newexchange/exchangeconvertercontact.cpp122
-rw-r--r--kresources/newexchange/kabc_newexchange.desktop1
-rw-r--r--kresources/newexchange/kabc_newexchange_final.desktop1
-rw-r--r--kresources/newexchange/kabc_resourceexchange.cpp8
-rw-r--r--kresources/newexchange/kcal_newexchange.desktop1
-rw-r--r--kresources/newexchange/kcal_newexchange_final.desktop1
-rw-r--r--kresources/newexchange/kcal_resourceexchange.cpp7
-rw-r--r--kresources/remote/remote.desktop1
-rw-r--r--kresources/remote/resourceremote.cpp2
-rw-r--r--kresources/scalix/kcal/resourcescalix.cpp18
-rw-r--r--kresources/scalix/kcal/resourcescalix.h3
-rw-r--r--kresources/slox/kabc_ox.desktop1
-rw-r--r--kresources/slox/kabc_slox.desktop1
-rw-r--r--kresources/slox/kabcresourceslox.cpp11
-rw-r--r--kresources/slox/kcal_ox.desktop1
-rw-r--r--kresources/slox/kcal_slox.desktop1
-rw-r--r--kresources/slox/kcalresourceslox.cpp2
-rw-r--r--ktnef/gui/ktnef.desktop2
-rw-r--r--ktnef/gui/ms-tnef.desktop4
-rw-r--r--libemailfunctions/email.cpp21
-rw-r--r--libkcal/Makefile.am12
-rw-r--r--libkcal/alarm.cpp60
-rw-r--r--libkcal/alarm.h48
-rw-r--r--libkcal/assignmentvisitor.cpp123
-rw-r--r--libkcal/assignmentvisitor.h122
-rw-r--r--libkcal/attachment.cpp111
-rw-r--r--libkcal/attachment.h57
-rw-r--r--libkcal/attachmenthandler.cpp258
-rw-r--r--libkcal/attachmenthandler.h178
-rw-r--r--libkcal/attendee.cpp3
-rw-r--r--libkcal/attendee.h4
-rw-r--r--libkcal/calendar.cpp185
-rw-r--r--libkcal/calendar.h87
-rw-r--r--libkcal/calendarlocal.cpp145
-rw-r--r--libkcal/calendarresources.cpp234
-rw-r--r--libkcal/calendarresources.h143
-rw-r--r--libkcal/calformat.cpp2
-rw-r--r--libkcal/calformat.h2
-rw-r--r--libkcal/calhelper.cpp167
-rw-r--r--libkcal/calhelper.h135
-rw-r--r--libkcal/calselectdialog.cpp101
-rw-r--r--libkcal/calselectdialog.h69
-rw-r--r--libkcal/comparisonvisitor.cpp107
-rw-r--r--libkcal/comparisonvisitor.h122
-rw-r--r--libkcal/dndfactory.cpp197
-rw-r--r--libkcal/dndfactory.h12
-rw-r--r--libkcal/duration.cpp140
-rw-r--r--libkcal/duration.h235
-rw-r--r--libkcal/event.cpp4
-rw-r--r--libkcal/event.h9
-rw-r--r--libkcal/exceptions.cpp77
-rw-r--r--libkcal/exceptions.h32
-rw-r--r--libkcal/freebusy.cpp9
-rw-r--r--libkcal/freebusy.h11
-rw-r--r--libkcal/htmlexport.cpp34
-rw-r--r--libkcal/icalformatimpl.cpp255
-rw-r--r--libkcal/incidence.h30
-rw-r--r--libkcal/incidencebase.cpp8
-rw-r--r--libkcal/incidencebase.h30
-rw-r--r--libkcal/incidenceformatter.cpp3526
-rw-r--r--libkcal/incidenceformatter.h65
-rw-r--r--libkcal/kcal_manager.desktop4
-rw-r--r--libkcal/libical/configure.in.in20
-rw-r--r--libkcal/libical/src/libical/icalattach.c151
-rw-r--r--libkcal/local.desktop1
-rw-r--r--libkcal/localdir.desktop1
-rw-r--r--libkcal/period.cpp8
-rw-r--r--libkcal/period.h18
-rw-r--r--libkcal/recurrence.cpp177
-rw-r--r--libkcal/recurrence.h15
-rw-r--r--libkcal/recurrencerule.cpp326
-rw-r--r--libkcal/recurrencerule.h121
-rw-r--r--libkcal/resourcecached.cpp21
-rw-r--r--libkcal/resourcecached.h16
-rw-r--r--libkcal/resourcecalendar.cpp46
-rw-r--r--libkcal/resourcecalendar.h60
-rw-r--r--libkcal/resourcelocaldir.cpp51
-rw-r--r--libkcal/resourcelocaldir.h1
-rw-r--r--libkcal/resourcelocaldirconfig.cpp11
-rw-r--r--libkcal/scheduler.cpp356
-rw-r--r--libkcal/scheduler.h27
-rw-r--r--libkcal/tests/Makefile.am7
-rw-r--r--libkcal/tests/data/RecurrenceRule/ConnectDaily/ConnectDaily11.ics.recurson.ref1
-rw-r--r--libkcal/tests/data/RecurrenceRule/KAlarm_3.4/KAlarm_TestCase06.ics.recurson.ref1
-rw-r--r--libkcal/tests/data/RecurrenceRule/LibICal/LibICal_TestCase02.ics.recurson.ref1
-rw-r--r--libkcal/tests/data/RecurrenceRule/LibICal/LibICal_TestCase24.ics.recurson.ref1
-rw-r--r--libkcal/tests/data/RecurrenceRule/LibICal/LibICal_TestCase42.ics.recurson.ref1
-rw-r--r--libkcal/tests/data/RecurrenceRule/RFC2445/RFC2445_RRULETestCase12.ics.recurson.ref2
-rw-r--r--libkcal/tests/data/RecurrenceRule/UntilInUTC/Until_TestCase02.ics.recurson.ref1
-rw-r--r--libkcal/tests/data/RecurrenceRule/UntilInUTC/Until_TestCase04.ics.recurson.ref1
-rw-r--r--libkcal/tests/data/RecurrenceRule/unsorted/lastworkday.ics.recurson.ref1
-rw-r--r--libkcal/tests/data/RecurrenceRule/unsorted/monthly.ics.recurson.ref1
-rw-r--r--libkcal/tests/data/RecurrenceRule/unsorted/rdate.ics.recurson.ref1
-rw-r--r--libkcal/tests/data/RecurrenceRule/unsorted/test1.ics.recurson.ref1
-rw-r--r--libkcal/tests/data/RecurrenceRule/unsorted/weekly.ics.recurson.ref208
-rwxr-xr-xlibkcal/tests/runtestcase.pl8
-rw-r--r--libkcal/tests/testcalselectdialog.cpp45
-rw-r--r--libkcal/todo.cpp33
-rw-r--r--libkcal/todo.h20
-rw-r--r--libkdenetwork/gpgmepp/context.cpp88
-rw-r--r--libkdenetwork/gpgmepp/context.h11
-rw-r--r--libkdenetwork/gpgmepp/data.cpp10
-rw-r--r--libkdenetwork/gpgmepp/decryptionresult.cpp12
-rw-r--r--libkdenetwork/gpgmepp/decryptionresult.h7
-rw-r--r--libkdenetwork/gpgmepp/encryptionresult.cpp26
-rw-r--r--libkdenetwork/gpgmepp/encryptionresult.h6
-rw-r--r--libkdenetwork/gpgmepp/signingresult.cpp42
-rw-r--r--libkdenetwork/gpgmepp/signingresult.h9
-rw-r--r--libkdenetwork/gpgmepp/util.h4
-rw-r--r--libkdenetwork/gpgmepp/verificationresult.cpp56
-rw-r--r--libkdenetwork/gpgmepp/verificationresult.h8
-rw-r--r--libkdepim/addresseelineedit.cpp354
-rw-r--r--libkdepim/addresseelineedit.h13
-rw-r--r--libkdepim/addressesdialog.cpp123
-rw-r--r--libkdepim/calendardiffalgo.h3
-rw-r--r--libkdepim/completionordereditor.cpp23
-rw-r--r--libkdepim/csshelper.cpp14
-rw-r--r--libkdepim/csshelper.h2
-rw-r--r--libkdepim/distributionlist.cpp8
-rw-r--r--libkdepim/htmldiffalgodisplay.h3
-rw-r--r--libkdepim/kabcresourcecached.cpp22
-rw-r--r--libkdepim/kaddrbook.cpp61
-rw-r--r--libkdepim/kaddrbook.h15
-rw-r--r--libkdepim/kcmdesignerfields.cpp1
-rw-r--r--libkdepim/kdepimprotocols.h32
-rw-r--r--libkdepim/kfoldertree.h11
-rw-r--r--libkdepim/kincidencechooser.cpp58
-rw-r--r--libkdepim/kincidencechooser.h53
-rw-r--r--libkdepim/komposer/core/komposerconfig.desktop2
-rw-r--r--libkdepim/komposer/core/komposereditor.desktop1
-rw-r--r--libkdepim/komposer/core/komposerplugin.desktop1
-rw-r--r--libkdepim/komposer/plugins/default/defaulteditor.desktop2
-rw-r--r--libkdepim/kprefsdialog.cpp2
-rw-r--r--libkdepim/ktimeedit.cpp2
-rw-r--r--libkdepim/kvcarddrag.cpp39
-rw-r--r--libkdepim/kvcarddrag.h14
-rw-r--r--libkdepim/ldapclient.cpp32
-rw-r--r--libkdepim/ldapclient.h2
-rw-r--r--libkdepim/ldapsearchdialog.cpp22
-rw-r--r--libkdepim/ldapsearchdialog.h2
-rw-r--r--libkdepim/progressdialog.cpp18
-rw-r--r--libkdepim/progressdialog.h2
-rw-r--r--libkdepim/progressmanager.cpp17
-rw-r--r--libkdepim/progressmanager.h27
-rw-r--r--libkdepim/statusbarprogresswidget.cpp13
-rw-r--r--libkdepim/statusbarprogresswidget.h1
-rw-r--r--libkdepim/tests/Makefile.am11
-rw-r--r--libkdepim/tests/testkincidencechooser.cpp45
-rw-r--r--libkdepim/tests/testutf7encoder2.cpp6
-rw-r--r--libkholidays/kholidays.cpp8
-rw-r--r--libkpgp/kpgp.cpp2
-rw-r--r--libkpgp/kpgpbase.cpp26
-rw-r--r--libkpimexchange/core/exchangedownload.cpp2
-rw-r--r--libkpimexchange/core/exchangeupload.cpp2
-rw-r--r--libkpimexchange/core/utils.cpp2
-rw-r--r--libkpimidentities/identity.cpp26
-rw-r--r--libkpimidentities/identity.h16
-rw-r--r--libkpimidentities/identitymanager.cpp22
-rw-r--r--libksieve/tests/lexertest.cpp1
-rw-r--r--libksieve/tests/parsertest.cpp1
-rw-r--r--mimelib/COPYRIGHT13
-rw-r--r--mimelib/datetime.cpp5
-rw-r--r--mimelib/dw_cte.cpp14
-rw-r--r--mimelib/dw_date.cpp54
-rw-r--r--mimelib/dw_mime.cpp9
-rw-r--r--mimelib/dwstring.cpp2
-rw-r--r--mimelib/mimelib/address.h3
-rw-r--r--mimelib/mimelib/enum.h1
-rw-r--r--mimelib/mimelib/headers.h1
-rw-r--r--mimelib/mimelib/mailbox.h1
-rw-r--r--mimelib/mimelib/mboxlist.h1
-rw-r--r--mimelib/mimelib/msgcmp.h4
-rw-r--r--mimelib/mimelib/protocol.h1
-rw-r--r--mimelib/test_boyermor.cpp1
-rw-r--r--networkstatus/networkstatus.desktop2
-rw-r--r--patchlog.txt0
-rw-r--r--plugins/kmail/bodypartformatter/attendeeselector.cpp12
-rw-r--r--plugins/kmail/bodypartformatter/text_calendar.cpp379
-rw-r--r--plugins/kmail/bodypartformatter/text_calendar.desktop2
-rw-r--r--plugins/kmail/bodypartformatter/text_vcard.cpp157
-rw-r--r--plugins/kmail/bodypartformatter/text_vcard.desktop2
-rw-r--r--plugins/kmail/bodypartformatter/text_xdiff.cpp2
-rw-r--r--plugins/kmail/bodypartformatter/text_xdiff.desktop2
-rw-r--r--release_howto90
-rw-r--r--translate83
-rw-r--r--wizards/Makefile.am44
-rw-r--r--wizards/egroupwaremain.cpp4
-rw-r--r--wizards/exchangemain.cpp4
-rw-r--r--wizards/groupwarewizard.desktop1
-rw-r--r--wizards/kmailchanges.cpp16
-rw-r--r--wizards/kolabmain.cpp4
-rw-r--r--wizards/overviewpage.cpp19
-rw-r--r--wizards/overviewpage.h1
911 files changed, 35043 insertions, 10782 deletions
diff --git a/LAST_ENTERPRISE_SYNC b/LAST_ENTERPRISE_SYNC
new file mode 100644
index 000000000..2e52917a0
--- /dev/null
+++ b/LAST_ENTERPRISE_SYNC
@@ -0,0 +1 @@
+Revision 1170137
diff --git a/Makefile.am.in b/Makefile.am.in
index 39ffd0087..9cea71b02 100644
--- a/Makefile.am.in
+++ b/Makefile.am.in
@@ -23,7 +23,7 @@ COMPILE_BEFORE_certmanager = libkdenetwork libkpgp
COMPILE_BEFORE_korganizer = libkdepim libkpimidentities libkpimexchange kgantt
COMPILE_BEFORE_kaddressbook = libkdepim certmanager akregator
COMPILE_BEFORE_kandy = libkdepim
-COMPILE_BEFORE_kmail= libkdepim libkpimidentities certmanager libkpgp libkmime indexlib
+COMPILE_BEFORE_kmail= libkdepim libkpimidentities certmanager libkpgp libkmime
COMPILE_BEFORE_knode= libkdepim libkpgp libkmime
COMPILE_BEFORE_karm = libkdepim kresources
COMPILE_BEFORE_plugins = kmail libkdepim libkcal
diff --git a/NewsLog.txt b/NewsLog.txt
new file mode 100644
index 000000000..10034235e
--- /dev/null
+++ b/NewsLog.txt
@@ -0,0 +1,2147 @@
+Friday, August 27th 2010
+
+Problems addressed
+------------------
+
+* Improve the error message when regenerating a corrupt index:
+ Show one error message for all folders on startup, instead of multiple error messages
+* Possibly fix a crash when selecting or deselecting resources when the side-by-side view is active
+
+
+Friday, August 20th 2010
+
+Problems addressed
+------------------
+
+* kolab/issue4332: event update mail which really is an invitation (rt#6125)
+* kolab/issue4484: Send S/MIME encrypted mail to address without certificate, search for external certificate button (rt#5659)
+* kolab/issue4485: Try to create a contact without writable folder; edit dialog is closed
+* kolab/issue4479: Change used kontact plugins crash (Kontact::MainWindow::addPlugin at mainwindow.cpp:719) (rt#6193)
+* kolab/issue4333: Renaming of a shared calendar folder failed (rt#6121)
+* Add more debug output to help finding the cause of kolab/issue4498
+* Regenerate the mail index earlier when finding inconsistencies in it
+
+
+Friday, August 13th 2010
+
+Problems addressed
+------------------
+
+* kolab/issue4484(Improvement): Send S/MIME encrypted mail to address without certificate, search for external certificate button (rt#5659)
+* kolab/issue4404: Reminder: the event entries of the events which triggered an alarm should be selected
+
+
+Friday, August 5th 2010
+
+Problems addressed
+------------------
+
+* kolab/issue4203(mainly): A reminder can contain non-existing events (rt#6051)
+* kolab/issue4335: D'n'D a mail attachment with the icon is not working (rt#6126)
+* kolab/issue3932: Kontact should show a warning, if a user tries to accept an invitation of a past event (rt#5833)
+* kolab/issue4005(improved): Attachments should open in read-only folders (rt#5915)
+* Speed up changing Kolab incidences in KOrganizer by only sending one change instead of two
+ to the server (see kolab/issue2109)
+
+kk4:
+* kolab/issue4469: (Kontact loses shared calendar folders (type changed)(rt#6174)
+
+kk6:
+* Add more debug output to help finding the cause of kolab/issue4498
+
+
+Friday, July 30th 2010
+
+Problems addressed
+------------------
+
+* kolab/issue4261(Mainly): Wish: Print whole day events at top of a day print (rt#6084)
+* kolab/issue3974: Clicking on an ics/vcs-attachment doesn't import or display the events of the attachment (rt#5812)
+* kolab/issue4429: Key selection dialog is too small. 'Abbrechen' button is cut
+
+
+Friday, July 23th 2010
+
+Problems addressed
+------------------
+
+* kolab/issue4335 (partly): D'n'D a mail attachment with the icon is not working (rt#6126)
+* kolab/issue3908 (partly): Mail view and print layout problem if description of attachment is to long (#5872)
+* kolab/issue4455: calendar activate/deactivate handling broken
+* kolab/issue4282: Adding a new event from an invitation update mail shows unnecssary message
+ dialog 'store/throw away' (rt#6094)
+* Fixed a few crashes in KOrganizer and a crash in KMail
+* Improvements in renaming calendar folders
+
+
+Friday, July 16th 2010
+
+Problems addressed
+------------------
+
+* kolab/issue4447: Deleting contact from distribution list with DELETE key and Remove button
+
+
+Friday, July 9th 2010
+
+Problems addressed
+------------------
+
+* kolab/issue4445: Importing a events into an existing resource and no resource activated, 1000x error messages
+* kolab/issue4437: Wrong update mail (other attendees are removed) after double accepting of an event
+* kolab/issue4406: Change write to read rights of a shared calendar folder, can lead to a focus problem (rt#6167)
+* kolab/issue4343 (improved): Wish: global audio file for all reminder (rt#6133)
+* kolab/issue4406: Change write to read rights of a shared calendar folder, can lead to a focus problem (rt#6167)
+
+Friday, July 1st 2010
+
+Problems addressed
+------------------
+
+* Fix crash when composing a message, when compiled with GCC >= 4.4
+* When adding many incidences, don't ask which calendar to put it in, for each incidence
+
+kk2:
+* kolab/issue4442: Some broken mails double themself in a sync.(rt#6183)
+
+
+Friday, June 25th 2010
+
+Problems addressed
+------------------
+
+* kolab/issue4417: Resizing a one day event changes the event wrongly (rt#6064)
+* kolab/issue4401(mainly): The contacts free-busy-url is not saved in the contact mail but in kde/share/apps/korganizer/freebusyurls
+* kolab/issue2652: Kontact generate invalid charset declaration for attached text files
+* kolab/issue4085: Wish: Mail attachments only in the header of a mail (rt#5987)
+
+
+Friday, June 18th 2010
+
+Problems addressed
+------------------
+
+* kolab/issue4031: sending mail to OpenPGP-only and S/MIME-only recipient sends only OpenPGP (rt#5938)
+* kolab/issue4369: KMail: Pressing Cancel in untrusted certificates warning dialog doesn't cancel, but continue
+* kolab/issue4411: todos alarm: configured alarm changed after opening the todo twice
+* kolab/issue3726(mainly): A changed Navigator toolbars is displayed without changes after restart (rt#5805)
+* kolab/issue4032: Todos summary shows no todos in offline (rt#5944)
+* kolab/issue4418: details view of a large multipart/mixed mail shows empty Message-ID (rt#5842)
+* kolab/issue4245: Wish: searchbar should also search for mail addresses (rt#6071)
+* kolab/issue4240: Wish: Maillist icons for invitations and update mails (rt#6065)
+* kolab/issue4419: Accept an invitation with set "Exchange compatible", update mail contains an untranslated
+ "Accepted" in the subject. (rt#5903)
+kk3:
+* kolab/issue4407: event with attachment: png/zip attachment size changes
+
+kk4:
+* kolab/issue4410: event attachment cannot be opend after restart (rt#6172)
+
+Friday, June 11th 2010
+
+Problems addressed
+------------------
+
+* Add a context menu for business card attachments in mails
+* Remove groupwise and groupdav resources
+* kolab/issue3411: kmail drag and drop (DnD) of email addresses with umlauts from reader to composer exposes encoded-word encoding
+* kolab/issue4352: Wish: Reminder: horizontal slider between event list and event details (rt#6142)
+* kolab/issue4414: print todos: in the result the priority and summary header overlap
+* kolab/issue4413: Todos: Print, but print events is selected
+* kolab/issue4408: event with attachment: textfield selection creates invitation without attachment
+
+
+Friday, June 4th 2010
+
+Problems addressed
+------------------
+
+* kolab/issue4400: Composer: create distribution list adds the dist list just into the default resource
+* kolab/issue4094: Scrollbar position changes, if a new mail is synced into the folder (rt#5997)
+* kolab/issue3911: mail enterprise header: cannot mail to the second to address
+* kolab/issue4350: Sometimes the date headers in the agenda view are grainy and doubled (rt#6140)
+* kolab/issue3411(partly): kmail drag and drop (DnD) of email addresses with umlauts from reader to composer exposes
+ encoded-word encoding
+
+
+Friday, May 28th 2010
+
+Problems addressed
+------------------
+
+* kolab/issue4365: Wish: Edit Todo: Complete button. (rt#6156)
+* kolab/issue4372: Rename context menu entry "Copy Link Address" to "Copy Email Address(es)
+* kolab/issue4281: Composer: create distlist, for every entry a resource chooser appears (rt#6098)
+* KDE bug 238945: Crash while displaying an invitation mail
+
+
+Friday, May 21th 2010
+
+Problems addressed
+------------------
+
+* kolab/issue4256: Event attendees tab, Select Addressee.. Enter Filter, empty topics are shown. (rt#6081)
+* kolab/issue4340: event edit dialog: Selected attachment should be deleted with shortcut "Remove"/German "Entf"(rt#6124)
+* kolab/issue4381: Imap cache corruption giving crash (SIGFPE) on each sync for email without length
+* kolab/issue3963: Alarm of an recurring task doesn't pop up (rt#5891)
+* kolab/issue4379: Event dialog: Added attendees of a dist list are removed, handling wrong (rt#6159)
+* kolab/issue4307: D'n'D a contact to calendar/todo sidebar icon added an empty attachment
+* kolab/issue4359 (mainly): Invitation, canceled at the resource dialog, but organizer gets accept mail (rt#6147)
+* kolab/issue4316: Pressing Cancel in Recurrence dialog does not discard changes
+* kolab/issue4093: In "enterprise" mail header CC and BCC addresses are displayed under the TO field (rt#5996)
+* kolab/issue4366: Use own fonts for printing
+* kolab/issue4322: Add signature to current line and linebreak (entered at wrong place (rt#6113)
+* kolab/issue4264: Advanced alarm dialog of an event/a todo: Change German "Entfernen ..." into "Entfernen" (rt#6087)
+* kolab/issue4286: Agenda view shows mix of long and short date format (rt#6105)
+* Improve error message if renaming a shared folder failed (see kolab/issue4333)
+
+
+Friday, May 7th 2010
+
+Problems addressed
+------------------
+
+* kolab/issue4315: Add attachment for event/task: Store inline should be set by default
+* kolab/issue4314: Can't open attachment of an invitation mail (rt#6109)
+* kolab/issue4317: Open invitation window closes, if an attachment is opened (rt#6111)
+* kolab/issue3882: Composer: Pressing TAB in the address completion popup list doesn't change to the next addressbook
+* kolab/issue4338: Toggle alarm "on" should create a 15 mins for start alarm. (rt#6131)
+* kolab/issue4119: Enter a distribution list as attendee into an event, should expand the members of the dist list into
+ the attendee field (rt#6027)
+* kolab/issue4349: Wish: remove standard event icon in the agenda view (rt#6139)
+* kolab/issue4363: An event with one attendee doesn't display the organizer in preview pane
+* kolab/issue4339: Small translation improvement: German "Kalender/Termin(iCS.." should be "Termin/Kalender (ICS.." (rt#6122)
+* kolab/issue4331: email addresses with comma or special characters should be displayed with quotes in the mail headers (rt#6128)
+* kolab/issue3999: Kontact sometimes changes from mail part to the calendar part
+* kolab/issue4093(partly): In "enterprise" mail header CC and BCC addresses are displayed under the TO field (rt#5996)
+* kolab/issue4351: Reminder: Focus after pressing remind me later, should be on the next event (rt#6141)
+* kolab/issue4350: Sometimes the date headers in the agenda view are grainy and doubled (rt#6140)
+* Add support for alias email addresses in the identity configuration
+
+
+Friday, April 9th 2010
+
+Problems addressed
+------------------
+
+* kolab/issue4267: information about the alarm are missing in the event views (rt#6090)
+* kolab/issue2470: Calendar: "Next Month" button doesn't change the displayed month (rt#5961)
+* kolab/issue3882(partly): Composer: Pressing TAB in the address completion popup list doesn't change to the next
+ addressbook
+* kolab/issue4280: Due time "00:00" is set for no time associated todos if todo resource disabled+enabled (rt#6096)
+* kolab/issue4301: calendar display for single events isn't correct
+* kolab/issue2762(partly): Sometimes whole day events overlap in the view (rt#5936)
+* kolab/issue4219(partly): Tasks: Copy, Select nothing, Paste of a subtask copies it as subtask
+
+
+Friday, April 1st 2010
+
+Problems addressed
+------------------
+
+* kolab/issue4270: alarm of an event with two lines shows strange half line title.(rt#6093)
+* kolab/issue4271: In korganizer's resource view, creating a subresource containing a / originates a crash
+* kolab/issue4268: Calendar: Black triangle shows that events are somewhere up, but the user scrolled already to 0:00 (rt#6091)
+* kolab/issue4267(partly): information about the alarm are missing in the event views (rt#6090)
+* kolab/issue4266: birthday resource should be named "Geburtstage" if German language is used (rt#6089)
+* kolab/issue3099: Replying to stored mail crashes Kontact
+* kolab/issue4284: Journal: Link Add Journal entry in the week view is not working (rt#6103)
+* kolab/issue4285: The default size of the reminder should be larger (rt#6104)
+* kolab/issue3469: KNotes: Deleted notes reappear
+* kolab/issue4272: Sometimes it is not possible to delete a folder
+* kolab/issue4248: Configure Filter dialog: Some filter conditions are not translated to German (rt#6074)
+
+
+Friday, March 26th 2010
+
+Problems addressed
+------------------
+
+* kolab/issue4229: Kontact hangs when switching to calendar with incorrect interval tag in event (rt#6063)
+* kolab/issue4230: Todo: alarm 0 mins vs 1 min in advanced alarm dialog
+* kolab/issue4220: Calander tabular view , side-by-side tab Move an event asks for resource
+* kolab/issue4064: Task with associated due time "00:00" isn't displayed in all calendar views (rt#5974)
+* kolab/issue4224: event viewer dialog to small (rt#6060)
+* kolab/issue4149: Search Directory Services and comma-formated names (rt#5954)
+* kolab/issue3599: KNotes: Crash in KNotesResourceManager::deleteNote at resourcemanager.cpp:109
+* kolab/issue4247: Composer: After removing an attachment is the focus not on the next attachment (rt#6073)
+* kolab/issue4246: Not possible to add umlauts to the move message dialog (rt#6072)
+* kolab/issue3902: Delete a folder while syncing leads to crash
+* kolab/issue4250: Edit "Out of office" replies: Resend notification only after: days is missing (rt#6076)
+* kolab/issue4249: Crash while printing a mail without preview pane (rt#6075)
+* kolab/issue4142: Composer: view all fields layout and small problems (rt#6032)
+* kolab/issue4012: Calender view update problem, if the same appointment is moved on the server in other folders (rt#5930)
+
+
+Friday, March 19th 2010
+
+Problems addressed
+------------------
+
+* kolab/issue4207: alarm time textfield in advanced alarm dialog should be 5-digits (rt#6055)
+* kolab/issue4200: Reminder date sorting doesn't recognize different month (rt#6047)
+* kolab/issue4215: Events ending at 00h appear in the wrong day in day-view
+* kolab/issue4054(needs to patch kdelibs, see issue): Umlauts and sending contacts problem (rt#5956)
+* kolab/issue4060: Wish: Auto-spellchecking: action to add new suggestion in context menu (rt#5969)
+* kolab/issue4224: event viewer dialog to small (rt#6060)
+* kolab/issue4218: Tasks: Copy to of a recurring event forgets the recurrence
+* kolab/issue4225: small month view: selected weekend days and holidays should be colored red in blue (rt#6061)
+* kolab/issue4194(partly): Task without starttime should have default alarm type "before the end" (rt#6045)
+
+
+Friday, March 12th 2010
+
+Problems addressed
+------------------
+
+* kolab/issue4195: Copy+Paste of a todo with recurrence should not change the enddate (rt#6046)
+* kolab/issue4192: Wish: Rename German "Start" into "Beginn" in a event advanced alarm dialog (rt#6043)
+* kolab/issue3706: copy+ paste of an appointment in the monthview creates the appointment at a wrong time (rt#6042)
+* kolab/issue4194: Task without starttime should have default alarm type "before the end" (rt#6045)
+* kolab/issue4109: Task with recurrence: Starttime not saved (rt#6019)
+* kolab/issue3963: Alarm of an recurring task doesn't pop up (rt#5891)
+* kolab/issue4066: Quota warning color coming later than server warning dialog (rt#5955)
+* kolab/issue4098: Cannot import "archived" mails into local folders
+* kolab/issue3596: Display a special text instead of a Toltec binary invitation email (rt#5766)
+* kolab/issue4203: A reminder can contain non-existing events.(rt#6051)
+* kolab/issue4201: Spellchecking in composer:RMB->suggestion deletes wrong word (rt#6050)
+* kolab/issue4187: Crash while switching between signed and unsigned mail (rt#5980)
+
+
+Friday, March 5th 2010
+
+Problems addressed
+------------------
+
+* kolab/issue4102: Wish: type of attendee of an event should be displayed in the small event pane (rt#6004)
+* kolab/issue4105: Three warning dialogs appears, if I try to create a todo and have deactivated the Task resources
+* kolab/issue4107: In workweek mode clicking on the month pane week number selects whole week (rt#6013)
+* kolab/issue1765: In parallel calender view there is no need to ask in which resource folder a new event should get. (rt#5816)
+* kolab/issue4110: Task with recurrence: due of a selected task in calendar doesn't match the right date (rt#6020)
+* kolab/issue4118(partly): Wish: next/previous week buttons in the small month pane (rt#6024)
+* kolab/issue3874: Calendar Timeline View: Resize and deactive and activate of a calendar resource changes the duration of
+ the event to 15 mins
+* kolab/issue4066(partly): Quota warning color coming later than server warning dialog (rt#5955)
+* kolab/issue2277: Usability problem with "enterprise headers" airmail icon
+* kolab/issue4177: A hidden reminder dialog should reappear, if a new alarm is triggered
+* kolab/issue4181: Wish: an additional column "folder" in the todos list in the todo component
+* kolab/issue4142(partly): Add some tooltips to KMail's composer
+* kolab/issue4096: User with write access to a calendar folder should be able to change the events
+ (even if he isnot the organizer) (rt#5999)
+* kolab/issue4148: New event, attendee dialog: entry with comma format should stay in comma format in the attendee pane (rt#6035)
+* kolab/issue4128: side-by-side view: scrollbar slider too small
+
+
+Friday, February 26th 2010
+
+Problems addressed
+------------------
+
+* kolab/issue4055: Workweek after restart is today and next 4 days (rt#5958)
+* kolab/issue4053: reminder of an event with recurrence shows wrong date (rt#5953)
+* kolab/issue4112: Event/Task conflict dialog is too difficult (rt#6009)
+* kolab/issue4060: Wish: Auto-spellchecking: action to add new suggestion in context menu (rt#5969)
+* When recovering a written message after a crash, don't delete the autosave file immediatley, to avoid data
+ loss in case KMail crashes again before the next autosave is triggered
+
+
+Friday, February 19th 2010
+
+Problems addressed
+------------------
+
+* kolab/issue4105: (partly) Three warning dialogs appears, if I try to create an event and have deactivated
+ the Task resources.
+* kolab/issue1765: (partly) In parallel calender view there is no need to ask in which resource folder a new event
+ should get (rt#5816)
+* kolab/issue4117: Reminder: Preselected "remind me later" time should always be 5 mins (rt#6017)
+* kolab/issue3597: Event reminder of a deleted event appears (rt#6010)
+* kolab/issue4108: Reminder option "remind me later" should work even if the user closed the session (rt#6016)
+* kolab/issue4125: (mainly) Event with recurrence: Changing attendee of one event, changes it for every event (rt#6029)
+* kolab/issue2079: Search for mails: Cannot create a new search if an old search is selected
+* kolab/issue4056: calendar month view: It is not visible in the big calendar, which day is selected in the
+ small month calendar (rt#5960)
+* kolab/issue4053: (partly) reminder of an event with recurrence shows wrong date (rt#5953)
+* kolab/issue4145: Calendar: month view/agenda view inconsistence with events with recurrence
+* kolab/issue4147: Event/Task conflict dialog "Take Both" should be default (rt#6009)
+
+
+Friday, February 12th 2010
+
+Problems addressed
+------------------
+
+* kolab/issue4059: After deactivating of a calendar the small monthview is not updated (rt#5966)
+* kolab/issue2656: Wrong scale is shown, if the calendar component is selected (rt#5916)
+* kolab/issue3835: Edit in the Reminder dialog doesn't work after restart of KDE
+* kolab/issue4090: Wish:Mail: Double click on mail in search dialog should open the mail in a window (rt#5992)
+* kolab/issue4066(partly): Change the default value for the close to quota threshold to 80%
+* kolab/issue4039: Size of an embedded event attachment is too small
+* kolab/issue4057: Attach file: if filedialog default directory doesn't exit, it should use the home directory
+ of the user as default (rt#5962)
+* kolab/issue4097: Wish for an option: reply should always quote the whole mail (rt#5995)
+* kolab/issue4089: Composer: double click on a word should select the word and not additional spaces,
+ brackets etc (rt#5991)
+* kolab/issue2524: KMail: message window shows backslash for quoted-pairs
+* Don't crash when using menu item Action->Show after deselecting an incidence
+
+
+Friday, February 5th 2010
+
+Problems addressed
+------------------
+
+* kolab/issue1765: In parallel calender view there is no need to ask in which resource folder a new
+ event should get. (rt#5816)
+* kolab/issue4072: too small window: kleopatra: German export secret key (rt#5848)
+* kolab/issue4054: Umlauts and sending contacts problem (rt#5956)
+* kolab/issue4076: Mail: search for whole message cannot handle umlauts (rt#5979)
+* kolab/issue3817: Wish: New choices for the option KMail->Misc->Folder->When entering a folder (rt#5857)
+* kolab/issue4081: Use of many kmail subwindows can lead to crash (KMFolder::open) (rt#5854)
+* kolab/issue4052: copy+paste of an appointment in side-by-side view creates the appointment at a
+ wrong time. (rt#5951)
+* kolab/issue4084: Overwriting of an address in the To/CC/BCC field of a composer doesnt work with "Paste"
+ of a copied address (rt#5988)
+* In the archiving dialog, disable the Ok button if the wrong folder or no file is selected
+* Add a warning when trying to use the current folder as expiry target
+* Don't allow deleting 'no content' IMAP folders
+* Don't write out the unused revision field to the XML of events
+* Remove unmaintained Scalix and featureplan support
+
+
+Friday, January 29th 2010
+
+Problems addressed
+------------------
+
+* kolab/issue4044: Wish: Mail window should close after pressing on reply/forward (rt#5945)
+* kolab/issue4043: extended alarm: Own reminder dialog text is ignored
+* kolab/issue4053: reminder of an event with recurrence shows wrong date (rt#5953)
+* kolab/issue3989: Calendar: Attendee names with comma are handled wrongly (rt#5899)
+* kolab/issue4058: German translation of "No Suggestions" of the auto spellchecking is missing (rt#5964)
+
+
+Friday, January 22th 2010
+
+Problems addressed
+------------------
+
+* kolab/issue4004: calendar prints should contain a print date (rt#5927)
+* kolab/issue4033: calendar print: week-schedule big time numbers didn't fit the border
+* kolab/issue3901: Result of printing a day seems to be broken
+* kolab/issue4036: calendar print: tasks are wrongly printed
+* kolab/issue4038: After deletion of an event the small monthview is not updated
+* kolab/issue3805: Sometimes at the Mail save dialog no filename is created from the subject (rt#5851)
+* kolab/issue3989: Calendar: Attendee names with comma are handled wrongly (rt#5899)
+* kolab/issue1783: Invitation gets lost, if no Kalender resource is activated
+* kolab/issue4042: minutes field in the extended alarm dialog has a problem
+
+
+Friday, January 15th 2010
+
+Problems addressed
+------------------
+
+* kolab/issue3790: Crash in KMReaderWin::parseMsg at kmreaderwin.cpp:1609
+* kolab/issue4013: Make KMail-Archive format input the default (rt#5817)
+* kolab/issue3903: Kontact hangs when switching to calendar side-by-side view (rt#5870)
+* kolab/issue3986: event/todo recurrence option should be consistent (rt#5900)
+* kolab/issue4027: Kontact crahes if store event attachment inline (rt#5941)
+* kolab/issue3813: reccuring events show wrong dates (rt#5855)
+* kolab/issue4015: Archiving file selector does not keep the suggested file name when changing the directory (rt#5817)
+* kolab/issue4026: mail will be printed with wrong header, if it is printed from a mail window (rt#5935)
+* kolab/issue4014(partial): Better Archiving zip -> tar.bz2 default (rt#5817)
+* kolab/issue4029: Save a attachment of a mail from the composer: no filename (rt#5940)
+* kolab/issue4030: The filename of an UTF-16 text attachment is displayed wrongly (rt#5942)
+* Fix regression in KMail: Subfolders were never created in the mbox format, even when requested
+* In KMail, disable some actions that are not applicable to read-only folders
+* Allow to select read-only folders when archiving
+* Don't crash when attempting to archive a folder without selecting a file name
+
+
+Friday, January 1st 2010
+
+Problems addressed
+------------------
+
+* kolab/issue3988: Calendar: update mail of a changed attendee asked to reply (rt#5899)
+* kolab/issue3929: Contacts: The user can add a distribution list to itself
+* kolab/issue3747: Archiving function has a memory leak
+* kolab/issue4000: A user rejects a delegation, the delegator cannot react on this
+* kolab/issue3948: Show a 'record' button if the organizer is *not* expecting an rsvp (rt#5879)
+* kolab/issue3740: Selection jumps after deleting an attachment from an email
+* kolab/issue3959: In side-by-side view without Marcus Bains line is the seperator displaced (rt#5912)
+* Fix email address spoofing by not allowing BIDI control characters in the display name
+
+
+Friday, December 18th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3964(partial): An attendee of an event is not informed about his role or status in the event (rt#5893)
+* kolab/issue3994: The calendar/event view configuration dialog is too wide
+* kolab/issue3934: Reply of mail with signature removes the signature (rt#5887)
+* kolab/issue3973: Improvement of the German calendar import menu texts (rt#5812)
+* kolab/issue3961: Mail attachment of a task should be persistent (rt#5915)
+* kolab/issue4003: Crash after copying a mail to a quota full OnlineIMAP inbox
+* Fix priorities of todos stored on the Kolab server not being remembered properly after a restart
+
+
+Friday, December 11th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3985: Typos in German dialog "Ungültige E-Mail-Adresse" (rt#5898)
+* kolab/issue3972: Event print order will be wrong, if recurring and single events are mixed. (rt#5914)
+* kolab/issue3964(partial): An attendee of an event is not informed about his role or status in the event (rt#5893)
+* kolab/issue3961: Mail attachment of a task should be persistent (rt#5915)
+* Fix translation problem in the archiving function
+
+
+Friday, December 4th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3805: Sometimes at the Mail save dialog no filename is created from the subject (rt#5851)
+* kolab/issue3928: Insert signature at cursor position: Two additional empty lines added (rt#5880)
+* kolab/issue3971: Users dislike the "Cannot edit attachment" error message (rt#5908)
+* kolab/issue3948: Show a 'record' button if the organizer is *not* expecting an rsvp (rt#5879)
+* kolab/issue3984: New filter "*.*" for the save mail as dialog (rt#5896)
+* kolab/issue3813: reccuring events show wrong dates (rt#5855)
+
+
+Friday, November 27th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3747: Better archiving function for a branch (subtree) of folders (rt#5817)
+* kolab/issue3098: OnlineIMAP, sometimes Mail body no longer shown -> Crash
+* kolab/issue3969(partial): two offline warning windows - that might overlap and lock (rt#5917)
+* kolab/issue3978: Forwarding some emails with an embedded email as text loses some of the text (rt#5919)
+* kolab/issue3955: Kontact automaticly sends a mail to all attendees of an event without confirm
+* kolab/issue3958(partial): Copy action on the address of an open mail doesn't work (rt#5911)
+* kolab/issue3957: Improvement of German text in conditionally accepted events (rt#5905)
+
+
+Friday, November 13th 2009
+
+Problems addressed
+------------------
+
+* Work on the archiving function (kolab/issue3747).
+
+
+Friday, November 6th 2009
+
+Problems addressed
+------------------
+
+* Work on the archiving function (kolab/issue3747). Disabled from the GUI at the moment,
+ until it is completed.
+
+
+Friday, October 30th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3923(partial): Save as of an attachment of an invitation crashes kontact
+* kolab/issue3930: time on the Marcus Bains line doesn't change
+* kolab/issue3908(partial): Mail view and print layout problem if description of attachment is to long (rt#5872)
+* kolab/issue3926: Start khelpcenter instead of webbrowser help: from the introduction/welcome screen (rt#5881)
+* kolab/issue3481: Keep current email in front after saving an attachment (rt#5746)
+* kolab/issue3098: OnlineIMAP, sometimes Mail body no longer shown -> Crash
+
+
+Monday, October 26th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3065: Crash in KOAgendaItem::paintEvent
+* kolab/issue3902: Delete a folder while syncing leads to crash
+* kolab/issue3903: Kontact hangs when switching to calendar view (rt#5870)
+* kolab/issue3908 (partial): Mail view and print layout problem if description of attachment is to long (rt#5872)
+* kolab/issue3807: Reminder: None of the buttons should be the default (rt#5845)
+* kolab/issue3809: Reminder: sorting in look&feel of kontact (rt#5846)
+* kolab/issue3813: reccuring events show wrong dates (rt#5855)
+* kolab/issue3922: Decline an updated event throws error message
+* kolab/issue3864: An invitation of a long event shows a wrong duration.
+* kolab/issue3926 (partial): Start khelpcenter instead of webbrowser help: from the introduction/welcome screen (rt#5881)
+* kolab/issue3880: Calendar: In an update mail the end time of an event is wrongly translated with the "Beginn"
+* Don't check for forgotten attachments in invitation mails
+* Better context-aware messages when asking to send mail for adding/changing/removing invitations
+
+
+Friday, October 9th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3899: Selecting of an event and try to print the day of the event leads to crash
+* kolab/issue1499: using the result of an ldap query from the address selection dialog for setting folder
+ rights might fail (rt#5298)
+* kolab/issue3900: confirm dialog will be empty, if a contact without email address is added from the lookup
+* kolab/issue3667: attachment icon is missing in use with OL/toltec (rt#5786)
+
+Friday, October 2th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3783: SMIME encrypted and signed mail: Audit log dialog contains ???? at the bottom
+* kolab/issue3823: mimetreeviewer doesn't show structure of forward-as-attachment message #n where #n > 1
+* kolab/issue3889: Kontact crahes if opening/changing calendar view (rt#5868)
+* kolab/issue3867: Save S/MIME encrypted mails unencrypted after reading them
+* Also use new icons in the special dates summary, for birthday, anniversary and holiday
+
+
+Friday, September 25th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3806: The sorting of mails in the mailview changes after opening a configuration dialog (rt#5852)
+* kolab/issue3182: Replies to invitations always sent with default outgoing transport
+* kolab/issue3876: regression: New Message To: doesn't fill in To: field in composer
+
+
+Friday, September 18th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue2974: Anniversary event has broken title
+* kolab/issue3865: Crash while syncing, automatic event archival enabled, in EventArchiver::archiveIncidences
+* kolab/issue3853: Crash after renaming a folder
+* kolab/issue2069: Kontact rewrites custom folder types
+* kolab/issue3830: Mail: Setting option properties->share unread state with all users on an inbox doesn't have an effect
+* Add new KOrganizer icons for anniversary, birthday, holiday and special occassion
+
+
+Friday, September 11th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3853: Crash after renaming a folder
+* kolab/issue3836: Saved auditlog contains some strange xml text
+* kolab/issue3833: Mails will vanish, if a folder is renamed
+* kolab/issue3837: Reproducible crash when (not) decrypting s/mime message
+* kolab/issue3577: [regression] S/MIME opaque signed and encrypted email without smime-type parameter suboptimal display
+* kolab/issue3855: [regression] S/MIME opaque signed and encrypted email suboptimal display
+* kolab/issue3831: Forward inline: the header of the forwarded msg doesn't contain the CC
+ field and the time after the date (rt#5862)
+* Fix copying of an URL from KMail, which was a recent regression
+
+
+Monday, September 7th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3816: event view: some topics miss the colon after the topic name (rt#5855)
+* kolab/issue3788: Calendar: A default for the reminder option should be configurable (rt#5841)
+* kolab/issue3827: Address completion ldap, missing results from some sources (rt#5853)
+* kolab/issue3799: Freebusy authentication dialog appears in the background
+* kolab/issue3803: Reply-to field in composer has unused "..." button
+* Fix crash when completing LDAP addresses
+* Don't print "CC:" and "BCC:" in the enterprise header.
+
+
+Friday, August 28th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3359: LDAP Search result not coming in later, if user typed too fast in email completion (rt#5853)
+* kolab/issue3815: event view: dates are displayed without weekday (rt#5855)
+* kolab/issue3808: Reminder: small problems (rt#5845)
+* kolab/issue3816: event view: some topics miss the colon after the topic name (rt#5855)
+* kolab/issue3804: Configuration of Address completion order: Missing last-used addresses (rt#5856)
+* kolab/issue3821: [regression] kmail reader: cannot drag attachment icon anymore
+* kolab/issue3792: Local Folder for Groupware: Type setting partly lost by restart.
+* kolab/issue3822: Configuration of Address completion order: last-used-addresses by default shown one but last, though sorted last (rt#5856)
+* kolab/issue3671: Calendar: To Today button doesn't display a workweek right (rt#5769)
+* kolab/issue3254: printed mail cut at the left side
+* kolab/issue3812: Recent addresses of addresses with comma are displayed with backslash and quote
+* Fix regressions that images were not shown in the reader in KMail
+* Fix regression that shift-clicking an attachment in KMail wouldn't open it anymore
+
+
+Friday, August 21th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3811: Rejecting an invitation, with the event existing and writable by someone else,
+ Kontact will delete the event without question (rt#5803)
+* kolab/issue3722: Dragging emails to an existing appointment or tasks does not work (rt#5806)
+* kolab/issue3788: Calendar: A default for the reminder option should be configurable (rt#5841)
+* kolab/issue3608: Lastname of an attendee is missing (rt#5802)
+* kolab/issue3814: Completion order configuration for emails broken (rt#5856)
+* kolab/issue3819: Calendar Birthday resource: Anniversary day handling has small problems
+* kolab/issue3717: The attachment of an invitation isn't displayed
+
+
+Friday, August 14th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue1536: Default to the sender as organizer when it is not set
+* kolab/issue3717: Add support for attachments in invitations
+* kolab/issue3802: When updating incidences, preserve the UIDs so that the update is correctly registered
+* kolab/issue3808: Rename 'Dismiss' into 'Dismiss Reminder' in the reminder dialog
+* kolab/issue3375: Make the attachment overview less confusing by making a difference between embedded and
+ normal attachments
+* kolab/issue3776: Show the 'Record into my calendar' button on updated invitations when sharing
+ a calendar with others who have access rights
+
+
+Friday, August 7th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3685: Make it possible again to enter the update mail of a moved event into the calendar
+* kolab/issue3789: Show again the buttons for the 'Delegate', 'Forward' and 'Look into Calendar' actions
+* kolab/issue3234: Put optional participants of events into the CC field of the invitation mails, not into
+ the To field, to make Outlook happy
+* kolab/issue3779: Always allow an attendee to remove invitation events from his calendar
+* kolab/issue3788: Make the default time and time unit for new reminders configurable
+* kolab/issue3742: Allow to specify the groupware type of local folders again
+* kolab/issue3375: When using 'Scroll To' on attachments, mark the scrolled-to attachment with a yellow border
+* kolab/issue3776: Don't ask for the storage location on invitation updates
+* kolab/issue3740: When displaying encapsulated messages in a seperate window, make deleting attachments work
+ correctly
+* kolab/issue3722: When dragging email messages as attachments, try to use the mail subject
+ as the attachment name in the KOrganizer attachment editor.
+* Fix a problem that attachments in encapsulated messages could not be deleted
+* Don't erroneously display the text part of encapsulated messages as attachment in the quick attachment list
+* Add nicer icon for the organizer, replacing the old 'tux' icon
+
+
+Friday, July 31th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3722: Make dragging mails to existing appointments work
+* kolab/issue3759: Don't enable the Apply button in the to-do editor when opened from KMail
+* kolab/issue3719: Don't remove linebreaks from the comments on invitations
+* kolab/issue3780: Allow declining an invitation without getting an error message
+* kolab/issue3777: Fix crash when creating a new folder in KMail
+* kolab/issue3724: Possible fix a problem that when multiple persons have write access to a folder,
+ things were confused for other users
+* kolab/issue3725: When forwarding an encrypted mail, don't ask for the passphrase twice
+* kolab/issue3781: Allow to delete an accepted appointment without notifing the organizer
+
+
+Friday, July 24th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3718: Don't show the warning about too many recipients when sending invitations
+* kolab/issue3769: Don't crash when reading a free/busy list that was sent as mail
+* kolab/issue3771: In the attendee edit dialog, allow to edit the organizer field if it is empty
+* kolab/issue3744: Also recognize invitation attachments marked as text/x-vcalendar
+* kolab/issue3734: Allow to change the free/busy and active alarm setting of the default groupware
+ folders as well
+* kolab/issue3683: Fix the webpage export in KOrganizer not showing the right events
+* kolab/issue3735: Fix append-only IMAP folders leading to sync and conflict loops
+* kolab/issue3725: When forwarding encrypted mails, correctly include the attachments in the mail
+* kolab/issue3724: Fix various issues with invitations if you have access to a calendar of another
+ person that is also invited
+* kolab/issue3742: Don't show the combo box that changes the folder type for online IMAP folders, since
+ that is not supported there
+
+
+Friday, July 17th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3687: When printing from KOrganizer, make sure to include the Location
+* kolab/issue3756: Fix problems with reminders not showing up with freshly configured folders
+
+
+Sunday, July 12th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3722 (partly): Don't indicate that mails can be dropped to the attachment editor, that is not possible
+* kolab/issue3746: Fix summary not showing in an update mail and remove empty rectangle
+* kolab/issue3721: Fix incorrect translation for ical import tool
+
+
+Friday, June 26th 2009
+
+Problems addressed
+------------------
+
+* Fix problems with Free/Busy passwords that have a '!' in them.
+ This fix is in kdelibs, not in the enterprise branch.
+* Fix incompatibility with GPGME 1.2
+
+
+Friday, June 19th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3375: Fix attachment overview in the header being confusing for short mails
+* kolab/issue3578: Minimize the amount of key lookups in KMail, especially when not encrypting at all
+* kolab/issue3682: Fix a crash when displaying certain S/MIME messages
+
+
+Friday, June 12th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3685: Fix invitation handling regression, now the update mails of moved events can be
+ entered into the calendar again
+* kolab/issue3678: Speed up displaying of inline PGP encrypted messages
+* kolab/issue3694: Fix crash when displaying an invitation mail
+* kolab/issue3692: Fix crash when quickly closing the window displaying a signed message
+* Add info about the invitation options in KMail's handbook
+
+
+Friday, June 5th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3673: Switch to calendar component when choosing "Look into the calendar" in invitations
+* kolab/issue3636: Prevent creating incorrect maildir folders when using an IMAP account
+* kolab/issue3648: Syncing mails was slow and used a lot of memory
+* Don't block the UI when displaying signed or encrypted mail
+* Add select all and unselect all buttons to the filter importer/export in KMail
+
+
+Friday, May 22th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3615 (partly): Confusing warnings when evaluating key trust in KMail
+
+
+Friday, May 15th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3608: Lastname of an attendee is missing
+* kolab/issue3598: Holidays are not colored correctly
+* kolab/issue2972: Bogus error message when refreshing the IMAP cache
+* kolab/issue3617: Kleopatra's setting dialog cannot deal with gpgconf TYPE=0
+* Some spelling and whitespace fixes in the english version of the KOrganizer manual
+
+
+Friday, May 8th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3605: System tray icon displayed even when there is no unread mail
+* kolab/issue3606: Some common folder properties are missing
+* kolab/issue2459: Don't crash when refreshing the IMAP cache
+* kolab/issue3598: Public holiday description of events are missing
+* kolab/issue2276: Export contacts or calendar overwrites files without a warning
+* kolab/issue2150: Reply action missing in the message popup menu
+
+
+Thursday, April 30th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3228: Forwarding filter action does not directly send the email
+* kolab/issue3251: Fix the phone numbers of a contact in the XML, so that syncing with Toltec etc works
+* kolab/issue2931: Fix an incorrect translation
+* kolab/issue2963: Crash while deleting mails, in KMMoveCommand::execute
+* kolab/issue3268: Changes to the reply prefix would need a restart of KMail to work
+* kolab/issue2152: System tray doesn't react on the change of a folder configuration
+* Some fixes for the color settings in KOrganizer
+* Fix a small memory leak
+
+
+Friday, April 24th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue2472: (partly) Default event color is not used
+* kolab/issue3576: Crash in KOrganizer when switching to the month view
+* kolab/issue2501: Set the default month view color strategy to "calendar inside, category outside"
+* kolab/issue2508: Don't send an invitation when it the event can't be written
+* kolab/issue1819: The help link in the template configuration didn't work
+* Fix crashes in KAddressbook when undo/redo is used on a deleted resource
+* Implement a new (currently hidden) configuration option for making the frames of month or agenda items prettier
+* Fix various memory leaks
+* Correctly disable various buttons if clicking them would lead to no action or crashes
+
+
+Friday, April 17th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue1894: Default width of folder name column was too small on first start
+* kolab/issue2130: Displayed header type in the mail display is wrong
+* kolab/issue1838: Remove the What's this icon from Kontact
+* kolab/issue3303: Departement and title were not saved and restored
+* Reenable dragging of folders in KMail after an error
+* Fix various memory leaks
+* Correctly disable various buttons if clicking them would lead to no action or crashes
+* In KAddressbook, cancel saving when we didn't select a resource
+
+
+Friday, April 10th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3492: Default outgoing transport changes randomly when removing any outgoing account
+* kolab/issue1996: Composer text-completion: Cursor always jumps to the end of the entered text
+* kolab/issue3244: Crash at KMFolder::addMsg after a second import of testmails
+* In KMail, don't allow executing something when clicking on a URL in the reader
+* When formatting incidences, don't add "[Accept]" to it if it can't be accepted
+* In the attendee editor, disable "Response request" when the attendee is oneself
+* When address completion is disabled, don't search on the LDAP server when typing
+* When exporting addresses to vcard, ask before overwriting files
+* Fix small memory leaks in KMail
+
+
+Monday, April 6th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3051: Pressing Shift+R at a shown mail opens a composer with a reference to the mail
+* kolab/issue2238: D'n'D a contact on the contact sidebar icon should not be possible.
+* kolab/issue1940: Activating "unseen mails behind folder" sets the option "unread mails in own column"
+* kolab/issue3512: Kontact does not detect shared seen folder capabilty anymore
+* kolab/issue2687: After applying a new identity, the columns of the mail view reset
+* Other small improvements in the sieve script editor
+* Fix crash in the composer if the transport is empty
+* Fix enable/disable action when we are in template folder
+
+
+Friday, March 27th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3482: Kontact creates invitations with reminders for one week (1W) that Outlook 2003 does not understand
+* kolab/issue3263: Support custom templates when forwarding with filters, and also support fixed recipients for templates
+* kolab/issue3471: Copy menu entry doubled in context menu
+* kolab/issue3312: Crashes if a contact is changed with the contact editor
+* In KMail, fix crash when changing the configuration
+* When deleting templates in KMail, make sure they are removed from the configuration file
+* Remove one unnecessary sync in KNotes
+
+Merges
+------
+
+* Merge the forwarding fixes from enterprise4, to prevent corrupt mails after using filters for forwarding
+
+
+Friday, March 20th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3467: Frequent crash after editing notes
+* Eliminate some unnecessary groupware syncs in KNotes
+* Don't crash when using "Save As" in KNotes
+* Fix problems with notes being randomly recreated or randomly placed
+* Don't allow resizes when a note is locked
+* Disable "Find Text" and "Show/Hide All Notes" actions when there are no notes
+
+
+Friday, March 13th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue2685: Signature not recognised with combined OpenPGP encrypted/signed email
+* kolab/issue2444: Kontact sends base64 encoded password when sieve server does not advertise STARTTLS
+* kolab/issue1950: gpgme config dialog broken when /etc/gnupg/gpgconf.conf not empty
+* kolab/issue2628: For encrypted emails where no encryption was tried, it says "decryption impossible"
+* kolab/issue3477: Kontact creates bad invitations if attendee name with umlauts is entered with double quotes
+* In KNotes, disable actions when the note is locked
+* In KMail, consider marginally trusted keys as trusted, too
+
+
+Friday, March 6th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3367: Changing organizer's status doesn't work
+* kolab/issue3119: Black notes are displayed after system start
+* Don't allow selection of S/MIME certificates when we only want OpenPGP ones (and vice versa)
+* Avoid some unnecessary resyncs in KNotes
+* Don't enable undo/redo for locked notes
+* Don't allow to rename locked notes
+* Fix memory leak in the Kolab resource
+* Don't save the spellcheck coloring to the notes
+
+Merges
+------
+
+* Speed up folder syncing for disconnected IMAP by only uploading flags that really changed
+
+
+Friday, February 27th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3436: Fix crash in extractAuditLog in KMail.
+* kolab/issue3377: Issue warning when emailing to more than X recipients
+* Fix enabling/disabling of the Add/Remove Quote Characters actions.
+
+
+Friday, February 20th 2009
+
+Problems addressed
+------------------
+
+* Fix memory leak in KMail when reading signed or encrypted messages
+
+
+Friday, February 13th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3385 Reminder of an event doesn't work
+* kolab/issue2523 Export Calendar as Web Page: Date range empty by default, no warning
+* kolab/issue3065: Crash in KOAgendaItem::paintEvent
+
+Merges
+------
+
+* Add a cancel button to the reoccurence editor
+* Fix memory leak in KNotes
+* Disable various buttons if they have no effect, in KOrganizer, Knotes, KAddressbook and KMail
+
+
+Friday, February 6th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3374 Window behaviour of Kontact is undesirable sometimes if a message box comes up.
+* kolab/issue3376 Make gui for option ForwardingInlineByDefault
+* kolab/issue3386 Kontact requires that free/busy urls match email addresses
+
+
+Friday, January 30th 2009
+
+Problems addressed
+-------------------
+
+* kolab/issue3275 translation of "calendar" to "Kalendar" is wrong, should be "Kalender"
+
+Tuesday, January 20th 2009
+
+Problems addressed
+------------------
+
+* kolab/issue3304 Pasting a contact opens an edit dialog.
+* kolab/issue3345 Calendar: The default status of an organizer should be accepted.
+* kolab/issue2677 Misleading german translation "Die Terminordner gehören zur Identität"
+* kolab/issue2908 Wrong default name when renaming IMAP ressources
+* kolab/issue3219 user templates do not work, if the email has an attachment
+
+
+Sunday, December 21st 2008
+
+Problems addressed
+------------------
+
+* kolab/issue3306 "No attendees" behind the title of a new event or task not translated into German.
+* kolab/issue3297 If kontact is started via knotes, knotes sometimes crashed while renaming a note
+* kolab/issue2962 Composer text snippets: Add/Edit group, snippet text "GROUP" is not translated into German.
+* kolab/issue3324 can delete attachments in read-only folders
+* kolab/issue3316 Doubled folder lists in move-to filteraction selection dialog
+* kolab/issue3314 Contact folder selection state not saved between KDE sessions
+* kolab/issue3084 An organizor of an event cannot change his status
+* kolab/issue1783 Invitation get lost, if no Kalender resource is activated
+
+Friday, December 12th 2008
+
+Problems addressed
+-------------------
+
+* kolab/issue3276 cannot encrypt to marginally trusted OpenPGP key, with email address not in key and key in contact entry ( part fix )
+* kolab/issue3305 Double click on a distribution list in the distribution list editor should open an edit dialog
+* kolab/issue2048 Distribution list: couldn't delete a contact from a dist list with pressing on "delete"
+
+Wednesday, December 3rd 2008
+
+Problems addressed
+------------------
+
+* kolab/issue3228 forwarding filter action does not directly send the email
+* kolab/issue1950 Kontact: gpgme config dialog broken when /etc/gnupg/gpgconf.conf not empty
+* kolab/issue3195 Sending a mail encrypted and signed with an expired Openpgp key shows confusing dialog
+* kolab/issue3265 OpenPGP key expiry warning not emitted for signing keys) Editing
+* kolab/issue2472 ("Default event color" is not used
+* kolab/issue3143 (s/mime invalid keys are accepted by KMail and shown green in kleo (certmanager/lib/ui/keyselectiondialog.cpp)
+* kolab/issue3249 (Strange crash while replying to an SMIME mail.
+* kolab/issue3281 (Kontact does not quote CNs in iCalendar mails, which Outlook 2003 (OL 2K3) then fails to recognise
+
+Friday, November 21st 2008
+
+Problems addressed
+------------------
+
+* kolab/issue2627 Status line for audit log shown, even when it is not implemented.
+* kolab/issue2617 Kleopatra: After importing a p7c or p12 file the user is informed, that he has imported 0 certifictes.
+* kolab/issue2620 Kleopatra throws an error message, if no .gnupg exists and no agent is running.
+
+
+Tuesday, November 19th 2008
+
+Problems addressed
+-------------------
+
+* kolab/issue3196 large number of appointments can lead to corrupt index and loss of events.
+
+Sunday, November 9th 2008
+
+Problems addressed
+------------------
+
+* kolab/issue2627 Status line for audit log shown, even when it is not implemented.
+*Support the /vendor/cmu/cyrus-imapd/sharedseen annotation available in Cyrus IMAP server 2.3.9 or higher which allows to share the seen flags between all users that have access to a folder.
+* Detect if the server supports shared seen flags. Also preserve the IMAP server capabilities in kmailrc so that detection also works without a prior sync.
+
+
+
+Monday, October 27th 2008
+
+Problems addressed
+-------------------
+
+* kolab/issue2230 Summary: Can select summaries of parts in the summary configuration dialog, which are deactivated in the components dialog.
+* kolab/issue2947 Kontact crashes by opening an added attachment file.
+
+
+Friday, October 17th 2008
+
+Problems addressed
+-------------------
+* kolab/issue2702 (calendar: After deleting an attendee no remaining attendee is selected.
+* kolab/issue3127 (Cannot open a mail d'n'ded to the desktop and then cannot restart kontact
+* kolab/issue2875 (Better guide the user to find S/MIME certificate manager when trying to encrypt email
+
+
+
+Friday, October 3rd 2008
+
+Problems addressed
+-------------------
+* kolab/issue2936 Document non-gui OutOfOffice settings for enterprise35.
+* kolab/issue1570 Make standard identity the default in the "Select Address" dialog
+* kolab/issue2501 Calendar: events in the month view are displayed in wrong colors
+* kolab/issue2472 "Default event color" is not used
+* kolab/issue2314 documentation of snippets missing, especially for the variable substitution
+* kolab/issue2962 Composer text snippets: Add/Edit group, snippet text "GROUP" is not translated into German.
+* kolab/issue2389 contact: After creating a new contact, while I have to select a contact resource the cursor is a clock.
+* kolab/issue2989 normal reminder changes to advanced reminder unexpectedly
+* kolab/issue1589 "Keep replies in this folder" not honored when replying with identity not matching original recipients
+* kolab/issue2614 The context menu of the favorite folder view and the folder view should be more similar
+
+
+Friday, September 26th 2008
+
+Problems addressed
+-------------------
+
+*kolab/issue2989 normal reminder changes to advanced reminder unexpectedly
+
+Friday, September 19th 2008
+
+Problems addressed
+-------------------
+* kolab/issue2830 Default identity used for invitation even if other identity is set as organizer.
+* kolab/issue2577 An invitation to a recurring event should give information about the recurrance.
+* kolab/issue1828 Printing event doesn't print list of attachment.
+
+
+Friday, September 12th 2008
+
+Problems addressed
+-------------------
+* kolab/issue2792 kontact sometimes doesn't display a shared folder
+
+Monday, September 8th 2008
+
+Problems addressed
+------------------
+* kolab/issue3024 Crash in KCal::Incidence::revision.
+
+Friday, August 29th 2008
+
+Problems addressed
+------------------
+
+* kolab/issue2680 Counter proposal: A user should be notified about an accepted counter proposal.
+* kolab/issue2625 Sync with the new sync button for emails stays offline without message.
+* kolab/issue2514 Moving a event and pressing "Cancel" in the send mail dialog, doesn't cancel the operation.
+* kolab/issue2489 Synchronize Calendar button always syncs all servers.
+* kolab/issue2111 Help->Feature Request looks for a non-existing page.
+* kolab/issue2655 Fast pressing "Down Arrow" Key in the address lookup of the composer selects an address in the "to" field.
+
+
+Saturday, August 23rd 2008
+
+Problems addressed
+------------------
+kolab/issue2927 Opened mails/composer are not reopened after a restart.
+kolab/issue2675 Calendar side-by-side view: scale doesn't fit with the hours view.
+
+
+
+Friday, August 22nd 2008
+
+Problems addressed
+------------------
+* kolab/issue2954 Possible to delete a mail if just max append rights.
+* kolab/issue2036 Press "cancel" at the calender folder selection deletes an updated event.
+
+
+
+Friday, August 13th 2008
+
+Problems addressed
+------------------
+
+* kolab/issue2933 Creating folder with a old folder name can trigger a crash.
+* kolab/issue2850 Crash while copying a mail to a read-only folder.
+* kolab/issue2904 Calender component reloads all events, e.g. after switching to todos and back.
+
+Friday, August 1st 2008
+
+Problems addressed
+------------------
+
+* kolab/issue2951 The name of the event which was created by d'n'd of a todo is "BEGIN:VCALENDAR".
+* kolab/issue2904 calender component reloads all events, e.g. after switching to todos and back.
+
+
+Friday, July 25th 2008
+
+Problems addressed
+-------------------
+
+* kolab/issue2866 In the todo summary a todo is shown which was deleted.
+* kolab/issue2867 Todos: Often deleted todos reappear.
+
+Monday, July 22nd 2008
+
+Problems addressed
+-------------------
+
+kolab/issue2801 Kontact doubles mails if a filter is used and every mail is filtered.
+kolab/issue2868 The name of the todo which was created by d'n'd of an event is "BEGIN:VCALENDAR"
+
+Friday, July 11th 2008
+
+Problems addressed
+-------------------
+
+* kolab/issue2522 Pressing ESC while moving a contact, deletes the contact.
+* kolab/issue2607 sync loop after deactivation of autosync.
+* kolab/issue2666 Deactivated calendar resources are reactivated after restart.
+
+Merges
+------
+* Enterprise branch is in sync with kdepim 3.5 branch
+* Bugfixes from enterprise ported to 3.5 branch
+
+Friday, July 4th 2008
+
+Problems addressed
+--------------------
+* kolab/issue2512 Kmail: "Subscription" should be renamed in "Serverside subscription"
+* kolab/issue2741 Button to do an ldap lookup is missing from the address selection dialog.
+* kolab/issue2511 Pressing "New" in the new event attendee view should not continue to create new attendees, if the first example attendee is not changed.
+
+Merges
+------
+
+* Enterprise branch is in sync with kdepim 3.5 branch
+
+Friday, June 27th 2008
+
+Problems addressed
+--------------------
+* kolab/issue2785 favorite folder: Two creation ways show different names.
+* kolab/issue2790 Strange date/time field in the new todo dialog.
+* kolab/issue2568 Button to open certificate manager is missing from encryption key dialog.
+* kolab/issue1998 An invitation via a server distribution list, cannot be accepted by attendees as they cannot choose one of their own identity.
+* kolab/issue2741 Button to do an ldap lookup is missing from the address selection dialog.
+* kolab/issue2618 Kleopatra: the dump of smime certificates doesn't contain the email addresses.
+* kolab/issue2773 Usability of "Order of Arrival" string?
+* kolab/issue2740 kleopatra shows an error message, if started and the search is on "In External Certificates"
+
+
+Friday, June 16th 2008
+
+Problems addressed
+--------------------
+
+* kolab/issue2506 Typo in the display of a smime signed mail.
+* kolab/issue2512 Kmail: "Subscription" should be renamed in "Serverside subscription"
+* kolab/issue2511 Pressing "New" in the new event attendee view should not continue to create new attendees, if the first example attendee is not changed.
+* kolab/issue2659 Copying and moving contacts with only one resource configured.
+* kolab/issue2741 Button to do an ldap lookup is missing from the address selection dialog
+* kolab/issue2619 Kleopatra: Trying to create a smime key pair with a "+" in the CN, fails without a warning.
+* kolab/issue2568 Button to open certificate manager is missing from encryption key dialog
+
+Merges
+--------
+
+* Enterprise branch is in sync with kdepim 3.5 branch
+
+Friday, May 30th 2008
+
+Problems addressed
+---------------------
+* kolab/issue2717 - Composer option "Insert signatures above quoted text" doesn't work. Implemented for replytoall for consistency.
+
+
+Merges
+-------
+* Enterprise in sync with kdepim 3.5 branch.
+
+
+
+Tuesday, May 20th 2008
+
+Problems addressed
+--------------------
+* kolab/issue2667 - Kontact sometimes tries to re-create existing folders and fails. (807761)
+* kolab/issue2717 - Composer option "Insert signatures above quoted text" doesn't work. (810237)
+
+Merges
+-------
+
+* Enterprise in sync with kdepim 3.5 branch.
+
+
+Friday, May 9th 2008
+
+Problems addressed
+-------------------
+
+* kolab/issue2560 Unsuccessful Sieve connection causes strange Progress Dialog.(804616)
+* kolab/issue2675 Calendar side-by-side view: scale doesn't fit with the hours view.(804642)
+* kolab/issue2669 (Profile does not save background color of emails.(804994)
+* kolab/issue2148 (counterproposal event should be inserted into the calender
+* Kolab issues 2148, 2678, 2681, 2683, 2680 - Counter proposal issues. (805191,805702)
+* kolab/issue2247 (Command line switch to choose Kontact profile (W1-32) (805348)
+
+Merges
+--------
+
+* Enterprise in sync with kdepim 3.5 branch.
+
+
+Saturday, May 3rd 2008
+
+Merges
+-------
+
+* Enterprise in sync with kdepim 3.5 branch.
+
+Monday, April 28th 2008
+
+Problems addressed
+-----------------------
+
+* kolab/issue2585 contacts of a LDAP resource folder should be seen in the mail address text completion of a composer
+* kolab/issue2443 kontact aborts sieve when imapd sends capabilities after starttls
+* kolab/issue2608 Calendar: counter proposal is not sent to the organizer
+* KDE bug 126025: Replying to address with umlaut and comma creates two addressees
+
+
+Friday, April 18th 2008
+
+Problems addressed
+-----------------------
+
+* kolab/issue2630 calendar: Wrong scrolling in the side-by-side view.
+* kolab/issue2629 calendar: At the headers of a week in the side-by-side view are not above the right columns
+
+Merges
+-------
+* Merges in from 3.5 branch.
+
+
+
+Friday, April 11th 2008
+
+Problems addressed
+-----------------------
+
+* kolab/issue2272 - Event Attendee Editor: After "Zoom To Fit" and zoom it is possible to scroll the fb part without the attendee part. (794734)
+* kolab/issue1869 (side-by-side calender view size depends on folder path length.(795745)
+* kolab/issue1883 (wasting space with many time scales in side-by-side-view.(795745)
+* kolab/issue1947 (calendar side-by-side view: superfluous scrollbars in the dayappointments.(795745)
+* kolab/issue1948 (calendar side-by-side view: wasting space by several scrollbars? Fix one grid option.(795745)
+* kolab/issue2561 (Side-By-Side view: the view of some folders are of different size.(795745)
+
+
+Friday, April 4th 2008
+
+Problems addressed
+--------------------
+
+* kolab/issue2577 An invitation to a recurring event should give information about the recurrance. (792202)
+* kolab/issue2581 The reject counter proposal mail is send to a wrong account.(792230)
+* kolab/issue2580 A user cancels a counterpropsal and the invitation mail is gone. (792231)
+* kolab/issue2582 After pressing "decline" in the counter proposal dialog and sending the counter proposal the event can be found in the calendar. (792950)
+* kolab/issue2578 After deletion of an event the organizer gets a mail, that some attendee accepted the event. (792957)
+
+
+
+Saturday, March 29st 2008
+
+Problems addressed
+------------------
+* kolab/issue2231 - Edit event: After adding and removing an mail address, an update mail is send to the address.
+* kolab/issue2217 - "open" button/funcationality in full search window missing (Z37)
+* kolab/issue2566 - Translation Error: German key
+* kolab/issue2565 - appointment dialog text quirks
+* kolab/issue2148 - counterproposal event should be inserted into the calender
+* kolab/issue2147 - There should exist two kind of counter proposals
+* kolab/issue2149 - A counterproposal should be displayed in a way, that the organizer understands.
+
+
+Friday, March 21st 2008
+
+Problems addressed
+------------------
+* kolab/issue1826 - Default (New Mail) template needs 3 spaces between the top and the signature.
+* kolab/issue2290 - Should warn and offer to change if there are two *.default groupware folders in one account.
+* kolab/issue2272 - Event Attendee Editor: After "Zoom To Fit" and zoom it is possible to scroll the fb part without the attendee part.
+
+
+Friday, March 14th 2008
+
+Problems addressed
+-------------------
+* kolab/issue1770 Delete attachment of a signed mail doesn't work. (783303)
+* kolab/issue2533 Reproducible crash in KMail::MessageProperty::filtering when refreshing IMAP cache. (784547)
+* kolab/issue2239 Addressbook extension doesn't recognise the deletion of a contact folder.(785317)
+* KDE Bug 146679 Can't set negative absolute hours - fixed. (785054)
+* kolab/issue2168 Email attachment overlay view, header style "enterprise" : Should be made foldable.
+* kolab/issue2529 Email attachment overlay view, header style "enterprise": fold button should vanish, if the mail has no attachments.
+
+
+
+Friday, March 7th 2008
+
+Problems addressed
+-------------------
+
+* kolab/issue2297 New event: Organisor is not attendee. (781595)
+* kolab/issue1988 Deleting a event should remove the deleter from the attendee list.(782029)
+* kolab/issue2443 kontact aborts sieve when imapd sends capabilities after starttls. (782672)
+
+Merges
+------
+
+* Merge35 Filter source folder whitelist (from proko2 ). (783244)
+
+Friday, February 29th 2008
+
+Problems addressed
+-------------------
+
+* Prevent crash after changing the layout and replying then. (778728)
+* kolab/issue2442 kolab/issue2442 (kioslave crashs after closing kontact, if the vacation reminder is activated. (779694)
+* "Enterprise headers" makes impossible to select text in first paragraph of body. [ kde-bug#151150 ] (779994)
+* kolab/issue1700 kleopatra crashes after ldap search. (780211)
+* kolab/issue2168 Email attachment overlay view, header style "enterprise" : Should be made foldable (780250)
+* kolab/issue2413 Kmail: Cannot select "Mark Thread" in the popup menu if I select two or more threads. (780251)
+* kolab/issue2312 Rejecting an invitation does not always work (780286)
+
+Merges
+---------
+* Merges in from 3.5 branch
+
+Friday, February 22nd 2008
+
+Problems addressed
+------------------
+* Prevent the message in the reader window from jumping back to the start of the message when the font or the font size is changed in the separate reader window.
+
+Merges
+------
+
+* Merges in from 3.5 branch.
+
+Friday, February 15th 2008
+
+Problems addressed
+-------------------
+* kolab/issue2160 contact view: move distribution list and addressbook view menu item to "views" (775026)
+* kolab/issue2477 Contacts: The Dist lists view is at the right side of the contacts list view. (775016)
+* Fixed cached imap local subscription so that it works for top-level folders.(774162)
+* Fixed the problem that filtering with online IMAP stopped after the first message had been processed.(773733)
+
+Merges
+------
+
+* Merges in from 3.5 branch.
+
+Friday, February 8th 2008
+
+Problems addressed
+-------------------
+
+* kolab/issue1981 Context menu entry "Paste" in kalender view
+* kolab/issue2260 New resource calendar folder default colors
+* Fix message status change randomly not working for non-toplevel mails
+* Really apply the identity when we edit a received message
+* kolab/issue2394 IMAP sync keeps calendar items which are deleted on the server
+* kolab/issue2450 Kmail: D'n'D and "Move To" from a read only folder is possible
+* kolab/issue2092 A latin-9 attachment is treated like a utf-8 file
+* Fix reply actions being disabled when a collapsed thread is selected
+* kolab/issue2390 contact: Two resources on the same server could looks like the same source in the contact view
+
+
+Friday, February 1st 2008
+
+Problems addressed
+-------------------
+
+* kolab/issue2036 Press "cancel" at the calender folder selection deletes an updated event. (768070)
+* kolab/issue2214 Creating a calender in local folder where the user have no rights shouldn't be possible.(768402)
+* kolab/issue2433 Debug log of kio_sieve shows password in base64. (768539)
+* kolab/issue2387 Crash when creating a subfolder of the calendar folder.(768738)
+* kolab/issue1841 Changing composer wrap margin does not affect currently open composer.(769033)
+* kolab/issue1843 Resized composer window snaps back if settings are changed.(769035)
+* kolab/issue2166 Rename "Create Task ..." to something that resembled "resubmission" or "reminder".(769042)
+* kolab/issue2159 Configure option: distribution list view and addressbook view under or left of the main list of contacts.(769058)
+* kolab/issue2167 New tasks should have reminder and until time set by default.(769058)
+
+Monday, January 28th 2008
+
+Warning
+--------
+The account password is shown in the debug output (See kolab/issue2344).
+Solution is to use "kdebugdialog" and switch "kio_sieve" off.
+
+Problems addressed
+-------------------
+
+* kolab/issue2387 Crash when creating a subfolder of the calendar folder. (767033)
+
+* kolab/issue2269 After locally unsubscribed a shared folder, the grey "user" and the grey "ltest1" folder didn't vanish. (765237)
+
+* kolab/issue2216 Crash in KMFolderSearch::addSerNum (764894)
+
+* kolab/issue2403 Forwarded or Delegated event not displayed correctly.(764828)
+
+* kolab/issue2405 Printing a encrypted mail should be possible (764404)
+
+Merges
+-------
+
+Merging complete with respect to 3.5 branch.
+
+Friday, January 18th 2008
+
+Problems addressed
+-------------------
+
+* kolab/issue2275 upgrade removed groupware resources.( 745813 )
+
+* kolab/issue2306 Crash below KMReaderWin::parseMsg after fast navigation through mails (746845)
+
+* kolab/issue2313 Crashed when subscribing new folders (e.g. in KMFolderMgr::removeFolderAux()) ( 746873 )
+
+* kolab/issue2173 "Copy contact to" and "Move contact to" have the same icons. ( 746925 )
+
+* kolab/issue2146 Kontact evaluates HTML tags in Contacts ( 747182 )
+
+* kolab/issue2182 Kontact shows misleading error messages for a mail encrypted with unsupported cyphers. ( 747318 )
+
+* kolab/issue2262 Crash below SnippetWidget::slotAdd()) (747340)
+
+* kolab/issue2286 Crash below KMail::CachedImapJob::slotPutMessageInfoData after working with tasks. ( 747584 )
+
+* kolab/issue2299 Sending a mail with softbreaks inserts newlines into this mail. (748016)
+
+* kolab/issue2220 "Action Item" and "Important" flag of mails behave different, if a folder is shared with read rights. (748416)
+
+* kolab/issue2344 Kontact crash on Deleting messages which are attachments shown in message viewer. (748425)
+
+* kolab/issue2191 filters lose conditions. (748479)
+
+* kolab/issue2004 Kontact, contact component: minsize of some components too wide (748501)
+
+* kolab/issue2061 three buttons lead to too large minimum width (in contact, calender and journal view). (748501)
+
+* kolab/issue2161 contacts view: distribution list view: Should have the usual buttons (748529)
+
+* kolab/issue2348 Crash on "checking" ToDo in calendar view (750031)
+
+* kolab/issue2304 Adding new attendees should be easier by clicking. (750093)
+
+* kolab/issue2301 Contacts: Undo asks to select a folder, after cutting some contacts. (750101)
+
+* kolab/issue2178 After inserting a text component to a mail the cursor should be at the end of this text component not at the beginning. (750499)
+
+* kolab/issue2169 Email header style "enterprise" does not jump to all email attachments (750562)
+
+* kolab/issue2008 Export of kontact profiles doesn't work. (750648)
+
+* kolab/issue1870 Display of whole day events in side-by-side view shows rubbish. (750879)
+
+* kolab/issue1952 favorite folder view: clicking on groupware folder should jump to corresponding view. (750904)
+
+* kolab/issue2379 Favorite todo folder: If the folder is already selected, clicking on it doesn't change the view. ( 758955 )
+
+* kolab/issue 2399 "Out of Office" reply reminder is activated althrough "Out of Office "reply is not activated. ( 762310 )
+
+* kolab/issue 2401 D'n'D attachment of a mail to the desktop: copy lots of different files to the desktop.( 762653 )
+
+* kolab/issue2195 German translation in kontact's Calendar box (long, Deppenapostroph). ( 762985 )
+
+
+
+Merges
+-------
+* More merges from all of kdepim.
+
+Monday, December 4th 2007
+
+Problems addressed
+--------------------
+
+* kolab/issue2260 Use better category and resource colors, make the list of default colors configurable, change the default working time color. (744677)
+
+New functionality
+-------------------
+
+* prokde35-z Item 60: Merge of the attachments and recurrence tabs into the main one, according to the usability suggestions and additional comments from the usability team. D'n'd and c'n'p support for attachments. (revision 742613)
+
+* prokde35-z Item 65: Merge of the attendee and free-busy tabs into the main one, according to the usability suggestions and additional comments from the usability team (revision 744005)
+
+* prokde35-z Item 61: Implementation of the xfb concept (revision 744092)
+
+* prokde35-z Item 203: implementation of the concept for better error messages for crypto operations (audit log) (revision 743026)
+
+* prokde35-z Item 32: Separate the recipients editor with a splitter, so the number of visible recipients can be freely configured (revision 744676)
+
+
+Friday, November 23rd 2007
+
+Problems addressed
+--------------------
+* kolab/issue2224 (Crash: KMFolder::countUnread, after hide groupware folders and sync) (739114)
+* kolab/issue1864 (Edit Categories not working when creating a new event) (739670)
+
+New functionality
+-------------------
+* prokde35-z Item 36: Clearer descriptions for search/filter criteria (738629)
+* prokde35-z Item 25: "Edit" for received mails. (739063)
+* prokde35-z Item 37: Make the splitters a bit more sensible, by preventing total collapsing, where it makes sense. (739069)
+* prokde35-z Item 26: per-account identities (739135)
+* prokde35-z Item 18: more and better configurable message actions on the main reader window (739157)
+* prokde35-z Item 53: Improved coloring of agenda view items (739603)
+* prokde35-z Item 50: Default colors for calendar resources (739689)
+* prokde35-z Item 79 (part 2): Statusbar indicator for active vacation scripts (740023)
+* prokde35-z Item 60 Allow files to be dropped onto the attachment view and ask whether they should be attached by link or by value. Implement dragging out of the view.
+
+Friday, November 16th 2007
+
+Problems addressed
+--------------------
+* kolab/issue2200 (After editing the attendee list the old attendes gets update mails without the possibility to enter them into their calender.) (737072)
+
+New functionality
+-------------------
+* prokde35-z Item 75: Aggregated reminders (737035)
+* prokde35-z Item 3: Hide no-content folders only containing groupware folders (737469)
+
+Merges
+---------
+* Merges from 3.5 branch for KMail, KAlarm, aKregator, KArm
+
+
+Friday, November 9th 2007
+
+Problems addressed
+--------------------
+* kolab/issue2123 Make sure the re-generated index is actually written out, to avoid crashes on switching out of the folder, and related unpleasantness. (732422)
+* kolab/issue2142 ( part 1 ) Make sure the file selector is shown on top of the filter dialog. (732794)
+* crash when there is no smime backend, and the protocol can't be determined.(733049 )
+* kolab/issue2151 Fix creation of new folders when restarting KMail before the next sync. ( 733149 )
+* kolab/issue2142 ( part 2 ) Provide a proper parent for the "ask to overwrite" dialog.(733495)
+* kolab/issue 2176 Move transaction code into the filtermanager, from the caller and make sure filter counts are written to and read from the right section. ( 733511 )
+* kolab/issue2175 Show an error message if the to-be-imported filters file can't be read. (733519 )
+* kolab/issue2181 Fix crash when opening a message without a parent, cleanup initialization order.(734247)
+
+New functionality
+-------------------
+* Prokde35-z Item 69 Allow comments to be given when reacting to invitations (733159)
+* Prokde35-z Item 68 (part 1) Make it configurable whether invitation emails are move to the trash once the reply to them has been sent and add gui for that to the groupware section of the main configuration dialog. (733883)
+* Prokde35-z Item 73: Show changes made by the organizer when showing invitation updates. (734580)
+
+Merges
+---------
+* Merges from 3.5 branch for KMail and KAlarm.
+
+
+
+Friday, November 2nd 2007
+
+Problems addressed
+------------------
+* kolab/issue2151 Creating a subfolder doesn't work correctly
+
+New functionality
+------------------
+* Prokde35-z Item 49: "Store Contact In" -> "Copy Contact To" and "Move Contact To" (729611)
+* Prokde35-z Item 201: Allow dragging of attachments from composer windows (729661)
+* Prokde35-z Item 203 (part 1): Port KMail from cryptplug to kleo (731701)
+* Add the ability to associate keyboard shortcuts with snippets. (731716)
+* Add a GUI option for syncing groupware changes immediately (731653)
+
+Friday, October 26th 2007
+
+Problems addressed
+------------------
+* ensure that tooltips also work on the main folder tree
+ and show quota info properly (729284)
+* kolab/issue2108 (Kontact sends broken invitation email.) Explicitely disable
+ word wrapping, instead of toggeling, where appropriate.
+
+New functionality
+------------------
+* Prokde35-z Item 16: Filter import/export (728541)
+* Prokde35-z Item 37: Open search results in standalone reader,
+ when preview pane is hidden (729306)
+
+
+Friday, October 12th 2007
+
+Problems addressed
+------------------
+* kolab/issue1941 (slow LDAP server lookup clears the To: field)
+ Don't overwrite the user selection if LDAP search results come in delayed.
+* kolab/issue2035 (Manage Sieve Script: Couldn't activate a script.) Allow
+ activation of sieve scripts when none are currently active
+* kolab/issue2042 (Not possible to create a new contact) Fix creation of
+ new contacts in kolab resources
+* kolab/issue2045 (Sending unencrypted, unsigned mail to myself throws warning)
+ Fix problems with ecnryption to untrusted keys
+* kolab/issue2046 (Crash: Try to copy an attachment to the konqueror)
+ Fix crash on drag
+* kolab/issue2067 (Kontact doubles mails when filter is used.) Make sure
+ to persist the list of deleted uids
+
+
+New functionality
+------------------
+
+* Prokde35-Z Item 55d: Immediately sync groupware changes (revision 723653)
+* Prokde35-z Item 27: Softbreaking in the kmail editor when no hardbreak limit is set (724153)
+* Prokde35-z Item 19: Raise hardbreak limit from 78 to 255 (724155)
+* Change the default for what to select on entering a folder to "last selected" from "jump to new".
+
+Merges
+------
+
+* kolab/issue1904 don't crash on shutdown if the kernel is already deleted
+* kolab/issue1942 Allow not fully trusted keys to be used for encryption, but ask the user to confirm their use.
+
+
+Wednesday, September 26st 2007
+
+Bugfixes
+--------
+
+* kolab/issue1983 Fix encoding issue in SMIME encryption message.
+* kolab/issue1924 Retain state of the crypto state indicators across drafts.
+* KDE bug 132938 Avoid asking the user to go online spuriously/
+* kolab/issue1743 Fix upload of out-of-office scripts (716765)
+* kolab/issue2023 Missing accelarators in text snippet context menu (716933)
+* kolab/issue2009 Fix new/unread flag handling during DIMAP sync (717162)
+* kolab/issue2029 Allow to hide signature details again (717191)
+
+Features
+--------
+
+* prokde35-z item 70: Check calendar link in invitations (714358)
+* prokde35-z item 30: Text snippet support in the kmail composer window (715206)
+* prokde35-z item 47: Support for read only contacts folders (715588)
+* prokde35-z item 67: Support for invitation counter proposals (716376)
+* prokde35-z item 21: D'n'D out of the folder view, removal of the "save encoded" menu entry (716393)
+* prokde35-z item 7: Close application despite presence of a system tray icon, configurably (716415)
+* prokde35-z item 40: Details on demand for pgp/smime signature status (716476)
+* prokde35-z item 79: Warn about active out-of-office scripts on startup (716765)
+* prokde35-z item 17: Better error reporting for quota errors (716771)
+* prokde35-z item 24: New attachment view in mail viewer (717292)
+
+
+Friday, September 21st 2007
+
+Bugfixes
+--------
+
+* kolab/issue1983 Fix encoding issue in SMIME encryption message.
+
+* kolab/issue1924 Retain state of the crypto state indicators across drafts.
+
+* KDE bug 132938 Avoid asking the user to go online spuriously/
+
+Features
+--------
+
+* prokde35-z item 70: Check calendar link in invitations (714358)
+
+* prokde35-z item 30: Text snippet support in the kmail composer window (715206)
+
+
+Friday, September 14th 2007
+
+Features
+--------
+
+* Make the maximum attachment size configurable by a non-gui (kioskable) option
+ and change the wording of the warning dialog to refer folks to their admin,
+ rather than blaming KMail for the limitation.
+
+Bugfixes
+--------
+
+* prokde35 W1-32 fixes for global profiling handling
+
+* kolab/issue896 Change the summary view title to "To-Do" from "To-do List" for consistency with the side bar.
+
+* Bump the kontact plugin version to reflect the profile loading changes and
+ update the version in those plugins we ship. Fixed crashes from basket on
+ startup in kubuntu, for example.
+
+* Make favourite folder area work with multiple main windows
+
+* kolab/issue1955 Fix crash when closing KMail.
+
+* kolab/issue1963, 1964 Make the create task action available in separate reader windows and the toolbar.
+
+* kolab/issue1984 fill distribution list listview delayed to avoid crash
+
+* kolab/issue1983 Make on-demand decrytion also work with SMIME.
+
+Merges
+------
+
+* Merge kalarm from 3.5 r708803-709812
+
+
+Friday, September 7th 2007
+
+Features
+--------
+* prokde35-z item 58: Rename "time associated" to "add-day event" and invert logic (706869)
+* Limit attachment size to a sensible value (upstreaming old SUSE patches, this one originally by Waldo Bastian). (706920)
+* prokde35-z feature 46: Rework distribution list integration in KAddressBook, add support for multiple active extensions (708034)
+* prokde35-z item 41: Decrypt messages only if requested (some prettification still pending) (708741)
+* prokde35-z item 9: third part: allow to disable local flags in read-only folders (708749)
+* prokde35-z item 2: Better and shorter resource folder names, showing the folder's owner (709038)
+* prokde35-z item 11: Message flags can be toggled by clicking into the corresponding header view columns (709066)
+* prokde35-z item 48: Allow adding LDAP entries to distribution lists from the LDAP search dialog. Add the ability to import LDAP contacts into the addressbook. (709092)
+* prokde35-z itme 42: Show colored indicators of signature and encryption state above the editor area (709142)
+
+Bugfixes
+--------
+* kolab/issue1376: fix \Seen flag handling on initial folder download (708706)
+* kolab/issue1924: encryption type is not stored if mail is saved to draft (709084)
+
+Merges
+------
+* Merge of kpilot fixed in 3.5 trunk (707923)
+* Merge of changes that help with folder open/close reference counting debugging (mostly from the SuSE team) (707659)
+
+
+Friday, August 31st 2007
+
+Features
+--------
+* Scalix support for Kontact.
+
+Bugfixes
+---------
+* kolab/issue1868: Crash after reply on a mail using search function (705173, merge issue 38)
+* BUG: 93436 - Always encrypt to self function was always on.
+* kolab/issue1923 Crash after pressing copy and paste in the composer. (706484)
+* kolab/issue1713 @ (at) sign in realname confuses kontact when creating appointments (704180)
+* kolab/issue/1894 Default width of the folder name column at first contact start is too small
+* kolab/issue1918 favorite folder view migration default size could be better (706063)
+
+Merges
+------
+* Merged kpilot, karm and kalarm changes from 3.5 branch into enterprise.
+
+Friday, 24th August 2007
+
+
+Features
+----------
+ - prokde35-z item 44: keep state of signing and encryption actions across drafts (fully implemented, ported to 3.5, trunk and proko2) (702320)
+ - prokde35-z item 35: consistent behavior of pasting URLs via keyboard shortcut, d'n'd and menu (fully implemented, ported to trunk) (702342)
+ - prokde35-z item 1: favourite folders view in KMail (fully implemented, port to trunk pending, merge 36) (702804)
+ - prokde35-z item 9: first part of this item, concerning sync of SEEN flags in read only folders (issue1376) (703473)
+ prokde35-z item 9: second part, ability to store custom flags on the server (704199) merges
+- prokde35 w1-20 (665722)
+- prokde35 w1-11: Let the navigator toolbar be always the last one, if it's in the top dockwindow ( 666073)
+ - prokde35 W1-19 / kolab/issue1749 Since mail folders are not groupware folders, do a full sync, when
+ the mail part is already active. (668988)
+ - prokde35 It's now possible to resize the magenta rectangle that represents the event in the freebusy
+ view, to change its start time, end time and duration (not only move it around, which preserved
+ duration).
+ - prokde35 w1-6 Implement a size column in the shared folder tree class and in kmail. Add the ability
+ to use a configurable color for the folder name and size when it is close to a configurable quota
+ threshold (provided the folder has quota info in the first place). Implement size retrieval for mbox
+ and maildir storage.
+ - prokde35 w1-23 Add a font family and size selector to the standalone readerwindow, which
+overrides the usual font for display and printing for that particular mail.
+ - prokde35 w1-30 Add an option to show two agenda views (669438)
+ - prokde35 W1-30 Start of a gantt-based view for korganizer (669557)
+ - prokde35 W22: prepare printing of notes from Kontact, move existing KNotes printing code to a library
+ shared by KNotes and the Notes plugin ( 670739)
+ - prokde35 W1-32: add profile support for kontact, with global/user-specific profiles, and profile
+ import/export (671800)
+ - prokde35 w1-15 Show the delegator and delegate in the even preview.
+ ( related to kolab/issue1773 kolab/issue1774 kolab/issue1776) (670673).
+ - prokde35 w1-10 Show plugins which failed to load their part as disabled,
+and make them not selectable.(670822)
+ - prokde35 W1-19 (sync buttons): Add submenu with "All" and the single accounts, similar as in
+the check mail action
+ - Drag and drop notes - (662503)
+ - Implemented the ability to drag the current meeting time in the freebusy view, in order to visually
+ move the meeting to a spot where the attendees are free.(668059)
+ - Merge (mostly) hidden config options and their uses from proko2
+
+Bugfixes
+=========
+ - kolab/issue896 naming inconsistencies in Kontact, enterprise only so far (703752)
+ - kolab/issue1318 potential fix for crashes during filtering (703867)
+ - kolab/issue1743 retain the vacation file name through account editing (703997)
+ - kolab/issue1894 better initial name column width in the kmail folder tree (704165)
+ - kolab/issue1713 @ (at) sign in realname confuses kontact when creating appointments (704180)
+ - kolab/issue1882 Crash after reply to a revoked mail(700851)
+ - kolab/issue1815 convert KMHeaders::applyFiltersOnMsg to using serial numbers instead of message pointers [in the case not using action scheduler]. Speculative fix to Intevation issue #1815 (Filtering 1450 mails crashes kontact). ( 703867 )
+ - More comprehensible documentation of KMFolder and friends ( 703507 )
+ - kolab/issue1640 - Minimum sync-interval for kontact ( 703384 )
+ - bugs.kde.org - 77223, 85630, 111419 ( 700059 )
+ - bugs.kde.org - 144303 - When sending an encrypted message, with an empty body, and the
+ encryption key selection or encryption prefs selection dialogs were cancelled, mNewBodyPart was
+ deleted without ever having been initialised. Also init some other vars ASAP. (700035)
+ - kolab/issue1712 Update revision when adding new attendees.(663228)
+ - kolab/issue1672 Make sure to open the folder when saving a single message as well.(664661)
+ - Fix lack of double-quotes around folder name, making GEQUOTAROOT fail on folders with a space in the
+ name.(665276)
+ - Port the ability to add and remove subfolders from korganizer's resource view from proko2. (665274)
+ - kolab/issue1721 Don't exit when the popup menu is canceled.(665679)
+ - Allow to edit attachments of already existing messages.(668156)
+ - kolab/issue1642 kontact crashed after moving some events (670485)
+ - kolab/issue1738 (Kontact escapes part of content type of text/calendar messages, makes Outlook fail
+ to directly recognise invitations)
+ - kolab/issue864 prokde35 freebusy display takes internal or does not honor "nobody" annotation(
+ 669428)
+ - kolab/issue1759 (Dragging emails onto tasks does not enable reminders by default.)
+ - kolab/issue1766 prokde35 Kontact crashes after moving event in a free/busy list (TQListViewItem)
+ - kolab/issue1784 prokde35 Kontact sometimes crashes by creating a new event.
+ - kolab/issue1780 i18n of "Agenda View Calender Display" missing
+ - kolab/issue1773 (Delegate an event back to the organizator shows strange effects.)
+ - kolab/issue1769 (editing attachment of a new mail stops with couldn't write error)
+ - prokde35 issue1768 - Percentage symbol missing
+ - kolab/issue1529, start date is set correctly when recurrence date is set
+ - kolab/issue1792 (email duplication occurs when using client-side filters and disconnected imap)
+ - kolab/issue1786 (moving folder shows error message)
+ - kolab/issue1794 (kontact mail composer is missing a combobox to choose the encryption type)
+ - kolab/issue1760 (Cannot make reminders for emails if left icon bar is disabled.)
+ - kolab/issue1569 (Kontact sometimes doesn't allow dragging of encrypted messages)
+ - kolab/issue1763 (Kontact still believes imap quota is set after quota is removed)
+ - kolab/issue1803 crash after unsharing a folder.
+ - kolab/issue1844 ("Copy To" on a mail doesn't work for online IMAP to same server)
+ - kolab/issue1839 (Kontact crashes after opening two composer dialogs and switching between summary and notes)
+ - kolab/issue1715 (Other disconnected Imap folders good as sources for client filters.)
+ - kolab/issue1303 (Inform user when a folder gets unshared and move new items (prevent data loss))
+ - kolab/issue1846 (Kontact crashes by moving many folders)
+ - Make sure the crypto state is not restored from headers if there are no headers. (703234)
+ - b.k.o 118060 - Ensure that there is a KMMainWidget before showing the config dialog, as parts of the config
+ (identitydialog) depend on its existence. (668075)
+ - b.k.o 121863 - Prevent crash if folder can't be found.(668092)
+ - Fixes from 3.5 merges - b.k.o 131176, 102001, 143511, 143866, 144166, 48461, 93199, 128435,50462,
+ 133395,144347,91252,143237,131029,144779,79685,85539,125920,146585,143869,140549,147602,143230,140881
+
+
+Current release is "Enterprise - Snapshot-06"
+
+Features:
+=========
+
+
+korganizer
+-----------
+ - proko35 W-15 forwarding and delegation of iCal invitations
+ - proko35 W1-29 "attaching mails directly to events as either the full message or just the message body"
+
+Aegypten
+-------------
+ - aegypten/issue 370 - Add scrollbar so that the dialog doesn't become too big when gpgconf gives us many options to configure.
+ - aegypten/issue 735 - Support for the NO_CHANGE flag from gpgconf 2.0.3 (readonly widgets)
+
+Bugfixes
+========
+ - kolab/issue 1698 -Ignore denied invitations from not invited attendees.
+ - kolab/issue1706 (addressbook: real adress type is broken) - introducing bugs in the GUI due to outlook compatibility,
+
+
+Miscellaneous
+==============
+ - prokde W1-16: when exporting a secret key to a .p12 file, allow the user to select the encoding (charset) of the passphrase in the p12 file.
+ - proko35 W1-8 Fix for usability issues with changes to the currently selected item when LDAP results come in delayed.
+ - kolab/35- W1-10 Add the possibility to have disabled plugins shown grayed out in the sidebar.
+Configurable by non-gui option.
+
+
+"Enterprise - Snapshot-05"
+Features:
+=========
+
+kmail
+----------
+- proko35 W1-7 (cyclic section changes on tab and backtab keys in the addressee selection completion popup)
+- Better unit test and automated packaging infrastructure.
+
+Bugfixes
+=========
+- Honor default forwarding settings for the toolbar button, the search window RMB and the keyboard shortcuts (issue 1530)
+- Fix documentation related to issue 1530
+- Also change the font of cut messages in case the inactive color is to similar to the normal color.(issue 1180)
+
+
+
+"Enterprise - Snapshot-04"
+
+Features:
+=========
+
+kmail
+----------
+- proko35 W1-14 (automatic moving of not yet synced mails from folders with insufficient access rights to a lost+found folder)
+- Unit tests fixed.
+- Kolab/issue1530 - make preferred form of forwarding configurable
+
+Bugfixes
+=========
+- Fixes related to opening of *mbox files.
+- Aegypten/issue734 - Moving email in dimap breaks signature, because lines removed
+
+Korganizer
+-----------
+- proko35 W1-9 icon alignment was improved.
+
+Additional Fixes
+================
+- Rebranched libkcal and kitchensync.
+
+
+"Enterprise - Snapshot-03"
+Features:
+=========
+
+kmail
+----------
+- Kolab/Merge14/issue1095 -Add local subscription
+- Kolab/issue1206 - kolabziward quirks
+- Kolab/issue1207 - groupware folders only as local subscription still shows mails in inbox
+- proko35 W1-5: selectable scope when reindexing a dimap cache
+
+
+Bugfixes:
+=========
+- Kolab/issue1583 - Fixing OL compatibility with attachments that have umlauts in the filename.
+- Kolab/issue 1658 - Adding a warning for empty To : field
+- proko35 W1-1 - kontact discards signature settings when signature is deactivated
+
+
+
+"Enterprise - Snapshot-02"
+
+Features:
+=========
+
+kmail
+----------
+- Kolab/issue1385 - add/insert signature
+- kolab/issue1216 - porting semicolon as separator to enterprise.
+- kolab/issue1367 : Made ".mbox" as a default extension/filter while saving messages.
+
+Bugfixes:
+=========
+
+
+kmail
+----------
+- kolab/issue 1632 - kontact sometimes crashs by moving mails from the message find dialog to a folder
+- kolab/issue1384 - Don't allow base64 or qp encoding for message attachements, such
+as when forwarding.
+
+
+"Enterprise - Snapshot-01"
+
+Features:
+=========
+
+kmail
+----------
+
+- proko35 Task - W1-24, Kolab/issue 1180 - Copy/move folders ( related kolab/issues 1294 and 1317 )
+
+- proko35 Task - W1-2 , Ktnef
+
+- proko35 Task - W1-28, Search result DnD
+
+- Kolab/issue 1222 - Reduce the memory consumption. Improve speed.
+
+- IMAP Quota feature - Forward ports of r503566, r504908, r504943, r544380, r550654, r573761, r573797, r573829, and r503568 from proko2
+
+
+
+Bugfixes:
+=========
+
+general
+----------
+
+- Kolab/issue 1362 - PO Box in kolab format.
+
+
+kmail
+----------
+
+- Apply fix for KMAcctCachedImap::processNewMail's crash (r631934)
diff --git a/akregator/src/akregator.desktop b/akregator/src/akregator.desktop
index 394cf1860..eb8952d3f 100644
--- a/akregator/src/akregator.desktop
+++ b/akregator/src/akregator.desktop
@@ -28,7 +28,6 @@ GenericName[hu]=RSS hírolvasó
GenericName[is]=RSS fréttaforrit
GenericName[it]=Lettore Fonti RSS
GenericName[ja]=RSS ニュースリーダー
-GenericName[ka]=RSS კვების წამკითხველი
GenericName[kk]=RSS жаңалықтарын оқу
GenericName[km]=កម្មវិធី​អាន​មតិព័ត៌មាន RSS
GenericName[ko]=RSS 피드 리더
@@ -53,8 +52,7 @@ GenericName[sv]=Läsare av RSS-kanaler
GenericName[ta]=RSS பீஃட் வாசிப்பான்
GenericName[tr]=RSS Haber Kaynağı Okuyucu
GenericName[uk]=Програма для читання подач RSS
-GenericName[uz]=RSS yangiliklarni oʻquvchi
-GenericName[uz@cyrillic]=RSS янгиликларни ўқувчи
+GenericName[uz]=RSS янгиликларни ўқувчи
GenericName[zh_CN]=RSS 种子阅读器
GenericName[zh_TW]=RSS Feed 閱讀器
Comment=An RSS Aggregator for KDE
@@ -79,7 +77,6 @@ Comment[hu]=KDE-s hírolvasó RSS hírcsatornákhoz
Comment[is]=RSS fréttaforrit fyrir KDE
Comment[it]=Un concentratore KDE per RSS
Comment[ja]=KDE 用 RSS アグリゲータ
-Comment[ka]= RSS აგრეგატი KDE-სთვის
Comment[kk]=KDE-нің RSS жаңалық агрегаторы
Comment[km]=កម្មវិធី​អាន RSS សម្រាប់ KDE
Comment[ko]=KDE용 RSS 리더
@@ -102,8 +99,7 @@ Comment[sv]=En RSS-samlare för KDE
Comment[ta]=கேடியிக்கான ஒரு RSS சேர்ப்பான்
Comment[tr]=Bir KDE RSS Okuyucusu
Comment[uk]=Агрегатор RSS для KDE
-Comment[uz]=KDE uchun RSS yangiliklarni oʻquvchi
-Comment[uz@cyrillic]=KDE учун RSS янгиликларни ўқувчи
+Comment[uz]=KDE учун RSS янгиликларни ўқувчи
Comment[zh_CN]=KDE RSS 新闻收集器
Comment[zh_TW]=KDE 的 RSS 收集器
Terminal=false
diff --git a/akregator/src/akregator_plugin.desktop b/akregator/src/akregator_plugin.desktop
index 986515c06..9f8608bce 100644
--- a/akregator/src/akregator_plugin.desktop
+++ b/akregator/src/akregator_plugin.desktop
@@ -25,7 +25,6 @@ Comment[hu]=Akregator bővítőmodul
Comment[is]=Íforrit fyrir Akregator
Comment[it]=Plugin per Akregator
Comment[ja]=Akregator 用プラグイン
-Comment[ka]=Akregator-ის მოდული
Comment[kk]=Akregator-дың плагин модулі
Comment[km]=កម្មវិធី​ជំនួយ Akregator
Comment[ko]=Akregator 플러그인
@@ -49,8 +48,7 @@ Comment[sr@Latn]=Priključak za Akregator
Comment[sv]=Insticksprogram för Akregator
Comment[tr]=Akregator Eklentisi
Comment[uk]=Втулок для Akregator
-Comment[uz]=Akregator uchun plagin
-Comment[uz@cyrillic]=Akregator учун плагин
+Comment[uz]=Akregator учун плагин
Comment[zh_CN]=Akregator 插件
Comment[zh_TW]=Akregator 外掛程式
diff --git a/akregator/src/akregator_view.cpp b/akregator/src/akregator_view.cpp
index d238307d2..8776ec123 100644
--- a/akregator/src/akregator_view.cpp
+++ b/akregator/src/akregator_view.cpp
@@ -225,7 +225,7 @@ View::View( Part *part, TQWidget *parent, ActionManagerImpl* actionManager, cons
setFocusPolicy(TQWidget::StrongFocus);
TQVBoxLayout *lt = new TQVBoxLayout( this );
-
+
m_horizontalSplitter = new TQSplitter(TQSplitter::Horizontal, this);
m_horizontalSplitter->setOpaqueResize(true);
@@ -260,7 +260,7 @@ View::View( Part *part, TQWidget *parent, ActionManagerImpl* actionManager, cons
connect(m_tagNodeListView, TQT_SIGNAL(signalContextMenu(KListView*, TreeNode*, const TQPoint&)), this, TQT_SLOT(slotFeedTreeContextMenu(KListView*, TreeNode*, const TQPoint&)));
-
+
ProgressManager::self()->setFeedList(m_feedList);
m_tabs = new TabWidget(m_horizontalSplitter);
@@ -321,8 +321,12 @@ View::View( Part *part, TQWidget *parent, ActionManagerImpl* actionManager, cons
connectFrame(m_mainFrame);
m_tabs->addFrame(m_mainFrame);
- m_horizontalSplitter->setSizes( Settings::splitter1Sizes() );
- m_articleSplitter->setSizes( Settings::splitter2Sizes() );
+ const TQValueList<int> sp1sizes = Settings::splitter1Sizes();
+ if ( sp1sizes.count() >= m_horizontalSplitter->sizes().count() )
+ m_horizontalSplitter->setSizes( sp1sizes );
+ const TQValueList<int> sp2sizes = Settings::splitter2Sizes();
+ if ( sp2sizes.count() >= m_articleSplitter->sizes().count() )
+ m_articleSplitter->setSizes( sp2sizes );
KConfig *conf = Settings::self()->config();
conf->setGroup("General");
@@ -374,7 +378,7 @@ void View::slotSettingsChanged()
{
// if tagging is hidden, show only feed list
m_listTabWidget->setViewMode(Settings::showTaggingGUI() ? ListTabWidget::verticalTabs : ListTabWidget::single);
-
+
}
void View::slotOnShutdown()
@@ -406,8 +410,12 @@ void View::slotOnShutdown()
void View::saveSettings()
{
- Settings::setSplitter1Sizes( m_horizontalSplitter->sizes() );
- Settings::setSplitter2Sizes( m_articleSplitter->sizes() );
+ const TQValueList<int> spl1 = m_horizontalSplitter->sizes();
+ if ( spl1.contains( 0 ) == 0 )
+ Settings::setSplitter1Sizes( spl1 );
+ const TQValueList<int> spl2 = m_articleSplitter->sizes();
+ if ( spl2.contains( 0 ) == 0 )
+ Settings::setSplitter2Sizes( spl2 );
Settings::setViewMode( m_viewMode );
Settings::writeConfig();
}
@@ -415,7 +423,7 @@ void View::saveSettings()
void View::slotOpenNewTab(const KURL& url, bool background)
{
PageViewer* page = new PageViewer(this, "page");
-
+
connect( m_part, TQT_SIGNAL(signalSettingsChanged()), page, TQT_SLOT(slotPaletteOrFontChanged()));
connect( page, TQT_SIGNAL(setTabIcon(const TQPixmap&)),
@@ -822,7 +830,7 @@ void View::slotOpenURL(const KURL& url, Viewer* currentViewer, BrowserRun::Openi
else
{
KParts::URLArgs args = currentViewer ? currentViewer->browserExtension()->urlArgs() : KParts::URLArgs();
-
+
BrowserRun* r = new BrowserRun(this, currentViewer, url, args, mode);
connect(r, TQT_SIGNAL(signalOpenInViewer(const KURL&, Akregator::Viewer*, Akregator::BrowserRun::OpeningMode)),
this, TQT_SLOT(slotOpenURLReply(const KURL&, Akregator::Viewer*, Akregator::BrowserRun::OpeningMode)));
@@ -832,7 +840,7 @@ void View::slotOpenURL(const KURL& url, Viewer* currentViewer, BrowserRun::Openi
//TODO: KDE4 remove this ugly ugly hack
void View::slotUrlClickedInViewer(const KURL& url, Viewer* viewer, bool newTab, bool background)
{
-
+
if (!newTab)
{
slotOpenURL(url, viewer, BrowserRun::CURRENT_TAB);
@@ -983,7 +991,7 @@ void View::slotNextUnreadArticle()
{
if (m_viewMode == CombinedView)
m_listTabWidget->activeView()->slotNextUnreadFeed();
-
+
TreeNode* sel = m_listTabWidget->activeView()->selectedNode();
if (sel && sel->unread() > 0)
m_articleList->slotNextUnreadArticle();
@@ -995,7 +1003,7 @@ void View::slotPrevUnreadArticle()
{
if (m_viewMode == CombinedView)
m_listTabWidget->activeView()->slotPrevUnreadFeed();
-
+
TreeNode* sel = m_listTabWidget->activeView()->selectedNode();
if (sel && sel->unread() > 0)
m_articleList->slotPreviousUnreadArticle();
@@ -1211,8 +1219,8 @@ void View::slotOpenCurrentArticle()
link = article.link();
else if (article.guidIsPermaLink())
link = KURL(article.guid());
-
- if (link.isValid())
+
+ if (link.isValid())
{
slotOpenURL(link, 0L, BrowserRun::NEW_TAB_FOREGROUND);
}
@@ -1236,8 +1244,8 @@ void View::slotOpenCurrentArticleBackgroundTab()
link = article.link();
else if (article.guidIsPermaLink())
link = KURL(article.guid());
-
- if (link.isValid())
+
+ if (link.isValid())
{
slotOpenURL(link, 0L, BrowserRun::NEW_TAB_BACKGROUND);
}
@@ -1307,7 +1315,7 @@ void View::slotArticleDelete()
msg = i18n("<qt>Are you sure you want to delete article <b>%1</b>?</qt>").arg(TQStyleSheet::escape(articles.first().title()));
break;
default:
- msg = i18n("<qt>Are you sure you want to delete the selected article?</qt>",
+ msg = i18n("<qt>Are you sure you want to delete the selected article?</qt>",
"<qt>Are you sure you want to delete the %n selected articles?</qt>",
articles.count());
}
@@ -1386,7 +1394,7 @@ void View::slotTextToSpeechRequest()
else
{
TQString selectedText = static_cast<PageViewer *>(m_currentFrame->part())->selectedText();
-
+
if (!selectedText.isEmpty())
SpeechClient::self()->slotSpeak(selectedText, "en");
}
@@ -1439,7 +1447,7 @@ void View::slotMouseOverInfo(const KFileItem *kifi)
void View::readProperties(KConfig* config)
{
-
+
if (!Settings::resetQuickFilterOnNodeChange())
{
m_searchBar->slotSetText(config->readEntry("searchLine"));
@@ -1447,7 +1455,7 @@ void View::readProperties(KConfig* config)
if (statusfilter != -1)
m_searchBar->slotSetStatus(statusfilter);
}
-
+
int selectedID = config->readNumEntry("selectedNodeID", -1);
if (selectedID != -1)
{
@@ -1471,7 +1479,7 @@ void View::saveProperties(KConfig* config)
// save filter settings
config->writeEntry("searchLine", m_searchBar->text());
config->writeEntry("searchCombo", m_searchBar->status());
-
+
TreeNode* sel = m_listTabWidget->activeView()->selectedNode();
if (sel)
diff --git a/akregator/src/eventsrc b/akregator/src/eventsrc
index 3be7516a8..6615ce17b 100644
--- a/akregator/src/eventsrc
+++ b/akregator/src/eventsrc
@@ -29,7 +29,6 @@ Name[hu]=Hírforrás felvéve
Name[is]=Straum bætt við
Name[it]=Aggiunta fonte
Name[ja]=フィード追加
-Name[ka]=დამატებულია კვება
Name[kk]=Қор қосылды
Name[km]=បាន​បន្ថែម​មតិព័ត៌មាន
Name[ko]=피드 추가됨
@@ -53,8 +52,7 @@ Name[sv]=Kanal tillagd
Name[ta]=பீஃட் சேர்க்கப்பட்டது
Name[tr]=Haber kaynağı eklendi
Name[uk]=Подачу додано
-Name[uz]=Yangiliklar tasmasi qoʻshildi
-Name[uz@cyrillic]=Янгиликлар тасмаси қўшилди
+Name[uz]=Янгиликлар тасмаси қўшилди
Name[zh_CN]=添加了新闻源
Name[zh_TW]=已加入 Feed
Comment=A new feed was remotely added to Akregator
@@ -78,7 +76,6 @@ Comment[hu]=Egy hírforrást távolról felvettek az Akregatorba
Comment[is]=Nýjum straum var bætt við Akregator
Comment[it]=Una nuova fonte è stata aggiunta ad Akregator da remoto
Comment[ja]=新規フィードがリモートで Akregator に追加されました
-Comment[ka]=Akregator-ის სიას დისტანციურად ახალი კვება დაემატა
Comment[kk]=Akregator-ға қашықтан жаңа қор қосылды
Comment[km]=បាន​បន្ថែម​មតិព័ត៌មាន​ថ្មី​មួយ​ពី​ចម្ងាយ​ទៅ Akregator
Comment[ko]=Akregator에 피드가 원격으로 추가됨
@@ -102,8 +99,7 @@ Comment[sv]=En ny kanal har lagts till i aKregator utifrån
Comment[ta]=Akregatorக்கு ஒரு புதிய உள்ளீடு சேர்க்கப்பட்டது
Comment[tr]=Akregator'a yeni bir haber kaynağı eklendi
Comment[uk]=Нову подачу було віддалено додано до Akregator
-Comment[uz]=Akregator dasturiga yangi yangiliklar tasmasi qoʻshildi
-Comment[uz@cyrillic]=Akregator дастурига янги янгиликлар тасмаси қўшилди
+Comment[uz]=Akregator дастурига янги янгиликлар тасмаси қўшилди
Comment[zh_CN]=新闻源远程添加进了 Akregator
Comment[zh_TW]=已從遠端加入新的 feed 到 Akregator
default_presentation=4
@@ -135,7 +131,6 @@ Name[hu]=Hírekk
Name[is]=Nýjar greinar
Name[it]=Nuovi articoli
Name[ja]=新規記事
-Name[ka]=ახალი სტატიები
Name[kk]=Жаңа мақалалар
Name[km]=អត្ថបទ​ថ្មី
Name[ko]=새 글
@@ -160,8 +155,7 @@ Name[sv]=Nya artiklar
Name[ta]= புதிய செய்திகள்
Name[tr]=Yeni Haberler
Name[uk]=Нові статті
-Name[uz]=Yangi maqolalar
-Name[uz@cyrillic]=Янги мақолалар
+Name[uz]=Янги мақолалар
Name[zh_CN]=新闻文章
Name[zh_TW]=新文章
Comment=New articles were fetched
@@ -188,7 +182,6 @@ Comment[hu]=Új hírek lettek letöltve
Comment[is]=Nýjar greinar voru sóttar
Comment[it]=I nuovi articoli sono stati recuperati
Comment[ja]=新規記事を取得しました
-Comment[ka]=მიღებულია ახალი სტატიები
Comment[kk]=Жаңа мақалалар қабылданды
Comment[km]=បាន​ប្រមូល​អត្ថបទ​ថ្មី
Comment[ko]=새 글을 가져옴
diff --git a/akregator/src/mk4storage/akregator_mk4storage_plugin.desktop b/akregator/src/mk4storage/akregator_mk4storage_plugin.desktop
index c7d899a7a..1e63cfc06 100644
--- a/akregator/src/mk4storage/akregator_mk4storage_plugin.desktop
+++ b/akregator/src/mk4storage/akregator_mk4storage_plugin.desktop
@@ -21,7 +21,6 @@ Name[hu]=Metakit tároló
Name[is]=Metakit geymslu bakendi
Name[it]=Backend archiviazione metakit
Name[ja]=メタキットストレージバックエンド
-Name[ka]=Metakit მეხსიერების ბუფერი
Name[kk]=Metakit архивтеу бағдарламасы
Name[km]=កម្មវិធី​ខាង​ក្រោយ​សម្រាប់​រក្សាទុក (Metakit)
Name[ko]=Metakit 저장소 백엔드
@@ -69,7 +68,6 @@ Comment[hu]=Akregator bővítőmodul
Comment[is]=Íforrit fyrir Akregator
Comment[it]=Plugin per Akregator
Comment[ja]=Akregator 用プラグイン
-Comment[ka]=Akregator-ის მოდული
Comment[kk]=Akregator-дың плагин модулі
Comment[km]=កម្មវិធី​ជំនួយ Akregator
Comment[ko]=Akregator 플러그인
@@ -93,8 +91,7 @@ Comment[sr@Latn]=Priključak za Akregator
Comment[sv]=Insticksprogram för Akregator
Comment[tr]=Akregator Eklentisi
Comment[uk]=Втулок для Akregator
-Comment[uz]=Akregator uchun plagin
-Comment[uz@cyrillic]=Akregator учун плагин
+Comment[uz]=Akregator учун плагин
Comment[zh_CN]=Akregator 插件
Comment[zh_TW]=Akregator 外掛程式
ServiceTypes=Akregator/Plugin
diff --git a/certmanager/certmanager.cpp b/certmanager/certmanager.cpp
index f12411bf5..c078315b9 100644
--- a/certmanager/certmanager.cpp
+++ b/certmanager/certmanager.cpp
@@ -889,7 +889,8 @@ void CertManager::slotDirmngrExited() {
This slot will import CRLs from a file.
*/
void CertManager::importCRLFromFile() {
- TQString filter = TQString("*.crl *.arl *-crl.der *-arl.der|") + i18n("Certificate Revocation List (*.crl *.arl *-crl.der *-arl.der)");
+ // loadcrl can only work with DER encoded files (verified with dirmngr 1.0.3)
+ TQString filter = TQString("*.crl *.arl *-crl.der *-arl.der|") + i18n("Certificate Revocation List, DER encoded (*.crl *.arl *-crl.der *-arl.der)");
KURL url = KFileDialog::getOpenURL( TQString::null,
filter,
this,
@@ -1277,9 +1278,11 @@ void CertManager::slotCertificateExportResult( const GpgME::Error & err, const T
void CertManager::slotExportSecretKey() {
Kleo::KeySelectionDialog dlg( i18n("Secret Key Export"),
- i18n("Select the secret key to export "
+ "<qt>" +
+ i18n("Select the secret key to export "
"(<b>Warning: The PKCS#12 format is insecure; "
- "exporting secret keys is discouraged</b>):"),
+ "exporting secret keys is discouraged</b>):") +
+ "</qt>",
std::vector<GpgME::Key>(),
Kleo::KeySelectionDialog::SecretKeys|Kleo::KeySelectionDialog::SMIMEKeys,
false /* no multiple selection */,
diff --git a/certmanager/conf/kleopatra_config_appear.desktop b/certmanager/conf/kleopatra_config_appear.desktop
index 8cbeaecf8..fa6fa6ba6 100644
--- a/certmanager/conf/kleopatra_config_appear.desktop
+++ b/certmanager/conf/kleopatra_config_appear.desktop
@@ -40,7 +40,6 @@ Name[hu]=Megjelenés
Name[is]=Útlit
Name[it]=Aspetto
Name[ja]=外観
-Name[ka]=იერსახე
Name[kk]=Сыртқы көрінісі
Name[km]=រូបរាង
Name[ko]=모양
@@ -67,8 +66,7 @@ Name[ta]=தோற்றம்
Name[tg]=Намуди зоҳирӣ
Name[tr]=Görünüm
Name[uk]=Вигляд
-Name[uz]=Koʻrinishi
-Name[uz@cyrillic]=Кўриниши
+Name[uz]=Кўриниши
Name[zh_CN]=外观
Comment=Colors & Fonts Configuration
Comment[af]=Kleur en skrif tipe opstelling
@@ -97,7 +95,6 @@ Comment[hu]=A színek és betűtípusok beállítása
Comment[is]=Stilling lita & leturgerða
Comment[it]=Configurazione tipi di carattere e colori
Comment[ja]=色とフォントの設定
-Comment[ka]=ფერთა და შრიფტთა კონფიგურაცია
Comment[kk]=Түс & Қаріп параметрлері
Comment[km]=ការ​កំណត់​រចនាសម្ព័ន្ធ​ពណ៌ & ពុម្ពអក្សរ
Comment[ko]=색과 글꼴 설정
@@ -153,7 +150,6 @@ Keywords[hu]=szín,betűtípus,beállítások
Keywords[is]=litir,letur, stillingar
Keywords[it]=colori, font, caratteri, configurazione
Keywords[ja]=色,フォント,設定
-Keywords[ka]=ფერები,შრიფტები, კონფიგურაცია
Keywords[km]=ពណ៌,ពុម្ពអក្សរ,ការ​កំណត់​រចនាសម្ព័ន្ធ
Keywords[ko]=색,글꼴,설정
Keywords[lt]=color,font, configuration, spalvų, šriftų konfigūravimas
diff --git a/certmanager/conf/kleopatra_config_dirserv.desktop b/certmanager/conf/kleopatra_config_dirserv.desktop
index 7a50a7c41..9153b003f 100644
--- a/certmanager/conf/kleopatra_config_dirserv.desktop
+++ b/certmanager/conf/kleopatra_config_dirserv.desktop
@@ -27,7 +27,7 @@ Name[et]=Kataloogiteenused
Name[eu]=Direktorio zerbitzuak
Name[fa]=خدمات فهرست راهنما
Name[fi]=Hakemistopalvelut
-Name[fr]=Services d'annuaire
+Name[fr]=Services de répertoires
Name[fy]=Maptsjinsten
Name[ga]=Seirbhísí Eolaire
Name[gl]=Servicios de Directorio
@@ -36,7 +36,6 @@ Name[hu]=Címtárszolgáltatások
Name[is]=Nafnaþjónustur
Name[it]=Servizi Directory
Name[ja]=ディレクトリサービス
-Name[ka]=საცნობარო მომსახურება
Name[kk]=Каталог қызметтері
Name[km]=សេវា​ថត
Name[ko]=디렉터리 서비스
@@ -80,7 +79,7 @@ Comment[et]=LDAP kataloogiteenuste seadistused
Comment[eu]=LDAP direktorio zerbitzuen konfigurazioa
Comment[fa]=پیکربندی خدمات فهرست راهنمای LDAP
Comment[fi]=Hakemistopalveluiden asetukset
-Comment[fr]=Configuration des services d'annuaire LDAP
+Comment[fr]=Configuration des répertoires LDAP
Comment[fy]=Konfiguraasje foar LDAP-tsjinsten
Comment[gl]=Configuración dos servicios de directorio LDAP
Comment[he]=תצורה של שירותי ספרייה עבור LDAP
@@ -88,7 +87,6 @@ Comment[hu]=Az LDAP címtárszolgáltatások beállításai
Comment[is]=Stillingar LDAP uppflettingaþjónustunnar
Comment[it]=Configurazione servizi LDAP
Comment[ja]=LDAP ディレクトリサービスの設定
-Comment[ka]=LDAP საცნობარო მომსახურების კონფიგურაცია
Comment[kk]=LDAP каталог қызметтер параметрлері
Comment[km]=ការ​កំណត់​រចនាសម្ព័ន្ធ​របស់​សេវា​ថត LDAP
Comment[ko]=LDAP 디렉터리 서비스 설정
@@ -133,7 +131,7 @@ Keywords[et]=ldap,kataloog,teenused
Keywords[eu]=Idap, direktorio, zerbitzuak
Keywords[fa]=ldap، فهرست راهنما، خدمات
Keywords[fi]=ldap,hakemisto,palvelut
-Keywords[fr]=ldap,annuaire,annuaires,service,services
+Keywords[fr]=ldap,dossier,dossiers,service,services
Keywords[fy]=ldap,directory,services,triemtafel,tsjinsten
Keywords[ga]=ldap,eolaire,seirbhísí
Keywords[gl]=ldap,directorio,servicios
@@ -142,7 +140,6 @@ Keywords[hu]=ldap,címtár,szolgáltatások
Keywords[is]=ldap,directory,services,nafnaþjónusta
Keywords[it]=ldap, servizi, directory
Keywords[ja]=ldap,ディレクトリ,サービス
-Keywords[ka]=ldap,ცნობარი,მომსახურება
Keywords[km]=ldap,ថត,សេវា
Keywords[ko]=ldap,디렉터리,서비스
Keywords[lt]=ldap,directory,services,aplankai,tarnybos
@@ -152,7 +149,7 @@ Keywords[nb]=ldap,mappe,tjenester
Keywords[nds]=LDAP,Verteken,Deensten
Keywords[ne]=ldap,डाइरेक्टरी,कार्य
Keywords[nn]=ldap,katalog,tenester
-Keywords[pl]=katalog,usługi katalogowe,usługi,LDAP
+Keywords[pl]=ldap,katalog,usługi katalogowe,usługi,LDAP
Keywords[pt]=ldap,directório,serviços
Keywords[pt_BR]=ldap,diretório,serviços
Keywords[ru]=LDAP,службы каталогов
diff --git a/certmanager/conf/kleopatra_config_dnorder.desktop b/certmanager/conf/kleopatra_config_dnorder.desktop
index dc46c3314..a14ffb3c7 100644
--- a/certmanager/conf/kleopatra_config_dnorder.desktop
+++ b/certmanager/conf/kleopatra_config_dnorder.desktop
@@ -34,7 +34,6 @@ Name[hu]=DN-attribútumsorrend
Name[is]=DN eiginleikaröðun
Name[it]=Attributi DN, ordine
Name[ja]=DN 属性順位
-Name[ka]=DN ატრიბუტთა რიგი
Name[kk]=DN-атрибуттер реті
Name[km]=លំដាប់​គុណលក្ខណៈ DN
Name[ko]=DN 분배 순서
@@ -85,7 +84,6 @@ Comment[hu]=A DN-attribútumok megjelenítési sorrendjének beállítása
Comment[is]=Stilla röð DN eiginleikanna
Comment[it]=Configura l'ordine in cui sono mostrati gli attributi DN
Comment[ja]=DN 属性を表示する順位を設定
-Comment[ka]=DN ატრიბუტთა ჩვენების რიგის კონფიგურაცია
Comment[kk]=DN атрибуттерді көрсету ретін баптау
Comment[km]=កំណត់​រចនាសម្ព័ន្ធ​លំដាប់ ដែល​ត្រូវ​បង្ហាញ​គុណលក្ខណៈ DN
Comment[lt]=Konfigūruoti DN savybių rodymo tvarką
@@ -137,7 +135,6 @@ Keywords[hu]=DN,sorrend,RDN,attribútum
Keywords[is]=DN,röð,order,RDN,attribute
Keywords[it]=DN,ordine,RDN,attributi
Keywords[ja]=DN,順位,RDN,属性
-Keywords[ka]=DN,რიგი,RDN,ატრიბუტი
Keywords[km]=DN,លំដាប់,RDN,គុណលក្ខណៈ
Keywords[lt]=DN,order,RDN,attribute,savybė,tvarka
Keywords[mk]=DN,order,RDN,attribute,редослед,атрибут
diff --git a/certmanager/lib/backends/qgpgme/qgpgmecryptoconfig.cpp b/certmanager/lib/backends/qgpgme/qgpgmecryptoconfig.cpp
index c67800502..ae45d6833 100644
--- a/certmanager/lib/backends/qgpgme/qgpgmecryptoconfig.cpp
+++ b/certmanager/lib/backends/qgpgme/qgpgmecryptoconfig.cpp
@@ -447,6 +447,13 @@ TQVariant QGpgMECryptoConfigEntry::stringToValue( const TQString& str, bool unes
bool isString = isStringType();
if ( isList() ) {
+ if ( argType() == ArgType_None ) {
+ bool ok = true;
+ const TQVariant v = str.isEmpty() ? 0U : str.toUInt( &ok ) ;
+ if ( !ok )
+ kdWarning(5150) << "list-of-none should have an unsigned int as value:" << str << endl;
+ return v;
+ }
TQValueList<TQVariant> lst;
TQStringList items = TQStringList::split( ',', str );
for( TQStringList::const_iterator valit = items.begin(); valit != items.end(); ++valit ) {
@@ -657,7 +664,10 @@ void QGpgMECryptoConfigEntry::resetToDefault()
if ( mFlags & GPGCONF_FLAG_DEFAULT )
mValue = mDefaultValue;
else if ( mArgType == ArgType_None )
- mValue = false;
+ if ( isList() )
+ mValue = 0U;
+ else
+ mValue = false;
}
void QGpgMECryptoConfigEntry::setBoolValue( bool b )
@@ -715,7 +725,9 @@ void QGpgMECryptoConfigEntry::setNumberOfTimesSet( unsigned int i )
{
Q_ASSERT( mArgType == ArgType_None );
Q_ASSERT( isList() );
- setUIntValue( i );
+ mValue = i;
+ mSet = i > 0;
+ mDirty = true;
}
void QGpgMECryptoConfigEntry::setStringValueList( const TQStringList& lst )
diff --git a/certmanager/lib/backends/qgpgme/qgpgmedecryptjob.cpp b/certmanager/lib/backends/qgpgme/qgpgmedecryptjob.cpp
index 692efa322..15d3246fe 100644
--- a/certmanager/lib/backends/qgpgme/qgpgmedecryptjob.cpp
+++ b/certmanager/lib/backends/qgpgme/qgpgmedecryptjob.cpp
@@ -85,7 +85,10 @@ GpgME::DecryptionResult Kleo::QGpgMEDecryptJob::exec( const TQByteArray & cipher
}
void Kleo::QGpgMEDecryptJob::doOperationDoneEvent( const GpgME::Error & ) {
- emit result( mCtx->decryptionResult(), mOutDataDataProvider->data() );
+ const GpgME::DecryptionResult res = mCtx->decrypt( *mInData, *mOutData );
+ const TQByteArray plainText = mOutDataDataProvider->data();
+ getAuditLog();
+ emit result( res, plainText );
}
#include "qgpgmedecryptjob.moc"
diff --git a/certmanager/lib/backends/qgpgme/qgpgmedecryptverifyjob.cpp b/certmanager/lib/backends/qgpgme/qgpgmedecryptverifyjob.cpp
index 68f67d0fd..a14e7e18f 100644
--- a/certmanager/lib/backends/qgpgme/qgpgmedecryptverifyjob.cpp
+++ b/certmanager/lib/backends/qgpgme/qgpgmedecryptverifyjob.cpp
@@ -87,9 +87,11 @@ Kleo::QGpgMEDecryptVerifyJob::exec( const TQByteArray & cipherText, TQByteArray
}
void Kleo::QGpgMEDecryptVerifyJob::doOperationDoneEvent( const GpgME::Error & ) {
- emit result( mCtx->decryptionResult(),
- mCtx->verificationResult(),
- mOutDataDataProvider->data() );
+ const GpgME::DecryptionResult dr = mCtx->decryptionResult();
+ const GpgME::VerificationResult vr = mCtx->verificationResult();
+ const TQByteArray plainText = mOutDataDataProvider->data();
+ getAuditLog();
+ emit result( dr, vr, plainText );
}
#include "qgpgmedecryptverifyjob.moc"
diff --git a/certmanager/lib/backends/qgpgme/qgpgmedeletejob.cpp b/certmanager/lib/backends/qgpgme/qgpgmedeletejob.cpp
index c06907eea..3665ee668 100644
--- a/certmanager/lib/backends/qgpgme/qgpgmedeletejob.cpp
+++ b/certmanager/lib/backends/qgpgme/qgpgmedeletejob.cpp
@@ -64,6 +64,7 @@ GpgME::Error Kleo::QGpgMEDeleteJob::start( const GpgME::Key & key, bool allowSec
}
void Kleo::QGpgMEDeleteJob::doOperationDoneEvent( const GpgME::Error & error ) {
+ getAuditLog();
emit result( error );
}
diff --git a/certmanager/lib/backends/qgpgme/qgpgmedownloadjob.cpp b/certmanager/lib/backends/qgpgme/qgpgmedownloadjob.cpp
index 364e8f9f7..979a85490 100644
--- a/certmanager/lib/backends/qgpgme/qgpgmedownloadjob.cpp
+++ b/certmanager/lib/backends/qgpgme/qgpgmedownloadjob.cpp
@@ -72,7 +72,9 @@ GpgME::Error Kleo::QGpgMEDownloadJob::start( const TQStringList & pats ) {
}
void Kleo::QGpgMEDownloadJob::doOperationDoneEvent( const GpgME::Error & error ) {
- emit result( error, mOutDataDataProvider->data() );
+ const TQByteArray data = mOutDataDataProvider->data();
+ getAuditLog();
+ emit result( error, data );
}
#include "qgpgmedownloadjob.moc"
diff --git a/certmanager/lib/backends/qgpgme/qgpgmeencryptjob.cpp b/certmanager/lib/backends/qgpgme/qgpgmeencryptjob.cpp
index ddd51717f..a6a380b0b 100644
--- a/certmanager/lib/backends/qgpgme/qgpgmeencryptjob.cpp
+++ b/certmanager/lib/backends/qgpgme/qgpgmeencryptjob.cpp
@@ -97,7 +97,10 @@ GpgME::EncryptionResult Kleo::QGpgMEEncryptJob::exec( const std::vector<GpgME::K
}
void Kleo::QGpgMEEncryptJob::doOperationDoneEvent( const GpgME::Error & ) {
- emit result( mResult = mCtx->encryptionResult(), mOutDataDataProvider->data() );
+ mResult = mCtx->encryptionResult();
+ const TQByteArray ciphertext = mOutDataDataProvider->data();
+ getAuditLog();
+ emit result( mResult, ciphertext );
}
void Kleo::QGpgMEEncryptJob::showErrorDialog( TQWidget * parent, const TQString & caption ) const {
diff --git a/certmanager/lib/backends/qgpgme/qgpgmeexportjob.cpp b/certmanager/lib/backends/qgpgme/qgpgmeexportjob.cpp
index c31074aff..16e5fb773 100644
--- a/certmanager/lib/backends/qgpgme/qgpgmeexportjob.cpp
+++ b/certmanager/lib/backends/qgpgme/qgpgmeexportjob.cpp
@@ -72,7 +72,9 @@ GpgME::Error Kleo::QGpgMEExportJob::start( const TQStringList & pats ) {
}
void Kleo::QGpgMEExportJob::doOperationDoneEvent( const GpgME::Error & error ) {
- emit result( error, mOutDataDataProvider->data() );
+ const TQByteArray data = mOutDataDataProvider->data();
+ getAuditLog();
+ emit result( error, data );
}
#include "qgpgmeexportjob.moc"
diff --git a/certmanager/lib/backends/qgpgme/qgpgmeimportjob.cpp b/certmanager/lib/backends/qgpgme/qgpgmeimportjob.cpp
index 7c698e7e7..80792161f 100644
--- a/certmanager/lib/backends/qgpgme/qgpgmeimportjob.cpp
+++ b/certmanager/lib/backends/qgpgme/qgpgmeimportjob.cpp
@@ -75,11 +75,15 @@ GpgME::Error Kleo::QGpgMEImportJob::start( const TQByteArray & keyData ) {
GpgME::ImportResult Kleo::QGpgMEImportJob::exec( const TQByteArray & keyData ) {
setup( keyData );
- return mCtx->importKeys( *mInData );
+ const GpgME::ImportResult res = mCtx->importKeys( *mInData );
+ getAuditLog();
+ return res;
}
void Kleo::QGpgMEImportJob::doOperationDoneEvent( const GpgME::Error & ) {
- emit result( mCtx->importResult() );
+ const GpgME::ImportResult res = mCtx->importResult();
+ getAuditLog();
+ emit result( res );
}
diff --git a/certmanager/lib/backends/qgpgme/qgpgmejob.cpp b/certmanager/lib/backends/qgpgme/qgpgmejob.cpp
index 72f9f77ff..6d7ae5b45 100644
--- a/certmanager/lib/backends/qgpgme/qgpgmejob.cpp
+++ b/certmanager/lib/backends/qgpgme/qgpgmejob.cpp
@@ -236,21 +236,19 @@ void Kleo::QGpgMEJob::createOutData() {
static const unsigned int GetAuditLogFlags = GpgME::Context::AuditLogWithHelp|GpgME::Context::HtmlAuditLog;
-static TQString audit_log_as_html( GpgME::Context * ctx ) {
- if ( !ctx )
- return TQString();
+static TQString audit_log_as_html( GpgME::Context * ctx, GpgME::Error & err ) {
+ assert( ctx );
QGpgME::QByteArrayDataProvider dp;
GpgME::Data data( &dp );
assert( !data.isNull() );
- if ( const GpgME::Error err = ctx->getAuditLog( data, GetAuditLogFlags ) )
+ if ( ( err = ctx->getAuditLog( data, GetAuditLogFlags ) ) )
return TQString();
- else
- return TQString::fromUtf8( dp.data().data() );
+ const TQByteArray ba = dp.data();
+ return TQString::fromUtf8( ba.data(), ba.size() );
}
void Kleo::QGpgMEJob::doSlotOperationDoneEvent( GpgME::Context * context, const GpgME::Error & e ) {
if ( context == mCtx ) {
- getAuditLog();
doEmitDoneSignal();
doOperationDoneEvent( e );
mThis->deleteLater();
@@ -258,7 +256,9 @@ void Kleo::QGpgMEJob::doSlotOperationDoneEvent( GpgME::Context * context, const
}
void Kleo::QGpgMEJob::getAuditLog() {
- mAuditLogAsHtml = audit_log_as_html( mCtx );
+ if ( !mCtx )
+ return;
+ mAuditLogAsHtml = audit_log_as_html( mCtx, mAuditLogError );
}
void Kleo::QGpgMEJob::doSlotCancel() {
diff --git a/certmanager/lib/backends/qgpgme/qgpgmejob.h b/certmanager/lib/backends/qgpgme/qgpgmejob.h
index 984bed445..0681c165d 100644
--- a/certmanager/lib/backends/qgpgme/qgpgmejob.h
+++ b/certmanager/lib/backends/qgpgme/qgpgmejob.h
@@ -37,6 +37,7 @@
#include <gpgmepp/interfaces/passphraseprovider.h>
#include <gpgmepp/key.h>
+#include <gpgmepp/context.h>
#include <tqcstring.h>
#include <tqstring.h>
@@ -45,8 +46,6 @@
#include <kdepimmacros.h>
namespace GpgME {
- class Error;
- class Context;
class Data;
}
@@ -120,6 +119,7 @@ namespace Kleo {
virtual void doEmitDoneSignal() = 0;
void doSlotCancel();
TQString auditLogAsHtml() const { return mAuditLogAsHtml; }
+ GpgME::Error auditLogError() const { return mAuditLogError; }
private:
/*! \reimp from GpgME::ProgressProvider */
@@ -146,6 +146,7 @@ namespace Kleo {
unsigned int mNumPatterns;
unsigned int mChunkSize;
unsigned int mPatternStartIndex, mPatternEndIndex;
+ GpgME::Error mAuditLogError;
TQString mAuditLogAsHtml;
};
@@ -154,7 +155,7 @@ namespace Kleo {
#define make_slot_cancel private: void slotCancel() { QGpgMEJob::doSlotCancel(); }
#define make_progress_emitter private: void doEmitProgressSignal( const TQString & what, int cur, int tot ) { emit progress( what, cur, tot ); }
#define make_done_emitter private: void doEmitDoneSignal() { emit done(); }
-#define make_auditLogAsHtml private: TQString auditLogAsHtml() const { return QGpgMEJob::auditLogAsHtml(); }
+#define make_auditLogAsHtml private: TQString auditLogAsHtml() const { return QGpgMEJob::auditLogAsHtml(); } GpgME::Error auditLogError() const { return QGpgMEJob::auditLogError(); }
#define QGPGME_JOB make_slot_cancel make_progress_emitter make_done_emitter make_auditLogAsHtml
#endif // __KLEO_QGPGMEJOB_H__
diff --git a/certmanager/lib/backends/qgpgme/qgpgmekeygenerationjob.cpp b/certmanager/lib/backends/qgpgme/qgpgmekeygenerationjob.cpp
index b226d6498..16e131348 100644
--- a/certmanager/lib/backends/qgpgme/qgpgmekeygenerationjob.cpp
+++ b/certmanager/lib/backends/qgpgme/qgpgmekeygenerationjob.cpp
@@ -80,7 +80,10 @@ GpgME::Error Kleo::QGpgMEKeyGenerationJob::start( const TQString & parameters )
}
void Kleo::QGpgMEKeyGenerationJob::doOperationDoneEvent( const GpgME::Error & ) {
- emit result( mCtx->keyGenerationResult(), mPubKeyDataProvider ? mPubKeyDataProvider->data() : TQByteArray() );
+ const GpgME::KeyGenerationResult res = mCtx->keyGenerationResult();
+ const TQByteArray data = mPubKeyDataProvider ? mPubKeyDataProvider->data() : TQByteArray() ;
+ getAuditLog();
+ emit result( res, data );
}
#include "qgpgmekeygenerationjob.moc"
diff --git a/certmanager/lib/backends/qgpgme/qgpgmekeylistjob.cpp b/certmanager/lib/backends/qgpgme/qgpgmekeylistjob.cpp
index 9e663e92d..b07135f01 100644
--- a/certmanager/lib/backends/qgpgme/qgpgmekeylistjob.cpp
+++ b/certmanager/lib/backends/qgpgme/qgpgmekeylistjob.cpp
@@ -48,6 +48,7 @@
#include <kdebug.h>
#include <tqstringlist.h>
+#include <tqtimer.h>
#include <algorithm>
@@ -97,6 +98,10 @@ GpgME::Error Kleo::QGpgMEKeyListJob::start( const TQStringList & pats, bool secr
kdDebug(5150) << "QGpgMEKeyListJob::start(): retrying keylisting with chunksize " << chunkSize() << endl;
continue;
}
+ } else if ( err.code() == GPG_ERR_EOF ) {
+ kdDebug(5150) << "QGpgMEKeyListJob::start(): early end of keylisting, trying to fake an empty result" << endl;
+ TQTimer::singleShot( 10, this, TQT_SLOT(slotFakeOperationDoneEvent()) );
+ return GpgME::Error();
}
deleteLater();
mResult = GpgME::KeyListResult( 0, err );
@@ -158,6 +163,17 @@ void Kleo::QGpgMEKeyListJob::slotNextKeyEvent( GpgME::Context * context, const G
emit nextKey( key );
}
+void Kleo::QGpgMEKeyListJob::slotFakeOperationDoneEvent() {
+ const GpgME::KeyListResult res = mCtx->keyListResult();
+ if ( !res.error().code() == GPG_ERR_EOF )
+ kdDebug(5150) << "QGpgMEKeyListJob::slotFakeOperationDoneEvent: expected EOF, got "
+ << res.error().asString() << endl;
+ mResult = GpgME::KeyListResult();
+ emit done();
+ emit result( mResult );
+ deleteLater();
+}
+
void Kleo::QGpgMEKeyListJob::slotOperationDoneEvent( GpgME::Context * context, const GpgME::Error & ) {
if ( context != mCtx )
return;
diff --git a/certmanager/lib/backends/qgpgme/qgpgmekeylistjob.h b/certmanager/lib/backends/qgpgme/qgpgmekeylistjob.h
index 0bc84c08c..388641076 100644
--- a/certmanager/lib/backends/qgpgme/qgpgmekeylistjob.h
+++ b/certmanager/lib/backends/qgpgme/qgpgmekeylistjob.h
@@ -65,6 +65,7 @@ namespace Kleo {
private slots:
void slotNextKeyEvent( GpgME::Context * context, const GpgME::Key & key );
void slotOperationDoneEvent( GpgME::Context * context, const GpgME::Error & e );
+ void slotFakeOperationDoneEvent();
private:
void doOperationDoneEvent( const GpgME::Error &) {} // unused, we implement slotOperationDoneEvent ourselves.
diff --git a/certmanager/lib/backends/qgpgme/qgpgmesignencryptjob.cpp b/certmanager/lib/backends/qgpgme/qgpgmesignencryptjob.cpp
index bc05eb86c..9a469001c 100644
--- a/certmanager/lib/backends/qgpgme/qgpgmesignencryptjob.cpp
+++ b/certmanager/lib/backends/qgpgme/qgpgmesignencryptjob.cpp
@@ -109,7 +109,9 @@ Kleo::QGpgMESignEncryptJob::exec( const std::vector<GpgME::Key> & signers,
void Kleo::QGpgMESignEncryptJob::doOperationDoneEvent( const GpgME::Error & ) {
mResult.first = mCtx->signingResult();
mResult.second = mCtx->encryptionResult();
- emit result( mResult.first, mResult.second, mOutDataDataProvider->data() );
+ const TQByteArray cipherText = mOutDataDataProvider->data();
+ getAuditLog();
+ emit result( mResult.first, mResult.second, cipherText );
}
void Kleo::QGpgMESignEncryptJob::showErrorDialog( TQWidget * parent, const TQString & caption ) const {
diff --git a/certmanager/lib/backends/qgpgme/qgpgmesignjob.cpp b/certmanager/lib/backends/qgpgme/qgpgmesignjob.cpp
index 0042d6a38..01ae8a91f 100644
--- a/certmanager/lib/backends/qgpgme/qgpgmesignjob.cpp
+++ b/certmanager/lib/backends/qgpgme/qgpgmesignjob.cpp
@@ -102,7 +102,10 @@ GpgME::SigningResult Kleo::QGpgMESignJob::exec( const std::vector<GpgME::Key> &
}
void Kleo::QGpgMESignJob::doOperationDoneEvent( const GpgME::Error & ) {
- emit result( mResult = mCtx->signingResult(), mOutDataDataProvider->data() );
+ mResult = mCtx->signingResult();
+ const TQByteArray signature = mOutDataDataProvider->data();
+ getAuditLog();
+ emit result( mResult, signature );
}
void Kleo::QGpgMESignJob::showErrorDialog( TQWidget * parent, const TQString & caption ) const {
diff --git a/certmanager/lib/backends/qgpgme/qgpgmeverifydetachedjob.cpp b/certmanager/lib/backends/qgpgme/qgpgmeverifydetachedjob.cpp
index b1022f61b..41fa48494 100644
--- a/certmanager/lib/backends/qgpgme/qgpgmeverifydetachedjob.cpp
+++ b/certmanager/lib/backends/qgpgme/qgpgmeverifydetachedjob.cpp
@@ -89,7 +89,9 @@ GpgME::VerificationResult Kleo::QGpgMEVerifyDetachedJob::exec( const TQByteArray
}
void Kleo::QGpgMEVerifyDetachedJob::doOperationDoneEvent( const GpgME::Error & ) {
- emit result( mCtx->verificationResult() );
+ const GpgME::VerificationResult res = mCtx->verificationResult();
+ getAuditLog();
+ emit result( res );
}
diff --git a/certmanager/lib/backends/qgpgme/qgpgmeverifyopaquejob.cpp b/certmanager/lib/backends/qgpgme/qgpgmeverifyopaquejob.cpp
index 92e1917b7..e4340aa39 100644
--- a/certmanager/lib/backends/qgpgme/qgpgmeverifyopaquejob.cpp
+++ b/certmanager/lib/backends/qgpgme/qgpgmeverifyopaquejob.cpp
@@ -84,7 +84,10 @@ GpgME::VerificationResult Kleo::QGpgMEVerifyOpaqueJob::exec( const TQByteArray &
}
void Kleo::QGpgMEVerifyOpaqueJob::doOperationDoneEvent( const GpgME::Error & ) {
- emit result( mCtx->verificationResult(), mOutDataDataProvider->data() );
+ const GpgME::VerificationResult res = mCtx->verificationResult();
+ const TQByteArray plainText = mOutDataDataProvider->data();
+ getAuditLog();
+ emit result( res, plainText );
}
diff --git a/certmanager/lib/kleo/job.cpp b/certmanager/lib/kleo/job.cpp
index c5371b646..dedbebfc2 100644
--- a/certmanager/lib/kleo/job.cpp
+++ b/certmanager/lib/kleo/job.cpp
@@ -52,9 +52,13 @@
#include "refreshkeysjob.h"
#include "specialjob.h"
+#include <gpgmepp/context.h>
+
#include <tqapplication.h>
#include <kdebug.h>
+#include <gpg-error.h>
+
Kleo::Job::Job( TQObject * parent, const char * name )
: TQObject( parent, name )
{
@@ -75,6 +79,16 @@ TQString Kleo::Job::auditLogAsHtml() const {
return TQString();
}
+GpgME::Error Kleo::Job::auditLogError() const {
+ kdDebug() << "Kleo::Job::auditLogError() should be reimplemented in Kleo::Job subclasses!" << endl;
+ return GpgME::Error( gpg_error( GPG_ERR_NOT_IMPLEMENTED ) );
+}
+
+bool Kleo::Job::isAuditLogSupported() const {
+ const GpgME::Error err = auditLogError();
+ return err.code() != GPG_ERR_NOT_IMPLEMENTED ;
+}
+
#define make_job_subclass(x) \
Kleo::x::x( TQObject * parent, const char * name ) : Job( parent, name ) {} \
Kleo::x::~x() {}
diff --git a/certmanager/lib/kleo/job.h b/certmanager/lib/kleo/job.h
index 1c091bab3..78ff58ce1 100644
--- a/certmanager/lib/kleo/job.h
+++ b/certmanager/lib/kleo/job.h
@@ -38,6 +38,10 @@
class TQWidget;
+namespace GpgME {
+ class Error;
+}
+
namespace Kleo {
/**
@@ -67,6 +71,8 @@ namespace Kleo {
virtual void showErrorDialog( TQWidget * parent=0, const TQString & caption=TQString::null ) const;
virtual TQString auditLogAsHtml() const;
+ virtual GpgME::Error auditLogError() const;
+ bool isAuditLogSupported() const;
public slots:
virtual void slotCancel() = 0;
diff --git a/certmanager/lib/libkleopatrarc.desktop b/certmanager/lib/libkleopatrarc.desktop
index 3af8feaf0..07af3adcd 100644
--- a/certmanager/lib/libkleopatrarc.desktop
+++ b/certmanager/lib/libkleopatrarc.desktop
@@ -22,7 +22,6 @@ Name[hu]=Nem ellenőrzött kulcs
Name[is]=Ekki staðfestur lykill
Name[it]=Chiave non convalidata
Name[ja]=認証されていない鍵
-Name[ka]=დაუმოწმებელი გასაღები
Name[kk]=Тексерілмеген кілт
Name[km]=កូនសោ​គ្មាន​សុពលភាព
Name[ko]=검증되지 않은 키
@@ -77,7 +76,6 @@ Name[hu]=Lejárt kulcs
Name[is]=Útrunninn lykill
Name[it]=Chiave scaduta
Name[ja]=期限切れの鍵
-Name[ka]=ვადაგასული გასაღები
Name[kk]=Ескірген кілт
Name[km]=កូនសោ​បាន​ផុតកំណត់
Name[ko]=만료된 키
@@ -130,7 +128,6 @@ Name[hu]=Visszavont kulcs
Name[is]=Afturkallaður lykill
Name[it]=Chiave revocata
Name[ja]=破棄された鍵
-Name[ka]=ანულირებული გასაღები
Name[kk]=Күші жойылған кілт
Name[km]=កូនសោ​ត្រូវ​បាន​ដកហូត
Name[ko]=거부된 키
@@ -183,7 +180,6 @@ Name[hu]=Megbízható gyökértanúsítvány
Name[is]=Treyst rótarskilríki
Name[it]=Certificato radice affidabile
Name[ja]=信頼されたルート証明書
-Name[ka]= რუტის სანდო სერთიფიკატი
Name[kk]=Сенім артылған түбір куәлігі
Name[km]=វិញ្ញាបនបត្រ Root ដែល​អាច​ជឿទុកចិត្ត
Name[lt]=Patikimas root sertifikatas
@@ -236,7 +232,6 @@ Name[hu]=Nem megbízható gyökértanúsítvány
Name[is]=Ekki traust rótarskilríki
Name[it]=Certificato radice non affidabile
Name[ja]=信頼されてないルート証明書
-Name[ka]=რუტის არასანდო სერტიფიკატი
Name[kk]=Сенім артылмаған түбір куәлігі
Name[km]=វិញ្ញាបនបត្រ Root ដែល​មិន​អាច​ជឿទុកចិត្ត
Name[lt]=Nepatikimas root sertifikatas
@@ -290,7 +285,6 @@ Name[hu]=Egyéb kulcsok
Name[is]=Aðrir lyklar
Name[it]=Altre chiavi
Name[ja]=他の鍵
-Name[ka]=სხვა გასაღებები
Name[kk]=Басқа кілттер
Name[km]=កូនសោ​ផ្សេង​ទៀត
Name[ko]=기타 키
@@ -316,8 +310,7 @@ Name[sv]=Andra nycklar
Name[ta]=மற்ற விசைகள்
Name[tr]=Diğer Anahtarlar
Name[uk]=Інші ключі
-Name[uz]=Boshqa kalitlar
-Name[uz@cyrillic]=Бошқа калитлар
+Name[uz]=Бошқа калитлар
Name[zh_CN]=其它密钥
Name[zh_TW]=其他金鑰
diff --git a/certmanager/lib/tests/test_verify.cpp b/certmanager/lib/tests/test_verify.cpp
index 54a88b4c2..cb5db396a 100644
--- a/certmanager/lib/tests/test_verify.cpp
+++ b/certmanager/lib/tests/test_verify.cpp
@@ -29,6 +29,7 @@
*/
#include <config.h>
+#include <cstdlib>
#include <kleo/cryptobackendfactory.h>
#include <kleo/verifydetachedjob.h>
diff --git a/certmanager/lib/ui/cryptoconfigdialog.cpp b/certmanager/lib/ui/cryptoconfigdialog.cpp
index 472429942..0d383083b 100644
--- a/certmanager/lib/ui/cryptoconfigdialog.cpp
+++ b/certmanager/lib/ui/cryptoconfigdialog.cpp
@@ -46,6 +46,12 @@ Kleo::CryptoConfigDialog::CryptoConfigDialog( Kleo::CryptoConfig* config, TQWidg
setMainWidget( mMainWidget );
connect( mMainWidget, TQT_SIGNAL( changed() ), TQT_SLOT( slotChanged() ) );
enableButton( Apply, false );
+ if ( mMainWidget->hasError() ) {
+ showButton( Default, false );
+ showButton( User1, false );
+ showButton( Apply, false );
+ showButton( Ok, false );
+ }
// Automatically assign accelerators
KAcceleratorManager::manage( this );
diff --git a/certmanager/lib/ui/cryptoconfigmodule.cpp b/certmanager/lib/ui/cryptoconfigmodule.cpp
index 33e7129c4..5b14d7c41 100644
--- a/certmanager/lib/ui/cryptoconfigmodule.cpp
+++ b/certmanager/lib/ui/cryptoconfigmodule.cpp
@@ -62,8 +62,20 @@ static inline TQPixmap loadIcon( TQString s ) {
->loadIcon( s.replace( TQRegExp( "[^a-zA-Z0-9_]" ), "_" ), KIcon::NoGroup, KIcon::SizeMedium );
}
+static unsigned int num_components_with_options( const Kleo::CryptoConfig * config ) {
+ if ( !config )
+ return 0;
+ const TQStringList components = config->componentList();
+ unsigned int result = 0;
+ for ( TQStringList::const_iterator it = components.begin() ; it != components.end() ; ++it )
+ if ( const Kleo::CryptoConfigComponent * const comp = config->component( *it ) )
+ if ( !comp->groupList().empty() )
+ ++result;
+ return result;
+}
+
static const KJanusWidget::Face determineJanusFace( const Kleo::CryptoConfig * config ) {
- return config && config->componentList().size() < 2
+ return num_components_with_options( config ) < 2
? KJanusWidget::Plain
: KJanusWidget::IconList ;
}
@@ -115,6 +127,22 @@ Kleo::CryptoConfigModule::CryptoConfigModule( Kleo::CryptoConfig* config, TQWidg
+ scrollView->style().pixelMetric(TQStyle::PM_ScrollBarExtent),
QMIN( compGUI->sizeHint().height(), dialogHeight ) );
}
+ if ( mComponentGUIs.empty() ) {
+ Q_ASSERT( face() == Plain );
+ const TQString msg = i18n("The gpgconf tool used to provide the information "
+ "for this dialog does not seem to be installed "
+ "properly. It did not return any components. "
+ "Try running \"%1\" on the command line for more "
+ "information.")
+ .arg( components.empty() ? "gpgconf --list-components" : "gpgconf --list-options gpg" );
+ TQLabel * label = new TQLabel( msg, vbox );
+ label->setAlignment( TQt::WordBreak );
+ label->setMinimumHeight( fontMetrics().lineSpacing() * 5 );
+ }
+}
+
+bool Kleo::CryptoConfigModule::hasError() const {
+ return mComponentGUIs.empty();
}
void Kleo::CryptoConfigModule::save()
diff --git a/certmanager/lib/ui/cryptoconfigmodule.h b/certmanager/lib/ui/cryptoconfigmodule.h
index 70c4a2691..167c3ac84 100644
--- a/certmanager/lib/ui/cryptoconfigmodule.h
+++ b/certmanager/lib/ui/cryptoconfigmodule.h
@@ -50,6 +50,8 @@ namespace Kleo {
public:
CryptoConfigModule( Kleo::CryptoConfig* config, TQWidget * parent=0, const char * name=0 );
+ bool hasError() const;
+
void save();
void reset(); // i.e. reload current settings, discarding user input
void defaults();
diff --git a/certmanager/lib/ui/keyselectiondialog.cpp b/certmanager/lib/ui/keyselectiondialog.cpp
index fcb257514..fc590d49b 100644
--- a/certmanager/lib/ui/keyselectiondialog.cpp
+++ b/certmanager/lib/ui/keyselectiondialog.cpp
@@ -61,6 +61,8 @@
#include <kconfig.h>
#include <kmessagebox.h>
#include <kprocess.h>
+#include <kactivelabel.h>
+#include <kurl.h>
// Qt
#include <tqcheckbox.h>
@@ -85,7 +87,12 @@ static bool checkKeyUsage( const GpgME::Key & key, unsigned int keyUsage ) {
if ( keyUsage & Kleo::KeySelectionDialog::ValidKeys ) {
if ( key.isInvalid() )
- kdDebug() << "key is invalid - ignoring" << endl;
+ if ( key.keyListMode() & GpgME::Context::Validate ) {
+ kdDebug() << "key is invalid" << endl;
+ return false;
+ } else {
+ kdDebug() << "key is invalid - ignoring" << endl;
+ }
if ( key.isExpired() ) {
kdDebug() << "key is expired" << endl;
return false;
@@ -309,6 +316,28 @@ Kleo::KeySelectionDialog::KeySelectionDialog( const TQString & title,
Kleo::KeySelectionDialog::KeySelectionDialog( const TQString & title,
const TQString & text,
+ const TQString & initialQuery,
+ const std::vector<GpgME::Key> & selectedKeys,
+ unsigned int keyUsage,
+ bool extendedSelection,
+ bool rememberChoice,
+ TQWidget * parent, const char * name,
+ bool modal )
+ : KDialogBase( parent, name, modal, title, Default|Ok|Cancel|Help, Ok ),
+ mOpenPGPBackend( 0 ),
+ mSMIMEBackend( 0 ),
+ mRememberCB( 0 ),
+ mSelectedKeys( selectedKeys ),
+ mKeyUsage( keyUsage ),
+ mSearchText( initialQuery ),
+ mInitialQuery( initialQuery ),
+ mCurrentContextMenuItem( 0 )
+{
+ init( rememberChoice, extendedSelection, text, initialQuery );
+}
+
+Kleo::KeySelectionDialog::KeySelectionDialog( const TQString & title,
+ const TQString & text,
const TQString & initialQuery,
unsigned int keyUsage,
bool extendedSelection,
@@ -321,6 +350,7 @@ Kleo::KeySelectionDialog::KeySelectionDialog( const TQString & title,
mRememberCB( 0 ),
mKeyUsage( keyUsage ),
mSearchText( initialQuery ),
+ mInitialQuery( initialQuery ),
mCurrentContextMenuItem( 0 )
{
init( rememberChoice, extendedSelection, text, initialQuery );
@@ -340,11 +370,26 @@ void Kleo::KeySelectionDialog::init( bool rememberChoice, bool extendedSelection
mTopLayout = new TQVBoxLayout( page, 0, spacingHint() );
if ( !text.isEmpty() ) {
- TQLabel* textLabel = new TQLabel( text, page );
- textLabel->setAlignment( textLabel->alignment() | Qt::WordBreak );
- mTopLayout->addWidget( textLabel );
+ if ( text.startsWith( "<qt>" ) ) {
+ KActiveLabel *textLabel = new KActiveLabel( text, page );
+ disconnect( textLabel, TQT_SIGNAL(linkClicked(const TQString&)), textLabel, TQT_SLOT(openLink(const TQString&)) );
+ connect( textLabel, TQT_SIGNAL(linkClicked(const TQString&)), TQT_SLOT(slotStartCertificateManager(const TQString&)) );
+ textLabel->setAlignment( textLabel->alignment() | TQt::WordBreak );
+ mTopLayout->addWidget( textLabel );
+ } else {
+ KActiveLabel *textLabel = new KActiveLabel( text, page );
+ textLabel->setAlignment( textLabel->alignment() | TQt::WordBreak );
+ mTopLayout->addWidget( textLabel );
+ }
}
+ TQPushButton * const searchExternalPB
+ = new TQPushButton( i18n("Search for &External Certificates"), page );
+ mTopLayout->addWidget( searchExternalPB, 0, TQt::AlignLeft );
+ connect( searchExternalPB, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotStartSearchForExternalCertificates()) );
+ if ( initialQuery.isEmpty() )
+ searchExternalPB->hide();
+
TQHBoxLayout * hlay = new TQHBoxLayout( mTopLayout ); // inherits spacing
TQLineEdit * le = new TQLineEdit( page );
le->setText( initialQuery );
@@ -500,10 +545,12 @@ void Kleo::KeySelectionDialog::slotHelp()
emit helpClicked();
}
-void Kleo::KeySelectionDialog::slotStartCertificateManager()
+void Kleo::KeySelectionDialog::slotStartCertificateManager( const TQString &query )
{
KProcess certManagerProc;
certManagerProc << "kleopatra";
+ if ( !query.isEmpty() )
+ certManagerProc << "--external" << "--query" << KURL::decode_string( query );
if( !certManagerProc.start( KProcess::DontCare ) )
KMessageBox::error( this, i18n( "Could not start certificate manager; "
diff --git a/certmanager/lib/ui/keyselectiondialog.h b/certmanager/lib/ui/keyselectiondialog.h
index fd8f67394..ab8dc756d 100644
--- a/certmanager/lib/ui/keyselectiondialog.h
+++ b/certmanager/lib/ui/keyselectiondialog.h
@@ -93,6 +93,15 @@ namespace Kleo {
bool modal=true );
KeySelectionDialog( const TQString & title,
const TQString & text,
+ const TQString & initialPattern,
+ const std::vector<GpgME::Key> & selectedKeys,
+ unsigned int keyUsage=AllKeys,
+ bool extendedSelection=false,
+ bool rememberChoice=false,
+ TQWidget * parent=0, const char * name=0,
+ bool modal=true );
+ KeySelectionDialog( const TQString & title,
+ const TQString & text,
const TQString & initialPattern,
unsigned int keyUsage=AllKeys,
bool extendedSelection=false,
@@ -129,7 +138,10 @@ namespace Kleo {
private slots:
void slotRereadKeys();
- void slotStartCertificateManager();
+ void slotStartCertificateManager( const TQString &query = TQString() );
+ void slotStartSearchForExternalCertificates() {
+ slotStartCertificateManager( mInitialQuery );
+ }
void slotKeyListResult( const GpgME::KeyListResult & );
void slotSelectionChanged();
void slotCheckSelection() { slotCheckSelection( 0 ); }
@@ -170,6 +182,7 @@ namespace Kleo {
TQTimer * mStartSearchTimer;
// cross-eventloop temporaries:
TQString mSearchText;
+ const TQString mInitialQuery;
Kleo::KeyListViewItem * mCurrentContextMenuItem;
int mTruncated, mListJobCount, mSavedOffsetY;
};
diff --git a/certmanager/lib/ui/messagebox.cpp b/certmanager/lib/ui/messagebox.cpp
index ddce8f04d..e05a21b9a 100644
--- a/certmanager/lib/ui/messagebox.cpp
+++ b/certmanager/lib/ui/messagebox.cpp
@@ -46,10 +46,15 @@
#include <klocale.h>
#include <ksavefile.h>
#include <kguiitem.h>
+#include <kdebug.h>
#include <tqtextedit.h>
#include <tqtextstream.h>
#include <tqvbox.h>
+#include <tqapplication.h>
+#include <tqstylesheet.h>
+
+#include <gpg-error.h>
using namespace Kleo;
using namespace GpgME;
@@ -74,6 +79,7 @@ public:
explicit AuditLogViewer( const TQString & log, TQWidget * parent=0, const char * name=0, WFlags f=0 )
: KDialogBase( parent, name, false, i18n("View GnuPG Audit Log"),
Close|User1|User2, Close, false, KGuiItem_save(), KGuiItem_copy() ),
+ m_log( /* sic */ ),
m_textEdit( new TQTextEdit( this, "m_textEdit" ) )
{
setWFlags( f );
@@ -85,7 +91,18 @@ public:
~AuditLogViewer() {}
void setAuditLog( const TQString & log ) {
- m_textEdit->setText( log );
+ if ( log == m_log )
+ return;
+ m_log = log;
+ m_textEdit->setText( "<qt>" + log + "</qt>" );
+ const TQRect rect = m_textEdit->paragraphRect( 0 );
+ kdDebug() << "setAuditLog: rect = " << rect << endl;
+ if ( !rect.isValid() )
+ return;
+ TQSize maxSize = qApp->desktop()->screenGeometry( this ).size() * 2 / 3 ;
+ if ( !maxSize.isValid() )
+ maxSize = TQSize( 640, 480 );
+ m_textEdit->setMinimumSize( rect.size().boundedTo( maxSize ) );
}
private:
@@ -98,7 +115,12 @@ private:
KSaveFile file( fileName );
if ( TQTextStream * const s = file.textStream() ) {
- *s << m_textEdit->text() << endl;
+ *s << "<html><head>";
+ if ( !caption().isEmpty() )
+ *s << "\n<title>" << /*TQt*/TQStyleSheet::escape( caption() ) << "</title>\n";
+ *s << "</head><body>\n"
+ << m_log
+ << "\n</body></html>" << endl;
file.close();
}
@@ -114,6 +136,7 @@ private:
}
private:
+ TQString m_log;
TQTextEdit * m_textEdit;
};
@@ -125,13 +148,23 @@ void MessageBox::auditLog( TQWidget * parent, const Job * job, const TQString &
if ( !job )
return;
- if ( !GpgME::hasFeature( AuditLogFeature ) ) {
+ if ( !GpgME::hasFeature( AuditLogFeature ) || !job->isAuditLogSupported() ) {
KMessageBox::information( parent, i18n("Your system does not have support for GnuPG Audit Logs"),
i18n("System Error") );
return;
}
+ const GpgME::Error err = job->auditLogError();
+
+ if ( err.code() != GPG_ERR_NO_DATA ) {
+ KMessageBox::information( parent, i18n("An error occurred while trying to retrieve the GnuPG Audit Log:\n%1")
+ .arg( TQString::fromLocal8Bit( err.asString() ) ),
+ i18n("GnuPG Audit Log Error") );
+ return;
+ }
+
const TQString log = job->auditLogAsHtml();
+
if ( log.isEmpty() ) {
KMessageBox::information( parent, i18n("No GnuPG Audit Log available for this operation."),
i18n("No GnuPG Audit Log") );
@@ -143,7 +176,7 @@ void MessageBox::auditLog( TQWidget * parent, const Job * job, const TQString &
// static
void MessageBox::auditLog( TQWidget * parent, const TQString & log, const TQString & caption ) {
- AuditLogViewer * const alv = new AuditLogViewer( "<qt>" + log + "</qt>", parent, "alv", Qt::WDestructiveClose );
+ AuditLogViewer * const alv = new AuditLogViewer( log, parent, "alv", Qt::WDestructiveClose );
alv->setCaption( caption );
alv->show();
}
@@ -247,8 +280,34 @@ void MessageBox::error( TQWidget * parent, const SigningResult & sresult, const
}
// static
+bool MessageBox::showAuditLogButton( const Kleo::Job * job ) {
+ if ( !job ) {
+ kdDebug() << "not showing audit log button (no job instance)" << endl;
+ return false;
+ }
+ if ( !GpgME::hasFeature( GpgME::AuditLogFeature ) ) {
+ kdDebug() << "not showing audit log button (gpgme too old)" << endl;
+ return false;
+ }
+ if ( !job->isAuditLogSupported() ) {
+ kdDebug() << "not showing audit log button (not supported)" << endl;
+ return false;
+ }
+ if ( job->auditLogError().code() == GPG_ERR_NO_DATA ) {
+ kdDebug() << "not showing audit log button (GPG_ERR_NO_DATA)" << endl;
+ return false;
+ }
+ if ( !job->auditLogError() && job->auditLogAsHtml().isEmpty() ) {
+ kdDebug() << "not showing audit log button (success, but result empty)" << endl;
+ return false;
+ }
+ return true;
+}
+
+
+// static
void MessageBox::make( TQWidget * parent, TQMessageBox::Icon icon, const TQString & text, const Job * job, const TQString & caption, int options ) {
- KDialogBase * dialog = GpgME::hasFeature( GpgME::AuditLogFeature )
+ KDialogBase * dialog = showAuditLogButton( job )
? new KDialogBase( caption, KDialogBase::Yes | KDialogBase::No,
KDialogBase::Yes, KDialogBase::Yes,
parent, "error", true, true,
diff --git a/certmanager/lib/ui/messagebox.h b/certmanager/lib/ui/messagebox.h
index 5ed2edaf4..ee72e43c3 100644
--- a/certmanager/lib/ui/messagebox.h
+++ b/certmanager/lib/ui/messagebox.h
@@ -40,6 +40,7 @@ namespace GpgME {
class EncryptionResult;
class DecryptionResult;
class VerificationResult;
+ class Error;
}
namespace Kleo {
@@ -73,6 +74,8 @@ namespace Kleo {
static void auditLog( TQWidget * parent, const TQString & log, const TQString & caption );
static void auditLog( TQWidget * parent, const TQString & log );
+ static bool showAuditLogButton( const Kleo::Job * job );
+
private:
static void make( TQWidget * parent, TQMessageBox::Icon icon, const TQString & text, const Kleo::Job * job, const TQString & caption, int options );
};
diff --git a/cvs.sh.diff b/cvs.sh.diff
new file mode 100644
index 000000000..313956b05
--- /dev/null
+++ b/cvs.sh.diff
@@ -0,0 +1,13 @@
+Index: admin/cvs.sh
+===================================================================
+--- admin/cvs.sh (revision 637526)
++++ admin/cvs.sh (working copy)
+@@ -592,7 +592,7 @@ for i in `ls -1 po.backup/*.pot 2>/dev/n
+ test -f po/$i || echo "disappeared: $i"
+ done
+ for i in `ls -1 po/*.pot 2>/dev/null | sed -e "s#po/##"`; do
+- sed -e 's,^"Content-Type: text/plain; charset=CHARSET\\n"$,"Content-Type: text/plain; charset=UTF-8\\n",' po/$i > po/$i.new && mv po/$i.new po/$i
++ sed -e 's,^"Content-Type: text/plain; charset=CHARSET\\n"$,"Content-Type: text/plain; charset=UTF-8\\n",; s,"Content-Transfer-Encoding: ENCODING\\n","Content-Transfer-Encoding: 8bit\\n", ; s,"Language-Team: LANGUAGE <LL@li.org>\\n","Language-Team: LANGUAGE <kde-i18n-doc@kde.org>\\n",' po/$i > po/$i.new && mv po/$i.new po/$i
+ #msgmerge -q -o po/$i po/$i po/$i
+ egrep -v '^#[^,]' po/$i | egrep '^.*[^ ]+.*$' | grep -v "\"POT-Creation" > temp.pot
+ if test -f po.backup/$i && ! cmp -s temp.pot po.backup/$i; then
diff --git a/doc/kleopatra/index.docbook b/doc/kleopatra/index.docbook
index ba4672156..09f9531b3 100644
--- a/doc/kleopatra/index.docbook
+++ b/doc/kleopatra/index.docbook
@@ -146,8 +146,8 @@ menu, as well as from the command line. The &kleopatra; executable is
named <userinput><command>kleopatra</command></userinput>.</para>
<note><para>This program is named after Cleopatra, a famous female
-Egyptian pharaoh that lived at the time of Julius Caesar, whom she is
-said to have had an intimate relationship with.</para>
+Egyptian pharaoh that lived at the time of Julius Caesar, with whom
+she had a child, Caesarion, unacknowledged as his heir.</para>
<para>The name was chosen since this program originates from the
<ulink url="http://www.gnupg.org/aegypten2/">&Auml;gypten
@@ -494,7 +494,7 @@ command line interface).</para>
<varlistentry id="view-stop-operation">
-<term><menuchoice><shortcut><keycombo action="simul"><keycap>Esc</keycap></keycombo></shortcut>
+<term><menuchoice><shortcut><keycombo action="simul">&Esc;</keycombo></shortcut>
<guimenu>View</guimenu><guimenuitem>Stop Operation</guimenuitem></menuchoice></term>
<listitem>
diff --git a/doc/kmail/configure.docbook b/doc/kmail/configure.docbook
index a66665ad3..7643b3562 100644
--- a/doc/kmail/configure.docbook
+++ b/doc/kmail/configure.docbook
@@ -648,7 +648,7 @@ so you can choose a monospaced font for the date field for better readability.</
quoted more than three times will appear in color. Note that the
<guilabel>Quoted text</guilabel> colors only work in the message reader, not in
the composer. If you want folders which are close to their quota
-(space alotment, usually used on IMAP servers) to be displayed in a different color,
+(space allotment, usually used on IMAP servers) to be displayed in a different color,
you can specify a percentage value as a threshold for this. The color to be used
can be configured along with the other custom colors.<!-- TODO --></para>
@@ -657,6 +657,11 @@ can be configured along with the other custom colors.<!-- TODO --></para>
<sect2 id="configure-appearance-layout">
<title>Layout</title>
+<para>If the <guilabel>Close message window after replying or forwarding</guilabel> option is
+activated, KMail will close the message window after replying to or forwarding the message that
+is displayed in the window. This only applies to the separate message window, not to the embedded
+message preview pane.</para>
+
<para><guilabel>Show HTML status bar</guilabel> activates a bar at the left side of the reader
pane that tells you if a message is &html; or not. This is important because
&html; messages might imitate the look of a signed and encrypted message, so
@@ -777,6 +782,32 @@ folder will be selected in &kmail;'s main window.
</para>
</listitem>
</varlistentry>
+ <varlistentry id="configure-composer-general-quote-selection-only">
+ <term>
+ <guilabel>Only quote selected text when repyling</guilabel>
+ </term>
+ <listitem>
+ <para>
+ If checked, &kmail; will quote only the selected text in the message window,
+ instead of the complete message, when replying.
+ With this, it is possible to quickly generate replies that quote only the relevant
+ paragraph to which you are actually replying, and omits the other paragraphs that are
+ not relevant to the context.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="configure-composer-general-strip-signatures">
+ <term>
+ <guilabel>Remove the signature when replying</guilabel>
+ </term>
+ <listitem>
+ <para>
+ If checked, &kmail; will remove the signature from the quoted text
+ when replying to a message. This is useful since it reduces the amount
+ of quoted text, which makes it easier to read the reply.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry id="configure-composer-general-auto-request-mdns">
<term>
<guilabel>Automatically request message disposition notifications</guilabel>
@@ -806,6 +837,19 @@ folder will be selected in &kmail;'s main window.
</para>
</listitem>
</varlistentry>
+ <varlistentry id="configure-composer-general-too-many-recipients">
+ <term>
+ <guilabel>Warn if the number of recipients is larger than</guilabel>
+ </term>
+ <listitem>
+ <para>
+ If the number of recipients is larger than this value, KMail will
+ warn and ask for a confirmation before sending the mail.
+ The default is to warn if there are more than <literal>5</literal> recipients.
+ This warning can be turned off.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry id="configure-composer-general-autosave-interval">
<term>
<guilabel>Autosave interval</guilabel>
@@ -819,6 +863,18 @@ folder will be selected in &kmail;'s main window.
</para>
</listitem>
</varlistentry>
+ <varlistentry id="configure-composer-general-forwading-type">
+ <term>
+ <guilabel>Default Forwarding Type</guilabel>
+ </term>
+ <listitem>
+ <para>
+ Lets you decide whether you want to forward messages inline or as an attachment by default.
+ This changes which type of forwarding mechanism is used when you click the toolbar icon or
+ when you activate the shortcut for forwarding.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry id="configure-composer-general-external-editor">
<term>
<guilabel>External Editor</guilabel>
@@ -1102,7 +1158,7 @@ of key words can be modified.</para>
<para>
Attaches the complete message to the disposition
notification. Usually, this is overkill. It does
- not add any valueable information that cannot be
+ not add any valuable information that cannot be
deduced from the message headers alone, but people
sometimes insist on this, since it is much easier
for humans to correlate the content of the message
@@ -1276,7 +1332,7 @@ of key words can be modified.</para>
</term>
<listitem>
<para>
- If checked, everytime you encrypt a message, a dialog
+ If checked, every time you encrypt a message, a dialog
will appear that presents you with the encryption keys
that will be used for each recipient. You can then
review the choice of keys, change them, and approve or
@@ -1335,7 +1391,7 @@ of key words can be modified.</para>
</title>
<para>
- On this tab you can switch security-relavant warnings on and
+ On this tab you can switch security-relevant warnings on and
off.
</para>
@@ -1386,7 +1442,7 @@ of key words can be modified.</para>
<listitem>
<para>
If checked, &kmail; will emit a warning if an &smime;
- certifciate or &openpgp; key will be used for a recipient
+ certificate or &openpgp; key will be used for a recipient
whose email address is not listed in the email addresses
stored in the certificate.
</para>
@@ -1698,7 +1754,7 @@ of key words can be modified.</para>
backends. Below each backend entry, you can see what protocols
(&openpgp; and/or &smime;) the backend supports. If a protocol
is not listed, the backend does not support it. If it is
- listed, but greyed out, the backend supports the protocol, but
+ listed, but grayed out, the backend supports the protocol, but
some required programs were not found, or other errors
occurred during initialization. If you press
<guibutton>Rescan</guibutton>, a dialog box will appear that
@@ -1793,12 +1849,39 @@ Correspondingly, if you ask &kmail; to go to the previous unread message.
</varlistentry>
<varlistentry>
-<term><guilabel>Jump to first unread message when entering a folder</guilabel></term>
+
+<term><guilabel>When entering a folder</guilabel></term>
+<listitem>
+<para>This option controls what happens if you open a folder.
+<itemizedlist>
+<listitem>
+<para>If <guilabel>Jump to First New Message</guilabel> is selected then &kmail; will select the
+first message it finds that is marked as new.
+</para>
+</listitem>
+<listitem>
+<para>If <guilabel>Jump to First Unread or New Message</guilabel> is selected then &kmail; will
+select the first message it finds that is marked either as new or as unread.
+</para>
+</listitem>
+<listitem>
+<para>If <guilabel>Jump to Last Selected Message</guilabel> is selected then &kmail; will select
+the message that was selected when the folder was open the last time.
+</para>
+</listitem>
+<listitem>
+<para>If <guilabel>Jump to Newest Message</guilabel> is selected then &kmail; will select the newest
+message by date.
+</para>
+</listitem>
<listitem>
-<para>If this option is enabled &kmail; will go to the first unread message
-when you enter a folder; if it is not enabled, &kmail; will go to first
-new message or, if there is no new message, to the message
-that was selected when you last left the folder.</para>
+<para>If <guilabel>Jump to Oldest Message</guilabel> is selected then &kmail; will select the oldest
+message by date.
+</para>
+</listitem>
+</itemizedlist>
+
+</para>
</listitem>
</varlistentry>
@@ -1908,6 +1991,21 @@ option is selected.</para>
<para>Invitations use to be send as attachments to a mail. By enabling this option, you let the invitation mails to be sent in the text of the mail, which is necessary to send invitations and replies to Microsoft Outlook(tm).</para>
</listitem>
</varlistentry>
+<varlistentry>
+<term><guilabel>Exchange compatible invitations naming</guilabel></term>
+<listitem>
+<para>Microsoft Outlook, when used in combination with a Microsoft Exchange
+server, has a problem understanding standards-compliant groupware e-mail.
+Enable this option to send groupware invitations in a way that Microsoft
+Exchange understands. The invitation will be sent as an attachment with name <filename>ical.ics</filename>.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Outlook compatible invitation reply comments</guilabel></term>
+<listitem>
+<para>When the user provides comments when responding to invitations, send the comment in way that Microsoft Outlook(tm) understands. If this option is not enabled, the response comments will not be seen in Outlook.</para>
+</listitem>
+</varlistentry>
</variablelist>
</sect2>
@@ -1934,7 +2032,7 @@ SendMDNsWithEmptySender=true
to the [MDN] section of the kmail configuration file. If there is no such section, simply add "[MDN]" on
a line by itself just above the option.
-Note that the default setting of "false" strictly speaking violates internet standards, but is
+Note that the default setting of "false" strictly speaking violates Internet standards, but is
set that way for practical reasons, to avoid servers rejecting MDNs that KMail generates because they
think they are SPAM.
</para>
@@ -1956,20 +2054,6 @@ The option is enabled by default. To disable the feature, add a line reading (un
</varlistentry>
<varlistentry>
-<term><guilabel>ForwardingInlineByDefault</guilabel></term>
-<listitem>
-<para>
-This option allows you to make inline forwarding the default forwarding method instead
-of forwarding as attachement.
-
-To enable the feature, add a line reading (under [Composer] section):
-</para>
-<programlisting>ForwardingInlineByDefault=true
-</programlisting>
-</listitem>
-</varlistentry>
-
-<varlistentry>
<term><guilabel>MaximumAttachmentSize</guilabel></term>
<listitem>
<para>
@@ -2011,6 +2095,73 @@ To disable the feature, add a line reading (under [OutOfOffice] section):
</listitem>
</varlistentry>
+<varlistentry>
+<term><guilabel>Allow out-of-office settings to be adjusted by the user.</guilabel></term>
+<listitem>
+<para>
+In case you don't want users to be able to upload their own out-of-office scripts to
+the server you can add:
+</para>
+<programlisting>AllowOutOfOfficeSettings=false
+</programlisting><para>
+to the [OutOfOffice] section of the kmail configuration file. If there is no such section, simply add "[OutOfOffice]" on
+a line by itself just above the option.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Allow out-of-office scripts to be uploaded by the user, but no settings changed.</guilabel></term>
+<listitem>
+<para>
+If you want to allow your users to upload their own out-of-office scripts but you do not want them to be
+able to change the domain to react to and the react-to-spam setting, you can add:
+</para>
+<programlisting>AllowOutOfOfficeUploadButNoSettings=true
+</programlisting><para>
+to the [OutOfOffice] section of the kmail configuration file. If there is no such section, simply add "[OutOfOffice]" on
+a line by itself just above the option.
+</para>
+</listitem>
+</varlistentry>
+
+
+<varlistentry>
+<term><guilabel>Default domain to limit out-of-office replies to.</guilabel></term>
+<listitem>
+<para>
+When editing vacation (out-of-office) scripts, the user can specify a domain to
+limit the sending of such replies to. To pre-load this setting with a default
+value, add
+</para>
+<programlisting>OutOfOfficeDomain=myMailDomain.test
+</programlisting><para>
+to the [OutOfOffice] section of the kmail configuration file. If there is no such section, simply add "[OutOfOffice]" on
+a line by itself just above the option.
+
+Applying defaults to the out-of-office configuration dialog via the corresponding
+button will restore this domain, in case the user has changed it.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Enable sending of out-of-office replies to messages marked as SPAM.</guilabel></term>
+<listitem>
+<para>
+By default, out-of-office replies are not sent to messages marked as SPAM. To override this
+behavior, add
+</para>
+<programlisting>OutOfOfficeReactToSpam=true
+</programlisting><para>
+to the [OutOfOffice] section of the kmail configuration file. If there is no such section, simply add "[OutOfOffice]" on
+a line by itself just above the option.
+
+Applying defaults to the out-of-office configuration dialog via the corresponding
+button will restore this setting, in case the user has changed it.
+</para>
+</listitem>
+</varlistentry>
<varlistentry>
<term><guilabel>disregardUmask</guilabel></term>
@@ -2030,7 +2181,7 @@ To enable the feature, add a line reading (under [General] section):
<listitem><para>Activate this option to automate the handling of not yet uploaded messages in disconnected IMAP
folders that can not be uploaded. This can happen if the folder was removed from the server or your access
rights have been restricted. Such messages will automatically moved to a newly created lost+found folder if
-this option is enabled, you will be ask how to proceed everytime otherwise.
+this option is enabled, you will be ask how to proceed every time otherwise.
To enable the feature, add a line reading:
</para>
diff --git a/doc/kmail/index.docbook b/doc/kmail/index.docbook
index fe38a5100..06faeb065 100644
--- a/doc/kmail/index.docbook
+++ b/doc/kmail/index.docbook
@@ -9,6 +9,7 @@
<!ENTITY kmail-menus SYSTEM "menus.docbook">
<!ENTITY kmail-faq SYSTEM "faq.docbook">
<!ENTITY kmail-importing SYSTEM "importing.docbook">
+ <!ENTITY kmail-chiasmus SYSTEM "using-chiasmus.docbook">
<!ENTITY kmail-credits-and-licenses SYSTEM "credits-and-licenses.docbook">
<!ENTITY % addindex "IGNORE">
<!ENTITY % English "INCLUDE" > <!-- change language only here -->
@@ -126,6 +127,7 @@
&kmail-menus;
&kmail-faq;
&kmail-importing;
+&kmail-chiasmus;
&kmail-credits-and-licenses;
<appendix id="installation">
diff --git a/doc/kmail/using-chiasmus.docbook b/doc/kmail/using-chiasmus.docbook
new file mode 100644
index 000000000..cd075d868
--- /dev/null
+++ b/doc/kmail/using-chiasmus.docbook
@@ -0,0 +1,158 @@
+<chapter id="chiasmus">
+
+<chapterinfo>
+<authorgroup>
+<author>
+<firstname>Jan-Oliver</firstname>
+<surname>Wagner</surname>
+<affiliation><address>
+<email>jan@intevation.de</email>
+</address></affiliation>
+</author>
+<author>
+<firstname>Till</firstname>
+<surname>Adam</surname>
+<affiliation><address>
+<email>till@kdab.net</email>
+</address></affiliation>
+</author>
+
+</authorgroup>
+
+<date>2005-06-30</date>
+<releaseinfo>1.8</releaseinfo>
+</chapterinfo>
+
+<title>Using the Chiasmus encryption tool</title>
+
+<sect1 id="chiasmus-preparations">
+<title>Preparations</title>
+
+<para>
+To encrypt and decrypt with Chiasmus, you need the BSI's Chiasmus
+command line tool for GNU/Linux. It is intended solely for use in
+government agencies and availabe from the BSI on request.
+</para>
+
+<para>
+When executed without parameters, the <command>chiasmus</command>
+program should output something like:
+</para>
+
+<para>
+<screen>
+Chiasmus (R) fuer Windows K 1.8.0.0
+Bundesamt fuer Sicherheit in der Informationstechnik
+Kontakt: Chiasmus@bsi.bund.de
+(C) 2001 - 2005
+[ ...]
+</screen>
+</para>
+
+<para>
+Version 1.8.0.0 was tested succesfully. Other versions may or may not
+work correctly.
+</para>
+
+<para>
+As a last preparation step a directory which will hold the key files
+ending in <filename>.xis</filename> has to be created, if none already exists. Usually
+<filename class="directory">~/.chiasmus/</filename> is used.
+</para>
+
+</sect1>
+
+<sect1 id="chiasmus-configuration">
+ <title>Configuration</title>
+<para>
+Select <menuchoice><guimenu>Settings</guimenu><guimenuitem>Configure KMail
+</guimenuitem></menuchoice> and choose the <guilabel>Crypto-Backends</guilabel>
+tab on the Security page. Select the entry for <guilabel>Chiasmus</guilabel> and click
+<guibutton>Configure....</guibutton> to open the configuration dialog
+for the Chiasmus backend.
+</para>
+
+<para>
+Specify the path to the Chiasmus binary and the directory where key files are
+to be stored, using the file selection dialogs which open when you click the
+folder icons next to the path entries.
+</para>
+
+<para>
+Close the backend configuration dialog by clicking <guibutton>Ok</guibutton>
+and check the <guilabel>Chiasmus Checkbox</guilabel> to activate it. Then also close the main
+configuration dialog.
+</para>
+
+</sect1>
+
+
+<sect1 id="chiasmus-encryption">
+ <title>Encryption</title>
+<para>
+To encrypt a message with Chiasmus, select <menuchoice><guimenu>
+Options</guimenu><guimenuitem>Encrypt message with chiasmus
+</guimenuitem></menuchoice>. A dialog comes up in which you can select
+the key file to use, as well as additional command line arguments to
+be passed to <command>chiasmus</command>.
+</para>
+
+<note>
+<para>
+If you want to use Chiasmus encryption regularly, you should add
+an icon for that option to your toolbar, using <menuchoice><guimenu>
+Settings</guimenu><guimenuitem>Configure toolbars</guimenuitem>
+</menuchoice>. Move the entry for <guilabel>Encrypt with Chiasmus
+</guilabel> from the left side of the dialog to the right, using the
+buttons between the two panes. You can then quickly enable or disable
+Chiasmus encryption using that toolbar button and have a visual
+indication of the current state.
+</para>
+</note>
+
+<note>
+<para>
+If automatic saving of backup copies of currently edited messages is
+enabled, you will be prompted for your Chiasmus password, if Chiamsus
+encryption is active.
+</para>
+</note>
+
+<para>
+On message sending, you will be prompted for the password. If the password
+is correct, the text of the message and all its attachments will be
+encrypted.
+</para>
+
+<note>
+<para>
+The other signing and encryption options are completely independent of
+the Chiasmus encryption. You can use those in addition to Chiasmus,
+&eg; to sign the message. Additional encryption, on the other hand,
+does not make much sense and complicates decryption for the
+recipients.
+</para>
+</note>
+
+</sect1>
+
+<sect1 id="chiasmus-decryption">
+ <title>Decryption</title>
+<para>
+&kmail; and &kontact; detect messages that have been encrypted
+using Chiasmus and will automatically ask for the key file to use for
+decryption, as well as the corresponding password. If the password is correct, the
+message will be decrypted and displayed.
+</para>
+
+<para>
+To decrypt attachments that were encrypted using Chiasmus (&ie; those which have
+a file name ending in <filename>.xia</filename>), right-click on the
+attachment you want to decrypt and select <menuchoice><guimenuitem>Decrypt using Chiasmus
+</guimenuitem></menuchoice>. After you have chosen a key file to be used for decryption and
+entered the correct password for it, a file selection dialog will allow you
+to specify where the decrypted attachment should be saved.
+</para>
+</sect1>
+
+</chapter>
diff --git a/doc/kmail/using-kmail.docbook b/doc/kmail/using-kmail.docbook
index 1d3b3e381..6bc1046fa 100644
--- a/doc/kmail/using-kmail.docbook
+++ b/doc/kmail/using-kmail.docbook
@@ -375,6 +375,25 @@ checker. Note that you may first need to configure the spellchecker using
</sect2>
+<sect2 id="setup-text-snippets">
+<title>Setting Up the Text Snippets Tool</title>
+<para>
+When editing in the composer window you can store often used parts of text as snippets. To configure the capabilities of the mail snippets part select <menuchoice> <guimenu>Settings</guimenu> <guimenuitem>Snippets</guimenuitem> </menuchoice> from the menubar. A new panel will appear on the left side of the composer.
+</para>
+<para>To add a new snippet to Snippet Panel, right click on panel, click on <menuchoice><guimenu>Add Snippet</guimenu></menuchoice> in the context menu. A snippet editor dialog will appear, in which new text can be added and the snippet can be given a name. Also a <guilabel>Shortcut</guilabel> can be associated with the snippet.
+Snippets can be grouped together as well by creating groups and adding snippets to particular group. If you want to view the stored text in a tooltip window whenever you keep the mouse cursor over the title of that snippet.
+</para>
+<para>The <guilabel>Snippets</guilabel> tool allows for a variable text in predefined places any time you insert a snippet into a file. To accomplish this <guilabel>Snippets</guilabel> provides its own variables' mechanism. You can set up its behaviour in the snippet text itself by using separators ( $ ) that enclose the variable names. For example : $variablename$, $invoicenumber$, $weekno$.
+</para>
+<para>
+The variable separator can be changed to some other character by changing "snippetDelimiter" in [SnippetPart] section. The Text Snippet configuration file can be found here $KDEHOME/share/config/kmailsnippetrc .
+<programlisting>
+snippetDelimiter=$
+</programlisting>
+
+</para>
+
+</sect2>
</sect1>
<sect1 id="folders">
@@ -503,7 +522,7 @@ events by using the <guilabel>Generate free/busy and activate alarms for</guilab
choice box.</para>
<para>In case you don't want to receive reminders for folders shared by someone else,
-you can block them locally by activating the <guilabel>Block free/busy and alarms locally</guilabel>
+you can block them locally by activating the <guilabel>Block alarms locally</guilabel>
checkbox.</para>
</sect3>
@@ -1321,7 +1340,7 @@ which you do not like.</para>
</varlistentry>
<varlistentry>
<term><guilabel>Forward To</guilabel></term>
-<listitem><para>This will forward the message inline (&ie; as if you selected <menuchoice><guimenu>Message</guimenu><guimenuitem>Forward</guimenuitem><guimenuitem>Inline...</guimenuitem></menuchoice>) to another email address.</para>
+<listitem><para>This will forward the message inline (&ie; as if you selected <menuchoice><guimenu>Message</guimenu><guimenuitem>Forward</guimenuitem><guimenuitem>Inline...</guimenuitem></menuchoice>) to another email address. You can select the template to be used when forwarding with this filter with the drop down list.</para>
</listitem>
</varlistentry>
<varlistentry>
diff --git a/doc/kontact/index.docbook b/doc/kontact/index.docbook
index 15a7c2c01..25b0a31f6 100644
--- a/doc/kontact/index.docbook
+++ b/doc/kontact/index.docbook
@@ -948,10 +948,89 @@ documentation</ulink>.
</sect1>
<sect1 id="kontact-configure-profiles">
<title>&kontact; Profiles</title>
-<para>&kontact;'s profile support makes it possible to load and save user settings in profiles.
-The settings stored in the profile include typical Look&amp;Feel related options such as app-specific color schemes, icon sets, toolbar layout and application defaults. Personal information, e.g. accounts and identities are not stored in profiles.
+<para>A profile is an arbitrary set of configuration values for any of the kontact components (mail, calendar, etc.) accompanied by a configuration file for the profile itself, which specifies its name, description etc. An example profile configuration file looks like this:
+</para>
+
+<informalexample>
+<para>
+<literallayout>
+[Kontact Profile]
+Description=Default KDE Kontact settings
+Identifier=KontactDefaults
+Name=Kontact Style
+</literallayout>
+</para>
+<para>
+The format is the standard .ini file format used for configuration throughout KDE, including in kiosk.
+</para>
+</informalexample>
+
+<para>
+&kontact;'s profile support makes it possible to load and save user settings in profiles.
+The settings stored in the profile include typical Look&amp;Feel related options such as app-specific color schemes, icon sets, toolbar layout and application defaults. Personal information, e.g. accounts and identities are not stored in profiles.
+</para>
+
+<para>
Two default profiles are provided by Kontact: &quot;&kontact; Style&quot;, which contains the default &kontact; settings, and &quot;Outlook Style&quot;, adapting &kontact; to Microsoft Outlook Look&amp;Feel.
-The user can adapt existing profiles, create new profiles from his current settings, and import and export profiles. To manage profiles, choose &quot;Configure Profiles&quot; from the &quot;Settings&quot; menu.
+The user can adapt existing profiles, create new profiles from his current settings, and import and export profiles.
+</para>
+
+<para>
+The dialog opened through Settings -> "Configure Profiles" allows profiles to be imported, exported, created, deleted and saved. They can also be loaded (applied) from there. Saving applies the currently active settings throughout Kontact to the selected profile, while import and export allow existing profiles to be written to or read from directories. To change a setting, one can edit the kontactrc file using a text editor and save it.
+</para>
+
+<para>
+Apart from the configuration file, a profile directory can contain configuration skeleton files for Kontact as a whole (kontactrc) or for any of the components (korganizerrc, kmailrc, etc.). These files can in turn contain any configuration values that the profile should set (overriding the user's current configuration) when the profile is loaded.
+
+<itemizedlist>
+ <listitem><para>
+ The korganizer configuration for the "Kontact Defaults" profile for example sets the calendar view to be merged, by default :
+<informalexample>
+<para>
+ [Views]
+ Agenda View Calendar Display=CalendarsMerged
+</para>
+</informalexample>
+</para>
+ </listitem>
+
+ <listitem><para>
+ The Outlook-like profile, on the other hand, sets it to be side by side, like in Outlook:
+<informalexample>
+<para>
+ [Views]
+ Agenda View Calendar Display=CalendarsSideBySide
+</para>
+</informalexample>
+</para>
+ </listitem>
+
+ <listitem><para>
+ If a profile wants to reset or remove a configuration key, it can specify that key like so:
+<informalexample>
+<para>
+ [General]
+ activeBackground=KONTACT_PROFILE_DELETE_KEY
+</para>
+</informalexample>
+</para>
+ </listitem>
+
+ <listitem><para>
+ This example resets the background color to whatever the KDE style suggests. The Outlook compatability profile sets this key to the Windows/Outlook color style:
+<informalexample>
+<para>
+ [General]
+ activeBackground=47,103,255
+</para>
+</informalexample>
+</para>
+ </listitem>
+ </itemizedlist>
+</para>
+
+<para>
+Currently Kontact ships with two (incomplete) profiles, one which (re-)configures things to look and feel the way Kontact natively does, while the other one attempts to approach the look&amp;feel of Outlook on Windows. To this end they change a variety of things, concretely the color palette used, the icon theme used, how the calendar view is layed out, whether the navigation toolbar is visible how the splitter sizes are initialized, in the main kontact interface.
</para>
</sect1>
</chapter>
diff --git a/doc/korganizer/index.docbook b/doc/korganizer/index.docbook
index a0398ed26..83b207e14 100644
--- a/doc/korganizer/index.docbook
+++ b/doc/korganizer/index.docbook
@@ -4,8 +4,6 @@
<!ENTITY kappname "&korganizer;">
<!ENTITY package "kdepim">
<!ENTITY plugins-chapter SYSTEM "plugins-chapter.docbook">
- <!ENTITY exchange-plugin-workshop SYSTEM "exchange-plugin.docbook">
- <!ENTITY group-scheduling-workshop SYSTEM "group-scheduling.docbook">
<!ENTITY outlook-to-vcalendar-workshop SYSTEM "outlook-to-vcalendar.docbook">
<!ENTITY % addindex "IGNORE">
<!ENTITY % English "INCLUDE">
@@ -123,7 +121,7 @@ help you keep your schedule. </para></abstract>
<keyword>alarm</keyword>
<keyword>appointment</keyword>
<keyword>event</keyword>
-<keyword>jornal</keyword>
+<keyword>journal</keyword>
<keyword>to-do</keyword>
</keywordset>
@@ -153,7 +151,7 @@ information and the freedom to choose the best solutions.
&kontact;, offering you an integrated solution for your
communication and information management needs: email, notes, contacts
management, news reader, synchronization with portable devices, and news feeds
-reader. Even if you don't use it inside &kontact;, &korganizer; is
+reader. Even if you do not use it inside &kontact;, &korganizer; is
integrated with the other &kde; <acronym>PIM</acronym> applications.
For instance, you can configure it to show birthdays from &kaddressbook; in your
agenda, use &kmail; to send and receive invitations, &etc;</para>
@@ -350,7 +348,7 @@ appear instantly, allowing you to set the new due date.</para>
<para>This five-minute course covered only the basic operation of &korganizer;.
Now you should go on and read the rest of this manual to unleash the full
-power of &korganizer;'s capabilities. But if you don't feel like it, you
+power of &korganizer;'s capabilities. But if you do not feel like it, you
should at least skip through the <link linkend="faq">&FAQ;</link>.</para>
</sect1>
@@ -405,7 +403,7 @@ want to use another resource, especially if you use a supported groupware
server. Please ask the server administrator for the information required to
configure the groupware resource, including free/busy information publishing
and retrieving. Access to free/busy information allows an event organizer to
-take the attendee's calendar in consideration when adding him to the the event's
+take the attendee's calendar in consideration when adding him to the event's
attendee list.</para>
<note><para>Besides calendar storage, groupware servers typically offer contacts,
@@ -514,7 +512,7 @@ storing your calendar information under
<listitem><para>
If you have access to a server that supports the
<ulink url="http://www.groupdav.org">GroupDav protocol</ulink>, add this
-resource in order to be able to to save (and load) events<!--, journals, free/busy information?--> and to-dos
+resource in order to be able to save (and load) events<!--, journals, free/busy information?--> and to-dos
to the server. To add the resource, you will need to know the server &URL;, your
user name and your password. The GroupDav protocol supports the storage of
contacts, so you may want to add and configure the &kaddressbook;
@@ -532,7 +530,7 @@ date list can be obtained at the
<listitem><para>
If you have access to a
<ulink url="http://www.novell.com/products/groupwise">Novell GroupWise Server</ulink>
-(version 6.5 or later), add this resource in order to be able to to save (and load)
+(version 6.5 or later), add this resource in order to be able to save (and load)
events, free/busy information <!--,journals ?-->and to-dos to the server. To add the resource, you will
need to know the server &URL;, your user name and your password. There is
support for storage of contacts, so you may want to configure &kaddressbook;
@@ -552,7 +550,7 @@ GroupWise resources, but &kmail;, &kaddressbook; too.</para>
<term><guilabel>Calendar on IMAP Server via &kmail;</guilabel></term>
<listitem><para>
If you have access to a server that shares calendar data via IMAP, add this
-resource in order to be able to to save (and load) events, to-dos, free/busy
+resource in order to be able to save (and load) events, to-dos, free/busy
information and journal entries to the IMAP server. To enable IMAP access, you
will need to configure &kmail; first, then add the &korganizer; resource.
Also, since you are using &kmail; to contact the server, &korganizer; will
@@ -617,7 +615,7 @@ corruption, you will lose only one calendar item, not the whole calendar.</para>
<listitem><para>
If you have access to a
<ulink url="http://www.microsoft.com/exchange">Exchange 2000 Server</ulink>,
-add this resource in order to be able to to save (and load)
+add this resource in order to be able to save (and load)
events FIXME:,journals, free/busy information and to-dos? to the server. To add the resource, you will
need to know the server &URL;, FIXME:port? your user name and your password. There
is support for (read only) contacts, so you may want to configure &kaddressbook;
@@ -690,7 +688,7 @@ the next start, if you set the <guilabel>Automatic Save</guilabel> to
to a regular interval). If you plan to use a calendar resource in
writable mode, make sure that your connection is stable, configure the
resource to save the file on each change (or at frequent intervals),
-and don't reload the file at regular intervals.</para>
+and do not reload the file at regular intervals.</para>
<para>A related, but opposite problem, is that two users cannot safely edit
the same remote file at the same time, because the remote file resource does not
@@ -706,13 +704,13 @@ the file, his changes will be lost.
<term><guilabel>SUSE &Linux; OpenExchange Server</guilabel></term>
<listitem><para>
If you have access to a
-<ulink url="http://www.novell.com/products/groupwise">SUSE &Linux; OpenExchange
-Server</ulink>, version 4.1, add this resource in order to be able to to save
+<ulink url="http://www.novell.com/coolsolutions/openexchange/">SUSE &Linux; OpenExchange
+Server</ulink>, version 4.1, add this resource in order to be able to save
(and load) events, free/busy information <!--,journals ?-->and to-dos to the server. To add the
resource, you will need to know the server &URL;, your user name and your
password. There is support for storage of contacts, so you may want to configure
&kaddressbook; resource.</para>
-<para>The most practical way to configure the access to a GroupWise server is
+<para>The most practical way to configure the access to an OpenExchange server is
to use the <application>sloxwizard</application> wizard. You can start it
from the command line prompt:
@@ -730,7 +728,7 @@ OpenExchange resources, but &kmail;, &kaddressbook; too.</para>
<listitem><para>
If you have access to a
<ulink url="http://www.egroupware.org">eGroupware
-Server</ulink>, version 1.0, add this resource in order to be able to to save
+Server</ulink>, version 1.0, add this resource in order to be able to save
(and load) events, free/busy information <!--,journals ?-->and to-dos to the server. To add the
resource, you will need to know the server &URL;, your user name and your
password. There is support for storage of contacts, so you may want to configure
@@ -827,8 +825,8 @@ calendar information with your colleagues and friends.</para>
<!--TODO: use case: export your friends birthdays?-->
<procedure id="procedure-export-html">
-<step><para>Disable all the resources you don't want to export, and filter out
-the items you don't want to export.</para></step>
+<step><para>Disable all the resources you do not want to export, and filter out
+the items you do not want to export.</para></step>
<step><para>Choose the <menuchoice><guimenu>File</guimenu>
<guisubmenu>Export</guisubmenu><guimenuitem>Export Web Page...</guimenuitem>
</menuchoice> menu item. You will get a window with three tabs:
@@ -1062,7 +1060,7 @@ a <guiicon>chasing-arrows</guiicon> icon is displayed if it repeats multiple
times. Hovering the mouse over an calendar item will bring up a tooltip
with the item detailed information. To make &korganizer; show a red line
marking the current-time on the current day (the Marcus Bains line),
-check the <guilabel>Show current-time (Marcus Bains Line)</guilabel> box in the
+check the <guilabel>Show current-time (Marcus Bains) line</guilabel> box in the
<link linkend="config-main-views">&korganizer; view
configuration</link>.</para>
@@ -1110,7 +1108,7 @@ will be able to quickly identify the type of event by its color.
</para>
<para>
-The aganda view can display events from all your calendars merged into one view or
+The agenda view can display events from all your calendars merged into one view or
show a view per calendar. Having both views available via tabs is also possible and
can be <link linkend="config-main-views">customized in the preferences dialog</link>.
</para>
@@ -1337,7 +1335,7 @@ the agenda view or in the month view (depending on the
<title>Filters</title>
<para>To help you view, find and export your data, you can create and
-use filters for your calendars. For instance, if you don't want to view
+use filters for your calendars. For instance, if you do not want to view
completed to-dos, you can filter them out, instead of
<link linkend="managing-purge-archive">purging them</link>. If you assign
categories, you can use them to create filters.</para>
@@ -1354,11 +1352,11 @@ and edit filters that will affect which items will be displayed by
<para>The <menuchoice><guimenu>View</guimenu>
<guisubmenu>Filter</guisubmenu></menuchoice> submenu and the filter toolbar drop
down offer access to all available filters created using
-the <link linkend="menu-settings-edit-filters"><guilabel>Edit
+the <link linkend="menu-settings-edit-filters"><guilabel>Edit Calendar
Filters</guilabel></link> dialog. To toggle the display of the filters toolbar
on and off, choose the <menuchoice><guimenu>Settings</guimenu>
<guisubmenu>Toolbars</guisubmenu><guimenuitem>Filter toolbar</guimenuitem></menuchoice>.
-If you don't want to use any filter, choose <guilabel>No filter</guilabel>.</para>
+If you do not want to use any filter, choose <guilabel>No filter</guilabel>.</para>
<para>Filters are useful when <link linkend="managing-export">exporting your
calendar</link>. If you use a filter, only the filtered (visible) items will
@@ -1381,8 +1379,8 @@ entries) according to title, description, and/or categories.
The find action will only search the specified fields.</para>
<tip><para>You can use wildcards if you do not remember the exact summary. If
-you don't know single character of the summary, put <userinput>?</userinput>
-instead of the missing character. If you don't know more characters, use
+you do not know single character of the summary, put <userinput>?</userinput>
+instead of the missing character. If you do not know more characters, use
<userinput>*</userinput>. For instance if you know that the event or to-do has
<emphasis>meeting</emphasis> in the beginning and <emphasis>product</emphasis>
after, you would write <userinput>meeting*product</userinput> in the Find dialog.
@@ -1449,7 +1447,7 @@ Enter your data as described below.</para></step>
<para>This is a thorough description of the individual event window fields and
widgets. Not all fields have to be filled in; some can be left empty. Read the
-<link linkend="entering-data-required-fields">Required fields section</link>
+<link linkend="entering-data-required-fields">Required fields</link> section
for detailed information. And if you prefer to learn by example, there's one
in the <link linkend="examples-entering-event">Entering event</link> section.
</para>
@@ -1511,7 +1509,7 @@ program; if you do not, the program will not run.</para></tip>-->
reminded, or click the <guibutton>Advanced</guibutton> button to open the
<guilabel>Edit Reminders</guilabel> dialog. Using this dialog, you can set
repeating intervals for your reminders, and create special reminders that play
-sounds, run programs, or send emails.</para>
+sounds or run programs.</para>
<!--Click the musical <guiicon>Note</guiicon> symbol to choose the
alarm sound. Click the <guiicon>Gear</guiicon> icon to browse for a
@@ -1522,7 +1520,7 @@ program that should run at the alarm time.</para>--></listitem>
<term><guilabel>Show Time As:</guilabel></term>
<listitem><para>The duration of the event may be shown as Busy or Free in your
schedule. Choose it from the <guilabel>Show Time As</guilabel>
-menu.</para></listitem>
+drop down box.</para></listitem>
</varlistentry>
<varlistentry>
@@ -1540,7 +1538,7 @@ you.</para></listitem>
<term><guilabel>Select Categories</guilabel></term>
<listitem><para>You can assign several
<link linkend="categories-view">categories</link> to a calendar item. Click the
-<guilabel>Select Categories</guilabel> button to open the
+<guilabel>Select</guilabel> button to open the
<guilabel>Select Categories</guilabel> dialog. Check the category boxes to
assign suitable categories to the event. You can also add a new category, modify
a category or delete a category by pressing the button
@@ -1556,8 +1554,8 @@ either Personal or Special Occasion - it is your choice.</para></tip>
<varlistentry>
<term><guilabel>Access:</guilabel></term>
<listitem><para>Choose <guilabel>Private</guilabel> or <guilabel>Confidential</guilabel>
-to keep the event private or confidential. Currently, this choice correctly
-sets the <quote>CLASS</quote> attribute of the events to
+to keep the event private or confidential. Currently, this choice correctly
+sets the <quote>CLASS</quote> attribute of the events to
<quote>PUBLIC</quote>, <quote>PRIVATE</quote> or <quote>CONFIDENTIAL</quote>.
However, if these settings are really used to restrict the access of the information
depends on the client and / or groupware server implementation.</para>
@@ -1572,7 +1570,7 @@ only you can access.</para></warning></listitem>
</variablelist>
-<para>When you want to confirm, call off or revert the entered data, choose
+<para>When you want to confirm, apply or call off the entered data, choose
among the <link linkend="reference-action-buttons">Action Buttons</link>,
<guibutton>OK</guibutton>, <guibutton>Apply</guibutton> and
<guibutton>Cancel</guibutton>.</para>
@@ -1649,7 +1647,7 @@ on.</para></listitem>
<para>This is similar to Monthly. You need to choose whether or not you
are indicating a calendar day of the year (&eg;, the 250th day of the
year) - <guilabel>Recur on day <replaceable>#</replaceable> of the
-year</guilabel>, in in a specific week on a specific day of the week of a month
+year</guilabel>, in a specific week on a specific day of the week of a month
(&eg;, the 2nd Tuesday of March), or the day of the month in a
particular month of the year - <guilabel>Recur on day <replaceable>#</replaceable>
of the <replaceable>month</replaceable></guilabel>. By default, &korganizer;
@@ -1775,7 +1773,7 @@ is displayed in the details list window gives you quick overview of what
should be done to make the event successful. It can be used for sorting (see
above). If you use groupware schedule and request responses from your
attendees, as you receive the responses the status of the attendee will be
-updated. If you don't request responses, you will have to update the status
+updated. If you do not request responses, you will have to update the status
manually.</para></listitem>
</varlistentry>
@@ -1819,7 +1817,7 @@ sending the invitations.</para>
represents one of the attendees, listed on the left. The marked areas on the
chart represent the time already taken by other events, unmarked areas represent
time free from other events. You can move the event to a different point in time
-by dragging it with the mouse, or resize it, by moving the edges of the highlighted
+by dragging it with the mouse, or resize it by moving the edges of the highlighted
area with the mouse.</para>
<para>The free/busy information is only available if the
@@ -1827,7 +1825,7 @@ attendee publishes his free/busy schedule, and if &korganizer; is correctly
configured to retrieve it. For more information about configuring &korganizer;
to publish and retrieve free/busy information, please check the
<xref linkend="config" />. Double-clicking on an attendee entry in the list
-will allow you to enter the location of their free/busy information.
+will allow you to enter the location of their free/busy information.
</para>
<variablelist>
@@ -1837,7 +1835,7 @@ will allow you to enter the location of their free/busy information.
<listitem><para>Sets the zoom level on the schedule chart. <guilabel>Hour</guilabel>
shows a range of several hours, <guilabel>Day</guilabel> shows a range of a few
days, <guilabel>Week</guilabel> shows a range of a few months, and
-<guilabel>Month</guilabel> shows a range of a few years, while
+<guilabel>Month</guilabel> shows a range of a few months, while
<guilabel>Automatic</guilabel> selects the range most appropriate for the
current event or to-do.</para></listitem>
</varlistentry>
@@ -1989,7 +1987,7 @@ where the to-do will take place.</para></listitem>
<term><guilabel>Date &amp; Time</guilabel></term>
<listitem><para>The <guilabel>Due</guilabel> and <guilabel>Start</guilabel>
boxes are not initially checked, as to-dos usually do not have a start and due
-date. Check one of both boxes and
+date. Check one or both boxes and
change these dates as desired. Enter the dates directly or use the
<link linkend="glossary" endterm="gloss-calendar-widget">Calendar Widget</link>.
Choose time from quarter hour intervals, or enter the desired time directly into
@@ -2013,7 +2011,7 @@ in steps of 10%.</para></listitem>
<varlistentry>
<term><guilabel>Priority</guilabel></term>
<listitem><para>Assign a priority to your to-do. This drop down menu offers
-priorities from one to five, one being the highest. Initially to-dos are set
+priorities from one to nine, one being the highest. Initially to-dos are set
to priority five (medium).</para></listitem>
</varlistentry>
@@ -2029,7 +2027,7 @@ program; if you do not, the program will not run.</para></tip>-->
reminded, or click the <guibutton>Advanced</guibutton> button to open the
<guilabel>Edit Reminders</guilabel> dialog. Using this dialog, you can set
repeating intervals for your reminders, and create special reminders that play
-sounds, run programs, or send emails.</para>
+sounds or run programs.</para>
<!--Click the musical <guiicon>Note</guiicon> symbol to choose the
alarm sound. Click the <guiicon>Gear</guiicon> icon to browse for a
@@ -2188,7 +2186,7 @@ events with other users using one of these clients.
&korganizer; is integrated with &kmail; for receiving, processing, and sending
events, event responses, updates, cancellations, &etc; For instance, when you
get an invitation in &kmail;, and decide to
-accept it, by clicking the the <guilabel>accept</guilabel> link in the mail
+accept it, by clicking the <guilabel>accept</guilabel> link in the mail
body, the event is added to your calendar, and a response to the event's
organizer is sent automatically.</para>
@@ -2288,11 +2286,11 @@ choosing the <menuchoice><guimenu>Schedule</guimenu><guimenuitem>Send Invitation
to Attendees</guimenuitem></menuchoice> menu item.
The attendees get an email containing all the relevant information
for the event or to-do. They can respond to the meeting proposal by accepting or
-rejecting it or by making a counter proposal. They can also delegate or forward the
+rejecting it or by making a counter proposal. They can also delegate or forward the
invitation.
-All this information is sent to you by email again and, if you have configured &kmail;
-appropriately the attendees responses are automatically inserted in your calendar. If
-there are additional attendees willing to participate (e.g. by accepting a forwarded
+All this information is sent to you by email again and, if you have configured &kmail;
+appropriately, the attendees responses are automatically inserted in your calendar.
+If there are additional attendees willing to participate (e.g. by accepting a forwarded
invitation) you will be asked to accept the new attendees.
</para>
@@ -2340,12 +2338,14 @@ view</link>.</para>
<guibutton>Accept</guibutton> or <guibutton>Accept Cond.</guibutton>. The
last two actions will insert the item to your calendar. In any case, &kmail; will
send your response to the organizer automatically.</para>
-<para>You can also <guibutton>Delegate</guibutton> or <guibutton>Forward</guibutton>
+
+<para>You can also <guibutton>Delegate</guibutton> or <guibutton>Forward</guibutton>
the invitation. When delegating, you can suggest another person as your proxy.
-Using <guibutton>Forward</guibutton> you can forward the invitation to one or more
+Using <guibutton>Forward</guibutton> you can forward the invitation to one or more
people not yet invited.
-When the receiver of the delegation or forward accepts the invitation,
+When the receiver of the delegation or forward accepts the invitation,
the organizer will be asked to approve the new attendee.</para>
+
<para>If for any reason you changed your mind, edit your status in the item's
<link linkend="entering-data-events-attendees">attendee tab</link>. If you
checked the <guilabel>Use Groupware Communication</guilabel> box
@@ -2565,7 +2565,7 @@ network files, &etc;), please check <xref linkend="managing-resources" />.</para
<title>Personal</title>
<para>The personal options relate to your personal identity, and other
-miscellaneous things that don't fall under any of the other general
+miscellaneous things that do not fall under any of the other general
categories.</para>
<variablelist>
@@ -2732,10 +2732,10 @@ defined in the <guilabel>Use holiday region</guilabel> drop down above.</para>
<variablelist>
<varlistentry>
-<term><guilabel>Enable tooltips displaying summary of events</guilabel></term>
+<term><guilabel>Enable tooltips for displaying summaries</guilabel></term>
<listitem><para>If your summary for an event is longer than would fit in the
current View, the remaining characters are not displayed. Check <guilabel>Enable
-tooltips displaying summary of events</guilabel> if you want the full summary
+tooltips for displaying summaries</guilabel> if you want the full summary
displayed when the hovering the mouse pointer over the appointment for a few
seconds.</para></listitem>
</varlistentry>
@@ -2769,6 +2769,13 @@ navigator</guilabel> box is checked, the days containing weekly recurring
events are shown in bold typeface in the date navigator.</para></listitem>
</varlistentry>
+<varlistentry>
+<term><guilabel>Week numbers select a work week when in work week view</guilabel></term>
+<listitem><para>If the <guilabel>Week numbers select a work week when in work
+week view</guilabel> box is checked, clicking on the week numbers along the
+side of the date navigator will navigate through work weeks rather than
+through normal 7-day weeks.</para></listitem>
+</varlistentry>
</variablelist>
@@ -2785,7 +2792,7 @@ in the agenda view.</para></listitem>
<varlistentry>
<term><guilabel>Next x days:</guilabel></term>
<listitem><para>This option allows you to change the amount of days of the
-<guimenu>Next x Days</guimenu> menu item in the <guimenu>Views</guimenu>
+<guimenu>Next x Days</guimenu> menu item in the <guimenu>View</guimenu>
menu.</para></listitem>
</varlistentry>
@@ -2817,7 +2824,7 @@ plan.</para></listitem>
<link linkend="config-main-colors">assign a different color to each
resource</link>. This check box toggles the use the resource color when
displaying the to-do or event in the agenda view on and off. Note that if you
-don't assign different colors, there is little sense in using this feature,
+do not assign different colors, there is little sense in using this feature,
as &korganizer; default configuration is to use the same color for
all resources.</para></listitem>
</varlistentry>
@@ -2856,7 +2863,7 @@ in the whole &korganizer; window instead of sharing the window with the sidebar
<link linkend="config-main-colors">assign a different color to each
category</link>. If you check this box, the event or to-do color in the month
view will reflect the category color, instead of using no color, or only the
-resource color. Note that if you don't assign different category colors,
+resource color. Note that if you do not assign different category colors,
there is little sense in using this feature, as &korganizer; default
configuration is to use the same color for all categories.</para></listitem>
</varlistentry>
@@ -2867,7 +2874,7 @@ configuration is to use the same color for all categories.</para></listitem>
<link linkend="config-main-colors">assign a different color to each
resource</link>. If you check this box, the event or to-do color in the month
view will reflect the resource color, instead of using no color, or only the
-category color. Note that if you don't assign different resource colors, there
+category color. Note that if you do not assign different resource colors, there
is little sense in using this feature, as &korganizer; default configuration
is to use the same color for all resources.</para></listitem>
</varlistentry>
@@ -2953,7 +2960,7 @@ navigator.</para></listitem>
<listitem><para>This button opens the <guilabel>Select Color</guilabel> dialog,
allowing you to select the highlight color. The highlight color will be used for
marking the currently selected area in your agenda and in the date
-navigator.navigator.</para></listitem>
+navigator.</para></listitem>
</varlistentry>
<varlistentry>
@@ -2974,7 +2981,7 @@ allowing you to select the agenda view background color.</para></listitem>
<varlistentry>
<term><guilabel>Working hours color</guilabel></term>
<listitem><para>This button opens the <guilabel>Select Color</guilabel> dialog,
-allowing you to select the agenda view.</para></listitem>
+allowing you to select the color of the working hours background in the agenda view.</para></listitem>
</varlistentry>
<varlistentry>
@@ -2992,7 +2999,7 @@ allowing you to select the to-do overdue color.</para></listitem>
<varlistentry>
<term><guilabel>Categories</guilabel></term>
<listitem><para>This group allows you to assign a color to each category. Select
-a category in the drop down, and press the button to open the
+a category in the drop down list, and press the button to open the
<guilabel>Select Color</guilabel> dialog, allowing you to select the color for
that category. <link linkend="config-main-views">Depending on the view
preferences</link>, this color will be used to mark events and to-dos which
@@ -3002,7 +3009,7 @@ belong to this category in your agenda and in the month view.</para></listitem>
<varlistentry>
<term><guilabel>Resources</guilabel></term>
<listitem><para>This group allows you to assign a color to each resource. Select
-a resource in the drop down, and press the button to open the
+a resource in the drop down list, and press the button to open the
<guilabel>Select Color</guilabel> dialog, allowing you to select the color for
that resource. <link linkend="config-main-views">Depending on the view
preferences</link>, this color will be used to mark events and to-dos which are
@@ -3026,7 +3033,7 @@ updating or deleting events or to-dos which involve others. This mail can be
an invitation to attendees of an event you created, a cancellation of an event
you created, an answer or an update on your invitation status, an event change
request, &etc; Check this option if you you want to use the groupware
-functionality (e.g Configuring &kontact; as a &kde;
+functionality (&eg; Configuring &kontact; as a &kde;
<guilabel>Kolab</guilabel> client).</para></listitem>
</varlistentry>
@@ -3119,7 +3126,7 @@ when inviting you to an event.</para>
<variablelist>
<varlistentry>
-<term><guilabel>Publish free/busy information</guilabel></term>
+<term><guilabel>Publish free/busy information automatically</guilabel></term>
<listitem><para>Enable this option if you wish your Free/Busy information to be
uploaded automatically. Note that you may skip this option and choose to mail or
upload your Free/Busy information via the <guilabel>Schedule</guilabel> menu of
@@ -3133,7 +3140,7 @@ it from other users.</para>
</varlistentry>
<varlistentry>
-<term><guilabel>Minimum time between uploads in minutes</guilabel></term>
+<term><guilabel>Minimum time between uploads (in minutes)</guilabel></term>
<listitem><para>In case you choose to publish your information automatically,
you may configure the interval of time in minutes between each upload.</para>
</listitem>
@@ -3160,7 +3167,7 @@ shall be published. Ask the server administrator for this information.</para>
<para>Kolab2 server specificity: Registered your UID (Unique IDentifier), by
default your UID would be similar to your email address on the Kolab2 server
but it may also be different. In the last case enter your UID. Ask about your
-UID to the server administrator if you don't know it.</para></listitem>
+UID to the server administrator if you do not know it.</para></listitem>
</varlistentry>
<varlistentry>
@@ -3222,7 +3229,7 @@ server.</para>
(Unique IDentifier), by default your UID would be similar to your email address
on the <guilabel>Kolab2 server</guilabel> but it may also be different. In the
last case enter your UID. Ask about your UID to the server administrator if you
-don't know it.</para></listitem>
+do not know it.</para></listitem>
</varlistentry>
<varlistentry>
@@ -3295,7 +3302,7 @@ linkend="other-features-drag-and-drop">drag-and-drop operations</link>.
<itemizedlist>
<listitem><para>The tool set is configured in the <menuchoice><guimenu>
Settings</guimenu><guimenuitem>Configure
-Toolbars....</guimenuitem></menuchoice> menu item.
+Toolbars...</guimenuitem></menuchoice> menu item.
</para></listitem>
<listitem><para>The graphic style (icon size, text position, &etc;) is
adjusted through the <guimenu>Toolbar Context Menu</guimenu>. Right click the
@@ -3324,9 +3331,9 @@ the window.</para>
<para>There are two rectangles below the toolbar title: <guilabel>Available
actions</guilabel> and <guilabel>Current actions</guilabel>. Using the left and
-right arrows (located between the rectangles) you can add icons from the
-Available actions group to the <guilabel>Current actions</guilabel> group. The
-toolbar will have every icon that is in the <guilabel>Current action</guilabel>
+right arrows (located between the rectangles) you can move icons from the
+<guilabel>Available actions</guilabel> group to the <guilabel>Current actions</guilabel> group. The
+toolbar will have every icon that is in the <guilabel>Current actions</guilabel>
box. The up and down arrows allow you reposition an icon.</para>
<tip><para>Remember that less icons may be better, because the screen is less
@@ -3439,7 +3446,7 @@ menu item and choose a different calendar). </para></listitem>
menu item to give your new calendar a filename and to save it).</para></listitem>
</itemizedlist>
-<para>For more information about this acton, please refer to
+<para>For more information about this action, please refer to
<xref linkend="managing-import-export" />.</para>
</listitem>
@@ -3518,7 +3525,7 @@ that you want to save, but also want to keep separate from your
File</guimenu> <guimenuitem>Revert</guimenuitem></menuchoice></term>
<listitem><para>When you choose <guimenuitem>Revert</guimenuitem>, &korganizer;
<action>loads the last saved version of the calendar, discarding all the
-changes made after the last save.</action>.</para>
+changes made after the last save</action>.</para>
<para>For more information about this action, please refer to
<xref linkend="managing-import-export" />.</para>
</listitem>
@@ -3578,8 +3585,8 @@ vCalendar with a few entries via email, for instance.</para>
<guimenuitem>Import From &UNIX; Ical Tool</guimenuitem>
</menuchoice></term>
<listitem><para>If you have used <application>ical</application>, a popular but
-older calendar program for &UNIX;, you may wish to <action>import your events,
-events, and to-do</action> directly to &korganizer;. This action
+older calendar program for &UNIX;, you may wish to <action>import your events
+and to-do</action> directly to &korganizer;. This action
will read the <filename>.calendar</filename> file from your home
folder and merge any entries it contains into your current calendar.
If any errors or suspicious things occur during the process, you will be
@@ -3864,7 +3871,7 @@ enough to remember in between sessions what the last active view was, and the
next time it is started, it will display that view.</para>
<para>In general, each view will provide a way of displaying your journal
-entries, to-dos and and events, constrained to a particular time period or
+entries, to-dos and events, constrained to a particular time period or
style of display. Click any item to select it for further action.
<mousebutton>Right</mousebutton> click an item to bring up a menu
with options such as <guimenuitem>edit</guimenuitem>,
@@ -4014,7 +4021,7 @@ day (<guimenuitem>Zoom In Vertically</guimenuitem> and
<listitem><para>This submenu offers access to the filters already created using
the <link linkend="menu-settings-edit-filters"><guilabel>Edit
Filters</guilabel></link> dialog. <action>Select on this submenu the filter
-that will be used in &korganizer; view.</action>. If you don't want to use a
+that will be used in &korganizer; view</action>. If you do not want to use a
filter, choose <guilabel>No filter</guilabel>.</para></listitem>
</varlistentry>
@@ -4091,8 +4098,8 @@ linkend="entering-data-to-do">the Entering To-dos</link> section.</para></listit
<guimenuitem>New Sub-to-do...</guimenuitem>
</menuchoice></term>
<listitem><para>Choose <guilabel>New Sub-to-do...</guilabel> to <action>start
-writing a new sub-to-do. The currently selected to-do will be the the
-sub-to-do parent.</action>. Initially the to-do has no due date, but you can
+writing a new sub-to-do. The currently selected to-do will be the
+sub-to-do parent</action>. Initially the to-do has no due date, but you can
specify one.</para>
<para>You can get a detailed description of the to-do window in <link
linkend="entering-data-to-do">Entering To-dos</link> section.</para></listitem>
@@ -4104,7 +4111,7 @@ linkend="entering-data-to-do">Entering To-dos</link> section.</para></listitem>
<guimenuitem>New Journal...</guimenuitem>
</menuchoice></term>
<listitem><para>Choose <guilabel>New Journal...</guilabel> to <action>start
-writing a new journal entry.</action>.</para></listitem>
+writing a new journal entry</action>.</para></listitem>
</varlistentry>
<varlistentry id="menu-actions-show-event">
@@ -4650,7 +4657,7 @@ calendar.</para>
<tip><para>However, you cannot drag from agenda view in one calendar to
agenda view in other calendar.</para></tip></listitem>
<listitem><para>Toolbars can be dragged on the screen. Move the mouse pointer
-over the tollbar's handle, and drag it to a new location on your
+over the toolbar's handle, and drag it to a new location on your
screen.</para></listitem>
</itemizedlist>
@@ -4820,7 +4827,7 @@ on your platform and the size of your calendar(s).</para>
(kdelibs). &kde; base package (kdebase) must also be installed to change
localization preferences like date and time formats. &korganizer; itself
is in the kdepim package. All packages can be found on <ulink
-url="http://www.kde.org">&kde; home page.</ulink>.</para>
+url="http://www.kde.org">&kde; home page</ulink>.</para>
<para>The &korganizer; homepage is at <ulink
url="http://korganizer.kde.org">http://korganizer.kde.org</ulink>
@@ -4856,7 +4863,7 @@ The single-arrow icons move forwards and backwards in time by increments of a
month, while the double-arrows allow moving by years at a time. Today's date
will be outlined with a small box. Dates which have events scheduled on them
will be bold. If you want to select a date, simply click it. Hold down the
-Control key and click the dates if you wish to select multiple neighbor dates at
+&Ctrl; key and click the dates if you wish to select multiple neighbor dates at
once. The dates will be displayed in the main panel.</para>
<para>Recurring events are not always displayed. You can forbid the display of
@@ -4939,7 +4946,7 @@ dialog.</para>
<itemizedlist>
<listitem><para>Events start and finish at distinct date. You can also specify
-distinct start and finish times, but you don't have to. While business
+distinct start and finish times, but you do not have to. While business
meetings, personal anniversaries and cinema visits are examples of carefully
planned events with exact time scheduling, a holiday is an event that takes
several days and thus there is no need to specify exact start and finish
diff --git a/kabc/kabcdistlistupdater/kabcdistlistupdater.desktop b/kabc/kabcdistlistupdater/kabcdistlistupdater.desktop
index 3bea0152a..c67030efa 100644
--- a/kabc/kabcdistlistupdater/kabcdistlistupdater.desktop
+++ b/kabc/kabcdistlistupdater/kabcdistlistupdater.desktop
@@ -1,20 +1,10 @@
# KDE Config File
[Desktop Entry]
Name=kabcdistlistupdater
-Name[nl]=kabcdistlijstbijwerker
Exec=kabcdistlistupdater --disable-autostart
Icon=misc
Type=Application
Comment=Tool to update the old distribution lists to the new ones.
-Comment[ca]=Eina per actualitzar les llistes de distribució antigues a les noves.
-Comment[es]=Herramienta para actualizar las antiguas listas de distribución al nuevo formato.
-Comment[et]=Tööriist vanade postiloendite uuendamiseks uue vormi kohaselt.
-Comment[nds]=Warktüüch, dat ole Verdeellisten to niege opfrischt
-Comment[nl]=Hulpmiddel om de oude distributielijsten bij te werken tot de nieuwe.
-Comment[sk]=Nástroj na aktualizáciu starých ditribučných zoznamov na nové.
-Comment[sr]=Алат за ажурирање старих дистрибуционих листи новима.
-Comment[sr@Latn]=Алат за ажурирање старих дистрибуционих листи новима.
-Comment[sv]=Verktyg för att uppdatera gamla distributionslistor till nya.
Terminal=false
NoDisplay=true
X-KDE-autostart-condition=kabcdistlistupdaterrc:Startup:EnableAutostart:true
diff --git a/kaddressbook/addresseeeditorextension.cpp b/kaddressbook/addresseeeditorextension.cpp
index 3f7fc175e..5c1ddcec6 100644
--- a/kaddressbook/addresseeeditorextension.cpp
+++ b/kaddressbook/addresseeeditorextension.cpp
@@ -22,6 +22,7 @@
*/
#include <tqlayout.h>
+#include <tqtimer.h>
#include <klocale.h>
@@ -52,17 +53,22 @@ AddresseeEditorExtension::~AddresseeEditorExtension()
void AddresseeEditorExtension::contactsSelectionChanged()
{
const KABC::Addressee::List selectedAddressees = selectedContacts();
- KABC::Addressee::List addressees;
-
+ KABC::Addressee::List modifiedAddress;
if ( mAddresseeEditor->dirty() ) {
mAddresseeEditor->save();
addressees.append( mAddresseeEditor->addressee() );
- emit modified( addressees );
+ modifiedAddress = addressees;
+ TQTimer::singleShot(0, this, TQT_SLOT(emitModifiedAddresses()));
}
mAddresseeEditor->setAddressee( selectedAddressees[ 0 ] );
}
+void AddresseeEditorExtension::emitModifiedAddresses()
+{
+ emit modified( addressees );
+}
+
TQString AddresseeEditorExtension::title() const
{
return i18n( "Contact Editor" );
diff --git a/kaddressbook/addresseeeditorextension.h b/kaddressbook/addresseeeditorextension.h
index ff4e3d657..d3368248a 100644
--- a/kaddressbook/addresseeeditorextension.h
+++ b/kaddressbook/addresseeeditorextension.h
@@ -50,10 +50,12 @@ class AddresseeEditorExtension : public KAB::ExtensionWidget
This method should be reimplemented and return a unique identifier.
*/
virtual TQString identifier() const;
-
+ private slots:
+ void emitModifiedAddresses();
private:
AddresseeEditorBase *mAddresseeEditor;
bool mDirty;
+ KABC::Addressee::List addressees;
};
#endif
diff --git a/kaddressbook/addresseeutil.cpp b/kaddressbook/addresseeutil.cpp
index d564a9cb1..7e5980176 100644
--- a/kaddressbook/addresseeutil.cpp
+++ b/kaddressbook/addresseeutil.cpp
@@ -29,6 +29,21 @@
#include "addresseeutil.h"
+#if defined(KABC_VCARD_ENCODING_FIX)
+TQByteArray AddresseeUtil::addresseesToClipboard( const KABC::Addressee::List &list )
+{
+ KABC::VCardConverter converter;
+
+ return converter.createVCardsRaw( list );
+}
+
+KABC::Addressee::List AddresseeUtil::clipboardToAddressees( const TQByteArray &data )
+{
+ KABC::VCardConverter converter;
+
+ return converter.parseVCardsRaw( data.data() );
+}
+#else
TQString AddresseeUtil::addresseesToClipboard( const KABC::Addressee::List &list )
{
KABC::VCardConverter converter;
@@ -42,6 +57,7 @@ KABC::Addressee::List AddresseeUtil::clipboardToAddressees( const TQString &data
return converter.parseVCards( data );
}
+#endif
TQString AddresseeUtil::addresseesToEmails( const KABC::Addressee::List &addrList )
{
diff --git a/kaddressbook/addresseeutil.h b/kaddressbook/addresseeutil.h
index 31d750e3f..5bcac3136 100644
--- a/kaddressbook/addresseeutil.h
+++ b/kaddressbook/addresseeutil.h
@@ -26,6 +26,7 @@
#include <tqstring.h>
#include <kabc/addressee.h>
+#include <kabc/vcardparser.h> // for KABC_VCARD_ENCODING_FIX define
/**
This class provides some utility methods for transposing an
@@ -43,15 +44,23 @@ class AddresseeUtil
/**
Same as above function, except that an entire list of KABC::Addressee
objects will be converted to vCard and put in the string.
- */
+ */
+#if defined(KABC_VCARD_ENCODING_FIX)
+ static TQByteArray addresseesToClipboard( const KABC::Addressee::List &addrList );
+#else
static TQString addresseesToClipboard( const KABC::Addressee::List &addrList );
+#endif
/**
Convert a string from the clipboard into a list of addressee objects.
If the clipboard text was not a valid vcard, an empty list
will be returned.
*/
+#if defined(KABC_VCARD_ENCODING_FIX)
+ static KABC::Addressee::List clipboardToAddressees( const TQByteArray &clipboard );
+#else
static KABC::Addressee::List clipboardToAddressees( const TQString &clipboard );
+#endif
/**
Converts the list of addressee objects into a list of email addresses.
diff --git a/kaddressbook/common/kaddressbook.kcfg b/kaddressbook/common/kaddressbook.kcfg
index 37e6ff0a6..d0a48c251 100644
--- a/kaddressbook/common/kaddressbook.kcfg
+++ b/kaddressbook/common/kaddressbook.kcfg
@@ -57,7 +57,7 @@
<entry type="Bool" name="ContactListAboveExtensions">
<default>true</default>
<whatsthis>If true, the contact list will be placed above the extensions on the left (distribution list editor etc.) instead of in the middle of the main window</whatsthis>
-
+
</entry>
</group>
diff --git a/kaddressbook/csv-templates/kaddressbook.desktop b/kaddressbook/csv-templates/kaddressbook.desktop
index a5b9c4066..505f3c549 100644
--- a/kaddressbook/csv-templates/kaddressbook.desktop
+++ b/kaddressbook/csv-templates/kaddressbook.desktop
@@ -19,7 +19,6 @@ Name[hi]=केडीईएड्रेसबुक (केडीई 3.1)
Name[hr]=KAdressBook (KDE 3.1)
Name[hu]=Címjegyzék (KDE 3.1)
Name[it]=Rubrica indirizzi (KDE 3.1)
-Name[ka]=წიგნაკი (KDE 3.1)
Name[mk]=КАдресар (KDE 3.1)
Name[nb]=Adressebok (KDE 3.1)
Name[nds]=KAdressbook (KDE 3.1)
diff --git a/kaddressbook/csv-templates/yahoo.desktop b/kaddressbook/csv-templates/yahoo.desktop
index b365365c8..43b771c85 100644
--- a/kaddressbook/csv-templates/yahoo.desktop
+++ b/kaddressbook/csv-templates/yahoo.desktop
@@ -32,7 +32,6 @@ Name[hu]=Yahoo! címjegyzék
Name[is]=Yahoo! póstfangaskrá
Name[it]=Rubrica indirizzi Yahoo!
Name[ja]=Yahoo! アドレス帳
-Name[ka]=წიგნაკი Yahoo!
Name[kk]=Yahoo! адрестік кітапшасы
Name[km]=សៀវភៅ​អាសយដ្ឋាន​របស់​យ៉ាហ៊ូ
Name[ko]=Yahoo! 주소록
@@ -58,8 +57,7 @@ Name[ta]=யாஹூ! முகவரிப் புத்தகம்
Name[tg]=Китоби адресии Yahoo!
Name[tr]=Yahoo! Adres Defteri
Name[uk]=Адресна книга Yahoo
-Name[uz]=Yahoo! manzillar daftari
-Name[uz@cyrillic]=Yahoo! манзиллар дафтари
+Name[uz]=Yahoo! манзиллар дафтари
Name[zh_CN]=Yahoo! 地址簿
Name[zh_TW]=Yahoo! 通訊錄
diff --git a/kaddressbook/customfieldswidget.cpp b/kaddressbook/customfieldswidget.cpp
index 4fc41819c..c9f4d8610 100644
--- a/kaddressbook/customfieldswidget.cpp
+++ b/kaddressbook/customfieldswidget.cpp
@@ -289,6 +289,33 @@ void FieldWidget::loadContact( KABC::Addressee *addr )
}
}
+void FieldWidget::setReadOnly( bool readOnly )
+{
+ FieldRecordList::ConstIterator it;
+ for ( it = mFieldList.begin(); it != mFieldList.end(); ++it ) {
+ TQString value;
+ if ( (*it).mWidget->isA( "TQLineEdit" ) ) {
+ TQLineEdit *wdg = static_cast<TQLineEdit*>( (*it).mWidget );
+ wdg->setReadOnly(readOnly);
+ } else if ( (*it).mWidget->isA( "TQSpinBox" ) ) {
+ TQSpinBox *wdg = static_cast<TQSpinBox*>( (*it).mWidget );
+ wdg->setEnabled( !readOnly );
+ } else if ( (*it).mWidget->isA( "TQCheckBox" ) ) {
+ TQCheckBox *wdg = static_cast<TQCheckBox*>( (*it).mWidget );
+ wdg->setEnabled( !readOnly );
+ } else if ( (*it).mWidget->isA( "TQDateEdit" ) ) {
+ TQDateEdit *wdg = static_cast<TQDateEdit*>( (*it).mWidget );
+ wdg->setEnabled( !readOnly );
+ } else if ( (*it).mWidget->isA( "TQTimeEdit" ) ) {
+ TQTimeEdit *wdg = static_cast<TQTimeEdit*>( (*it).mWidget );
+ wdg->setEnabled( !readOnly );
+ } else if ( (*it).mWidget->isA( "TQDateTimeEdit" ) ) {
+ TQDateTimeEdit *wdg = static_cast<TQDateTimeEdit*>( (*it).mWidget );
+ wdg->setEnabled( !readOnly );
+ }
+ }
+}
+
void FieldWidget::storeContact( KABC::Addressee *addr )
{
FieldRecordList::ConstIterator it;
@@ -390,6 +417,7 @@ void CustomFieldsWidget::setReadOnly( bool readOnly )
{
mAddButton->setEnabled( !readOnly );
mRemoveButton->setEnabled( !readOnly && !mFieldWidget->fields().isEmpty() );
+ mFieldWidget->setReadOnly( readOnly );
}
void CustomFieldsWidget::addField()
diff --git a/kaddressbook/dcopaddressbook.desktop b/kaddressbook/dcopaddressbook.desktop
index 50ee3455d..feea50c0e 100644
--- a/kaddressbook/dcopaddressbook.desktop
+++ b/kaddressbook/dcopaddressbook.desktop
@@ -28,7 +28,6 @@ Comment[hu]=Címjegyzék DCOP-felülettel
Comment[is]=Vistfangaskrá með DCOP tengingu
Comment[it]=Rubrica indirizzi con un'interfaccia DCOP
Comment[ja]=DCOP インターフェースを持つアドレス帳
-Comment[ka]=წიგნაკი DCOP-ის ინტერფეისით
Comment[kk]=DCOP интерфейсті адрестік кітапшасы
Comment[km]=សៀវភៅ​អាសយដ្ឋាន​ដែល​មាន​ចំណុច​ប្រទាក់ DCOP
Comment[ko]=DCOP 인터페이스를 사용하는 주소록
@@ -54,7 +53,6 @@ Comment[ta]=முகவரிப்புத்தகத்துடன் DCOP
Comment[tg]=Китоби адрес бо интерфейси DCOP
Comment[tr]=DCOP Arayüzü Olan Adres Defteri
Comment[uk]=Адресна книга з інтерфейсом DCOP
-Comment[uz]=DCOP interfeysli manzillar daftari
-Comment[uz@cyrillic]=DCOP интерфейсли манзиллар дафтари
+Comment[uz]=DCOP интерфейсли манзиллар дафтари
Comment[zh_CN]=具有 DCOP 接口的地址簿
Comment[zh_TW]=有 DCOP 介面的通訊錄
diff --git a/kaddressbook/distributionlisteditor.cpp b/kaddressbook/distributionlisteditor.cpp
index 1b379b4a1..c088978f3 100644
--- a/kaddressbook/distributionlisteditor.cpp
+++ b/kaddressbook/distributionlisteditor.cpp
@@ -28,10 +28,11 @@
#include <libemailfunctions/email.h>
#include <kabc/addressbook.h>
+#include <kabc/resource.h>
#include <kapplication.h>
#include <kdialogbase.h>
-#include <kglobal.h>
+#include <kglobal.h>
#include <kiconloader.h>
#include <klineedit.h>
#include <klocale.h>
@@ -41,6 +42,7 @@
#include <tqlayout.h>
#include <tqsignalmapper.h>
#include <tqtoolbutton.h>
+#include <tqguardedptr.h>
class KPIM::DistributionListEditor::EditorWidgetPrivate
{
@@ -55,6 +57,7 @@ public:
TQWidget* memberListWidget;
TQVBoxLayout* addresseeLayout;
TQValueList<KPIM::DistributionListEditor::Line*> addressees;
+ TQGuardedPtr<KABC::Resource> resource;
KPIM::DistributionList distributionList;
KPIM::DistributionListEditor::Line* addLineForEntry( const KPIM::DistributionList::Entry& entry );
int lastLineId;
@@ -94,7 +97,7 @@ void KPIM::DistributionListEditor::Line::setEntry( const KPIM::DistributionList:
{
m_uid = entry.addressee.uid();
m_initialText = entry.addressee.fullEmail( entry.email );
- m_lineEdit->setText( m_initialText );
+ m_lineEdit->setText( m_initialText );
}
KABC::Addressee KPIM::DistributionListEditor::Line::findAddressee( const TQString& name, const TQString& email ) const
@@ -105,7 +108,7 @@ KABC::Addressee KPIM::DistributionListEditor::Line::findAddressee( const TQStrin
typedef KABC::Addressee::List List;
const List byEmail = m_addressBook->findByEmail( email );
if ( !byEmail.isEmpty() )
- {
+ {
const List::ConstIterator end = byEmail.end();
for ( List::ConstIterator it = byEmail.begin(); it != end; ++it )
{
@@ -138,7 +141,7 @@ KPIM::DistributionList::Entry KPIM::DistributionListEditor::Line::entry() const
res.addressee = addr;
}
if ( res.addressee.isEmpty() )
- res.addressee = findAddressee( name, email );
+ res.addressee = findAddressee( name, email );
res.email = res.addressee.preferredEmail() != email ? email : TQString();
return res;
}
@@ -146,18 +149,19 @@ KPIM::DistributionList::Entry KPIM::DistributionListEditor::Line::entry() const
KPIM::DistributionListEditor::LineEdit::LineEdit( TQWidget* parent ) : KPIM::AddresseeLineEdit( parent )
{
+ allowDistributionLists( false );
}
-KPIM::DistributionListEditor::EditorWidget::EditorWidget( KABC::AddressBook* book, TQWidget* parent )
+KPIM::DistributionListEditor::EditorWidget::EditorWidget( KABC::AddressBook* book, TQWidget* parent )
: KDialogBase( parent, /*name=*/0, /*modal=*/ true, /*caption=*/TQString(), KDialogBase::Ok|KDialogBase::Cancel ), d( new DistributionListEditor::EditorWidgetPrivate )
{
d->addressBook = book;
Q_ASSERT( d->addressBook );
d->lastLineId = 0;
d->mapper = new TQSignalMapper( this );
- connect( d->mapper, TQT_SIGNAL( mapped( int ) ),
- this, TQT_SLOT( lineTextChanged( int ) ) );
+ connect( d->mapper, TQT_SIGNAL( mapped( int ) ),
+ this, TQT_SLOT( lineTextChanged( int ) ) );
setCaption( i18n( "Edit Distribution List" ) );
TQWidget* main = new TQWidget( this );
TQVBoxLayout* mainLayout = new TQVBoxLayout( main );
@@ -192,12 +196,12 @@ KPIM::DistributionListEditor::EditorWidget::EditorWidget( KABC::AddressBook* boo
memberLayout->addStretch();
d->scrollView->addChild( d->memberListWidget );
d->scrollView->setResizePolicy( TQScrollView::AutoOneFit );
-
+
setMainWidget( main );
KPIM::DistributionListEditor::Line* const last = d->addLineForEntry( KPIM::DistributionList::Entry() );
const TQSize hint = sizeHint();
- resize( hint.width() * 1.5, hint.height() );
+ resize( hint.width() * 3L/2, hint.height() );
}
KPIM::DistributionListEditor::EditorWidget::~EditorWidget()
@@ -217,6 +221,7 @@ void KPIM::DistributionListEditor::EditorWidget::setDistributionList( const KPIM
{
d->distListUid = list.uid();
d->nameLineEdit->setText( list.name() );
+ d->resource = list.resource();
using KPIM::DistributionListEditor::Line;
typedef TQValueList<Line*>::ConstIterator ListIterator;
@@ -238,12 +243,12 @@ void KPIM::DistributionListEditor::EditorWidget::setDistributionList( const KPIM
}
KPIM::DistributionListEditor::Line* KPIM::DistributionListEditor::EditorWidgetPrivate::addLineForEntry( const KPIM::DistributionList::Entry& entry )
-{
+{
KPIM::DistributionListEditor::Line* line = new KPIM::DistributionListEditor::Line( addressBook, memberListWidget );
line->setEntry( entry );
addresseeLayout->addWidget( line );
addressees.append( line );
- TQObject::connect( line, TQT_SIGNAL( textChanged() ),
+ TQObject::connect( line, TQT_SIGNAL( textChanged() ),
mapper, TQT_SLOT( map() ) );
mapper->setMapping( line, ++lastLineId );
line->setShown( true );
@@ -256,23 +261,39 @@ void KPIM::DistributionListEditor::EditorWidget::slotOk()
const KPIM::DistributionList existing = KPIM::DistributionList::findByName( d->addressBook, name );
if ( !existing.isEmpty() && existing.uid() != d->distListUid )
{
- KMessageBox::error( this, i18n( "A distribution list with the name %1 already exists. Please choose another name." ).arg( name ), i18n( "Name in Use" ) );
+ KMessageBox::error( this, i18n( "A distribution list with the name %1 already exists. Please choose another name." ).arg( name ), i18n( "Name in Use" ) );
+ return;
+ }
+
+ KABC::Ticket *ticket = d->resource->requestSaveTicket();
+ if ( !ticket ) {
+ kdWarning(5720) << "Unable to get save ticket!" << endl;
return;
}
KPIM::DistributionList list;
list.setUid( d->distListUid.isNull() ? KApplication::randomString( 10 ) :d->distListUid );
list.setName( name );
+ list.setResource( d->resource );
typedef TQValueList<KPIM::DistributionListEditor::Line*>::ConstIterator ListIterator;
for ( ListIterator it = d->addressees.begin(), end = d->addressees.end(); it != end; ++it )
- {
+ {
const KPIM::DistributionList::Entry entry = (*it)->entry();
if ( entry.addressee.isEmpty() )
continue;
list.insertEntry( entry.addressee, entry.email );
}
d->distributionList = list;
- accept();
+
+ d->addressBook->insertAddressee( d->distributionList );
+ if ( !d->resource->save( ticket ) ) {
+ kdWarning(5720) << "Unable to save dist list!" << endl;
+ }
+ d->resource->releaseSaveTicket( ticket );
+
+ if ( !KPIM::DistributionList::findByName( d->addressBook, name ).isEmpty() ) {
+ accept();
+ }
}
KPIM::DistributionList KPIM::DistributionListEditor::EditorWidget::distributionList() const
diff --git a/kaddressbook/editors/cryptosettings.desktop b/kaddressbook/editors/cryptosettings.desktop
index 90ea108b7..4baaa54ae 100644
--- a/kaddressbook/editors/cryptosettings.desktop
+++ b/kaddressbook/editors/cryptosettings.desktop
@@ -24,7 +24,6 @@ Name[hu]=Titkosítási beállítások
Name[is]=Stillingar dulritunar
Name[it]=Preferenze crittografia
Name[ja]=暗号の設定
-Name[ka]=დაშიფრვის პარამეტრები
Name[kk]=Шифрлау параметрлері
Name[km]=ចំណង់​ចំណូល​ចិត្ត Crypto
Name[ko]=암호화 설정
diff --git a/kaddressbook/editors/imaddresseditor.desktop b/kaddressbook/editors/imaddresseditor.desktop
index 64dc74425..bb6b341c4 100644
--- a/kaddressbook/editors/imaddresseditor.desktop
+++ b/kaddressbook/editors/imaddresseditor.desktop
@@ -21,7 +21,6 @@ Name[hu]=Azonnali üzenetküldés (IM)
Name[is]=Skilaboðaforrit
Name[it]=Messaggistica istantanea
Name[ja]=インスタントメッセージ
-Name[ka]=მყისიერი შეტყობინებები
Name[kk]=Лезде хабарласу
Name[km]=ផ្ញើ​សារ​បន្ទាន់
Name[ko]=인스턴트 페시징
@@ -45,8 +44,7 @@ Name[ta]=உடனடி செய்தி பரிமாற்றம்
Name[tg]=Хизматгоҳи мубодилаи иттилоот
Name[tr]=Hızlı Mesajlaşma
Name[uk]=Миттєвий зв'язок
-Name[uz]=Xabar almashish
-Name[uz@cyrillic]=Хабар алмашиш
+Name[uz]=Хабар алмашиш
Name[zh_CN]=即时通讯
Name[zh_TW]=即時通訊
Comment=Instant Messaging Address Editor
@@ -72,7 +70,6 @@ Comment[hu]=IM-címszerkesztő
Comment[is]=Vistfangaritill fyrir skilaboðaforrit
Comment[it]=Editor degli indirizzi per messaggi istantanei
Comment[ja]=インスタントメッセージのアドレスを編集
-Comment[ka]=მყისიერი შეტყობინებების წიგნაკის რედაქტორი
Comment[kk]=Лезде хабарласу адрестер өңдегіші
Comment[km]=កម្មវិធី​និពន្ធ​អាសយដ្ឋាន​ដើម្បី​ផ្ញើ​សារ​បន្ទាន់
Comment[ko]=인스턴트 메시징 주소 편집기
diff --git a/kaddressbook/editors/imeditorwidget.cpp b/kaddressbook/editors/imeditorwidget.cpp
index 0da0feb03..ad84505c2 100644
--- a/kaddressbook/editors/imeditorwidget.cpp
+++ b/kaddressbook/editors/imeditorwidget.cpp
@@ -362,6 +362,8 @@ void IMEditorWidget::slotAdd()
void IMEditorWidget::slotEdit()
{
+ if( mReadOnly )
+ return;
TQListViewItemIterator it( mWidget->lvAddresses, TQListViewItemIterator::Selected );
// Just edit the first one selected.
diff --git a/kaddressbook/editors/kaddressbookimprotocol.desktop b/kaddressbook/editors/kaddressbookimprotocol.desktop
index 80a6f89aa..ad4eda6c4 100644
--- a/kaddressbook/editors/kaddressbookimprotocol.desktop
+++ b/kaddressbook/editors/kaddressbookimprotocol.desktop
@@ -25,7 +25,6 @@ Name[hu]=KAddressbook azonnali üzenetküldési protokoll
Name[is]=KAddressbook skilaboðaforritið
Name[it]=KAddressbook protocollo messaggistica istantanea
Name[ja]=KAddressbook インスタントメッセージプロトコル
-Name[ka]=KDE ოქმი მყისიერი შეტყობინებებისათვისწიგნაკითვის
Name[kk]=KAddressbook лезде хабарласу протоколы
Name[km]=ពិធីការ​ផ្ញើសារ​បន្ទាន់​របស់ KAddressbook
Name[ko]=KAddressbook 인스턴트 메시징 프로토콜
diff --git a/kaddressbook/editors/protocols/aimprotocol.desktop b/kaddressbook/editors/protocols/aimprotocol.desktop
index e17be1f67..a29098d8d 100644
--- a/kaddressbook/editors/protocols/aimprotocol.desktop
+++ b/kaddressbook/editors/protocols/aimprotocol.desktop
@@ -29,7 +29,6 @@ Comment[hu]=AIM protokoll
Comment[is]=AIM samskiptamátinn
Comment[it]=Protocollo AIM
Comment[ja]=AIM プロトコル
-Comment[ka]=AIM ოქმი
Comment[kk]=AIM протоколы
Comment[km]=ពិធីការ AIM
Comment[ko]=AIM 프로토콜
diff --git a/kaddressbook/editors/protocols/gaduprotocol.desktop b/kaddressbook/editors/protocols/gaduprotocol.desktop
index 96ee6e9ee..9ccea3c52 100644
--- a/kaddressbook/editors/protocols/gaduprotocol.desktop
+++ b/kaddressbook/editors/protocols/gaduprotocol.desktop
@@ -30,7 +30,6 @@ Comment[hu]=Gadu-Gadu protokoll
Comment[is]=Gadu-Gadu samskiptamátinn
Comment[it]=Protocollo Gadu-Gadu
Comment[ja]=Gadu-Gadu プロトコル
-Comment[ka]=Gadu-Gadu ოქმი
Comment[kk]=Gadu-Gadu протоколы
Comment[km]=ពិធីការ Gadu-Gadu
Comment[lt]=Gadu-Gadu protokolas
diff --git a/kaddressbook/editors/protocols/groupwiseprotocol.desktop b/kaddressbook/editors/protocols/groupwiseprotocol.desktop
index 0ee40fd2e..0fc2cce0f 100644
--- a/kaddressbook/editors/protocols/groupwiseprotocol.desktop
+++ b/kaddressbook/editors/protocols/groupwiseprotocol.desktop
@@ -18,7 +18,6 @@ Comment[fy]=Novell GroupWise-messenger
Comment[he]=מסנג'ר של Novell GroupWise
Comment[is]=Novell GroupWise Samskiptatólið
Comment[ja]=Novell GroupWise メッセンジャー
-Comment[ka]= Novell GroupWise მყისიერი შეტყობინებების მაცნე
Comment[kk]=Novell GroupWise хабарласу
Comment[km]=កម្មវិធី​ផ្ញើ​សារ​របស់​ណូវែល - GroupWise
Comment[lt]=Novell GroupWise momentinių žinučių klientas
diff --git a/kaddressbook/editors/protocols/icqprotocol.desktop b/kaddressbook/editors/protocols/icqprotocol.desktop
index e071238ed..be9fff528 100644
--- a/kaddressbook/editors/protocols/icqprotocol.desktop
+++ b/kaddressbook/editors/protocols/icqprotocol.desktop
@@ -29,7 +29,6 @@ Comment[hu]=ICQ protokoll
Comment[is]=ICQ samskiptamátinn
Comment[it]=Protocollo ICQ
Comment[ja]=ICQ プロトコル
-Comment[ka]=ICQ ოქმი
Comment[kk]=ICQ протоколы
Comment[km]=ពិធីការ ICQ
Comment[lt]=ICQ protokolas
diff --git a/kaddressbook/editors/protocols/ircprotocol.desktop b/kaddressbook/editors/protocols/ircprotocol.desktop
index 78f19447b..40f73a367 100644
--- a/kaddressbook/editors/protocols/ircprotocol.desktop
+++ b/kaddressbook/editors/protocols/ircprotocol.desktop
@@ -9,7 +9,6 @@ Comment[fa]=گپ بازپخش اینترنت
Comment[hu]=IRC (Internet Relay Chat)
Comment[is]=Internet spjall
Comment[ja]=インターネットリレーチャット
-Comment[ka]=IRC
Comment[kk]=Internet Relay Chat хабарласу
Comment[km]=ជជែក​កំសាន្ត​តាមអ៊ីនធឺណិត
Comment[lt]=Estafetinis Interneto pokalbis
diff --git a/kaddressbook/editors/protocols/jabberprotocol.desktop b/kaddressbook/editors/protocols/jabberprotocol.desktop
index 94b7271b7..b34f88093 100644
--- a/kaddressbook/editors/protocols/jabberprotocol.desktop
+++ b/kaddressbook/editors/protocols/jabberprotocol.desktop
@@ -30,7 +30,6 @@ Comment[hu]=Jabber protokoll
Comment[is]=Jabber samskiptamátinn
Comment[it]=Protocollo Jabber
Comment[ja]=Jabber プロトコル
-Comment[ka]=Jabber ოქმი
Comment[kk]=Jabber протоколы
Comment[km]=ពិធីការ Jabber
Comment[lt]=Jabber protokolas
diff --git a/kaddressbook/editors/protocols/meanwhileprotocol.desktop b/kaddressbook/editors/protocols/meanwhileprotocol.desktop
index 7442cd04d..23e9fe3d8 100644
--- a/kaddressbook/editors/protocols/meanwhileprotocol.desktop
+++ b/kaddressbook/editors/protocols/meanwhileprotocol.desktop
@@ -29,7 +29,6 @@ Comment[hu]=Meanwhile protokoll
Comment[is]=Meanwhile samskiptamátinn
Comment[it]=Protocollo Meanwhile
Comment[ja]=Meanwhile プロトコル
-Comment[ka]=Meanwhile ოქმი
Comment[kk]=Meanwhile протоколы
Comment[km]=ពិធីការ Meanwhile
Comment[lt]=Meanwhile protokolas
diff --git a/kaddressbook/editors/protocols/msnprotocol.desktop b/kaddressbook/editors/protocols/msnprotocol.desktop
index 58504fd71..1256278a5 100644
--- a/kaddressbook/editors/protocols/msnprotocol.desktop
+++ b/kaddressbook/editors/protocols/msnprotocol.desktop
@@ -12,7 +12,6 @@ Comment[fa]=پیام‌رسان MSN
Comment[fr]=Messagerie MSN
Comment[is]=MSN spjallforritið
Comment[ja]=MSN メッセンジャー
-Comment[ka]=MSN შიკრიკი
Comment[km]=កម្មវិធី​ផ្ញើ​សារ MSN
Comment[nds]=MSN-Kortnarichtenmaker
Comment[ne]=एमएसएन म्यासेन्जर
@@ -25,7 +24,6 @@ Name[cy]=Negesydd MSN
Name[eo]=MSN Mesaĝilo
Name[fa]=پیام‌رسان MSN
Name[ja]=MSN メッセンジャー
-Name[ka]=MSN შიკრიკი
Name[km]=កម្មវិធី​ផ្ញើសារ MSN
Name[nds]=MSN-Kortnarichtenmaker
Name[ne]=एमएसएन म्यासेन्जर
diff --git a/kaddressbook/editors/protocols/skypeprotocol.desktop b/kaddressbook/editors/protocols/skypeprotocol.desktop
index 60ac34060..a5c67fc47 100644
--- a/kaddressbook/editors/protocols/skypeprotocol.desktop
+++ b/kaddressbook/editors/protocols/skypeprotocol.desktop
@@ -24,7 +24,6 @@ Comment[hu]=Skype internetes telefon
Comment[is]=Skype Internet sími
Comment[it]=Telefonia internet Skype
Comment[ja]=Skype インターネット電話
-Comment[ka]=Skype ინტერნეტ ტელეფონი
Comment[kk]=Skype Интернет телефониясы
Comment[km]=ទូរស័ព្ទ​តាម​អ៊ីនធឺណិត​ដោយ​ប្រើ Skype
Comment[lt]=Skype Interneto telefonija
diff --git a/kaddressbook/editors/protocols/smsprotocol.desktop b/kaddressbook/editors/protocols/smsprotocol.desktop
index 30b50a1ea..38710e837 100644
--- a/kaddressbook/editors/protocols/smsprotocol.desktop
+++ b/kaddressbook/editors/protocols/smsprotocol.desktop
@@ -29,7 +29,6 @@ Comment[hu]=SMS protokoll
Comment[is]=SMS samskiptamátinn
Comment[it]=Protocollo SMS
Comment[ja]=SMS プロトコル
-Comment[ka]= SMS ოქმი
Comment[kk]=SMS протоколы
Comment[km]=ពិធីការ​សេវា​សារ​ខ្លីៗ
Comment[lt]=SMS protokolas
diff --git a/kaddressbook/editors/protocols/yahooprotocol.desktop b/kaddressbook/editors/protocols/yahooprotocol.desktop
index c3055472e..8064f772f 100644
--- a/kaddressbook/editors/protocols/yahooprotocol.desktop
+++ b/kaddressbook/editors/protocols/yahooprotocol.desktop
@@ -30,7 +30,6 @@ Comment[hu]=Yahoo protokoll
Comment[is]=Yahoo samskiptamátinn
Comment[it]=Protocollo Yahoo
Comment[ja]=Yahoo プロトコル
-Comment[ka]=Yahoo ოქმი
Comment[kk]=Yahoo протоколы
Comment[km]=ពិធីការ​យ៉ាហ៊ូ
Comment[lt]=Yahoo protokolas
diff --git a/kaddressbook/features/distributionlist.desktop b/kaddressbook/features/distributionlist.desktop
index b05d7b5e8..844a48961 100644
--- a/kaddressbook/features/distributionlist.desktop
+++ b/kaddressbook/features/distributionlist.desktop
@@ -27,7 +27,6 @@ Name[hu]=KAB címlista bővítőmodul
Name[is]=Íforrit fyrir KAB dreifilista
Name[it]=Plugin lista di distribuzione KAB
Name[ja]=KAB 配布リストプラグイン
-Name[ka]=KAB დისტრიბუციის სიის მოდული
Name[kk]=KAB тарату тізімінің плагин модулі
Name[km]=កម្មវិធី​ជំនួយ​បញ្ជី​ចែកចាយ​របស់ KAB
Name[lt]=KAB platinimo sąrašo priedas
@@ -51,8 +50,7 @@ Name[ta]=KABயின் பகிர்ந்தளித்தல் பட்
Name[tg]=Рӯйхати ба ҳар тараф мефиристодагӣ
Name[tr]=KAB Dağıtım Listesi Eklentisi
Name[uk]=Втулок списку розповсюдження KAB
-Name[uz]=Tarqatish roʻyxat plagini
-Name[uz@cyrillic]=Тарқатиш рўйхат плагини
+Name[uz]=Тарқатиш рўйхат плагини
Name[zh_CN]=KAB 分发列表插件
Comment=Plugin for managing distribution lists
Comment[af]=Inprop module vir die bestuur van verspreiding lyste
@@ -82,7 +80,6 @@ Comment[hu]=Bővítőmodul címlisták kezeléséhez
Comment[is]=Íforrit til að sjá um dreifilista
Comment[it]=Plugin per gestire liste di distribuzione
Comment[ja]=配布リスト管理用プラグイン
-Comment[ka]=სადისტრიბუციო სიათა მართვის მოდული
Comment[kk]=Тарату тізімімен айналысу плагин модулі
Comment[km]=កម្មវិធី​ជំនួយ​ដើម្បី​គ្រប់គ្រង​បញ្ជី​ចែកចាយ
Comment[lt]=Priedas platinimo sąrašų tvarkymui
@@ -107,8 +104,7 @@ Comment[ta]=பகிர்தல் பட்டியல் நிர்வக
Comment[tg]=Кор бо рӯйхати ба ҳар тараф мефиристодагӣ
Comment[tr]=Dağıtım listelerini yönetmek için eklenti
Comment[uk]=Втулок для керування списками розповсюдження
-Comment[uz]=Tarqatish roʻyxatlarni boshqarish uchu plagin
-Comment[uz@cyrillic]=Тарқатиш рўйхатларни бошқариш учу плагин
+Comment[uz]=Тарқатиш рўйхатларни бошқариш учу плагин
Comment[zh_CN]=管理分发列表的插件
Comment[zh_TW]=管理分配清單外掛程式
Type=Service
diff --git a/kaddressbook/features/distributionlistng.desktop b/kaddressbook/features/distributionlistng.desktop
index 84d7070bb..e805a91a7 100644
--- a/kaddressbook/features/distributionlistng.desktop
+++ b/kaddressbook/features/distributionlistng.desktop
@@ -6,22 +6,16 @@ Name[ca]=Endollable de la propera generació de la llista de distribució KAB
Name[da]=Næste generations-plugin til KAB-Distribution-liste
Name[de]=Verteilerlisten-Modul für neues Adressbuch
Name[el]=Πρόσθετο επόμενης γενιάς λίστας διανομής του KAB
-Name[es]=Complemento de nueva generación KAB para listas de distribución
Name[et]=KAB postiloendi järgmise põlvkonna plugin
-Name[fr]=Module de liste de diffusion nouvelle génération pour KAB
-Name[is]=Næstu kynslóðar íforrit fyrir KAB dreifilista
Name[it]=Plugin lista di distribuzione KAB di nuova generazione
Name[ja]=KAB 配布リスト次世代プラグイン
-Name[km]=កម្មវិធី​ជំនួយ​ជំនាន់​ក្រោយ​របស់​​បញ្ជី​ចែកចាយ​ KAB
Name[nds]=Verbetert Verdeellist-Moduul för KAdressbook
Name[nl]=Plugin voor KAB Distributielijst (Nieuwe Generatie)
Name[pl]=Wtyczka KAB do obsługi list wysyłkowych
-Name[ru]=Списки рассылки (новая версия)
Name[sk]=KAB plugin distribučného zoznamu ďaľšej generácie
Name[sr]=Прикључак KAB-а наредне генерације за дистрибуционе листе
Name[sr@Latn]=Priključak KAB-a naredne generacije za distribucione liste
Name[sv]=Adressbokens nästa generation insticksprogram för distributionslistor
-Name[tr]=KAB Dağıtım Listesi Sonraki Kuşak Eklentisi
Name[zh_CN]=KAB 分发列表生成插件
Name[zh_TW]=KAB 分派清單下一代外掛程式
Comment=Plugin for managing distribution lists
@@ -52,7 +46,6 @@ Comment[hu]=Bővítőmodul címlisták kezeléséhez
Comment[is]=Íforrit til að sjá um dreifilista
Comment[it]=Plugin per gestire liste di distribuzione
Comment[ja]=配布リスト管理用プラグイン
-Comment[ka]=სადისტრიბუციო სიათა მართვის მოდული
Comment[kk]=Тарату тізімімен айналысу плагин модулі
Comment[km]=កម្មវិធី​ជំនួយ​ដើម្បី​គ្រប់គ្រង​បញ្ជី​ចែកចាយ
Comment[lt]=Priedas platinimo sąrašų tvarkymui
@@ -77,8 +70,7 @@ Comment[ta]=பகிர்தல் பட்டியல் நிர்வக
Comment[tg]=Кор бо рӯйхати ба ҳар тараф мефиристодагӣ
Comment[tr]=Dağıtım listelerini yönetmek için eklenti
Comment[uk]=Втулок для керування списками розповсюдження
-Comment[uz]=Tarqatish roʻyxatlarni boshqarish uchu plagin
-Comment[uz@cyrillic]=Тарқатиш рўйхатларни бошқариш учу плагин
+Comment[uz]=Тарқатиш рўйхатларни бошқариш учу плагин
Comment[zh_CN]=管理分发列表的插件
Comment[zh_TW]=管理分配清單外掛程式
Type=Service
diff --git a/kaddressbook/features/distributionlistngwidget.cpp b/kaddressbook/features/distributionlistngwidget.cpp
index 08ef3e4cd..4ca4e365e 100644
--- a/kaddressbook/features/distributionlistngwidget.cpp
+++ b/kaddressbook/features/distributionlistngwidget.cpp
@@ -71,12 +71,11 @@ void KAB::DistributionListNg::ListBox::dropEvent( TQDropEvent *event )
if ( !item || index( item ) == 0 )
return;
- TQString vcards;
- if ( !KVCardDrag::decode( event, vcards ) )
+ KABC::Addressee::List list;
+ if ( !KVCardDrag::decode( event, list ) )
return;
- KABC::VCardConverter converter;
- emit dropped( item->text(), converter.parseVCards( vcards ) );
+ emit dropped( item->text(), list );
}
namespace KAB {
@@ -154,6 +153,7 @@ KAB::DistributionListNg::MainWidget::MainWidget( KAB::Core *core, TQWidget *pare
this, TQT_SLOT( contactsDropped( const TQString &, const KABC::Addressee::List & ) ) );
connect( mListBox, TQT_SIGNAL( highlighted( int ) ),
this, TQT_SLOT( itemSelected( int ) ) );
+ connect( mListBox, TQT_SIGNAL(doubleClicked(TQListBoxItem*)), TQT_SLOT(editSelectedDistributionList()) );
layout->addWidget( mListBox );
connect( core, TQT_SIGNAL( contactsUpdated() ),
@@ -172,7 +172,7 @@ void KAB::DistributionListNg::MainWidget::contextMenuRequested( TQListBoxItem *i
{
TQGuardedPtr<KPopupMenu> menu = new KPopupMenu( this );
menu->insertItem( i18n( "New Distribution List..." ), core(), TQT_SLOT( newDistributionList() ) );
- if ( item )
+ if ( item && ( item->text() !=i18n( "All Contacts" ) ) )
{
menu->insertItem( i18n( "Edit..." ), this, TQT_SLOT( editSelectedDistributionList() ) );
menu->insertItem( i18n( "Delete" ), this, TQT_SLOT( deleteSelectedDistributionList() ) );
diff --git a/kaddressbook/features/resourceselection.cpp b/kaddressbook/features/resourceselection.cpp
index d6edba25e..59a3c1ee6 100644
--- a/kaddressbook/features/resourceselection.cpp
+++ b/kaddressbook/features/resourceselection.cpp
@@ -251,7 +251,6 @@ void ResourceSelection::add()
return;
}
- resource->setResourceName( i18n( "%1 address book" ).arg( type ) );
resource->setAddressBook(core()->addressBook());
KRES::ConfigDialog dlg( this, TQString( "contact" ), resource );
@@ -262,6 +261,7 @@ void ResourceSelection::add()
mLastResource = resource->identifier();
updateView();
+ currentChanged(mListView->currentItem() );
} else {
delete resource;
resource = 0;
@@ -309,6 +309,7 @@ void ResourceSelection::remove()
core()->addressBook()->emitAddressBookChanged();
updateView();
+ currentChanged(mListView->currentItem() );
}
void ResourceSelection::currentChanged( TQListViewItem *item )
diff --git a/kaddressbook/features/resourceselection.desktop b/kaddressbook/features/resourceselection.desktop
index 4879e939f..b1f336988 100644
--- a/kaddressbook/features/resourceselection.desktop
+++ b/kaddressbook/features/resourceselection.desktop
@@ -26,7 +26,6 @@ Name[hu]=Címjegyzékkezelő bővítőmodul
Name[is]=Umsjónaríforrit vistfangaflettis
Name[it]=Plugin per gestire rubriche indirizzi
Name[ja]=アドレス帳管理プラグイン
-Name[ka]=წიგნაკის მართვის მოდული
Name[kk]=Адрестік кітапшамен айналысу плагин модулі
Name[km]=កម្មវិធី​ជំនួយ​ការ​គ្រប់គ្រង​សៀវភៅ​អាសយដ្ឋាន
Name[lt]=Adresų knygelės tvarkymo priedas
@@ -78,7 +77,6 @@ Comment[hu]=Bővítőmodul címjegyzékek kezeléséhez
Comment[is]=Íforrit til að sjá um vistfangaskrár
Comment[it]=Plugin per gestire rubriche indirizzi
Comment[ja]=アドレス帳管理用プラグイン
-Comment[ka]=წიგნაკის მართვის მოდული
Comment[kk]=Адрестік кітапшамен айналысу плагин модулі
Comment[km]=កម្មវិធី​ជំនួយ​ដើម្បី​គ្រប់គ្រង​សៀវភៅ​អាសយដ្ឋាន
Comment[lt]=Priedas adresų knygelių tvarkymui
diff --git a/kaddressbook/freebusywidget.cpp b/kaddressbook/freebusywidget.cpp
index 9bda32491..096c1d583 100644
--- a/kaddressbook/freebusywidget.cpp
+++ b/kaddressbook/freebusywidget.cpp
@@ -68,6 +68,11 @@ void FreeBusyWidget::storeContact( KABC::Addressee *addr )
KCal::FreeBusyUrlStore::self()->writeUrl( addr->preferredEmail(), mURL->url() );
KCal::FreeBusyUrlStore::self()->sync();
+ if ( mURL->url().isEmpty() ) {
+ addr->removeCustom( "KADDRESSBOOK", "FreeBusyURL" );
+ } else {
+ addr->insertCustom( "KADDRESSBOOK", "FreeBusyURL", mURL->url() );
+ }
}
void FreeBusyWidget::setReadOnly( bool readOnly )
diff --git a/kaddressbook/imagewidget.cpp b/kaddressbook/imagewidget.cpp
index ddacc2cd1..7d8ac8f51 100644
--- a/kaddressbook/imagewidget.cpp
+++ b/kaddressbook/imagewidget.cpp
@@ -222,6 +222,8 @@ void ImageButton::contextMenuEvent( TQContextMenuEvent *event )
void ImageButton::load()
{
+ if ( mReadOnly )
+ return;
KURL url = KFileDialog::getOpenURL( TQString(), KImageIO::pattern(), this );
if ( url.isValid() ) {
if ( mImageLoader ) {
diff --git a/kaddressbook/interfaces/kaddressbook_contacteditorwidget.desktop b/kaddressbook/interfaces/kaddressbook_contacteditorwidget.desktop
index bb646e78c..e8159d594 100644
--- a/kaddressbook/interfaces/kaddressbook_contacteditorwidget.desktop
+++ b/kaddressbook/interfaces/kaddressbook_contacteditorwidget.desktop
@@ -24,7 +24,6 @@ Comment[hu]=KAddressBook névjegyszerkesztő bővítőmodul
Comment[is]=KAddressbook tengiliðaritils íforrit
Comment[it]=Plugin editor dei contatti di KAddressbook
Comment[ja]=KAddressbook 連絡先エディタ ウィジェット プラグイン
-Comment[ka]= KDE-ს წიგნაკის კონტაქტთა რედაქტირების ელემენტის მოდული
Comment[kk]=Адрестік кітапшаның контактты өңдеу модулі
Comment[km]=កម្មវិធី​ជំនួយ​ធាតុ​ក្រាហ្វិក​កម្មវិធី​និពន្ធ​ទំនាក់ទំនង​របស់ KAddressBook
Comment[lt]=KAddressBook kontaktų redaktoriaus valdiklių priedas
diff --git a/kaddressbook/interfaces/kaddressbook_extension.desktop b/kaddressbook/interfaces/kaddressbook_extension.desktop
index 55be3b71e..0bf353967 100644
--- a/kaddressbook/interfaces/kaddressbook_extension.desktop
+++ b/kaddressbook/interfaces/kaddressbook_extension.desktop
@@ -27,7 +27,6 @@ Comment[hu]=KAddressBook kiegészítő modul
Comment[is]=KAddressbook viðbótar íforrit
Comment[it]=Plugin estensione di KAddressbook
Comment[ja]=KAddressbook 拡張プラグイン
-Comment[ka]=KDE წიგნაკის გაფართოების მოდული
Comment[kk]=KAddressBook кеңейту модулі
Comment[km]=កម្មវិធី​ជំនួយ​ផ្នែក​បន្ថែម​របស់ KAddressBook
Comment[lt]=KAddressBook praplėtimo priedas
diff --git a/kaddressbook/interfaces/kaddressbook_xxport.desktop b/kaddressbook/interfaces/kaddressbook_xxport.desktop
index fb2b03d0d..3d9e5503e 100644
--- a/kaddressbook/interfaces/kaddressbook_xxport.desktop
+++ b/kaddressbook/interfaces/kaddressbook_xxport.desktop
@@ -28,7 +28,6 @@ Comment[hu]=KAddressBook importálási/exportálási bővítőmodul
Comment[is]=KAddressbook flytja inn/út íforrit
Comment[it]=Plugin importa/esporta di KAddressbook
Comment[ja]=KAddressbook インポート/エクスポートプラグイン
-Comment[ka]=წიგნაკის იმპორტ/ექსპორტის მოდული
Comment[kk]=KAddressBook импорт/экспорт модулі
Comment[km]=កម្មវិធី​ជំនួយ​នាំចូល/នាំចេញ​របស់ KAddressBook
Comment[lt]=KAddressBook importo/eksporto priedas
@@ -52,8 +51,7 @@ Comment[ta]=கேமுகவரிப்புத்தகம் ஏற்ற
Comment[tg]=Содирот ва воридоти китоби адрес
Comment[tr]=KAdresDefteri Al/Gönder Eklentisi
Comment[uk]=Втулок імпорту/експорту адресної книги KAddressBook
-Comment[uz]=Manzillar daftari uchun import/eksport plagini
-Comment[uz@cyrillic]=Манзиллар дафтари учун импорт/экспорт плагини
+Comment[uz]=Манзиллар дафтари учун импорт/экспорт плагини
Comment[zh_CN]=KAddressBook 导入/导出插件
Comment[zh_TW]=KAddressBook 匯入/匯出外掛程式
diff --git a/kaddressbook/kabcore.cpp b/kaddressbook/kabcore.cpp
index 427cb79ab..7951cded0 100644
--- a/kaddressbook/kabcore.cpp
+++ b/kaddressbook/kabcore.cpp
@@ -34,6 +34,8 @@
#include <tqwidgetstack.h>
#include <tqregexp.h>
#include <tqvbox.h>
+#include <tqtooltip.h>
+#include <tqwhatsthis.h>
#include <kabc/addresseelist.h>
#include <kabc/errorhandler.h>
@@ -277,7 +279,23 @@ KABC::Resource *KABCore::requestResource( TQWidget *parent )
KABC::Resource *resource;
while ( ( resource = resIt.current() ) != 0 ) {
++resIt;
- if ( !resource->readOnly() ) {
+ bool writable = false;
+ if ( resource->inherits( "KPIM::ResourceABC" ) ) {
+ KPIM::ResourceABC *resAbc = static_cast<KPIM::ResourceABC *>( resource );
+ const TQStringList subresources = resAbc->subresources();
+ for ( TQStringList::ConstIterator it = subresources.begin(); it != subresources.end(); ++it ) {
+ if ( resAbc->subresourceActive(*it) && resAbc->subresourceWritable(*it) ) {
+ writable = true;
+ break;
+ }
+ }
+ } else {
+ if ( !resource->readOnly() ) {
+ writable = true;
+ }
+ }
+
+ if ( writable ) {
KRES::Resource *res = resource; // downcast
kresResources.append( res );
}
@@ -401,7 +419,7 @@ void KABCore::setContactSelected( const TQString &uid )
mActionDelete->setEnabled( someSelected && writable );
// the "edit" dialog doubles as the details dialog and it knows when the addressee is read-only
// (### this does not make much sense from the user perspective!)
- mActionEditAddressee->setEnabled( singleSelected );
+ mActionEditAddressee->setEnabled( singleSelected && !mExtensionManager->isQuickEditVisible());
mActionCopyAddresseeTo->setEnabled( someSelected && moreThanOneResource );
mActionMoveAddresseeTo->setEnabled( someSelected && moreThanOneResource && writable );
mActionMail->setEnabled( someSelected );
@@ -413,9 +431,18 @@ void KABCore::setContactSelected( const TQString &uid )
if ( mReadWrite ) {
QClipboard *cb = TQApplication::clipboard();
+#if defined(KABC_VCARD_ENCODING_FIX)
+ const TQMimeSource *data = cb->data( QClipboard::Clipboard );
+ list = AddresseeUtil::clipboardToAddressees( data->encodedData( "text/x-vcard" ) );
+#else
list = AddresseeUtil::clipboardToAddressees( cb->text() );
+#endif
mActionPaste->setEnabled( !list.isEmpty() );
}
+#ifdef KDEPIM_NEW_DISTRLISTS
+ mAddDistListButton->setEnabled( writable );
+ mRemoveDistListButton->setEnabled( someSelected && writable );
+#endif
}
void KABCore::sendMail()
@@ -495,10 +522,20 @@ void KABCore::deleteContacts( const TQStringList &uids )
++it;
}
- if ( KMessageBox::warningContinueCancelList( mWidget, i18n( "Do you really want to delete this contact?",
- "Do you really want to delete these %n contacts?", uids.count() ),
- names, TQString::null, KStdGuiItem::del() ) == KMessageBox::Cancel )
+ if ( KMessageBox::warningContinueCancelList(
+ mWidget,
+ i18n( "<qt>"
+ "Do you really want to delete this contact from your addressbook?<br>"
+ "<b>Note:</b>The contact will be also removed from all distribution lists."
+ "</qt>",
+ "<qt>"
+ "Do you really want to delete these %n contacts from your addressbook?<br>"
+ "<b>Note:</b>The contacts will be also removed from all distribution lists."
+ "</qt>",
+ uids.count() ),
+ names, TQString::null, KStdGuiItem::del() ) == KMessageBox::Cancel ) {
return;
+ }
DeleteCommand *command = new DeleteCommand( mAddressBook, uids );
mCommandHistory->addCommand( command );
@@ -513,12 +550,15 @@ void KABCore::copyContacts()
{
KABC::Addressee::List addrList = mViewManager->selectedAddressees();
+#if defined(KABC_VCARD_ENCODING_FIX)
+ TQByteArray clipText = AddresseeUtil::addresseesToClipboard( addrList );
+ QClipboard *cb = TQApplication::clipboard();
+ cb->setText( TQString::fromUtf8( clipText.data() ) );
+#else
TQString clipText = AddresseeUtil::addresseesToClipboard( addrList );
-
- kdDebug(5720) << "KABCore::copyContacts: " << clipText << endl;
-
QClipboard *cb = TQApplication::clipboard();
cb->setText( clipText );
+#endif
}
void KABCore::cutContacts()
@@ -536,9 +576,12 @@ void KABCore::cutContacts()
void KABCore::pasteContacts()
{
QClipboard *cb = TQApplication::clipboard();
-
+#if defined(KABC_VCARD_ENCODING_FIX)
+ const TQMimeSource *data = cb->data( QClipboard::Clipboard );
+ KABC::Addressee::List list = AddresseeUtil::clipboardToAddressees( data->encodedData( "text/x-vcard" ) );
+#else
KABC::Addressee::List list = AddresseeUtil::clipboardToAddressees( cb->text() );
-
+#endif
pasteContacts( list );
}
@@ -667,6 +710,10 @@ void KABCore::contactModified( const KABC::Addressee &addr )
void KABCore::newDistributionList()
{
#ifdef KDEPIM_NEW_DISTRLISTS
+ KABC::Resource *resource = requestResource( mWidget );
+ if ( !resource )
+ return;
+
TQString name = i18n( "New Distribution List" );
const KPIM::DistributionList distList = KPIM::DistributionList::findByName( addressBook(), name );
if ( !distList.isEmpty() ) {
@@ -680,6 +727,7 @@ void KABCore::newDistributionList()
KPIM::DistributionList list;
list.setUid( KApplication::randomString( 10 ) );
list.setName( name );
+ list.setResource( resource );
editDistributionList( list );
#endif
}
@@ -827,27 +875,14 @@ void KABCore::storeContactIn( const TQString &uid, bool copy /*false*/ )
if ( !resource )
return;
- KABLock::self( mAddressBook )->lock( resource );
- TQStringList::Iterator it( uidList.begin() );
- const TQStringList::Iterator endIt( uidList.end() );
- while ( it != endIt ) {
- KABC::Addressee addr = mAddressBook->findByUid( *it++ );
- if ( !addr.isEmpty() ) {
- KABC::Addressee newAddr( addr );
- // We need to set a new uid, otherwise the insert below is
- // ignored. This is bad for syncing, but unavoidable, afaiks
- newAddr.setUid( KApplication::randomString( 10 ) );
- newAddr.setResource( resource );
- addressBook()->insertAddressee( newAddr );
- const bool inserted = addressBook()->find( newAddr ) != addressBook()->end();
- if ( !copy && inserted ) {
- KABLock::self( mAddressBook )->lock( addr.resource() );
- addressBook()->removeAddressee( addr );
- KABLock::self( mAddressBook )->unlock( addr.resource() );
- }
- }
+ if ( copy ) {
+ CopyToCommand *command = new CopyToCommand( mAddressBook, uidList, resource );
+ mCommandHistory->addCommand( command );
+ }
+ else {
+ MoveToCommand *command = new MoveToCommand( this, uidList, resource );
+ mCommandHistory->addCommand( command );
}
- KABLock::self( mAddressBook )->unlock( resource );
addressBookChanged();
setModified( true );
@@ -1201,19 +1236,30 @@ void KABCore::initGUI()
buttonLayout->setSpacing( KDialog::spacingHint() );
buttonLayout->addStretch( 1 );
- KPushButton *addDistListButton = new KPushButton( mDistListButtonWidget );
- addDistListButton->setText( i18n( "Add" ) );
- connect( addDistListButton, TQT_SIGNAL( clicked() ),
+ mAddDistListButton = new KPushButton( mDistListButtonWidget );
+ mAddDistListButton->setEnabled( false );
+ mAddDistListButton->setText( i18n( "Add" ) );
+ TQToolTip::add( mAddDistListButton, i18n( "Add contacts to the distribution list" ) );
+ TQWhatsThis::add( mAddDistListButton,
+ i18n( "Click this button if you want to add more contacts to "
+ "the current distribution list. You will be shown a dialog that allows "
+ "to enter a list of existing contacts to this distribution list." ) );
+ connect( mAddDistListButton, TQT_SIGNAL( clicked() ),
this, TQT_SLOT( editSelectedDistributionList() ) );
- buttonLayout->addWidget( addDistListButton );
+ buttonLayout->addWidget( mAddDistListButton );
mDistListButtonWidget->setShown( false );
viewLayout->addWidget( mDistListButtonWidget );
- KPushButton *removeDistListButton = new KPushButton( mDistListButtonWidget );
- removeDistListButton->setText( i18n( "Remove" ) );
- connect( removeDistListButton, TQT_SIGNAL( clicked() ),
+ mRemoveDistListButton = new KPushButton( mDistListButtonWidget );
+ mRemoveDistListButton->setEnabled( false );
+ mRemoveDistListButton->setText( i18n( "Remove" ) );
+ TQToolTip::add( mRemoveDistListButton, i18n( "Remove contacts from the distribution list" ) );
+ TQWhatsThis::add( mRemoveDistListButton,
+ i18n( "Click this button if you want to remove the selected contacts from "
+ "the current distribution list." ) );
+ connect( mRemoveDistListButton, TQT_SIGNAL( clicked() ),
this, TQT_SLOT( removeSelectedContactsFromDistList() ) );
- buttonLayout->addWidget( removeDistListButton );
+ buttonLayout->addWidget( mRemoveDistListButton );
#endif
mFilterSelectionWidget = new FilterSelectionWidget( searchTB , "kde toolbar widget" );
@@ -1566,8 +1612,42 @@ void KABCore::removeSelectedContactsFromDistList()
const TQStringList uids = selectedUIDs();
if ( uids.isEmpty() )
return;
- for ( TQStringList::ConstIterator it = uids.begin(); it != uids.end(); ++it ) {
- dist.removeEntry ( *it );
+
+ TQStringList names;
+ TQStringList::ConstIterator it = uids.begin();
+ const TQStringList::ConstIterator endIt( uids.end() );
+ while ( it != endIt ) {
+ KABC::Addressee addr = mAddressBook->findByUid( *it );
+ names.append( addr.realName().isEmpty() ? addr.preferredEmail() : addr.realName() );
+ ++it;
+ }
+
+ if ( KMessageBox::warningContinueCancelList(
+ mWidget,
+ i18n( "<qt>"
+ "Do you really want to remove this contact from the %1 distribution list?<br>"
+ "<b>Note:</b>The contact will be not be removed from your addressbook nor from "
+ "any other distribution list."
+ "</qt>",
+ "<qt>"
+ "Do you really want to remove these %n contacts from the %1 distribution list?<br>"
+ "<b>Note:</b>The contacts will be not be removed from your addressbook nor from "
+ "any other distribution list."
+ "</qt>",
+ uids.count() ).arg( mSelectedDistributionList ),
+ names, TQString::null, KStdGuiItem::del() ) == KMessageBox::Cancel ) {
+ return;
+ }
+
+ for ( TQStringList::ConstIterator uidIt = uids.begin(); uidIt != uids.end(); ++uidIt ) {
+ typedef KPIM::DistributionList::Entry::List EntryList;
+ const EntryList entries = dist.entries( addressBook() );
+ for ( EntryList::ConstIterator it = entries.begin(); it != entries.end(); ++it ) {
+ if ( (*it).addressee.uid() == (*uidIt) ) {
+ dist.removeEntry( (*it).addressee, (*it).email );
+ break;
+ }
+ }
}
addressBook()->insertAddressee( dist );
setModified();
@@ -1631,7 +1711,6 @@ void KABCore::editDistributionList( const KPIM::DistributionList &dist )
if ( dlg->exec() == TQDialog::Accepted && dlg ) {
const KPIM::DistributionList newDist = dlg->distributionList();
if ( newDist != dist ) {
- addressBook()->insertAddressee( newDist );
setModified();
}
}
@@ -1648,15 +1727,21 @@ void KABCore::setSelectedDistributionList( const TQString &name )
{
mSelectedDistributionList = name;
mSearchManager->setSelectedDistributionList( name );
- mViewHeaderLabel->setText( name.isNull() ? i18n( "Contacts" ) : i18n( "Distribution List: %1" ).arg( name ) );
+ mViewHeaderLabel->setText( name.isNull() ?
+ i18n( "Contacts" ) :
+ i18n( "Distribution List: %1" ).arg( name ) );
mDistListButtonWidget->setShown( !mSelectedDistributionList.isNull() );
if ( !name.isNull() ) {
mDetailsStack->raiseWidget( mDistListEntryView );
+ if ( selectedUIDs().isEmpty() ) {
+ mViewManager->setFirstSelected( true );
+ }
const TQStringList selectedUids = selectedUIDs();
showDistributionListEntry( selectedUids.isEmpty() ? TQString() : selectedUids.first() );
+ } else {
+ mDetailsStack->raiseWidget( mExtensionManager->activeDetailsWidget() ?
+ mExtensionManager->activeDetailsWidget() : mDetailsWidget );
}
- else
- mDetailsStack->raiseWidget( mExtensionManager->activeDetailsWidget() ? mExtensionManager->activeDetailsWidget() : mDetailsWidget );
}
TQStringList KABCore::distributionListNames() const
diff --git a/kaddressbook/kabcore.h b/kaddressbook/kabcore.h
index ac2975106..2e6fded32 100644
--- a/kaddressbook/kabcore.h
+++ b/kaddressbook/kabcore.h
@@ -24,6 +24,8 @@
#ifndef KABCORE_H
#define KABCORE_H
+#include <config.h> // FOR KDEPIM_NEW_DISTRLISTS
+
#include <kabc/field.h>
#include <tqdict.h>
@@ -48,6 +50,7 @@ class KAboutData;
class KAction;
class KActionCollection;
class KConfig;
+class KPushButton;
class KStatusBar;
class KToggleAction;
class KXMLGUIClient;
@@ -157,7 +160,7 @@ class KDE_EXPORT KABCore : public KAB::Core
/**
sets the distribution list to display. If null, the regular
- address book is to be displayed.
+ address book is to be displayed.
*/
virtual void setSelectedDistributionList( const TQString &name );
#endif
@@ -308,7 +311,7 @@ class KDE_EXPORT KABCore : public KAB::Core
*/
virtual void newContact();
- /**
+ /**
DCOP METHOD: Opens distribution list editor to create a new distribution list
*/
virtual void newDistributionList();
@@ -347,7 +350,7 @@ class KDE_EXPORT KABCore : public KAB::Core
* If the adding to the new resource is successfull, the contact is
* removed from the old one, unless the Copy flag is given. */
void storeContactIn( const TQString &uid = TQString::null, bool copy = false );
-
+
/**
* Lets the user chose a different resource for the selected contacts and
* copies it there.
@@ -421,7 +424,7 @@ class KDE_EXPORT KABCore : public KAB::Core
void removeSelectedContactsFromDistList();
void editSelectedDistributionList();
- void sendMailToDistributionList( const TQString &id );
+ void sendMailToDistributionList( const TQString &id );
private:
void initGUI();
@@ -443,6 +446,8 @@ class KDE_EXPORT KABCore : public KAB::Core
#ifdef KDEPIM_NEW_DISTRLISTS
TQString mSelectedDistributionList;
+ KPushButton *mAddDistListButton;
+ KPushButton *mRemoveDistListButton;
TQWidget *mDistListButtonWidget;
#endif
diff --git a/kaddressbook/kabtools.cpp b/kaddressbook/kabtools.cpp
index ba3b886f0..7e6b5c9cd 100644
--- a/kaddressbook/kabtools.cpp
+++ b/kaddressbook/kabtools.cpp
@@ -80,12 +80,15 @@ void KABTools::mailVCards( const TQStringList &uids, KABC::AddressBook *ab )
KABC::VCardConverter converter;
KABC::Addressee::List list;
list.append( addressee );
+#if defined(KABC_VCARD_ENCODING_FIX)
+ const TQCString vcard = converter.createVCardsRaw( list, KABC::VCardConverter::v3_0 );
+ file.writeBlock( vcard, vcard.length() );
+#else
TQString vcard = converter.createVCards( list, KABC::VCardConverter::v3_0 );
-
TQTextStream t( &file );
t.setEncoding( TQTextStream::UnicodeUTF8 );
t << vcard;
-
+#endif
file.close();
KURL url( path );
diff --git a/kaddressbook/kaddressbook.desktop b/kaddressbook/kaddressbook.desktop
index 92a1ee73a..a636c7760 100644
--- a/kaddressbook/kaddressbook.desktop
+++ b/kaddressbook/kaddressbook.desktop
@@ -42,7 +42,6 @@ GenericName[hu]=Címjegyzékkezelő
GenericName[is]=Vistfangastjóri
GenericName[it]=Gestore degli indirizzi
GenericName[ja]=アドレスマネージャ
-GenericName[ka]=წიგნაკის მმართველი
GenericName[kk]=Адрестік кітапшасы
GenericName[km]=កម្មវិធី​គ្រប់គ្រង​អាសយដ្ឋាន
GenericName[lt]=Adresų tvarkyklė
diff --git a/kaddressbook/kaddressbook_view.desktop b/kaddressbook/kaddressbook_view.desktop
index 05e445e39..ffd4e8d5c 100644
--- a/kaddressbook/kaddressbook_view.desktop
+++ b/kaddressbook/kaddressbook_view.desktop
@@ -28,7 +28,6 @@ Comment[hu]=KAddressBook nézeti bővítőmodul
Comment[is]=KAddressbook birtingar íforrit
Comment[it]=Plugin visualizzazione di KAddressbook
Comment[ja]=Addressbook ビュープラグイン
-Comment[ka]= KDE წიგნაკის ჩვენების მოდული
Comment[kk]=Адрестік кітапшасын қарау модулі
Comment[km]=កម្មវិធី​ជំនួយ​ទិដ្ឋភាព​របស់ KAddressBook
Comment[lt]=KAddressBook peržiūros priedas
diff --git a/kaddressbook/kcmconfigs/kabconfig.desktop b/kaddressbook/kcmconfigs/kabconfig.desktop
index 17a0b1b5a..f5e5d450d 100644
--- a/kaddressbook/kcmconfigs/kabconfig.desktop
+++ b/kaddressbook/kcmconfigs/kabconfig.desktop
@@ -36,7 +36,6 @@ Name[hu]=Általános
Name[is]=Almennt
Name[it]=Generale
Name[ja]=全般
-Name[ka]=ზოგადი
Name[kk]=Жалпы
Name[km]=ទូទៅ
Name[lt]=Bendras
@@ -62,8 +61,7 @@ Name[ta]=பொதுவான
Name[th]=ทั่วไป
Name[tr]=Genel
Name[uk]=Загальні
-Name[uz]=Umumiy
-Name[uz@cyrillic]=Умумий
+Name[uz]=Умумий
Name[zh_CN]=常规
Comment=Configure the Address Book
Comment[af]=Stel die adres boek op
@@ -94,7 +92,6 @@ Comment[hu]=A címjegyzék beállítása
Comment[is]=Stilla vistfangaskrána
Comment[it]=Configura la rubrica indirizzi
Comment[ja]=アドレス帳設定
-Comment[ka]=წიგნაკის კონფიგურაცია
Comment[kk]=Адрестік кітапшаны баптау
Comment[km]=កំណត់​រចនាសម្ព័ន្ធ​សៀវភៅ​អាសយដ្ឋាន
Comment[lt]=Konfigūruoti adresų knygelę
@@ -120,8 +117,7 @@ Comment[ta]=கேமுகவரிப்புத்தகத்தை கட
Comment[tg]=Танзимоти китоби адрес
Comment[tr]=Adres Defterini Yapılandır
Comment[uk]=Налаштування адресної книги
-Comment[uz]=Manzillar daftarini moslash
-Comment[uz@cyrillic]=Манзиллар дафтарини мослаш
+Comment[uz]=Манзиллар дафтарини мослаш
Comment[zh_CN]=配置地址簿
Comment[zh_TW]=設定通訊錄
Keywords=kaddressbook, configure, settings
@@ -151,7 +147,6 @@ Keywords[hu]=kaddressbook, konfigurálás, beállítások
Keywords[is]=kaddressbook, stillingar, stilla
Keywords[it]=kaddressbook, configura, impostazioni
Keywords[ja]=kaddressbook 設定
-Keywords[ka]=kaddressbook,კონფიგურაცია, პარამეტრები
Keywords[km]=kaddressbook,កំណត់​រចនាសម្ព័ន្ធ,ការ​កំណត់
Keywords[lt]=kaddressbook, configure, settings, konfigūravimas, nustatymai
Keywords[mk]=kaddressbook, configure, settings, КАдресар, конфигурирање, конфигурација, поставување
@@ -175,6 +170,5 @@ Keywords[ta]=கேமுகவரிப்புத்தகம்,கட்ட
Keywords[tg]=kaddressbook,китоби адрес,танзимот
Keywords[tr]=kadresdefteri, yapılandırma, ayarlar
Keywords[uk]=kaddressbook, налаштування, параметри
-Keywords[uz]=kaddressbook, moslash, moslamalar, manzillar daftari
-Keywords[uz@cyrillic]=kaddressbook, мослаш, мосламалар, манзиллар дафтари
+Keywords[uz]=kaddressbook, мослаш, мосламалар, манзиллар дафтари
Keywords[zh_CN]=kaddressbook, configure, settings, 配置, 设置
diff --git a/kaddressbook/kcmconfigs/kabcustomfields.desktop b/kaddressbook/kcmconfigs/kabcustomfields.desktop
index f0b7cf1ff..c2d97c0f8 100644
--- a/kaddressbook/kcmconfigs/kabcustomfields.desktop
+++ b/kaddressbook/kcmconfigs/kabcustomfields.desktop
@@ -37,7 +37,6 @@ Name[hu]=Egyéni lapok
Name[is]=Sérsniðnar síður
Name[it]=Pagine personalizzate
Name[ja]=カスタムページ
-Name[ka]=სამომხმარებლო გვერდები
Name[kk]=Қосымша парақтар
Name[km]=ទំព័រ​ផ្ទាល់​ខ្លួន
Name[lt]=Pasirinkti puslapiai
@@ -89,7 +88,6 @@ Comment[hu]=Az egyéni lapok beállítása
Comment[is]=Stilla sérsniðnu síðurnar
Comment[it]=Configura le pagine personalizzate
Comment[ja]=カスタムページの設定
-Comment[ka]=სამომხმარებლო გვერდების კონფიგურაცია
Comment[kk]=Қосымша парақтарды баптау
Comment[km]=កំណត់​រចនាសម្ព័ន្ធ​ទំព័រ​ផ្ទាល់​ខ្លួន
Comment[lt]=Konfigūruoti darbastalių skaičių ir pavadinimus
@@ -137,7 +135,6 @@ Keywords[hu]=kaddressbook, beállítás, beállítások, egyéni mezők
Keywords[is]=kaddressbook, stillingar, stilla, sérsniðnir reitir
Keywords[it]=kaddressbook, configura, impostazioni, campi personalizzati
Keywords[ja]=kaddressbook、設定、設定,カスタムフィールド
-Keywords[ka]=kaddressbook,კონფიგურაცია,პარამეტრები,სამომხმარებლო ველები
Keywords[km]=kaddressbook,កំណត់​រចនាសម្ព័ន្ធ,ការ​កំណត់,វាល​ផ្ទាល់​ខ្លួន
Keywords[lt]=kaddressbook, configure, settings, custom fields, pasirinkti laukai,konfigūruoti, nustatymai
Keywords[mk]=kaddressbook, configure, settings, custom fields, КАдресар, конфигурација, конфигурирање, сопствени полиња
diff --git a/kaddressbook/kcmconfigs/kabldapconfig.desktop b/kaddressbook/kcmconfigs/kabldapconfig.desktop
index a13645a98..2d29acdf0 100644
--- a/kaddressbook/kcmconfigs/kabldapconfig.desktop
+++ b/kaddressbook/kcmconfigs/kabldapconfig.desktop
@@ -38,7 +38,6 @@ Name[hu]=LDAP-lekérdezés
Name[is]=LDAP uppfletting
Name[it]=Ricerca LDAP
Name[ja]=LDAP 検索
-Name[ka]= ძებნა LDAP-ში
Name[kk]=LDAP іздеу
Name[km]=ស្វែងរក LDAP
Name[lt]=LDAP paieška
@@ -89,7 +88,6 @@ Comment[hu]=A címjegyzék LDAP-beállításainak megváltoztatása
Comment[is]=Breyta LDAP stillingum vistfangaskráarinnar
Comment[it]=Configurare le impostazioni LDAP della rubrica indirizzi
Comment[ja]=アドレス帳 LDAP 設定
-Comment[ka]=LDAP წიგნაკის პარამეტრების კონფიგურაცია
Comment[kk]=Адрестік кітапшаның LDAP параметрлерін баптау
Comment[km]=កំណត់​រចនាសម្ព័ន្ធ​ការ​កំណត់ LDAP របស់​សៀវភៅ​អាសយដ្ឋាន
Comment[lt]=Konfigūruoti adresų knygelės LDAP nustatymus
@@ -113,8 +111,7 @@ Comment[ta]=கேமுகவரிபுத்தகத்தை உருவ
Comment[tg]=Танзимоти серверҳои LDAP-и китоби адрес
Comment[tr]=Adres Defteri LDAP Ayarlarını Yapılandır
Comment[uk]=Налаштування параметрів LDAP для адресної книги
-Comment[uz]=LDAP manzillar daftarini moslash
-Comment[uz@cyrillic]=LDAP манзиллар дафтарини мослаш
+Comment[uz]=LDAP манзиллар дафтарини мослаш
Comment[zh_CN]=配置地址簿 LDAP 设置
Comment[zh_TW]=設定通訊錄 LDAP 設定
Keywords=kaddressbook, configure, settings, LDAP
@@ -142,7 +139,6 @@ Keywords[hu]=kaddressbook, konfiguráció, beállítások, LDAP
Keywords[is]=kaddressbook, stillingar, stilla, LDAP
Keywords[it]=kaddressbook, configura, impostazioni, LDAP
Keywords[ja]=kaddressbook LDAP 設定
-Keywords[ka]=kaddressbook,კონფიგურაცია,პარამეტრები, LDAP
Keywords[km]=kaddressbook,កំណត់​រចនាសម្ព័ន្ធ,ការ​កំណត់,LDAP
Keywords[lt]=kaddressbook, configure, settings, LDAP, nustatymai, konfigūruoti
Keywords[mk]=kaddressbook, configure, settings, LDAP, кадресар, конфигурација, конфигурирање, поставувања
@@ -166,6 +162,5 @@ Keywords[ta]=கேமுகவரிபுத்தகம்,கட்டமை
Keywords[tg]=kaddressbook, configure, settings, LDAP, китоби адрес, танзимот
Keywords[tr]=adres defteri,yapılandırma,ayarlar,LDAP
Keywords[uk]=kaddressbook, налаштування, параметри, LDAP
-Keywords[uz]=kaddressbook, moslash, moslamalar, manzillar daftari, LDAP
-Keywords[uz@cyrillic]=kaddressbook, мослаш, мосламалар, манзиллар дафтари, LDAP
+Keywords[uz]=kaddressbook, мослаш, мосламалар, манзиллар дафтари, LDAP
Keywords[zh_CN]=kaddressbook, configure, settings, LDAP, 配置, 设置
diff --git a/kaddressbook/ldapsearchdialog.cpp b/kaddressbook/ldapsearchdialog.cpp
index fc99562d4..c42ff6693 100644
--- a/kaddressbook/ldapsearchdialog.cpp
+++ b/kaddressbook/ldapsearchdialog.cpp
@@ -576,7 +576,14 @@ KABC::Addressee::List LDAPSearchDialog::importContactsUnlessTheyExist( const TQV
addr.setNote( i18n( "arguments are host name, datetime", "Imported from LDAP directory %1 on %2" ).arg( d->itemToServer[cli], KGlobal::locale()->formatDateTime( now ) ) );
addr.setResource( resource );
mCore->addressBook()->insertAddressee( addr );
- importedAddrs.append( addr.fullEmail() );
+ TQString displayString;
+ if ( !addr.fullEmail().isEmpty() ) {
+ displayString = addr.fullEmail();
+ }
+ else {
+ displayString = addr.formattedName();
+ }
+ importedAddrs.append( displayString );
localAddrs.append( addr );
} else {
localAddrs.append( existing.first() );
@@ -595,14 +602,15 @@ KABC::Addressee::List LDAPSearchDialog::importContactsUnlessTheyExist( const TQV
void LDAPSearchDialog::slotUser2()
{
#ifdef KDEPIM_NEW_DISTRLISTS
- KABC::Resource *resource = mCore->requestResource( this );
- if ( !resource ) return;
-
const TQValueList<ContactListItem*> selectedItems = d->selectedItems( mResultListView );
if ( selectedItems.isEmpty() ) {
KMessageBox::information( this, i18n( "Please select the contacts you want to add to the distribution list." ), i18n( "No Contacts Selected" ) );
return;
}
+
+ KABC::Resource *resource = mCore->requestResource( this );
+ if ( !resource ) return;
+
KPIM::DistributionList dist = selectDistributionList();
if ( dist.isEmpty() )
return;
@@ -628,6 +636,8 @@ void LDAPSearchDialog::slotUser1()
KABC::Resource *resource = mCore->requestResource( this );
if ( !resource ) return;
const TQValueList<ContactListItem*> selectedItems = d->selectedItems( mResultListView );
+ if( selectedItems.isEmpty() )
+ return;
importContactsUnlessTheyExist( selectedItems, resource );
}
diff --git a/kaddressbook/searchmanager.cpp b/kaddressbook/searchmanager.cpp
index 0cd23b5a1..374a1af5b 100644
--- a/kaddressbook/searchmanager.cpp
+++ b/kaddressbook/searchmanager.cpp
@@ -20,6 +20,7 @@
with any edition of Qt, and distribute the resulting executable,
without including the source code for Qt in the source distribution.
*/
+#include <config.h> // FOR KDEPIM_NEW_DISTRLISTS
#include <kabc/addresseelist.h>
#include <kdeversion.h>
diff --git a/kaddressbook/thumbnailcreator/ldifvcardcreator.cpp b/kaddressbook/thumbnailcreator/ldifvcardcreator.cpp
index 0ed562e18..3de0220f0 100644
--- a/kaddressbook/thumbnailcreator/ldifvcardcreator.cpp
+++ b/kaddressbook/thumbnailcreator/ldifvcardcreator.cpp
@@ -75,7 +75,13 @@ bool VCard_LDIFCreator::readContents( const TQString &path )
text.truncate(0);
// read the file
+#if defined(KABC_VCARD_ENCODING_FIX)
+ const TQByteArray data = file.readAll();
+ const TQString contents( data );
+ const TQCString contentsRaw( data.data(), data.size() );
+#else
TQString contents = file.readAll();
+#endif
file.close();
// convert the file contents to a KABC::Addressee address
@@ -83,7 +89,11 @@ bool VCard_LDIFCreator::readContents( const TQString &path )
KABC::Addressee addr;
KABC::VCardConverter converter;
+#if defined(KABC_VCARD_ENCODING_FIX)
+ addrList = converter.parseVCardsRaw( contentsRaw );
+#else
addrList = converter.parseVCards( contents );
+#endif
if ( addrList.count() == 0 )
if ( !KABC::LDIFConverter::LDIFToAddressee( contents, addrList ) )
return false;
diff --git a/kaddressbook/thumbnailcreator/ldifvcardcreator.h b/kaddressbook/thumbnailcreator/ldifvcardcreator.h
index 7b5cface5..2de6c7b41 100644
--- a/kaddressbook/thumbnailcreator/ldifvcardcreator.h
+++ b/kaddressbook/thumbnailcreator/ldifvcardcreator.h
@@ -23,6 +23,7 @@
#include <tqpixmap.h>
#include <kio/thumbcreator.h>
+#include <kabc/vcardparser.h> // for KABC_VCARD_ENCODING_FIX define
class KPixmapSplitter;
diff --git a/kaddressbook/thumbnailcreator/ldifvcardthumbnail.desktop b/kaddressbook/thumbnailcreator/ldifvcardthumbnail.desktop
index 2eb63ab57..90d73eac3 100644
--- a/kaddressbook/thumbnailcreator/ldifvcardthumbnail.desktop
+++ b/kaddressbook/thumbnailcreator/ldifvcardthumbnail.desktop
@@ -25,7 +25,6 @@ Name[hu]=Elektronikus névjegykártyák
Name[is]=Skrár með rafrænum nafnspjöldum
Name[it]=Biglietto da visita elettronico
Name[ja]=電子ビジネスカードファイル
-Name[ka]=ელექტრონული სავიზიტო ბარათების ფაილები
Name[kk]=Электрондық визитка файлдары
Name[km]=ឯកសារ​នាមប័ណ្ណ​អេឡិចត្រូនិច
Name[lt]=Elektroninės verslo kortelės bylos
diff --git a/kaddressbook/undocmds.cpp b/kaddressbook/undocmds.cpp
index ee9895951..0f6e555d4 100644
--- a/kaddressbook/undocmds.cpp
+++ b/kaddressbook/undocmds.cpp
@@ -28,6 +28,8 @@
#include <klocale.h>
#include <kapplication.h>
+#include <kabc/resource.h>
+
#include "addresseeutil.h"
#include "addresseeconfig.h"
#include "core.h"
@@ -35,6 +37,16 @@
#include "undocmds.h"
+bool Command::resourceExist( KABC::Resource *resource )
+{
+ TQPtrList<KABC::Resource> lst = addressBook()->resources();
+ for ( Resource *res = lst.first(); res; res = lst.next() ) {
+ if ( res == resource )
+ return true;
+ }
+ return false;
+}
+
DeleteCommand::DeleteCommand( KABC::AddressBook *addressBook,
const TQStringList &uidList)
: Command( addressBook ), mUIDList( uidList )
@@ -57,7 +69,8 @@ void DeleteCommand::unexecute()
lock()->lock( (*it).resource() );
for ( it = mAddresseeList.begin(); it != endIt; ++it ) {
- addressBook()->insertAddressee( *it );
+ if ( resourceExist( ( *it ).resource() ) )
+ addressBook()->insertAddressee( *it );
lock()->unlock( (*it).resource() );
}
@@ -81,7 +94,8 @@ void DeleteCommand::execute()
KABC::Addressee::List::ConstIterator addrIt;
const KABC::Addressee::List::ConstIterator addrEndIt( mAddresseeList.end() );
for ( addrIt = mAddresseeList.begin(); addrIt != addrEndIt; ++addrIt ) {
- addressBook()->removeAddressee( *addrIt );
+ if ( resourceExist( ( *addrIt ).resource() ) )
+ addressBook()->removeAddressee( *addrIt );
lock()->unlock( (*addrIt).resource() );
}
}
@@ -107,7 +121,8 @@ void PasteCommand::unexecute()
lock()->lock( (*it).resource() );
for ( it = mAddresseeList.begin(); it != endIt; ++it ) {
- addressBook()->removeAddressee( *it );
+ if ( resourceExist( ( *it ).resource() ) )
+ addressBook()->removeAddressee( *it );
lock()->unlock( (*it).resource() );
}
}
@@ -126,20 +141,19 @@ void PasteCommand::execute()
KABC::Addressee::List::Iterator it;
const KABC::Addressee::List::Iterator endIt( mAddresseeList.end() );
for ( it = mAddresseeList.begin(); it != endIt; ++it ) {
- /**
- We have to set a new uid for the contact, otherwise insertAddressee()
- ignore it.
- */
- (*it).setUid( KApplication::randomString( 10 ) );
- uids.append( (*it).uid() );
- addressBook()->insertAddressee( *it );
+ if ( resourceExist( ( *it ).resource() ) ) {
+
+ /**
+ We have to set a new uid for the contact, otherwise insertAddressee()
+ ignore it.
+ */
+ (*it).setUid( KApplication::randomString( 10 ) );
+ uids.append( (*it).uid() );
+ addressBook()->insertAddressee( *it );
+ }
lock()->unlock( (*it).resource() );
}
- TQStringList::ConstIterator uidIt;
- const TQStringList::ConstIterator uidEndIt( uids.end() );
- for ( uidIt = uids.begin(); uidIt != uidEndIt; ++uidIt )
- mCore->editContact( *uidIt );
}
@@ -163,7 +177,8 @@ void NewCommand::unexecute()
lock()->lock( (*it).resource() );
for ( it = mAddresseeList.begin(); it != endIt; ++it ) {
- addressBook()->removeAddressee( *it );
+ if ( resourceExist( ( *it ).resource() ) )
+ addressBook()->removeAddressee( *it );
lock()->unlock( (*it).resource() );
}
}
@@ -178,7 +193,8 @@ void NewCommand::execute()
lock()->lock( (*it).resource() );
for ( it = mAddresseeList.begin(); it != endIt; ++it ) {
- addressBook()->insertAddressee( *it );
+ if ( resourceExist( ( *it ).resource() ) )
+ addressBook()->insertAddressee( *it );
lock()->unlock( (*it).resource() );
}
}
@@ -199,16 +215,22 @@ TQString EditCommand::name() const
void EditCommand::unexecute()
{
- lock()->lock( mOldAddressee.resource() );
- addressBook()->insertAddressee( mOldAddressee );
- lock()->unlock( mOldAddressee.resource() );
+ if ( resourceExist( mOldAddressee.resource() ) )
+ {
+ lock()->lock( mOldAddressee.resource() );
+ addressBook()->insertAddressee( mOldAddressee );
+ lock()->unlock( mOldAddressee.resource() );
+ }
}
void EditCommand::execute()
{
- lock()->lock( mNewAddressee.resource() );
- addressBook()->insertAddressee( mNewAddressee );
- lock()->unlock( mNewAddressee.resource() );
+ if ( resourceExist( mNewAddressee.resource() ) )
+ {
+ lock()->lock( mNewAddressee.resource() );
+ addressBook()->insertAddressee( mNewAddressee );
+ lock()->unlock( mNewAddressee.resource() );
+ }
}
@@ -232,7 +254,8 @@ void CutCommand::unexecute()
lock()->lock( (*it).resource() );
for ( it = mAddresseeList.begin(); it != endIt; ++it ) {
- addressBook()->insertAddressee( *it );
+ if ( resourceExist( ( *it ).resource() ) )
+ addressBook()->insertAddressee( *it );
lock()->unlock( (*it).resource() );
}
@@ -258,7 +281,8 @@ void CutCommand::execute()
KABC::Addressee::List::ConstIterator addrIt;
const KABC::Addressee::List::ConstIterator addrEndIt( mAddresseeList.end() );
for ( addrIt = mAddresseeList.begin(); addrIt != addrEndIt; ++addrIt ) {
- addressBook()->removeAddressee( *addrIt );
+ if ( resourceExist( ( *addrIt ).resource() ) )
+ addressBook()->removeAddressee( *addrIt );
lock()->unlock( addr.resource() );
}
@@ -268,5 +292,115 @@ void CutCommand::execute()
QClipboard *cb = TQApplication::clipboard();
mOldText = cb->text();
kapp->processEvents();
+#if defined(KABC_VCARD_ENCODING_FIX)
+ cb->setText( TQString::fromUtf8( mClipText.data() ) );
+#else
cb->setText( mClipText );
+#endif
+}
+
+CopyToCommand::CopyToCommand( KABC::AddressBook *addressBook, const TQStringList &uidList,
+ KABC::Resource *resource )
+ : Command( addressBook ), mUIDList( uidList ), mResource( resource )
+{
+}
+
+TQString CopyToCommand::name() const
+{
+ return i18n( "Copy Contact To", "Copy %n Contacts To", mUIDList.count() );
+}
+
+void CopyToCommand::unexecute()
+{
+ KABC::Addressee::List::ConstIterator it;
+ const KABC::Addressee::List::ConstIterator endIt( mAddresseeList.end() );
+ //For copy : just remove it from the "copied to" resource.
+ // lock resources
+ for ( it = mAddresseeList.begin(); it != endIt; ++it )
+ lock()->lock( (*it).resource() );
+
+ for ( it = mAddresseeList.begin(); it != endIt; ++it ) {
+ if ( resourceExist( ( *it ).resource() ) )
+ addressBook()->removeAddressee( *it );
+ lock()->unlock( (*it).resource() );
+ }
+}
+
+void CopyToCommand::execute()
+{
+ KABLock::self( addressBook() )->lock( mResource );
+ TQStringList::Iterator it( mUIDList.begin() );
+ const TQStringList::Iterator endIt( mUIDList.end() );
+ while ( it != endIt ) {
+ KABC::Addressee addr = addressBook()->findByUid( *it++ );
+ if ( !addr.isEmpty() ) {
+ KABC::Addressee newAddr( addr );
+ // We need to set a new uid, otherwise the insert below is
+ // ignored. This is bad for syncing, but unavoidable, afaiks
+ newAddr.setUid( KApplication::randomString( 10 ) );
+ newAddr.setResource( mResource );
+ if ( resourceExist( newAddr.resource() ) )
+ addressBook()->insertAddressee( newAddr );
+ mAddresseeList.append( newAddr );
+ }
+ }
+ KABLock::self( addressBook() )->unlock( mResource );
+
+}
+
+MoveToCommand::MoveToCommand( KAB::Core *core, const TQStringList &uidList,
+ KABC::Resource *resource )
+ : Command( core->addressBook() ), mUIDList( uidList ), mResource( resource ), mCore( core )
+{
+}
+
+TQString MoveToCommand::name() const
+{
+ return i18n( "Move Contact To", "Move %n Contacts To", mUIDList.count() );
+}
+
+void MoveToCommand::unexecute()
+{
+ //For move : remove it from the "copied to" resource and insert it back to "copied from" resource.
+ KABC::Resource *resource = mCore->requestResource( mCore->widget() );
+ if ( !resource )
+ return;
+ moveContactTo( resource );
+}
+
+void MoveToCommand::execute()
+{
+ moveContactTo( mResource );
+}
+
+void MoveToCommand::moveContactTo( KABC::Resource *resource )
+{
+ KABLock::self( addressBook() )->lock( resource );
+ TQStringList::Iterator it( mUIDList.begin() );
+ const TQStringList::Iterator endIt( mUIDList.end() );
+ while ( it != endIt ) {
+ KABC::Addressee addr = addressBook()->findByUid( *it++ );
+ if ( !addr.isEmpty() ) {
+ KABC::Addressee newAddr( addr );
+ // We need to set a new uid, otherwise the insert below is
+ // ignored. This is bad for syncing, but unavoidable, afaiks
+ TQString uid = KApplication::randomString( 10 );
+ newAddr.setUid( uid );
+ newAddr.setResource( resource );
+ if ( resourceExist( newAddr.resource() ) )
+ addressBook()->insertAddressee( newAddr );
+ mAddresseeList.append( newAddr );
+ mUIDList.append( uid );
+ const bool inserted = addressBook()->find( newAddr ) != addressBook()->end();
+ if ( inserted ) {
+ if ( resourceExist( addr.resource() ) ) {
+ KABLock::self( addressBook() )->lock( addr.resource() );
+ addressBook()->removeAddressee( addr );
+ KABLock::self( addressBook() )->unlock( addr.resource() );
+ }
+ }
+ }
+ }
+ KABLock::self( addressBook() )->unlock( resource );
+
}
diff --git a/kaddressbook/undocmds.h b/kaddressbook/undocmds.h
index 192a4e80b..43f6aae99 100644
--- a/kaddressbook/undocmds.h
+++ b/kaddressbook/undocmds.h
@@ -32,6 +32,8 @@
#include <kabc/addressbook.h>
#include <kabc/addressee.h>
+#include <kabc/vcardparser.h> // for KABC_VCARD_ENCODING_FIX define
+
#include <kcommand.h>
#include "kablock.h"
@@ -48,9 +50,9 @@ class Command : public KCommand
protected:
KABC::AddressBook *addressBook() const { return mAddressBook; }
KABLock *lock() const { return KABLock::self( mAddressBook ); }
-
+ bool resourceExist( KABC::Resource *resource );
private:
- KABC::AddressBook *mAddressBook;
+ KABC::AddressBook* mAddressBook;
};
class DeleteCommand : public Command
@@ -94,7 +96,11 @@ class CutCommand : public Command
private:
KABC::Addressee::List mAddresseeList;
TQStringList mUIDList;
+#if defined(KABC_VCARD_ENCODING_FIX)
+ TQByteArray mClipText;
+#else
TQString mClipText;
+#endif
TQString mOldText;
};
@@ -127,4 +133,37 @@ class EditCommand : public Command
KABC::Addressee mNewAddressee;
};
+class CopyToCommand : public Command
+{
+ public:
+ CopyToCommand( KABC::AddressBook *addressBook, const TQStringList &uidList,
+ KABC::Resource *resource );
+
+ virtual TQString name() const;
+ virtual void unexecute();
+ virtual void execute();
+
+ private:
+ KABC::Addressee::List mAddresseeList;
+ TQStringList mUIDList;
+ KABC::Resource *mResource;
+};
+
+class MoveToCommand : public Command
+{
+ public:
+ MoveToCommand( KAB::Core *core, const TQStringList &uidList,
+ KABC::Resource *resource );
+
+ virtual TQString name() const;
+ virtual void unexecute();
+ virtual void execute();
+ void moveContactTo( KABC::Resource *resource );
+
+ private:
+ KABC::Addressee::List mAddresseeList;
+ TQStringList mUIDList;
+ KABC::Resource *mResource;
+ KAB::Core *mCore;
+};
#endif
diff --git a/kaddressbook/viewmanager.cpp b/kaddressbook/viewmanager.cpp
index 4e4cd5a65..5dab74e25 100644
--- a/kaddressbook/viewmanager.cpp
+++ b/kaddressbook/viewmanager.cpp
@@ -419,7 +419,7 @@ void ViewManager::dropped( TQDropEvent *e )
if ( e->source() == this )
return;
- TQString clipText, vcards;
+ KABC::Addressee::List list;
KURL::List urls;
if ( KURLDrag::decode( e, urls) ) {
@@ -433,10 +433,7 @@ void ViewManager::dropped( TQDropEvent *e )
}
} else if ( c == 1 )
emit urlDropped( *it );
- } else if ( KVCardDrag::decode( e, vcards ) ) {
- KABC::VCardConverter converter;
-
- const KABC::Addressee::List list = converter.parseVCards( vcards );
+ } else if ( KVCardDrag::decode( e, list ) ) {
KABC::Addressee::List::ConstIterator it;
for ( it = list.begin(); it != list.end(); ++it ) {
KABC::Addressee a = mCore->addressBook()->findByUid( (*it).uid() );
@@ -467,7 +464,11 @@ void ViewManager::startDrag()
KMultipleDrag *drag = new KMultipleDrag( this );
KABC::VCardConverter converter;
+#if defined(KABC_VCARD_ENCODING_FIX)
+ TQCString vcards = converter.createVCardsRaw( addrList );
+#else
TQString vcards = converter.createVCards( addrList );
+#endif
// Best text representation is given by textdrag, so it must be first
drag->addDragObject( new TQTextDrag( AddresseeUtil::addresseesToEmails( addrList ), this ) );
@@ -484,7 +485,11 @@ void ViewManager::startDrag()
TQFile tempFile( tempDir.name() + "/" + fileName );
if ( tempFile.open( IO_WriteOnly ) ) {
+#if defined(KABC_VCARD_ENCODING_FIX)
+ tempFile.writeBlock( vcards, vcards.length() );
+#else
tempFile.writeBlock( vcards.utf8() );
+#endif
tempFile.close();
KURLDrag *urlDrag = new KURLDrag( KURL( tempFile.name() ), this );
diff --git a/kaddressbook/views/cardview.desktop b/kaddressbook/views/cardview.desktop
index cb8d35cb0..7dfe4152d 100644
--- a/kaddressbook/views/cardview.desktop
+++ b/kaddressbook/views/cardview.desktop
@@ -28,7 +28,6 @@ Name[hu]=Kártyanézet
Name[is]=Spjaldsýn
Name[it]=Vista scheda
Name[ja]=カードビュー
-Name[ka]=ბარათების ჩვენება
Name[kk]=Визитка
Name[km]=ទិដ្ឋភាព​កាត
Name[lt]=Kortelės vaizdas
diff --git a/kaddressbook/views/iconview.desktop b/kaddressbook/views/iconview.desktop
index 59853a70e..4e99a5c5b 100644
--- a/kaddressbook/views/iconview.desktop
+++ b/kaddressbook/views/iconview.desktop
@@ -32,7 +32,6 @@ Name[id]=Tampilan Ikon
Name[is]=Táknmyndasýn
Name[it]=Vista a icone
Name[ja]=アイコンビュー
-Name[ka]=ხატულების ჩვენება
Name[kk]=Таңбаша
Name[km]=ទិដ្ឋភាព​រូបតំណាង
Name[lt]=Rodyti piktogramas
@@ -63,8 +62,7 @@ Name[tg]=Ишоротҳо
Name[th]=มุมมองแบบไอคอน
Name[tr]=Simge Görünümü
Name[uk]=Вигляд піктограмами
-Name[uz]=Nishoncha koʻrinishida
-Name[uz@cyrillic]=Нишонча кўринишида
+Name[uz]=Нишонча кўринишида
Name[ven]=Mbonalelo ya aikhono
Name[vi]=Xem icon
Name[xh]=Imboniselo ye Icon
diff --git a/kaddressbook/views/tableview.desktop b/kaddressbook/views/tableview.desktop
index b07b2a19c..71856c965 100644
--- a/kaddressbook/views/tableview.desktop
+++ b/kaddressbook/views/tableview.desktop
@@ -28,7 +28,6 @@ Name[hu]=Táblázatos nézet
Name[is]=Töflusýn
Name[it]=Vista tabella
Name[ja]=テーブルビュー
-Name[ka]=ცხრილი
Name[kk]=Кесте
Name[km]=ទិដ្ឋភាព​តារាង
Name[lt]=Lentelės vaizdas
@@ -55,8 +54,7 @@ Name[ta]=அட்டவணை காட்சி
Name[tg]=Ҷадвал
Name[tr]=Tablo Görünümü
Name[uk]=Вигляд таблицею
-Name[uz]=Jadval koʻrinishida
-Name[uz@cyrillic]=Жадвал кўринишида
+Name[uz]=Жадвал кўринишида
Name[zh_CN]=表格视图
Name[zh_TW]=表格檢視
Type=Service
diff --git a/kaddressbook/xxport/bookmark_xxport.desktop b/kaddressbook/xxport/bookmark_xxport.desktop
index 54d337162..186d1378e 100644
--- a/kaddressbook/xxport/bookmark_xxport.desktop
+++ b/kaddressbook/xxport/bookmark_xxport.desktop
@@ -24,7 +24,6 @@ Name[hi]=केएबी पसंदीदा XXपोर्ट प्लग
Name[hu]=KAB könyvjelzőkezelő XXPort bővítőmodul
Name[is]=Íforrit fyrir KAB XXPort bókarmerki
Name[ja]=KAB ブックマーク インポート/エクスポートプラグイン
-Name[ka]=KAB სანიშნეების ექსპორტის მოდული
Name[kk]=Бетбелгіні экспорт ету
Name[km]=កម្មវិធី​ជំនួយ KAB Bookmark XXPort
Name[lt]=KAB žymelių XXPort priedas
@@ -72,7 +71,6 @@ Comment[hu]=Bővítőmodul webcímek exportáláshoz, könyvjelzőként
Comment[is]=Íforrit til að skrá vefföng tengiliða sem bókarmerki
Comment[it]=Plugin per esportare come segnalibro gli indirizzi web dei contatti
Comment[ja]=連絡先のウェブアドレスをブックマークとしてエクスポートするプラグイン
-Comment[ka]= კონტაქტების ვებ-მისამართების სანიშნეებად ექსპორტის მოდული
Comment[kk]=Контакттың веб адрестерін бетбелгіге экспорттау модулі
Comment[km]=កម្មវិធី​ជំនួយ​ដើម្បី​នាំចេញ​អាសយដ្ឋាន​បណ្ដាញ​របស់​ទំនាក់ទំនង ជា​ចំណាំ
Comment[lt]=Priedas skirtas žiniatinklio adresų kontaktuose eksportavimui į žymeles
diff --git a/kaddressbook/xxport/csv_xxport.cpp b/kaddressbook/xxport/csv_xxport.cpp
index fa4be2c9b..b1ee94047 100644
--- a/kaddressbook/xxport/csv_xxport.cpp
+++ b/kaddressbook/xxport/csv_xxport.cpp
@@ -49,6 +49,11 @@ bool CSVXXPort::exportContacts( const KABC::AddresseeList &list, const TQString&
if ( url.isEmpty() )
return true;
+ if( TQFileInfo(url.path()).exists() ) {
+ if(KMessageBox::questionYesNo( parentWidget(), i18n("Do you want to overwrite file \"%1\"").arg( url.path()) ) == KMessageBox::No)
+ return false;
+ }
+
if ( !url.isLocalFile() ) {
KTempFile tmpFile;
if ( tmpFile.status() != 0 ) {
diff --git a/kaddressbook/xxport/csv_xxport.desktop b/kaddressbook/xxport/csv_xxport.desktop
index de6a51c42..9031c2226 100644
--- a/kaddressbook/xxport/csv_xxport.desktop
+++ b/kaddressbook/xxport/csv_xxport.desktop
@@ -24,7 +24,6 @@ Name[hi]=केएबी सीएसवी XXपोर्ट प्लगइन
Name[hu]=KAB XXPort bővítőmodul
Name[is]=Íforrit fyrir KAV CSV XXPort
Name[ja]=KAB CSV インポート/エクスポートプラグイン
-Name[ka]=KAB CSV ექსპორტის მოდული
Name[kk]=CSV файлды экспорт/импорт ету
Name[km]=កម្មវិធី​ជំនួយ KAB CSV XXPort
Name[lt]=KAB CSV XXPort priedas
@@ -71,7 +70,6 @@ Comment[hu]=Bővítőmodul névjegyek importálásához/exportálásához, CSV f
Comment[is]=Íforrit til að flytja tengiliði inn og út í CSV sniði
Comment[it]=Plugin per importare ed esportare contatti in formato CSV
Comment[ja]=CSV フォーマットで連絡先をインポート/エクスポートするプラグイン
-Comment[ka]=კონტაქტების CSV ფორმატით იმპორტ/ექსპორტის მოდული
Comment[kk]=Контакттарды CSV пішіміне экспорт/импорт ету модулі
Comment[km]=កម្មវិធី ជំនួយ​ដើម្បី​នាំចូល និង​នាំចេញ​ទំនាក់ទំនង​ក្នុង​ទ្រង់ទ្រាយ​ជា CSV ។
Comment[lt]=Priedas, skirtas kontaktų eksportui ir importui CSV formatu
diff --git a/kaddressbook/xxport/csvimportdialog.cpp b/kaddressbook/xxport/csvimportdialog.cpp
index cfcac0fec..bbcd74d2a 100644
--- a/kaddressbook/xxport/csvimportdialog.cpp
+++ b/kaddressbook/xxport/csvimportdialog.cpp
@@ -857,6 +857,10 @@ void CSVImportDialog::saveTemplate()
if ( !fileName.contains( ".desktop" ) )
fileName += ".desktop";
+ if( TQFileInfo(fileName).exists() ) {
+ if(KMessageBox::questionYesNo( this, i18n("Do you want to overwrite file \"%1\"").arg(fileName) ) == KMessageBox::No)
+ return;
+ }
TQString name = KInputDialog::getText( i18n( "Template Name" ), i18n( "Please enter a name for the template:" ) );
if ( name.isEmpty() )
diff --git a/kaddressbook/xxport/eudora_xxport.desktop b/kaddressbook/xxport/eudora_xxport.desktop
index a075f3f83..10adbfa7e 100644
--- a/kaddressbook/xxport/eudora_xxport.desktop
+++ b/kaddressbook/xxport/eudora_xxport.desktop
@@ -24,7 +24,6 @@ Name[hi]=केएबी यूडोरा XXपोर्ट प्लगइन
Name[hu]=KAB Eudora XXPort bővítőmodul
Name[is]=Íforrit fyrir KAB Eudora XXPort
Name[ja]=KAB Eudora インポート/エクスポートプラグイン
-Name[ka]= KAB Eudora-სთან ექსპორტის მოდული
Name[kk]=Eudora-ға экспорт/импорт ету
Name[km]=កម្មវិធី​ជំនួយ KAB Eudora XXPort
Name[lt]=KAB Eudora XXPort priedas
@@ -72,7 +71,6 @@ Comment[hu]=Bővítőmodul Eudora névjegyek importálásához/exportálásához
Comment[is]=Íforrit til að flytja inn og út Eudora tengiliði
Comment[it]=Plugin importare ed esportare contatti Eudora
Comment[ja]=Eudora の連絡先をインポート/エクスポートするプラグイン
-Comment[ka]=Eudora-ს კონტაქტების იმპორტ/ექსპორტის მოდული
Comment[kk]=Eudora контакттарды экспорт/импорт ету модулі
Comment[km]=កម្មវិធី​ជំនួយ​ដើម្បី​នាំចូល និង​នាំចេញ​ទំនាក់ទំនង​របស់ Eudora
Comment[lt]=Priedas Eudora kontaktų importui ir eksportui
diff --git a/kaddressbook/xxport/gnokii_xxport.desktop b/kaddressbook/xxport/gnokii_xxport.desktop
index c937a7d70..e6152fd73 100644
--- a/kaddressbook/xxport/gnokii_xxport.desktop
+++ b/kaddressbook/xxport/gnokii_xxport.desktop
@@ -24,7 +24,6 @@ Name[hu]=KAB mobiltelefon XXPort bővítőmodul
Name[is]=Íforrit fyrir KAB farsíma XXPort
Name[it]=Plugin KAB telefono cellulare XXPort
Name[ja]=KAB 携帯電話インポート/エクスポートプラグイン
-Name[ka]=KAB მობილურ ტელეფონთან ექსპორტის მოდული
Name[kk]=Қалта телефонға экспорт/импорт ету
Name[km]=កម្មវិធី​ជំនួយ KAB Mobile Phone XXPort
Name[lt]=KAB mobilaus telefono XXPort priedas
@@ -72,7 +71,6 @@ Comment[hu]=Mobiltelefonos bővítőmodul címbejegyzések importálásához/exp
Comment[is]=Íforrit til að færa tengilið milli póstfangaskrár og farsíma
Comment[it]=Plugin per importare ed esportare voci della rubrica da un telefono cellulare
Comment[ja]=アドレス帳のエントリをインポート/エクスポートする携帯電話用プラグイン
-Comment[ka]=მობილური ტელეფონის მოდული წიგნაკის ელემენტების იმპორტ/ექსპორტისათვის
Comment[kk]=Қалта телефонға адр. кітапша жазуын экспорт/импорт ету модулі
Comment[km]=កម្មវិធី​ជំនួយ​ទូរស័ព្ទ​ចល័ត​ដើម្បី​នាំចូល និង​នាំចេញ​ធាតុ​សៀវភៅ​អាសយដ្ឋាន
Comment[lt]=Priedas skirtas importuoti ir eksportuoti adresų knygelės įrašus į mobiliuosius telefonus
diff --git a/kaddressbook/xxport/kde2_xxport.cpp b/kaddressbook/xxport/kde2_xxport.cpp
index 8e754b39c..92a311023 100644
--- a/kaddressbook/xxport/kde2_xxport.cpp
+++ b/kaddressbook/xxport/kde2_xxport.cpp
@@ -66,9 +66,10 @@ KABC::AddresseeList KDE2XXPort::importContacts( const TQString& ) const
proc << "--override";
} else if ( result == KMessageBox::No )
proc << "kab2kabc";
- else
+ else {
kdDebug(5720) << "KAddressBook::importKDE2(): Unknow return value." << endl;
-
+ return KABC::AddresseeList();
+ }
proc.start( KProcess::Block );
addressBook()->load();
diff --git a/kaddressbook/xxport/kde2_xxport.desktop b/kaddressbook/xxport/kde2_xxport.desktop
index f2c20026c..d47d108f5 100644
--- a/kaddressbook/xxport/kde2_xxport.desktop
+++ b/kaddressbook/xxport/kde2_xxport.desktop
@@ -25,7 +25,6 @@ Name[hi]=केएबी केडीई2 XXपोर्ट प्लगइन
Name[hu]=KAB KDE2 XXPort bővítőmodul
Name[is]=Íforrit fyrir KAB KDE2 XXPort
Name[ja]=KAB KDE2 インポート/プラグイン
-Name[ka]=KAB KDE2-ს ექსპორტის მოდული
Name[kk]=KDE2 пішімінен импорт ету
Name[km]=កម្មវិធី​ជំនួយ KAB KDE2 XXPort
Name[lt]=KAB KDE2 XXPort priedas
@@ -73,7 +72,6 @@ Comment[hu]=Bővítőmodul KDE2-es címjegyzék importálásához
Comment[is]=Íforrit til að færa inn gömlu KDE2 vistfangaskrána
Comment[it]=Plugin per importare le vecchie voci della rubrica di KDE2
Comment[ja]=古い KDE 2 アドレス帳をインポートするプラグイン
-Comment[ka]=ძველი KDE2-ს წიგნაკის იმპორტის მოდული
Comment[kk]=Ескі KDE2 адр.кітапшасынан импорт ету модулі
Comment[km]=កម្មវិធី​ជំនួយ​ដើម្បី​នាំចូល​សៀវភៅ​អាសយដ្ឋាន KDE 2 ចាស់ៗ
Comment[lt]=Priedas senosios KDE 2 adresų knygelės importui
@@ -97,8 +95,7 @@ Comment[ta]=பழைய KDE 2 கேமுகவரிபுத்தகத்
Comment[tg]=Модул барои воридоти файлҳои китобиадресии KDE2
Comment[tr]=KDE 2 adres defteri bilgilerini alma eklentisi
Comment[uk]=Втулок для імпорту адресної книги старого формату часів KDE 2
-Comment[uz]=Eski KDE 2 manzillar daftarini import qilish uchun plagin
-Comment[uz@cyrillic]=Эски KDE 2 манзиллар дафтарини импорт қилиш учун плагин
+Comment[uz]=Эски KDE 2 манзиллар дафтарини импорт қилиш учун плагин
Comment[zh_CN]=导入旧的 KDE 2 地址簿的插件
Comment[zh_TW]=匯入舊的 KDE2 通訊錄的外掛程式
Type=Service
diff --git a/kaddressbook/xxport/ldif_xxport.cpp b/kaddressbook/xxport/ldif_xxport.cpp
index d632d449b..92143c7e2 100644
--- a/kaddressbook/xxport/ldif_xxport.cpp
+++ b/kaddressbook/xxport/ldif_xxport.cpp
@@ -96,6 +96,12 @@ bool LDIFXXPort::exportContacts( const KABC::AddresseeList &list, const TQString
if ( url.isEmpty() )
return true;
+ if( TQFileInfo(url.path()).exists() ) {
+ if(KMessageBox::questionYesNo( parentWidget(), i18n("Do you want to overwrite file \"%1\"").arg( url.path()) ) == KMessageBox::No)
+ return false;
+ }
+
+
if ( !url.isLocalFile() ) {
KTempFile tmpFile;
if ( tmpFile.status() != 0 ) {
diff --git a/kaddressbook/xxport/ldif_xxport.desktop b/kaddressbook/xxport/ldif_xxport.desktop
index abdc10958..1274b4d86 100644
--- a/kaddressbook/xxport/ldif_xxport.desktop
+++ b/kaddressbook/xxport/ldif_xxport.desktop
@@ -25,7 +25,6 @@ Name[hi]=केएबी एलडीआईएफ XXपोर्ट प्लग
Name[hu]=KAB LDIF XXPort bővítőmodul
Name[is]=Íforrit fyrir KAB LDIF XXPort
Name[ja]=KAB LDIF インポート/エクスポートプラグイン
-Name[ka]=KAB LDIF-ის ექსპორტის მოდული
Name[kk]=LDIF пішіміне экспорт/импорт ету
Name[km]=កម្មវិធី​ជំនួយ KAB LDIF XXPort
Name[lt]=KAB LDIF XXPort priedas
@@ -74,7 +73,6 @@ Comment[hu]=Bővítőmodul Netscape és Mozilla LDIF formátumú névjegyek impo
Comment[is]=Íforrit sem flytur flytja inn eða út tengiliði í Netscape og Mozilla LDIF sniði
Comment[it]=Plugin per importare ed esportare contatti in formato Netscape e Mozilla LDIF
Comment[ja]=Netscape と Mozilla の LDIF フォーマットで連絡先をインポート/エクスポートするプラグイン
-Comment[ka]= Netscape-სა და Mozilla-ს კონტაქტების იმპორტ/ექსპორტის მოდული LDIF ფორმატით
Comment[kk]=Netscape пен Mozilla LDIF пішіміне экспорт/импорт ету модулі
Comment[km]=កម្មវិធី​ជំនួយ​ដើម្បី​នាំចូល និង​នាំចេញ​ទំនាក់ទំនង​ក្នុង​ទ្រង់ទ្រាយ​ជា Netscape និង Mozilla LDIF
Comment[lt]=Priedas, skirtas kontaktų importavimui ir eksportavimui Netscape ir Mozilla LDIFF formatu
diff --git a/kaddressbook/xxport/opera_xxport.desktop b/kaddressbook/xxport/opera_xxport.desktop
index ddbcff7bf..c1d3c2002 100644
--- a/kaddressbook/xxport/opera_xxport.desktop
+++ b/kaddressbook/xxport/opera_xxport.desktop
@@ -24,7 +24,6 @@ Name[hi]=केएबी ऑपेरा XXपोर्ट प्लगइन
Name[hu]=KAB Opera XXPort bővítőmodul
Name[is]=Íforrit fyrir KAP Opera XXPort
Name[ja]=KAB Opera インポート/エクスポートプラグイン
-Name[ka]=KAB Opera-ს ექსპორტის მოდული
Name[kk]=Opera пішіміне экспорт/импорт ету
Name[km]=កម្មវិធី​ជំនួយ KAB Opera XXPort
Name[lt]=KAB Opera XXPort priedas
@@ -72,7 +71,6 @@ Comment[hu]=Bővítőmodul Opera névjegyek importálásához
Comment[is]=Íforrit til flytja inn eða út Opera tengiliði
Comment[it]=Plugin per importare contatti da Opera
Comment[ja]=Opera の連絡先をインポートするプラグイン
-Comment[ka]=Opera-ს კონტაქტების იმპორტის მოდული
Comment[kk]=Opera контактарын экспорт/импорт ету модулі
Comment[km]=កម្មវិធី​ជំនួយ​ដើម្បី​នាំចូល​ទំនាក់ទំនង​របស់ Opera
Comment[lt]=Priedas Opera kontaktų importui
diff --git a/kaddressbook/xxport/pab_xxport.desktop b/kaddressbook/xxport/pab_xxport.desktop
index e35ad24d4..c0af8e3d6 100644
--- a/kaddressbook/xxport/pab_xxport.desktop
+++ b/kaddressbook/xxport/pab_xxport.desktop
@@ -23,7 +23,6 @@ Name[hi]=केएबी एमएस एक्सचेंज निजी प
Name[hu]=KAB XXPort bővítőmodul MS Exchange személyes címjegyzékekhez
Name[is]=Íforrit fyrir KAB MS Exchange Personal Addressbook XXPort
Name[ja]=KAB MS Exchange パーソナルアドレス帳インポート/エクスポートプラグイン
-Name[ka]= MS Exchange-ის პერსონალური წიგნაკის ექსპორტის მოდული
Name[kk]=MS Exchange адрестік кітапшасына экспорт/импорт ету
Name[km]=កម្មវិធី​ជំនួយ KAB MS Exchange Personal Addressbook XXPort
Name[lt]=KAB MS Exchange asmeninės adresų knygelės XXPort priedas
@@ -72,7 +71,6 @@ Comment[hu]=Bővítőmodul MS Exchange személyes címjegyzékek importálásáh
Comment[is]=Íforrit til að flytja tengiliði í eða úr MS Exchange Personal Address Book
Comment[it]=Plugin per importare rubriche personali da MS Exchange
Comment[ja]=MS Exchange パーソナルアドレス帳をインポートするプラグイン
-Comment[ka]=MS Exchange-ის პერსონალური წიგნაკის იმპორტის მოდული
Comment[kk]=MS Exchange адрестік кітапшасына экспорт/импорт ету модулі
Comment[km]=កម្មវិធី​ជំនួយ​ដើម្បី​នាំចូល​សៀវភៅ​អាសយដ្ឋាន​ផ្ទាល់​ខ្លួន​របស់ MS Exchange
Comment[lt]=Priedas leidžiantis importuoti MS Exchange asmenines adresų knygeles
diff --git a/kaddressbook/xxport/vcard_xxport.cpp b/kaddressbook/xxport/vcard_xxport.cpp
index 85cf8c763..1dfc9bcc4 100644
--- a/kaddressbook/xxport/vcard_xxport.cpp
+++ b/kaddressbook/xxport/vcard_xxport.cpp
@@ -118,9 +118,15 @@ bool VCardXXPort::exportContacts( const KABC::AddresseeList &addrList, const TQS
return true;
if ( data == "v21" )
+#if defined(KABC_VCARD_ENCODING_FIX)
+ ok = doExport( url, converter.createVCardsRaw( list, KABC::VCardConverter::v2_1 ) );
+ else
+ ok = doExport( url, converter.createVCardsRaw( list, KABC::VCardConverter::v3_0 ) );
+#else
ok = doExport( url, converter.createVCards( list, KABC::VCardConverter::v2_1 ) );
else
ok = doExport( url, converter.createVCards( list, KABC::VCardConverter::v3_0 ) );
+#endif
} else {
TQString msg = i18n( "You have selected a list of contacts, shall they be "
"exported to several files?" );
@@ -151,10 +157,15 @@ bool VCardXXPort::exportContacts( const KABC::AddresseeList &addrList, const TQS
tmpList.append( *it );
if ( data == "v21" )
+#if defined(KABC_VCARD_ENCODING_FIX)
+ tmpOk = doExport( url, converter.createVCardsRaw( tmpList, KABC::VCardConverter::v2_1 ) );
+ else
+ tmpOk = doExport( url, converter.createVCardsRaw( tmpList, KABC::VCardConverter::v3_0 ) );
+#else
tmpOk = doExport( url, converter.createVCards( tmpList, KABC::VCardConverter::v2_1 ) );
else
tmpOk = doExport( url, converter.createVCards( tmpList, KABC::VCardConverter::v3_0 ) );
-
+#endif
ok = ok && tmpOk;
}
break;
@@ -166,9 +177,15 @@ bool VCardXXPort::exportContacts( const KABC::AddresseeList &addrList, const TQS
return true;
if ( data == "v21" )
+#if defined(KABC_VCARD_ENCODING_FIX)
+ ok = doExport( url, converter.createVCardsRaw( list, KABC::VCardConverter::v2_1 ) );
+ else
+ ok = doExport( url, converter.createVCardsRaw( list, KABC::VCardConverter::v3_0 ) );
+#else
ok = doExport( url, converter.createVCards( list, KABC::VCardConverter::v2_1 ) );
else
ok = doExport( url, converter.createVCards( list, KABC::VCardConverter::v3_0 ) );
+#endif
}
}
}
@@ -182,9 +199,14 @@ KABC::AddresseeList VCardXXPort::importContacts( const TQString& ) const
KABC::AddresseeList addrList;
KURL::List urls;
- if ( !XXPortManager::importData.isEmpty() )
+ if ( !XXPortManager::importData.isEmpty() ) {
+#if defined(KABC_VCARD_ENCODING_FIX)
+ TQCString data = XXPortManager::importData.ascii();
+ addrList = parseVCard( data );
+#else
addrList = parseVCard( XXPortManager::importData );
- else {
+#endif
+ } else {
if ( XXPortManager::importURL.isEmpty() )
urls = KFileDialog::getOpenURLs( TQString::null, "*.vcf|vCards", parentWidget(),
i18n( "Select vCard to Import" ) );
@@ -203,11 +225,28 @@ KABC::AddresseeList VCardXXPort::importContacts( const TQString& ) const
TQFile file( fileName );
if ( file.open( IO_ReadOnly ) ) {
+#if defined(KABC_VCARD_ENCODING_FIX)
+ TQByteArray data = file.readAll();
+ file.close();
+ if ( data.size() > 0 )
+ addrList += parseVCard( data );
+#else
TQByteArray rawData = file.readAll();
file.close();
- if ( rawData.size() > 0 )
- addrList += parseVCard( rawData );
-
+ if ( rawData.size() > 0 ) {
+
+ TQString vCardText;
+
+ // With version 3.0, vCards are encoded with UTF-8 by default. Otherwise, use fromLatin1()
+ // and hope that are fields are encoded correctly.
+ if ( TQString::fromLatin1( rawData ).lower().contains( "version:3.0" ) ) {
+ vCardText = TQString::fromUtf8( rawData );
+ } else {
+ vCardText = TQString::fromLatin1( rawData );
+ }
+ addrList += parseVCard( vCardText );
+ }
+#endif
KIO::NetAccess::removeTempFile( fileName );
} else {
TQString text = i18n( "<qt>When trying to read the vCard, there was an error opening the file '%1': %2</qt>" );
@@ -243,6 +282,29 @@ KABC::AddresseeList VCardXXPort::importContacts( const TQString& ) const
return addrList;
}
+#if defined(KABC_VCARD_ENCODING_FIX)
+KABC::AddresseeList VCardXXPort::parseVCard( const TQByteArray &data ) const
+{
+ KABC::VCardConverter converter;
+
+ return converter.parseVCardsRaw( data.data() );
+}
+
+bool VCardXXPort::doExport( const KURL &url, const TQByteArray &data )
+{
+ if( TQFileInfo(url.path()).exists() ) {
+ if(KMessageBox::questionYesNo( parentWidget(), i18n("Do you want to overwrite file \"%1\"").arg( url.path()) ) == KMessageBox::No)
+ return false;
+ }
+ KTempFile tmpFile;
+ tmpFile.setAutoDelete( true );
+
+ tmpFile.file()->writeBlock( data.data(), data.size() );
+ tmpFile.close();
+
+ return KIO::NetAccess::upload( tmpFile.name(), url, parentWidget() );
+}
+#else
KABC::AddresseeList VCardXXPort::parseVCard( const TQString &data ) const
{
KABC::VCardConverter converter;
@@ -252,6 +314,10 @@ KABC::AddresseeList VCardXXPort::parseVCard( const TQString &data ) const
bool VCardXXPort::doExport( const KURL &url, const TQString &data )
{
+ if( TQFileInfo(url.path()).exists() ) {
+ if(KMessageBox::questionYesNo( parentWidget(), i18n("Do you want to overwrite file \"%1\"").arg( url.path()) ) == KMessageBox::No)
+ return false;
+ }
KTempFile tmpFile;
tmpFile.setAutoDelete( true );
@@ -263,6 +329,7 @@ bool VCardXXPort::doExport( const KURL &url, const TQString &data )
return KIO::NetAccess::upload( tmpFile.name(), url, parentWidget() );
}
+#endif
KABC::AddresseeList VCardXXPort::filterContacts( const KABC::AddresseeList &addrList )
{
diff --git a/kaddressbook/xxport/vcard_xxport.desktop b/kaddressbook/xxport/vcard_xxport.desktop
index d0a0146a2..0745d5a52 100644
--- a/kaddressbook/xxport/vcard_xxport.desktop
+++ b/kaddressbook/xxport/vcard_xxport.desktop
@@ -25,7 +25,6 @@ Name[hi]=केएबी वी-कार्डXXपोर्ट प्लगइ
Name[hu]=KAB vCard XXPort bővítőmodul
Name[is]=Íforrit fyrir KAB vCard XXPort
Name[ja]=KAB vCazrd インポート/エクスポートプラグイン
-Name[ka]=KAB vCard ექსპორტის მოდული
Name[kk]=vCard-ты экспорт/импорт ету
Name[km]=កម្មវិធី​ជំនួយ KAB vCard XXPort
Name[lt]=KAB vCard XXPort priedas
@@ -74,7 +73,6 @@ Comment[hu]=Bővítőmodul vCard névjegyek importálásához/exportálásához
Comment[is]=Íforrit til að flytja inn eða út tengiliði í vCard sniði
Comment[it]=Plugin per importare ed esportare contatti in formato vCard
Comment[ja]=vCard フォーマットで連絡先をインポート/エクスポートするプラグイン
-Comment[ka]=კონტაქტების vCard-ის ფორმატით იმპორტ/ექსპორტის მოდული
Comment[kk]=vCard пішіміне экспорт/импорт ету модулі
Comment[km]=កម្មវិធី​ជំនួយ​ដើម្បី​នាំចូល និង​នាំចេញ​ទំនាក់ទំនង​ក្នុង​ទ្រង់ទ្រាយ​ជា vCard
Comment[lt]=Įskiepis kontaktų importavimui ir eksportavimui vCard formatu
diff --git a/kaddressbook/xxport/vcard_xxport.h b/kaddressbook/xxport/vcard_xxport.h
index 8208e23c6..191d37a39 100644
--- a/kaddressbook/xxport/vcard_xxport.h
+++ b/kaddressbook/xxport/vcard_xxport.h
@@ -25,6 +25,7 @@
#define VCARD_XXPORT_H
#include <xxport.h>
+#include <kabc/vcardparser.h> // for KABC_VCARD_ENCODING_FIX define
class VCardXXPort : public KAB::XXPort
{
@@ -40,8 +41,13 @@ class VCardXXPort : public KAB::XXPort
KABC::AddresseeList importContacts( const TQString &data ) const;
private:
- KABC::AddresseeList parseVCard( const TQString &data ) const;
- bool doExport( const KURL &url, const TQString &data );
+#if defined(KABC_VCARD_ENCODING_FIX)
+ KABC::AddresseeList parseVCard( const TQByteArray &data ) const;
+ bool doExport( const KURL &url, const TQByteArray &data );
+#else
+ KABC::AddresseeList parseVCard( const TQString &data ) const;
+ bool doExport( const KURL &url, const TQString &data );
+#endif
void addKey( KABC::Addressee &addr, KABC::Key::Types type );
KABC::AddresseeList filterContacts( const KABC::AddresseeList& );
diff --git a/kaddressbook/xxportmanager.cpp b/kaddressbook/xxportmanager.cpp
index c46855c47..aee87fd46 100644
--- a/kaddressbook/xxportmanager.cpp
+++ b/kaddressbook/xxportmanager.cpp
@@ -39,7 +39,7 @@
#include "xxportmanager.h"
KURL XXPortManager::importURL = KURL();
-TQString XXPortManager::importData = TQString::null;
+TQString XXPortManager::importData = TQString();
XXPortManager::XXPortManager( KAB::Core *core, TQObject *parent, const char *name )
: TQObject( parent, name ), mCore( core )
diff --git a/kalarm/Changelog b/kalarm/Changelog
index 6c51c621e..a3a1c6590 100644
--- a/kalarm/Changelog
+++ b/kalarm/Changelog
@@ -1,6 +1,6 @@
KAlarm Change Log
-=== Version 1.5.5 --- 21 January 2009 ===
+=== Version 1.5.5 --- 9 January 2009 ===
- Require a real double click to accept the selected template in pick list.
- Make mouse wheel work, and fix highlighting, for left-hand time spinbox
buttons in Plastik style.
@@ -15,7 +15,6 @@ KAlarm Change Log
- Ignore events in calendar without usable alarms, which prevents them getting
stuck in the alarm list).
- Prevent defer dialogue date being set outside the allowed range.
-- Cancel screensaver when an alarm is displayed.
=== Version 1.5.4 (KDE 3.5.10) --- 18 August 2008 ===
- Show background colour selector for file display alarms.
diff --git a/kalarm/alarmevent.cpp b/kalarm/alarmevent.cpp
index 8aa898922..34ce46a29 100644
--- a/kalarm/alarmevent.cpp
+++ b/kalarm/alarmevent.cpp
@@ -2427,7 +2427,7 @@ KARecurrence::Type KAEvent::checkRecur() const
KARecurrence::Type type = mRecurrence->type();
switch (type)
{
- case KARecurrence::MINUTELY: // hourly
+ case KARecurrence::MINUTELY: // hourly
case KARecurrence::DAILY: // daily
case KARecurrence::WEEKLY: // weekly on multiple days of week
case KARecurrence::MONTHLY_DAY: // monthly on multiple dates in month
@@ -2776,7 +2776,7 @@ void KAEvent::convertKCalEvents(KCal::Calendar& calendar, int version, bool adju
if (types.count() > 0)
alarm->setCustomProperty(APPNAME, TYPE_PROPERTY, types.join(","));
- if (pre_0_7 && alarm->repeatCount() > 0 && alarm->snoozeTime() > 0)
+ if (pre_0_7 && alarm->repeatCount() > 0 && alarm->snoozeTime().value() > 0)
{
// It's a KAlarm pre-0.7 calendar file.
// Minutely recurrences were stored differently.
@@ -3028,7 +3028,7 @@ void KAEvent::convertKCalEvents(KCal::Calendar& calendar, int version, bool adju
}
}
}
-
+
if (pre_1_5_0)
{
/*
@@ -3087,7 +3087,7 @@ bool KAEvent::convertRepetition(KCal::Event* event)
for (Alarm::List::ConstIterator alit = alarms.begin(); alit != alarms.end(); ++alit)
{
Alarm* alarm = *alit;
- if (alarm->repeatCount() > 0 && alarm->snoozeTime() > 0)
+ if (alarm->repeatCount() > 0 && alarm->snoozeTime().value() > 0)
{
if (!converted)
{
diff --git a/kalarm/functions.cpp b/kalarm/functions.cpp
index 45537e3d9..28f73499d 100644
--- a/kalarm/functions.cpp
+++ b/kalarm/functions.cpp
@@ -71,9 +71,6 @@ bool sendToKOrganizer(const KAEvent&);
bool deleteFromKOrganizer(const TQString& eventID);
bool runKOrganizer();
}
-#ifdef HAVE_XTEST
-void x11_cancelScreenSaver();
-#endif
namespace KAlarm
@@ -931,17 +928,6 @@ TQString stripAccel(const TQString& text)
return out;
}
-/******************************************************************************
-* Cancel the screen saver, in case it is active.
-* Only implemented if the X11 XTest extension is installed.
-*/
-void cancelScreenSaver()
-{
-#ifdef HAVE_XTEST
- x11_cancelScreenSaver();
-#endif // HAVE_XTEST
-}
-
} // namespace KAlarm
diff --git a/kalarm/functions.h b/kalarm/functions.h
index 762aecc6e..37041f6f2 100644
--- a/kalarm/functions.h
+++ b/kalarm/functions.h
@@ -108,7 +108,6 @@ UpdateStatus enableEvent(KAEvent&, AlarmListView* selectionView, bool ena
void displayUpdateError(TQWidget* parent, UpdateStatus, UpdateError, int nAlarms);
void displayKOrgUpdateError(TQWidget* parent, KOrgUpdateError, int nAlarms);
-void cancelScreenSaver();
TQString stripAccel(const TQString&);
int localeFirstDayOfWeek();
diff --git a/kalarm/kalarm.desktop b/kalarm/kalarm.desktop
index da42c9113..8724fb64c 100644
--- a/kalarm/kalarm.desktop
+++ b/kalarm/kalarm.desktop
@@ -44,7 +44,6 @@ GenericName[hu]=Emlékeztetőkezelő
GenericName[is]=Áminningakerfi
GenericName[it]=Programmatore degli avvisi personali
GenericName[ja]=個人アラームスケジューラ
-GenericName[ka]=პერსონალური მაღვიძარას მგეგმავი
GenericName[kk]=Дербес ескертулер жоспарлағышы
GenericName[km]=កម្មវិធី​កំណត់​ម៉ោង​រោទ៍​ផ្ទាល់​ខ្លួន
GenericName[lt]=Asmeninių žinučių-priminimų planuoklis
diff --git a/kalarm/kalarm.tray.desktop b/kalarm/kalarm.tray.desktop
index d161dc67e..a15aa26bb 100644
--- a/kalarm/kalarm.tray.desktop
+++ b/kalarm/kalarm.tray.desktop
@@ -34,7 +34,7 @@ Comment[et]=Häirete ja meeldetuletuste ajakava: käivitamine süsteemse doki ik
Comment[eu]=Alarma pertsonalen programatzailea: abiatu sistemaren bandejako ikono bezala
Comment[fa]=زمان‌بند هشدار شخصی: آغاز به عنوان شمایل سینی سیستم
Comment[fi]=Henkilökohtainen hälytysajastin: käynnistä paneelikuvake
-Comment[fr]=Planificateur d'alarme personnel : démarre dans la boîte à miniatures
+Comment[fr]=Planificateur d'alarme personnel : démarre dans la boîte à miniatures
Comment[fy]=Persoanlike alarmplanner: begjinne yn it systeemfak
Comment[gl]=Programador persoal de alarmas: iniciar como icona na bandexa do sistema
Comment[he]=מתזמן הודעות תזכורת: הפעלה בתור סמל במגש המערכת
@@ -43,7 +43,6 @@ Comment[hu]=Az emlékeztető üzenetek megjelenítőprogramja: indítás a panel
Comment[is]=Áminningakerfi: ræsir sem táknmynd á spjaldinu
Comment[it]=Programmatore personale degli avvisi: all'avvio si mette nel vassoio di sistema
Comment[ja]=個人アラームスケジューラ: システムトレイアイコンで起動
-Comment[ka]=პესონალური მაღვიძარას მგეგმავი: სისტემურ პანელის ხატულად იწყება
Comment[kk]=Дербес ескертулер жоспарлағышы: жүйелік сөреде орналасады
Comment[km]=កម្មវិធី​កំណត់​ម៉ោង​រោទ៍​ផ្ទាល់​ខ្លួន ៖ ចាប់ផ្ដើម​ជា​រូបតំណាង​ក្នុង​ថាស​ប្រព័ន្ធ
Comment[lt]=Žinučių-priminimų planuoklis: paleisti kaip sisteminio dėklo ženkliuką
diff --git a/kalarm/kalarmapp.cpp b/kalarm/kalarmapp.cpp
index f4daec9c2..7607892db 100644
--- a/kalarm/kalarmapp.cpp
+++ b/kalarm/kalarmapp.cpp
@@ -1631,13 +1631,11 @@ void* KAlarmApp::execAlarm(KAEvent& event, const KAAlarm& alarm, bool reschedule
if (win)
win->setRecreating(); // prevent post-alarm actions
delete win;
- KAlarm::cancelScreenSaver();
(new MessageWin(event, alarm, reschedule, allowDefer))->show();
}
else
{
// Raise the existing message window and replay any sound
- KAlarm::cancelScreenSaver();
win->repeat(alarm); // N.B. this reschedules the alarm
}
break;
diff --git a/kalarm/kalarmd/kalarmd.autostart.desktop b/kalarm/kalarmd/kalarmd.autostart.desktop
index de5add486..c2ea7d569 100644
--- a/kalarm/kalarmd/kalarmd.autostart.desktop
+++ b/kalarm/kalarmd/kalarmd.autostart.desktop
@@ -23,7 +23,6 @@ Name[hu]=KAlarm szolgáltatás
Name[is]=KAlarm þjónn
Name[it]=Demone degli avvisi
Name[ja]=KAlarm デーモン
-Name[ka]=KAlarm დემონი
Name[kk]=KAlarm қызметі
Name[km]=ដេមិន KAlarm
Name[lt]=KAlarm tarnyba
@@ -71,7 +70,6 @@ Comment[hu]=A KAlarm emlékeztető szolgáltatás automatikus elindítása
Comment[is]=Ræsa KAlarm áminningaþjónn sjálfkrafa við byrjun setu
Comment[it]=Avvio automatico del demone degli avvisi
Comment[ja]=KAlarm アラームデーモンのログイン時の自動起動
-Comment[ka]=KAlarm მაღვიძარას დემონის ავტოდაწყება შესვლისას
Comment[kk]=KAlarm қызметі жүйеге кіргенде жегіледі
Comment[km]=ចាប់ផ្ដើម​ដេមិន​រោទ៍​របស់ KAlarm ពេល​ចូល
Comment[lt]=KOrganizer/KAlarm priminimų tarnybos automatinis paleidimas prisiregistruojant
diff --git a/kalarm/kalarmd/kalarmd.desktop b/kalarm/kalarmd/kalarmd.desktop
index 31d3a0fa7..6b4817182 100644
--- a/kalarm/kalarmd/kalarmd.desktop
+++ b/kalarm/kalarmd/kalarmd.desktop
@@ -23,7 +23,6 @@ Name[hu]=KAlarm szolgáltatás
Name[is]=KAlarm þjónn
Name[it]=Demone degli avvisi
Name[ja]=KAlarm デーモン
-Name[ka]=KAlarm დემონი
Name[kk]=KAlarm қызметі
Name[km]=ដេមិន KAlarm
Name[lt]=KAlarm tarnyba
diff --git a/kandy/src/kandy.desktop b/kandy/src/kandy.desktop
index b003dd045..d1357a92b 100644
--- a/kandy/src/kandy.desktop
+++ b/kandy/src/kandy.desktop
@@ -24,7 +24,6 @@ Comment[hu]=Segédprogram számítógép és mobiltelefon címjegyzékének szin
Comment[is]=Tól sem samstillir vistfangagögn við farsíma
Comment[it]=Strumento per sincronizzare i dati della rubrica indirizzi con i telefoni cellulari
Comment[ja]=アドレス帳のデータを携帯電話と同期するためのツール
-Comment[ka]=მობილურ ტელეფონთან წიგნაკის მონაცემების სინქრონიზაციის ხელსაწყო
Comment[kk]=Адрестік кітапшаны қалта телефонмен қадамдастыру құралы
Comment[km]=ឧបករណ៍​សម្រាប់​ធ្វើ​សមកាលកម្ម​ទិន្នន័យ​សៀវភៅ​អាសយដ្ឋាន​ជាមួយ​នឹង​ទូរស័ព្ទ​ចល័ត
Comment[lt]=Įrankis adresų knygelės sinchronizavimui su mobiliaisiais telefonais
@@ -79,7 +78,6 @@ GenericName[hu]=Mobil-címjegyzék
GenericName[is]=Farsímatól
GenericName[it]=Strumento per i telefoni cellulari
GenericName[ja]=携帯電話ツール
-GenericName[ka]=მობილურ ტელეფონთან სამუშაო ხელსაწყო
GenericName[kk]=Қалта телефон құралы
GenericName[km]=ឧបករណ៍​ទូរស័ព្ទ​ចល័ត
GenericName[lt]=Mobilaus telefono įrankis
@@ -108,8 +106,7 @@ GenericName[tg]=Кор бо телефони мобилӣ
GenericName[th]=เครื่องมือสำหรับโทรศัพท์เคลื่อนที่
GenericName[tr]=Cep Telefonu Aracı
GenericName[uk]=Засіб для мобільних телефонів
-GenericName[uz]=Uyali telefon uchun vosita
-GenericName[uz@cyrillic]=Уяли телефон учун восита
+GenericName[uz]=Уяли телефон учун восита
GenericName[ven]=Tshishumiswa tsha lutingo thendeleki
GenericName[vi]=Công cụ điện thoại di động
GenericName[xh]=Isixhobo Semfono-mfono Ekuhanjwa nayo
diff --git a/karm/support/karm.desktop b/karm/support/karm.desktop
index 66b016af2..736f497ce 100644
--- a/karm/support/karm.desktop
+++ b/karm/support/karm.desktop
@@ -33,7 +33,6 @@ GenericName[hu]=Időfelhasználás-figyelő
GenericName[id]=Tracker Waktu Pribadi
GenericName[is]=Fylgjast með í hvað tíminn fer
GenericName[it]=Segnatempo personale
-GenericName[ka]=პერსონალური დროის აღმრიცხველი
GenericName[kk]=Дербес уақыт қадағалағышы
GenericName[km]=កម្មវិធី​តាមដាន​ពេលវេលា​ផ្ទាល់​ខ្លួន
GenericName[ko]=일하는 시간을 잴 수 있습니다
diff --git a/karm/task.cpp b/karm/task.cpp
index 5ade426f0..7d84bcd2c 100644
--- a/karm/task.cpp
+++ b/karm/task.cpp
@@ -183,12 +183,12 @@ void Task::setPercentComplete(const int percent, KarmStorage *storage)
void Task::setPixmapProgress()
{
- TQPixmap* icon = new TQPixmap();
+ TQPixmap icon ;
if (_percentcomplete >= 100)
- *icon = UserIcon("task-complete.xpm");
+ icon = UserIcon("task-complete.xpm");
else
- *icon = UserIcon("task-incomplete.xpm");
- setPixmap(0, *icon);
+ icon = UserIcon("task-incomplete.xpm");
+ setPixmap(0, icon);
}
bool Task::isComplete() { return _percentcomplete == 100; }
diff --git a/kfile-plugins/ics/kfile_ics.desktop b/kfile-plugins/ics/kfile_ics.desktop
index 2a530ce21..ce3f2188a 100644
--- a/kfile-plugins/ics/kfile_ics.desktop
+++ b/kfile-plugins/ics/kfile_ics.desktop
@@ -24,7 +24,6 @@ Name[hu]=ICS-jellemzők
Name[is]=ICS upplýsingar
Name[it]=Informazioni ICS
Name[ja]=ICS 情報
-Name[ka]=ICS ინფორმაცია
Name[kk]=ICS ақпараты
Name[km]=ព័ត៌មាន ICS
Name[lt]=ICS informacija
diff --git a/kfile-plugins/palm-databases/kfile_palm.desktop b/kfile-plugins/palm-databases/kfile_palm.desktop
index 9d1fe121d..66ccbfe90 100644
--- a/kfile-plugins/palm-databases/kfile_palm.desktop
+++ b/kfile-plugins/palm-databases/kfile_palm.desktop
@@ -26,7 +26,6 @@ Name[hu]=PalmOS adatbázis-jellemzők
Name[is]=PalmOS gagnagrunnsupplýsingar
Name[it]=Informazioni database PalmOs
Name[ja]=PalmOS データベース 情報
-Name[ka]=PalmOS-ს მონაცემთა ბაზის ინფორმაცია
Name[kk]=PalmOS деректер қорының мәліметі
Name[km]=ព័ត៌មាន​មូលដ្ឋាន​ទិន្នន័យ PalmOS
Name[lt]=PalmOS duomenų bazės info
diff --git a/kfile-plugins/rfc822/kfile_rfc822.desktop b/kfile-plugins/rfc822/kfile_rfc822.desktop
index 1428c96f8..b6928cfdb 100644
--- a/kfile-plugins/rfc822/kfile_rfc822.desktop
+++ b/kfile-plugins/rfc822/kfile_rfc822.desktop
@@ -27,7 +27,6 @@ Name[hu]=E-mail-jellemzők
Name[is]=Tölvupóst upplýsingar
Name[it]=Informazioni di posta elettronica
Name[ja]=Eメール 情報
-Name[ka]=ელფოსტის ინფორმაცია
Name[kk]=Эл.пошта мәліметі
Name[km]=ព័ត៌មាន​អ៊ីមែល
Name[lt]=E. pašto info
diff --git a/kfile-plugins/vcf/kfile_vcf.cpp b/kfile-plugins/vcf/kfile_vcf.cpp
index 76b3383c6..5dcfc2c17 100644
--- a/kfile-plugins/vcf/kfile_vcf.cpp
+++ b/kfile-plugins/vcf/kfile_vcf.cpp
@@ -68,8 +68,11 @@ bool KVcfPlugin::readInfo( KFileMetaInfo& info, uint /*what*/ )
file.close();
KABC::VCardConverter converter;
- KABC::Addressee addr = converter.parseVCard(contents);
-
+#if defined(KABC_VCARD_ENCODING_FIX)
+ KABC::Addressee addr = converter.parseVCardRaw( contents.utf8() );
+#else
+ KABC::Addressee addr = converter.parseVCard( contents );
+#endif
KFileMetaInfoGroup group = appendGroup(info, "Technical");
// prepare the text
diff --git a/kfile-plugins/vcf/kfile_vcf.desktop b/kfile-plugins/vcf/kfile_vcf.desktop
index ced0dfc34..4d1c5b4b3 100644
--- a/kfile-plugins/vcf/kfile_vcf.desktop
+++ b/kfile-plugins/vcf/kfile_vcf.desktop
@@ -26,7 +26,6 @@ Name[hu]=VCard-jellemzők
Name[is]=vCard upplýsingar
Name[it]=Informazioni vCard
Name[ja]=vCard 情報
-Name[ka]=vCard ინფორმაცია
Name[kk]=vCard мәліметі
Name[km]=ព័ត៌មាន vCard
Name[lt]=vCard informacija
diff --git a/kioslaves/imap4/imap4.cc b/kioslaves/imap4/imap4.cc
index 1cfd56027..2290c6787 100644
--- a/kioslaves/imap4/imap4.cc
+++ b/kioslaves/imap4/imap4.cc
@@ -1780,14 +1780,15 @@ IMAP4Protocol::rename (const KURL & src, const KURL & dest, bool overwrite)
completeQueue.removeRef(cmd);
if (!ok)
{
- error(ERR_CANNOT_RENAME, i18n("Unable to close mailbox."));
+ kdWarning(7116) << "Unable to close mailbox!" << endl;
+ error(ERR_CANNOT_RENAME, src.path());
return;
}
setState(ISTATE_LOGIN);
}
imapCommand *cmd = doCommand (imapCommand::clientRename (sBox, dBox));
if (cmd->result () != "OK") {
- error (ERR_CANNOT_RENAME, cmd->result ());
+ error (ERR_CANNOT_RENAME, src.path());
completeQueue.removeRef (cmd);
return;
}
@@ -1798,13 +1799,13 @@ IMAP4Protocol::rename (const KURL & src, const KURL & dest, bool overwrite)
case ITYPE_MSG:
case ITYPE_ATTACH:
case ITYPE_UNKNOWN:
- error (ERR_CANNOT_RENAME, src.prettyURL());
+ error (ERR_CANNOT_RENAME, src.path());
break;
}
}
else
{
- error (ERR_CANNOT_RENAME, src.prettyURL());
+ error (ERR_CANNOT_RENAME, src.path());
return;
}
finished ();
@@ -2111,6 +2112,18 @@ bool IMAP4Protocol::makeLogin ()
removeCapability( "ANNOTATEMORE" );
}
+ // starting from Cyrus IMAP 2.3.9, shared seen flags are available
+ TQRegExp regExp( "Cyrus\\sIMAP[4]{0,1}\\sv(\\d+)\\.(\\d+)\\.(\\d+)", false );
+ if ( regExp.search( greeting ) >= 0 ) {
+ const int major = regExp.cap( 1 ).toInt();
+ const int minor = regExp.cap( 2 ).toInt();
+ const int patch = regExp.cap( 3 ).toInt();
+ if ( major > 2 || (major == 2 && (minor > 3 || (minor == 3 && patch > 9))) ) {
+ kdDebug(7116) << k_funcinfo << "Cyrus IMAP >= 2.3.9 detected, enabling shared seen flag support" << endl;
+ imapCapabilities.append( "x-kmail-sharedseen" );
+ }
+ }
+
kdDebug(7116) << "IMAP4::makeLogin - attempting login" << endl;
KIO::AuthInfo authInfo;
diff --git a/kioslaves/sieve/sieve.cpp b/kioslaves/sieve/sieve.cpp
index 9f3b547a2..bc7811662 100644
--- a/kioslaves/sieve/sieve.cpp
+++ b/kioslaves/sieve/sieve.cpp
@@ -39,6 +39,7 @@ extern "C" {
#include <kurl.h>
#include <kmdcodec.h>
#include <kglobal.h>
+#include <kmessagebox.h>
#include <tqcstring.h>
#include <tqregexp.h>
@@ -46,6 +47,7 @@ extern "C" {
#include <cstdlib>
using std::exit;
#include <sys/stat.h>
+#include <cassert>
#include <kdepimmacros.h>
@@ -193,6 +195,7 @@ kio_sieveProtocol::kio_sieveProtocol(const TQCString &pool_socket, const TQCStri
, m_connMode(NORMAL)
, m_supportsTLS(false)
, m_shouldBeConnected(false)
+ , m_allowUnencrypted(false)
{
}
@@ -274,7 +277,7 @@ bool kio_sieveProtocol::parseCapabilities(bool requestCapabilities/* = false*/)
setMetaData("tlsSupported", "true");
} else {
- ksDebug() << "Unrecognised key " << r.getKey() << endl;
+ ksDebug() << "Unrecognised key." << endl;
}
}
@@ -288,7 +291,7 @@ bool kio_sieveProtocol::parseCapabilities(bool requestCapabilities/* = false*/)
/* ---------------------------------------------------------------------------------- */
/**
- * Checks if connection parameters (currently - auth method) have changed.
+ * Checks if connection parameters have changed.
* If it it, close the current connection
*/
void kio_sieveProtocol::changeCheck( const KURL &url )
@@ -316,6 +319,14 @@ void kio_sieveProtocol::changeCheck( const KURL &url )
if ( isConnectionValid() )
disconnect();
}
+
+ // For TLS, only disconnect if we are unencrypted and are
+ // no longer allowed (otherwise, it's still fine):
+ const bool allowUnencryptedNow = url.queryItem("x-allow-unencrypted") == "true" ;
+ if ( m_allowUnencrypted && !allowUnencryptedNow )
+ if ( isConnectionValid() )
+ disconnect();
+ m_allowUnencrypted = allowUnencryptedNow;
}
/* ---------------------------------------------------------------------------------- */
@@ -349,8 +360,25 @@ bool kio_sieveProtocol::connect(bool useTLSIfAvailable)
}
// Attempt to start TLS
+ if ( !m_allowUnencrypted && !canUseTLS() ) {
+ error( ERR_SLAVE_DEFINED, i18n("Can not use TLS. Please enable TLS in the KDE cryptography setting.") );
+ disconnect();
+ return false;
+ }
+
+ if ( !m_allowUnencrypted && useTLSIfAvailable && canUseTLS() && !m_supportsTLS &&
+ messageBox( WarningContinueCancel,
+ i18n("TLS encryption was requested, but your Sieve server does not advertise TLS in its capabilities.\n"
+ "You can choose to try to initiate TLS negotiations nonetheless, or cancel the operation."),
+ i18n("Server Does Not Advertise TLS"), i18n("&Start TLS nonetheless"), i18n("&Cancel") ) != KMessageBox::Continue )
+ {
+ error( ERR_USER_CANCELED, i18n("TLS encryption requested, but not supported by server.") );
+ disconnect();
+ return false;
+ }
+
// FIXME find a test server and test that this works
- if (useTLSIfAvailable && m_supportsTLS && canUseTLS()) {
+ if (useTLSIfAvailable && canUseTLS()) {
sendData("STARTTLS");
if (operationSuccessful()) {
ksDebug() << "TLS has been accepted. Starting TLS..." << endl
@@ -362,15 +390,31 @@ bool kio_sieveProtocol::connect(bool useTLSIfAvailable)
parseCapabilities( requestCapabilitiesAfterStartTLS() );
} else {
ksDebug() << "TLS initiation failed, code " << retval << endl;
- disconnect(true);
- return connect(false);
- // error(ERR_INTERNAL, i18n("TLS initiation failed."));
+ if ( m_allowUnencrypted ) {
+ disconnect(true);
+ return connect(false);
+ }
+ if ( retval != -3 )
+ messageBox( Information,
+ i18n("Your Sieve server claims to support TLS, "
+ "but negotiation was unsuccessful."),
+ i18n("Connection Failed") );
+ disconnect(true);
+ return false;
}
+ } else if ( !m_allowUnencrypted ) {
+ ksDebug() << "Server incapable of TLS." << endl;
+ disconnect();
+ error( ERR_SLAVE_DEFINED, i18n("The server does not seem to support TLS. "
+ "Disable TLS if you want to connect without encryption.") );
+ return false;
} else
ksDebug() << "Server incapable of TLS. Transmitted documents will be unencrypted." << endl;
} else
ksDebug() << "We are incapable of TLS. Transmitted documents will be unencrypted." << endl;
+ assert( m_allowUnencrypted || usingTLS() );
+
infoMessage(i18n("Authenticating user..."));
if (!authenticate()) {
disconnect();
@@ -637,7 +681,7 @@ void kio_sieveProtocol::put(const KURL& url, int /*permissions*/, bool /*overwri
i18n("The script did not upload successfully.\n"
"This is probably due to errors in the script.\n"
"The server responded:\n%1").arg(r.getKey()));
- } else
+ } else
error(ERR_INTERNAL_SERVER,
i18n("The script did not upload successfully.\n"
"The script may contain errors."));
diff --git a/kioslaves/sieve/sieve.h b/kioslaves/sieve/sieve.h
index f8749f013..0fc3bbd68 100644
--- a/kioslaves/sieve/sieve.h
+++ b/kioslaves/sieve/sieve.h
@@ -122,6 +122,7 @@ protected:
QString m_sPass;
QString m_sAuth;
bool m_shouldBeConnected;
+ bool m_allowUnencrypted;
private:
bool requestCapabilitiesAfterStartTLS() const;
diff --git a/kioslaves/sieve/sieve.protocol b/kioslaves/sieve/sieve.protocol
index 3bd00e25e..484d48da0 100644
--- a/kioslaves/sieve/sieve.protocol
+++ b/kioslaves/sieve/sieve.protocol
@@ -23,14 +23,13 @@ Description[et]=Sieve e-kirjade filtreerimise protokolli IO-moodul
Description[eu]=Sieve posta iragazketa protokoloarentztko irteerako/sarrerako mendeko bat
Description[fa]=یک ioslave برای قرارداد پالایش نامۀ Sieve
Description[fi]=Siirräntätyöskentelijä Sieve-sähköpostiensuodatusyhteyskäytännölle
-Description[fr]=Un module d'entrées / sorties pour le protocole de filtrage de messagerie Sieve
+Description[fr]=Un ioslave pour le protocole de filtrage de messagerie Sieve
Description[fy]=In ioslave foar it Sieve-mailfilterprotokol
Description[gl]=Un esclavo io para o protocolo de filtraxe de correo Sieve
Description[hu]=KDE-protokoll a Sieve levélszűrő protokollhoz
Description[is]=Ioslave fyrir Sieve tölvupóstsíu samskiptaregluna
Description[it]=Un ioslave per il protocollo di filtraggio posta Sieve
Description[ja]=Sieve メールフィルタプロトコル用 ioslave
-Description[ka]=Sieve ფოსტის ფილტრის შეტანა-გამოტანის განაწესი
Description[kk]=Sieve поштаны сүзгілеу протоколының ioslave модулі
Description[km]=ioslave សម្រាប់​ពិធីការ​ត្រង​សំបុត្រ Sieve
Description[ms]=Hamba io untuk protokol tapisan mel saringan
diff --git a/kitchensync/src/kitchensync.desktop b/kitchensync/src/kitchensync.desktop
index e7df319b5..e9f5ae60c 100644
--- a/kitchensync/src/kitchensync.desktop
+++ b/kitchensync/src/kitchensync.desktop
@@ -26,7 +26,6 @@ GenericName[hu]=Szinkronizáció
GenericName[is]=Samstilling
GenericName[it]=Sincronizzazione
GenericName[ja]=同期
-GenericName[ka]=სინქრონიზაცია
GenericName[kk]=Қадамдастыру
GenericName[km]=ការ​​ធ្វើ​សមកាលកម្ម
GenericName[lt]=Sinchronizacija
diff --git a/kmail/KMail.desktop b/kmail/KMail.desktop
index 52e31f0e3..556c94098 100644
--- a/kmail/KMail.desktop
+++ b/kmail/KMail.desktop
@@ -46,7 +46,6 @@ GenericName[id]=Klien Mail
GenericName[is]=Póstforrit
GenericName[it]=Programma di posta elettronica
GenericName[ja]=メールクライアント
-GenericName[ka]=ფოსტის კლიენტი
GenericName[kk]=Эл.пошта клиент бағдарламасы
GenericName[km]=កម្មវិធី​អ៊ីមែល
GenericName[lt]=Pašto klientas
@@ -77,8 +76,7 @@ GenericName[tg]=Клиенти почтавӣ
GenericName[th]=ไคลเอนต์จดหมายอิเล็กทรอนิกส์
GenericName[tr]=E-posta İstemcisi
GenericName[uk]=Поштовий клієнт
-GenericName[uz]=Xat-xabar klienti
-GenericName[uz@cyrillic]=Хат-хабар клиенти
+GenericName[uz]=Хат-хабар клиенти
GenericName[ven]=Mushumisani na poso
GenericName[xh]=Umxhasi Weposi
GenericName[zh_CN]=邮件客户程序
diff --git a/kmail/Makefile.am b/kmail/Makefile.am
index 56b89dbcf..629390928 100644
--- a/kmail/Makefile.am
+++ b/kmail/Makefile.am
@@ -1,5 +1,5 @@
#KDE_OPTIONS = nofinal
-KDE_CXXFLAGS = $(USE_RTTI)
+KDE_CXXFLAGS = $(USE_RTTI) -fexceptions
SUBDIRS = interfaces . about pics profiles avscripts tests
@@ -91,6 +91,7 @@ libkmailprivate_la_SOURCES = kmmessage.cpp kmmainwin.cpp configuredialog.cpp \
headerstrategy.cpp headerstyle.cpp khtmlparthtmlwriter.cpp \
filehtmlwriter.cpp teehtmlwriter.cpp \
mailcomposerIface.skel objecttreeparser.cpp \
+ objecttreeparser_p.cpp \
attachmentcollector.cpp \
bodypartformatter.cpp bodypartformatterfactory.cpp \
partNode.cpp \
@@ -150,7 +151,15 @@ libkmailprivate_la_SOURCES = kmmessage.cpp kmmainwin.cpp configuredialog.cpp \
snippetsettingsbase.ui \
scalix.cpp \
messageactions.cpp \
- korghelper.cpp
+ korghelper.cpp \
+ foldersetselector.cpp \
+ stringutil.cpp \
+ treebase.cpp \
+ backupjob.cpp \
+ importjob.cpp \
+ folderutil.cpp \
+ archivefolderdialog.cpp \
+ importarchivedialog.cpp
libkmailprivate_la_COMPILE_FIRST = globalsettings_base.h customtemplates_base.h templatesconfiguration_base.h
@@ -209,7 +218,7 @@ update_SCRIPTS = upgrade-transport.pl kmail-pgpidentity.pl \
kmail-3.3b1-misc.pl \
kmail-3.4-misc.pl \
kmail-3.4.1-update-status-filters.pl \
- kmail-3.5-filter-icons.pl \
+ kmail-3.5-filter-icons.pl \
kmail-3.5-trigger-flag-migration.pl
confdir = $(kde_confdir)
@@ -226,10 +235,10 @@ kde_services_DATA = kmail_config_misc.desktop kmail_config_appearance.desktop \
kmail_config_security.desktop
messages: rc.cpp
- rm -f tips.txt
- $(PREPARETIPS) > tips.txt
- $(XGETTEXT) -ktranslate *.cpp *.txt *.h -o $(podir)/kmail.pot
- rm -f tips.txt
+ rm -f tips.cpp
+ $(PREPARETIPS) > tips.cpp
+ $(XGETTEXT) -ktranslate *.cpp *.h -o $(podir)/kmail.pot
+ rm -f tips.cpp
kde_kcfg_DATA = kmail.kcfg replyphrases.kcfg custommimeheader.kcfg \
templatesconfiguration_kfg.kcfg customtemplates_kfg.kcfg
diff --git a/kmail/accountdialog.cpp b/kmail/accountdialog.cpp
index 6203d3e87..8254bac9a 100644
--- a/kmail/accountdialog.cpp
+++ b/kmail/accountdialog.cpp
@@ -984,7 +984,7 @@ void AccountDialog::makeImapAccountPage( bool connected )
++row;
mImap.subscribedFoldersCheck = new TQCheckBox(
- i18n("Show only s&ubscribed folders"), page1);
+ i18n("Show only serverside s&ubscribed folders"), page1);
grid->addMultiCellWidget( mImap.subscribedFoldersCheck, row, row, 0, 1 );
++row;
diff --git a/kmail/accountwizard.cpp b/kmail/accountwizard.cpp
index de6c43178..589ef5d63 100644
--- a/kmail/accountwizard.cpp
+++ b/kmail/accountwizard.cpp
@@ -146,7 +146,7 @@ void AccountWizard::showPage( TQWidget *page )
const KPIM::Identity &identity = manager->defaultIdentity();
mRealName->setText( identity.fullName() );
- mEMailAddress->setText( identity.emailAddr() );
+ mEMailAddress->setText( identity.primaryEmailAddress() );
mOrganization->setText( identity.organization() );
}
} else if ( page == mLoginInformationPage ) {
@@ -356,7 +356,7 @@ void AccountWizard::accept()
KPIM::Identity &identity = manager->modifyIdentityForUoid( manager->defaultIdentity().uoid() );
identity.setFullName( mRealName->text() );
- identity.setEmailAddr( mEMailAddress->text() );
+ identity.setPrimaryEmailAddress( mEMailAddress->text() );
identity.setOrganization( mOrganization->text() );
manager->commit();
diff --git a/kmail/acljobs.cpp b/kmail/acljobs.cpp
index 41931829e..1f9b6bb5d 100644
--- a/kmail/acljobs.cpp
+++ b/kmail/acljobs.cpp
@@ -48,7 +48,9 @@ static unsigned int IMAPRightsToPermission( const TQString& str, const KURL& url
case 'w': perm |= ACLJobs::WriteFlags; break;
case 'i': perm |= ACLJobs::Insert; break;
case 'p': perm |= ACLJobs::Post; break;
+ case 'k': // fall through
case 'c': perm |= ACLJobs::Create; break;
+ case 'x': // fall through
case 'd': perm |= ACLJobs::Delete; break;
case 'a': perm |= ACLJobs::Administer; break;
default: break;
diff --git a/kmail/acljobs.h b/kmail/acljobs.h
index 7abc8065b..2a868540b 100644
--- a/kmail/acljobs.h
+++ b/kmail/acljobs.h
@@ -59,6 +59,14 @@ namespace KMail {
*/
namespace ACLJobs {
+ // Used by KMFolderCachedImap and KMFolderImap, no better place for that yet, until we have a
+ // common base class for both
+ enum ACLFetchState {
+ NotFetchedYet, ///< The user rights/ACL have not been fetched from the server yet, we don't know them
+ Ok, ///< The user rights/ACL have been fetched from the server sucessfully
+ FetchFailed ///< The attempt to fetch the user rights/ACL from the server failed
+ };
+
/// Bitfield modelling the possible permissions.
/// This is modelled after the imap4 permissions except that Read is "rs".
/// The semantics of the bits is protocol-dependent.
diff --git a/kmail/annotationjobs.cpp b/kmail/annotationjobs.cpp
index 6b9cd8e86..4e5dc2015 100644
--- a/kmail/annotationjobs.cpp
+++ b/kmail/annotationjobs.cpp
@@ -117,7 +117,7 @@ void AnnotationJobs::MultiGetAnnotationJob::slotResult( KIO::Job *job )
GetAnnotationJob* getJob = static_cast<GetAnnotationJob *>( job );
const AnnotationList& lst = getJob->annotations();
for ( unsigned int i = 0 ; i < lst.size() ; ++ i ) {
- kdDebug(5006) << "found annotation " << lst[i].name << " = " << lst[i].value << endl;
+ //kdDebug(5006) << "found annotation " << lst[i].name << " = " << lst[i].value << endl;
if ( lst[i].name.startsWith( "value." ) ) { // value.priv or value.shared
found = true;
value = lst[i].value;
diff --git a/kmail/antispamwizard.cpp b/kmail/antispamwizard.cpp
index e01093fd3..17d7ed1ed 100644
--- a/kmail/antispamwizard.cpp
+++ b/kmail/antispamwizard.cpp
@@ -34,7 +34,6 @@
#include "kmfilteraction.h"
#include "kmfiltermgr.h"
#include "kmkernel.h"
-#include "kmfolderseldlg.h"
#include "kmfoldertree.h"
#include "kmmainwin.h"
#include "networkaccount.h"
@@ -428,7 +427,13 @@ void AntiSpamWizard::accept()
classHamFilter->setConfigureShortcut( true );
classHamFilter->setConfigureToolbar( true );
filterList.append( classHamFilter );
- }
+ }
+
+ /* Now that all the filters have been added to the list, tell
+ * the filter manager about it. That will emit filterListUpdate
+ * which will result in the filter list in kmmainwidget being
+ * initialized. This should happend only once. */
+ KMKernel::self()->filterMgr()->appendFilters( filterList );
/* Now that all the filters have been added to the list, tell
* the filter manager about it. That will emit filterListUpdate
@@ -834,9 +839,8 @@ ASWizPage::ASWizPage( TQWidget * parent, const char * name,
banner = *bannerName;
mLayout = new TQHBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
- mPixmap = new TQPixmap( UserIcon(banner) );
mBannerLabel = new TQLabel( this );
- mBannerLabel->setPixmap( *mPixmap );
+ mBannerLabel->setPixmap( UserIcon(banner) );
mBannerLabel->setScaledContents( false );
mBannerLabel->setFrameShape( TQFrame::StyledPanel );
mBannerLabel->setFrameShadow( TQFrame::Sunken );
diff --git a/kmail/antispamwizard.h b/kmail/antispamwizard.h
index e9707e822..738d8516a 100644
--- a/kmail/antispamwizard.h
+++ b/kmail/antispamwizard.h
@@ -29,6 +29,8 @@
#ifndef KMAIL_ANTISPAMWIZARD_H
#define KMAIL_ANTISPAMWIZARD_H
+#include "simplefoldertree.h"
+
#include <kconfig.h>
#include <klistbox.h>
#include <kwizard.h>
@@ -44,7 +46,6 @@ class TQLabel;
namespace KMail {
- class SimpleFolderTree;
class FolderRequester;
class ASWizInfoPage;
@@ -289,7 +290,6 @@ namespace KMail {
TQBoxLayout *mLayout;
private:
- TQPixmap *mPixmap;
TQLabel *mBannerLabel;
};
diff --git a/kmail/app_octetstream.cpp b/kmail/app_octetstream.cpp
index 735946452..c740f02df 100644
--- a/kmail/app_octetstream.cpp
+++ b/kmail/app_octetstream.cpp
@@ -38,7 +38,7 @@ namespace {
class Formatter : public KMail::Interface::BodyPartFormatter {
public:
- Result format( KMail::Interface::BodyPart *, KMail::HtmlWriter * ) const { return AsIcon; }
+ Result format( KMail::Interface::BodyPart *, KMail::HtmlWriter *, KMail::Callback & ) const { return AsIcon; }
};
class Plugin : public KMail::Interface::BodyPartFormatterPlugin {
diff --git a/kmail/application_octetstream.desktop b/kmail/application_octetstream.desktop
index a0272b6bb..ec2bbf1ec 100644
--- a/kmail/application_octetstream.desktop
+++ b/kmail/application_octetstream.desktop
@@ -14,7 +14,6 @@ Name[fy]=Applikaasje octetstream
Name[gl]=Aplicación Octetstream
Name[hu]=Alkalmazás-adatfolyam
Name[ja]=アプリケーション オクテット ストリーム
-Name[ka]=რვადინებიანი პროგრამა
Name[kk]=Қолданбаның бинарлы ағымы
Name[km]=Octetstream កម្មវិធី
Name[ms]=Aliran Oktet Aplikasi
@@ -55,7 +54,6 @@ Comment[hu]=Formázómodul application/octet-stream típusú adatfolyamokhoz
Comment[is]=Sniðmátstól fyrir application/octet-stream
Comment[it]=Un plugin per formattare application/octet-stream
Comment[ja]=application/octet-stream の Bodypart フォーマッタプラグイン
-Comment[ka]=ნაწილიბრივი დამფორმატებელი მოდული პროგრამისთვის/octet-stream
Comment[kk]=Application/octet-stream үшін пішімдегіш модулі
Comment[km]=កម្មវិធី​ជំនួយ​កម្មវិធី​ធ្វើ​ទ្រង់ទ្រាយ​ផ្នែក​តួ សម្រាប់​កម្មវិធី/octet-stream
Comment[lt]=application/octet-stream formatavimo priedas
diff --git a/kmail/archivefolderdialog.cpp b/kmail/archivefolderdialog.cpp
new file mode 100644
index 000000000..5bf2cf93f
--- /dev/null
+++ b/kmail/archivefolderdialog.cpp
@@ -0,0 +1,209 @@
+/* Copyright 2009 Klarälvdalens 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) version 3 or any later version
+ accepted by the membership of KDE e.V. (or its successor approved
+ by the membership of KDE e.V.), which shall act as a proxy
+ defined in Section 14 of version 3 of the license.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "archivefolderdialog.h"
+
+#include "backupjob.h"
+#include "kmkernel.h"
+#include "kmfolder.h"
+#include "kmmainwidget.h"
+#include "folderrequester.h"
+#include "util.h"
+
+#include <klocale.h>
+#include <kcombobox.h>
+#include <kurlrequester.h>
+#include <kmessagebox.h>
+#include <kfiledialog.h>
+
+#include <tqlabel.h>
+#include <tqcheckbox.h>
+#include <tqlayout.h>
+
+using namespace KMail;
+
+static TQString standardArchivePath( const TQString &folderName )
+{
+ TQString currentPath = KGlobalSettings::documentPath();
+ TQDir dir( currentPath );
+ if( !dir.exists() ) {
+ currentPath = TQDir::homeDirPath() + '/';
+ }
+ return currentPath +
+ i18n( "Start of the filename for a mail archive file" , "Archive" ) + "_" + folderName +
+ "_" + TQDate::currentDate().toString( TQt::ISODate ) + ".tar.bz2";
+}
+
+ArchiveFolderDialog::ArchiveFolderDialog( TQWidget *parent )
+ : KDialogBase( parent, "archive_folder_dialog", false, i18n( "Archive Folder" ),
+ KDialogBase::Ok | KDialogBase::Cancel,
+ KDialogBase::Ok, true ),
+ mParentWidget( parent )
+{
+ TQWidget *mainWidget = new TQWidget( this );
+ TQGridLayout *mainLayout = new TQGridLayout( mainWidget );
+ mainLayout->setSpacing( KDialog::spacingHint() );
+ mainLayout->setMargin( KDialog::marginHint() );
+ setMainWidget( mainWidget );
+
+ int row = 0;
+
+ // TODO: better label for "Ok" button
+ // TODO: Explaination label
+ // TODO: Use QFormLayout in KDE4
+
+ TQLabel *folderLabel = new TQLabel( i18n( "&Folder:" ), mainWidget );
+ mainLayout->addWidget( folderLabel, row, 0 );
+ mFolderRequester = new FolderRequester( mainWidget, kmkernel->getKMMainWidget()->folderTree() );
+ mFolderRequester->setMustBeReadWrite( false );
+ connect( mFolderRequester, TQT_SIGNAL(folderChanged(KMFolder *)),
+ TQT_SLOT(slotFolderChanged(KMFolder *)) );
+ folderLabel->setBuddy( mFolderRequester );
+ mainLayout->addWidget( mFolderRequester, row, 1 );
+ row++;
+
+ TQLabel *formatLabel = new TQLabel( i18n( "F&ormat:" ), mainWidget );
+ mainLayout->addWidget( formatLabel, row, 0 );
+ mFormatComboBox = new KComboBox( mainWidget );
+ formatLabel->setBuddy( mFormatComboBox );
+
+ // These combobox values have to stay in sync with the ArchiveType enum from BackupJob!
+ mFormatComboBox->insertItem( i18n( "Compressed Zip Archive (.zip)" ) );
+ mFormatComboBox->insertItem( i18n( "Uncompressed Archive (.tar)" ) );
+ mFormatComboBox->insertItem( i18n( "BZ2-Compressed Tar Archive (.tar.bz2)" ) );
+ mFormatComboBox->insertItem( i18n( "GZ-Compressed Tar Archive (.tar.gz)" ) );
+ mFormatComboBox->setCurrentItem( 2 );
+ connect( mFormatComboBox, TQT_SIGNAL(activated(int)),
+ this, TQT_SLOT(slotFixFileExtension()) );
+ mainLayout->addWidget( mFormatComboBox, row, 1 );
+ row++;
+
+ TQLabel *fileNameLabel = new TQLabel( i18n( "&Archive File:" ), mainWidget );
+ mainLayout->addWidget( fileNameLabel, row, 0 );
+ mUrlRequester = new KURLRequester( mainWidget );
+ mUrlRequester->setMode( KFile::LocalOnly );
+ mUrlRequester->setFilter( "*.tar *.zip *.tar.gz *.tar.bz2" );
+ mUrlRequester->fileDialog()->setKeepLocation( true );
+ fileNameLabel->setBuddy( mUrlRequester );
+ connect( mUrlRequester->lineEdit(), TQT_SIGNAL(textChanged(const TQString &)),
+ TQT_SLOT(slotUrlChanged(const TQString &)) );
+ connect( mUrlRequester, TQT_SIGNAL(urlSelected(const TQString&)),
+ this, TQT_SLOT(slotFixFileExtension()) );
+ mainLayout->addWidget( mUrlRequester, row, 1 );
+ row++;
+
+ // TODO: Make this appear more dangerous!
+ mDeleteCheckBox = new TQCheckBox( i18n( "&Delete folders after completion" ), mainWidget );
+ mainLayout->addMultiCellWidget( mDeleteCheckBox, row, row, 0, 1, TQt::AlignLeft );
+ row++;
+
+ // TODO: what's this, tooltips
+
+ // TODO: Warn that user should do mail check for online IMAP and possibly cached IMAP as well
+
+ mainLayout->setColStretch( 1, 1 );
+ mainLayout->addItem( new TQSpacerItem( 1, 1, TQSizePolicy::Expanding, TQSizePolicy::Expanding ), row, 0 );
+
+ // Make it a bit bigger, else the folder requester cuts off the text too early
+ resize( 500, minimumSize().height() );
+}
+
+void ArchiveFolderDialog::slotUrlChanged( const TQString &text )
+{
+ enableButton( Ok, !text.isEmpty() );
+}
+
+bool canRemoveFolder( KMFolder *folder )
+{
+ return
+ folder &&
+ folder->canDeleteMessages() &&
+ !folder->noContent() &&
+ !folder->isSystemFolder();
+}
+
+void ArchiveFolderDialog::slotFolderChanged( KMFolder *folder )
+{
+ mDeleteCheckBox->setEnabled( canRemoveFolder( folder ) );
+ enableButton( Ok, folder && !folder->noContent());
+}
+
+void ArchiveFolderDialog::setFolder( KMFolder *defaultFolder )
+{
+ mFolderRequester->setFolder( defaultFolder );
+ // TODO: what if the file already exists?
+ mUrlRequester->setURL( standardArchivePath( defaultFolder->name() ) );
+ mDeleteCheckBox->setEnabled( canRemoveFolder( defaultFolder ) );
+}
+
+void ArchiveFolderDialog::slotOk()
+{
+ if ( !Util::checkOverwrite( mUrlRequester->url(), this ) ) {
+ return;
+ }
+
+ if ( !mFolderRequester->folder() ) {
+ KMessageBox::information( this, i18n( "Please select the folder that should be archived." ),
+ i18n( "No folder selected" ) );
+ return;
+ }
+
+ // TODO: check if url is empty. or better yet, disable ok button until file is chosen
+ KMail::BackupJob *backupJob = new KMail::BackupJob( mParentWidget );
+ backupJob->setRootFolder( mFolderRequester->folder() );
+ backupJob->setSaveLocation( mUrlRequester->url() );
+ backupJob->setArchiveType( static_cast<BackupJob::ArchiveType>( mFormatComboBox->currentItem() ) );
+ backupJob->setDeleteFoldersAfterCompletion( mDeleteCheckBox->isEnabled() &&
+ mDeleteCheckBox->isChecked() );
+ backupJob->start();
+ accept();
+}
+
+void ArchiveFolderDialog::slotFixFileExtension()
+{
+ // KDE4: use KMimeType::extractKnownExtension() here
+ const int numExtensions = 4;
+
+ // These extensions are sorted differently, .tar has to come last, or it will match before giving
+ // the more specific ones time to match.
+ const char *sortedExtensions[numExtensions] = { ".zip", ".tar.bz2", ".tar.gz", ".tar" };
+
+ // The extensions here are also sorted, like the enum order of BackupJob::ArchiveType
+ const char *extensions[numExtensions] = { ".zip", ".tar", ".tar.bz2", ".tar.gz" };
+
+ TQString fileName = mUrlRequester->url();
+ if ( fileName.isEmpty() ) {
+ fileName = standardArchivePath( mFolderRequester->folder() ?
+ mFolderRequester->folder()->name() : "" );
+ }
+
+ // First, try to find the extension of the file name and remove it
+ for( int i = 0; i < numExtensions; i++ ) {
+ int index = fileName.lower().findRev( sortedExtensions[i] );
+ if ( index != -1 ) {
+ fileName = fileName.left( fileName.length() - TQString( sortedExtensions[i] ).length() );
+ break;
+ }
+ }
+
+ // Now, we've got a filename without an extension, simply append the correct one
+ fileName += extensions[mFormatComboBox->currentItem()];
+ mUrlRequester->setURL( fileName );
+}
+
+#include "archivefolderdialog.moc"
diff --git a/kmail/archivefolderdialog.h b/kmail/archivefolderdialog.h
new file mode 100644
index 000000000..806d5b127
--- /dev/null
+++ b/kmail/archivefolderdialog.h
@@ -0,0 +1,62 @@
+/* Copyright 2009 Klarälvdalens 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) version 3 or any later version
+ accepted by the membership of KDE e.V. (or its successor approved
+ by the membership of KDE e.V.), which shall act as a proxy
+ defined in Section 14 of version 3 of the license.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef ARCHIVEFOLDERDIALOG_H
+#define ARCHIVEFOLDERDIALOG_H
+
+#include <kdialogbase.h>
+
+class TQCheckBox;
+class KURLRequester;
+class KComboBox;
+class KMFolder;
+
+namespace KMail
+{
+class FolderRequester;
+
+class ArchiveFolderDialog : public KDialogBase
+{
+ Q_OBJECT
+
+ public:
+
+ ArchiveFolderDialog( TQWidget *parent = 0 );
+ void setFolder( KMFolder *defaultFolder );
+
+ protected slots:
+
+ void slotFixFileExtension();
+ void slotFolderChanged( KMFolder * );
+ void slotUrlChanged( const TQString & );
+
+ /** reimp */
+ virtual void slotOk();
+
+ private:
+
+ TQWidget *mParentWidget;
+ TQCheckBox *mDeleteCheckBox;
+ FolderRequester *mFolderRequester;
+ KComboBox *mFormatComboBox;
+ KURLRequester *mUrlRequester;
+};
+
+}
+
+#endif
diff --git a/kmail/attachmentcollector.h b/kmail/attachmentcollector.h
index 52454e8d2..e74496072 100644
--- a/kmail/attachmentcollector.h
+++ b/kmail/attachmentcollector.h
@@ -40,20 +40,7 @@ namespace KMail {
class AttachmentCollector {
public:
- AttachmentCollector()
- : mDiveIntoEncryptions( true ),
- mDiveIntoSignatures( true ),
- mDiveIntoMessages( false ) {}
-
- void setDiveIntoEncryptions( bool dive ) {
- mDiveIntoEncryptions = dive;
- }
- void setDiveIntoSignatures( bool dive ) {
- mDiveIntoSignatures = dive;
- }
- void setDiveIntoMessages( bool dive ) {
- mDiveIntoMessages = dive;
- }
+ AttachmentCollector() {}
void collectAttachmentsFrom( partNode * node );
@@ -61,9 +48,6 @@ namespace KMail {
private:
std::vector<partNode*> mAttachments;
- bool mDiveIntoEncryptions : 1;
- bool mDiveIntoSignatures : 1;
- bool mDiveIntoMessages : 1;
private: // disabled
AttachmentCollector( const AttachmentCollector & );
diff --git a/kmail/attachmentstrategy.cpp b/kmail/attachmentstrategy.cpp
index 8d1e59a90..6e147b946 100644
--- a/kmail/attachmentstrategy.cpp
+++ b/kmail/attachmentstrategy.cpp
@@ -45,6 +45,21 @@
namespace KMail {
+static AttachmentStrategy::Display smartDisplay( const partNode *node )
+{
+ if ( node->hasContentDispositionInline() )
+ // explict "inline" disposition:
+ return AttachmentStrategy::Inline;
+ if ( node->isAttachment() )
+ // explicit "attachment" disposition:
+ return AttachmentStrategy::AsIcon;
+ if ( node->type() == DwMime::kTypeText &&
+ node->msgPart().fileName().stripWhiteSpace().isEmpty() &&
+ node->msgPart().name().stripWhiteSpace().isEmpty() )
+ // text/* w/o filename parameter:
+ return AttachmentStrategy::Inline;
+ return AttachmentStrategy::AsIcon;
+}
//
// IconicAttachmentStrategy:
@@ -60,7 +75,7 @@ namespace KMail {
public:
const char * name() const { return "iconic"; }
const AttachmentStrategy * next() const { return smart(); }
- const AttachmentStrategy * prev() const { return hidden(); }
+ const AttachmentStrategy * prev() const { return headerOnly(); }
bool inlineNestedMessages() const { return false; }
Display defaultDisplay( const partNode * ) const { return AsIcon; }
@@ -86,18 +101,7 @@ namespace KMail {
bool inlineNestedMessages() const { return true; }
Display defaultDisplay( const partNode * node ) const {
- if ( node->hasContentDispositionInline() )
- // explict "inline" disposition:
- return Inline;
- if ( node->isAttachment() )
- // explicit "attachment" disposition:
- return AsIcon;
- if ( node->type() == DwMime::kTypeText &&
- node->msgPart().fileName().stripWhiteSpace().isEmpty() &&
- node->msgPart().name().stripWhiteSpace().isEmpty() )
- // text/* w/o filename parameter:
- return Inline;
- return AsIcon;
+ return smartDisplay( node );
}
};
@@ -134,13 +138,45 @@ namespace KMail {
public:
const char * name() const { return "hidden"; }
- const AttachmentStrategy * next() const { return iconic(); }
+ const AttachmentStrategy * next() const { return headerOnly(); }
const AttachmentStrategy * prev() const { return inlined(); }
bool inlineNestedMessages() const { return false; }
Display defaultDisplay( const partNode * ) const { return None; }
};
+ class HeaderOnlyAttachmentStrategy : public AttachmentStrategy {
+ friend class ::KMail::AttachmentStrategy;
+ protected:
+ HeaderOnlyAttachmentStrategy() : AttachmentStrategy() {}
+ virtual ~HeaderOnlyAttachmentStrategy() {}
+
+ public:
+ const char * name() const { return "headerOnly"; }
+ const AttachmentStrategy * next() const { return iconic(); }
+ const AttachmentStrategy * prev() const { return hidden(); }
+
+ bool inlineNestedMessages() const {
+ return true;
+ }
+
+ Display defaultDisplay( const partNode *node ) const {
+ if ( node->isInEncapsulatedMessage() ) {
+ return smartDisplay( node );
+ }
+
+ partNode::AttachmentDisplayInfo info = node->attachmentDisplayInfo();
+ if ( info.displayInHeader ) {
+ // The entire point about this attachment strategy: Hide attachments in the body that are
+ // already displayed in the attachment quick list
+ return None;
+ } else {
+ return smartDisplay( node );
+ }
+ }
+ };
+
+
//
// AttachmentStrategy abstract base:
@@ -156,10 +192,11 @@ namespace KMail {
const AttachmentStrategy * AttachmentStrategy::create( Type type ) {
switch ( type ) {
- case Iconic: return iconic();
- case Smart: return smart();
- case Inlined: return inlined();
- case Hidden: return hidden();
+ case Iconic: return iconic();
+ case Smart: return smart();
+ case Inlined: return inlined();
+ case Hidden: return hidden();
+ case HeaderOnly: return headerOnly();
}
kdFatal( 5006 ) << "AttachmentStrategy::create(): Unknown attachment startegy ( type == "
<< (int)type << " ) requested!" << endl;
@@ -168,10 +205,11 @@ namespace KMail {
const AttachmentStrategy * AttachmentStrategy::create( const TQString & type ) {
TQString lowerType = type.lower();
- if ( lowerType == "iconic" ) return iconic();
+ if ( lowerType == "iconic" ) return iconic();
//if ( lowerType == "smart" ) return smart(); // not needed, see below
- if ( lowerType == "inlined" ) return inlined();
- if ( lowerType == "hidden" ) return hidden();
+ if ( lowerType == "inlined" ) return inlined();
+ if ( lowerType == "hidden" ) return hidden();
+ if ( lowerType == "headeronly" ) return headerOnly();
// don't kdFatal here, b/c the strings are user-provided
// (KConfig), so fail gracefully to the default:
return smart();
@@ -181,6 +219,7 @@ namespace KMail {
static const AttachmentStrategy * smartStrategy = 0;
static const AttachmentStrategy * inlinedStrategy = 0;
static const AttachmentStrategy * hiddenStrategy = 0;
+ static const AttachmentStrategy * headerOnlyStrategy = 0;
const AttachmentStrategy * AttachmentStrategy::iconic() {
if ( !iconicStrategy )
@@ -206,4 +245,10 @@ namespace KMail {
return hiddenStrategy;
}
+ const AttachmentStrategy * AttachmentStrategy::headerOnly() {
+ if ( !headerOnlyStrategy )
+ headerOnlyStrategy = new HeaderOnlyAttachmentStrategy();
+ return headerOnlyStrategy;
+ }
+
} // namespace KMail
diff --git a/kmail/attachmentstrategy.h b/kmail/attachmentstrategy.h
index e4440b246..835768949 100644
--- a/kmail/attachmentstrategy.h
+++ b/kmail/attachmentstrategy.h
@@ -46,7 +46,7 @@ namespace KMail {
//
// Factory methods:
//
- enum Type { Iconic, Smart, Inlined, Hidden };
+ enum Type { Iconic, Smart, Inlined, Hidden, HeaderOnly };
static const AttachmentStrategy * create( Type type );
static const AttachmentStrategy * create( const TQString & type );
@@ -55,6 +55,7 @@ namespace KMail {
static const AttachmentStrategy * smart();
static const AttachmentStrategy * inlined();
static const AttachmentStrategy * hidden();
+ static const AttachmentStrategy * headerOnly();
//
// Navigation methods:
diff --git a/kmail/backupjob.cpp b/kmail/backupjob.cpp
new file mode 100644
index 000000000..fd53997b3
--- /dev/null
+++ b/kmail/backupjob.cpp
@@ -0,0 +1,500 @@
+/* Copyright 2009 Klarälvdalens 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) version 3 or any later version
+ accepted by the membership of KDE e.V. (or its successor approved
+ by the membership of KDE e.V.), which shall act as a proxy
+ defined in Section 14 of version 3 of the license.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "backupjob.h"
+
+#include "kmmsgdict.h"
+#include "kmfolder.h"
+#include "kmfoldercachedimap.h"
+#include "kmfolderdir.h"
+#include "folderutil.h"
+
+#include "progressmanager.h"
+
+#include "kzip.h"
+#include "ktar.h"
+#include "kmessagebox.h"
+
+#include "tqfile.h"
+#include "tqfileinfo.h"
+#include "tqstringlist.h"
+
+using namespace KMail;
+
+BackupJob::BackupJob( TQWidget *parent )
+ : TQObject( parent ),
+ mArchiveType( Zip ),
+ mRootFolder( 0 ),
+ mArchive( 0 ),
+ mParentWidget( parent ),
+ mCurrentFolderOpen( false ),
+ mArchivedMessages( 0 ),
+ mArchivedSize( 0 ),
+ mProgressItem( 0 ),
+ mAborted( false ),
+ mDeleteFoldersAfterCompletion( false ),
+ mCurrentFolder( 0 ),
+ mCurrentMessage( 0 ),
+ mCurrentJob( 0 )
+{
+}
+
+BackupJob::~BackupJob()
+{
+ mPendingFolders.clear();
+ if ( mArchive ) {
+ delete mArchive;
+ mArchive = 0;
+ }
+}
+
+void BackupJob::setRootFolder( KMFolder *rootFolder )
+{
+ mRootFolder = rootFolder;
+}
+
+void BackupJob::setSaveLocation( const KURL &savePath )
+{
+ mMailArchivePath = savePath;
+}
+
+void BackupJob::setArchiveType( ArchiveType type )
+{
+ mArchiveType = type;
+}
+
+void BackupJob::setDeleteFoldersAfterCompletion( bool deleteThem )
+{
+ mDeleteFoldersAfterCompletion = deleteThem;
+}
+
+TQString BackupJob::stripRootPath( const TQString &path ) const
+{
+ TQString ret = path;
+ ret = ret.remove( mRootFolder->path() );
+ if ( ret.startsWith( "/" ) )
+ ret = ret.right( ret.length() - 1 );
+ return ret;
+}
+
+void BackupJob::queueFolders( KMFolder *root )
+{
+ mPendingFolders.append( root );
+ KMFolderDir *dir = root->child();
+ if ( dir ) {
+ for ( KMFolderNode * node = dir->first() ; node ; node = dir->next() ) {
+ if ( node->isDir() )
+ continue;
+ KMFolder *folder = static_cast<KMFolder*>( node );
+ queueFolders( folder );
+ }
+ }
+}
+
+bool BackupJob::hasChildren( KMFolder *folder ) const
+{
+ KMFolderDir *dir = folder->child();
+ if ( dir ) {
+ for ( KMFolderNode * node = dir->first() ; node ; node = dir->next() ) {
+ if ( !node->isDir() )
+ return true;
+ }
+ }
+ return false;
+}
+
+void BackupJob::cancelJob()
+{
+ abort( i18n( "The operation was canceled by the user." ) );
+}
+
+void BackupJob::abort( const TQString &errorMessage )
+{
+ // We could be called this twice, since killing the current job below will cause the job to fail,
+ // and that will call abort()
+ if ( mAborted )
+ return;
+
+ mAborted = true;
+ if ( mCurrentFolderOpen && mCurrentFolder ) {
+ mCurrentFolder->close( "BackupJob" );
+ mCurrentFolder = 0;
+ }
+ if ( mArchive && mArchive->isOpened() ) {
+ mArchive->close();
+ }
+ if ( mCurrentJob ) {
+ mCurrentJob->kill();
+ mCurrentJob = 0;
+ }
+ if ( mProgressItem ) {
+ mProgressItem->setComplete();
+ mProgressItem = 0;
+ // The progressmanager will delete it
+ }
+
+ TQString text = i18n( "Failed to archive the folder '%1'." ).arg( mRootFolder->name() );
+ text += "\n" + errorMessage;
+ KMessageBox::sorry( mParentWidget, text, i18n( "Archiving failed." ) );
+ deleteLater();
+ // Clean up archive file here?
+}
+
+void BackupJob::finish()
+{
+ if ( mArchive->isOpened() ) {
+ mArchive->close();
+ if ( !mArchive->closeSucceeded() ) {
+ abort( i18n( "Unable to finalize the archive file." ) );
+ return;
+ }
+ }
+
+ mProgressItem->setStatus( i18n( "Archiving finished" ) );
+ mProgressItem->setComplete();
+ mProgressItem = 0;
+
+ TQFileInfo archiveFileInfo( mMailArchivePath.path() );
+ TQString text = i18n( "Archiving folder '%1' successfully completed. "
+ "The archive was written to the file '%2'." )
+ .arg( mRootFolder->name() ).arg( mMailArchivePath.path() );
+ text += "\n" + i18n( "1 message of size %1 was archived.",
+ "%n messages with the total size of %1 were archived.", mArchivedMessages )
+ .arg( KIO::convertSize( mArchivedSize ) );
+ text += "\n" + i18n( "The archive file has a size of %1." )
+ .arg( KIO::convertSize( archiveFileInfo.size() ) );
+ KMessageBox::information( mParentWidget, text, i18n( "Archiving finished." ) );
+
+ if ( mDeleteFoldersAfterCompletion ) {
+ // Some saftey checks first...
+ if ( archiveFileInfo.size() > 0 && ( mArchivedSize > 0 || mArchivedMessages == 0 ) ) {
+ // Sorry for any data loss!
+ FolderUtil::deleteFolder( mRootFolder, mParentWidget );
+ }
+ }
+
+ deleteLater();
+}
+
+void BackupJob::archiveNextMessage()
+{
+ if ( mAborted )
+ return;
+
+ mCurrentMessage = 0;
+ if ( mPendingMessages.isEmpty() ) {
+ kdDebug(5006) << "===> All messages done in folder " << mCurrentFolder->name() << endl;
+ mCurrentFolder->close( "BackupJob" );
+ mCurrentFolderOpen = false;
+ archiveNextFolder();
+ return;
+ }
+
+ unsigned long serNum = mPendingMessages.front();
+ mPendingMessages.pop_front();
+
+ KMFolder *folder;
+ mMessageIndex = -1;
+ KMMsgDict::instance()->getLocation( serNum, &folder, &mMessageIndex );
+ if ( mMessageIndex == -1 ) {
+ kdWarning(5006) << "Failed to get message location for sernum " << serNum << endl;
+ abort( i18n( "Unable to retrieve a message for folder '%1'." ).arg( mCurrentFolder->name() ) );
+ return;
+ }
+
+ Q_ASSERT( folder == mCurrentFolder );
+ const KMMsgBase *base = mCurrentFolder->getMsgBase( mMessageIndex );
+ mUnget = base && !base->isMessage();
+ KMMessage *message = mCurrentFolder->getMsg( mMessageIndex );
+ if ( !message ) {
+ kdWarning(5006) << "Failed to retrieve message with index " << mMessageIndex << endl;
+ abort( i18n( "Unable to retrieve a message for folder '%1'." ).arg( mCurrentFolder->name() ) );
+ return;
+ }
+
+ kdDebug(5006) << "Going to get next message with subject " << message->subject() << ", "
+ << mPendingMessages.size() << " messages left in the folder." << endl;
+
+ if ( message->isComplete() ) {
+ // Use a singleshot timer, or otherwise we risk ending up in a very big recursion
+ // for folders that have many messages
+ mCurrentMessage = message;
+ TQTimer::singleShot( 0, this, TQT_SLOT( processCurrentMessage() ) );
+ }
+ else if ( message->parent() ) {
+ mCurrentJob = message->parent()->createJob( message );
+ mCurrentJob->setCancellable( false );
+ connect( mCurrentJob, TQT_SIGNAL( messageRetrieved( KMMessage* ) ),
+ this, TQT_SLOT( messageRetrieved( KMMessage* ) ) );
+ connect( mCurrentJob, TQT_SIGNAL( result( KMail::FolderJob* ) ),
+ this, TQT_SLOT( folderJobFinished( KMail::FolderJob* ) ) );
+ mCurrentJob->start();
+ }
+ else {
+ kdWarning(5006) << "Message with subject " << mCurrentMessage->subject()
+ << " is neither complete nor has a parent!" << endl;
+ abort( i18n( "Internal error while trying to retrieve a message from folder '%1'." )
+ .arg( mCurrentFolder->name() ) );
+ }
+
+ mProgressItem->setProgress( ( mProgressItem->progress() + 5 ) );
+}
+
+static int fileInfoToUnixPermissions( const TQFileInfo &fileInfo )
+{
+ int perm = 0;
+ if ( fileInfo.permission( TQFileInfo::ExeOther ) ) perm += S_IXOTH;
+ if ( fileInfo.permission( TQFileInfo::WriteOther ) ) perm += S_IWOTH;
+ if ( fileInfo.permission( TQFileInfo::ReadOther ) ) perm += S_IROTH;
+ if ( fileInfo.permission( TQFileInfo::ExeGroup ) ) perm += S_IXGRP;
+ if ( fileInfo.permission( TQFileInfo::WriteGroup ) ) perm += S_IWGRP;
+ if ( fileInfo.permission( TQFileInfo::ReadGroup ) ) perm += S_IRGRP;
+ if ( fileInfo.permission( TQFileInfo::ExeOwner ) ) perm += S_IXUSR;
+ if ( fileInfo.permission( TQFileInfo::WriteOwner ) ) perm += S_IWUSR;
+ if ( fileInfo.permission( TQFileInfo::ReadOwner ) ) perm += S_IRUSR;
+ return perm;
+}
+
+void BackupJob::processCurrentMessage()
+{
+ if ( mAborted )
+ return;
+
+ if ( mCurrentMessage ) {
+ kdDebug(5006) << "Processing message with subject " << mCurrentMessage->subject() << endl;
+ const DwString &messageDWString = mCurrentMessage->asDwString();
+ const uint messageSize = messageDWString.size();
+ const char *messageString = mCurrentMessage->asDwString().c_str();
+ TQString messageName;
+ TQFileInfo fileInfo;
+ if ( messageName.isEmpty() ) {
+ messageName = TQString::number( mCurrentMessage->getMsgSerNum() ); // IMAP doesn't have filenames
+ if ( mCurrentMessage->storage() ) {
+ fileInfo.setFile( mCurrentMessage->storage()->location() );
+ // TODO: what permissions etc to take when there is no storage file?
+ }
+ }
+ else {
+ // TODO: What if the message is not in the "cur" directory?
+ fileInfo.setFile( mCurrentFolder->location() + "/cur/" + mCurrentMessage->fileName() );
+ messageName = mCurrentMessage->fileName();
+ }
+
+ const TQString fileName = stripRootPath( mCurrentFolder->location() ) +
+ "/cur/" + messageName;
+
+ TQString user;
+ TQString group;
+ mode_t permissions = 0700;
+ time_t creationTime = time( 0 );
+ time_t modificationTime = time( 0 );
+ time_t accessTime = time( 0 );
+ if ( !fileInfo.fileName().isEmpty() ) {
+ user = fileInfo.owner();
+ group = fileInfo.group();
+ permissions = fileInfoToUnixPermissions( fileInfo );
+ creationTime = fileInfo.created().toTime_t();
+ modificationTime = fileInfo.lastModified().toTime_t();
+ accessTime = fileInfo.lastRead().toTime_t();
+ }
+ else {
+ kdWarning(5006) << "Unable to find file for message " << fileName << endl;
+ }
+
+ if ( !mArchive->writeFile( fileName, user, group, messageSize, permissions, accessTime,
+ modificationTime, creationTime, messageString ) ) {
+ abort( i18n( "Failed to write a message into the archive folder '%1'." ).arg( mCurrentFolder->name() ) );
+ return;
+ }
+
+ if ( mUnget ) {
+ Q_ASSERT( mMessageIndex >= 0 );
+ mCurrentFolder->unGetMsg( mMessageIndex );
+ }
+
+ mArchivedMessages++;
+ mArchivedSize += messageSize;
+ }
+ else {
+ // No message? According to ImapJob::slotGetMessageResult(), that means the message is no
+ // longer on the server. So ignore this one.
+ kdWarning(5006) << "Unable to download a message for folder " << mCurrentFolder->name() << endl;
+ }
+ archiveNextMessage();
+}
+
+void BackupJob::messageRetrieved( KMMessage *message )
+{
+ mCurrentMessage = message;
+ processCurrentMessage();
+}
+
+void BackupJob::folderJobFinished( KMail::FolderJob *job )
+{
+ if ( mAborted )
+ return;
+
+ // The job might finish after it has emitted messageRetrieved(), in which case we have already
+ // started a new job. Don't set the current job to 0 in that case.
+ if ( job == mCurrentJob ) {
+ mCurrentJob = 0;
+ }
+
+ if ( job->error() ) {
+ if ( mCurrentFolder )
+ abort( i18n( "Downloading a message in folder '%1' failed." ).arg( mCurrentFolder->name() ) );
+ else
+ abort( i18n( "Downloading a message in the current folder failed." ) );
+ }
+}
+
+bool BackupJob::writeDirHelper( const TQString &directoryPath, const TQString &permissionPath )
+{
+ TQFileInfo fileInfo( permissionPath );
+ TQString user = fileInfo.owner();
+ TQString group = fileInfo.group();
+ mode_t permissions = fileInfoToUnixPermissions( fileInfo );
+ time_t creationTime = fileInfo.created().toTime_t();
+ time_t modificationTime = fileInfo.lastModified().toTime_t();
+ time_t accessTime = fileInfo.lastRead().toTime_t();
+ return mArchive->writeDir( stripRootPath( directoryPath ), user, group, permissions, accessTime,
+ modificationTime, creationTime );
+}
+
+void BackupJob::archiveNextFolder()
+{
+ if ( mAborted )
+ return;
+
+ if ( mPendingFolders.isEmpty() ) {
+ finish();
+ return;
+ }
+
+ mCurrentFolder = mPendingFolders.take( 0 );
+ kdDebug(5006) << "===> Archiving next folder: " << mCurrentFolder->name() << endl;
+ mProgressItem->setStatus( i18n( "Archiving folder %1" ).arg( mCurrentFolder->name() ) );
+ if ( mCurrentFolder->open( "BackupJob" ) != 0 ) {
+ abort( i18n( "Unable to open folder '%1'.").arg( mCurrentFolder->name() ) );
+ return;
+ }
+ mCurrentFolderOpen = true;
+
+ const TQString folderName = mCurrentFolder->name();
+ bool success = true;
+ if ( hasChildren( mCurrentFolder ) ) {
+ if ( !writeDirHelper( mCurrentFolder->subdirLocation(), mCurrentFolder->subdirLocation() ) )
+ success = false;
+ }
+ if ( !writeDirHelper( mCurrentFolder->location(), mCurrentFolder->location() ) )
+ success = false;
+ if ( !writeDirHelper( mCurrentFolder->location() + "/cur", mCurrentFolder->location() ) )
+ success = false;
+ if ( !writeDirHelper( mCurrentFolder->location() + "/new", mCurrentFolder->location() ) )
+ success = false;
+ if ( !writeDirHelper( mCurrentFolder->location() + "/tmp", mCurrentFolder->location() ) )
+ success = false;
+ if ( !success ) {
+ abort( i18n( "Unable to create folder structure for folder '%1' within archive file." )
+ .arg( mCurrentFolder->name() ) );
+ return;
+ }
+
+ for ( int i = 0; i < mCurrentFolder->count( false /* no cache */ ); i++ ) {
+ unsigned long serNum = KMMsgDict::instance()->getMsgSerNum( mCurrentFolder, i );
+ if ( serNum == 0 ) {
+ // Uh oh
+ kdWarning(5006) << "Got serial number zero in " << mCurrentFolder->name()
+ << " at index " << i << "!" << endl;
+ // TODO: handle error in a nicer way. this is _very_ bad
+ abort( i18n( "Unable to backup messages in folder '%1', the index file is corrupted." )
+ .arg( mCurrentFolder->name() ) );
+ return;
+ }
+ else
+ mPendingMessages.append( serNum );
+ }
+ archiveNextMessage();
+}
+
+// TODO
+// - error handling
+// - import
+// - connect to progressmanager, especially abort
+// - messagebox when finished (?)
+// - ui dialog
+// - use correct permissions
+// - save index and serial number?
+// - guarded pointers for folders
+// - online IMAP: check mails first, so sernums are up-to-date?
+// - "ignore errors"-mode, with summary how many messages couldn't be archived?
+// - do something when the user quits KMail while the backup job is running
+// - run in a thread?
+// - delete source folder after completion. dangerous!!!
+//
+// BUGS
+// - Online IMAP: Test Mails -> Test%20Mails
+// - corrupted sernums indices stop backup job
+void BackupJob::start()
+{
+ Q_ASSERT( !mMailArchivePath.isEmpty() );
+ Q_ASSERT( mRootFolder );
+
+ queueFolders( mRootFolder );
+
+ switch ( mArchiveType ) {
+ case Zip: {
+ KZip *zip = new KZip( mMailArchivePath.path() );
+ zip->setCompression( KZip::DeflateCompression );
+ mArchive = zip;
+ break;
+ }
+ case Tar: {
+ mArchive = new KTar( mMailArchivePath.path(), "application/x-tar" );
+ break;
+ }
+ case TarGz: {
+ mArchive = new KTar( mMailArchivePath.path(), "application/x-gzip" );
+ break;
+ }
+ case TarBz2: {
+ mArchive = new KTar( mMailArchivePath.path(), "application/x-bzip2" );
+ break;
+ }
+ }
+
+ kdDebug(5006) << "Starting backup." << endl;
+ if ( !mArchive->open( IO_WriteOnly ) ) {
+ abort( i18n( "Unable to open archive for writing." ) );
+ return;
+ }
+
+ mProgressItem = KPIM::ProgressManager::createProgressItem(
+ "BackupJob",
+ i18n( "Archiving" ),
+ TQString(),
+ true );
+ mProgressItem->setUsesBusyIndicator( true );
+ connect( mProgressItem, TQT_SIGNAL(progressItemCanceled(KPIM::ProgressItem*)),
+ this, TQT_SLOT(cancelJob()) );
+
+ archiveNextFolder();
+}
+
+#include "backupjob.moc"
+
diff --git a/kmail/backupjob.h b/kmail/backupjob.h
new file mode 100644
index 000000000..f6383d669
--- /dev/null
+++ b/kmail/backupjob.h
@@ -0,0 +1,109 @@
+/* Copyright 2009 Klarälvdalens 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) version 3 or any later version
+ accepted by the membership of KDE e.V. (or its successor approved
+ by the membership of KDE e.V.), which shall act as a proxy
+ defined in Section 14 of version 3 of the license.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef BACKUPJOB_H
+#define BACKUPJOB_H
+
+#include <kurl.h>
+#include <tqptrlist.h>
+
+#include <tqobject.h>
+
+class KMFolder;
+class KMMessage;
+class KArchive;
+class KProcess;
+class TQWidget;
+
+namespace KPIM {
+ class ProgressItem;
+}
+
+namespace KMail
+{
+ class FolderJob;
+
+/**
+ * Writes an entire folder structure to an archive file.
+ * The archive is structured like a hierarchy of maildir folders. However, every type of folder
+ * works as the source, i.e. also online IMAP folders.
+ *
+ * The job deletes itself after it finished.
+ */
+class BackupJob : public TQObject
+{
+ Q_OBJECT
+
+ public:
+
+ // These enum values have to stay in sync with the format combobox of ArchiveFolderDialog!
+ enum ArchiveType { Zip = 0, Tar = 1, TarBz2 = 2, TarGz = 3 };
+
+ explicit BackupJob( TQWidget *parent = 0 );
+ ~BackupJob();
+ void setRootFolder( KMFolder *rootFolder );
+ void setSaveLocation( const KURL &savePath );
+ void setArchiveType( ArchiveType type );
+ void setDeleteFoldersAfterCompletion( bool deleteThem );
+ void start();
+
+ private slots:
+
+ void messageRetrieved( KMMessage *message );
+ void folderJobFinished( KMail::FolderJob *job );
+ void processCurrentMessage();
+ void cancelJob();
+
+ private:
+
+ void queueFolders( KMFolder *root );
+ void archiveNextFolder();
+ void archiveNextMessage();
+ TQString stripRootPath( const TQString &path ) const;
+ bool hasChildren( KMFolder *folder ) const;
+ void finish();
+ void abort( const TQString &errorMessage );
+ bool writeDirHelper( const TQString &directoryPath, const TQString &permissionPath );
+
+ KURL mMailArchivePath;
+ ArchiveType mArchiveType;
+ KMFolder *mRootFolder;
+ KArchive *mArchive;
+ TQWidget *mParentWidget;
+ bool mCurrentFolderOpen;
+ int mArchivedMessages;
+ uint mArchivedSize;
+ KPIM::ProgressItem *mProgressItem;
+ bool mAborted;
+ bool mDeleteFoldersAfterCompletion;
+
+ // True if we obtained ownership of the kMMessage after calling getMsg(), since we need
+ // to call ungetMsg() then. For that, we also remember the original index.
+ bool mUnget;
+ int mMessageIndex;
+
+ TQPtrList<KMFolder> mPendingFolders;
+ KMFolder *mCurrentFolder;
+ TQValueList<unsigned long> mPendingMessages;
+ KMMessage *mCurrentMessage;
+ FolderJob *mCurrentJob;
+};
+
+}
+
+#endif
diff --git a/kmail/bodypartformatter.cpp b/kmail/bodypartformatter.cpp
index efe12f672..6b61b9bce 100644
--- a/kmail/bodypartformatter.cpp
+++ b/kmail/bodypartformatter.cpp
@@ -39,6 +39,7 @@
#include "objecttreeparser.h"
#include "partNode.h"
+#include "callback.h"
#include <mimelib/enum.h>
#include <mimelib/string.h>
@@ -53,7 +54,7 @@ namespace {
public KMail::Interface::BodyPartFormatter {
static const AnyTypeBodyPartFormatter * self;
public:
- Result format( KMail::Interface::BodyPart *, KMail::HtmlWriter * ) const {
+ Result format( KMail::Interface::BodyPart *, KMail::HtmlWriter *, KMail::Callback & ) const {
kdDebug(5006) << "AnyTypeBodyPartFormatter::format() acting as a KMail::Interface::BodyPartFormatter!" << endl;
return AsIcon;
}
diff --git a/kmail/cachedimapjob.cpp b/kmail/cachedimapjob.cpp
index 3b8ff4115..2393b2576 100644
--- a/kmail/cachedimapjob.cpp
+++ b/kmail/cachedimapjob.cpp
@@ -452,18 +452,21 @@ void CachedImapJob::slotPutMessageDataReq(KIO::Job *job, TQByteArray &data)
}
//----------------------------------------------------------------------------
-void CachedImapJob::slotPutMessageInfoData(KIO::Job *job, const TQString &data)
+void CachedImapJob::slotPutMessageInfoData( KIO::Job *job, const TQString &data )
{
- KMFolderCachedImap * imapFolder = static_cast<KMFolderCachedImap*>(mDestFolder->storage());
- KMAcctCachedImap *account = imapFolder->account();
- ImapAccountBase::JobIterator it = account->findJob( job );
- if ( it == account->jobsEnd() ) return;
+ KMFolderCachedImap *imapFolder = static_cast<KMFolderCachedImap*>( mDestFolder->storage() );
+ if ( imapFolder ) {
+ KMAcctCachedImap *account = imapFolder->account();
+ ImapAccountBase::JobIterator it = account->findJob( job );
+ if ( it == account->jobsEnd() ) {
+ return;
+ }
- if ( data.find("UID") != -1 && mMsg )
- {
- int uid = (data.right(data.length()-4)).toInt();
- kdDebug( 5006 ) << k_funcinfo << "Server told us uid is: " << uid << endl;
- mMsg->setUID( uid );
+ if ( data.find( "UID" ) != -1 && mMsg ) {
+ int uid = ( data.right( data.length() - 4 ) ).toInt();
+ kdDebug( 5006 ) << k_funcinfo << "Server told us uid is: " << uid << endl;
+ mMsg->setUID( uid );
+ }
}
}
@@ -728,20 +731,23 @@ void CachedImapJob::slotCheckUidValidityResult(KIO::Job * job)
void CachedImapJob::renameFolder( const TQString &newName )
{
+ mNewName = newName;
+
// Set the source URL
KURL urlSrc = mAccount->getUrl();
- urlSrc.setPath( mFolder->imapPath() );
+ mOldImapPath = mFolder->imapPath();
+ urlSrc.setPath( mOldImapPath );
// Set the destination URL - this is a bit trickier
KURL urlDst = mAccount->getUrl();
- TQString imapPath( mFolder->imapPath() );
+ mNewImapPath = mFolder->imapPath();
// Destination url = old imappath - oldname + new name
- imapPath.truncate( imapPath.length() - mFolder->folder()->name().length() - 1);
- imapPath += newName + '/';
- urlDst.setPath( imapPath );
+ mNewImapPath.truncate( mNewImapPath.length() - mFolder->folder()->name().length() - 1);
+ mNewImapPath += newName + '/';
+ urlDst.setPath( mNewImapPath );
ImapAccountBase::jobData jd( newName, mFolder->folder() );
- jd.path = imapPath;
+ jd.path = mNewImapPath;
KIO::SimpleJob *simpleJob = KIO::rename( urlSrc, urlDst, false );
KIO::Scheduler::assignJobToSlave( mAccount->slave(), simpleJob );
@@ -774,6 +780,70 @@ static void renameChildFolders( KMFolderDir* dir, const TQString& oldPath,
}
}
+void CachedImapJob::revertLabelChange()
+{
+ TQMap<TQString, KMAcctCachedImap::RenamedFolder>::ConstIterator renit = mAccount->renamedFolders().find( mFolder->imapPath() );
+ Q_ASSERT( renit != mAccount->renamedFolders().end() );
+ if ( renit != mAccount->renamedFolders().end() ) {
+ mFolder->folder()->setLabel( (*renit).mOldLabel );
+ mAccount->removeRenamedFolder( mFolder->imapPath() );
+ kmkernel->dimapFolderMgr()->contentsChanged();
+ }
+}
+
+void CachedImapJob::renameOnDisk()
+{
+ TQString oldName = mFolder->name();
+ TQString oldPath = mFolder->imapPath();
+ mAccount->removeRenamedFolder( oldPath );
+ mFolder->setImapPath( mNewImapPath );
+ mFolder->FolderStorage::rename( mNewName );
+
+ if( oldPath.endsWith( "/" ) ) oldPath.truncate( oldPath.length() -1 );
+ TQString newPath = mFolder->imapPath();
+ if( newPath.endsWith( "/" ) ) newPath.truncate( newPath.length() -1 );
+ renameChildFolders( mFolder->folder()->child(), oldPath, newPath );
+ kmkernel->dimapFolderMgr()->contentsChanged();
+}
+
+void CachedImapJob::slotSubscribtionChange1Failed( const TQString &errorMessage )
+{
+ KMessageBox::sorry( 0, i18n( "Error while trying to subscribe to the renamed folder %1.\n"
+ "Renaming itself was successful, but the renamed folder might disappear "
+ "from the folder list after the next sync since it is unsubscribed on the server.\n"
+ "You can try to manually subscribe to the folder yourself.\n\n"
+ "%2" )
+ .arg( mFolder->label() ).arg( errorMessage ) );
+ delete this;
+}
+
+void CachedImapJob::slotSubscribtionChange2Failed( const TQString &errorMessage )
+{
+ kdWarning(5006) << k_funcinfo << errorMessage << endl;
+ // Ignore this error, not something user-visible anyway
+ delete this;
+}
+
+void CachedImapJob::slotSubscribtionChange1Done( const TQString&, bool )
+{
+ disconnect( mAccount, TQT_SIGNAL( subscriptionChanged( const TQString&, bool ) ),
+ this, TQT_SLOT( slotSubscribtionChange1Done( const TQString&, bool ) ) );
+ connect( mAccount, TQT_SIGNAL( subscriptionChanged( const TQString&, bool ) ),
+ this, TQT_SLOT( slotSubscribtionChange2Done( const TQString&, bool ) ) );
+ disconnect( mAccount, TQT_SIGNAL( subscriptionChangeFailed( const TQString& ) ),
+ this, TQT_SLOT( slotSubscribtionChange1Failed( const TQString& ) ) );
+ connect( mAccount, TQT_SIGNAL( subscriptionChangeFailed( const TQString& ) ),
+ this, TQT_SLOT( slotSubscribtionChange2Failed( const TQString& ) ) );
+
+ mAccount->changeSubscription( false, mOldImapPath, true /* quiet */ );
+}
+
+void CachedImapJob::slotSubscribtionChange2Done( const TQString&, bool )
+{
+ // Finally done with everything!
+ delete this;
+}
+
void CachedImapJob::slotRenameFolderResult( KIO::Job *job )
{
KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
@@ -782,34 +852,25 @@ void CachedImapJob::slotRenameFolderResult( KIO::Job *job )
return;
}
-
if( job->error() ) {
- // Error, revert label change
- TQMap<TQString, KMAcctCachedImap::RenamedFolder>::ConstIterator renit = mAccount->renamedFolders().find( mFolder->imapPath() );
- Q_ASSERT( renit != mAccount->renamedFolders().end() );
- if ( renit != mAccount->renamedFolders().end() ) {
- mFolder->folder()->setLabel( (*renit).mOldLabel );
- mAccount->removeRenamedFolder( mFolder->imapPath() );
- }
- mAccount->handleJobError( job, i18n( "Error while trying to rename folder %1" ).arg( mFolder->label() ) + '\n' );
+ revertLabelChange();
+ const TQString errorMessage = i18n( "Error while trying to rename folder %1" ).arg( mFolder->label() );
+ mAccount->handleJobError( job, errorMessage );
+ delete this;
} else {
- // Okay, the folder seems to be renamed on the server,
- // now rename it on disk
- TQString oldName = mFolder->name();
- TQString oldPath = mFolder->imapPath();
- mAccount->removeRenamedFolder( oldPath );
- mFolder->setImapPath( (*it).path );
- mFolder->FolderStorage::rename( (*it).url );
-
- if( oldPath.endsWith( "/" ) ) oldPath.truncate( oldPath.length() -1 );
- TQString newPath = mFolder->imapPath();
- if( newPath.endsWith( "/" ) ) newPath.truncate( newPath.length() -1 );
- renameChildFolders( mFolder->folder()->child(), oldPath, newPath );
- kmkernel->dimapFolderMgr()->contentsChanged();
- mAccount->removeJob(it);
+ mAccount->removeJob( it );
+ renameOnDisk();
+
+ // Okay, the folder seems to be renamed on the server and on disk.
+ // Now unsubscribe from the old folder name and subscribe to the new folder name,
+ // so that the folder doesn't suddenly disappear after renaming it
+ connect( mAccount, TQT_SIGNAL( subscriptionChangeFailed( const TQString& ) ),
+ this, TQT_SLOT( slotSubscribtionChange1Failed( const TQString& ) ) );
+ connect( mAccount, TQT_SIGNAL( subscriptionChanged( const TQString&, bool ) ),
+ this, TQT_SLOT( slotSubscribtionChange1Done( const TQString&, bool ) ) );
+ mAccount->changeSubscription( true, mNewImapPath, true /* quiet */ );
}
- delete this;
}
void CachedImapJob::slotListMessagesResult( KIO::Job * job )
diff --git a/kmail/cachedimapjob.h b/kmail/cachedimapjob.h
index 6581ec742..4a2885b00 100644
--- a/kmail/cachedimapjob.h
+++ b/kmail/cachedimapjob.h
@@ -121,8 +121,16 @@ protected slots:
virtual void slotListMessagesResult( KIO::Job * job );
void slotDeleteNextMessages( KIO::Job* job = 0 );
void slotProcessedSize( KIO::Job *, KIO::filesize_t processed );
+ void slotSubscribtionChange1Done( const TQString&, bool );
+ void slotSubscribtionChange2Done( const TQString&, bool );
+ void slotSubscribtionChange1Failed( const TQString &errorMessage );
+ void slotSubscribtionChange2Failed( const TQString &errorMessage );
private:
+
+ void renameOnDisk();
+ void revertLabelChange();
+
KMFolderCachedImap *mFolder;
KMAcctCachedImap *mAccount;
TQValueList<KMFolderCachedImap*> mFolderList;
@@ -133,6 +141,7 @@ private:
TQStringList mFoldersOrMessages; // Folder deletion: path list. Message deletion: sets of uids
KMMessage* mMsg;
TQString mString; // Used as uids and as rename target
+ TQString mOldImapPath, mNewImapPath, mNewName; // used for renaming
KMFolderCachedImap *mParentFolder;
};
diff --git a/kmail/callback.cpp b/kmail/callback.cpp
index 0e25758c1..be787ff8e 100644
--- a/kmail/callback.cpp
+++ b/kmail/callback.cpp
@@ -41,6 +41,7 @@
#include "composer.h"
#include "kmreaderwin.h"
#include "secondarywindow.h"
+#include "transportmanager.h"
#include <mimelib/enum.h>
@@ -56,6 +57,32 @@ Callback::Callback( KMMessage* msg, KMReaderWin* readerWin )
{
}
+TQString Callback::askForTransport( bool nullIdentity ) const
+{
+ const TQStringList transports = KMail::TransportManager::transportNames();
+ if ( transports.size() == 1 )
+ return transports.first();
+
+ const TQString defaultTransport = GlobalSettings::self()->defaultTransport();
+ const int defaultIndex = QMAX( 0, transports.findIndex( defaultTransport ) );
+
+ TQString text;
+ if ( nullIdentity )
+ text = i18n( "<qt>The receiver of this invitation doesn't match any of your identities.<br>"
+ "Please select the transport which should be used to send your reply.</qt>" );
+ else
+ text = i18n( "<qt>The identity matching the receiver of this invitation doesn't have an "
+ "associated transport configured.<br>"
+ "Please select the transport which should be used to send your reply.</qt>");
+ bool ok;
+ const TQString transport = KInputDialog::getItem( i18n( "Select Transport" ), text,
+ transports, defaultIndex, FALSE, &ok, kmkernel->mainWin() );
+ if ( !ok )
+ return TQString();
+
+ return transport;
+}
+
bool Callback::mailICal( const TQString& to, const TQString &iCal,
const TQString& subject, const TQString &status,
bool delMessage ) const
@@ -67,13 +94,13 @@ bool Callback::mailICal( const TQString& to, const TQString &iCal,
msg->setSubject( subject );
if ( GlobalSettings::self()->exchangeCompatibleInvitations() ) {
if ( status == TQString("cancel") )
- msg->setSubject( TQString("Declined: %1").arg(subject).replace("Answer: ","") );
+ msg->setSubject( i18n( "Declined: %1" ).arg(subject).replace("Answer: ","") );
else if ( status == TQString("tentative") )
- msg->setSubject(TQString("Tentative: %1").arg(subject).replace("Answer: ","") );
+ msg->setSubject( i18n( "Tentative: %1" ).arg(subject).replace("Answer: ","") );
else if ( status == TQString("accepted") )
- msg->setSubject( TQString("Accepted: %1").arg(subject).replace("Answer: ","") );
+ msg->setSubject( i18n( "Accepted: %1" ).arg(subject).replace("Answer: ","") );
else if ( status == TQString("delegated") )
- msg->setSubject( TQString("Delegated: %1").arg(subject).replace("Answer: ","") );
+ msg->setSubject( i18n( "Delegated: %1" ).arg(subject).replace("Answer: ","") );
}
msg->setTo( to );
msg->setFrom( receiver() );
@@ -89,23 +116,40 @@ bool Callback::mailICal( const TQString& to, const TQString &iCal,
* has been sent successfully. Set a link header which accomplishes that. */
msg->link( mMsg, KMMsgStatusDeleted );
+ // Try and match the receiver with an identity.
+ // Setting the identity here is important, as that is used to select the correct
+ // transport later
+ const KPIM::Identity& identity = kmkernel->identityManager()->identityForAddress( receiver() );
+ const bool nullIdentity = ( identity == KPIM::Identity::null() );
+ if ( !nullIdentity ) {
+ msg->setHeaderField("X-KMail-Identity", TQString::number( identity.uoid() ));
+ }
+
+ const bool identityHasTransport = !identity.transport().isEmpty();
+ if ( !nullIdentity && identityHasTransport )
+ msg->setHeaderField( "X-KMail-Transport", identity.transport() );
+ else if ( !nullIdentity && identity.isDefault() )
+ msg->setHeaderField( "X-KMail-Transport", GlobalSettings::self()->defaultTransport() );
+ else {
+ const TQString transport = askForTransport( nullIdentity );
+ if ( transport.isEmpty() )
+ return false; // user canceled transport selection dialog
+ msg->setHeaderField( "X-KMail-Transport", transport );
+ }
+
// Outlook will only understand the reply if the From: header is the
// same as the To: header of the invitation message.
KConfigGroup options( KMKernel::config(), "Groupware" );
if( !options.readBoolEntry( "LegacyMangleFromToHeaders", true ) ) {
- // Try and match the receiver with an identity
- const KPIM::Identity& identity =
- kmkernel->identityManager()->identityForAddress( receiver() );
if( identity != KPIM::Identity::null() ) {
- // Identity found. Use this
msg->setFrom( identity.fullEmailAddr() );
- msg->setHeaderField("X-KMail-Identity", TQString::number( identity.uoid() ));
}
// Remove BCC from identity on ical invitations (https://intevation.de/roundup/kolab/issue474)
msg->setBcc( "" );
}
KMail::Composer * cWin = KMail::makeComposer();
+ cWin->ignoreStickyFields();
cWin->setMsg( msg, false /* mayAutoSign */ );
// cWin->setCharset( "", true );
cWin->disableWordWrap();
@@ -126,6 +170,8 @@ bool Callback::mailICal( const TQString& to, const TQString &iCal,
cWin->addAttach( msgPart );
}
+ cWin->disableRecipientNumberCheck();
+ cWin->disableForgottenAttachmentsCheck();
if ( options.readBoolEntry( "AutomaticSending", true ) ) {
cWin->setAutoDeleteWindow( true );
cWin->slotSendNow();
@@ -170,7 +216,7 @@ TQString Callback::receiver() const
selectMessage = i18n("<qt>None of your identities match the "
"receiver of this message,<br>please "
"choose which of the following addresses "
- "is yours, if any:");
+ "is yours, if any, or select one of your identities to use in the reply:");
addrs += kmkernel->identityManager()->allEmails();
} else {
selectMessage = i18n("<qt>Several of your identities match the "
@@ -179,10 +225,14 @@ TQString Callback::receiver() const
"is yours:");
}
+ // select default identity by default
+ const TQString defaultAddr = kmkernel->identityManager()->defaultIdentity().primaryEmailAddress();
+ const int defaultIndex = QMAX( 0, addrs.findIndex( defaultAddr ) );
+
mReceiver =
KInputDialog::getItem( i18n( "Select Address" ),
selectMessage,
- addrs+ccaddrs, 0, FALSE, &ok, kmkernel->mainWin() );
+ addrs+ccaddrs, defaultIndex, FALSE, &ok, kmkernel->mainWin() );
if( !ok )
mReceiver = TQString::null;
}
@@ -213,6 +263,16 @@ bool Callback::deleteInvitationAfterReply() const
return GlobalSettings::self()->deleteInvitationEmailsAfterSendingReply();
}
+bool Callback::exchangeCompatibleInvitations() const
+{
+ return GlobalSettings::self()->exchangeCompatibleInvitations();
+}
+
+bool Callback::outlookCompatibleInvitationReplyComments() const
+{
+ return GlobalSettings::self()->outlookCompatibleInvitationReplyComments();
+}
+
TQString Callback::sender() const
{
return mMsg->from();
diff --git a/kmail/callback.h b/kmail/callback.h
index 9bd188899..c7f26058f 100644
--- a/kmail/callback.h
+++ b/kmail/callback.h
@@ -77,8 +77,12 @@ public:
bool askForComment( KCal::Attendee::PartStat status ) const;
bool deleteInvitationAfterReply() const;
+ bool exchangeCompatibleInvitations() const;
+ bool outlookCompatibleInvitationReplyComments() const;
private:
+ TQString askForTransport( bool nullIdentity ) const;
+
KMMessage* mMsg;
KMReaderWin* mReaderWin;
mutable TQString mReceiver;
diff --git a/kmail/composer.h b/kmail/composer.h
index 4c176aa14..91c473445 100644
--- a/kmail/composer.h
+++ b/kmail/composer.h
@@ -66,12 +66,19 @@ namespace KMail {
virtual void setMsg( KMMessage * newMsg, bool mayAutoSign=true,
bool allowDecryption=false, bool isModified=false) = 0;
+ /**
+ * Returns @c true while the message composing is in progress.
+ */
+ virtual bool isComposing() const = 0;
+
public: // kmkernel
/**
* Set the filename which is used for autosaving.
*/
virtual void setAutoSaveFilename( const TQString & filename ) = 0;
+
+
public: // kmkernel, callback
/**
* If this flag is set the message of the composer is deleted when
@@ -141,6 +148,12 @@ namespace KMail {
virtual void disableWordWrap() = 0;
+ virtual void disableRecipientNumberCheck() = 0;
+
+ virtual void disableForgottenAttachmentsCheck() = 0;
+
+ virtual void ignoreStickyFields() = 0;
+
public: // kmcommand
/**
* Add an attachment to the list.
diff --git a/kmail/configuredialog.cpp b/kmail/configuredialog.cpp
index ea0536a9f..32399f815 100644
--- a/kmail/configuredialog.cpp
+++ b/kmail/configuredialog.cpp
@@ -99,6 +99,7 @@ using KMime::DateFormatter;
#include <kconfig.h>
#include <kactivelabel.h>
#include <kcmultidialog.h>
+#include <kcombobox.h>
// Qt headers:
#include <tqvalidator.h>
@@ -252,13 +253,15 @@ ConfigureDialog::~ConfigureDialog() {
}
void ConfigureDialog::slotApply() {
- GlobalSettings::self()->writeConfig();
KCMultiDialog::slotApply();
+ GlobalSettings::self()->writeConfig();
+ emit configChanged();
}
void ConfigureDialog::slotOk() {
- GlobalSettings::self()->writeConfig();
KCMultiDialog::slotOk();
+ GlobalSettings::self()->writeConfig();
+ emit configChanged();
}
void ConfigureDialog::slotUser2() {
@@ -767,7 +770,6 @@ void AccountsPage::SendingTab::slotSetDefaultTransport()
} else {
item->setText( 1, i18n( "sendmail (Default)" ));
}
-
GlobalSettings::self()->setDefaultTransport( item->text(0) );
}
@@ -901,6 +903,10 @@ void AccountsPage::SendingTab::slotRemoveSelectedTransport()
TQListViewItem *item = mTransportList->selectedItem();
if ( !item ) return;
+ bool selectedTransportWasDefault = false;
+ if ( item->text( 0 ) == GlobalSettings::self()->defaultTransport() ) {
+ selectedTransportWasDefault = true;
+ }
TQStringList changedIdents;
KPIM::IdentityManager * im = kmkernel->identityManager();
for ( KPIM::IdentityManager::Iterator it = im->modifyBegin(); it != im->modifyEnd(); ++it ) {
@@ -930,25 +936,25 @@ void AccountsPage::SendingTab::slotRemoveSelectedTransport()
KMTransportInfo ti;
- TQListViewItem *newCurrent = item->itemBelow();
- if ( !newCurrent ) newCurrent = item->itemAbove();
- //mTransportList->removeItem( item );
- if ( newCurrent ) {
- mTransportList->setCurrentItem( newCurrent );
- mTransportList->setSelected( newCurrent, true );
- GlobalSettings::self()->setDefaultTransport( newCurrent->text(0) );
- ti.readConfig( KMTransportInfo::findTransport( newCurrent->text(0) ));
- if ( item->text( 0 ) == GlobalSettings::self()->defaultTransport() ) {
+ if( selectedTransportWasDefault )
+ {
+ TQListViewItem *newCurrent = item->itemBelow();
+ if ( !newCurrent ) newCurrent = item->itemAbove();
+ //mTransportList->removeItem( item );
+ if ( newCurrent ) {
+ mTransportList->setCurrentItem( newCurrent );
+ mTransportList->setSelected( newCurrent, true );
+ GlobalSettings::self()->setDefaultTransport( newCurrent->text(0) );
+ ti.readConfig( KMTransportInfo::findTransport( newCurrent->text(0) ));
if ( ti.type != "sendmail" ) {
newCurrent->setText( 1, i18n("smtp (Default)") );
} else {
newCurrent->setText( 1, i18n("sendmail (Default)" ));
}
+ } else {
+ GlobalSettings::self()->setDefaultTransport( TQString::null );
}
- } else {
- GlobalSettings::self()->setDefaultTransport( TQString::null );
}
-
delete item;
mTransportInfoList.remove( it );
@@ -1760,6 +1766,7 @@ AppearancePageColorsTab::AppearancePageColorsTab( TQWidget * parent, const char
mCloseToQuotaThreshold = new TQSpinBox( 0, 100, 1, this );
connect( mCloseToQuotaThreshold, TQT_SIGNAL( valueChanged( int ) ),
this, TQT_SLOT( slotEmitChanged( void ) ) );
+ mCloseToQuotaThreshold->setEnabled( false );
mCloseToQuotaThreshold->setSuffix( i18n("%"));
hbox->addWidget( mCloseToQuotaThreshold );
hbox->addWidget( new TQWidget(this), 2 );
@@ -1771,6 +1778,8 @@ AppearancePageColorsTab::AppearancePageColorsTab( TQWidget * parent, const char
mRecycleColorCheck, TQT_SLOT(setEnabled(bool)) );
connect( mCustomColorCheck, TQT_SIGNAL(toggled(bool)),
l, TQT_SLOT(setEnabled(bool)) );
+ connect( mCustomColorCheck, TQT_SIGNAL(toggled(bool)),
+ mCloseToQuotaThreshold, TQT_SLOT(setEnabled(bool)) );
connect( mCustomColorCheck, TQT_SIGNAL( stateChanged( int ) ),
this, TQT_SLOT( slotEmitChanged( void ) ) );
@@ -1909,10 +1918,6 @@ AppearancePageLayoutTab::AppearancePageLayoutTab( TQWidget * parent, const char
connect( mFavoriteFolderViewCB, TQT_SIGNAL(toggled(bool)), TQT_SLOT(slotEmitChanged()) );
vlay->addWidget( mFavoriteFolderViewCB );
- mFolderQuickSearchCB = new TQCheckBox( i18n("Show folder quick search field"), this );
- connect( mFolderQuickSearchCB, TQT_SIGNAL(toggled(bool)), TQT_SLOT(slotEmitChanged()) );
- vlay->addWidget( mFolderQuickSearchCB );
-
// "show reader window" radio buttons:
populateButtonGroup( mReaderWindowModeGroup = new TQVButtonGroup( this ), readerWindowMode );
vlay->addWidget( mReaderWindowModeGroup );
@@ -1943,7 +1948,6 @@ void AppearancePage::LayoutTab::doLoadOther() {
loadWidget( mMIMETreeModeGroup, reader, mimeTreeMode );
loadWidget( mReaderWindowModeGroup, geometry, readerWindowMode );
mFavoriteFolderViewCB->setChecked( GlobalSettings::self()->enableFavoriteFolderView() );
- mFolderQuickSearchCB->setChecked( GlobalSettings::self()->enableFolderQuickSearch() );
}
void AppearancePage::LayoutTab::installProfile( KConfig * profile ) {
@@ -1965,7 +1969,6 @@ void AppearancePage::LayoutTab::save() {
saveButtonGroup( mMIMETreeModeGroup, reader, mimeTreeMode );
saveButtonGroup( mReaderWindowModeGroup, geometry, readerWindowMode );
GlobalSettings::self()->setEnableFavoriteFolderView( mFavoriteFolderViewCB->isChecked() );
- GlobalSettings::self()->setEnableFolderQuickSearch( mFolderQuickSearchCB->isChecked() );
}
//
@@ -2003,8 +2006,6 @@ AppearancePageHeadersTab::AppearancePageHeadersTab( TQWidget * parent, const cha
group = new TQVButtonGroup( i18n( "General Options" ), this );
group->layout()->setSpacing( KDialog::spacingHint() );
- mShowQuickSearch = new TQCheckBox( i18n("Show Quick Search"), group );
-
mMessageSizeCheck = new TQCheckBox( i18n("Display messa&ge sizes"), group );
mCryptoIconsCheck = new TQCheckBox( i18n( "Show crypto &icons" ), group );
@@ -2014,8 +2015,6 @@ AppearancePageHeadersTab::AppearancePageHeadersTab( TQWidget * parent, const cha
mNestedMessagesCheck =
new TQCheckBox( i18n("&Threaded message list"), group );
- connect( mShowQuickSearch, TQT_SIGNAL( stateChanged( int ) ),
- this, TQT_SLOT( slotEmitChanged( void ) ) );
connect( mMessageSizeCheck, TQT_SIGNAL( stateChanged( int ) ),
this, TQT_SLOT( slotEmitChanged( void ) ) );
connect( mAttachmentCheck, TQT_SIGNAL( stateChanged( int ) ),
@@ -2123,7 +2122,6 @@ void AppearancePage::HeadersTab::doLoadOther() {
mMessageSizeCheck->setChecked( general.readBoolEntry( "showMessageSize", false ) );
mCryptoIconsCheck->setChecked( general.readBoolEntry( "showCryptoIcons", false ) );
mAttachmentCheck->setChecked( general.readBoolEntry( "showAttachmentIcon", true ) );
- mShowQuickSearch->setChecked( GlobalSettings::self()->quickSearchActive() );
// "Message Header Threading Options":
int num = geometry.readNumEntry( "nestingPolicy", 3 );
@@ -2204,7 +2202,6 @@ void AppearancePage::HeadersTab::save() {
general.writeEntry( "showMessageSize", mMessageSizeCheck->isChecked() );
general.writeEntry( "showCryptoIcons", mCryptoIconsCheck->isChecked() );
general.writeEntry( "showAttachmentIcon", mAttachmentCheck->isChecked() );
- GlobalSettings::self()->setQuickSearchActive( mShowQuickSearch->isChecked() );
int dateDisplayID = mDateDisplay->id( mDateDisplay->selected() );
// check bounds:
@@ -2220,6 +2217,10 @@ void AppearancePage::HeadersTab::save() {
//
+static const BoolConfigEntry closeAfterReplyOrForward = {
+ "Reader", "CloseAfterReplyOrForward", I18N_NOOP("Close message window after replying or forwarding"), false
+};
+
static const BoolConfigEntry showColorbarMode = {
"Reader", "showColorbar", I18N_NOOP("Show HTML stat&us bar"), false
};
@@ -2251,6 +2252,15 @@ AppearancePageReaderTab::AppearancePageReaderTab( TQWidget * parent,
{
TQVBoxLayout *vlay = new TQVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
+ // "close message window after replying or forwarding" checkbox
+ populateCheckBox( mCloseAfterReplyOrForwardCheck = new TQCheckBox( this ),
+ closeAfterReplyOrForward );
+ TQToolTip::add( mCloseAfterReplyOrForwardCheck,
+ i18n( "Close the standalone message window after replying or forwarding the message" ) );
+ vlay->addWidget( mCloseAfterReplyOrForwardCheck );
+ connect( mCloseAfterReplyOrForwardCheck, TQT_SIGNAL ( stateChanged( int ) ),
+ this, TQT_SLOT( slotEmitChanged() ) );
+
// "show colorbar" check box:
populateCheckBox( mShowColorbarCheck = new TQCheckBox( this ), showColorbarMode );
vlay->addWidget( mShowColorbarCheck );
@@ -2403,6 +2413,7 @@ void AppearancePage::ReaderTab::readCurrentOverrideCodec()
void AppearancePage::ReaderTab::doLoadFromGlobalSettings()
{
+ mCloseAfterReplyOrForwardCheck->setChecked( GlobalSettings::self()->closeAfterReplyOrForward() );
mShowEmoticonsCheck->setChecked( GlobalSettings::self()->showEmoticons() );
mShrinkQuotesCheck->setChecked( GlobalSettings::self()->shrinkQuotes() );
mShowExpandQuotesMark->setChecked( GlobalSettings::self()->showExpandQuotesMark() );
@@ -2423,6 +2434,7 @@ void AppearancePage::ReaderTab::save() {
KConfigGroup reader( KMKernel::config(), "Reader" );
saveCheckBox( mShowColorbarCheck, reader, showColorbarMode );
saveCheckBox( mShowSpamStatusCheck, reader, showSpamStatusMode );
+ GlobalSettings::self()->setCloseAfterReplyOrForward( mCloseAfterReplyOrForwardCheck->isChecked() );
GlobalSettings::self()->setShowEmoticons( mShowEmoticonsCheck->isChecked() );
GlobalSettings::self()->setShrinkQuotes( mShrinkQuotesCheck->isChecked() );
GlobalSettings::self()->setShowExpandQuotesMark( mShowExpandQuotesMark->isChecked() );
@@ -2439,6 +2451,7 @@ void AppearancePage::ReaderTab::save() {
void AppearancePage::ReaderTab::installProfile( KConfig * /* profile */ ) {
const KConfigGroup reader( KMKernel::config(), "Reader" );
+ loadProfile( mCloseAfterReplyOrForwardCheck, reader, closeAfterReplyOrForward );
loadProfile( mShowColorbarCheck, reader, showColorbarMode );
loadProfile( mShowSpamStatusCheck, reader, showSpamStatusMode );
loadProfile( mShowEmoticonsCheck, reader, showEmoticons );
@@ -2605,10 +2618,29 @@ ComposerPageGeneralTab::ComposerPageGeneralTab( TQWidget * parent, const char *
mSmartQuoteCheck = new TQCheckBox(
GlobalSettings::self()->smartQuoteItem()->label(),
this, "kcfg_SmartQuote" );
+ TQToolTip::add( mSmartQuoteCheck,
+ i18n( "When replying, add quote signs in front of all lines of the quoted text,\n"
+ "even when the line was created by adding an additional linebreak while\n"
+ "word-wrapping the text." ) );
vlay->addWidget( mSmartQuoteCheck );
connect( mSmartQuoteCheck, TQT_SIGNAL( stateChanged(int) ),
this, TQT_SLOT( slotEmitChanged( void ) ) );
+ mQuoteSelectionOnlyCheck = new TQCheckBox( GlobalSettings::self()->quoteSelectionOnlyItem()->label(),
+ this, "kcfg_QuoteSelectionOnly" );
+ TQToolTip::add( mQuoteSelectionOnlyCheck,
+ i18n( "When replying, only quote the selected text instead of the complete message "
+ "when there is text selected in the message window." ) );
+ vlay->addWidget( mQuoteSelectionOnlyCheck );
+ connect( mQuoteSelectionOnlyCheck, TQT_SIGNAL( stateChanged(int) ),
+ this, TQT_SLOT( slotEmitChanged(void) ) );
+
+ mStripSignatureCheck = new TQCheckBox( GlobalSettings::self()->stripSignatureItem()->label(),
+ this, "kcfg_StripSignature" );
+ vlay->addWidget( mStripSignatureCheck );
+ connect( mStripSignatureCheck, TQT_SIGNAL( stateChanged(int) ),
+ this, TQT_SLOT( slotEmitChanged( void ) ) );
+
mAutoRequestMDNCheck = new TQCheckBox(
GlobalSettings::self()->requestMDNItem()->label(),
this, "kcfg_RequestMDN" );
@@ -2645,6 +2677,41 @@ ComposerPageGeneralTab::ComposerPageGeneralTab( TQWidget * parent, const char *
connect( mWordWrapCheck, TQT_SIGNAL(toggled(bool)),
mWrapColumnSpin, TQT_SLOT(setEnabled(bool)) );
+ // a checkbox for "too many recipient warning" and a spinbox for the recipient threshold
+ hlay = new TQHBoxLayout( vlay ); // inherits spacing
+ mRecipientCheck = new TQCheckBox(
+ GlobalSettings::self()->tooManyRecipientsItem()->label(),
+ this, "kcfg_TooManyRecipients" );
+ hlay->addWidget( mRecipientCheck );
+ connect( mRecipientCheck, TQT_SIGNAL( stateChanged(int) ),
+ this, TQT_SLOT( slotEmitChanged( void ) ) );
+
+ TQString recipientCheckWhatsthis =
+ i18n( GlobalSettings::self()->tooManyRecipientsItem()->whatsThis().utf8() );
+ TQWhatsThis::add( mRecipientCheck, recipientCheckWhatsthis );
+ TQToolTip::add( mRecipientCheck,
+ i18n( "Warn if too many recipients are specified" ) );
+
+ mRecipientSpin = new KIntSpinBox( 1/*min*/, 100/*max*/, 1/*step*/,
+ 5/*init*/, 10 /*base*/, this, "kcfg_RecipientThreshold" );
+ mRecipientSpin->setEnabled( false );
+ connect( mRecipientSpin, TQT_SIGNAL( valueChanged(int) ),
+ this, TQT_SLOT( slotEmitChanged( void ) ) );
+
+ TQString recipientWhatsthis =
+ i18n( GlobalSettings::self()->recipientThresholdItem()->whatsThis().utf8() );
+ TQWhatsThis::add( mRecipientSpin, recipientWhatsthis );
+ TQToolTip::add( mRecipientSpin,
+ i18n( "Warn if more than this many recipients are specified" ) );
+
+
+ hlay->addWidget( mRecipientSpin );
+ hlay->addStretch( 1 );
+ // only enable the spinbox if the checkbox is checked:
+ connect( mRecipientCheck, TQT_SIGNAL(toggled(bool)),
+ mRecipientSpin, TQT_SLOT(setEnabled(bool)) );
+
+
hlay = new TQHBoxLayout( vlay ); // inherits spacing
mAutoSave = new KIntSpinBox( 0, 60, 1, 1, 10, this, "kcfg_AutosaveInterval" );
label = new TQLabel( mAutoSave,
@@ -2658,6 +2725,20 @@ ComposerPageGeneralTab::ComposerPageGeneralTab( TQWidget * parent, const char *
this, TQT_SLOT( slotEmitChanged( void ) ) );
hlay = new TQHBoxLayout( vlay ); // inherits spacing
+ mForwardTypeCombo = new KComboBox( false, this );
+ label = new TQLabel( mForwardTypeCombo,
+ i18n( "Default Forwarding Type:" ),
+ this );
+ mForwardTypeCombo->insertStringList( TQStringList()
+ << i18n( "Inline" )
+ << i18n( "As Attachment" ) );
+ hlay->addWidget( label );
+ hlay->addWidget( mForwardTypeCombo );
+ hlay->addStretch( 1 );
+ connect( mForwardTypeCombo, TQT_SIGNAL(activated(int)),
+ this, TQT_SLOT( slotEmitChanged( void ) ) );
+
+ hlay = new TQHBoxLayout( vlay ); // inherits spacing
TQPushButton *completionOrderBtn = new TQPushButton( i18n( "Configure Completion Order" ), this );
connect( completionOrderBtn, TQT_SIGNAL( clicked() ),
this, TQT_SLOT( slotConfigureCompletionOrder() ) );
@@ -2721,11 +2802,19 @@ void ComposerPage::GeneralTab::doLoadFromGlobalSettings() {
GlobalSettings::self()->autoTextSignature()=="auto" );
mTopQuoteCheck->setChecked( GlobalSettings::self()->prependSignature() );
mSmartQuoteCheck->setChecked( GlobalSettings::self()->smartQuote() );
+ mQuoteSelectionOnlyCheck->setChecked( GlobalSettings::self()->quoteSelectionOnly() );
+ mStripSignatureCheck->setChecked( GlobalSettings::self()->stripSignature() );
mAutoRequestMDNCheck->setChecked( GlobalSettings::self()->requestMDN() );
mWordWrapCheck->setChecked( GlobalSettings::self()->wordWrap() );
mWrapColumnSpin->setValue( GlobalSettings::self()->lineWrapWidth() );
+ mRecipientCheck->setChecked( GlobalSettings::self()->tooManyRecipients() );
+ mRecipientSpin->setValue( GlobalSettings::self()->recipientThreshold() );
mAutoSave->setValue( GlobalSettings::self()->autosaveInterval() );
+ if ( GlobalSettings::self()->forwardingInlineByDefault() )
+ mForwardTypeCombo->setCurrentItem( 0 );
+ else
+ mForwardTypeCombo->setCurrentItem( 1 );
// editor group:
mExternalEditorCheck->setChecked( GlobalSettings::self()->useExternalEditor() );
@@ -2744,12 +2833,20 @@ void ComposerPage::GeneralTab::installProfile( KConfig * profile ) {
mTopQuoteCheck->setChecked( composer.readBoolEntry( "prepend-signature" ) );
if ( composer.hasKey( "smart-quote" ) )
mSmartQuoteCheck->setChecked( composer.readBoolEntry( "smart-quote" ) );
+ if ( composer.hasKey( "StripSignature" ) )
+ mStripSignatureCheck->setChecked( composer.readBoolEntry( "StripSignature" ) );
+ if ( composer.hasKey( "QuoteSelectionOnly" ) )
+ mQuoteSelectionOnlyCheck->setChecked( composer.readBoolEntry( "QuoteSelectionOnly" ) );
if ( composer.hasKey( "request-mdn" ) )
mAutoRequestMDNCheck->setChecked( composer.readBoolEntry( "request-mdn" ) );
if ( composer.hasKey( "word-wrap" ) )
mWordWrapCheck->setChecked( composer.readBoolEntry( "word-wrap" ) );
if ( composer.hasKey( "break-at" ) )
mWrapColumnSpin->setValue( composer.readNumEntry( "break-at" ) );
+ if ( composer.hasKey( "too-many-recipients" ) )
+ mRecipientCheck->setChecked( composer.readBoolEntry( "too-many-recipients" ) );
+ if ( composer.hasKey( "recipient-threshold" ) )
+ mRecipientSpin->setValue( composer.readNumEntry( "recipient-threshold" ) );
if ( composer.hasKey( "autosave" ) )
mAutoSave->setValue( composer.readNumEntry( "autosave" ) );
@@ -2765,11 +2862,16 @@ void ComposerPage::GeneralTab::save() {
mAutoAppSignFileCheck->isChecked() ? "auto" : "manual" );
GlobalSettings::self()->setPrependSignature( mTopQuoteCheck->isChecked());
GlobalSettings::self()->setSmartQuote( mSmartQuoteCheck->isChecked() );
+ GlobalSettings::self()->setQuoteSelectionOnly( mQuoteSelectionOnlyCheck->isChecked() );
+ GlobalSettings::self()->setStripSignature( mStripSignatureCheck->isChecked() );
GlobalSettings::self()->setRequestMDN( mAutoRequestMDNCheck->isChecked() );
GlobalSettings::self()->setWordWrap( mWordWrapCheck->isChecked() );
GlobalSettings::self()->setLineWrapWidth( mWrapColumnSpin->value() );
+ GlobalSettings::self()->setTooManyRecipients( mRecipientCheck->isChecked() );
+ GlobalSettings::self()->setRecipientThreshold( mRecipientSpin->value() );
GlobalSettings::self()->setAutosaveInterval( mAutoSave->value() );
+ GlobalSettings::self()->setForwardingInlineByDefault( mForwardTypeCombo->currentItem() == 0 );
// editor group:
GlobalSettings::self()->setUseExternalEditor( mExternalEditorCheck->isChecked() );
@@ -4491,7 +4593,11 @@ MiscPageFolderTab::MiscPageFolderTab( TQWidget * parent, const char * name )
<< i18n("continuation of \"When entering a folder:\"",
"Jump to First Unread or New Message")
<< i18n("continuation of \"When entering a folder:\"",
- "Jump to Last Selected Message"));
+ "Jump to Last Selected Message")
+ << i18n("continuation of \"When entering a folder:\"",
+ "Jump to Newest Message")
+ << i18n("continuation of \"When entering a folder:\"",
+ "Jump to Oldest Message") );
hlay->addWidget( label );
hlay->addWidget( mActionEnterFolder, 1 );
connect( mActionEnterFolder, TQT_SIGNAL( activated( int ) ),
@@ -4720,7 +4826,7 @@ MiscPageGroupwareTab::MiscPageGroupwareTab( TQWidget* parent, const char* name )
mStorageFormatCombo = new TQComboBox( false, mBox );
storageFormatLA->setBuddy( mStorageFormatCombo );
TQStringList formatLst;
- formatLst << i18n("Standard (Ical / Vcard)") << i18n("Kolab (XML)");
+ formatLst << i18n("Deprecated Kolab1 (iCal/vCard)") << i18n("Kolab2 (XML)");
mStorageFormatCombo->insertStringList( formatLst );
grid->addWidget( mStorageFormatCombo, 0, 1 );
TQToolTip::add( mStorageFormatCombo, toolTip );
@@ -4806,8 +4912,8 @@ MiscPageGroupwareTab::MiscPageGroupwareTab( TQWidget* parent, const char* name )
i18n( "Synchronize groupware changes in disconnected IMAP folders immediately when being online." ) );
connect( mSyncImmediately, TQT_SIGNAL(toggled(bool)), TQT_SLOT(slotEmitChanged()) );
grid->addMultiCellWidget( mSyncImmediately, 4, 4, 0, 1 );
-
- mDeleteInvitations = new TQCheckBox(
+
+ mDeleteInvitations = new TQCheckBox(
i18n( GlobalSettings::self()->deleteInvitationEmailsAfterSendingReplyItem()->label().utf8() ), mBox );
TQWhatsThis::add( mDeleteInvitations, i18n( GlobalSettings::self()
->deleteInvitationEmailsAfterSendingReplyItem()->whatsThis().utf8() ) );
@@ -4844,12 +4950,19 @@ MiscPageGroupwareTab::MiscPageGroupwareTab( TQWidget* parent, const char* name )
this, TQT_SLOT( slotEmitChanged( void ) ) );
mExchangeCompatibleInvitations = new TQCheckBox( i18n( "Exchange compatible invitation naming" ), gBox );
- TQToolTip::add( mExchangeCompatibleInvitations, i18n( "Microsoft Outlook, when used in combination with a Microsoft Exchange server, has a problem understanding standards-compliant groupware e-mail. Turn this option on to send groupware invitations in a way that Microsoft Exchange understands." ) );
+ TQToolTip::add( mExchangeCompatibleInvitations, i18n( "Outlook(tm), when used in combination with a Microsoft Exchange server,\nhas a problem understanding standards-compliant groupware e-mail.\nTurn this option on to send groupware invitations and replies in an Exchange compatible way." ) );
TQWhatsThis::add( mExchangeCompatibleInvitations, i18n( GlobalSettings::self()->
exchangeCompatibleInvitationsItem()->whatsThis().utf8() ) );
connect( mExchangeCompatibleInvitations, TQT_SIGNAL( stateChanged( int ) ),
this, TQT_SLOT( slotEmitChanged( void ) ) );
+ mOutlookCompatibleInvitationComments = new TQCheckBox( i18n( "Outlook compatible invitation reply comments" ), gBox );
+ TQToolTip::add( mOutlookCompatibleInvitationComments, i18n( "Send invitation reply comments in a way that Microsoft Outlook(tm) understands." ) );
+ TQWhatsThis::add( mOutlookCompatibleInvitationComments, i18n( GlobalSettings::self()->
+ outlookCompatibleInvitationReplyCommentsItem()->whatsThis().utf8() ) );
+ connect( mOutlookCompatibleInvitationComments, TQT_SIGNAL( stateChanged( int ) ),
+ this, TQT_SLOT( slotEmitChanged( void ) ) );
+
mAutomaticSending = new TQCheckBox( i18n( "Automatic invitation sending" ), gBox );
TQToolTip::add( mAutomaticSending, i18n( "When this is on, the user will not see the mail composer window. Invitation mails are sent automatically" ) );
TQWhatsThis::add( mAutomaticSending, i18n( GlobalSettings::self()->
@@ -4897,6 +5010,8 @@ void MiscPage::GroupwareTab::doLoadFromGlobalSettings() {
mExchangeCompatibleInvitations->setChecked( GlobalSettings::self()->exchangeCompatibleInvitations() );
+ mOutlookCompatibleInvitationComments->setChecked( GlobalSettings::self()->outlookCompatibleInvitationReplyComments() );
+
mAutomaticSending->setChecked( GlobalSettings::self()->automaticSending() );
mAutomaticSending->setEnabled( !mLegacyBodyInvites->isChecked() );
@@ -4959,6 +5074,7 @@ void MiscPage::GroupwareTab::save() {
groupware.writeEntry( "LegacyMangleFromToHeaders", mLegacyMangleFromTo->isChecked() );
groupware.writeEntry( "LegacyBodyInvites", mLegacyBodyInvites->isChecked() );
groupware.writeEntry( "ExchangeCompatibleInvitations", mExchangeCompatibleInvitations->isChecked() );
+ groupware.writeEntry( "OutlookCompatibleInvitationReplyComments", mOutlookCompatibleInvitationComments->isChecked() );
groupware.writeEntry( "AutomaticSending", mAutomaticSending->isChecked() );
if ( mEnableGwCB ) {
@@ -4967,6 +5083,7 @@ void MiscPage::GroupwareTab::save() {
GlobalSettings::self()->setLegacyMangleFromToHeaders( mLegacyMangleFromTo->isChecked() );
GlobalSettings::self()->setLegacyBodyInvites( mLegacyBodyInvites->isChecked() );
GlobalSettings::self()->setExchangeCompatibleInvitations( mExchangeCompatibleInvitations->isChecked() );
+ GlobalSettings::self()->setOutlookCompatibleInvitationReplyComments( mOutlookCompatibleInvitationComments->isChecked() );
GlobalSettings::self()->setAutomaticSending( mAutomaticSending->isChecked() );
int format = mStorageFormatCombo->currentItem();
diff --git a/kmail/configuredialog.h b/kmail/configuredialog.h
index f9c32731c..062bbf783 100644
--- a/kmail/configuredialog.h
+++ b/kmail/configuredialog.h
@@ -48,6 +48,7 @@ signals:
included in the file.
*/
void installProfile( KConfig *profile );
+ void configChanged();
protected:
void hideEvent( TQHideEvent *i );
protected slots:
diff --git a/kmail/configuredialog_p.h b/kmail/configuredialog_p.h
index 54db5c8e7..6a1f538e6 100644
--- a/kmail/configuredialog_p.h
+++ b/kmail/configuredialog_p.h
@@ -58,6 +58,7 @@ class KFontRequester;
class KIconButton;
class KKeyButton;
class TQSpinBox;
+class KComboBox;
namespace Kpgp {
class Config;
@@ -485,7 +486,6 @@ private: // data
TQButtonGroup *mMIMETreeModeGroup;
TQButtonGroup *mReaderWindowModeGroup;
TQCheckBox *mFavoriteFolderViewCB;
- TQCheckBox *mFolderQuickSearchCB;
};
class AppearancePageHeadersTab : public ConfigModuleTab {
@@ -505,7 +505,6 @@ private: // methods
void setDateDisplay( int id, const TQString & format );
private: // data
- TQCheckBox *mShowQuickSearch;
TQCheckBox *mMessageSizeCheck;
TQCheckBox *mAttachmentCheck;
TQCheckBox *mNestedMessagesCheck;
@@ -533,6 +532,7 @@ private:
void readCurrentOverrideCodec();
private: // data
+ TQCheckBox *mCloseAfterReplyOrForwardCheck;
TQCheckBox *mShowColorbarCheck;
TQCheckBox *mShowSpamStatusCheck;
TQCheckBox *mShowEmoticonsCheck;
@@ -611,13 +611,18 @@ private:
TQCheckBox *mAutoAppSignFileCheck;
TQCheckBox *mTopQuoteCheck;
TQCheckBox *mSmartQuoteCheck;
+ TQCheckBox *mStripSignatureCheck;
+ TQCheckBox *mQuoteSelectionOnlyCheck;
TQCheckBox *mAutoRequestMDNCheck;
- QCheckBox *mShowRecentAddressesInComposer;
+ TQCheckBox *mShowRecentAddressesInComposer;
TQCheckBox *mWordWrapCheck;
KIntSpinBox *mWrapColumnSpin;
+ TQCheckBox *mRecipientCheck;
+ KIntSpinBox *mRecipientSpin;
KIntSpinBox *mAutoSave;
TQCheckBox *mExternalEditorCheck;
KURLRequester *mEditorRequester;
+ KComboBox *mForwardTypeCombo;
};
class ComposerPagePhrasesTab : public ConfigModuleTab {
@@ -1020,6 +1025,7 @@ private:
TQCheckBox* mLegacyMangleFromTo;
TQCheckBox* mLegacyBodyInvites;
TQCheckBox* mExchangeCompatibleInvitations;
+ TQCheckBox* mOutlookCompatibleInvitationComments;
TQCheckBox* mAutomaticSending;
};
diff --git a/kmail/customtemplates.cpp b/kmail/customtemplates.cpp
index 93b24e8f7..6a0a7f4cf 100644
--- a/kmail/customtemplates.cpp
+++ b/kmail/customtemplates.cpp
@@ -20,15 +20,19 @@
#include <config.h>
-#include <klocale.h>
-#include <kglobal.h>
#include <tqpopupmenu.h>
#include <tqpushbutton.h>
#include <tqtextedit.h>
+#include <tqlabel.h>
#include <tqlineedit.h>
#include <tqtoolbox.h>
-#include <kdebug.h>
+#include <tqtooltip.h>
+#include <tqwhatsthis.h>
#include <tqfont.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kglobal.h>
#include <kiconloader.h>
#include <kpushbutton.h>
#include <klistview.h>
@@ -44,11 +48,14 @@
#include "globalsettings.h"
#include "kmkernel.h"
#include "kmmainwidget.h"
+#include "kmfawidgets.h"
#include "customtemplates.h"
CustomTemplates::CustomTemplates( TQWidget *parent, const char *name )
- :CustomTemplatesBase( parent, name ), mCurrentItem( 0 )
+ :CustomTemplatesBase( parent, name ),
+ mCurrentItem( 0 ),
+ mBlockChangeSignal( false )
{
TQFont f = KGlobalSettings::fixedFont();
mEdit->setFont( f );
@@ -61,8 +68,14 @@ CustomTemplates::CustomTemplates( TQWidget *parent, const char *name )
mEditFrame->setEnabled( false );
+ connect( mName, TQT_SIGNAL( textChanged ( const TQString &) ),
+ this, TQT_SLOT( slotNameChanged( const TQString & ) ) );
connect( mEdit, TQT_SIGNAL( textChanged() ),
this, TQT_SLOT( slotTextChanged( void ) ) );
+ connect( mToEdit, TQT_SIGNAL( textChanged(const TQString&) ),
+ this, TQT_SLOT( slotTextChanged( void ) ) );
+ connect( mCCEdit, TQT_SIGNAL( textChanged(const TQString&) ),
+ this, TQT_SLOT( slotTextChanged( void ) ) );
connect( mInsertCommand, TQT_SIGNAL( insertCommand(TQString, int) ),
this, TQT_SLOT( slotInsertCommand(TQString, int) ) );
@@ -105,6 +118,29 @@ CustomTemplates::CustomTemplates( TQWidget *parent, const char *name )
"You cannot bind keyboard shortcut to <i>Universal</i> templates.</p>"
"</qt>" );
mHelp->setText( i18n( "<a href=\"whatsthis:%1\">How does this work?</a>" ).arg( help ) );
+
+ const TQString toToolTip = i18n( "Additional recipients of the message when forwarding" );
+ const TQString ccToolTip = i18n( "Additional recipients who get a copy of the message when forwarding" );
+ const TQString toWhatsThis = i18n( "When using this template for forwarding, the default recipients are those you enter here. This is a comma-separated list of mail addresses." );
+ const TQString ccWhatsThis = i18n( "When using this template for forwarding, the recipients you enter here will by default get a copy of this message. This is a comma-separated list of mail addresses." );
+
+ // We only want to set the tooltip/whatsthis to the lineedit, not the complete widget,
+ // so we use the name here to find the lineedit. This is similar to what KMFilterActionForward
+ // does.
+ KLineEdit *ccLineEdit = dynamic_cast<KLineEdit*>( mCCEdit->child( "addressEdit" ) );
+ KLineEdit *toLineEdit = dynamic_cast<KLineEdit*>( mToEdit->child( "addressEdit" ) );
+ Q_ASSERT( ccLineEdit && toLineEdit );
+
+ TQToolTip::add( mCCLabel, ccToolTip );
+ TQToolTip::add( ccLineEdit, ccToolTip );
+ TQToolTip::add( mToLabel, toToolTip );
+ TQToolTip::add( toLineEdit, toToolTip );
+ TQWhatsThis::add( mCCLabel, ccWhatsThis );
+ TQWhatsThis::add( ccLineEdit, ccWhatsThis );
+ TQWhatsThis::add( mToLabel, toWhatsThis );
+ TQWhatsThis::add( toLineEdit, toWhatsThis );
+
+ slotNameChanged( mName->text() );
}
CustomTemplates::~CustomTemplates()
@@ -118,6 +154,19 @@ CustomTemplates::~CustomTemplates()
}
}
+void CustomTemplates::setRecipientsEditsEnabled( bool enabled )
+{
+ mToEdit->setHidden( !enabled );
+ mCCEdit->setHidden( !enabled );
+ mToLabel->setHidden( !enabled );
+ mCCLabel->setHidden( !enabled );
+}
+
+void CustomTemplates::slotNameChanged( const TQString& text )
+{
+ mAdd->setEnabled( !text.isEmpty() );
+}
+
TQString CustomTemplates::indexToType( int index )
{
TQString typeStr;
@@ -141,7 +190,8 @@ TQString CustomTemplates::indexToType( int index )
void CustomTemplates::slotTextChanged()
{
- emit changed();
+ if ( !mBlockChangeSignal )
+ emit changed();
}
void CustomTemplates::load()
@@ -155,7 +205,7 @@ void CustomTemplates::load()
CustomTemplateItem *vitem =
new CustomTemplateItem( *it, t.content(),
shortcut,
- static_cast<Type>( t.type() ) );
+ static_cast<Type>( t.type() ), t.to(), t.cC() );
mItemList.insert( *it, vitem );
TQListViewItem *item = new TQListViewItem( mList, typeStr, *it, t.content() );
switch ( t.type() ) {
@@ -178,11 +228,22 @@ void CustomTemplates::load()
void CustomTemplates::save()
{
+ // Before saving the new templates, delete the old ones. That needs to be done before
+ // saving, since otherwise a new template with the new name wouldn't get saved.
+ for ( TQStringList::const_iterator it = mItemsToDelete.constBegin();
+ it != mItemsToDelete.constEnd(); ++it ) {
+ CTemplates t( (*it) );
+ const TQString configGroup = t.currentGroup();
+ kmkernel->config()->deleteGroup( configGroup );
+ }
+
if ( mCurrentItem ) {
CustomTemplateItem *vitem = mItemList[ mCurrentItem->text( 1 ) ];
if ( vitem ) {
vitem->mContent = mEdit->text();
vitem->mShortcut = mKeyButton->shortcut();
+ vitem->mTo = mToEdit->text();
+ vitem->mCC = mCCEdit->text();
}
}
TQStringList list;
@@ -191,8 +252,7 @@ void CustomTemplates::save()
list.append( (*lit)->text( 1 ) );
++lit;
}
- TQDictIterator<CustomTemplateItem> it( mItemList );
- for ( ; it.current() ; ++it ) {
+ for ( TQDictIterator<CustomTemplateItem> it( mItemList ); it.current() ; ++it ) {
// list.append( (*it)->mName );
CTemplates t( (*it)->mName );
TQString &content = (*it)->mContent;
@@ -202,6 +262,8 @@ void CustomTemplates::save()
t.setContent( content );
t.setShortcut( (*it)->mShortcut.toString() );
t.setType( (*it)->mType );
+ t.setTo( (*it)->mTo );
+ t.setCC( (*it)->mCC );
t.writeConfig();
}
GlobalSettings::self()->setCustomTemplates( list );
@@ -229,13 +291,15 @@ void CustomTemplates::slotAddClicked()
if ( !str.isEmpty() ) {
CustomTemplateItem *vitem = mItemList[ str ];
if ( !vitem ) {
- vitem = new CustomTemplateItem( str, "", KShortcut::null(), TUniversal );
+ vitem = new CustomTemplateItem( str, "", KShortcut::null(), TUniversal,
+ TQString(), TQString() );
mItemList.insert( str, vitem );
TQListViewItem *item =
new TQListViewItem( mList, indexToType( TUniversal ), str, "" );
mList->setSelected( item, true );
mKeyButton->setEnabled( false );
- emit changed();
+ if ( !mBlockChangeSignal )
+ emit changed();
}
}
}
@@ -243,13 +307,14 @@ void CustomTemplates::slotAddClicked()
void CustomTemplates::slotRemoveClicked()
{
if ( mCurrentItem ) {
- CustomTemplateItem *vitem = mItemList.take( mCurrentItem->text( 1 ) );
- if ( vitem ) {
- delete vitem;
- }
+ const TQString templateName = mCurrentItem->text( 1 );
+ mItemsToDelete.append( templateName );
+ CustomTemplateItem *vitem = mItemList.take( templateName );
+ delete vitem;
delete mCurrentItem;
mCurrentItem = 0;
- emit changed();
+ if ( !mBlockChangeSignal )
+ emit changed();
}
}
@@ -268,16 +333,14 @@ void CustomTemplates::slotListSelectionChanged()
mCurrentItem = item;
CustomTemplateItem *vitem = mItemList[ mCurrentItem->text( 1 ) ];
if ( vitem ) {
- // avoid emit changed()
- disconnect( mEdit, TQT_SIGNAL( textChanged() ),
- this, TQT_SLOT( slotTextChanged( void ) ) );
+ mBlockChangeSignal = true;
mEdit->setText( vitem->mContent );
mKeyButton->setShortcut( vitem->mShortcut, false );
mType->setCurrentItem( vitem->mType );
-
- connect( mEdit, TQT_SIGNAL( textChanged() ),
- this, TQT_SLOT( slotTextChanged( void ) ) );
+ mToEdit->setText( vitem->mTo );
+ mCCEdit->setText( vitem->mCC );
+ mBlockChangeSignal = false;
if ( vitem->mType == TUniversal )
{
@@ -285,11 +348,15 @@ void CustomTemplates::slotListSelectionChanged()
} else {
mKeyButton->setEnabled( true );
}
+ setRecipientsEditsEnabled( vitem->mType == TForward ||
+ vitem->mType == TUniversal );
}
} else {
mEditFrame->setEnabled( false );
mCurrentItem = 0;
mEdit->clear();
+ mToEdit->clear();
+ mCCEdit->clear();
mKeyButton->setShortcut( KShortcut::null(), false );
mType->setCurrentItem( 0 );
}
@@ -324,8 +391,14 @@ void CustomTemplates::slotTypeActivated( int index )
} else {
mKeyButton->setEnabled( true );
}
- emit changed();
+
+ setRecipientsEditsEnabled( vitem->mType == TForward ||
+ vitem->mType == TUniversal );
+ if ( !mBlockChangeSignal )
+ emit changed();
}
+ else
+ setRecipientsEditsEnabled( false );
}
void CustomTemplates::slotShortcutCaptured( const KShortcut &shortcut )
@@ -369,7 +442,8 @@ void CustomTemplates::slotShortcutCaptured( const KShortcut &shortcut )
}
if ( assign ) {
mKeyButton->setShortcut( sc, false );
- emit changed();
+ if ( !mBlockChangeSignal )
+ emit changed();
}
}
diff --git a/kmail/customtemplates.h b/kmail/customtemplates.h
index dc454bf6c..a8c240619 100644
--- a/kmail/customtemplates.h
+++ b/kmail/customtemplates.h
@@ -26,6 +26,8 @@
#include "customtemplates_base.h"
#include "templatesinsertcommand.h"
+#include <kshortcut.h>
+
struct CustomTemplateItem;
typedef TQDict<CustomTemplateItem> CustomTemplateItemList;
class KShortcut;
@@ -59,20 +61,29 @@ class CustomTemplates : public CustomTemplatesBase
void slotListSelectionChanged();
void slotTypeActivated( int index );
void slotShortcutCaptured( const KShortcut &shortcut );
-
+ void slotNameChanged( const TQString& );
signals:
void changed();
protected:
+ void setRecipientsEditsEnabled( bool enabled );
+
TQListViewItem *mCurrentItem;
CustomTemplateItemList mItemList;
+ /// These templates will be deleted when we're saving.
+ TQStringList mItemsToDelete;
+
TQPixmap mReplyPix;
TQPixmap mReplyAllPix;
TQPixmap mForwardPix;
+ /// Whether or not to emit the changed() signal. This is useful to disable when loading
+ /// templates, which changes the UI without user action
+ bool mBlockChangeSignal;
+
};
struct CustomTemplateItem
@@ -81,12 +92,15 @@ struct CustomTemplateItem
CustomTemplateItem( const TQString &name,
const TQString &content,
KShortcut &shortcut,
- CustomTemplates::Type type ) :
- mName( name ), mContent( content ), mShortcut(shortcut), mType( type ) {}
+ CustomTemplates::Type type,
+ TQString to, TQString cc ) :
+ mName( name ), mContent( content ), mShortcut(shortcut), mType( type ),
+ mTo( to ), mCC( cc ) {}
TQString mName, mContent;
KShortcut mShortcut;
CustomTemplates::Type mType;
+ TQString mTo, mCC;
};
#endif // CUSTOMTEMPLATES_H
diff --git a/kmail/customtemplates_base.ui b/kmail/customtemplates_base.ui
index 5a4cb9d44..6a578030e 100644
--- a/kmail/customtemplates_base.ui
+++ b/kmail/customtemplates_base.ui
@@ -1,267 +1,312 @@
<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
<class>CustomTemplatesBase</class>
<widget class="QWidget">
- <property name="name">
- <cstring>Form1</cstring>
- </property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
- <width>600</width>
- <height>480</height>
+ <width>589</width>
+ <height>463</height>
</rect>
</property>
- <vbox>
+ <grid>
<property name="name">
<cstring>unnamed</cstring>
</property>
- <widget class="QSplitter">
+ <widget class="QLayoutWidget" row="0" column="0">
<property name="name">
- <cstring>splitter2</cstring>
- </property>
- <property name="orientation">
- <enum>Horizontal</enum>
+ <cstring>layout9</cstring>
</property>
- <widget class="QLayoutWidget">
+ <vbox>
<property name="name">
- <cstring>layout9</cstring>
+ <cstring>unnamed</cstring>
</property>
- <vbox>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QLayoutWidget">
<property name="name">
- <cstring>unnamed</cstring>
- </property>
- <property name="margin">
- <number>0</number>
+ <cstring>layout8</cstring>
</property>
- <widget class="QLayoutWidget">
+ <hbox>
<property name="name">
- <cstring>layout8</cstring>
+ <cstring>unnamed</cstring>
</property>
- <hbox>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="KLineEdit">
<property name="name">
- <cstring>unnamed</cstring>
+ <cstring>mName</cstring>
</property>
- <property name="margin">
- <number>0</number>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
</property>
- <widget class="KLineEdit">
- <property name="name">
- <cstring>mName</cstring>
- </property>
- <property name="sizePolicy">
- <sizepolicy>
- <hsizetype>3</hsizetype>
- <vsizetype>0</vsizetype>
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>100</width>
- <height>0</height>
- </size>
- </property>
- </widget>
- <widget class="KPushButton">
- <property name="name">
- <cstring>mAdd</cstring>
- </property>
- <property name="text">
- <string></string>
- </property>
- </widget>
- <widget class="KPushButton">
- <property name="name">
- <cstring>mRemove</cstring>
- </property>
- <property name="text">
- <string></string>
- </property>
- </widget>
- </hbox>
- </widget>
- <widget class="QListView">
- <column>
- <property name="text">
- <string>Type</string>
- </property>
- <property name="clickable">
- <bool>true</bool>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
</property>
- <property name="resizable">
- <bool>true</bool>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>mAdd</cstring>
</property>
- </column>
- <column>
<property name="text">
- <string>Name</string>
+ <string></string>
</property>
- <property name="clickable">
- <bool>true</bool>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>mRemove</cstring>
</property>
- <property name="resizable">
- <bool>true</bool>
+ <property name="text">
+ <string></string>
</property>
- </column>
- <property name="name">
- <cstring>mList</cstring>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QListView">
+ <column>
+ <property name="text">
+ <string>Type</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
</property>
- <property name="sizePolicy">
- <sizepolicy>
- <hsizetype>5</hsizetype>
- <vsizetype>7</vsizetype>
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
</property>
- <property name="allColumnsShowFocus">
+ <property name="resizable">
<bool>true</bool>
</property>
- </widget>
- </vbox>
- </widget>
- <widget class="QFrame">
+ </column>
+ <property name="name">
+ <cstring>mList</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>3</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KActiveLabel" >
+ <property name="name">
+ <cstring>mHelp</cstring>
+ </property>
+ <property name="text">
+ <string>How does this work?</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QFrame" row="0" column="1">
+ <property name="name">
+ <cstring>mEditFrame</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>12</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <vbox>
<property name="name">
- <cstring>mEditFrame</cstring>
- </property>
- <property name="sizePolicy">
- <sizepolicy>
- <hsizetype>7</hsizetype>
- <vsizetype>5</vsizetype>
- <horstretch>12</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
+ <cstring>unnamed</cstring>
</property>
- <property name="frameShape">
- <enum>NoFrame</enum>
+ <property name="margin">
+ <number>0</number>
</property>
- <property name="frameShadow">
- <enum>Raised</enum>
- </property>
- <vbox>
+ <widget class="QLayoutWidget">
<property name="name">
- <cstring>unnamed</cstring>
- </property>
- <property name="margin">
- <number>0</number>
+ <cstring>layout8</cstring>
</property>
- <widget class="QTextEdit">
- <property name="name">
- <cstring>mEdit</cstring>
- </property>
- <property name="sizePolicy">
- <sizepolicy>
- <hsizetype>7</hsizetype>
- <vsizetype>7</vsizetype>
- <horstretch>3</horstretch>
- <verstretch>1</verstretch>
- </sizepolicy>
- </property>
- <property name="textFormat">
- <enum>PlainText</enum>
- </property>
- <property name="wordWrap">
- <enum>NoWrap</enum>
- </property>
- </widget>
- <widget class="QLayoutWidget">
+ <hbox>
<property name="name">
- <cstring>layout4</cstring>
+ <cstring>unnamed</cstring>
</property>
- <grid>
+ <widget class="QLayoutWidget">
<property name="name">
- <cstring>unnamed</cstring>
+ <cstring>layout6</cstring>
</property>
- <widget class="QComboBox" row="1" column="2">
- <item>
- <property name="text">
- <string>Universal</string>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>mToLabel</cstring>
</property>
- </item>
- <item>
<property name="text">
- <string>Reply</string>
+ <string>To:</string>
</property>
- </item>
- <item>
- <property name="text">
- <string>Reply to All</string>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>mCCLabel</cstring>
</property>
- </item>
- <item>
<property name="text">
- <string>Forward</string>
+ <string>CC:</string>
</property>
- </item>
- <property name="name">
- <cstring>mType</cstring>
- </property>
- </widget>
- <widget class="QLabel" row="0" column="1">
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <vbox>
<property name="name">
- <cstring>textLabel1_2</cstring>
+ <cstring>unnamed</cstring>
</property>
+ <widget class="KMFilterActionWithAddressWidget">
+ <property name="name">
+ <cstring>mToEdit</cstring>
+ </property>
+ </widget>
+ <widget class="KMFilterActionWithAddressWidget">
+ <property name="name">
+ <cstring>mCCEdit</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QTextEdit">
+ <property name="name">
+ <cstring>mEdit</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>3</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ <property name="wordWrap">
+ <enum>NoWrap</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QComboBox" row="1" column="2">
+ <item>
<property name="text">
- <string>Shortc&amp;ut:</string>
- </property>
- <property name="alignment">
- <set>AlignVCenter|AlignRight</set>
- </property>
- <property name="buddy" stdset="0">
- <cstring>mKeyButton</cstring>
- </property>
- </widget>
- <widget class="QLabel" row="1" column="1">
- <property name="name">
- <cstring>textLabel1</cstring>
- </property>
- <property name="sizePolicy">
- <sizepolicy>
- <hsizetype>5</hsizetype>
- <vsizetype>5</vsizetype>
- <horstretch>1</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
+ <string>Universal</string>
</property>
+ </item>
+ <item>
<property name="text">
- <string>&amp;Template type:</string>
- </property>
- <property name="alignment">
- <set>AlignVCenter|AlignRight</set>
- </property>
- <property name="buddy" stdset="0">
- <cstring>mType</cstring>
- </property>
- </widget>
- <widget class="TemplatesInsertCommand" row="1" column="0">
- <property name="name">
- <cstring>mInsertCommand</cstring>
- </property>
- </widget>
- <widget class="KKeyButton" row="0" column="2">
- <property name="name">
- <cstring>mKeyButton</cstring>
+ <string>Reply</string>
</property>
+ </item>
+ <item>
<property name="text">
- <string>None</string>
- </property>
- </widget>
- <widget class="KActiveLabel" row="0" column="0">
- <property name="name">
- <cstring>mHelp</cstring>
+ <string>Reply to All</string>
</property>
+ </item>
+ <item>
<property name="text">
- <string>How does this work?</string>
+ <string>Forward</string>
</property>
- </widget>
- </grid>
- </widget>
- </vbox>
- </widget>
+ </item>
+ <property name="name">
+ <cstring>mType</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Shortc&amp;ut:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>mKeyButton</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="1">
+ <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>&amp;Template type:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>mType</cstring>
+ </property>
+ </widget>
+ <widget class="TemplatesInsertCommand" row="1" column="0">
+ <property name="name">
+ <cstring>mInsertCommand</cstring>
+ </property>
+ </widget>
+ <widget class="KKeyButton" row="0" column="2">
+ <property name="name">
+ <cstring>mKeyButton</cstring>
+ </property>
+ <property name="text">
+ <string>None</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
</widget>
- </vbox>
+ </grid>
</widget>
<customwidgets>
<customwidget>
@@ -281,10 +326,29 @@
<pixmap>image0</pixmap>
<signal>insertCommand(int)</signal>
</customwidget>
+ <customwidget>
+ <class>KMFilterActionWithAddressWidget</class>
+ <header location="local">kmfawidgets.h</header>
+ <sizehint>
+ <width>50</width>
+ <height>10</height>
+ </sizehint>
+ <container>1</container>
+ <sizepolicy>
+ <hordata>7</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image1</pixmap>
+ </customwidget>
</customwidgets>
<images>
<image name="image0">
- <data format="PNG" length="807">89504e470d0a1a0a0000000d49484452000000100000001008060000001ff3ff61000002ee49444154388d7d93cd6b5c6514c67fe7bdef9d8f24d349c66412a203b1b4282d21140918824816418a0b454d75e1a28ab8c8dfe1c25d70e34e0812ea4644d13610c43a1121b5d84cab6943486227499d869ae6633e32f7de79ef71d58644f0593dabdf39cf7938a2aa4c4f4f9b300c0b954ae56ca55249876128aa2a9c90738eadadada0542afd954ea7cb636363a19d9f9f4755cff6f4a53e4d67ed78f7b37ebb8b05e3810818017d0a68f1dcc36463a7ea8a4b8bdb9fcccdcdddf6eaf5bae4f3f9f7bb7a773faee94fed81b983a6d6d9ab6eb2f5f73affec6de1a536c9e4d7497696c9f63cf237d66b85b5e570cf3977c7aeaeae9a42a130d03d506bdbaddda3d1805faec6dc5a68e2a208e30124187a39c9ebefa6c8f544f84949a9ea69e75cd60641c0e1e1a1b8b849142ac51f226ece1f32fc4a86f31732f86db076178ad70e20765cfae8142207009eaafac639270022c2fd15a1b470c8f81b59defed0637024c44596c269cb3b1fe4585c68f2c76f0e23064000639e5c5804caab2d8c24187ed5c3265adc5bf4b9f2f91e377eae73fe254b6fbfc7ea7283588f9a314756089b31ed5925dd61b87b2bc5d75fd4a91d843c7fa68d5caf23fb4c8246fdc9f01300e3412e9f60f7313c285b6edf0c696bf338f3620773df3de2ea15d8de0ce92f2448f8472bd8a700515e18146e5c3714afd5197f3343ae3b463ce1cbcf94efbf7a48b6cb303462595c3801505514280c182ebed5ce37333bec3f8e387721859f80da7e8c114714097b3be65804eb799e562a95e641358e4d47cb8cbc66c9f5f6f1eb8f55967eafa140bedfe7e27b7dac2c4588a7ec6cb7622004629b4c2629954a7fda6c6b3f5f08baac1f61bd2683c3867a358931865339c8e69a9c1b323cb87fc0fa72d81091351189646262426667677b620e2fabea25942e504144fef34d80735a752daeab9a6f7ddf5f9162b1c8e4e4a45f2e974f0541d0a3aa19c03f16f4b862a061adddc96432bba2aaccccccc8d4d494b7b1b1910c8220a1aae6ff00d6da56676767303a3a1afd0b29d2596f22d0b7b20000000049454e44ae426082</data>
+ <data format="PNG" length="749">89504e470d0a1a0a0000000d49484452000000100000001008060000001ff3ff61000002b449444154388d8d93cd6b546714c67fef7bdf3b73274e9c38662621ed8015c1e2108248c0108a642145ba68699bb6db16ff9fe0a6bb6ea4d84d29143f02a15463e9255634a3259ac8cc6092b1d76063e27c6466ee9df79e2e4293545df481036771f8719e737894effbacacac481886044140100484618888f0baacb5d46a354aa512a9548aa9a9290c8088901bf648650c83efb8d858a11d500ab402d903f478f77992cd8665697183b9b9399c7abd2ef97c9e23435b34e557bafa21e255d96eac53fbabcadfdb351c6f9dfe7c95e4c02a99dc0bd6aa4d2acb21d65a4cb95ca650283078acc956f3313b3bf0dbf598fb0b1d6c14a11d80046367937cf4a5473617e1261522b20be876bbb4db6d6cdc210a85f96b11776fb719ffa09fe2e97edc3ea83c82f91b75882d5f5c3c8c5275feb5aeadb50028a578fa44515a6873fee30c9f7de3303a11622343e1b8e1f3afb32c2e74f8f30f8b567aefb07b9d52b05aeea15582f1730e26d1e3f1a2cb956fb7b973ab45f18c6168c4a1bcbc437ce041fb28146127e6504648a5358fee7bfcf85d8b663de4bd137d64872c99a309765abbb36f00b403d97c82ad97f06cd5f0e06e485f9fc389f7d3ccfdfc82eb5760633d64a49020e1eeaf60f6004a3839aab87353337fa3c5f94ffac90ec6284771f99270f587e7648e68c6260c8b0baf014404010ac734173e3dc44fdf6ff2ea65c4a9d31e6e029aaf62b4b24491627b53ffc782711c872008a8376274bac7c48786ecd030bfffd260e95e1301f2232e17be1ae6c952847284cd8dde3e20994c522a9530991ef94217e34618a7c3e8b8a6d548a2b5e6701632d90ea7c634cf9ed6a92e8728a5766b7a7a5a6667678969ef06480004943ab0e8c14009b607221ad775c1f77d8ac5a2a4d369715d578c31ffab3ccf935c2e27caf77d2a958accccccb0b6b646b7db7d6b940fca18c3c0c000939393fc038f463fba9bedfea40000000049454e44ae426082</data>
+ </image>
+ <image name="image1">
+ <data format="PNG" length="1002">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b149444154388dad945f4c5b551cc73fe7dc4b7b4bcba0762d45c43114323599ee6192609c51d883892ce083f1718b3ebb185f8dc91e972cf39d2d2a2f1af664b6f1e0fe3863a0718969700eb0c52142da0242a1bd6d696f7bcff101585203ceb8fd9ece39f99dcff9fe7edf939f88c562ec465f5f9fe609442c161362173c3e3eae7b7a7ac8e7f36432196cdbfe4f907c3e4f2291201e8fe338cec3737357e9e8e828aded1e229d650e1f2d51754b082110124c13a4dc5ea341eb9dc284c0558a853f3ce8cb0677ef500fde7d39d2596679e326597b8e9abb85d7a770ab16ab6983ec5a05b487a70e36f0f4e10afe408d6a558310980108478dba4a1e8233990c5d474b64ed39aa3a8fe5f3317fbf81dbd70bccfeb205947632fd74f6589c1c6ea2f70d03a58ba0c1f2c9bdc1b66de3b8256a6e11cbe7e3ee1d181b590124fe2693aeee08d223c82c3a2c24b7b874bec8f26288774f7bd054504aef0dde6e99c0eb83f9fb266323cb80a27fb0958141836044605a2ee5523393371cc646fee2da37195aa35d0c0c5b4859ac03d7e91712dcaac5adab3650a3ff9d08ef7dd8404bb48869e5d958b5b87dadc4c9a1464e9f0d0326df7ebd86bd2e310cb1bf62d384d59441f2d70a070e1c60e09489929b988681bdd9cc97170bcc4c65595f71f8e0e3301337fc24a7732467831875a47f289652b0be5e4151e6d07316c1b0c0340d8ab92023e76d66a6b2840e36d2fb7a13fee632475e6edc367ea98a90fb98b7dd6310ca0328a44761582e1bab41befabcc0ec940d28bc5e93b68e064cab84e1d9beaeb48934eac1f53b01c1b000fca496aa54b61a99fcde61662a4b4b4b23d1680be9d426173e4df3602a48ea411989a4fd590f52a8fd156b05ed9d350e3defe3cfdf4b4c7ce770ea7d3fb9f520afbe1620daeee5c26735d20b9b9cfb6811a754a439e4e5c5639a4caa1e5caf586bfc0197b78702005cb9b4cae4cd3267ce8638fe964bd72b393e39d74928d242617303a756a37f284447770dcdbffc6384a05a85de1306e9a52057c7527c7131c3c42d3f475eb2303c82d4fc3276d6811db37efeb148723082d9b08f79f97c1e5729109a9a28307cc622d2d6cdf52b2b24efe548dedb00142009862cfa879ee1a71f6cec928353511472fbf4389148b0b0e0c108081412458dfe21c9f11351e67e7358595468246d1d1e5e38a6e9e851bc39d84ab502a669331dafec0d8ec7e3e8cb06e1a881d727d1ae40180a434a8c9db129a54126ad48a7358c2b4c5352c8c374bcccdab2bb37d8719cba79fab8211f9df218e0582c261e95f8bfc04f1a1e8bc5c4dfe0a190172af6a9690000000049454e44ae426082</data>
</image>
</images>
<slots>
@@ -296,6 +360,8 @@
<includehint>klineedit.h</includehint>
<includehint>kpushbutton.h</includehint>
<includehint>kpushbutton.h</includehint>
+ <includehint>kmfawidgets.h</includehint>
+ <includehint>kmfawidgets.h</includehint>
<includehint>templatesinsertcommand.h</includehint>
<includehint>kkeybutton.h</includehint>
<includehint>kactivelabel.h</includehint>
diff --git a/kmail/customtemplates_kfg.kcfg b/kmail/customtemplates_kfg.kcfg
index f5689810e..5e3c88664 100644
--- a/kmail/customtemplates_kfg.kcfg
+++ b/kmail/customtemplates_kfg.kcfg
@@ -23,6 +23,12 @@
<whatsthis></whatsthis>
<default>0</default>
</entry>
+ <entry name="To" type="String" key="To">
+ <default></default>
+ </entry>
+ <entry name="CC" type="String" key="CC">
+ <default></default>
+ </entry>
</group>
</kcfg>
diff --git a/kmail/dcopimap.desktop b/kmail/dcopimap.desktop
index c1ed3737e..0e6afdeba 100644
--- a/kmail/dcopimap.desktop
+++ b/kmail/dcopimap.desktop
@@ -26,7 +26,6 @@ Comment[hu]=Levelezőprogram DCOP felülettel
Comment[is]=Póstforrit með DCOP viðmóti
Comment[it]=Programma di posta con un'interfaccia DCOP
Comment[ja]=DCOP インターフェース付のメールプログラム
-Comment[ka]=საფოსტო პროგრამა DCOP ინტერფეისით
Comment[kk]=DCOP интерфейсті пошта бағдарламасы
Comment[km]=កម្មវិធី​អ៊ីមែល​ដែល​មាន​ចំណុច​ប្រទាក់ DCOP
Comment[lt]=Pašto programa su DCOP sąsaja
diff --git a/kmail/dcopmail.desktop b/kmail/dcopmail.desktop
index 6772a1f6e..26aaaa569 100644
--- a/kmail/dcopmail.desktop
+++ b/kmail/dcopmail.desktop
@@ -26,7 +26,6 @@ Comment[hu]=Levelezőprogram DCOP felülettel
Comment[is]=Póstforrit með DCOP viðmóti
Comment[it]=Programma di posta con un'interfaccia DCOP
Comment[ja]=DCOP インターフェース付のメールプログラム
-Comment[ka]=საფოსტო პროგრამა DCOP ინტერფეისით
Comment[kk]=DCOP интерфейсті пошта бағдарламасы
Comment[km]=កម្មវិធី​អ៊ីមែល​ដែល​មាន​ចំណុច​ប្រទាក់ DCOP
Comment[lt]=Pašto programa su DCOP sąsaja
diff --git a/kmail/dictionarycombobox.cpp b/kmail/dictionarycombobox.cpp
index 88b776231..947d1deb8 100644
--- a/kmail/dictionarycombobox.cpp
+++ b/kmail/dictionarycombobox.cpp
@@ -134,6 +134,7 @@ namespace KMail {
mSpellConfig = new KSpellConfig( 0, 0, 0, false );
mSpellConfig->fillDicts( this, &mDictionaries );
mDefaultDictionary = currentItem();
+ mSpellConfig->setDictionary( currentDictionary() );
}
void DictionaryComboBox::slotDictionaryChanged( int idx )
diff --git a/kmail/distributionlistdialog.cpp b/kmail/distributionlistdialog.cpp
index b591afd71..470518662 100644
--- a/kmail/distributionlistdialog.cpp
+++ b/kmail/distributionlistdialog.cpp
@@ -31,6 +31,7 @@
#ifdef KDEPIM_NEW_DISTRLISTS
#include <libkdepim/distributionlist.h>
#endif
+#include <libkdepim/kaddrbook.h>
#include <klistview.h>
#include <klocale.h>
@@ -153,8 +154,6 @@ void DistributionListDialog::slotUser1()
{
bool isEmpty = true;
- KABC::AddressBook *ab = KABC::StdAddressBook::self( true );
-
TQListViewItem *i = mRecipientsList->firstChild();
while( i ) {
DistributionListItem *item = static_cast<DistributionListItem *>( i );
@@ -188,6 +187,8 @@ void DistributionListDialog::slotUser1()
return;
}
+ KABC::AddressBook *ab = KABC::StdAddressBook::self( true );
+
#ifdef KDEPIM_NEW_DISTRLISTS
if ( !KPIM::DistributionList::findByName( ab, name ).isEmpty() ) {
#else
@@ -199,6 +200,18 @@ void DistributionListDialog::slotUser1()
return;
}
+ KABC::Resource* const resource = KAddrBookExternal::selectResourceForSaving( ab );
+ if ( !resource )
+ return;
+
+ // Ask for a save ticket here, we use it for inserting the recipients into the addressbook and
+ // also for saving the addressbook, see https://issues.kolab.org/issue4281
+ KABC::Ticket *ticket = ab->requestSaveTicket( resource );
+ if ( !ticket ) {
+ kdWarning(5006) << "Unable to get save ticket!" << endl;
+ return;
+ }
+
#ifdef KDEPIM_NEW_DISTRLISTS
KPIM::DistributionList dlist;
dlist.setName( name );
@@ -209,7 +222,7 @@ void DistributionListDialog::slotUser1()
if ( item->isOn() ) {
kdDebug() << " " << item->addressee().fullEmail() << endl;
if ( item->isTransient() ) {
- ab->insertAddressee( item->addressee() );
+ resource->insertAddressee( item->addressee() );
}
if ( item->email() == item->addressee().preferredEmail() ) {
dlist.insertEntry( item->addressee() );
@@ -220,7 +233,7 @@ void DistributionListDialog::slotUser1()
i = i->nextSibling();
}
- ab->insertAddressee( dlist );
+ resource->insertAddressee( dlist );
#else
KABC::DistributionList *dlist = new KABC::DistributionList( &manager, name );
i = mRecipientsList->firstChild();
@@ -229,7 +242,7 @@ void DistributionListDialog::slotUser1()
if ( item->isOn() ) {
kdDebug() << " " << item->addressee().fullEmail() << endl;
if ( item->isTransient() ) {
- ab->insertAddressee( item->addressee() );
+ resource->insertAddressee( item->addressee() );
}
if ( item->email() == item->addressee().preferredEmail() ) {
dlist->insertEntry( item->addressee() );
@@ -241,21 +254,23 @@ void DistributionListDialog::slotUser1()
}
#endif
- // FIXME: Ask the user which resource to save to instead of the default
- bool saveError = true;
- KABC::Ticket *ticket = ab->requestSaveTicket( 0 /*default resource */ );
- if ( ticket )
- if ( ab->save( ticket ) )
- saveError = false;
- else
- ab->releaseSaveTicket( ticket );
-
- if ( saveError )
+ if ( !ab->save( ticket ) ) {
kdWarning(5006) << k_funcinfo << " Couldn't save new addresses in the distribution list just created to the address book" << endl;
+ ab->releaseSaveTicket( ticket );
+ return;
+ }
#ifndef KDEPIM_NEW_DISTRLISTS
manager.save();
#endif
- close();
+ // Only accept when the dist list is really in the addressbook, since we can't detect if the
+ // user aborted saving in another way, since insertAddressee() lacks a return code.
+#ifdef KDEPIM_NEW_DISTRLISTS
+ if ( !KPIM::DistributionList::findByName( ab, name ).isEmpty() ) {
+#else
+ if ( manager.list( name ) ) {
+#endif
+ accept();
+ }
}
diff --git a/kmail/editorwatcher.cpp b/kmail/editorwatcher.cpp
index 273c5997f..dbf5f3f96 100644
--- a/kmail/editorwatcher.cpp
+++ b/kmail/editorwatcher.cpp
@@ -48,12 +48,14 @@
using namespace KMail;
-EditorWatcher::EditorWatcher(const KURL & url, const TQString &mimeType, bool openWith, TQObject * parent) :
+EditorWatcher::EditorWatcher(const KURL & url, const TQString &mimeType, bool openWith,
+ TQObject * parent, TQWidget *parentWidget) :
TQObject( parent ),
mUrl( url ),
mMimeType( mimeType ),
mOpenWith( openWith ),
mEditor( 0 ),
+ mParentWidget( parentWidget ),
mHaveInotify( false ),
mFileOpen( false ),
mEditorRunning( false ),
@@ -154,8 +156,13 @@ void EditorWatcher::checkEditDone()
// nobody can edit that fast, we seem to be unable to detect
// when the editor will be closed
if ( mEditTime.elapsed() <= 3000 ) {
- KMessageBox::error( 0, i18n("KMail is unable to detect when the choosen editor is closed. "
- "To avoid data loss, editing the attachment will be aborted."), i18n("Unable to edit attachment") );
+ KMessageBox::information(
+ mParentWidget,
+ i18n( "KMail is unable to detect when the chosen editor is closed. "
+ "To avoid data loss, editing the attachment will be aborted." ),
+ i18n( "Unable to edit attachment" ),
+ "UnableToEditAttachment" );
+
}
emit editDone( this );
diff --git a/kmail/editorwatcher.h b/kmail/editorwatcher.h
index e0d609051..839386f84 100644
--- a/kmail/editorwatcher.h
+++ b/kmail/editorwatcher.h
@@ -39,7 +39,15 @@ class EditorWatcher : public QObject
{
Q_OBJECT
public:
- EditorWatcher( const KURL &url, const TQString &mimeType, bool openWith, TQObject *parent = 0 );
+ /**
+ * Constructs an EditorWatcher.
+ * @param parent the parent object of this EditorWatcher, which will take care of deleting
+ * this EditorWatcher if the parent is deleted.
+ * @param parentWidget the parent widget of this EditorWatcher, which will be used as the parent
+ * widget for message dialogs.
+ */
+ EditorWatcher( const KURL &url, const TQString &mimeType, bool openWith,
+ TQObject *parent, TQWidget *parentWidget );
bool start();
bool fileChanged() const { return mFileModified; }
signals:
@@ -55,6 +63,7 @@ class EditorWatcher : public QObject
TQString mMimeType;
bool mOpenWith;
KProcess *mEditor;
+ TQWidget *mParentWidget;
int mInotifyFd;
int mInotifyWatch;
diff --git a/kmail/encodingdetector.cpp b/kmail/encodingdetector.cpp
index 60913c9fc..f036a193b 100644
--- a/kmail/encodingdetector.cpp
+++ b/kmail/encodingdetector.cpp
@@ -729,87 +729,6 @@ static TQCString automaticDetectionForWesternEuropean( const unsigned char* ptr,
return "";
}
-// Other browsers allow comments in the head section, so we need to also.
-// It's important not to look for tags inside the comments.
-static void skipComment(const char *&ptr, const char *pEnd)
-{
- const char *p = ptr;
- // Allow <!-->; other browsers do.
- if (*p=='>')
- {
- p++;
- }
- else
- {
- while (p!=pEnd)
- {
- if (*p=='-')
- {
- // This is the real end of comment, "-->".
- if (p[1]=='-' && p[2]=='>')
- {
- p += 3;
- break;
- }
- // This is the incorrect end of comment that other browsers allow, "--!>".
- if (p[1] == '-' && p[2] == '!' && p[3] == '>')
- {
- p += 4;
- break;
- }
- }
- p++;
- }
- }
- ptr=p;
-}
-
-// Returns the position of the encoding string.
-static int findXMLEncoding(const TQCString &str, int &encodingLength)
-{
- int len = str.length();
- int pos = str.find("encoding");
- if (pos == -1)
- return -1;
- pos += 8;
-
- // Skip spaces and stray control characters.
- while (pos<len && str[pos]<=' ')
- ++pos;
-
- //Bail out if nothing after
- // Skip equals sign.
- if (pos>=len || str[pos] != '=')
- return -1;
- ++pos;
-
- // Skip spaces and stray control characters.
- while (pos<len && str[pos]<=' ')
- ++pos;
-
- //Bail out if nothing after
- if (pos >= len)
- return -1;
-
- // Skip quotation mark.
- char quoteMark = str[pos];
- if (quoteMark != '"' && quoteMark != '\'')
- return -1;
- ++pos;
-
- // Find the trailing quotation mark.
- int end=pos;
- while (end<len && str[end]!=quoteMark)
- ++end;
-
- if (end>=len)
- return -1;
-
- encodingLength = end-pos;
- return pos;
-}
-
-
bool EncodingDetector::errorsIfUtf8 (const char* data, int length)
{
if (d->m_codec->mibEnum()!=MibUtf8)
@@ -905,6 +824,7 @@ EncodingDetector::EncodingChoiceSource EncodingDetector::encodingChoiceSource()
const char* EncodingDetector::encoding() const
{
d->m_storeDecoderName = d->m_codec->name();
+ d->m_storeDecoderName = d->m_storeDecoderName.lower().replace( "iso ", "iso-" );
return d->m_storeDecoderName.data();
}
diff --git a/kmail/eventsrc b/kmail/eventsrc
index 76720efeb..6f4c38dea 100644
--- a/kmail/eventsrc
+++ b/kmail/eventsrc
@@ -34,7 +34,6 @@ Name[hu]=Új levél érkezett
Name[is]=Nýr póstur
Name[it]=Nuova posta arrivata
Name[ja]=新規メール着信
-Name[ka]=მიღებულია ახალი ფოსტა
Name[kk]=Жаңа пошта келді
Name[km]=មាន​អ៊ីមែល​ថ្មី​មក​ដល់
Name[lt]=Atėjo naujas paštas
@@ -60,8 +59,7 @@ Name[ta]=புதிய அஞ்சல் வந்துள்ளது
Name[tg]=Почтаи нав қабул шуд
Name[tr]=Yeni E-posta Geldi
Name[uk]=Отримана нова пошта
-Name[uz]=Yangi xat keldi
-Name[uz@cyrillic]=Янги хат келди
+Name[uz]=Янги хат келди
Name[zh_CN]=新邮件到达
Name[zh_TW]=您有新郵件
Comment=New mail arrived
@@ -90,7 +88,6 @@ Comment[hu]=Új levél érkezett
Comment[is]=Nýr póstur
Comment[it]=Nuova posta
Comment[ja]=新規メール着信
-Comment[ka]=მიღებულია ახალი ფოსტა
Comment[kk]=Жаңа пошта келді
Comment[km]=មាន​អ៊ីមែល​ថ្មី​មក​ដល់
Comment[lt]=Atėjo naujas paštas
@@ -116,8 +113,7 @@ Comment[ta]=புதிய அஞ்சல் வந்துள்ளது
Comment[tg]=Почтаи нав қабул шуд
Comment[tr]=Yeni e-posta geldi
Comment[uk]=Надійшла нова пошта
-Comment[uz]=Yangi xat keldi
-Comment[uz@cyrillic]=Янги хат келди
+Comment[uz]=Янги хат келди
Comment[zh_CN]=新邮件到达
Comment[zh_TW]=您有新郵件
default_sound=
diff --git a/kmail/expirypropertiesdialog.cpp b/kmail/expirypropertiesdialog.cpp
index a313cc88d..c524f8b32 100644
--- a/kmail/expirypropertiesdialog.cpp
+++ b/kmail/expirypropertiesdialog.cpp
@@ -28,8 +28,8 @@ using namespace KMail;
*
*/
ExpiryPropertiesDialog::ExpiryPropertiesDialog( KMFolderTree* tree, KMFolder* folder )
- : KDialogBase( tree, "expiry_properties", false, i18n( "Mail Expiry Properties" ),
- KDialogBase::Ok|KDialogBase::Cancel,
+ : KDialogBase( tree, "expiry_properties", false, i18n( "Mail Expiry Properties" ),
+ KDialogBase::Ok|KDialogBase::Cancel,
KDialogBase::Ok, true ),
mFolder( folder )
{
@@ -37,10 +37,10 @@ ExpiryPropertiesDialog::ExpiryPropertiesDialog( KMFolderTree* tree, KMFolder* fo
TQWidget* privateLayoutWidget = new TQWidget( this, "globalVBox" );
setMainWidget( privateLayoutWidget );
privateLayoutWidget->setGeometry( TQRect( 10, 20, 270, 138 ) );
- globalVBox = new TQVBoxLayout( privateLayoutWidget, 11, 6, "globalVBox");
+ globalVBox = new TQVBoxLayout( privateLayoutWidget, 11, 6, "globalVBox");
globalVBox->setSpacing( 20 );
- readHBox = new TQHBoxLayout( 0, 0, 6, "readHBox");
+ readHBox = new TQHBoxLayout( 0, 0, 6, "readHBox");
expireReadMailCB = new TQCheckBox( privateLayoutWidget, "expireReadMailCB" );
expireReadMailCB->setText( i18n( "Expire read mails after" ) );
@@ -58,7 +58,7 @@ ExpiryPropertiesDialog::ExpiryPropertiesDialog( KMFolderTree* tree, KMFolder* fo
readHBox->addWidget( labelDays );
globalVBox->addLayout( readHBox );
- unreadHBox = new TQHBoxLayout( 0, 0, 6, "unreadHBox");
+ unreadHBox = new TQHBoxLayout( 0, 0, 6, "unreadHBox");
expireUnreadMailCB = new TQCheckBox( privateLayoutWidget, "expireUnreadMailCB" );
expireUnreadMailCB->setText( i18n( "Expire unread mails after" ) );
@@ -77,18 +77,18 @@ ExpiryPropertiesDialog::ExpiryPropertiesDialog( KMFolderTree* tree, KMFolder* fo
unreadHBox->addWidget( labelDays2 );
globalVBox->addLayout( unreadHBox );
- expiryActionHBox = new TQHBoxLayout( 0, 0, 6, "expiryActionHBox");
+ expiryActionHBox = new TQHBoxLayout( 0, 0, 6, "expiryActionHBox");
expiryActionLabel = new TQLabel( privateLayoutWidget, "expiryActionLabel" );
expiryActionLabel->setText( i18n( "Expiry action:" ) );
expiryActionLabel->setAlignment( int( TQLabel::AlignVCenter ) );
expiryActionHBox->addWidget( expiryActionLabel );
- actionsHBox = new TQVBoxLayout( 0, 0, 6, "actionsHBox");
+ actionsHBox = new TQVBoxLayout( 0, 0, 6, "actionsHBox");
actionsGroup = new TQButtonGroup( this );
actionsGroup->hide(); // for mutual exclusion of the radio buttons
- moveToHBox = new TQHBoxLayout( 0, 0, 6, "moveToHBox");
+ moveToHBox = new TQHBoxLayout( 0, 0, 6, "moveToHBox");
moveToRB = new TQRadioButton( privateLayoutWidget, "moveToRB" );
actionsGroup->insert( moveToRB );
@@ -119,14 +119,14 @@ ExpiryPropertiesDialog::ExpiryPropertiesDialog( KMFolderTree* tree, KMFolder* fo
int daysToExpireRead, daysToExpireUnread;
mFolder->daysToExpire( daysToExpireUnread, daysToExpireRead);
- if ( expiryGloballyOn
- && mFolder->getReadExpireUnits() != expireNever
+ if ( expiryGloballyOn
+ && mFolder->getReadExpireUnits() != expireNever
&& daysToExpireRead >= 0 ) {
expireReadMailCB->setChecked( true );
expireReadMailSB->setValue( daysToExpireRead );
}
if ( expiryGloballyOn
- && mFolder->getUnreadExpireUnits() != expireNever
+ && mFolder->getUnreadExpireUnits() != expireNever
&& daysToExpireUnread >= 0 ) {
expireUnreadMailCB->setChecked( true );
expireUnreadMailSB->setValue( daysToExpireUnread );
@@ -159,11 +159,29 @@ ExpiryPropertiesDialog::~ExpiryPropertiesDialog()
void ExpiryPropertiesDialog::slotOk()
{
bool enableGlobally = expireReadMailCB->isChecked() || expireUnreadMailCB->isChecked();
- if ( enableGlobally && moveToRB->isChecked() && !folderSelector->folder() ) {
- KMessageBox::error( this, i18n("Please select a folder to expire messages into."),
- i18n( "No Folder Selected" ) );
+
+ KMFolder *expireToFolder = folderSelector->folder();
+ if ( enableGlobally && moveToRB->isChecked() && !expireToFolder ) {
+ KMessageBox::error(
+ this,
+ i18n( "Please select a folder to expire messages into." ),
+ i18n( "No Folder Selected" ) );
return;
- }
+ }
+
+ if ( expireToFolder ) {
+ if ( expireToFolder->idString() == mFolder->idString() ) {
+ KMessageBox::error(
+ this,
+ i18n( "Please select a different folder than the current folder "
+ "to expire message into." ),
+ i18n( "Wrong Folder Selected" ) );
+ return;
+ } else {
+ mFolder->setExpireToFolderId( expireToFolder->idString() );
+ }
+ }
+
mFolder->setAutoExpire( enableGlobally );
// we always write out days now
mFolder->setReadExpireAge( expireReadMailSB->value() );
@@ -175,9 +193,6 @@ void ExpiryPropertiesDialog::slotOk()
mFolder->setExpireAction( KMFolder::ExpireDelete );
else
mFolder->setExpireAction( KMFolder::ExpireMove );
- KMFolder* expireToFolder = folderSelector->folder();
- if ( expireToFolder )
- mFolder->setExpireToFolderId( expireToFolder->idString() );
// trigger immediate expiry if there is something to do
if ( enableGlobally )
diff --git a/kmail/favoritefolderview.cpp b/kmail/favoritefolderview.cpp
index 35b2e3ee4..5d8e3d13a 100644
--- a/kmail/favoritefolderview.cpp
+++ b/kmail/favoritefolderview.cpp
@@ -309,7 +309,8 @@ void FavoriteFolderView::dropped(TQDropEvent * e, TQListViewItem * after)
KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>( it.current() );
if ( !fti->folder() )
continue;
- afterItem = addFolder( fti->folder(), prettyName( fti ), afterItem );
+ if( !mFolderToItem.contains( fti->folder() ) )
+ afterItem = addFolder( fti->folder(), prettyName( fti ), afterItem );
}
e->accept();
}
@@ -323,20 +324,25 @@ void FavoriteFolderView::contextMenu(TQListViewItem * item, const TQPoint & poin
mContextMenuItem = fti;
KPopupMenu contextMenu;
if ( fti && fti->folder() ) {
- contextMenu.insertItem( SmallIconSet("editdelete"), i18n("Remove From Favorites"),
- this, TQT_SLOT(removeFolder()) );
- contextMenu.insertItem( SmallIconSet("edit"), i18n("Rename Favorite"), this, TQT_SLOT(renameFolder()) );
- contextMenu.insertSeparator();
-
mainWidget()->action("mark_all_as_read")->plug( &contextMenu );
if ( fti->folder()->folderType() == KMFolderTypeImap || fti->folder()->folderType() == KMFolderTypeCachedImap )
mainWidget()->action("refresh_folder")->plug( &contextMenu );
if ( fti->folder()->isMailingListEnabled() )
mainWidget()->action("post_message")->plug( &contextMenu );
+ mainWidget()->action("search_messages")->plug( &contextMenu );
+ if ( fti->folder()->canDeleteMessages() && ( fti->folder()->count() > 0 ) )
+ mainWidget()->action("empty")->plug( &contextMenu );
+ contextMenu.insertSeparator();
contextMenu.insertItem( SmallIconSet("configure_shortcuts"), i18n("&Assign Shortcut..."), fti, TQT_SLOT(assignShortcut()) );
contextMenu.insertItem( i18n("Expire..."), fti, TQT_SLOT(slotShowExpiryProperties()) );
mainWidget()->action("modify")->plug( &contextMenu );
+ contextMenu.insertSeparator();
+
+ contextMenu.insertItem( SmallIconSet("editdelete"), i18n("Remove From Favorites"),
+ this, TQT_SLOT(removeFolder()) );
+ contextMenu.insertItem( SmallIconSet("edit"), i18n("Rename Favorite"), this, TQT_SLOT(renameFolder()) );
+
} else {
contextMenu.insertItem( SmallIconSet("bookmark_add"), i18n("Add Favorite Folder..."),
this, TQT_SLOT(addFolder()) );
@@ -346,8 +352,13 @@ void FavoriteFolderView::contextMenu(TQListViewItem * item, const TQPoint & poin
void FavoriteFolderView::removeFolder()
{
+ KMFolderTreeItem *fti = mContextMenuItem;
+ KMFolder *folder = 0;
+ if( fti )
+ folder = fti->folder();
delete mContextMenuItem;
mContextMenuItem = 0;
+ removeFromFolderToItemMap(folder);
notifyInstancesOnChange();
}
@@ -446,6 +457,9 @@ void FavoriteFolderView::addFolder()
KMFolder *folder = dlg.folder();
if ( !folder )
return;
+ if ( mFolderToItem.contains( folder ) )
+ return;
+
KMFolderTreeItem *fti = findFolderTreeItem( folder );
addFolder( folder, fti ? prettyName( fti ) : folder->label() );
}
@@ -454,7 +468,8 @@ void KMail::FavoriteFolderView::addFolder(KMFolderTreeItem * fti)
{
if ( !fti || !fti->folder() )
return;
- addFolder( fti->folder(), prettyName( fti ) );
+ if ( !mFolderToItem.contains( fti->folder() ) )
+ addFolder( fti->folder(), prettyName( fti ) );
}
KMFolderTreeItem * FavoriteFolderView::findFolderTreeItem(KMFolder * folder) const
@@ -485,7 +500,7 @@ void FavoriteFolderView::checkMail()
imap->getAndCheckFolder();
} else if ( fti->folder()->folderType() == KMFolderTypeCachedImap ) {
KMFolderCachedImap* f = static_cast<KMFolderCachedImap*>( fti->folder()->storage() );
- f->account()->processNewMailSingleFolder( fti->folder() );
+ f->account()->processNewMailInFolder( fti->folder() );
}
}
}
diff --git a/kmail/filterimporterexporter.cpp b/kmail/filterimporterexporter.cpp
index bfe40170c..c5780431d 100644
--- a/kmail/filterimporterexporter.cpp
+++ b/kmail/filterimporterexporter.cpp
@@ -38,74 +38,105 @@
#include <kfiledialog.h>
#include <kdialogbase.h>
#include <klistview.h>
+#include <kpushbutton.h>
#include <tqregexp.h>
+#include <tqlayout.h>
using namespace KMail;
-class FilterSelectionDialog : public KDialogBase
+FilterSelectionDialog::FilterSelectionDialog( TQWidget * parent )
+ :KDialogBase( parent, "filterselection", true, i18n("Select Filters"), Ok|Cancel, Ok, true ),
+ wasCancelled( false )
{
-public:
- FilterSelectionDialog( TQWidget * parent = 0 )
- :KDialogBase( parent, "filterselection", true, i18n("Select Filters"), Ok|Cancel, Ok, true ),
- wasCancelled( false )
- {
- filtersListView = new KListView( this );
- setMainWidget(filtersListView);
- filtersListView->setSorting( -1 );
- filtersListView->setSelectionMode( TQListView::NoSelection );
- filtersListView->addColumn( i18n("Filters"), 300 );
- filtersListView->setFullWidth( true );
- resize( 300, 350 );
- }
+ TQWidget *w = new TQWidget( this );
+ TQVBoxLayout *top = new TQVBoxLayout( w );
+
+ filtersListView = new KListView( w );
+ top->addWidget( filtersListView );
+ setMainWidget(w);
+ filtersListView->setSorting( -1 );
+ filtersListView->setSelectionMode( TQListView::NoSelection );
+ filtersListView->addColumn( i18n("Filters"), 300 );
+ filtersListView->setFullWidth( true );
+ TQHBoxLayout *buttonLayout = new TQHBoxLayout( this );
+ top->addLayout( buttonLayout );
+ selectAllButton = new KPushButton( i18n( "Select All" ), w );
+ buttonLayout->addWidget( selectAllButton );
+ unselectAllButton = new KPushButton( i18n( "Unselect All" ), w );
+ buttonLayout->addWidget( unselectAllButton );
+ connect( selectAllButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotSelectAllButton() ) );
+ connect( unselectAllButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotUnselectAllButton() ) );
+ resize( 300, 350 );
+}
- virtual ~FilterSelectionDialog()
- {
- }
-
- virtual void slotCancel()
- {
- wasCancelled = true;
- KDialogBase::slotCancel();
- }
-
- bool cancelled()
- {
- return wasCancelled;
- }
+FilterSelectionDialog::~FilterSelectionDialog()
+{
+}
- void setFilters( const TQValueList<KMFilter*>& filters )
- {
- originalFilters = filters;
- filtersListView->clear();
- TQValueListConstIterator<KMFilter*> it = filters.constEnd();
- while ( it != filters.constBegin() ) {
- --it;
- KMFilter* filter = *it;
- TQCheckListItem* item = new TQCheckListItem( filtersListView, filter->name(), TQCheckListItem::CheckBox );
- item->setOn( true );
- }
- }
-
- TQValueList<KMFilter*> selectedFilters() const
- {
- TQValueList<KMFilter*> filters;
- TQListViewItemIterator it( filtersListView );
- int i = 0;
- while( it.current() ) {
- TQCheckListItem* item = static_cast<TQCheckListItem*>( it.current() );
- if ( item->isOn() )
- filters << originalFilters[i];
- ++i; ++it;
- }
- return filters;
- }
-private:
- KListView *filtersListView;
- TQValueList<KMFilter*> originalFilters;
- bool wasCancelled;
-};
+void FilterSelectionDialog::slotCancel()
+{
+ wasCancelled = true;
+ KDialogBase::slotCancel();
+}
+
+bool FilterSelectionDialog::cancelled()
+{
+ return wasCancelled;
+}
+
+void FilterSelectionDialog::setFilters( const TQValueList<KMFilter*>& filters )
+{
+ if ( filters.isEmpty() )
+ {
+ enableButtonOK( false );
+ return;
+ }
+ originalFilters = filters;
+ filtersListView->clear();
+ TQValueListConstIterator<KMFilter*> it = filters.constEnd();
+ while ( it != filters.constBegin() ) {
+ --it;
+ KMFilter* filter = *it;
+ TQCheckListItem* item = new TQCheckListItem( filtersListView, filter->name(), TQCheckListItem::CheckBox );
+ item->setOn( true );
+ }
+}
+
+TQValueList<KMFilter*> FilterSelectionDialog::selectedFilters() const
+{
+ TQValueList<KMFilter*> filters;
+ TQListViewItemIterator it( filtersListView );
+ int i = 0;
+ while( it.current() ) {
+ TQCheckListItem* item = static_cast<TQCheckListItem*>( it.current() );
+ if ( item->isOn() )
+ filters << originalFilters[i];
+ ++i; ++it;
+ }
+ return filters;
+}
+
+void FilterSelectionDialog::slotUnselectAllButton()
+{
+ TQListViewItemIterator it( filtersListView );
+ while( it.current() ) {
+ TQCheckListItem* item = static_cast<TQCheckListItem*>( it.current() );
+ item->setOn( false );
+ ++it;
+ }
+}
+
+void FilterSelectionDialog::slotSelectAllButton()
+{
+ TQListViewItemIterator it( filtersListView );
+ while( it.current() ) {
+ TQCheckListItem* item = static_cast<TQCheckListItem*>( it.current() );
+ item->setOn( true );
+ ++it;
+ }
+}
/* static */
TQValueList<KMFilter*> FilterImporterExporter::readFiltersFromConfig( KConfig* config, bool bPopFilter )
@@ -116,7 +147,7 @@ TQValueList<KMFilter*> FilterImporterExporter::readFiltersFromConfig( KConfig* c
numFilters = config->readNumEntry("popfilters",0);
else
numFilters = config->readNumEntry("filters",0);
-
+
TQValueList<KMFilter*> filters;
for ( int i=0 ; i < numFilters ; ++i ) {
TQString grpName;
@@ -136,7 +167,7 @@ TQValueList<KMFilter*> FilterImporterExporter::readFiltersFromConfig( KConfig* c
return filters;
}
-/* static */
+/* static */
void FilterImporterExporter::writeFiltersToConfig( const TQValueList<KMFilter*>& filters, KConfig* config, bool bPopFilter )
{
// first, delete all groups:
@@ -145,7 +176,7 @@ void FilterImporterExporter::writeFiltersToConfig( const TQValueList<KMFilter*>&
for ( TQStringList::Iterator it = filterGroups.begin() ;
it != filterGroups.end() ; ++it )
config->deleteGroup( *it );
-
+
int i = 0;
for ( TQValueListConstIterator<KMFilter*> it = filters.constBegin() ;
it != filters.constEnd() ; ++it ) {
@@ -180,9 +211,9 @@ FilterImporterExporter::~FilterImporterExporter()
TQValueList<KMFilter*> FilterImporterExporter::importFilters()
{
TQString fileName = KFileDialog::getOpenFileName( TQDir::homeDirPath(), TQString::null, mParent, i18n("Import Filters") );
- if ( fileName.isEmpty() )
+ if ( fileName.isEmpty() )
return TQValueList<KMFilter*>(); // cancel
-
+
{ // scoping
TQFile f( fileName );
if ( !f.open( IO_ReadOnly ) ) {
@@ -190,7 +221,7 @@ TQValueList<KMFilter*> FilterImporterExporter::importFilters()
return TQValueList<KMFilter*>();
}
}
-
+
KConfig config( fileName );
TQValueList<KMFilter*> imported = readFiltersFromConfig( &config, mPopFilter );
FilterSelectionDialog dlg( mParent );
@@ -202,10 +233,10 @@ TQValueList<KMFilter*> FilterImporterExporter::importFilters()
void FilterImporterExporter::exportFilters(const TQValueList<KMFilter*> & filters )
{
KURL saveUrl = KFileDialog::getSaveURL( TQDir::homeDirPath(), TQString::null, mParent, i18n("Export Filters") );
-
+
if ( saveUrl.isEmpty() || !Util::checkOverwrite( saveUrl, mParent ) )
return;
-
+
KConfig config( saveUrl.path() );
FilterSelectionDialog dlg( mParent );
dlg.setFilters( filters );
@@ -214,3 +245,4 @@ void FilterImporterExporter::exportFilters(const TQValueList<KMFilter*> & filter
writeFiltersToConfig( dlg.selectedFilters(), &config, mPopFilter );
}
+#include "filterimporterexporter.moc"
diff --git a/kmail/filterimporterexporter.h b/kmail/filterimporterexporter.h
index 75f43d14f..8b9a63bb8 100644
--- a/kmail/filterimporterexporter.h
+++ b/kmail/filterimporterexporter.h
@@ -31,10 +31,11 @@
#define __FILTERIMPORTEREXPORTER_H__
#include <tqvaluelist.h>
-
+#include <kdialogbase.h>
class KMFilter;
class KConfig;
class TQWidget;
+class KPushButton;
namespace KMail
{
@@ -48,22 +49,44 @@ class FilterImporterExporter
public:
FilterImporterExporter( TQWidget* parent, bool popFilter = false );
virtual ~FilterImporterExporter();
-
- /** Export the given filter rules to a file which
+
+ /** Export the given filter rules to a file which
* is asked from the user. The list to export is also
* presented for confirmation/selection. */
void exportFilters( const TQValueList<KMFilter*> & );
-
+
/** Import filters. Ask the user where to import them from
* and which filters to import. */
TQValueList<KMFilter*> importFilters();
-
+
static void writeFiltersToConfig( const TQValueList<KMFilter*>& filters, KConfig* config, bool bPopFilter );
static TQValueList<KMFilter*> readFiltersFromConfig( KConfig* config, bool bPopFilter );
private:
TQWidget* mParent;
bool mPopFilter;
};
+class FilterSelectionDialog : public KDialogBase
+{
+ Q_OBJECT
+public:
+ FilterSelectionDialog( TQWidget * parent = 0 );
+
+ virtual ~FilterSelectionDialog();
+ virtual void slotCancel();
+ bool cancelled();
+ void setFilters( const TQValueList<KMFilter*>& filters );
+
+ TQValueList<KMFilter*> selectedFilters() const;
+public slots:
+ void slotUnselectAllButton();
+ void slotSelectAllButton();
+private:
+ KListView *filtersListView;
+ TQValueList<KMFilter*> originalFilters;
+ bool wasCancelled;
+ KPushButton *selectAllButton;
+ KPushButton *unselectAllButton;
+};
}
diff --git a/kmail/folderdiaacltab.cpp b/kmail/folderdiaacltab.cpp
index d1f02a57c..bebd9c319 100644
--- a/kmail/folderdiaacltab.cpp
+++ b/kmail/folderdiaacltab.cpp
@@ -30,7 +30,7 @@
* your version.
*/
-#include <config.h>
+#include <config.h> // FOR KDEPIM_NEW_DISTRLISTS
#include "folderdiaacltab.h"
#include "acljobs.h"
@@ -90,7 +90,7 @@ KMail::ACLEntryDialog::ACLEntryDialog( IMAPUserIdFormat userIdFormat, const TQSt
{
TQWidget *page = new TQWidget( this );
setMainWidget(page);
- TQGridLayout *topLayout = new TQGridLayout( page, 3 /*rows*/, 3 /*cols*/, 0, spacingHint() );
+ TQGridLayout *topLayout = new TQGridLayout( page, 4 /*rows*/, 3 /*cols*/, 0, spacingHint() );
TQLabel *label = new TQLabel( i18n( "&User identifier:" ), page );
topLayout->addWidget( label, 0, 0 );
@@ -100,7 +100,7 @@ KMail::ACLEntryDialog::ACLEntryDialog( IMAPUserIdFormat userIdFormat, const TQSt
label->setBuddy( mUserIdLineEdit );
TQWhatsThis::add( mUserIdLineEdit, i18n( "The User Identifier is the login of the user on the IMAP server. This can be a simple user name or the full email address of the user; the login for your own account on the server will tell you which one it is." ) );
- TQPushButton* kabBtn = new TQPushButton( "...", page );
+ TQPushButton* kabBtn = new TQPushButton( i18n( "Se&lect..." ), page );
topLayout->addWidget( kabBtn, 0, 2 );
mButtonGroup = new TQVButtonGroup( i18n( "Permissions" ), page );
@@ -115,6 +115,9 @@ KMail::ACLEntryDialog::ACLEntryDialog( IMAPUserIdFormat userIdFormat, const TQSt
}
topLayout->setRowStretch(2, 10);
+ TQLabel *noteLabel = new TQLabel( i18n( "<b>Note: </b>Renaming requires write permissions on the parent folder." ), page );
+ topLayout->addMultiCellWidget( noteLabel, 2, 2, 0, 2 );
+
connect( mUserIdLineEdit, TQT_SIGNAL( textChanged( const TQString& ) ), TQT_SLOT( slotChanged() ) );
connect( kabBtn, TQT_SIGNAL( clicked() ), TQT_SLOT( slotSelectAddresses() ) );
connect( mButtonGroup, TQT_SIGNAL( clicked( int ) ), TQT_SLOT( slotChanged() ) );
@@ -178,12 +181,7 @@ TQString KMail::ACLEntryDialog::userId() const
TQStringList KMail::ACLEntryDialog::userIds() const
{
- TQStringList lst = TQStringList::split( ",", mUserIdLineEdit->text() );
- for( TQStringList::Iterator it = lst.begin(); it != lst.end(); ++it ) {
- // Strip white space (in particular, due to ", ")
- *it = (*it).stripWhiteSpace();
- }
- return lst;
+ return KPIM::splitEmailAddrList( mUserIdLineEdit->text() );
}
unsigned int KMail::ACLEntryDialog::permissions() const
@@ -319,6 +317,7 @@ KMail::FolderDiaACLTab::FolderDiaACLTab( KMFolderDialog* dlg, TQWidget* parent,
: FolderDiaTab( parent, name ),
mImapAccount( 0 ),
mUserRights( 0 ),
+ mUserRightsState( KMail::ACLJobs::NotFetchedYet ),
mDlg( dlg ),
mChanged( false ), mAccepting( false ), mSaving( false )
{
@@ -344,7 +343,7 @@ KMail::FolderDiaACLTab::FolderDiaACLTab( KMFolderDialog* dlg, TQWidget* parent,
TQT_SLOT(slotEditACL(TQListViewItem*)) );
connect( mListView, TQT_SIGNAL(returnPressed(TQListViewItem*)),
TQT_SLOT(slotEditACL(TQListViewItem*)) );
- connect( mListView, TQT_SIGNAL(selectionChanged(TQListViewItem*)),
+ connect( mListView, TQT_SIGNAL(currentChanged(TQListViewItem*)),
TQT_SLOT(slotSelectionChanged(TQListViewItem*)) );
TQVBox* buttonBox = new TQVBox( mACLWidget );
@@ -381,12 +380,14 @@ void KMail::FolderDiaACLTab::initializeWithValuesFromFolder( KMFolder* folder )
mImapPath = folderImap->imapPath();
mImapAccount = folderImap->account();
mUserRights = folderImap->userRights();
+ mUserRightsState = folderImap->userRightsState();
}
else if ( mFolderType == KMFolderTypeCachedImap ) {
KMFolderCachedImap* folderImap = static_cast<KMFolderCachedImap*>( folder->storage() );
mImapPath = folderImap->imapPath();
mImapAccount = folderImap->account();
mUserRights = folderImap->userRights();
+ mUserRightsState = folderImap->userRightsState();
}
else
assert( 0 ); // see KMFolderDialog constructor
@@ -422,13 +423,16 @@ void KMail::FolderDiaACLTab::load()
if ( mFolderType == KMFolderTypeCachedImap ) {
KMFolder* folder = mDlg->folder() ? mDlg->folder() : mDlg->parentFolder();
KMFolderCachedImap* folderImap = static_cast<KMFolderCachedImap*>( folder->storage() );
- if ( mUserRights == -1 ) { // error
- mLabel->setText( i18n( "Error retrieving user permissions." ) );
- } else if ( mUserRights == 0 /* can't happen anymore*/ || folderImap->aclList().isEmpty() ) {
- /* We either synced, or we read user rights from the config, so we can
- assume the server supports acls and an empty list means we haven't
- synced yet. */
- mLabel->setText( i18n( "Information not retrieved from server yet, please use \"Check Mail\"." ) );
+ if ( mUserRightsState == KMail::ACLJobs::FetchFailed ||
+ folderImap->aclListState() == KMail::ACLJobs::FetchFailed ) {
+ TQString text = i18n( "Error retrieving user permissions." );
+ if ( mUserRightsState == KMail::ACLJobs::Ok ) {
+ text += "\n" + i18n( "You might not have enough permissions to see the permissions of this folder." );
+ }
+ mLabel->setText( text );
+ } else if ( mUserRightsState == KMail::ACLJobs::NotFetchedYet ||
+ folderImap->aclListState() == KMail::ACLJobs::NotFetchedYet ) {
+ mLabel->setText( i18n( "Information not retrieved from server, you need to use \"Check Mail\" and have administrative privileges on the folder."));
} else {
loadFinished( folderImap->aclList() );
}
@@ -474,7 +478,7 @@ void KMail::FolderDiaACLTab::slotConnectionResult( int errorCode, const TQString
return;
}
- if ( mUserRights == 0 ) {
+ if ( mUserRightsState != KMail::ACLJobs::Ok ) {
connect( mImapAccount, TQT_SIGNAL( receivedUserRights( KMFolder* ) ),
this, TQT_SLOT( slotReceivedUserRights( KMFolder* ) ) );
KMFolder* folder = mDlg->folder() ? mDlg->folder() : mDlg->parentFolder();
@@ -494,6 +498,7 @@ void KMail::FolderDiaACLTab::slotReceivedUserRights( KMFolder* folder )
if ( folder == mDlg->folder() ? mDlg->folder() : mDlg->parentFolder() ) {
KMFolderImap* folderImap = static_cast<KMFolderImap*>( folder->storage() );
mUserRights = folderImap->userRights();
+ mUserRightsState = folderImap->userRightsState();
startListing();
}
}
diff --git a/kmail/folderdiaacltab.h b/kmail/folderdiaacltab.h
index 87b296eef..6576d13e6 100644
--- a/kmail/folderdiaacltab.h
+++ b/kmail/folderdiaacltab.h
@@ -33,6 +33,7 @@
#define FOLDERDIAACL_H
#include "kmfolderdia.h"
+#include "acljobs.h"
#include "kmfoldertype.h"
class KMFolderImap;
@@ -137,6 +138,7 @@ private:
TQString mImapPath;
ImapAccountBase* mImapAccount;
int mUserRights;
+ KMail::ACLJobs::ACLFetchState mUserRightsState;
KMFolderType mFolderType;
ACLList mInitialACLList;
ACLList mACLList; // to be set
diff --git a/kmail/foldersetselector.cpp b/kmail/foldersetselector.cpp
new file mode 100644
index 000000000..c35fd0c1e
--- /dev/null
+++ b/kmail/foldersetselector.cpp
@@ -0,0 +1,88 @@
+/*
+ Copyright (c) 2007 Volker Krause <vkrause@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 "foldersetselector.h"
+
+#include "globalsettings.h"
+#include "kmfoldertree.h"
+#include "simplefoldertree.h"
+#include "kmfoldercachedimap.h"
+
+#include <tqvbox.h>
+
+using namespace KMail;
+
+FolderSetSelector::FolderSetSelector( KMFolderTree *ft, TQWidget * parent )
+ : KDialogBase( parent, "FolderSetSelector", true, TQString(), Ok|Cancel, Ok, true )
+{
+ assert( ft );
+
+ mTreeView = new KMail::SimpleFolderTreeBase<TQCheckListItem>( makeVBoxMainWidget(), ft,
+ GlobalSettings::self()->lastSelectedFolder(), false );
+ mTreeView->setFocus();
+
+ TQListViewItemIterator it( mTreeView );
+ while ( it.current() ) {
+ SimpleFolderTreeItem<TQCheckListItem> *item = dynamic_cast<SimpleFolderTreeItem<TQCheckListItem>*>( it.current() );
+ ++it;
+ if ( !item )
+ continue;
+ if ( !item->folder() ) {
+ item->setEnabled( false );
+ continue;
+ }
+ if ( item->folder()->folderType() == KMFolderTypeCachedImap
+ && static_cast<const KMFolderCachedImap*>( item->folder()->storage() )->imapPath() == "/INBOX/" ) {
+ item->setOn( true );
+ }
+ if ( item->folder()->folderType() != KMFolderTypeCachedImap ) {
+ item->setEnabled( false );
+ }
+ }
+
+}
+
+TQValueList< int > FolderSetSelector::selectedFolders()
+{
+ TQValueList<int> rv;
+ TQListViewItemIterator it( mTreeView );
+ while ( it.current() ) {
+ SimpleFolderTreeItem<TQCheckListItem> *item = dynamic_cast<SimpleFolderTreeItem<TQCheckListItem>*>( it.current() );
+ if ( item && item->isOn() && item->folder() )
+ rv.append( item->folder()->id() );
+ ++it;
+ }
+ return rv;
+}
+
+void FolderSetSelector::setSelectedFolders(const TQValueList< int > & folderIds)
+{
+ TQListViewItemIterator it( mTreeView );
+ while ( it.current() ) {
+ SimpleFolderTreeItem<TQCheckListItem> *item = dynamic_cast<SimpleFolderTreeItem<TQCheckListItem>*>( it.current() );
+ if ( item && item->folder() ) {
+ if ( folderIds.contains( item->folder()->id() ) )
+ item->setOn( true );
+ else
+ item->setOn( false );
+ }
+ ++it;
+ }
+}
+
+#include "foldersetselector.moc"
diff --git a/kmail/foldersetselector.h b/kmail/foldersetselector.h
new file mode 100644
index 000000000..5d51db31b
--- /dev/null
+++ b/kmail/foldersetselector.h
@@ -0,0 +1,45 @@
+/*
+ Copyright (c) 2007 Volker Krause <vkrause@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 KMAIL_FOLDERSETSELECTOR_H
+#define KMAIL_FOLDERSETSELECTOR_H
+
+#include <kdialogbase.h>
+
+class KListView;
+class KMFolderTree;
+
+namespace KMail {
+
+class FolderSetSelector : public KDialogBase
+{
+ Q_OBJECT
+
+ public:
+ FolderSetSelector( KMFolderTree *ft, TQWidget *parent = 0 );
+
+ TQValueList<int> selectedFolders();
+ void setSelectedFolders( const TQValueList<int> &folderIds );
+
+ private:
+ KListView *mTreeView;
+};
+
+}
+
+#endif
diff --git a/kmail/folderstorage.cpp b/kmail/folderstorage.cpp
index c1d447a67..78724d502 100644
--- a/kmail/folderstorage.cpp
+++ b/kmail/folderstorage.cpp
@@ -85,8 +85,8 @@ FolderStorage::FolderStorage( KMFolder* folder, const char* aName )
mHasChildren = HasNoChildren;
mContentsType = KMail::ContentsTypeMail;
-
- connect(this, TQT_SIGNAL(closed(KMFolder*)), mFolder, TQT_SIGNAL(closed()));
+
+ connect(this, TQT_SIGNAL(closed(KMFolder*)), mFolder, TQT_SIGNAL(closed()));
}
//-----------------------------------------------------------------------------
@@ -477,11 +477,11 @@ void FolderStorage::take(TQPtrList<KMMessage> msgList)
KMMessage* FolderStorage::getMsg(int idx)
{
if ( mOpenCount <= 0 ) {
- kdWarning(5006) << "FolderStorage::getMsg was called on a closed folder: " << folder()->prettyURL() << endl;
+ kdWarning(5006) << "FolderStorage::getMsg was called on a closed folder: " << folder()->prettyURL() << endl;
return 0;
}
- if ( idx < 0 || idx >= count() ) {
- kdWarning(5006) << "FolderStorage::getMsg was asked for an invalid index. idx =" << idx << " count()=" << count() << endl;
+ if ( idx < 0 || idx >= count() ) {
+ kdWarning(5006) << "FolderStorage::getMsg was asked for an invalid index. idx =" << idx << " count()=" << count() << endl;
return 0;
}
@@ -502,6 +502,10 @@ KMMessage* FolderStorage::getMsg(int idx)
if (mCompactable && (!msg || (msg->subject().isEmpty() != mbSubject.isEmpty()))) {
kdDebug(5006) << "Error: " << location() <<
" Index file is inconsistent with folder file. This should never happen." << endl;
+
+ // We can't recreate the index at this point, since that would invalidate the current
+ // message list and delete KMMsgBase or KMMessage objects that are in use.
+ // Do it later in KMFolderIndex::readIndexHeader() instead.
mCompactable = false; // Don't compact
writeConfig();
}
@@ -522,11 +526,16 @@ KMMessage* FolderStorage::getMsg(int idx)
//-----------------------------------------------------------------------------
KMMessage* FolderStorage::readTemporaryMsg(int idx)
{
- if(!(idx >= 0 && idx <= count()))
+ if(!(idx >= 0 && idx <= count())) {
+ kdDebug(5006) << k_funcinfo << "Invalid index " << idx << "!" << endl;
return 0;
+ }
KMMsgBase* mb = getMsgBase(idx);
- if (!mb) return 0;
+ if (!mb) {
+ kdDebug(5006) << k_funcinfo << "getMsgBase() for " << idx << " failed!" << endl;
+ return 0;
+ }
unsigned long sernum = mb->getMsgSerNum();
@@ -542,7 +551,11 @@ KMMessage* FolderStorage::readTemporaryMsg(int idx)
msg = new KMMessage(*(KMMsgInfo*)mb);
msg->setMsgSerNum(sernum); // before fromDwString so that readyToShow uses the right sernum
msg->setComplete( true );
- msg->fromDwString(getDwString(idx));
+ const DwString msgString = getDwString( idx );
+ if ( msgString.size() <= 0 ) {
+ kdDebug(5006) << k_funcinfo << " Calling getDwString() failed!" << endl;
+ }
+ msg->fromDwString( msgString );
}
msg->setEnableUndo(undo);
return msg;
@@ -914,7 +927,7 @@ void FolderStorage::readConfig()
mCompactable = config->readBoolEntry("Compactable", true);
if ( mSize == -1 )
mSize = config->readNum64Entry("FolderSize", -1);
-
+
int type = config->readNumEntry( "ContentsType", 0 );
if ( type < 0 || type > KMail::ContentsTypeLast ) type = 0;
setContentsType( static_cast<KMail::FolderContentsType>( type ) );
@@ -1173,4 +1186,22 @@ KMAccount* FolderStorage::account() const
return 0;
}
+bool FolderStorage::mailCheckInProgress() const
+{
+ return false;
+}
+
+bool FolderStorage::canDeleteMessages() const
+{
+ return !isReadOnly();
+}
+
+void FolderStorage::setNoContent(bool aNoContent)
+{
+ const bool changed = aNoContent != mNoContent;
+ mNoContent = aNoContent;
+ if ( changed )
+ emit noContentChanged();
+}
+
#include "folderstorage.moc"
diff --git a/kmail/folderstorage.h b/kmail/folderstorage.h
index e132c7b07..7d7165431 100644
--- a/kmail/folderstorage.h
+++ b/kmail/folderstorage.h
@@ -106,8 +106,7 @@ public:
virtual bool noContent() const { return mNoContent; }
/** Specify, that the folder can't contain mails. */
- virtual void setNoContent(bool aNoContent)
- { mNoContent = aNoContent; }
+ virtual void setNoContent(bool aNoContent);
/** Returns, if the folder can't have children */
virtual bool noChildren() const { return mNoChildren; }
@@ -342,6 +341,9 @@ public:
/** Is the folder read-only? */
virtual bool isReadOnly() const = 0;
+ /** Can messages in this folder be deleted? */
+ virtual bool canDeleteMessages() const;
+
/** Returns the label of the folder for visualization. */
TQString label() const;
@@ -417,6 +419,8 @@ public:
virtual KMAccount* account() const;
+ virtual bool mailCheckInProgress() const;
+
signals:
/** Emitted when the status, name, or associated accounts of this
folder changed. */
@@ -432,7 +436,7 @@ signals:
/** Emitted when the folder was closed and ticket owners have to reopen */
void closed( KMFolder* );
-
+
/** Emitted when the serial numbers of this folder were invalidated. */
void invalidated( KMFolder * );
@@ -451,6 +455,9 @@ signals:
/** Emitted when the readonly status of the folder changes. */
void readOnlyChanged(KMFolder*);
+ /** Emitted when the no content state of the folder changes. */
+ void noContentChanged();
+
/** Emitted before a message is removed from the folder. */
void msgRemoved(KMFolder*, Q_UINT32 sernum);
@@ -494,6 +501,11 @@ signals:
/** Emitted when the folder's size changes. */
void folderSizeChanged();
+ /**
+ * Emiitted when the sync state, i.e. mailCheckInProgress(), changes.
+ * Currently only supported for disconnected IMAP.
+ */
+ void syncStateChanged();
public slots:
/** Incrementally update the index if possible else call writeIndex */
diff --git a/kmail/foldertreebase.cpp b/kmail/foldertreebase.cpp
index 3ca61845e..c35c88074 100644
--- a/kmail/foldertreebase.cpp
+++ b/kmail/foldertreebase.cpp
@@ -81,12 +81,12 @@ int FolderTreeBase::dndMode(bool alwaysAsk)
action = DRAG_MOVE;
} else {
if ( GlobalSettings::self()->showPopupAfterDnD() || alwaysAsk ) {
- KPopupMenu *menu = new KPopupMenu( this );
- menu->insertItem( i18n("&Move Here"), DRAG_MOVE, 0 );
- menu->insertItem( SmallIcon("editcopy"), i18n("&Copy Here"), DRAG_COPY, 1 );
- menu->insertSeparator();
- menu->insertItem( SmallIcon("cancel"), i18n("C&ancel"), DRAG_CANCEL, 3 );
- action = menu->exec( TQCursor::pos(), 0 );
+ KPopupMenu menu;
+ menu.insertItem( i18n("&Move Here"), DRAG_MOVE, 0 );
+ menu.insertItem( SmallIcon("editcopy"), i18n("&Copy Here"), DRAG_COPY, 1 );
+ menu.insertSeparator();
+ menu.insertItem( SmallIcon("cancel"), i18n("C&ancel"), DRAG_CANCEL, 3 );
+ action = menu.exec( TQCursor::pos(), 0 );
}
else
action = DRAG_MOVE;
diff --git a/kmail/folderutil.cpp b/kmail/folderutil.cpp
new file mode 100644
index 000000000..8e65fff27
--- /dev/null
+++ b/kmail/folderutil.cpp
@@ -0,0 +1,113 @@
+/* Copyright 2009 Klarälvdalens 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) version 3 or any later version
+ accepted by the membership of KDE e.V. (or its successor approved
+ by the membership of KDE e.V.), which shall act as a proxy
+ defined in Section 14 of version 3 of the license.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "folderutil.h"
+
+#include "kmfolder.h"
+#include "kmfolderimap.h"
+#include "kmfoldercachedimap.h"
+#include "kmfoldermgr.h"
+
+#include <kmessagebox.h>
+
+using namespace KMail;
+using namespace FolderUtil;
+
+KMFolder *KMail::FolderUtil::createSubFolder( KMFolder *parentFolder, KMFolderDir *parentDir,
+ const TQString &folderName, const TQString &namespaceName,
+ KMFolderType localFolderType )
+{
+ KMFolder *newFolder = 0;
+
+ if ( parentFolder && parentFolder->folderType() == KMFolderTypeImap ) {
+ KMFolderImap* selectedStorage = static_cast<KMFolderImap*>( parentFolder->storage() );
+ KMAcctImap *anAccount = selectedStorage->account();
+ // check if a connection is available BEFORE creating the folder
+ if (anAccount->makeConnection() == ImapAccountBase::Connected) {
+ newFolder = kmkernel->imapFolderMgr()->createFolder( folderName, false, KMFolderTypeImap, parentDir );
+ if ( newFolder ) {
+ TQString imapPath, parent;
+ if ( !namespaceName.isEmpty() ) {
+ // create folder with namespace
+ parent = anAccount->addPathToNamespace( namespaceName );
+ imapPath = anAccount->createImapPath( parent, folderName );
+ } else {
+ imapPath = anAccount->createImapPath( selectedStorage->imapPath(), folderName );
+ }
+ KMFolderImap* newStorage = static_cast<KMFolderImap*>( newFolder->storage() );
+ selectedStorage->createFolder(folderName, parent); // create it on the server
+ newStorage->initializeFrom( selectedStorage, imapPath, TQString::null );
+ static_cast<KMFolderImap*>(parentFolder->storage())->setAccount( selectedStorage->account() );
+ return newFolder;
+ }
+ }
+ } else if ( parentFolder && parentFolder->folderType() == KMFolderTypeCachedImap ) {
+ newFolder = kmkernel->dimapFolderMgr()->createFolder( folderName, false, KMFolderTypeCachedImap,
+ parentDir );
+ if ( newFolder ) {
+ KMFolderCachedImap* selectedStorage = static_cast<KMFolderCachedImap*>( parentFolder->storage() );
+ KMFolderCachedImap* newStorage = static_cast<KMFolderCachedImap*>( newFolder->storage() );
+ newStorage->initializeFrom( selectedStorage );
+ if ( !namespaceName.isEmpty() ) {
+ // create folder with namespace
+ TQString path = selectedStorage->account()->createImapPath(
+ namespaceName, folderName );
+ newStorage->setImapPathForCreation( path );
+ }
+ return newFolder;
+ }
+ } else {
+ // local folder
+ Q_ASSERT( localFolderType == KMFolderTypeMaildir || localFolderType == KMFolderTypeMbox );
+ newFolder = kmkernel->folderMgr()->createFolder( folderName, false, localFolderType,
+ parentDir );
+ return newFolder;
+ }
+
+ return newFolder;
+}
+
+void KMail::FolderUtil::deleteFolder( KMFolder *folderToDelete, TQWidget *parent )
+{
+ if ( folderToDelete->hasAccounts() ) {
+ // this folder has an account, so we need to change that to the inbox
+ for ( AccountList::Iterator it (folderToDelete->acctList()->begin() ),
+ end( folderToDelete->acctList()->end() ); it != end; ++it ) {
+ (*it)->setFolder( kmkernel->inboxFolder() );
+ KMessageBox::information(parent,
+ i18n("<qt>The folder you deleted was associated with the account "
+ "<b>%1</b> which delivered mail into it. The folder the account "
+ "delivers new mail into was reset to the main Inbox folder.</qt>").arg( (*it)->name()));
+ }
+ }
+ if (folderToDelete->folderType() == KMFolderTypeImap)
+ kmkernel->imapFolderMgr()->remove(folderToDelete);
+ else if (folderToDelete->folderType() == KMFolderTypeCachedImap) {
+ // Deleted by user -> tell the account (see KMFolderCachedImap::listDirectory2)
+ KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>( folderToDelete->storage() );
+ KMAcctCachedImap* acct = storage->account();
+ if ( acct )
+ acct->addDeletedFolder( folderToDelete );
+
+ kmkernel->dimapFolderMgr()->remove(folderToDelete);
+ }
+ else if (folderToDelete->folderType() == KMFolderTypeSearch)
+ kmkernel->searchFolderMgr()->remove(folderToDelete);
+ else
+ kmkernel->folderMgr()->remove(folderToDelete);
+}
diff --git a/kmail/folderutil.h b/kmail/folderutil.h
new file mode 100644
index 000000000..fbb4d0697
--- /dev/null
+++ b/kmail/folderutil.h
@@ -0,0 +1,65 @@
+/* Copyright 2009 Klarälvdalens 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) version 3 or any later version
+ accepted by the membership of KDE e.V. (or its successor approved
+ by the membership of KDE e.V.), which shall act as a proxy
+ defined in Section 14 of version 3 of the license.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef FOLDERUTIL_H
+#define FOLDERUTIL_H
+
+#include "kmfoldertype.h"
+
+class KMFolder;
+class KMFolderDir;
+class TQString;
+class TQWidget;
+
+namespace KMail
+{
+
+namespace FolderUtil
+{
+
+/**
+ * Low-level function to create a subfolder for a folder of any kind.
+ *
+ * @param parentFolder parent folder of the folder that should be created. Can be 0 in case of
+ * local folders
+ * @param parentDir parent folder directory, which should be the folder directory of parentFolder
+ * @param folderName the name the newly created folder should have
+ * @param namespaceName for (d)IMAP folders, the namespace the new folder should be in. Can be empty.
+ * @param localFolderType for local folders, this determines if the folder should be MBOX or maildir
+ *
+ * @return the newly created folder or 0 in case an error occured
+ */
+KMFolder *createSubFolder( KMFolder *parentFolder, KMFolderDir *parentDir,
+ const TQString &folderName, const TQString &namespaceName,
+ KMFolderType localFolderType );
+
+/**
+ * Deletes a folder and all its subfolders.
+ * Handles all types of folders correctly, as well as folders with accounts
+ *
+ * @param folderToDelete the folder which is going to be deleted
+ * @param parent the parent widget, which is used when displaying a messagebox,
+ * which happens when removing a folder with an associated account
+ */
+void deleteFolder( KMFolder *folderToDelete, TQWidget *parent );
+
+}
+
+}
+
+#endif
diff --git a/kmail/globalsettings_base.kcfgc b/kmail/globalsettings_base.kcfgc
index 7fbfbaf8a..3ca476056 100644
--- a/kmail/globalsettings_base.kcfgc
+++ b/kmail/globalsettings_base.kcfgc
@@ -4,4 +4,4 @@ Mutators=true
Singleton=true
ItemAccessors=true
SetUserTexts=true
-IncludeFiles=templatesconfiguration.h,kmglobal.h,templatesconfiguration_base.h
+IncludeFiles=templatesconfiguration.h,kmglobal.h,templatesconfiguration_base.h,objecttreeparser.h
diff --git a/kmail/headeritem.cpp b/kmail/headeritem.cpp
index f950d35c7..188e05324 100644
--- a/kmail/headeritem.cpp
+++ b/kmail/headeritem.cpp
@@ -115,6 +115,28 @@ int HeaderItem::msgId() const
return mMsgId;
}
+TQString HeaderItem::to() const
+{
+ KMHeaders * const headers = static_cast<KMHeaders*>( listView() );
+ KMMsgBase * const msgBase = headers->folder()->getMsgBase( mMsgId );
+ if ( msgBase ) {
+ return msgBase->to();
+ } else {
+ return TQString();
+ }
+}
+
+TQString HeaderItem::from() const
+{
+ KMHeaders * const headers = static_cast<KMHeaders*>( listView() );
+ KMMsgBase * const msgBase = headers->folder()->getMsgBase( mMsgId );
+ if ( msgBase ) {
+ return msgBase->from();
+ } else {
+ return TQString();
+ }
+}
+
// Return the serial number
Q_UINT32 HeaderItem::msgSerNum() const
{
@@ -295,9 +317,14 @@ const TQPixmap *HeaderItem::pixmap(int col) const
// Only merge the attachment icon in if that is configured.
if ( headers->paintInfo()->showAttachmentIcon &&
!headers->paintInfo()->showAttachment &&
- msgBase->attachmentState() == KMMsgHasAttachment )
+ msgBase->attachmentState() == KMMsgHasAttachment )
pixmaps << *KMHeaders::pixAttachment;
+ // Only merge the invitation icon in if that is configured.
+ if ( headers->paintInfo()->showInvitationIcon &&
+ msgBase->invitationState() == KMMsgHasInvitation )
+ pixmaps << *KMHeaders::pixInvitation;
+
// Only merge the crypto icons in if that is configured.
if ( headers->paintInfo()->showCryptoIcons ) {
const TQPixmap *pix;
@@ -326,6 +353,10 @@ const TQPixmap *HeaderItem::pixmap(int col) const
if ( msgBase->attachmentState() == KMMsgHasAttachment )
return KMHeaders::pixAttachment;
}
+ else if ( col == headers->paintInfo()->invitationCol ) {
+ if ( msgBase->invitationState() == KMMsgHasInvitation )
+ return KMHeaders::pixInvitation;
+ }
else if ( col == headers->paintInfo()->importantCol ) {
if ( msgBase->isImportant() )
return KMHeaders::pixFlag;
@@ -485,6 +516,10 @@ TQString HeaderItem::generate_key( KMHeaders *headers,
TQString s(msg->attachmentState() == KMMsgHasAttachment ? "1" : "0");
return ret + s + sortArrival;
}
+ else if (column == paintInfo->invitationCol) {
+ TQString s(msg->invitationState() == KMMsgHasInvitation ? "1" : "0");
+ return ret + s + sortArrival;
+ }
else if (column == paintInfo->importantCol) {
TQString s(msg->isImportant() ? "1" : "0");
return ret + s + sortArrival;
@@ -558,6 +593,7 @@ int HeaderItem::compare( TQListViewItem *i, int col, bool ascending ) const
if ( ( col == headers->paintInfo()->statusCol ) ||
( col == headers->paintInfo()->sizeCol ) ||
( col == headers->paintInfo()->attachmentCol ) ||
+ ( col == headers->paintInfo()->invitationCol ) ||
( col == headers->paintInfo()->importantCol ) ||
( col == headers->paintInfo()->todoCol ) ||
( col == headers->paintInfo()->spamHamCol ) ||
diff --git a/kmail/headeritem.h b/kmail/headeritem.h
index 961c99b70..ac46cb959 100644
--- a/kmail/headeritem.h
+++ b/kmail/headeritem.h
@@ -179,6 +179,9 @@ public:
/** Return the msgId of the message associated with this item. */
int msgId() const;
+ TQString to() const;
+ TQString from() const;
+
// Return the serial number of the message associated with this item;
Q_UINT32 msgSerNum() const;
diff --git a/kmail/headerlistquicksearch.cpp b/kmail/headerlistquicksearch.cpp
index 9f20b7e80..69ac5b1f7 100644
--- a/kmail/headerlistquicksearch.cpp
+++ b/kmail/headerlistquicksearch.cpp
@@ -69,6 +69,7 @@ HeaderListQuickSearch::HeaderListQuickSearch( TQWidget *parent,
TQLabel *label = new TQLabel( i18n("Stat&us:"), parent, "kde toolbar widget" );
mStatusCombo = new TQComboBox( parent, "quick search status combo box" );
+ mStatusCombo->setSizeLimit( 12 );
mStatusCombo->insertItem( SmallIcon( "run" ), i18n("Any Status") );
insertStatus( StatusUnread );
@@ -78,6 +79,7 @@ HeaderListQuickSearch::HeaderListQuickSearch( TQWidget *parent,
insertStatus( StatusForwarded );
insertStatus( StatusToDo );
insertStatus( StatusHasAttachment );
+ insertStatus( StatusInvitation );
insertStatus( StatusWatched );
insertStatus( StatusIgnored );
mStatusCombo->setCurrentItem( 0 );
@@ -91,7 +93,7 @@ HeaderListQuickSearch::HeaderListQuickSearch( TQWidget *parent,
0, i18n( "Open Full Search" ) );
connect( btn, TQT_SIGNAL( clicked() ), TQT_SIGNAL( requestFullSearch() ) );
- /* Disable the signal connected by KListViewSearchLine since it will call
+ /* Disable the signal connected by KListViewSearchLine since it will call
* itemAdded during KMHeaders::readSortOrder() which will in turn result
* in getMsgBaseForItem( item ) wanting to access items which are no longer
* there. Rather rely on KMHeaders::msgAdded and its signal. */
@@ -149,6 +151,17 @@ bool HeaderListQuickSearch::itemMatches(const TQListViewItem *item, const TQStri
if ( !msg || ! ( msg->status() & mStatus ) )
return false;
}
+
+ // The full email address is not visible, but we still want it to be searchable.
+ // KListViewSearchLine::itemMatches() only searches in visible columns.
+ const HeaderItem *headerItem = static_cast<const HeaderItem*>( item );
+ if ( headerItem->from().lower().contains( s.lower() ) ) {
+ return true;
+ }
+ if ( headerItem->to().lower().contains( s.lower() ) ) {
+ return true;
+ }
+
return KListViewSearchLine::itemMatches(item, s);
}
diff --git a/kmail/headerstyle.cpp b/kmail/headerstyle.cpp
index 9e6e63156..29046112a 100644
--- a/kmail/headerstyle.cpp
+++ b/kmail/headerstyle.cpp
@@ -118,6 +118,7 @@ namespace KMail {
TQString BriefHeaderStyle::format( const KMMessage * message,
const HeaderStrategy * strategy,
const TQString & vCardName, bool printing, bool topLevel ) const {
+ Q_UNUSED( topLevel );
if ( !message ) return TQString::null;
if ( !strategy )
strategy = HeaderStrategy::brief();
@@ -216,6 +217,7 @@ namespace KMail {
TQString PlainHeaderStyle::format( const KMMessage * message,
const HeaderStrategy * strategy,
const TQString & vCardName, bool printing, bool topLevel ) const {
+ Q_UNUSED( topLevel );
if ( !message ) return TQString::null;
if ( !strategy )
strategy = HeaderStrategy::rich();
@@ -416,6 +418,7 @@ namespace KMail {
TQString FancyHeaderStyle::format( const KMMessage * message,
const HeaderStrategy * strategy,
const TQString & vCardName, bool printing, bool topLevel ) const {
+ Q_UNUSED( topLevel );
if ( !message ) return TQString::null;
if ( !strategy )
strategy = HeaderStrategy::rich();
@@ -785,23 +788,10 @@ namespace KMail {
// reverse colors for encapsulated
if( !topLevel ){
activeColorDark = activeColor.dark(50);
- fontColor = qApp->palette().active().text();
- linkColor = "";
+ fontColor = TQColor(TQt::black);
+ linkColor = "class =\"black\"";
}
- TQStringList headerParts;
- if( strategy->showHeader( "to" ) )
- headerParts << KMMessage::emailAddrAsAnchor( message->to(), false, linkColor );
-
- if ( strategy->showHeader( "cc" ) && !message->cc().isEmpty() )
- headerParts << i18n("CC: ") + KMMessage::emailAddrAsAnchor( message->cc(), true, linkColor );
-
- if ( strategy->showHeader( "bcc" ) && !message->bcc().isEmpty() )
- headerParts << i18n("BCC: ") + KMMessage::emailAddrAsAnchor( message->bcc(), true, linkColor );
-
- // remove all empty (modulo whitespace) entries and joins them via ", \n"
- TQString headerPart = " " + headerParts.grep( TQRegExp( "\\S" ) ).join( ", " );
-
// Prepare the date string (when printing always use the localized date)
TQString dateString;
if( printing ) {
@@ -822,12 +812,12 @@ namespace KMail {
if(topLevel)
headerStr +=
"<div style=\"position: fixed; top: 0px; left: 0px; background-color: #606060; "
- "background-image: url("+imgpath+"shadow_left.png); width: 10px; min-height: 100%;\">&nbsp;</div>"
+ "width: 10px; min-height: 100%;\">&nbsp;</div>"
"<div style=\"position: fixed; top: 0px; right: 0px; background-color: #606060; "
- "background-image: url("+imgpath+"shadow_right.png); width: 10px; min-height: 100%;\">&nbsp;</div>";
+ "width: 10px; min-height: 100%;\">&nbsp;</div>";
headerStr += ""
- "<div style=\"margin-left: 8px; top: 0px;\"><span style=\"font-size: 10px; font-weight: bold;\">"+dateString+"</span></div>"
+ "<div style=\"margin-left: 10px; top: 0px;\"><span style=\"font-size: 10px; font-weight: bold;\">"+dateString+"</span></div>"
// #0057ae
"<table style=\"background: "+activeColorDark.name()+"; border-collapse:collapse; top: 14px; min-width: 200px; \" cellpadding=0> \n"
" <tr> \n"
@@ -836,8 +826,15 @@ namespace KMail {
" <td style=\"min-width: 6px; background: url("+imgpath+"top_right.png); \"></td> </tr> \n"
" <tr> \n"
" <td style=\"min-width: 6px; max-width: 6px; background: url("+imgpath+"left.png); \"></td> \n"
- " <td style=\"\"> \n"
- " <table style=\"color: "+fontColor.name()+" ! important; margin: 1px; border-spacing: 0px;\" cellpadding=0> \n";
+ " <td style=\"\"> \n";
+
+ headerStr +=
+ " <div class=\"noprint\" style=\"z-index: 1; float:right; position: relative; top: -35px; right: 20px ;\">\n"
+ " <img src=\""+imgpath+"icon.png\">\n"
+ " </div>\n";
+
+ headerStr +=
+ " <table style=\"color: "+fontColor.name()+" ! important; margin: 1px; border-spacing: 0px;\" cellpadding=0> \n";
// subject
//strToHtml( message->subject() )
@@ -845,7 +842,7 @@ namespace KMail {
headerStr +=
" <tr> \n"
" <td style=\"font-size: 6px; text-align: right; padding-left: 5px; padding-right: 24px; "+borderSettings+"\"></td> \n"
- " <td style=\"font-weight: bolder; font-size: 120%;"+borderSettings+"\">"+message->subject()+"</td> \n"
+ " <td style=\"font-weight: bolder; font-size: 120%; padding-right: 91px; "+borderSettings+"\">"+message->subject()+"</td> \n"
" </tr> \n";
}
@@ -858,7 +855,7 @@ namespace KMail {
TQString fromPart = KMMessage::emailAddrAsAnchor( fromStr, true, linkColor );
if ( !vCardName.isEmpty() )
fromPart += "&nbsp;&nbsp;<a href=\"" + vCardName + "\" "+linkColor+">" + i18n("[vCard]") + "</a>";
- //TDDO strategy date
+ //TODO strategy date
//if ( strategy->showHeader( "date" ) )
headerStr +=
" <tr> \n"
@@ -867,14 +864,35 @@ namespace KMail {
" </tr> ";
}
- // to, cc, bcc
- headerStr +=
+ // to line
+ if( strategy->showHeader( "to" ) )
+ headerStr +=
+ " <tr> "
+ " <td style=\"font-size: 6px; text-align: right; padding-left: 5px; padding-right: 24px; " + borderSettings + "\">" + i18n("To: ") + "</td> "
+ " <td style=\"" + borderSettings + "\">" +
+ KMMessage::emailAddrAsAnchor( message->to(), false, linkColor ) +
+ " </td> "
+ " </tr>\n";
+
+ // cc line, if any
+ if ( strategy->showHeader( "cc" ) && !message->cc().isEmpty() )
+ headerStr +=
" <tr> "
- " <td style=\"font-size: 6px; text-align: right; padding-left: 5px; padding-right: 24px; "+borderSettings+"\">"+i18n("To: ")+"</td> "
- " <td style=\""+borderSettings+"\">"
- +headerPart+
+ " <td style=\"font-size: 6px; text-align: right; padding-left: 5px; padding-right: 24px; " + borderSettings + "\">" + i18n("CC: ") + "</td> "
+ " <td style=\"" + borderSettings + "\">" +
+ KMMessage::emailAddrAsAnchor( message->cc(), false, linkColor ) +
" </td> "
- " </tr> ";
+ " </tr>\n";
+
+ // bcc line, if any
+ if ( strategy->showHeader( "bcc" ) && !message->bcc().isEmpty() )
+ headerStr +=
+ " <tr> "
+ " <td style=\"font-size: 6px; text-align: right; padding-left: 5px; padding-right: 24px; " + borderSettings + "\">" + i18n("BCC: ") + "</td> "
+ " <td style=\"" + borderSettings + "\">" +
+ KMMessage::emailAddrAsAnchor( message->bcc(), false, linkColor ) +
+ " </td> "
+ " </tr>\n";
// header-bottom
headerStr +=
@@ -893,25 +911,27 @@ namespace KMail {
// kmail icon
if(topLevel) {
- headerStr +=
- "<div class=\"noprint\" style=\"position: absolute; top: -14px; right: 30px; width: 91px; height: 91px;\">\n"
- "<img style=\"float: right;\" src=\""+imgpath+"icon.png\">\n"
- "</div>\n";
// attachments
headerStr +=
- "<div class=\"noprint\" style=\"position: fixed; top: 60px; right: 20px; width: 91px; height: 200px;\">"
+ "<div class=\"noprint\" style=\"position: absolute; top: 60px; right: 20px; width: 91px; height: 200px;\">"
"<div id=\"attachmentInjectionPoint\"></div>"
"</div>\n";
}
- headerStr += "<div style=\"padding: 6px;\">";
+ if ( printing ) {
+ //provide a bit more left padding when printing
+ //kolab/issue3254 (printed mail cut at the left side)
+ headerStr += "<div style=\"padding: 6px; padding-left: 10px;\">";
+ } else {
+ headerStr += "<div style=\"padding: 6px;\">";
+ }
- // TODO
- // spam status
- // ### iterate over the rest of strategy->headerToDisplay() (or
- // ### all headers if DefaultPolicy == Display) (elsewhere, too)
- return headerStr;
+ // TODO
+ // spam status
+ // ### iterate over the rest of strategy->headerToDisplay() (or
+ // ### all headers if DefaultPolicy == Display) (elsewhere, too)
+ return headerStr;
}
// #####################
diff --git a/kmail/identitydialog.cpp b/kmail/identitydialog.cpp
index c0a1952d7..22b5a4c81 100644
--- a/kmail/identitydialog.cpp
+++ b/kmail/identitydialog.cpp
@@ -48,6 +48,7 @@ using KMail::FolderRequester;
#include "kmfolder.h"
#include "templatesconfiguration.h"
#include "templatesconfiguration_kfg.h"
+#include "simplestringlisteditor.h"
// other kdepim headers:
// libkdepim
@@ -76,6 +77,8 @@ using KMail::FolderRequester;
#include <tqpushbutton.h>
#include <tqcheckbox.h>
#include <tqcombobox.h>
+#include <tqgroupbox.h>
+#include <tqtextedit.h>
// other headers:
#include <gpgmepp/key.h>
@@ -107,7 +110,7 @@ namespace KMail {
tab = new TQWidget( tabWidget );
tabWidget->addTab( tab, i18n("&General") );
- glay = new TQGridLayout( tab, 4, 2, marginHint(), spacingHint() );
+ glay = new TQGridLayout( tab, 5, 2, marginHint(), spacingHint() );
glay->setRowStretch( 3, 1 );
glay->setColStretch( 1, 1 );
@@ -140,19 +143,40 @@ namespace KMail {
TQWhatsThis::add( mOrganizationEdit, msg );
// "Email Address" line edit and label:
- // (row 3: spacer)
++row;
mEmailEdit = new KLineEdit( tab );
glay->addWidget( mEmailEdit, row, 1 );
label = new TQLabel( mEmailEdit, i18n("&Email address:"), tab );
glay->addWidget( label, row, 0 );
msg = i18n("<qt><h3>Email address</h3>"
- "<p>This field should have your full email address.</p>"
+ "<p>This field should have your full email address</p>"
+ "<p>This address is the primary one, used for all outgoing mail. "
+ "If you have more than one address, either create a new identity, "
+ "or add additional alias addresses in the field below.</p>"
"<p>If you leave this blank, or get it wrong, people "
"will have trouble replying to you.</p></qt>");
TQWhatsThis::add( label, msg );
TQWhatsThis::add( mEmailEdit, msg );
+ // "Email Aliases" string list edit and label:
+ ++row;
+ mAliasEdit = new SimpleStringListEditor( tab );
+ glay->addMultiCellWidget( mAliasEdit, row, row+1, 1, 1 );
+ label = new TQLabel( mAliasEdit, i18n("Email a&liases:"), tab );
+ glay->addWidget( label, row, 0, TQt::AlignTop );
+ msg = i18n("<qt><h3>Email aliases</h3>"
+ "<p>This field contains alias addresses that should also "
+ "be considered as belonging to this identity (as opposed "
+ "to representing a different identity).</p>"
+ "<p>Example:</p>"
+ "<table>"
+ "<tr><th>Primary address:</th><td>first.last@example.org</td></tr>"
+ "<tr><th>Aliases:</th><td>first@example.org<br>last@example.org</td></tr>"
+ "</table>"
+ "<p>Type one alias address per line.</p></qt>");
+ TQWhatsThis::add( label, msg );
+ TQWhatsThis::add( mAliasEdit, msg );
+
//
// Tab Widget: Cryptography
//
@@ -499,6 +523,15 @@ void IdentityDialog::slotOk() {
return;
}
+ const TQStringList aliases = mAliasEdit->stringList();
+ for ( TQStringList::const_iterator it = aliases.begin(), end = aliases.end() ; it != end ; ++it ) {
+ if ( !isValidSimpleEmailAddress( *it ) ) {
+ TQString errorMsg( simpleEmailAddressErrorMsg());
+ KMessageBox::sorry( this, errorMsg, i18n("Invalid Email Alias \"%1\"").arg( *it ) );
+ return;
+ }
+ }
+
if ( !validateAddresses( mReplyToEdit->text().stripWhiteSpace() ) ) {
return;
}
@@ -584,7 +617,8 @@ void IdentityDialog::slotOk() {
// "General" tab:
mNameEdit->setText( ident.fullName() );
mOrganizationEdit->setText( ident.organization() );
- mEmailEdit->setText( ident.emailAddr() );
+ mEmailEdit->setText( ident.primaryEmailAddress() );
+ mAliasEdit->setStringList( ident.emailAliases() );
// "Cryptography" tab:
mPGPSigningKeyRequester->setFingerprint( ident.pgpSigningKey() );
@@ -652,7 +686,9 @@ void IdentityDialog::slotOk() {
ident.setFullName( mNameEdit->text() );
ident.setOrganization( mOrganizationEdit->text() );
TQString email = mEmailEdit->text();
- ident.setEmailAddr( email );
+ ident.setPrimaryEmailAddress( email );
+ const TQStringList aliases = mAliasEdit->stringList();
+ ident.setEmailAliases( aliases );
// "Cryptography" tab:
ident.setPGPSigningKey( mPGPSigningKeyRequester->fingerprint().latin1() );
ident.setPGPEncryptionKey( mPGPEncryptionKeyRequester->fingerprint().latin1() );
diff --git a/kmail/identitydialog.h b/kmail/identitydialog.h
index 20bb55a70..f8e71073c 100644
--- a/kmail/identitydialog.h
+++ b/kmail/identitydialog.h
@@ -40,6 +40,7 @@ class TQCheckBox;
class TQComboBox;
class TQString;
class TQStringList;
+class SimpleStringListEditor;
class TemplatesConfiguration;
class KPushButton;
namespace Kleo {
@@ -87,6 +88,7 @@ namespace KMail {
TQLineEdit *mNameEdit;
TQLineEdit *mOrganizationEdit;
TQLineEdit *mEmailEdit;
+ SimpleStringListEditor *mAliasEdit;
// "cryptography" tab:
TQWidget *mCryptographyTab;
Kleo::SigningKeyRequester *mPGPSigningKeyRequester;
diff --git a/kmail/imapaccountbase.cpp b/kmail/imapaccountbase.cpp
index 778403988..b0f78c5aa 100644
--- a/kmail/imapaccountbase.cpp
+++ b/kmail/imapaccountbase.cpp
@@ -198,6 +198,7 @@ namespace KMail {
setOnlyLocallySubscribedFolders( config.readBoolEntry( "locally-subscribed-folders", false ) );
setLoadOnDemand( config.readBoolEntry( "loadondemand", false ) );
setListOnlyOpenFolders( config.readBoolEntry( "listOnlyOpenFolders", false ) );
+ mCapabilities = config.readListEntry( "capabilities", TQStringList() );
// read namespaces
nsMap map;
TQStringList list = config.readListEntry( TQString::number( PersonalNS ) );
@@ -237,6 +238,7 @@ namespace KMail {
config.writeEntry( "locally-subscribed-folders", onlyLocallySubscribedFolders() );
config.writeEntry( "loadondemand", loadOnDemand() );
config.writeEntry( "listOnlyOpenFolders", listOnlyOpenFolders() );
+ config.writeEntry( "capabilities", mCapabilities );
TQString data;
for ( nsMap::Iterator it = mNamespaces.begin(); it != mNamespaces.end(); ++it ) {
if ( !it.data().isEmpty() ) {
@@ -357,7 +359,7 @@ namespace KMail {
}
//-----------------------------------------------------------------------------
- void ImapAccountBase::changeSubscription( bool subscribe, const TQString& imapPath )
+ void ImapAccountBase::changeSubscription( bool subscribe, const TQString& imapPath, bool quiet )
{
// change the subscription of the folder
KURL url = getUrl();
@@ -380,6 +382,7 @@ namespace KMail {
// a bit of a hack to save one slot
if (subscribe) jd.onlySubscribed = true;
else jd.onlySubscribed = false;
+ jd.quiet = quiet;
insertJob(job, jd);
connect(job, TQT_SIGNAL(result(KIO::Job *)),
@@ -396,7 +399,9 @@ namespace KMail {
TQString path = static_cast<KIO::SimpleJob*>(job)->url().path();
if (job->error())
{
- handleJobError( job, i18n( "Error while trying to subscribe to %1:" ).arg( path ) + '\n' );
+ if ( !(*it).quiet )
+ handleJobError( job, i18n( "Error while trying to subscribe to %1:" ).arg( path ) + '\n' );
+ emit subscriptionChangeFailed( job->errorString() );
// ## emit subscriptionChanged here in case anyone needs it to support continue/cancel
}
else
@@ -416,9 +421,9 @@ namespace KMail {
// don't even allow removing one's own admin permission, so this code won't hurt either).
if ( imapPath == "/INBOX/" ) {
if ( parent->folderType() == KMFolderTypeImap )
- static_cast<KMFolderImap*>( parent->storage() )->setUserRights( ACLJobs::All );
+ static_cast<KMFolderImap*>( parent->storage() )->setUserRights( ACLJobs::All, ACLJobs::Ok );
else if ( parent->folderType() == KMFolderTypeCachedImap )
- static_cast<KMFolderCachedImap*>( parent->storage() )->setUserRights( ACLJobs::All );
+ static_cast<KMFolderCachedImap*>( parent->storage() )->setUserRights( ACLJobs::All, ACLJobs::Ok );
emit receivedUserRights( parent ); // warning, you need to connect first to get that one
return;
}
@@ -452,12 +457,15 @@ namespace KMail {
#ifndef NDEBUG
//kdDebug(5006) << "User Rights: " << ACLJobs::permissionsToString( job->permissions() ) << endl;
#endif
- // Store the permissions
- if ( folder->folderType() == KMFolderTypeImap )
- static_cast<KMFolderImap*>( folder->storage() )->setUserRights( job->permissions() );
- else if ( folder->folderType() == KMFolderTypeCachedImap )
- static_cast<KMFolderCachedImap*>( folder->storage() )->setUserRights( job->permissions() );
}
+ // Store the permissions
+ if ( folder->folderType() == KMFolderTypeImap )
+ static_cast<KMFolderImap*>( folder->storage() )->setUserRights( job->permissions(),
+ job->error() ? KMail::ACLJobs::FetchFailed : KMail::ACLJobs::Ok );
+ else if ( folder->folderType() == KMFolderTypeCachedImap )
+ static_cast<KMFolderCachedImap*>( folder->storage() )->setUserRights( job->permissions(),
+ job->error() ? KMail::ACLJobs::FetchFailed : KMail::ACLJobs::Ok );
+
if (mSlave) removeJob(job);
emit receivedUserRights( folder );
}
@@ -802,7 +810,7 @@ namespace KMail {
//-----------------------------------------------------------------------------
TQString ImapAccountBase::delimiterForNamespace( const TQString& prefix )
{
- kdDebug(5006) << "delimiterForNamespace " << prefix << endl;
+ //kdDebug(5006) << "delimiterForNamespace " << prefix << endl;
// try to match exactly
if ( mNamespaceToDelimiter.contains(prefix) ) {
return mNamespaceToDelimiter[prefix];
@@ -826,7 +834,7 @@ namespace KMail {
return mNamespaceToDelimiter[""];
}
// well, we tried
- kdDebug(5006) << "delimiterForNamespace - not found" << endl;
+ //kdDebug(5006) << "delimiterForNamespace - not found" << endl;
return TQString::null;
}
@@ -893,17 +901,17 @@ namespace KMail {
bool readOnly = false;
if (it != mapJobData.end()) {
const KMFolder * const folder = (*it).parent;
- assert(folder);
+ if( !folder ) return _error;
const KMFolderCachedImap * const imap = dynamic_cast<const KMFolderCachedImap*>( folder->storage() );
if ( imap ) {
- quotaAsString = imap->quotaInfo().toString();
+ quotaAsString = imap->quotaInfo().toString();
}
readOnly = folder->isReadOnly();
}
error = i18n("The folder is too close to its quota limit. (%1)").arg( quotaAsString );
if ( readOnly ) {
error += i18n("\nSince you do not have write privileges on this folder, "
- "please ask the owner of the folder to free up some space in it.");
+ "please ask the owner of the folder to free up some space in it.");
}
return error;
}
@@ -1015,12 +1023,12 @@ namespace KMail {
}
//-----------------------------------------------------------------------------
- void ImapAccountBase::processNewMailSingleFolder(KMFolder* folder)
+ void ImapAccountBase::processNewMailInFolder( KMFolder* folder, FolderListType type /*= Single*/ )
{
if ( mFoldersQueuedForChecking.contains( folder ) )
return;
- mFoldersQueuedForChecking.append(folder);
- mCheckingSingleFolder = true;
+ mFoldersQueuedForChecking.append( folder );
+ mCheckingSingleFolder = ( type == Single );
if ( checkingMail() )
{
disconnect( this, TQT_SIGNAL( finishedCheck( bool, CheckStatus ) ),
diff --git a/kmail/imapaccountbase.h b/kmail/imapaccountbase.h
index 26d7a4b01..39fb33b69 100644
--- a/kmail/imapaccountbase.h
+++ b/kmail/imapaccountbase.h
@@ -187,8 +187,10 @@ namespace KMail {
* Subscribe (@p subscribe = TRUE) / Unsubscribe the folder
* identified by @p imapPath.
* Emits subscriptionChanged signal on success.
+ * Emits subscriptionChangeFailed signal when it fails.
+ * @param quiet if false, an error message will be displayed if the job fails.
*/
- void changeSubscription(bool subscribe, const TQString& imapPath);
+ void changeSubscription(bool subscribe, const TQString& imapPath, bool quiet = false );
/**
* Returns whether the account is locally subscribed to the
@@ -252,9 +254,10 @@ namespace KMail {
virtual void cancelMailCheck();
/**
- * Init a new-mail-check for a single folder
+ * Init a new-mail-check for a single folder, and optionally its subfolders.
*/
- void processNewMailSingleFolder(KMFolder* folder);
+ enum FolderListType { Single, Recursive };
+ void processNewMailInFolder( KMFolder* folder, FolderListType type = Single );
/**
* Return true if we are processing a mailcheck for a single folder
@@ -323,7 +326,7 @@ namespace KMail {
/**
* Returns the root folder of this account
*/
- virtual FolderStorage* const rootFolder() const = 0;
+ virtual FolderStorage* rootFolder() const = 0;
/**
* Progress item for listDir
@@ -586,6 +589,12 @@ namespace KMail {
void subscriptionChanged(const TQString& imapPath, bool subscribed);
/**
+ * Emitted when changeSubscription() failed.
+ * @param errorMessage the error message that contains the reason for the failure
+ */
+ void subscriptionChangeFailed( const TQString &errorMessage );
+
+ /**
* Emitted upon completion of the job for setting the status for a group of UIDs,
* as a result of a setImapStatus call.
* On error, if the user chooses abort (not continue), cont is set to false.
@@ -595,7 +604,8 @@ namespace KMail {
/**
* Emitted when the get-user-rights job is done,
* as a result of a getUserRights call.
- * Use userRights() to retrieve them, they will still be on 0 if the job failed.
+ * Use userRights() to retrieve them after using userRightsState() to see if the results are
+ * valid.
*/
void receivedUserRights( KMFolder* folder );
diff --git a/kmail/imapjob.cpp b/kmail/imapjob.cpp
index 50db423cb..560343689 100644
--- a/kmail/imapjob.cpp
+++ b/kmail/imapjob.cpp
@@ -420,6 +420,8 @@ void ImapJob::slotGetMessageResult( KIO::Job * job )
// do not know if the message has no attachment or we simply did not load the header
if (msg->attachmentState() != KMMsgHasAttachment)
msg->updateAttachmentState();
+ if (msg->invitationState() != KMMsgHasInvitation)
+ msg->updateInvitationState();
}
} else {
kdDebug(5006) << "ImapJob::slotGetMessageResult - got no data for " << mPartSpecifier << endl;
diff --git a/kmail/importarchivedialog.cpp b/kmail/importarchivedialog.cpp
new file mode 100644
index 000000000..bdae8054d
--- /dev/null
+++ b/kmail/importarchivedialog.cpp
@@ -0,0 +1,107 @@
+/* Copyright 2009 Klarälvdalens 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) version 3 or any later version
+ accepted by the membership of KDE e.V. (or its successor approved
+ by the membership of KDE e.V.), which shall act as a proxy
+ defined in Section 14 of version 3 of the license.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "importarchivedialog.h"
+
+#include "kmfolder.h"
+#include "folderrequester.h"
+#include "kmmainwidget.h"
+#include "importjob.h"
+
+#include <kurlrequester.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#include <tqlayout.h>
+#include <tqlabel.h>
+
+using namespace KMail;
+
+ImportArchiveDialog::ImportArchiveDialog( TQWidget *parent, TQt::WidgetFlags flags )
+ : KDialogBase( parent, "import_archive_dialog", false, i18n( "Import Archive" ),
+ KDialogBase::Ok | KDialogBase::Cancel,
+ KDialogBase::Ok, true ),
+ mParentWidget( parent )
+{
+ setWFlags( flags );
+ TQWidget *mainWidget = new TQWidget( this );
+ TQGridLayout *mainLayout = new TQGridLayout( mainWidget );
+ mainLayout->setSpacing( KDialog::spacingHint() );
+ mainLayout->setMargin( KDialog::marginHint() );
+ setMainWidget( mainWidget );
+
+ int row = 0;
+
+ // TODO: Explaination label
+ // TODO: Use QFormLayout in KDE4
+ // TODO: better label for "Ok" button
+
+ TQLabel *folderLabel = new TQLabel( i18n( "&Folder:" ), mainWidget );
+ mainLayout->addWidget( folderLabel, row, 0 );
+ mFolderRequester = new FolderRequester( mainWidget, kmkernel->getKMMainWidget()->folderTree() );
+ folderLabel->setBuddy( mFolderRequester );
+ mainLayout->addWidget( mFolderRequester, row, 1 );
+ row++;
+
+ TQLabel *fileNameLabel = new TQLabel( i18n( "&Archive File:" ), mainWidget );
+ mainLayout->addWidget( fileNameLabel, row, 0 );
+ mUrlRequester = new KURLRequester( mainWidget );
+ mUrlRequester->setMode( KFile::LocalOnly );
+ mUrlRequester->setFilter( "*.tar *.zip *.tar.gz *.tar.bz2" );
+ fileNameLabel->setBuddy( mUrlRequester );
+ mainLayout->addWidget( mUrlRequester, row, 1 );
+ row++;
+
+ // TODO: what's this, tooltips
+
+ mainLayout->setColStretch( 1, 1 );
+ mainLayout->addItem( new TQSpacerItem( 1, 1, TQSizePolicy::Expanding, TQSizePolicy::Expanding ), row, 0 );
+
+ // Make it a bit bigger, else the folder requester cuts off the text too early
+ resize( 500, minimumSize().height() );
+}
+
+void ImportArchiveDialog::setFolder( KMFolder *defaultFolder )
+{
+ mFolderRequester->setFolder( defaultFolder );
+}
+
+void ImportArchiveDialog::slotOk()
+{
+ if ( !TQFile::exists( mUrlRequester->url() ) ) {
+ KMessageBox::information( this, i18n( "Please select an archive file that should be imported." ),
+ i18n( "No archive file selected" ) );
+ return;
+ }
+
+ if ( !mFolderRequester->folder() ) {
+ KMessageBox::information( this, i18n( "Please select the folder where the archive should be imported to." ),
+ i18n( "No target folder selected" ) );
+ return;
+ }
+
+ // TODO: check if url is empty. or better yet, disable ok button until file is chosen
+
+ ImportJob *importJob = new KMail::ImportJob( mParentWidget );
+ importJob->setFile( mUrlRequester->url() );
+ importJob->setRootFolder( mFolderRequester->folder() );
+ importJob->start();
+ accept();
+}
+
+#include "importarchivedialog.moc"
diff --git a/kmail/importarchivedialog.h b/kmail/importarchivedialog.h
new file mode 100644
index 000000000..0b04d9b84
--- /dev/null
+++ b/kmail/importarchivedialog.h
@@ -0,0 +1,55 @@
+/* Copyright 2009 Klarälvdalens 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) version 3 or any later version
+ accepted by the membership of KDE e.V. (or its successor approved
+ by the membership of KDE e.V.), which shall act as a proxy
+ defined in Section 14 of version 3 of the license.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef IMPORTARCHIVEDIALOG_H
+#define IMPORTARCHIVEDIALOG_H
+
+#include <kdialogbase.h>
+
+class KMFolder;
+class KURLRequester;
+
+namespace KMail
+{
+class FolderRequester;
+
+// TODO: Common base class for ArchiveFolderDialog and ImportArchiveDialog?
+class ImportArchiveDialog : public KDialogBase
+{
+ Q_OBJECT
+
+ public:
+
+ ImportArchiveDialog( TQWidget *parent, TQt::WidgetFlags flags );
+ void setFolder( KMFolder *defaultFolder );
+
+ protected slots:
+
+ /** reimp */
+ virtual void slotOk();
+
+ private:
+
+ TQWidget *mParentWidget;
+ FolderRequester *mFolderRequester;
+ KURLRequester *mUrlRequester;
+};
+
+}
+
+#endif
diff --git a/kmail/importjob.cpp b/kmail/importjob.cpp
new file mode 100644
index 000000000..3a7de1981
--- /dev/null
+++ b/kmail/importjob.cpp
@@ -0,0 +1,396 @@
+/* Copyright 2009 Klarälvdalens 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) version 3 or any later version
+ accepted by the membership of KDE e.V. (or its successor approved
+ by the membership of KDE e.V.), which shall act as a proxy
+ defined in Section 14 of version 3 of the license.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "importjob.h"
+
+#include "kmfolder.h"
+#include "folderutil.h"
+#include "kmfolderdir.h"
+#include "kmfolderimap.h"
+#include "imapjob.h"
+
+#include "progressmanager.h"
+
+#include <kdebug.h>
+#include <kzip.h>
+#include <ktar.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kmimetype.h>
+
+#include <tqwidget.h>
+#include <tqtimer.h>
+#include <tqfile.h>
+
+using namespace KMail;
+
+KMail::ImportJob::ImportJob( TQWidget *parentWidget )
+ : TQObject( parentWidget ),
+ mArchive( 0 ),
+ mRootFolder( 0 ),
+ mParentWidget( parentWidget ),
+ mNumberOfImportedMessages( 0 ),
+ mCurrentFolder( 0 ),
+ mCurrentMessage( 0 ),
+ mCurrentMessageFile( 0 ),
+ mProgressItem( 0 ),
+ mAborted( false )
+{
+}
+
+KMail::ImportJob::~ImportJob()
+{
+ if ( mArchive && mArchive->isOpened() ) {
+ mArchive->close();
+ }
+ delete mArchive;
+ mArchive = 0;
+}
+
+void KMail::ImportJob::setFile( const KURL &archiveFile )
+{
+ mArchiveFile = archiveFile;
+}
+
+void KMail::ImportJob::setRootFolder( KMFolder *rootFolder )
+{
+ mRootFolder = rootFolder;
+}
+
+void KMail::ImportJob::finish()
+{
+ kdDebug(5006) << "Finished import job." << endl;
+ mProgressItem->setComplete();
+ mProgressItem = 0;
+ TQString text = i18n( "Importing the archive file '%1' into the folder '%2' succeeded." )
+ .arg( mArchiveFile.path() ).arg( mRootFolder->name() );
+ text += "\n" + i18n( "1 message was imported.", "%n messages were imported.", mNumberOfImportedMessages );
+ KMessageBox::information( mParentWidget, text, i18n( "Import finished." ) );
+ deleteLater();
+}
+
+void KMail::ImportJob::cancelJob()
+{
+ abort( i18n( "The operation was canceled by the user." ) );
+}
+
+void KMail::ImportJob::abort( const TQString &errorMessage )
+{
+ if ( mAborted )
+ return;
+
+ mAborted = true;
+ TQString text = i18n( "Failed to import the archive into folder '%1'." ).arg( mRootFolder->name() );
+ text += "\n" + errorMessage;
+ if ( mProgressItem ) {
+ mProgressItem->setComplete();
+ mProgressItem = 0;
+ // The progressmanager will delete it
+ }
+ KMessageBox::sorry( mParentWidget, text, i18n( "Importing archive failed." ) );
+ deleteLater();
+}
+
+KMFolder * KMail::ImportJob::createSubFolder( KMFolder *parent, const TQString &folderName, mode_t permissions )
+{
+ KMFolder *newFolder = FolderUtil::createSubFolder( parent, parent->child(), folderName, TQString(),
+ KMFolderTypeMaildir );
+ if ( !newFolder ) {
+ abort( i18n( "Unable to create subfolder for folder '%1'." ).arg( parent->name() ) );
+ return 0;
+ }
+ else {
+ newFolder->createChildFolder(); // TODO: Just creating a child folder here is wasteful, only do
+ // that if really needed. We do it here so we can set the
+ // permissions
+ chmod( newFolder->location().latin1(), permissions | S_IXUSR );
+ chmod( newFolder->subdirLocation().latin1(), permissions | S_IXUSR );
+ // TODO: chown?
+ // TODO: what about subdirectories like "cur"?
+ return newFolder;
+ }
+}
+
+void KMail::ImportJob::enqueueMessages( const KArchiveDirectory *dir, KMFolder *folder )
+{
+ const KArchiveDirectory *messageDir = dynamic_cast<const KArchiveDirectory*>( dir->entry( "cur" ) );
+ if ( messageDir ) {
+ Messages messagesToQueue;
+ messagesToQueue.parent = folder;
+ const TQStringList entries = messageDir->entries();
+ for ( uint i = 0; i < entries.size(); i++ ) {
+ const KArchiveEntry *entry = messageDir->entry( entries[i] );
+ Q_ASSERT( entry );
+ if ( entry->isDirectory() ) {
+ kdWarning(5006) << "Unexpected subdirectory in archive folder " << dir->name() << endl;
+ }
+ else {
+ kdDebug(5006) << "Queueing message " << entry->name() << endl;
+ const KArchiveFile *file = static_cast<const KArchiveFile*>( entry );
+ messagesToQueue.files.append( file );
+ }
+ }
+ mQueuedMessages.append( messagesToQueue );
+ }
+ else {
+ kdWarning(5006) << "No 'cur' subdirectory for archive directory " << dir->name() << endl;
+ }
+}
+
+void KMail::ImportJob::messageAdded()
+{
+ mNumberOfImportedMessages++;
+ if ( mCurrentFolder->folderType() == KMFolderTypeMaildir ||
+ mCurrentFolder->folderType() == KMFolderTypeCachedImap ) {
+ const TQString messageFile = mCurrentFolder->location() + "/cur/" + mCurrentMessage->fileName();
+ // TODO: what if the file is not in the "cur" subdirectory?
+ if ( TQFile::exists( messageFile ) ) {
+ chmod( messageFile.latin1(), mCurrentMessageFile->permissions() );
+ // TODO: changing user/group he requires a bit more work, requires converting the strings
+ // to uid_t and gid_t
+ //getpwnam()
+ //chown( messageFile,
+ }
+ else {
+ kdWarning(5006) << "Unable to change permissions for newly created file: " << messageFile << endl;
+ }
+ }
+ // TODO: Else?
+
+ mCurrentMessage = 0;
+ mCurrentMessageFile = 0;
+ TQTimer::singleShot( 0, this, TQT_SLOT( importNextMessage() ) );
+}
+
+void KMail::ImportJob::importNextMessage()
+{
+ if ( mAborted )
+ return;
+
+ if ( mQueuedMessages.isEmpty() ) {
+ kdDebug(5006) << "importNextMessage(): Processed all messages in the queue." << endl;
+ if ( mCurrentFolder ) {
+ mCurrentFolder->close( "ImportJob" );
+ }
+ mCurrentFolder = 0;
+ importNextDirectory();
+ return;
+ }
+
+ Messages &messages = mQueuedMessages.front();
+ if ( messages.files.isEmpty() ) {
+ mQueuedMessages.pop_front();
+ importNextMessage();
+ return;
+ }
+
+ KMFolder *folder = messages.parent;
+ if ( folder != mCurrentFolder ) {
+ kdDebug(5006) << "importNextMessage(): Processed all messages in the current folder of the queue." << endl;
+ if ( mCurrentFolder ) {
+ mCurrentFolder->close( "ImportJob" );
+ }
+ mCurrentFolder = folder;
+ if ( mCurrentFolder->open( "ImportJob" ) != 0 ) {
+ abort( i18n( "Unable to open folder '%1'." ).arg( mCurrentFolder->name() ) );
+ return;
+ }
+ kdDebug(5006) << "importNextMessage(): Current folder of queue is now: " << mCurrentFolder->name() << endl;
+ mProgressItem->setStatus( i18n( "Importing folder %1" ).arg( mCurrentFolder->name() ) );
+ }
+
+ mProgressItem->setProgress( ( mProgressItem->progress() + 5 ) );
+
+ mCurrentMessageFile = messages.files.first();
+ Q_ASSERT( mCurrentMessageFile );
+ messages.files.removeFirst();
+
+ mCurrentMessage = new KMMessage();
+ mCurrentMessage->fromByteArray( mCurrentMessageFile->data(), true /* setStatus */ );
+ int retIndex;
+
+ // If this is not an IMAP folder, we can add the message directly. Otherwise, the whole thing is
+ // async, for online IMAP. While addMsg() fakes a sync call, we rather do it the async way here
+ // ourselves, as otherwise the whole thing gets pretty much messed up with regards to folder
+ // refcounting. Furthermore, the completion dialog would be shown before the messages are actually
+ // uploaded.
+ if ( mCurrentFolder->folderType() != KMFolderTypeImap ) {
+ if ( mCurrentFolder->addMsg( mCurrentMessage, &retIndex ) != 0 ) {
+ abort( i18n( "Failed to add a message to the folder '%1'." ).arg( mCurrentFolder->name() ) );
+ return;
+ }
+ messageAdded();
+ }
+ else {
+ ImapJob *imapJob = new ImapJob( mCurrentMessage, ImapJob::tPutMessage,
+ dynamic_cast<KMFolderImap*>( mCurrentFolder->storage() ) );
+ connect( imapJob, TQT_SIGNAL(result(KMail::FolderJob*)),
+ TQT_SLOT(messagePutResult(KMail::FolderJob*)) );
+ imapJob->start();
+ }
+}
+
+void KMail::ImportJob::messagePutResult( KMail::FolderJob *job )
+{
+ if ( mAborted )
+ return;
+
+ if ( job->error() ) {
+ abort( i18n( "Failed to upload a message to the IMAP server." ) );
+ return;
+ } else {
+
+ KMFolderImap *imap = dynamic_cast<KMFolderImap*>( mCurrentFolder->storage() );
+ Q_ASSERT( imap );
+
+ // Ok, we uploaded the message, but we still need to add it to the folder. Use addMsgQuiet(),
+ // otherwise it will be uploaded again.
+ imap->addMsgQuiet( mCurrentMessage );
+ messageAdded();
+ }
+}
+
+// Input: .inbox.directory
+// Output: inbox
+// Can also return an empty string if this is no valid dir name
+static TQString folderNameForDirectoryName( const TQString &dirName )
+{
+ Q_ASSERT( dirName.startsWith( "." ) );
+ const TQString end = ".directory";
+ const int expectedIndex = dirName.length() - end.length();
+ if ( dirName.lower().find( end ) != expectedIndex )
+ return TQString();
+ TQString returnName = dirName.left( dirName.length() - end.length() );
+ returnName = returnName.right( returnName.length() - 1 );
+ return returnName;
+}
+
+KMFolder* KMail::ImportJob::getOrCreateSubFolder( KMFolder *parentFolder, const TQString &subFolderName,
+ mode_t subFolderPermissions )
+{
+ if ( !parentFolder->createChildFolder() ) {
+ abort( i18n( "Unable to create subfolder for folder '%1'." ).arg( parentFolder->name() ) );
+ return 0;
+ }
+
+ KMFolder *subFolder = 0;
+ subFolder = dynamic_cast<KMFolder*>( parentFolder->child()->hasNamedFolder( subFolderName ) );
+
+ if ( !subFolder ) {
+ subFolder = createSubFolder( parentFolder, subFolderName, subFolderPermissions );
+ }
+ return subFolder;
+}
+
+void KMail::ImportJob::importNextDirectory()
+{
+ if ( mAborted )
+ return;
+
+ if ( mQueuedDirectories.isEmpty() ) {
+ finish();
+ return;
+ }
+
+ Folder folder = mQueuedDirectories.first();
+ KMFolder *currentFolder = folder.parent;
+ mQueuedDirectories.pop_front();
+ kdDebug(5006) << "importNextDirectory(): Working on directory " << folder.archiveDir->name() << endl;
+
+ TQStringList entries = folder.archiveDir->entries();
+ for ( uint i = 0; i < entries.size(); i++ ) {
+ const KArchiveEntry *entry = folder.archiveDir->entry( entries[i] );
+ Q_ASSERT( entry );
+ kdDebug(5006) << "Queueing entry " << entry->name() << endl;
+ if ( entry->isDirectory() ) {
+ const KArchiveDirectory *dir = static_cast<const KArchiveDirectory*>( entry );
+ if ( !dir->name().startsWith( "." ) ) {
+
+ kdDebug(5006) << "Queueing messages in folder " << entry->name() << endl;
+ KMFolder *subFolder = getOrCreateSubFolder( currentFolder, entry->name(), entry->permissions() );
+ if ( !subFolder )
+ return;
+
+ enqueueMessages( dir, subFolder );
+ }
+
+ // Entry starts with a dot, so we assume it is a subdirectory
+ else {
+
+ const TQString folderName = folderNameForDirectoryName( entry->name() );
+ if ( folderName.isEmpty() ) {
+ abort( i18n( "Unexpected subdirectory named '%1'." ).arg( entry->name() ) );
+ return;
+ }
+ KMFolder *subFolder = getOrCreateSubFolder( currentFolder, folderName, entry->permissions() );
+ if ( !subFolder )
+ return;
+
+ Folder newFolder;
+ newFolder.archiveDir = dir;
+ newFolder.parent = subFolder;
+ kdDebug(5006) << "Enqueueing directory " << entry->name() << endl;
+ mQueuedDirectories.push_back( newFolder );
+ }
+ }
+ }
+
+ importNextMessage();
+}
+
+// TODO:
+// BUGS:
+// Online IMAP can fail spectacular, for example when cancelling upload
+// Online IMAP: Inform that messages are still being uploaded on finish()!
+void KMail::ImportJob::start()
+{
+ Q_ASSERT( mRootFolder );
+ Q_ASSERT( mArchiveFile.isValid() );
+
+ KMimeType::Ptr mimeType = KMimeType::findByURL( mArchiveFile, 0, true /* local file */ );
+ if ( !mimeType->patterns().grep( "tar", false /* no case-sensitive */ ).isEmpty() )
+ mArchive = new KTar( mArchiveFile.path() );
+ else if ( !mimeType->patterns().grep( "zip", false ).isEmpty() )
+ mArchive = new KZip( mArchiveFile.path() );
+ else {
+ abort( i18n( "The file '%1' does not appear to be a valid archive." ).arg( mArchiveFile.path() ) );
+ return;
+ }
+
+ if ( !mArchive->open( IO_ReadOnly ) ) {
+ abort( i18n( "Unable to open archive file '%1'" ).arg( mArchiveFile.path() ) );
+ return;
+ }
+
+ mProgressItem = KPIM::ProgressManager::createProgressItem(
+ "ImportJob",
+ i18n( "Importing Archive" ),
+ TQString(),
+ true );
+ mProgressItem->setUsesBusyIndicator( true );
+ connect( mProgressItem, TQT_SIGNAL(progressItemCanceled(KPIM::ProgressItem*)),
+ this, TQT_SLOT(cancelJob()) );
+
+ Folder nextFolder;
+ nextFolder.archiveDir = mArchive->directory();
+ nextFolder.parent = mRootFolder;
+ mQueuedDirectories.push_back( nextFolder );
+ importNextDirectory();
+}
+
+#include "importjob.moc"
diff --git a/kmail/importjob.h b/kmail/importjob.h
new file mode 100644
index 000000000..ee7a0ac8b
--- /dev/null
+++ b/kmail/importjob.h
@@ -0,0 +1,126 @@
+/* Copyright 2009 Klarälvdalens 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) version 3 or any later version
+ accepted by the membership of KDE e.V. (or its successor approved
+ by the membership of KDE e.V.), which shall act as a proxy
+ defined in Section 14 of version 3 of the license.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef IMPORTJOB_H
+#define IMPORTJOB_H
+
+#include <kurl.h>
+
+#include <tqobject.h>
+#include <tqvaluelist.h>
+#include <tqptrlist.h>
+
+#include <sys/types.h>
+
+class TQWidget;
+class KArchive;
+class KArchiveDirectory;
+class KArchiveFile;
+class KMFolder;
+class KMMessage;
+
+namespace KPIM
+{
+ class ProgressItem;
+}
+
+namespace KMail
+{
+ class FolderJob;
+
+/**
+ * Imports an archive that was previously backed up with an BackupJob.
+ * This job will re-create the folder structure, under the root folder given in setRootFolder().
+ *
+ * The job deletes itself after it finished.
+ */
+class ImportJob : public TQObject
+{
+ Q_OBJECT
+
+ public:
+
+ explicit ImportJob( TQWidget *parentWidget = 0 );
+ ~ImportJob();
+ void start();
+ void setFile( const KURL &archiveFile );
+ void setRootFolder( KMFolder *rootFolder );
+
+ private slots:
+
+ void importNextMessage();
+ void cancelJob();
+ void messagePutResult( KMail::FolderJob *job );
+
+ private:
+
+ struct Folder
+ {
+ KMFolder *parent;
+ const KArchiveDirectory *archiveDir;
+ };
+
+ struct Messages
+ {
+ KMFolder *parent;
+ TQPtrList<KArchiveFile> files;
+ };
+
+ void finish();
+ void abort( const TQString &errorMessage );
+ void queueFolders();
+ void importNextDirectory();
+ KMFolder* createSubFolder( KMFolder *parent, const TQString &folderName, mode_t permissions );
+ KMFolder* getOrCreateSubFolder( KMFolder *parentFolder, const TQString &subFolderName,
+ mode_t subFolderPermissions );
+ void enqueueMessages( const KArchiveDirectory *dir, KMFolder *folder );
+ void messageAdded();
+
+ KArchive *mArchive;
+
+ // The root folder which the user has selected as the folder to which everything should be
+ // imported
+ KMFolder *mRootFolder;
+
+ TQWidget *mParentWidget;
+ KURL mArchiveFile;
+ int mNumberOfImportedMessages;
+
+ // List of archive folders with their corresponding KMail parent folder that are awaiting
+ // processing
+ TQValueList<Folder> mQueuedDirectories;
+
+ // List of list of messages and their parent folders which are awaiting processing
+ TQValueList<Messages> mQueuedMessages;
+
+ // The folder to which we are currently importing messages
+ KMFolder *mCurrentFolder;
+
+ // The message which is currently being added
+ KMMessage *mCurrentMessage;
+
+ // The archive file of the current message that is being added
+ KArchiveFile *mCurrentMessageFile;
+
+ KPIM::ProgressItem *mProgressItem;
+ bool mAborted;
+};
+
+}
+
+#endif
diff --git a/kmail/interfaces/bodypartformatter.h b/kmail/interfaces/bodypartformatter.h
index b31cb26b7..9bc947f53 100644
--- a/kmail/interfaces/bodypartformatter.h
+++ b/kmail/interfaces/bodypartformatter.h
@@ -35,7 +35,7 @@
#define __KMAIL_INTERFACE_BODYPARTFORMATTER_H__
namespace KMail {
-
+ class Callback;
class HtmlWriter;
namespace Interface {
@@ -47,7 +47,7 @@ namespace KMail {
public:
virtual ~BodyPartFormatter() {}
- /**
+ /**
@li Ok returned when format() generated some HTML
@li NeedContent returned when format() needs the body of the part
@li AsIcon returned when the part should be shown iconified
@@ -61,7 +61,7 @@ namespace KMail {
@return the result code (see above)
*/
- virtual Result format( BodyPart * part, KMail::HtmlWriter * writer ) const = 0;
+ virtual Result format( BodyPart * part, KMail::HtmlWriter * writer, Callback &c ) const = 0;
};
/**
diff --git a/kmail/interfaces/urlhandler.h b/kmail/interfaces/urlhandler.h
index fba673d65..38ada083f 100644
--- a/kmail/interfaces/urlhandler.h
+++ b/kmail/interfaces/urlhandler.h
@@ -57,6 +57,41 @@ namespace KMail {
false otherwise.
*/
virtual bool handleClick( const KURL & url, KMReaderWin * w ) const = 0;
+
+ /**
+ * Called when shift-clicking the link in the reader.
+ * @return true if the click was handled by this URLHandler, false otherwise
+ */
+ virtual bool handleShiftClick( const KURL &url, KMReaderWin *window ) const {
+ Q_UNUSED( url );
+ Q_UNUSED( window );
+ return false;
+ }
+
+ /**
+ * @return should return true if this URLHandler will handle the drag
+ */
+ virtual bool willHandleDrag( const KURL &url, const TQString &imagePath,
+ KMReaderWin *window ) const {
+ Q_UNUSED( url );
+ Q_UNUSED( window );
+ Q_UNUSED( imagePath );
+ return false;
+ }
+
+ /**
+ * Called when starting a drag with the given URL.
+ * If the drag is handled, you should create a drag object.
+ * @return true if the click was handled by this URLHandler, false otherwise
+ */
+ virtual bool handleDrag( const KURL &url, const TQString &imagePath,
+ KMReaderWin *window ) const {
+ Q_UNUSED( url );
+ Q_UNUSED( window );
+ Q_UNUSED( imagePath );
+ return false;
+ }
+
/** Called when RMB-clicking on a link in the reader. Should show
a context menu at the specified point with the specified
widget as parent.
diff --git a/kmail/isubject.cpp b/kmail/isubject.cpp
index 7219dc0e9..d231d365c 100644
--- a/kmail/isubject.cpp
+++ b/kmail/isubject.cpp
@@ -31,8 +31,15 @@ namespace KMail {
void ISubject::notify()
{
kdDebug(5006) << "ISubject::notify " << mObserverList.size() << endl;
- for ( TQValueVector<Interface::Observer*>::iterator it = mObserverList.begin() ; it != mObserverList.end() ; ++it )
- (*it)->update( this );
+
+ // iterate over a copy (to prevent crashes when
+ // {attach(),detach()} is called from an Observer::update()
+ const TQValueVector<Interface::Observer*> copy = mObserverList;
+ for ( TQValueVector<Interface::Observer*>::const_iterator it = copy.begin() ; it != copy.end() ; ++it ) {
+ if ( (*it) ) {
+ (*it)->update( this );
+ }
+ }
}
}
diff --git a/kmail/keyresolver.cpp b/kmail/keyresolver.cpp
index e35a7f5f9..3c1a952ca 100644
--- a/kmail/keyresolver.cpp
+++ b/kmail/keyresolver.cpp
@@ -42,6 +42,7 @@
#include "kcursorsaver.h"
#include "kleo_util.h"
+#include "stl_util.h"
#include <libemailfunctions/email.h>
#include <ui/keyselectiondialog.h>
@@ -103,7 +104,7 @@ static inline bool WithRespectToKeyID( const GpgME::Key & left, const GpgME::Key
return qstrcmp( left.keyID(), right.keyID() ) == 0 ;
}
-static bool ValidTrustedOpenPGPEncryptionKey( const GpgME::Key & key ) {
+static bool ValidOpenPGPEncryptionKey( const GpgME::Key & key ) {
if ( key.protocol() != GpgME::Context::OpenPGP ) {
return false;
}
@@ -119,9 +120,15 @@ static bool ValidTrustedOpenPGPEncryptionKey( const GpgME::Key & key ) {
#endif
if ( key.isRevoked() || key.isExpired() || key.isDisabled() || !key.canEncrypt() )
return false;
+ return true;
+}
+
+static bool ValidTrustedOpenPGPEncryptionKey( const GpgME::Key & key ) {
+ if ( !ValidOpenPGPEncryptionKey( key ) )
+ return false;
const std::vector<GpgME::UserID> uids = key.userIDs();
for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin() ; it != uids.end() ; ++it ) {
- if ( !it->isRevoked() && it->validity() != GpgME::UserID::Marginal )
+ if ( !it->isRevoked() && it->validity() >= GpgME::UserID::Marginal )
return true;
#if 0
else
@@ -134,7 +141,7 @@ static bool ValidTrustedOpenPGPEncryptionKey( const GpgME::Key & key ) {
return false;
}
-static bool ValidTrustedSMIMEEncryptionKey( const GpgME::Key & key ) {
+static bool ValidSMIMEEncryptionKey( const GpgME::Key & key ) {
if ( key.protocol() != GpgME::Context::CMS )
return false;
if ( key.isRevoked() || key.isExpired() || key.isDisabled() || !key.canEncrypt() )
@@ -142,6 +149,12 @@ static bool ValidTrustedSMIMEEncryptionKey( const GpgME::Key & key ) {
return true;
}
+static bool ValidTrustedSMIMEEncryptionKey( const GpgME::Key & key ) {
+ if ( !ValidSMIMEEncryptionKey( key ) )
+ return false;
+ return true;
+}
+
static inline bool ValidTrustedEncryptionKey( const GpgME::Key & key ) {
switch ( key.protocol() ) {
case GpgME::Context::OpenPGP:
@@ -153,6 +166,17 @@ static inline bool ValidTrustedEncryptionKey( const GpgME::Key & key ) {
}
}
+static inline bool ValidEncryptionKey( const GpgME::Key & key ) {
+ switch ( key.protocol() ) {
+ case GpgME::Context::OpenPGP:
+ return ValidOpenPGPEncryptionKey( key );
+ case GpgME::Context::CMS:
+ return ValidSMIMEEncryptionKey( key );
+ default:
+ return false;
+ }
+}
+
static inline bool ValidSigningKey( const GpgME::Key & key ) {
if ( key.isRevoked() || key.isExpired() || key.isDisabled() || !key.canSign() )
return false;
@@ -171,14 +195,26 @@ static inline bool NotValidTrustedOpenPGPEncryptionKey( const GpgME::Key & key )
return !ValidTrustedOpenPGPEncryptionKey( key );
}
+static inline bool NotValidOpenPGPEncryptionKey( const GpgME::Key & key ) {
+ return !ValidOpenPGPEncryptionKey( key );
+}
+
static inline bool NotValidTrustedSMIMEEncryptionKey( const GpgME::Key & key ) {
return !ValidTrustedSMIMEEncryptionKey( key );
}
+static inline bool NotValidSMIMEEncryptionKey( const GpgME::Key & key ) {
+ return !ValidSMIMEEncryptionKey( key );
+}
+
static inline bool NotValidTrustedEncryptionKey( const GpgME::Key & key ) {
return !ValidTrustedEncryptionKey( key );
}
+static inline bool NotValidEncryptionKey( const GpgME::Key & key ) {
+ return !ValidEncryptionKey( key );
+}
+
static inline bool NotValidSigningKey( const GpgME::Key & key ) {
return !ValidSigningKey( key );
}
@@ -191,6 +227,40 @@ static inline bool NotValidSMIMESigningKey( const GpgME::Key & key ) {
return !ValidSMIMESigningKey( key );
}
+namespace {
+ struct ByTrustScore {
+ static int score( const GpgME::UserID & uid ) {
+ return uid.isRevoked() || uid.isInvalid() ? -1 : uid.validity() ;
+ }
+ bool operator()( const GpgME::UserID & lhs, const GpgME::UserID & rhs ) const {
+ return score( lhs ) < score( rhs ) ;
+ }
+ };
+}
+
+static std::vector<GpgME::UserID> matchingUIDs( const std::vector<GpgME::UserID> & uids, const TQString & address ) {
+ if ( address.isEmpty() )
+ return std::vector<GpgME::UserID>();
+
+ std::vector<GpgME::UserID> result;
+ result.reserve( uids.size() );
+ for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin(), end = uids.end() ; it != end ; ++it )
+ // PENDING(marc) check DN for an EMAIL, too, in case of X.509 certs... :/
+ if ( const char * email = it->email() )
+ if ( *email && TQString::fromUtf8( email ).stripWhiteSpace().lower() == address )
+ result.push_back( *it );
+ return result;
+}
+
+static GpgME::UserID findBestMatchUID( const GpgME::Key & key, const TQString & address ) {
+ const std::vector<GpgME::UserID> all = key.userIDs();
+ if ( all.empty() )
+ return GpgME::UserID();
+ const std::vector<GpgME::UserID> matching = matchingUIDs( all, address.lower() );
+ const std::vector<GpgME::UserID> & v = matching.empty() ? all : matching ;
+ return *std::max_element( v.begin(), v.end(), ByTrustScore() );
+}
+
static TQStringList keysAsStrings( const std::vector<GpgME::Key>& keys ) {
TQStringList strings;
for ( std::vector<GpgME::Key>::const_iterator it = keys.begin() ; it != keys.end() ; ++it ) {
@@ -205,35 +275,40 @@ static TQStringList keysAsStrings( const std::vector<GpgME::Key>& keys ) {
return strings;
}
-static inline std::vector<GpgME::Key> TrustedOrConfirmed( const std::vector<GpgME::Key> & keys ) {
+static std::vector<GpgME::Key> trustedOrConfirmed( const std::vector<GpgME::Key> & keys, const TQString & address, bool & canceled ) {
+ // PENDING(marc) work on UserIDs here?
std::vector<GpgME::Key> fishies;
std::vector<GpgME::Key> ickies;
+ std::vector<GpgME::Key> rewookies;
std::vector<GpgME::Key>::const_iterator it = keys.begin();
const std::vector<GpgME::Key>::const_iterator end = keys.end();
for ( ; it != end ; it++ ) {
- const GpgME::Key key = *it;
- assert( ValidTrustedEncryptionKey( key ) );
- const std::vector<GpgME::UserID> uids = key.userIDs();
- for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin() ; it != uids.end() ; ++it ) {
- if ( !it->isRevoked() && it->validity() == GpgME::UserID::Marginal ) {
+ const GpgME::Key & key = *it;
+ assert( ValidEncryptionKey( key ) );
+ const GpgME::UserID uid = findBestMatchUID( key, address );
+ if ( uid.isRevoked() ) {
+ rewookies.push_back( key );
+ }
+ if ( !uid.isRevoked() && uid.validity() == GpgME::UserID::Marginal ) {
fishies.push_back( key );
- break;
- }
- if ( !it->isRevoked() && it->validity() < GpgME::UserID::Never ) {
+ }
+ if ( !uid.isRevoked() && uid.validity() < GpgME::UserID::Never ) {
ickies.push_back( key );
- break;
- }
}
}
- if ( fishies.empty() && ickies.empty() )
+ if ( fishies.empty() && ickies.empty() && rewookies.empty() )
return keys;
// if some keys are not fully trusted, let the user confirm their use
- TQString msg = i18n("One or more of your configured OpenPGP encryption "
- "keys or S/MIME certificates is not fully trusted "
- "for encryption.");
+ TQString msg = address.isEmpty()
+ ? i18n("One or more of your configured OpenPGP encryption "
+ "keys or S/MIME certificates is not fully trusted "
+ "for encryption.")
+ : i18n("One or more of the OpenPGP encryption keys or S/MIME "
+ "certificates for recipient \"%1\" is not fully trusted "
+ "for encryption.").arg(address) ;
if ( !fishies.empty() ) {
// certificates can't have marginal trust
@@ -244,6 +319,10 @@ static inline std::vector<GpgME::Key> TrustedOrConfirmed( const std::vector<GpgM
msg += i18n( "\nThe following keys or certificates have unknown trust level: \n");
msg += keysAsStrings( ickies ).join(",");
}
+ if ( !rewookies.empty() ) {
+ msg += i18n( "\nThe following keys or certificates are <b>revoked</b>: \n");
+ msg += keysAsStrings( rewookies ).join(",");
+ }
if( KMessageBox::warningContinueCancel( 0, msg, i18n("Not Fully Trusted Encryption Keys"),
KStdGuiItem::cont(),
@@ -251,7 +330,8 @@ static inline std::vector<GpgME::Key> TrustedOrConfirmed( const std::vector<GpgM
== KMessageBox::Continue )
return keys;
else
- return std::vector<GpgME::Key>();
+ canceled = true;
+ return std::vector<GpgME::Key>();
}
namespace {
@@ -266,6 +346,20 @@ namespace {
const Kleo::CryptoMessageFormat format;
};
+
+ struct IsForFormat : std::unary_function<GpgME::Key,bool> {
+ explicit IsForFormat( Kleo::CryptoMessageFormat f )
+ : protocol( isOpenPGP( f ) ? GpgME::Context::OpenPGP :
+ isSMIME( f ) ? GpgME::Context::CMS :
+ /* else */ GpgME::Context::Unknown ) {}
+
+ bool operator()( const GpgME::Key & key ) const {
+ return key.protocol() == protocol ;
+ }
+
+ const GpgME::Context::Protocol protocol;
+ };
+
}
@@ -334,6 +428,11 @@ public:
}
void operator()( Item & item );
+ template <typename Container>
+ void process( Container & c ) {
+ *this = std::for_each( c.begin(), c.end(), *this );
+ }
+
#define make_int_accessor(x) unsigned int num##x() const { return m##x; }
make_int_accessor(NoKey)
make_int_accessor(NeverEncrypt)
@@ -346,6 +445,7 @@ public:
#undef make_int_accessor
private:
EncryptionPreference mDefaultPreference;
+ bool mNoOps;
unsigned int mTotal;
unsigned int mNoKey;
unsigned int mNeverEncrypt, mUnknownPreference, mAlwaysEncrypt,
@@ -353,12 +453,14 @@ private:
};
void Kleo::KeyResolver::EncryptionPreferenceCounter::operator()( Item & item ) {
+ if ( _this ) {
if ( item.needKeys )
item.keys = _this->getEncryptionKeys( item.address, true );
if ( item.keys.empty() ) {
++mNoKey;
return;
}
+ }
switch ( !item.pref ? mDefaultPreference : item.pref ) {
#define CASE(x) case Kleo::x: ++m##x; break
CASE(NeverEncrypt);
@@ -427,13 +529,13 @@ namespace {
void EncryptionFormatPreferenceCounter::operator()( const Kleo::KeyResolver::Item & item ) {
if ( item.format & (Kleo::InlineOpenPGPFormat|Kleo::OpenPGPMIMEFormat) &&
std::find_if( item.keys.begin(), item.keys.end(),
- ValidTrustedOpenPGPEncryptionKey ) != item.keys.end() ) {
+ ValidTrustedOpenPGPEncryptionKey ) != item.keys.end() ) { // -= trusted?
CASE(OpenPGPMIME);
CASE(InlineOpenPGP);
}
if ( item.format & (Kleo::SMIMEFormat|Kleo::SMIMEOpaqueFormat) &&
std::find_if( item.keys.begin(), item.keys.end(),
- ValidTrustedSMIMEEncryptionKey ) != item.keys.end() ) {
+ ValidTrustedSMIMEEncryptionKey ) != item.keys.end() ) { // -= trusted?
CASE(SMIME);
CASE(SMIMEOpaque);
}
@@ -523,13 +625,108 @@ Kpgp::Result Kleo::KeyResolver::checkKeyNearExpiry( const GpgME::Key & key, cons
const GpgME::Subkey subkey = key.subkey(0);
if ( d->alreadyWarnedFingerprints.count( subkey.fingerprint() ) )
return Kpgp::Ok; // already warned about this one (and so about it's issuers)
- d->alreadyWarnedFingerprints.insert( subkey.fingerprint() );
if ( subkey.neverExpires() )
return Kpgp::Ok;
static const double secsPerDay = 24 * 60 * 60;
- const int daysTillExpiry =
- 1 + int( ::difftime( subkey.expirationTime(), time(0) ) / secsPerDay );
+ const double secsTillExpiry = ::difftime( subkey.expirationTime(), time(0) );
+ if ( secsTillExpiry <= 0 ) {
+ const int daysSinceExpiry = 1 + int( -secsTillExpiry / secsPerDay );
+ kdDebug() << "Key 0x" << key.shortKeyID() << " expired less than "
+ << daysSinceExpiry << " days ago" << endl;
+ const TQString msg =
+ key.protocol() == GpgME::Context::OpenPGP
+ ? ( mine ? sign
+ ? i18n("<p>Your OpenPGP signing key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
+ "<p>expired less than a day ago.</p>",
+ "<p>Your OpenPGP signing key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
+ "<p>expired %n days ago.</p>",
+ daysSinceExpiry )
+ : i18n("<p>Your OpenPGP encryption key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
+ "<p>expired less than a day ago.</p>",
+ "<p>Your OpenPGP encryption key</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
+ "<p>expired %n days ago.</p>",
+ daysSinceExpiry )
+ : i18n("<p>The OpenPGP key for</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
+ "<p>expired less than a day ago.</p>",
+ "<p>The OpenPGP key for</p><p align=center><b>%1</b> (KeyID 0x%2)</p>"
+ "<p>expired %n days ago.</p>",
+ daysSinceExpiry ) ).arg( TQString::fromUtf8( key.userID(0).id() ),
+ key.shortKeyID() )
+ : ( ca
+ ? ( key.isRoot()
+ ? ( mine ? sign
+ ? i18n("<p>The root certificate</p><p align=center><b>%3</b></p>"
+ "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired less than a day ago.</p>",
+ "<p>The root certificate</p><p align=center><b>%3</b></p>"
+ "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired %n days ago.</p>",
+ daysSinceExpiry )
+ : i18n("<p>The root certificate</p><p align=center><b>%3</b></p>"
+ "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired less than a day ago.</p>",
+ "<p>The root certificate</p><p align=center><b>%3</b></p>"
+ "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired %n days ago.</p>",
+ daysSinceExpiry )
+ : i18n("<p>The root certificate</p><p align=center><b>%3</b></p>"
+ "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired less than a day ago.</p>",
+ "<p>The root certificate</p><p align=center><b>%3</b></p>"
+ "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired %n days ago.</p>",
+ daysSinceExpiry ) )
+ : ( mine ? sign
+ ? i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
+ "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired less than a day ago.</p>",
+ "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
+ "<p>for your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired %n days ago.</p>",
+ daysSinceExpiry )
+ : i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
+ "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired less than a day ago.</p>",
+ "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
+ "<p>for your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired %n days ago.</p>",
+ daysSinceExpiry )
+ : i18n("<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
+ "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired less than a day ago.</p>",
+ "<p>The intermediate CA certificate</p><p align=center><b>%3</b></p>"
+ "<p>for S/MIME certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired %n days ago.</p>",
+ daysSinceExpiry ) ) ).arg( Kleo::DN( orig.userID(0).id() ).prettyDN(),
+ orig.issuerSerial(),
+ Kleo::DN( key.userID(0).id() ).prettyDN() )
+ : ( mine ? sign
+ ? i18n("<p>Your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired less than a day ago.</p>",
+ "<p>Your S/MIME signing certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired %n days ago.</p>",
+ daysSinceExpiry )
+ : i18n("<p>Your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired less than a day ago.</p>",
+ "<p>Your S/MIME encryption certificate</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired %n days ago.</p>",
+ daysSinceExpiry )
+ : i18n("<p>The S/MIME certificate for</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired less than a day ago.</p>",
+ "<p>The S/MIME certificate for</p><p align=center><b>%1</b> (serial number %2)</p>"
+ "<p>expired %n days ago.</p>",
+ daysSinceExpiry ) ).arg( Kleo::DN( key.userID(0).id() ).prettyDN(),
+ key.issuerSerial() ) );
+ d->alreadyWarnedFingerprints.insert( subkey.fingerprint() );
+ if ( KMessageBox::warningContinueCancel( 0, msg,
+ key.protocol() == GpgME::Context::OpenPGP
+ ? i18n("OpenPGP Key Expired" )
+ : i18n("S/MIME Certificate Expired" ),
+ KStdGuiItem::cont(), dontAskAgainName ) == KMessageBox::Cancel )
+ return Kpgp::Canceled;
+ } else {
+ const int daysTillExpiry = 1 + int( secsTillExpiry / secsPerDay );
kdDebug() << "Key 0x" << key.shortKeyID() << " expires in less than "
<< daysTillExpiry << " days" << endl;
const int threshold =
@@ -629,6 +826,7 @@ Kpgp::Result Kleo::KeyResolver::checkKeyNearExpiry( const GpgME::Key & key, cons
"<p>expires in less than %n days.</p>",
daysTillExpiry ) ).arg( Kleo::DN( key.userID(0).id() ).prettyDN(),
key.issuerSerial() ) );
+ d->alreadyWarnedFingerprints.insert( subkey.fingerprint() );
if ( KMessageBox::warningContinueCancel( 0, msg,
key.protocol() == GpgME::Context::OpenPGP
? i18n("OpenPGP Key Expires Soon" )
@@ -637,6 +835,7 @@ Kpgp::Result Kleo::KeyResolver::checkKeyNearExpiry( const GpgME::Key & key, cons
== KMessageBox::Cancel )
return Kpgp::Canceled;
}
+ }
if ( key.isRoot() )
return Kpgp::Ok;
else if ( const char * chain_id = key.chainID() ) {
@@ -657,10 +856,10 @@ Kpgp::Result Kleo::KeyResolver::setEncryptToSelfKeys( const TQStringList & finge
std::vector<GpgME::Key> keys = lookup( fingerprints );
std::remove_copy_if( keys.begin(), keys.end(),
std::back_inserter( d->mOpenPGPEncryptToSelfKeys ),
- NotValidTrustedOpenPGPEncryptionKey );
+ NotValidTrustedOpenPGPEncryptionKey ); // -= trusted?
std::remove_copy_if( keys.begin(), keys.end(),
std::back_inserter( d->mSMIMEEncryptToSelfKeys ),
- NotValidTrustedSMIMEEncryptionKey );
+ NotValidTrustedSMIMEEncryptionKey ); // -= trusted?
if ( d->mOpenPGPEncryptToSelfKeys.size() + d->mSMIMEEncryptToSelfKeys.size()
< keys.size() ) {
@@ -814,6 +1013,20 @@ Kleo::Action Kleo::KeyResolver::checkEncryptionPreferences( bool encryptionReque
d->mOpenPGPEncryptToSelfKeys.empty() && d->mSMIMEEncryptToSelfKeys.empty() )
return Impossible;
+ if ( !encryptionRequested && !mOpportunisticEncyption ) {
+ // try to minimize crypto ops (including key lookups) by only
+ // looking up keys when at least one the the encryption
+ // preferences needs it:
+ EncryptionPreferenceCounter count( 0, UnknownPreference );
+ count.process( d->mPrimaryEncryptionKeys );
+ count.process( d->mSecondaryEncryptionKeys );
+ if ( !count.numAlwaysEncrypt() &&
+ !count.numAlwaysAskForEncryption() && // this guy might not need a lookup, when declined, but it's too complex to implement that here
+ !count.numAlwaysEncryptIfPossible() &&
+ !count.numAskWheneverPossible() )
+ return DontDoIt;
+ }
+
EncryptionPreferenceCounter count( this, mOpportunisticEncyption ? AskWheneverPossible : UnknownPreference );
count = std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
count );
@@ -859,9 +1072,10 @@ Kpgp::Result Kleo::KeyResolver::resolveAllKeys( bool& signingRequested, bool& en
result = resolveEncryptionKeys( signingRequested );
if ( result != Kpgp::Ok )
return result;
- if ( signingRequested )
- if ( encryptionRequested )
+ if ( signingRequested ) {
+ if ( encryptionRequested ) {
result = resolveSigningKeysForEncryption();
+ }
else {
result = resolveSigningKeysForSigningOnly();
if ( result == Kpgp::Failure ) {
@@ -869,6 +1083,7 @@ Kpgp::Result Kleo::KeyResolver::resolveAllKeys( bool& signingRequested, bool& en
return Kpgp::Ok;
}
}
+ }
return result;
}
@@ -1334,10 +1549,10 @@ Kpgp::Result Kleo::KeyResolver::showKeyApprovalDialog() {
std::remove_copy_if( senderKeys.begin(), senderKeys.end(),
std::back_inserter( d->mOpenPGPEncryptToSelfKeys ),
- NotValidTrustedOpenPGPEncryptionKey );
+ NotValidTrustedOpenPGPEncryptionKey ); // -= trusted (see above, too)?
std::remove_copy_if( senderKeys.begin(), senderKeys.end(),
std::back_inserter( d->mSMIMEEncryptToSelfKeys ),
- NotValidTrustedSMIMEEncryptionKey );
+ NotValidTrustedSMIMEEncryptionKey ); // -= trusted (see above, too)?
return Kpgp::Ok;
}
@@ -1364,16 +1579,21 @@ std::vector<GpgME::Key> Kleo::KeyResolver::signingKeys( CryptoMessageFormat f )
std::vector<GpgME::Key> Kleo::KeyResolver::selectKeys( const TQString & person, const TQString & msg, const std::vector<GpgME::Key> & selectedKeys ) const {
+ const bool opgp = containsOpenPGP( mCryptoMessageFormats );
+ const bool x509 = containsSMIME( mCryptoMessageFormats );
+
Kleo::KeySelectionDialog dlg( i18n("Encryption Key Selection"),
- msg, selectedKeys,
- Kleo::KeySelectionDialog::ValidEncryptionKeys,
+ msg, KPIM::getEmailAddress(person), selectedKeys,
+ Kleo::KeySelectionDialog::ValidEncryptionKeys
+ & ~(opgp ? 0 : Kleo::KeySelectionDialog::OpenPGPKeys)
+ & ~(x509 ? 0 : Kleo::KeySelectionDialog::SMIMEKeys),
true, true ); // multi-selection and "remember choice" box
if ( dlg.exec() != TQDialog::Accepted )
return std::vector<GpgME::Key>();
std::vector<GpgME::Key> keys = dlg.selectedKeys();
keys.erase( std::remove_if( keys.begin(), keys.end(),
- NotValidTrustedEncryptionKey ),
+ NotValidTrustedEncryptionKey ), // -= trusted?
keys.end() );
if ( !keys.empty() && dlg.rememberSelection() )
setKeysForAddress( person, dlg.pgpKeyFingerprints(), dlg.smimeFingerprints() );
@@ -1396,70 +1616,80 @@ std::vector<GpgME::Key> Kleo::KeyResolver::getEncryptionKeys( const TQString & p
if ( !keys.empty() ) {
// Check if all of the keys are trusted and valid encryption keys
if ( std::find_if( keys.begin(), keys.end(),
- NotValidTrustedEncryptionKey ) != keys.end() ) {
+ NotValidTrustedEncryptionKey ) != keys.end() ) { // -= trusted?
// not ok, let the user select: this is not conditional on !quiet,
// since it's a bug in the configuration and the user should be
// notified about it as early as possible:
keys = selectKeys( person,
i18n("if in your language something like "
- "'key(s)' isn't possible please "
+ "'certificate(s)' isn't possible please "
"use the plural in the translation",
"There is a problem with the "
- "encryption key(s) for \"%1\".\n\n"
- "Please re-select the key(s) which should "
+ "encryption certificate(s) for \"%1\".\n\n"
+ "Please re-select the certificate(s) which should "
"be used for this recipient.").arg(person),
keys );
}
- keys = TrustedOrConfirmed( keys );
+ bool canceled = false;
+ keys = trustedOrConfirmed( keys, address, canceled );
+ if ( canceled )
+ return std::vector<GpgME::Key>();
if ( !keys.empty() )
return keys;
- // hmmm, should we not return the keys in any case here?
+ // keys.empty() is considered cancel by callers, so go on
}
}
// Now search all public keys for matching keys
std::vector<GpgME::Key> matchingKeys = lookup( person );
matchingKeys.erase( std::remove_if( matchingKeys.begin(), matchingKeys.end(),
- NotValidTrustedEncryptionKey ),
+ NotValidEncryptionKey ),
matchingKeys.end() );
// if no keys match the complete address look for keys which match
// the canonical mail address
if ( matchingKeys.empty() ) {
matchingKeys = lookup( address );
matchingKeys.erase( std::remove_if( matchingKeys.begin(), matchingKeys.end(),
- NotValidTrustedEncryptionKey ),
+ NotValidEncryptionKey ),
matchingKeys.end() );
}
// if called with quite == true (from EncryptionPreferenceCounter), we only want to
// check if there are keys for this recipients, not (yet) their validity, so
// don't show the untrusted encryption key warning in that case
+ bool canceled = false;
if ( !quiet )
- matchingKeys = TrustedOrConfirmed( matchingKeys );
+ matchingKeys = trustedOrConfirmed( matchingKeys, address, canceled );
+ if ( canceled )
+ return std::vector<GpgME::Key>();
if ( quiet || matchingKeys.size() == 1 )
return matchingKeys;
// no match until now, or more than one key matches; let the user
// choose the key(s)
// FIXME: let user get the key from keyserver
- return TrustedOrConfirmed( selectKeys( person,
+ return trustedOrConfirmed( selectKeys( person,
matchingKeys.empty()
? i18n("if in your language something like "
- "'key(s)' isn't possible please "
+ "'certificate(s)' isn't possible please "
"use the plural in the translation",
- "No valid and trusted encryption key was "
- "found for \"%1\".\n\n"
- "Select the key(s) which should "
- "be used for this recipient.").arg(person)
+ "<qt>No valid and trusted encryption certificate was "
+ "found for \"%1\".<br/><br/>"
+ "Select the certificate(s) which should "
+ "be used for this recipient. If there is no suitable certificate in the list "
+ "you can also search for external certificates by clicking the button: search for external certificates.</qt>")
+ .arg( TQStyleSheet::escape(person) )
: i18n("if in your language something like "
- "'key(s)' isn't possible please "
+ "'certificate(s)' isn't possible please "
"use the plural in the translation",
- "More than one key matches \"%1\".\n\n"
- "Select the key(s) which should "
- "be used for this recipient.").arg(person),
- matchingKeys ) );
+ "More than one certificate matches \"%1\".\n\n"
+ "Select the certificate(s) which should "
+ "be used for this recipient.").arg( TQStyleSheet::escape(person) ),
+ matchingKeys ), address, canceled );
+ // we can ignore 'canceled' here, since trustedOrConfirmed() returns
+ // an empty vector when canceled == true, and we'd just do the same
}
@@ -1513,8 +1743,11 @@ void Kleo::KeyResolver::addKeys( const std::vector<Item> & items ) {
SplitInfo si( it->address );
CryptoMessageFormat f = AutoFormat;
for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) {
- if ( concreteCryptoMessageFormats[i] & it->format ) {
- f = concreteCryptoMessageFormats[i];
+ const CryptoMessageFormat fmt = concreteCryptoMessageFormats[i];
+ if ( ( fmt & it->format ) &&
+ kdtools::any( it->keys.begin(), it->keys.end(), IsForFormat( fmt ) ) )
+ {
+ f = fmt;
break;
}
}
diff --git a/kmail/khtmlparthtmlwriter.cpp b/kmail/khtmlparthtmlwriter.cpp
index dfc9fd358..2d29d3c9e 100644
--- a/kmail/khtmlparthtmlwriter.cpp
+++ b/kmail/khtmlparthtmlwriter.cpp
@@ -49,7 +49,7 @@ namespace KMail {
KHtmlPartHtmlWriter::KHtmlPartHtmlWriter( KHTMLPart * part,
TQObject * parent, const char * name )
: TQObject( parent, name ), HtmlWriter(),
- mHtmlPart( part ), mState( Ended ), mHtmlTimer( 0, "mHtmlTimer" )
+ mHtmlPart( part ), mHtmlTimer( 0, "mHtmlTimer" ), mState( Ended )
{
assert( part );
connect( &mHtmlTimer, TQT_SIGNAL(timeout()), TQT_SLOT(slotWriteNextHtmlChunk()) );
diff --git a/kmail/kleo_util.h b/kmail/kleo_util.h
index b2378e9fa..dc0eb6d2c 100644
--- a/kmail/kleo_util.h
+++ b/kmail/kleo_util.h
@@ -77,5 +77,12 @@ static inline bool isOpenPGP( Kleo::CryptoMessageFormat f ) {
return f == Kleo::InlineOpenPGPFormat || f == Kleo::OpenPGPMIMEFormat ;
}
+static inline bool containsSMIME( unsigned int f ) {
+ return f & (Kleo::SMIMEFormat|Kleo::SMIMEOpaqueFormat) ;
+}
+
+static inline bool containsOpenPGP( unsigned int f ) {
+ return f & (Kleo::OpenPGPMIMEFormat|Kleo::InlineOpenPGPFormat) ;
+}
#endif // __KDEPIM_KMAIL_KLEO_UTIL_H__
diff --git a/kmail/kmacctcachedimap.cpp b/kmail/kmacctcachedimap.cpp
index 2305b0809..b673b5e14 100644
--- a/kmail/kmacctcachedimap.cpp
+++ b/kmail/kmacctcachedimap.cpp
@@ -179,21 +179,6 @@ void KMAcctCachedImap::cancelMailCheck()
}
}
-//-----------------------------------------------------------------------------
-void KMAcctCachedImap::killJobsForItem(KMFolderTreeItem * fti)
-{
- TQMap<KIO::Job *, jobData>::Iterator it = mapJobData.begin();
- while (it != mapJobData.end())
- {
- if (it.data().parent == fti->folder())
- {
- killAllJobs();
- break;
- }
- else ++it;
- }
-}
-
// Reimplemented from ImapAccountBase because we only check one folder at a time
void KMAcctCachedImap::slotCheckQueuedFolders()
{
@@ -217,7 +202,12 @@ void KMAcctCachedImap::processNewMail( bool /*interactive*/ )
else {
KMFolder* f = mMailCheckFolders.front();
mMailCheckFolders.pop_front();
- processNewMail( static_cast<KMFolderCachedImap *>( f->storage() ), false );
+
+ // Only check mail if the folder really exists, it might have been removed by the sync in
+ // the meantime.
+ if ( f ) {
+ processNewMail( static_cast<KMFolderCachedImap *>( f->storage() ), !checkingSingleFolder() );
+ }
}
}
@@ -234,7 +224,7 @@ void KMAcctCachedImap::processNewMail( KMFolderCachedImap* folder,
mNoopTimer.stop();
// reset namespace todo
- if ( folder == mFolder ) {
+ if ( folder == mFolder && !namespaces().isEmpty() ) {
TQStringList nsToList = namespaces()[PersonalNS];
TQStringList otherNSToCheck = namespaces()[OtherUsersNS];
otherNSToCheck += namespaces()[SharedNS];
@@ -361,8 +351,8 @@ void KMAcctCachedImap::invalidateIMAPFolders( KMFolderCachedImap* folder )
TQStringList strList;
TQValueList<TQGuardedPtr<KMFolder> > folderList;
kmkernel->dimapFolderMgr()->createFolderList( &strList, &folderList,
- folder->folder()->child(), TQString::null,
- false );
+ folder->folder()->child(), TQString::null,
+ false );
TQValueList<TQGuardedPtr<KMFolder> >::Iterator it;
mCountLastUnread = 0;
mUnreadBeforeCheck.clear();
@@ -374,13 +364,12 @@ void KMAcctCachedImap::invalidateIMAPFolders( KMFolderCachedImap* folder )
// This invalidates the folder completely
cfolder->setUidValidity("INVALID");
cfolder->writeUidCache();
- processNewMailSingleFolder( f );
}
}
folder->setUidValidity("INVALID");
folder->writeUidCache();
- processNewMailSingleFolder( folder->folder() );
+ processNewMailInFolder( folder->folder(), Recursive );
}
//-----------------------------------------------------------------------------
@@ -462,7 +451,7 @@ void KMAcctCachedImap::slotProgressItemCanceled( ProgressItem* )
}
}
-FolderStorage* const KMAcctCachedImap::rootFolder() const
+FolderStorage* KMAcctCachedImap::rootFolder() const
{
return mFolder;
}
diff --git a/kmail/kmacctcachedimap.h b/kmail/kmacctcachedimap.h
index e8e428204..72ed5c7db 100644
--- a/kmail/kmacctcachedimap.h
+++ b/kmail/kmacctcachedimap.h
@@ -76,11 +76,6 @@ public:
virtual void processNewMail( bool interactive );
/**
- * Kill all jobs related the the specified folder
- */
- void killJobsForItem(KMFolderTreeItem * fti);
-
- /**
* Kill the slave if any jobs are active
*/
virtual void killAllJobs( bool disconnectSlave=false );
@@ -179,7 +174,7 @@ public:
/**
* Returns the root folder of this account
*/
- virtual FolderStorage* const rootFolder() const;
+ virtual FolderStorage* rootFolder() const;
/** return if the account passed the annotation test */
bool annotationCheckPassed(){ return mAnnotationCheckPassed;};
diff --git a/kmail/kmacctimap.cpp b/kmail/kmacctimap.cpp
index bf96c79a1..4ead745c7 100644
--- a/kmail/kmacctimap.cpp
+++ b/kmail/kmacctimap.cpp
@@ -547,7 +547,7 @@ void KMAcctImap::slotMailCheckCanceled()
}
//-----------------------------------------------------------------------------
-FolderStorage* const KMAcctImap::rootFolder() const
+FolderStorage* KMAcctImap::rootFolder() const
{
return mFolder;
}
diff --git a/kmail/kmacctimap.h b/kmail/kmacctimap.h
index c69bca899..fac17eebe 100644
--- a/kmail/kmacctimap.h
+++ b/kmail/kmacctimap.h
@@ -87,7 +87,7 @@ public:
/**
* Returns the root folder of this account
*/
- virtual FolderStorage* const rootFolder() const;
+ virtual FolderStorage* rootFolder() const;
/**
* Queues a message for automatic filtering
diff --git a/kmail/kmacctlocal.cpp b/kmail/kmacctlocal.cpp
index b486b5378..d1e15f83a 100644
--- a/kmail/kmacctlocal.cpp
+++ b/kmail/kmacctlocal.cpp
@@ -220,6 +220,7 @@ bool KMAcctLocal::fetchMsg()
msg->setSignatureStateChar( msg->headerField( "X-KMail-SignatureState" ).at(0));
msg->setComplete(true);
msg->updateAttachmentState();
+ msg->updateInvitationState();
mAddedOk = processNewMsg(msg);
diff --git a/kmail/kmaddrbook.cpp b/kmail/kmaddrbook.cpp
index b115f54e2..055b29fcc 100644
--- a/kmail/kmaddrbook.cpp
+++ b/kmail/kmaddrbook.cpp
@@ -29,7 +29,6 @@
#include <kmessagebox.h>
#include <kabc/stdaddressbook.h>
#include <kabc/distributionlist.h>
-#include <kabc/vcardconverter.h>
#include <dcopref.h>
#include <tqregexp.h>
diff --git a/kmail/kmail.kcfg b/kmail/kmail.kcfg
index afb228cfe..4192d234f 100644
--- a/kmail/kmail.kcfg
+++ b/kmail/kmail.kcfg
@@ -24,6 +24,8 @@
<choice name="SelectFirstNew"/>
<choice name="SelectFirstUnreadNew"/>
<choice name="SelectLastSelected"/>
+ <choice name="SelectNewest"/>
+ <choice name="SelectOldest"/>
</choices>
<default>SelectLastSelected</default>
</entry>
@@ -153,7 +155,7 @@
<entry name="CloseToQuotaThreshold" type="Int">
<label>The threshold for when to warn the user that a folder is nearing its quota limit.</label>
- <default>85</default>
+ <default>80</default>
</entry>
</group>
@@ -184,6 +186,12 @@
<default>false</default>
</entry>
+ <entry name="OutlookCompatibleInvitationReplyComments" type="Bool">
+ <label>Outlook compatible invitation reply comments</label>
+ <whatsthis>When replying to invitations, send the reply comment in way that Microsoft Outlook understands.</whatsthis>
+ <default>false</default>
+ </entry>
+
<entry name="AutomaticSending" type="Bool">
<label>Automatic invitation sending</label>
<whatsthis>When this is checked, you will not see the mail composer window. Instead, all invitation mails are sent automatically. If you want to see the mail before sending it, you can uncheck this option. However, be aware that the text in the composer window is in iCalendar syntax, and you should not try modifying it by hand.</whatsthis>
@@ -200,15 +208,25 @@
</choices>
<default>AskForAllButAcceptance</default>
</entry>
-
+
<entry name="DeleteInvitationEmailsAfterSendingReply" type="Bool">
<label>Delete invitation emails after the reply to them has been sent</label>
<whatsthis>When this is checked, received invitation emails that have been replied to will be moved to the Trash folder, once the reply has been successfully sent.</whatsthis>
<default>true</default>
</entry>
-
- </group>
+ <entry name="ShowToltecReplacementText" type="Bool">
+ <label>When encountering a Toltec scheduling message, display a custom replacement text for it.</label>
+ <default>true</default>
+ </entry>
+
+ <entry name="ToltecReplacementText" type="String">
+ <label>The text that will be displayed as a replacement when encountering Toltec scheduling messages.</label>
+ <default code="true">KMail::ObjectTreeParser::defaultToltecReplacementText()</default>
+ </entry>
+
+
+ </group>
<group name="IMAP Resource">
<entry name="TheIMAPResourceEnabled" type="Bool">
@@ -253,14 +271,12 @@
<default>0</default>
</entry>
- <entry name="FilterOnlyDIMAPInbox" type="Bool">
- <default>true</default>
- <label>Only filter mails received in disconnected IMAP inbox.</label>
- </entry>
<entry name="FilterGroupwareFolders" type="Bool">
<default>false</default>
<label>Also filter new mails received in groupware folders.</label>
</entry>
+ <entry name="FilterSourceFolders" type="IntList">
+ </entry>
<entry name="ImmediatlySyncDIMAPOnGroupwareChanges" type="Bool">
<default>true</default>
@@ -293,10 +309,6 @@
<whatsthis>This option enables or disables the search line edit above the message list which can be used to quickly search the information shown in the message list.</whatsthis>
<default>true</default>
</entry>
- <entry name="EnableFolderQuickSearch" type="Bool">
- <label>Show folder quick search line edit</label>
- <default>false</default>
- </entry>
<entry name="HideLocalInbox" type="Bool">
<label>Hide local inbox if unused</label>
<default>true</default>
@@ -333,6 +345,11 @@
<whatsthis>Remember this mail transport, so that it will be used in future composer windows as well.</whatsthis>
<default>false</default>
</entry>
+ <entry name="StickyDictionary" type="Bool">
+ <whatsthis>Remember this dictionary, so that it will be used in future composer windows as well.
+ </whatsthis>
+ <default>false</default>
+ </entry>
<entry name="WordWrap" type="Bool" key="word-wrap">
<label>Word &amp;wrap at column:</label>
<default>true</default>
@@ -347,8 +364,21 @@
<min>30</min>
<max>255</max>
</entry>
+ <entry name="TooManyRecipients" type="Bool" key="too-many-recipients">
+ <label>Warn if the number of recipients is larger than</label>
+ <default>true</default>
+ <whatsthis>If the number of recipients is larger than this value, KMail will warn and ask for a confirmation before sending the mail. The warning can be turned off.</whatsthis>
+ </entry>
+ <entry name="RecipientThreshold" type="Int" key="recipient-threshold">
+ <label></label>
+ <default>5</default>
+ <min>1</min>
+ <max>100</max>
+ <whatsthis>If the number of recipients is larger than this value, KMail will warn and ask for a confirmation before sending the mail. The warning can be turned off.</whatsthis>
+ </entry>
<entry name="PreviousIdentity" type="UInt" key="previous-identity" />
<entry name="PreviousFcc" type="String" key="previous-fcc" />
+ <entry name="PreviousDictionary" type="String" />
<entry name="TransportHistory" type="StringList" key="transport-history" />
<entry name="CurrentTransport" type="String" key="current-transport" />
<entry name="DefaultTransport" type="String" key="default-transport" />
@@ -436,6 +466,14 @@
<label>Use smart &amp;quoting</label>
<default>true</default>
</entry>
+ <entry name="StripSignature" type="Bool">
+ <label>Remove the signature when replying</label>
+ <default>true</default>
+ </entry>
+ <entry name="QuoteSelectionOnly" type="Bool">
+ <label>Only quote selected text when replying</label>
+ <default>true</default>
+ </entry>
<entry name="AddresseeSelectorType" type="Enum">
<label>Type of addressee selector</label>
@@ -515,6 +553,10 @@
</group>
<group name="Reader">
+ <entry name="CloseAfterReplyOrForward" type="Bool">
+ <label>Close message window after replying or forwarding the message.</label>
+ <default>false</default>
+ </entry>
<entry name="UseDefaultColors" type="Bool" key="defaultColors">
<default>true</default>
</entry>
diff --git a/kmail/kmailIface.h b/kmail/kmailIface.h
index fd47f0485..2338a4c40 100644
--- a/kmail/kmailIface.h
+++ b/kmail/kmailIface.h
@@ -60,6 +60,19 @@ k_dcop:
const TQString &attachParamValue,
const TQCString &attachContDisp,
const TQCString &attachCharset) = 0;
+ virtual int openComposer (const TQString &to, const TQString &cc,
+ const TQString &bcc, const TQString &subject,
+ const TQString &body, int hidden,
+ const TQString &attachName,
+ const TQCString &attachCte,
+ const TQCString &attachData,
+ const TQCString &attachType,
+ const TQCString &attachSubType,
+ const TQCString &attachParamAttr,
+ const TQString &attachParamValue,
+ const TQCString &attachContDisp,
+ const TQCString &attachCharset,
+ uint identity) = 0;
/** Open composer and return reference to DCOP interface of composer window.
If hidden is true, the window will not be shown. If you use that option,
it's your responsibility to call the send() function of the composer in
@@ -102,6 +115,7 @@ k_dcop:
virtual int dcopAddMessage(const TQString & foldername,
const KURL & messagefile,
const TQString & MsgStatusFlags = TQString()) = 0;
+ virtual void showImportArchiveDialog() = 0;
virtual TQStringList folderList() const =0;
virtual DCOPRef getFolder( const TQString& vpath ) =0;
@@ -211,7 +225,7 @@ k_dcop_hidden:
/** Clears the list of added message ids which is used to filter out
duplicates. */
virtual void dcopResetAddMessage() = 0;
-
+
virtual void loadProfile( const TQString& path ) = 0;
virtual void saveToProfile( const TQString& path ) const = 0;
};
diff --git a/kmail/kmail_config_accounts.desktop b/kmail/kmail_config_accounts.desktop
index 4c2c9f92c..c2e58a03e 100644
--- a/kmail/kmail_config_accounts.desktop
+++ b/kmail/kmail_config_accounts.desktop
@@ -39,7 +39,6 @@ Name[hu]=Fiókok
Name[is]=Tengingar
Name[it]=Account
Name[ja]=アカウント
-Name[ka]=ანგარიშები
Name[kk]=Тіркелгілері
Name[km]=គណនី
Name[lt]=Paskyros
@@ -64,8 +63,7 @@ Name[ta]=கணக்குகள்
Name[tg]=Қайдҳои баҳисобгирӣ
Name[tr]=Hesaplar
Name[uk]=Рахунки
-Name[uz]=Hisoblar
-Name[uz@cyrillic]=Ҳисоблар
+Name[uz]=Ҳисоблар
Name[zh_CN]=账户
Name[zh_TW]=帳號
Comment=Setup for Sending and Receiving Messages
@@ -91,7 +89,6 @@ Comment[hu]=Küldési és fogadási beállítások
Comment[is]=Uppsetning fyrir sendingu og móttöku af tölvupósti
Comment[it]=Impostazioni per spedire e ricevere messaggi
Comment[ja]=メッセージを送受信するための設定
-Comment[ka]=შეტყობინებების გაგზავნისა და მიღების კონფიგურაცია
Comment[kk]=Хаттарды жіберу мен қабылдауды баптау
Comment[km]=រៀបចំ​ដើម្បី​ផ្ញើ និង​ទទួល​សារ
Comment[lt]=Laiškų siuntimo ir gavimo sąranka
@@ -139,7 +136,6 @@ Keywords[he]=kmail,accounts,דוא"ל, חשבון, חשבונות
Keywords[hu]=kmail,azonosítók
Keywords[is]=kmail,accounts,tengingar
Keywords[it]=kmail,account
-Keywords[ka]=kmail,ანგარიშები
Keywords[km]=kmail,គណនី
Keywords[lt]=kmail,accounts,paskyros
Keywords[mk]=kmail,accounts,кпошта,сметка,сметки
diff --git a/kmail/kmail_config_appearance.desktop b/kmail/kmail_config_appearance.desktop
index 09df7ea4a..3008ea543 100644
--- a/kmail/kmail_config_appearance.desktop
+++ b/kmail/kmail_config_appearance.desktop
@@ -39,7 +39,6 @@ Name[hu]=Megjelenés
Name[is]=Útlit
Name[it]=Aspetto
Name[ja]=外観
-Name[ka]=იერსახე
Name[kk]=Сыртқы көрінісі
Name[km]=រូបរាង
Name[ko]=모양
@@ -66,8 +65,7 @@ Name[ta]=தோற்றம்
Name[tg]=Намуди зоҳирӣ
Name[tr]=Görünüm
Name[uk]=Вигляд
-Name[uz]=Koʻrinishi
-Name[uz@cyrillic]=Кўриниши
+Name[uz]=Кўриниши
Name[zh_CN]=外观
Comment=Customize Visual Appearance
Comment[af]=Pasmaak die visuele voorkoms
@@ -93,7 +91,6 @@ Comment[hu]=A grafikai megjelenés testreszabása
Comment[is]=Stilla útlit
Comment[it]=Personalizza l'aspetto
Comment[ja]=外観をカスタマイズ
-Comment[ka]=ვიზუალური იერსახის დაყენება
Comment[kk]=Сыртқы көрінісін ыңғайлау
Comment[km]=ប្ដូរ​រូបរាង​មើល​ឃើញ​តាម​បំណង
Comment[lt]=Derinti vizualinę išvaizdą
@@ -143,7 +140,6 @@ Keywords[hu]=kmail,megjelenés
Keywords[is]=kmail,útlit
Keywords[it]=kmail,aspetto
Keywords[ja]=kmail,外観
-Keywords[ka]=kmail,იერსახე
Keywords[km]=kmail,រូបរាង
Keywords[lt]=kmail,appearance,išvaizda
Keywords[mk]=kmail,appearance,кпошта,појава,изглед,визуелно
diff --git a/kmail/kmail_config_composer.desktop b/kmail/kmail_config_composer.desktop
index 5c75a1c4c..4cc868bbc 100644
--- a/kmail/kmail_config_composer.desktop
+++ b/kmail/kmail_config_composer.desktop
@@ -35,7 +35,6 @@ Name[he]=עורך
Name[hu]=Szerkesztő
Name[it]=Compositore
Name[ja]=メール作成
-Name[ka]=წერილების რედაქტორი
Name[kk]=Құрастарғыш
Name[km]=កម្មវិធី​តែង
Name[lt]=Redaktorius
@@ -80,7 +79,6 @@ Comment[fr]=Modèles et comportement général
Comment[fy]=Sjabloanen en algemien gedrach
Comment[gl]=Planteis e Comportamento Xeral
Comment[hu]=Sablonok, általános működési jellemzők
-Comment[is]=Forsnið & almenn hegðun
Comment[it]=Modelli e comportamento generale
Comment[ja]=テンプレートと全般的な動作
Comment[kk]=Үлгілер мен Жалпы тәртібі
@@ -124,7 +122,6 @@ Keywords[he]=kmail,composer,כתבן
Keywords[hu]=kmail,szerkesztő
Keywords[is]=kmail,ritill
Keywords[it]=kmail,compositore
-Keywords[ka]=kmail,წერილების რედაქტორი
Keywords[km]=kmail កម្មវិធី​តែង
Keywords[lt]=kmail,composer,redaktorius
Keywords[mk]=kmail,composer,кпошта,составувач
diff --git a/kmail/kmail_config_identity.desktop b/kmail/kmail_config_identity.desktop
index 8cf28eb02..fe985db67 100644
--- a/kmail/kmail_config_identity.desktop
+++ b/kmail/kmail_config_identity.desktop
@@ -37,7 +37,6 @@ Name[hu]=Azonosítók
Name[is]=Auðkenni
Name[it]=Identità
Name[ja]=個人情報
-Name[ka]=პროფილები
Name[kk]=Іс-әлпеттері
Name[km]=អត្តសញ្ញាណ
Name[lt]=Tapatybės
@@ -62,8 +61,7 @@ Name[ta]=அடையாளங்கள்
Name[tg]=Профилҳо
Name[tr]=Kimlikler
Name[uk]=Профілі
-Name[uz]=Shaxsiyatlar
-Name[uz@cyrillic]=Шахсиятлар
+Name[uz]=Шахсиятлар
Name[zh_CN]=身份
Name[zh_TW]=身份
Comment=Manage Identities
@@ -92,7 +90,6 @@ Comment[hu]=Az azonosítók kezelése
Comment[is]=Stjórna auðkennum
Comment[it]=Gestisce le identità
Comment[ja]=個人情報の管理
-Comment[ka]=პროფილების მართვა
Comment[kk]=Іс-әлпеттерді басқару
Comment[km]=គ្រប់គ្រង​អត្តសញ្ញាណ
Comment[lt]=Tvarkyti tapatybes
@@ -143,7 +140,6 @@ Keywords[hu]=kmail,azonosító
Keywords[is]=kmail,auðkenni
Keywords[it]=kmail,identità
Keywords[ja]=kmail,個人情報
-Keywords[ka]=kmail,პროფილი
Keywords[km]=kmail,អត្តសញ្ញាណ
Keywords[lt]=kmail,identity,tapatybė
Keywords[mk]=kmail,identity,кпошта,идентитет,идентитети
@@ -165,6 +161,5 @@ Keywords[ta]=கேஅஞ்சல்,அடையாளம்
Keywords[tg]=kmail,identity,профил
Keywords[tr]=kmail,kimlikler
Keywords[uk]=kmail,профіль
-Keywords[uz]=kmail,shaxsiyat
-Keywords[uz@cyrillic]=kmail,шахсият
+Keywords[uz]=kmail,шахсият
Keywords[zh_CN]=kmail,identity, 身份
diff --git a/kmail/kmail_config_misc.desktop b/kmail/kmail_config_misc.desktop
index 6a33c6432..7c1d946fd 100644
--- a/kmail/kmail_config_misc.desktop
+++ b/kmail/kmail_config_misc.desktop
@@ -36,7 +36,6 @@ Name[hu]=Egyéb
Name[is]=Ýmislegt
Name[it]=Varie
Name[ja]=その他
-Name[ka]=სხვადასხვა
Name[kk]=Басқалары
Name[km]=ផ្សេងៗ
Name[lt]=Įvairūs
@@ -62,8 +61,7 @@ Name[ta]=இதர
Name[tg]=Ғайра
Name[tr]=Çeşitli
Name[uk]=Різне
-Name[uz]=Har xil
-Name[uz@cyrillic]=Ҳар хил
+Name[uz]=Ҳар хил
Name[zh_CN]=杂项
Name[zh_TW]=其他
Comment=Settings that don't fit elsewhere
@@ -89,7 +87,6 @@ Comment[hu]=A máshová nem besorolható beállítások
Comment[is]=Stillingar sem passa ekki annars staðar
Comment[it]=Impostazioni che non rientrano in altre categorie
Comment[ja]=その他の設定
-Comment[ka]=პარამეტრები,რომლებიც სხვას არ ერგება
Comment[kk]=Басқа параметрлері
Comment[km]=ការ​កំណត់​ដែល​មិន​ត្រូវ​នឹង​កន្លែង​ផ្សេង
Comment[lt]=Kiti nustatymai
@@ -138,7 +135,6 @@ Keywords[hu]=kmail,egyéb
Keywords[is]=kmail,ýmislegt
Keywords[it]=kmail,varie
Keywords[ja]=kmail,その他
-Keywords[ka]=kmail,სხვადასხვა
Keywords[km]=kmail,ផ្សេងៗ
Keywords[lt]=kmail,misc,įvairūs
Keywords[mk]=kmail,misc,кпошта,разно
@@ -161,6 +157,5 @@ Keywords[ta]=கேஅஞ்சல், இதர
Keywords[tg]=kmail,misc,ғайра,дигар
Keywords[tr]=kmail,çeşitli
Keywords[uk]=kmail,різне
-Keywords[uz]=kmail,har xil
-Keywords[uz@cyrillic]=kmail,ҳар хил
+Keywords[uz]=kmail,ҳар хил
Keywords[zh_CN]=kmail,misc,杂项
diff --git a/kmail/kmail_config_security.desktop b/kmail/kmail_config_security.desktop
index 1b61544e4..4d1a2a402 100644
--- a/kmail/kmail_config_security.desktop
+++ b/kmail/kmail_config_security.desktop
@@ -38,7 +38,6 @@ Name[hu]=Biztonság
Name[is]=Öryggi
Name[it]=Sicurezza
Name[ja]=セキュリティ
-Name[ka]=უსაფრთხოება
Name[kk]=Қауіпсіздік
Name[km]=សុវត្ថិភាព
Name[lt]=Saugumas
@@ -64,8 +63,7 @@ Name[ta]=பாதுகாப்பு
Name[tg]=Амният
Name[tr]=Güvenlik
Name[uk]=Безпека
-Name[uz]=Xavfsizlik
-Name[uz@cyrillic]=Хавфсизлик
+Name[uz]=Хавфсизлик
Name[zh_CN]=安全
Name[zh_TW]=安全性
Comment=Security & Privacy Settings
@@ -93,7 +91,6 @@ Comment[hu]=Biztonsági és adatvédelmi beállítások
Comment[is]=Öryggis & einkalífsstillingar
Comment[it]=Impostazioni sicurezza e privacy
Comment[ja]=セキュリティ & プライバシーの設定
-Comment[ka]=უსაფრთხოებისა და პირადულობის პარამეტრები
Comment[kk]=Қауіпсіздігі пен Дербестік параметрлері
Comment[km]=ការ​កំណត់​សុវត្ថិភាព & ភាព​ឯកជន
Comment[lt]=Saugumo ir privatumo nustatymai
@@ -144,7 +141,6 @@ Keywords[hu]=kmail,biztonság
Keywords[is]=kmail,öryggi
Keywords[it]=kmail,sicurezza
Keywords[ja]=kmail,セキュリティ
-Keywords[ka]=kmail,უსაფრთხოება
Keywords[km]=kmail,សុវត្ថិភាព
Keywords[lt]=kmail,security,saugumas
Keywords[mk]=kmail,security,кпошта,безбедност
@@ -167,6 +163,5 @@ Keywords[ta]=கேஅஞ்சல்,பாதுகாப்பு
Keywords[tg]=kmail,security,амният
Keywords[tr]=kmail,güvenlik
Keywords[uk]=kmail,безпека
-Keywords[uz]=kmail,xavfsizlik
-Keywords[uz@cyrillic]=kmail,хавфсизлик
+Keywords[uz]=kmail,хавфсизлик
Keywords[zh_CN]=kmail,security,安全
diff --git a/kmail/kmail_part.rc b/kmail/kmail_part.rc
index 72cf6ec35..fb4794dfd 100644
--- a/kmail/kmail_part.rc
+++ b/kmail/kmail_part.rc
@@ -2,7 +2,7 @@
the same menu entries at the same place in KMail and Kontact -->
<!DOCTYPE kpartgui>
-<kpartgui version="18" name="kmail_part" >
+<kpartgui version="20" name="kmail_part" >
<MenuBar>
<Menu noMerge="1" name="file" >
<text>&amp;File</text>
@@ -100,6 +100,7 @@
<Action name="troubleshoot_folder" />
<Separator/>
<Action name="empty" />
+ <Action name="archive_folder" />
<Action name="delete_folder" />
<Separator/>
<Action name="prefer_html" />
diff --git a/kmail/kmailicalIface.h b/kmail/kmailicalIface.h
index d57611035..fc1b7a815 100644
--- a/kmail/kmailicalIface.h
+++ b/kmail/kmailicalIface.h
@@ -128,9 +128,15 @@ k_dcop:
virtual bool removeSubresource( const TQString& resource ) = 0;
/**
+ * Returns the number of dimap folders in the account manager.
+ */
+ virtual int dimapAccounts() = 0;
+
+ /**
* Causes all resource folders of the given type to be synced with the server.
*/
virtual bool triggerSync( const TQString & ) = 0;
+ virtual void changeResourceUIName( const TQString &folderPath, const TQString &newName ) = 0;
k_dcop_signals:
void incidenceAdded( const TQString& type, const TQString& folder,
diff --git a/kmail/kmailicalifaceimpl.cpp b/kmail/kmailicalifaceimpl.cpp
index c1f626f85..05524e027 100644
--- a/kmail/kmailicalifaceimpl.cpp
+++ b/kmail/kmailicalifaceimpl.cpp
@@ -67,6 +67,7 @@ using KMail::AccountManager;
#include <kdebug.h>
#include <kiconloader.h>
+#include <kinputdialog.h>
#include <dcopclient.h>
#include <kmessagebox.h>
#include <kconfig.h>
@@ -75,6 +76,8 @@ using KMail::AccountManager;
using namespace KMail;
+TQMap<TQString, TQString> *KMailICalIfaceImpl::mSubResourceUINamesMap = new TQMap<TQString, TQString>;
+
// Local helper methods
static void vPartMicroParser( const TQString& str, TQString& s );
static void reloadFolderTree();
@@ -548,10 +551,12 @@ TQMap<Q_UINT32, TQString> KMailICalIfaceImpl::incidencesKolab( const TQString& m
f->open( "incidences" );
+ kdDebug(5006) << k_funcinfo << "Getting incidences (" << mimetype << ") for folder " << f->label()
+ << ", starting with index " << startIndex << ", " << nbMessages << " messages." << endl;
+ kdDebug(5006) << "The folder has " << f->count() << " messages." << endl;
+
int stopIndex = nbMessages == -1 ? f->count() :
QMIN( f->count(), startIndex + nbMessages );
- kdDebug(5006) << "KMailICalIfaceImpl::incidencesKolab( " << mimetype << ", "
- << resource << " ) from " << startIndex << " to " << stopIndex << endl;
for(int i = startIndex; i < stopIndex; ++i) {
#if 0
@@ -590,6 +595,8 @@ TQMap<Q_UINT32, TQString> KMailICalIfaceImpl::incidencesKolab( const TQString& m
#else
delete msg;
#endif
+ } else {
+ kdDebug(5006) << k_funcinfo << " Unable to retrieve message " << i << " for incidence!" << endl;
}
}
f->close( "incidences" );
@@ -652,10 +659,20 @@ static int dimapAccountCount()
return count;
}
+int KMailICalIfaceImpl::dimapAccounts()
+{
+ return dimapAccountCount();
+}
+
static TQString subresourceLabelForPresentation( const KMFolder * folder )
{
+ if( KMailICalIfaceImpl::getResourceMap()->contains( folder->location() ) ) {
+ return folder->label();
+ }
+
TQString label = folder->prettyURL();
TQStringList parts = TQStringList::split( TQString::fromLatin1("/"), label );
+
// In the common special case of some other user's folder shared with us
// the url looks like "Server Name/user/$USERNAME/Folder/Name". Make
// those a bit nicer.
@@ -678,9 +695,15 @@ static TQString subresourceLabelForPresentation( const KMFolder * folder )
remainder.pop_front();
remainder.pop_front();
if ( dimapAccountCount() > 1 ) {
+ // Fix kolab issue 2531 folder->storage() )->account() can be null
+ if( folder->storage() && static_cast<const KMFolderCachedImap*>( folder->storage() )->account() ) {
label = i18n( "My %1 (%2)")
.arg( remainder.join( TQString::fromLatin1("/") ),
static_cast<const KMFolderCachedImap*>( folder->storage() )->account()->name() );
+ } else {
+ label = i18n("My %1")
+ .arg( remainder.join( TQString::fromLatin1("/") ) );
+ }
} else {
label = i18n("My %1")
.arg( remainder.join( TQString::fromLatin1("/") ) );
@@ -700,9 +723,9 @@ TQValueList<KMailICalIfaceImpl::SubResource> KMailICalIfaceImpl::subresourcesKol
KMFolder* f = folderFromType( contentsType, TQString::null );
if ( f ) {
subResources.append( SubResource( f->location(), subresourceLabelForPresentation( f ),
- !f->isReadOnly(), folderIsAlarmRelevant( f ) ) );
+ f->isWritable(), folderIsAlarmRelevant( f ) ) );
kdDebug(5006) << "Adding(1) folder " << f->location() << " " <<
- ( f->isReadOnly() ? "readonly" : "" ) << endl;
+ ( !f->isWritable() ? "readonly" : "" ) << endl;
}
// get the extra ones
@@ -712,9 +735,9 @@ TQValueList<KMailICalIfaceImpl::SubResource> KMailICalIfaceImpl::subresourcesKol
f = it.current()->folder;
if ( f && f->storage()->contentsType() == t ) {
subResources.append( SubResource( f->location(), subresourceLabelForPresentation( f ),
- !f->isReadOnly(), folderIsAlarmRelevant( f ) ) );
+ f->isWritable(), folderIsAlarmRelevant( f ) ) );
kdDebug(5006) << "Adding(2) folder " << f->location() << " " <<
- ( f->isReadOnly() ? "readonly" : "" ) << endl;
+ ( !f->isWritable() ? "readonly" : "" ) << endl;
}
}
@@ -743,7 +766,9 @@ bool KMailICalIfaceImpl::triggerSync( const TQString& contentsType )
imap->getAndCheckFolder();
} else if ( f->folderType() == KMFolderTypeCachedImap ) {
KMFolderCachedImap* cached = static_cast<KMFolderCachedImap*>( f->storage() );
- cached->account()->processNewMailSingleFolder( f );
+ if ( cached->account() ) {
+ cached->account()->processNewMailInFolder( f );
+ }
}
}
return true;
@@ -758,7 +783,7 @@ bool KMailICalIfaceImpl::isWritableFolder( const TQString& type,
// Definitely not writable
return false;
- return !f->isReadOnly();
+ return f->isWritable();
}
/* Used by the resource to query the storage format of the folder. */
@@ -1432,7 +1457,7 @@ void KMailICalIfaceImpl::folderContentsTypeChanged( KMFolder* folder,
}
// Tell about the new resource
subresourceAdded( folderContentsType( contentsType ), location, subresourceLabelForPresentation(folder),
- !folder->isReadOnly(), folderIsAlarmRelevant( folder ) );
+ folder->isWritable(), folderIsAlarmRelevant( folder ) );
}
KMFolder* KMailICalIfaceImpl::extraFolder( const TQString& type,
@@ -1577,8 +1602,7 @@ void KMailICalIfaceImpl::slotFolderPropertiesChanged( KMFolder* folder )
subresourceDeleted( contentsTypeStr, location );
subresourceAdded( contentsTypeStr, location, subresourceLabelForPresentation( folder ),
- !folder->isReadOnly(), folderIsAlarmRelevant( folder ) );
-
+ folder->isWritable(), folderIsAlarmRelevant( folder ) );
}
}
@@ -1629,6 +1653,33 @@ KMFolder* KMailICalIfaceImpl::findResourceFolder( const TQString& resource )
return 0;
}
+void KMailICalIfaceImpl::changeResourceUIName( const TQString &folderPath, const TQString &newName )
+{
+ kdDebug() << "Folder path " << folderPath << endl;
+ KMFolder *f = findResourceFolder( folderPath );
+ if ( f ) {
+ KMailICalIfaceImpl::getResourceMap()->insert( folderPath, newName );
+ kmkernel->folderMgr()->renameFolder( f, newName );
+ KConfigGroup configGroup( kmkernel->config(), "Resource UINames" );
+ configGroup.writeEntry( folderPath, newName );
+ }
+}
+
+// Builds a folder list from the dimap and the local folder list.
+static void createFolderList( TQStringList &folderNames, TQValueList<TQGuardedPtr<KMFolder> > &folderList )
+{
+ TQStringList dimapFolderNames;
+ TQStringList localFolderNames;
+ TQValueList<TQGuardedPtr<KMFolder> > dimapFolderList;
+ TQValueList<TQGuardedPtr<KMFolder> > localFolderList;
+ kmkernel->dimapFolderMgr()->createFolderList( &dimapFolderNames, &dimapFolderList );
+ kmkernel->folderMgr()->createFolderList( &localFolderNames, &localFolderList );
+ folderNames += dimapFolderNames;
+ folderNames += localFolderNames;
+ folderList += dimapFolderList;
+ folderList += localFolderList;
+}
+
/****************************
* The config stuff
*/
@@ -1790,22 +1841,22 @@ void KMailICalIfaceImpl::readConfig()
if ( mNotes->folderType() == KMFolderTypeCachedImap )
static_cast<KMFolderCachedImap *>( mNotes->storage() )->updateAnnotationFolderType();
- // BEGIN TILL TODO The below only uses the dimap folder manager, which
- // will fail for all other folder types. Adjust.
-
- kdDebug(5006) << k_funcinfo << "mCalendar=" << mCalendar << " " << mCalendar->location() << endl;
- kdDebug(5006) << k_funcinfo << "mContacts=" << mContacts << " " << mContacts->location() << endl;
- kdDebug(5006) << k_funcinfo << "mNotes=" << mNotes << " " << mNotes->location() << endl;
+ //kdDebug(5006) << k_funcinfo << "mCalendar=" << mCalendar << " " << mCalendar->location() << endl;
+ //kdDebug(5006) << k_funcinfo << "mContacts=" << mContacts << " " << mContacts->location() << endl;
+ //kdDebug(5006) << k_funcinfo << "mNotes=" << mNotes << " " << mNotes->location() << endl;
// Find all extra folders
TQStringList folderNames;
TQValueList<TQGuardedPtr<KMFolder> > folderList;
- kmkernel->dimapFolderMgr()->createFolderList(&folderNames, &folderList);
- for(TQValueList<TQGuardedPtr<KMFolder> >::iterator it = folderList.begin();
- it != folderList.end(); ++it)
+ createFolderList( folderNames, folderList );
+ for( TQValueList<TQGuardedPtr<KMFolder> >::iterator it = folderList.begin();
+ it != folderList.end(); ++it )
{
- FolderStorage* storage = (*it)->storage();
- if ( storage->contentsType() != 0 ) {
+ FolderStorage *storage = (*it)->storage();
+ KMFolderCachedImap* dimapStorage = dynamic_cast<KMFolderCachedImap*>( storage );
+ if ( storage && storage->contentsType() != 0 ) {
+ if ( dimapStorage )
+ dimapStorage->updateAnnotationFolderType();
folderContentsTypeChanged( *it, storage->contentsType() );
}
}
@@ -1818,8 +1869,6 @@ void KMailICalIfaceImpl::readConfig()
mExtraFolders.remove( mContacts->location() );
mExtraFolders.remove( mNotes->location() );
- // END TILL TODO
-
subresourceAdded( folderContentsType( KMail::ContentsTypeCalendar ), mCalendar->location(), mCalendar->label(), true, true );
subresourceAdded( folderContentsType( KMail::ContentsTypeTask ), mTasks->location(), mTasks->label(), true, true );
subresourceAdded( folderContentsType( KMail::ContentsTypeJournal ), mJournals->location(), mJournals->label(), true, false );
@@ -1901,6 +1950,10 @@ void KMailICalIfaceImpl::readConfig()
subresourceAdded( folderContentsType( KMail::ContentsTypeNote ), mNotes->location(), mNotes->label(), true, false );
}
+ KConfig *config = kmkernel->config();
+ config->setGroup("Resource UINames");
+ *KMailICalIfaceImpl::mSubResourceUINamesMap = config->entryMap( "Resource UINames" );
+
reloadFolderTree();
}
@@ -1930,6 +1983,19 @@ KMFolder* KMailICalIfaceImpl::initFolder( KMail::FolderContentsType contentsType
// Find the folder
StandardFolderSearchResult result = findStandardResourceFolder( mFolderParentDir, contentsType );
+
+ // deal with multiple default groupware folders
+ if ( result.folders.count() > 1 && result.found == StandardFolderSearchResult::FoundAndStandard ) {
+ TQStringList labels;
+ for ( TQValueList<KMFolder*>::ConstIterator it = result.folders.begin(); it != result.folders.end(); ++it )
+ labels << (*it)->prettyURL();
+ const TQString selected = KInputDialog::getItem( i18n("Default folder"),
+ i18n("There are multiple %1 default folders, please choose one:")
+ .arg( localizedDefaultFolderName( contentsType ) ), labels );
+ if ( !selected.isEmpty() )
+ result.folder = result.folders[ labels.findIndex( selected ) ];
+ }
+
KMFolder* folder = result.folder;
if ( !folder ) {
@@ -2125,21 +2191,22 @@ static void vPartMicroParser( const TQString& str, TQString& s )
}
// Returns the first child folder having the given annotation
-static KMFolder* findFolderByAnnotation( KMFolderDir* folderParentDir, const TQString& annotation )
-{
- TQPtrListIterator<KMFolderNode> it( *folderParentDir );
- for ( ; it.current(); ++it ) {
- if ( !it.current()->isDir() ) {
- KMFolder* folder = static_cast<KMFolder *>( it.current() );
- if ( folder->folderType() == KMFolderTypeCachedImap ) {
- TQString folderAnnotation = static_cast<KMFolderCachedImap*>( folder->storage() )->annotationFolderType();
- //kdDebug(5006) << "findStandardResourceFolder: " << folder->name() << " has annotation " << folderAnnotation << endl;
- if ( folderAnnotation == annotation )
- return folder;
- }
+static TQValueList<KMFolder*> findFolderByAnnotation( KMFolderDir* folderParentDir, const TQString& annotation )
+{
+ TQValueList<KMFolder*> rv;
+ TQPtrListIterator<KMFolderNode> it( *folderParentDir );
+ for ( ; it.current(); ++it ) {
+ if ( !it.current()->isDir() ) {
+ KMFolder* folder = static_cast<KMFolder *>( it.current() );
+ if ( folder->folderType() == KMFolderTypeCachedImap ) {
+ TQString folderAnnotation = static_cast<KMFolderCachedImap*>( folder->storage() )->annotationFolderType();
+ //kdDebug(5006) << "findStandardResourceFolder: " << folder->name() << " has annotation " << folderAnnotation << endl;
+ if ( folderAnnotation == annotation )
+ rv.append( folder );
}
}
- return 0;
+ }
+ return rv;
}
KMailICalIfaceImpl::StandardFolderSearchResult KMailICalIfaceImpl::findStandardResourceFolder( KMFolderDir* folderParentDir, KMail::FolderContentsType contentsType )
@@ -2147,14 +2214,14 @@ KMailICalIfaceImpl::StandardFolderSearchResult KMailICalIfaceImpl::findStandardR
if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML )
{
// Look for a folder with an annotation like "event.default"
- KMFolder* folder = findFolderByAnnotation( folderParentDir, TQString( s_folderContentsType[contentsType].annotation ) + ".default" );
- if ( folder )
- return StandardFolderSearchResult( folder, StandardFolderSearchResult::FoundAndStandard );
+ TQValueList<KMFolder*> folders = findFolderByAnnotation( folderParentDir, TQString( s_folderContentsType[contentsType].annotation ) + ".default" );
+ if ( !folders.isEmpty() )
+ return StandardFolderSearchResult( folders, StandardFolderSearchResult::FoundAndStandard );
// Fallback: look for a folder with an annotation like "event"
- folder = findFolderByAnnotation( folderParentDir, TQString( s_folderContentsType[contentsType].annotation ) );
- if ( folder )
- return StandardFolderSearchResult( folder, StandardFolderSearchResult::FoundByType );
+ folders = findFolderByAnnotation( folderParentDir, TQString( s_folderContentsType[contentsType].annotation ) );
+ if ( !folders.isEmpty() )
+ return StandardFolderSearchResult( folders, StandardFolderSearchResult::FoundByType );
// Fallback: look for the folder by name (we'll need to change its type)
KMFolderNode* node = folderParentDir->hasNamedFolder( localizedDefaultFolderName( contentsType ) );
@@ -2188,12 +2255,14 @@ bool KMailICalIfaceImpl::folderIsAlarmRelevant( const KMFolder *folder )
if ( folder->folderType() == KMFolderTypeImap ) {
const KMFolderImap *imapFolder = static_cast<const KMFolderImap*>( folder->storage() );
administerRights =
- imapFolder->userRights() <= 0 || imapFolder->userRights() & KMail::ACLJobs::Administer;
+ imapFolder->userRightsState() != KMail::ACLJobs::Ok ||
+ imapFolder->userRights() & KMail::ACLJobs::Administer;
}
if ( folder->folderType() == KMFolderTypeCachedImap ) {
const KMFolderCachedImap *dimapFolder = static_cast<const KMFolderCachedImap*>( folder->storage() );
administerRights =
- dimapFolder->userRights() <= 0 || dimapFolder->userRights() & KMail::ACLJobs::Administer;
+ dimapFolder->userRightsState() != KMail::ACLJobs::Ok ||
+ dimapFolder->userRights() & KMail::ACLJobs::Administer;
relevantForOwner = !dimapFolder->alarmsBlocked() && ( dimapFolder->incidencesFor () == KMFolderCachedImap::IncForAdmins );
relevantForEveryone = !dimapFolder->alarmsBlocked() && ( dimapFolder->incidencesFor() == KMFolderCachedImap::IncForReaders );
}
@@ -2227,6 +2296,12 @@ bool KMailICalIfaceImpl::addSubresource( const TQString& resource,
KMFolderDir *parentFolderDir = !parent.isEmpty() && folder ? folder->createChildFolder(): mFolderParentDir;
if ( !parentFolderDir || parentFolderDir->hasNamedFolder( resource ) ) return false;
+ TQString msg;
+ if ( parentFolderDir->owner() && !parentFolderDir->owner()->isValidName( resource, msg ) ) {
+ KMessageBox::error( 0, msg );
+ return false;
+ }
+
KMFolderType type = mFolderType;
if( type == KMFolderTypeUnknown ) type = KMFolderTypeMaildir;
@@ -2291,7 +2366,7 @@ void KMailICalIfaceImpl::syncFolder(KMFolder * folder) const
else
return;
}
- dimapFolder->account()->processNewMailSingleFolder( folder );
+ dimapFolder->account()->processNewMailInFolder( folder );
}
#include "kmailicalifaceimpl.moc"
diff --git a/kmail/kmailicalifaceimpl.h b/kmail/kmailicalifaceimpl.h
index 5a92ffe92..c0308f928 100644
--- a/kmail/kmailicalifaceimpl.h
+++ b/kmail/kmailicalifaceimpl.h
@@ -113,6 +113,7 @@ public:
const TQString& resource,
int startIndex,
int nbMessages );
+ int dimapAccounts();
TQValueList<SubResource> subresourcesKolab( const TQString& contentsType );
@@ -223,6 +224,8 @@ public:
bool isResourceQuiet() const;
void setResourceQuiet(bool q);
+ static TQMap<TQString, TQString>* getResourceMap() { return mSubResourceUINamesMap; }
+
public slots:
/* (Re-)Read configuration file */
void readConfig();
@@ -235,6 +238,7 @@ public slots:
// Called when a folder is made readonly or readwrite, or renamed,
// or any other similar change that affects the resources
void slotFolderPropertiesChanged( KMFolder* folder );
+ void changeResourceUIName( const TQString &folderPath, const TQString &newName );
private slots:
void slotRefreshFolder( KMFolder* );
@@ -259,7 +263,10 @@ private:
enum FoundEnum { FoundAndStandard, NotFound, FoundByType, FoundByName };
StandardFolderSearchResult() : folder( 0 ) {}
StandardFolderSearchResult( KMFolder* f, FoundEnum e ) : folder( f ), found( e ) {}
+ StandardFolderSearchResult( const TQValueList<KMFolder*> &f, FoundEnum e ) :
+ folder( f.first() ), folders( f ), found( e ) {}
KMFolder* folder; // NotFound implies folder==0 of course.
+ TQValueList<KMFolder*> folders; // in case we found multiple default folders (which should not happen)
FoundEnum found;
};
@@ -341,6 +348,7 @@ private:
TQMap<Q_UINT32, bool> mTheUnGetMes;
TQMap<TQString, TQString> mPendingUpdates;
TQMap<TQString, bool> mInTransit;
+ static TQMap<TQString, TQString> *mSubResourceUINamesMap;
};
diff --git a/kmail/kmcommands.cpp b/kmail/kmcommands.cpp
index e0b911df7..7bf978b07 100644
--- a/kmail/kmcommands.cpp
+++ b/kmail/kmcommands.cpp
@@ -101,6 +101,7 @@ using KMail::ActionScheduler;
#include "kcursorsaver.h"
#include "partNode.h"
#include "objecttreeparser.h"
+#include "csshelper.h"
using KMail::ObjectTreeParser;
using KMail::FolderJob;
#include "chiasmuskeyselector.h"
@@ -243,13 +244,16 @@ void KMCommand::slotStart()
return;
}
- for (KMMsgBase *mb = mMsgList.first(); mb; mb = mMsgList.next())
- if (!mb->parent()) {
- emit messagesTransfered( Failed );
- return;
- } else {
- keepFolderOpen( mb->parent() );
+ for ( KMMsgBase *mb = mMsgList.first(); mb; mb = mMsgList.next() ) {
+ if ( mb ) {
+ if ( !mb->parent() ) {
+ emit messagesTransfered( Failed );
+ return;
+ } else {
+ keepFolderOpen( mb->parent() );
+ }
}
+ }
// transfer the selected messages first
transferSelectedMsgs();
@@ -446,7 +450,7 @@ void KMCommand::slotTransferCancelled()
void KMCommand::keepFolderOpen( KMFolder *folder )
{
- folder->open("kmcommand");
+ folder->open( "kmcommand" );
mFolders.append( folder );
}
@@ -757,10 +761,25 @@ KMCommand::Result KMShowMsgSrcCommand::execute()
return OK;
}
-static KURL subjectToUrl( const TQString & subject ) {
- return KFileDialog::getSaveURL( subject.stripWhiteSpace()
- .replace( TQDir::separator(), '_' ),
- "*.mbox" );
+static KURL subjectToUrl( const TQString & subject )
+{
+ // We need to replace colons with underscores since those cause problems with KFileDialog (bug
+ // in KFileDialog though) and also on Windows filesystems.
+ // We also look at the special case of ": ", since converting that to "_ " would look strange,
+ // simply "_" looks better.
+ // We also don't allow filenames starting with a dot, since then the file is hidden and the poor
+ // user can't find it anymore.
+ // Don't allow filenames starting with a tilde either, since that will cause the file dialog to
+ // discard the filename entirely.
+ // https://issues.kolab.org/issue3805
+ const TQString filter = i18n( "*.mbox|email messages (*.mbox)\n*|all files (*)" );
+ TQString cleanSubject = subject.stripWhiteSpace()
+ .replace( TQDir::separator(), '_' )
+ .replace( ": ", "_" )
+ .replace( ':', '_' )
+ .replace( '.', '_' )
+ .replace( '~', '_' );
+ return KFileDialog::getSaveURL( cleanSubject, filter );
}
KMSaveMsgCommand::KMSaveMsgCommand( TQWidget *parent, KMMessage * msg )
@@ -857,16 +876,23 @@ void KMSaveMsgCommand::slotSaveDataReq()
assert( p );
assert( idx >= 0 );
//kdDebug() << "SERNUM: " << mMsgList[mMsgListIndex] << " idx: " << idx << " folder: " << p->prettyURL() << endl;
+
+ const bool alreadyGot = p->isMessage( idx );
+
msg = p->getMsg(idx);
if ( msg ) {
+ // Only unGet the message if it isn't already got.
+ if ( !alreadyGot ) {
+ mUngetMsgs.append( msg );
+ }
if ( msg->transferInProgress() ) {
TQByteArray data = TQByteArray();
mJob->sendAsyncData( data );
}
msg->setTransferInProgress( true );
- if (msg->isComplete() ) {
- slotMessageRetrievedForSaving( msg );
+ if ( msg->isComplete() ) {
+ slotMessageRetrievedForSaving( msg );
} else {
// retrieve Message first
if ( msg->parent() && !msg->isComplete() ) {
@@ -918,7 +944,8 @@ void KMSaveMsgCommand::slotMessageRetrievedForSaving(KMMessage *msg)
}
++mMsgListIndex;
// Get rid of the message.
- if ( msg && msg->parent() && msg->getMsgSerNum() ) {
+ if ( msg && msg->parent() && msg->getMsgSerNum() &&
+ mUngetMsgs.contains( msg ) ) {
int idx = -1;
KMFolder * p = 0;
KMMsgDict::instance()->getLocation( msg, &p, &idx );
@@ -1229,9 +1256,9 @@ KMCommand::Result KMForwardInlineCommand::execute()
// fwdMsg->setBody( msgText );
for ( KMMessage *msg = linklist.first(); msg; msg = linklist.next() ) {
- TemplateParser parser( fwdMsg, TemplateParser::Forward,
- msg->body(), false, false, false, false);
- parser.process( msg, 0, true );
+ TemplateParser parser( fwdMsg, TemplateParser::Forward );
+ parser.setSelection( msg->body() ); // FIXME: Why is this needed?
+ parser.process( msg, 0, true );
fwdMsg->link( msg, KMMsgStatusForwarded );
}
@@ -1256,7 +1283,6 @@ KMCommand::Result KMForwardInlineCommand::execute()
{
KMail::Composer * win = KMail::makeComposer( fwdMsg, id );
win->setCharset( fwdMsg->codec()->mimeName(), true );
- win->setBody( fwdMsg->bodyToUnicode() );
win->show();
}
}
@@ -1459,7 +1485,7 @@ KMCommand::Result KMCustomReplyToCommand::execute()
return Failed;
}
KMMessage *reply = msg->createReply( KMail::ReplySmart, mSelection,
- false, true, false, mTemplate );
+ false, true, mTemplate );
KMail::Composer * win = KMail::makeComposer( reply );
win->setCharset( msg->codec()->mimeName(), true );
win->setReplyFocus();
@@ -1484,7 +1510,7 @@ KMCommand::Result KMCustomReplyAllToCommand::execute()
return Failed;
}
KMMessage *reply = msg->createReply( KMail::ReplyAll, mSelection,
- false, true, false, mTemplate );
+ false, true, mTemplate );
KMail::Composer * win = KMail::makeComposer( reply );
win->setCharset( msg->codec()->mimeName(), true );
win->setReplyFocus();
@@ -1533,9 +1559,9 @@ KMCommand::Result KMCustomForwardCommand::execute()
// fwdMsg->setBody( msgText );
for ( KMMessage *msg = linklist.first(); msg; msg = linklist.next() ) {
- TemplateParser parser( fwdMsg, TemplateParser::Forward,
- msg->body(), false, false, false, false);
- parser.process( msg, 0, true );
+ TemplateParser parser( fwdMsg, TemplateParser::Forward );
+ parser.setSelection( msg->body() ); // FIXME: Why is this needed?
+ parser.process( msg, 0, true );
fwdMsg->link( msg, KMMsgStatusForwarded );
}
@@ -1567,14 +1593,24 @@ KMCommand::Result KMCustomForwardCommand::execute()
}
-KMPrintCommand::KMPrintCommand( TQWidget *parent,
- KMMessage *msg, bool htmlOverride, bool htmlLoadExtOverride,
- bool useFixedFont, const TQString & encoding )
- : KMCommand( parent, msg ), mHtmlOverride( htmlOverride ),
+KMPrintCommand::KMPrintCommand( TQWidget *parent, KMMessage *msg,
+ const KMail::HeaderStyle *headerStyle,
+ const KMail::HeaderStrategy *headerStrategy,
+ bool htmlOverride, bool htmlLoadExtOverride,
+ bool useFixedFont, const TQString & encoding )
+ : KMCommand( parent, msg ),
+ mHeaderStyle( headerStyle ), mHeaderStrategy( headerStrategy ),
+ mHtmlOverride( htmlOverride ),
mHtmlLoadExtOverride( htmlLoadExtOverride ),
mUseFixedFont( useFixedFont ), mEncoding( encoding )
{
- mOverrideFont = KGlobalSettings::generalFont();
+ if ( GlobalSettings::useDefaultFonts() )
+ mOverrideFont = KGlobalSettings::generalFont();
+ else {
+ KConfigGroup fonts( KMKernel::config(), "Fonts" );
+ TQString tmp = fonts.readEntry( "print-font", KGlobalSettings::generalFont().toString() );
+ mOverrideFont.fromString( tmp );
+ }
}
@@ -1588,11 +1624,13 @@ KMCommand::Result KMPrintCommand::execute()
KMReaderWin printWin( 0, 0, 0 );
printWin.setPrinting( true );
printWin.readConfig();
+ if ( mHeaderStyle != 0 && mHeaderStrategy != 0 )
+ printWin.setHeaderStyleAndStrategy( mHeaderStyle, mHeaderStrategy );
printWin.setHtmlOverride( mHtmlOverride );
printWin.setHtmlLoadExtOverride( mHtmlLoadExtOverride );
printWin.setUseFixedFont( mUseFixedFont );
printWin.setOverrideEncoding( mEncoding );
- printWin.setPrintFont( mOverrideFont );
+ printWin.cssHelper()->setPrintFont( mOverrideFont );
printWin.setDecryptMessageOverwrite( true );
printWin.setMsg( retrievedMessage(), true );
printWin.printMsg();
@@ -2149,14 +2187,21 @@ KMCommand::Result KMMoveCommand::execute()
mProgressItem->setTotalItems( mSerNumList.count() );
for ( TQValueList<Q_UINT32>::ConstIterator it = mSerNumList.constBegin(); it != mSerNumList.constEnd(); ++it ) {
- KMFolder *srcFolder;
+ if ( *it == 0 ) {
+ kdDebug(5006) << k_funcinfo << "serial number == 0!" << endl;
+ continue; // invalid message
+ }
+ KMFolder *srcFolder = 0;
int idx = -1;
KMMsgDict::instance()->getLocation( *it, &srcFolder, &idx );
if (srcFolder == mDestFolder)
continue;
+ assert(srcFolder);
assert(idx != -1);
- srcFolder->open( "kmmovecommand" );
- mOpenedFolders.append( srcFolder );
+ if ( !srcFolder->isOpened() ) {
+ srcFolder->open( "kmmovecommand" );
+ mOpenedFolders.append( srcFolder );
+ }
msg = srcFolder->getMsg(idx);
if ( !msg ) {
kdDebug(5006) << k_funcinfo << "No message found for serial number " << *it << endl;
@@ -2328,6 +2373,11 @@ KMDeleteMsgCommand::KMDeleteMsgCommand( KMFolder* srcFolder, KMMessage * msg )
KMDeleteMsgCommand::KMDeleteMsgCommand( Q_UINT32 sernum )
:KMMoveCommand( sernum )
{
+ if ( !sernum ) {
+ setDestFolder( 0 );
+ return;
+ }
+
KMFolder *srcFolder = 0;
int idx;
KMMsgDict::instance()->getLocation( sernum, &srcFolder, &idx );
@@ -3146,7 +3196,7 @@ void KMHandleAttachmentCommand::atmSave()
parts.append( mNode );
// save, do not leave encoded
KMSaveAttachmentsCommand *command =
- new KMSaveAttachmentsCommand( 0, parts, mMsg, false );
+ new KMSaveAttachmentsCommand( parentWidget(), parts, mMsg, false );
command->start();
}
@@ -3306,6 +3356,13 @@ AttachmentModifyCommand::AttachmentModifyCommand(partNode * node, KMMessage * ms
{
}
+AttachmentModifyCommand::AttachmentModifyCommand( int nodeId, KMMessage *msg, TQWidget *parent )
+ : KMCommand( parent, msg ),
+ mPartIndex( nodeId ),
+ mSernum( 0 )
+{
+}
+
AttachmentModifyCommand::~ AttachmentModifyCommand()
{
}
@@ -3370,31 +3427,14 @@ void AttachmentModifyCommand::messageDeleteResult(KMCommand * cmd)
deleteLater();
}
-DwBodyPart * AttachmentModifyCommand::findPart(KMMessage* msg, int index)
-{
- int accu = 0;
- return findPartInternal( msg->getTopLevelPart(), index, accu );
-}
-
-DwBodyPart * AttachmentModifyCommand::findPartInternal(DwEntity * root, int index, int & accu)
+KMDeleteAttachmentCommand::KMDeleteAttachmentCommand(partNode * node, KMMessage * msg, TQWidget * parent) :
+ AttachmentModifyCommand( node, msg, parent )
{
- accu++;
- if ( index < accu ) // should not happen
- return 0;
- DwBodyPart *current = dynamic_cast<DwBodyPart*>( root );
- if ( index == accu )
- return current;
- DwBodyPart *rv = 0;
- if ( root->Body().FirstBodyPart() )
- rv = findPartInternal( root->Body().FirstBodyPart(), index, accu );
- if ( !rv && current && current->Next() )
- rv = findPartInternal( current->Next(), index, accu );
- return rv;
+ kdDebug(5006) << k_funcinfo << endl;
}
-
-KMDeleteAttachmentCommand::KMDeleteAttachmentCommand(partNode * node, KMMessage * msg, TQWidget * parent) :
- AttachmentModifyCommand( node, msg, parent )
+KMDeleteAttachmentCommand::KMDeleteAttachmentCommand( int nodeId, KMMessage *msg, TQWidget *parent )
+ : AttachmentModifyCommand( nodeId, msg, parent )
{
kdDebug(5006) << k_funcinfo << endl;
}
@@ -3407,37 +3447,8 @@ KMDeleteAttachmentCommand::~KMDeleteAttachmentCommand()
KMCommand::Result KMDeleteAttachmentCommand::doAttachmentModify()
{
KMMessage *msg = retrievedMessage();
- KMMessagePart part;
- DwBodyPart *dwpart = findPart( msg, mPartIndex );
- if ( !dwpart )
+ if ( !msg || !msg->deleteBodyPart( mPartIndex ) )
return Failed;
- KMMessage::bodyPart( dwpart, &part, true );
- if ( !part.isComplete() )
- return Failed;
-
- DwBody *parentNode = dynamic_cast<DwBody*>( dwpart->Parent() );
- if ( !parentNode )
- return Failed;
- parentNode->RemoveBodyPart( dwpart );
-
- // add dummy part to show that a attachment has been deleted
- KMMessagePart dummyPart;
- dummyPart.duplicate( part );
- TQString comment = i18n("This attachment has been deleted.");
- if ( !part.fileName().isEmpty() )
- comment = i18n( "The attachment '%1' has been deleted." ).arg( part.fileName() );
- dummyPart.setContentDescription( comment );
- dummyPart.setBodyEncodedBinary( TQByteArray() );
- TQCString cd = dummyPart.contentDisposition();
- if ( cd.find( "inline", 0, false ) == 0 ) {
- cd.replace( 0, 10, "attachment" );
- dummyPart.setContentDisposition( cd );
- } else if ( cd.isEmpty() ) {
- dummyPart.setContentDisposition( "attachment" );
- }
- DwBodyPart* newDwPart = msg->createDWBodyPart( &dummyPart );
- parentNode->AddBodyPart( newDwPart );
- msg->getTopLevelPart()->Assemble();
KMMessage *newMsg = new KMMessage();
newMsg->fromDwString( msg->asDwString() );
@@ -3455,6 +3466,13 @@ KMEditAttachmentCommand::KMEditAttachmentCommand(partNode * node, KMMessage * ms
mTempFile.setAutoDelete( true );
}
+KMEditAttachmentCommand::KMEditAttachmentCommand( int nodeId, KMMessage *msg, TQWidget *parent )
+ : AttachmentModifyCommand( nodeId, msg, parent )
+{
+ kdDebug(5006) << k_funcinfo << endl;
+ mTempFile.setAutoDelete( true );
+}
+
KMEditAttachmentCommand::~ KMEditAttachmentCommand()
{
}
@@ -3462,8 +3480,11 @@ KMEditAttachmentCommand::~ KMEditAttachmentCommand()
KMCommand::Result KMEditAttachmentCommand::doAttachmentModify()
{
KMMessage *msg = retrievedMessage();
+ if ( !msg )
+ return Failed;
+
KMMessagePart part;
- DwBodyPart *dwpart = findPart( msg, mPartIndex );
+ DwBodyPart *dwpart = msg->findPart( mPartIndex );
if ( !dwpart )
return Failed;
KMMessage::bodyPart( dwpart, &part, true );
@@ -3476,7 +3497,10 @@ KMCommand::Result KMEditAttachmentCommand::doAttachmentModify()
mTempFile.file()->writeBlock( part.bodyDecodedBinary() );
mTempFile.file()->flush();
- KMail::EditorWatcher *watcher = new KMail::EditorWatcher( KURL(mTempFile.file()->name()), part.typeStr() + "/" + part.subtypeStr(), false, this );
+ KMail::EditorWatcher *watcher =
+ new KMail::EditorWatcher( KURL( mTempFile.file()->name() ),
+ part.typeStr() + "/" + part.subtypeStr(),
+ false, this, parentWidget() );
connect( watcher, TQT_SIGNAL(editDone(KMail::EditorWatcher*)), TQT_SLOT(editDone(KMail::EditorWatcher*)) );
if ( !watcher->start() )
return Failed;
@@ -3502,7 +3526,7 @@ void KMEditAttachmentCommand::editDone(KMail::EditorWatcher * watcher)
// build the new message
KMMessage *msg = retrievedMessage();
KMMessagePart part;
- DwBodyPart *dwpart = findPart( msg, mPartIndex );
+ DwBodyPart *dwpart = msg->findPart( mPartIndex );
KMMessage::bodyPart( dwpart, &part, true );
DwBody *parentNode = dynamic_cast<DwBody*>( dwpart->Parent() );
@@ -3549,8 +3573,8 @@ KMCommand::Result CreateTodoCommand::execute()
tf.close();
KCalendarIface_stub *iface = new KCalendarIface_stub( kapp->dcopClient(), "korganizer", "CalendarIface" );
- iface->openTodoEditor( i18n("Mail: %1").arg( msg->subject() ), txt,
- uri, tf.name(), TQStringList(), "message/rfc822" );
+ iface->openTodoEditor( i18n("Mail: %1").arg( msg->subject() ), txt, uri,
+ tf.name(), TQStringList(), "message/rfc822", true );
delete iface;
return OK;
diff --git a/kmail/kmcommands.h b/kmail/kmcommands.h
index 7d1385a66..781a80873 100644
--- a/kmail/kmcommands.h
+++ b/kmail/kmcommands.h
@@ -39,6 +39,8 @@ namespace KMail {
class Composer;
class FolderJob;
class EditorWatcher;
+ class HeaderStyle;
+ class HeaderStrategy;
}
namespace GpgME { class Error; }
namespace Kleo { class SpecialJob; }
@@ -83,9 +85,11 @@ public slots:
void slotProgress( unsigned long done, unsigned long total );
signals:
+
+ /// @param result The status of the command.
void messagesTransfered( KMCommand::Result result );
- /** Emitted when the command has completed.
- * @param result The status of the command. */
+
+ /// Emitted when the command has completed.
void completed( KMCommand *command );
protected:
@@ -342,6 +346,7 @@ private:
static const int MAX_CHUNK_SIZE = 64*1024;
KURL mUrl;
TQValueList<unsigned long> mMsgList;
+ TQValueList<KMMsgBase *> mUngetMsgs;
unsigned int mMsgListIndex;
KMMessage *mStandAloneMessage;
TQByteArray mData;
@@ -601,8 +606,10 @@ class KDE_EXPORT KMPrintCommand : public KMCommand
public:
KMPrintCommand( TQWidget *parent, KMMessage *msg,
- bool htmlOverride=false,
- bool htmlLoadExtOverride=false,
+ const KMail::HeaderStyle *headerStyle = 0,
+ const KMail::HeaderStrategy *headerStrategy = 0,
+ bool htmlOverride = false,
+ bool htmlLoadExtOverride = false,
bool useFixedFont = false,
const TQString & encoding = TQString() );
@@ -611,6 +618,8 @@ public:
private:
virtual Result execute();
+ const KMail::HeaderStyle *mHeaderStyle;
+ const KMail::HeaderStrategy *mHeaderStrategy;
bool mHtmlOverride;
bool mHtmlLoadExtOverride;
bool mUseFixedFont;
@@ -1036,11 +1045,11 @@ class KDE_EXPORT AttachmentModifyCommand : public KMCommand
Q_OBJECT
public:
AttachmentModifyCommand( partNode *node, KMMessage *msg, TQWidget *parent );
+ AttachmentModifyCommand( int nodeId, KMMessage *msg, TQWidget *parent );
~AttachmentModifyCommand();
protected:
void storeChangedMessage( KMMessage* msg );
- DwBodyPart* findPart( KMMessage* msg, int index );
virtual Result doAttachmentModify() = 0;
protected:
@@ -1049,7 +1058,6 @@ class KDE_EXPORT AttachmentModifyCommand : public KMCommand
private:
Result execute();
- DwBodyPart* findPartInternal( DwEntity* root, int index, int &accu );
private slots:
void messageStoreResult( KMFolderImap* folder, bool success );
@@ -1064,6 +1072,7 @@ class KDE_EXPORT KMDeleteAttachmentCommand : public AttachmentModifyCommand
Q_OBJECT
public:
KMDeleteAttachmentCommand( partNode *node, KMMessage *msg, TQWidget *parent );
+ KMDeleteAttachmentCommand( int nodeId, KMMessage *msg, TQWidget *parent );
~KMDeleteAttachmentCommand();
protected:
@@ -1076,6 +1085,7 @@ class KDE_EXPORT KMEditAttachmentCommand : public AttachmentModifyCommand
Q_OBJECT
public:
KMEditAttachmentCommand( partNode *node, KMMessage *msg, TQWidget *parent );
+ KMEditAttachmentCommand( int nodeId, KMMessage *msg, TQWidget *parent );
~KMEditAttachmentCommand();
protected:
diff --git a/kmail/kmcomposewin.cpp b/kmail/kmcomposewin.cpp
index 592248a0a..a1ab32d8a 100644
--- a/kmail/kmcomposewin.cpp
+++ b/kmail/kmcomposewin.cpp
@@ -69,8 +69,6 @@ using KRecentAddress::RecentAddresses;
#include <gpgmepp/context.h>
#include <gpgmepp/key.h>
-#include <kabc/vcardconverter.h>
-#include <libkdepim/kvcarddrag.h>
#include <kio/netaccess.h>
#include "klistboxdialog.h"
@@ -159,6 +157,7 @@ KMComposeWin::KMComposeWin( KMMessage *aMsg, uint id )
mSpellCheckInProgress( false ),
mDone( false ),
mAtmModified( false ),
+ mAtmSelectNew( 0 ),
mMsg( 0 ),
mAttachMenu( 0 ),
mSigningAndEncryptionExplicitlyDisabled( false ),
@@ -183,7 +182,11 @@ KMComposeWin::KMComposeWin( KMMessage *aMsg, uint id )
mLabelWidth( 0 ),
mAutoSaveTimer( 0 ), mLastAutoSaveErrno( 0 ),
mSignatureStateIndicator( 0 ), mEncryptionStateIndicator( 0 ),
- mPreserveUserCursorPosition( false )
+ mPreserveUserCursorPosition( false ),
+ mPreventFccOverwrite( false ),
+ mCheckForRecipients( true ),
+ mCheckForForgottenAttachments( true ),
+ mIgnoreStickyFields( false )
{
mClassicalRecipients = GlobalSettings::self()->recipientsEditorType() ==
GlobalSettings::EnumRecipientsEditorType::Classic;
@@ -200,17 +203,29 @@ KMComposeWin::KMComposeWin( KMMessage *aMsg, uint id )
TQVBoxLayout *v = new TQVBoxLayout( mMainWidget );
v->addWidget( mHeadersToEditorSplitter );
mIdentity = new KPIM::IdentityCombo(kmkernel->identityManager(), mHeadersArea);
+ TQToolTip::add( mIdentity,
+ i18n( "Select an identity for this message" ) );
+
mDictionaryCombo = new DictionaryComboBox( mHeadersArea );
+ TQToolTip::add( mDictionaryCombo,
+ i18n( "Select the dictionary to use when spell-checking this message" ) );
+
mFcc = new KMFolderComboBox(mHeadersArea);
mFcc->showOutboxFolder( false );
+ TQToolTip::add( mFcc,
+ i18n( "Select the sent-mail folder where a copy of this message will be saved" ) );
+
mTransport = new TQComboBox(true, mHeadersArea);
+ TQToolTip::add( mTransport,
+ i18n( "Select the outgoing account to use for sending this message" ) );
+
mEdtFrom = new KMLineEdit(false,mHeadersArea, "fromLine");
+ TQToolTip::add( mEdtFrom,
+ i18n( "Set the \"From:\" email address for this message" ) );
mEdtReplyTo = new KMLineEdit(true,mHeadersArea, "replyToLine");
- mLblReplyTo = new TQLabel(mHeadersArea);
- mBtnReplyTo = new TQPushButton("...",mHeadersArea);
- mBtnReplyTo->setFocusPolicy(TQWidget::NoFocus);
- connect(mBtnReplyTo,TQT_SIGNAL(clicked()),TQT_SLOT(slotAddrBookReplyTo()));
+ TQToolTip::add( mEdtReplyTo,
+ i18n( "Set the \"Reply-To:\" email address for this message" ) );
connect(mEdtReplyTo,TQT_SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
TQT_SLOT(slotCompletionModeChanged(KGlobalSettings::Completion)));
@@ -234,7 +249,6 @@ KMComposeWin::KMComposeWin( KMMessage *aMsg, uint id )
TQToolTip::add( mBtnTo, tip );
TQToolTip::add( mBtnCc, tip );
TQToolTip::add( mBtnBcc, tip );
- TQToolTip::add( mBtnReplyTo, tip );
mBtnTo->setFocusPolicy(TQWidget::NoFocus);
mBtnCc->setFocusPolicy(TQWidget::NoFocus);
@@ -277,16 +291,30 @@ KMComposeWin::KMComposeWin( KMMessage *aMsg, uint id )
mRecipientsEditor->setFocus();
}
mEdtSubject = new KMLineEditSpell(false,mHeadersArea, "subjectLine");
- mLblIdentity = new TQLabel(mHeadersArea);
- mDictionaryLabel = new TQLabel( mHeadersArea );
- mLblFcc = new TQLabel(mHeadersArea);
- mLblTransport = new TQLabel(mHeadersArea);
- mLblFrom = new TQLabel(mHeadersArea);
- mLblSubject = new TQLabel(mHeadersArea);
+ TQToolTip::add( mEdtSubject,
+ i18n( "Set a subject for this message" ) );
+
+ mLblIdentity = new TQLabel( i18n("&Identity:"), mHeadersArea );
+ mDictionaryLabel = new TQLabel( i18n("&Dictionary:"), mHeadersArea );
+ mLblFcc = new TQLabel( i18n("&Sent-Mail folder:"), mHeadersArea );
+ mLblTransport = new TQLabel( i18n("&Mail transport:"), mHeadersArea );
+ mLblFrom = new TQLabel( i18n("sender address field", "&From:"), mHeadersArea );
+ mLblReplyTo = new TQLabel( i18n("&Reply to:"), mHeadersArea );
+ mLblSubject = new TQLabel( i18n("S&ubject:"), mHeadersArea );
+
TQString sticky = i18n("Sticky");
mBtnIdentity = new TQCheckBox(sticky,mHeadersArea);
+ TQToolTip::add( mBtnIdentity,
+ i18n( "Use the selected value as your identity for future messages" ) );
mBtnFcc = new TQCheckBox(sticky,mHeadersArea);
+ TQToolTip::add( mBtnFcc,
+ i18n( "Use the selected value as your sent-mail folder for future messages" ) );
mBtnTransport = new TQCheckBox(sticky,mHeadersArea);
+ TQToolTip::add( mBtnTransport,
+ i18n( "Use the selected value as your outgoing account for future messages" ) );
+ mBtnDictionary = new TQCheckBox( sticky, mHeadersArea );
+ TQToolTip::add( mBtnDictionary,
+ i18n( "Use the selected value as your dictionary for future messages" ) );
//setWFlags( WType_TopLevel | WStyle_Dialog );
mHtmlMarkup = GlobalSettings::self()->useHtmlMarkup();
@@ -350,6 +378,8 @@ KMComposeWin::KMComposeWin( KMMessage *aMsg, uint id )
GlobalSettings::self()->stickyFccItem()->whatsThis() );
TQWhatsThis::add( mBtnTransport,
GlobalSettings::self()->stickyTransportItem()->whatsThis() );
+ TQWhatsThis::add( mBtnTransport,
+ GlobalSettings::self()->stickyDictionaryItem()->whatsThis() );
mSpellCheckInProgress=false;
@@ -359,6 +389,7 @@ KMComposeWin::KMComposeWin( KMMessage *aMsg, uint id )
mBtnIdentity->setFocusPolicy(TQWidget::NoFocus);
mBtnFcc->setFocusPolicy(TQWidget::NoFocus);
mBtnTransport->setFocusPolicy(TQWidget::NoFocus);
+ mBtnDictionary->setFocusPolicy( TQWidget::NoFocus );
mAtmListView = new AttachmentListView( this, mSplitter,
"attachment list view" );
@@ -657,6 +688,7 @@ void KMComposeWin::readConfig( bool reload /* = false */ )
}
mBtnFcc->setChecked( GlobalSettings::self()->stickyFcc() );
mBtnTransport->setChecked( GlobalSettings::self()->stickyTransport() );
+ mBtnDictionary->setChecked( GlobalSettings::self()->stickyDictionary() );
TQStringList transportHistory = GlobalSettings::self()->transportHistory();
TQString currentTransport = GlobalSettings::self()->currentTransport();
@@ -711,8 +743,6 @@ void KMComposeWin::readConfig( bool reload /* = false */ )
const KPIM::Identity & ident =
kmkernel->identityManager()->identityForUoid( mIdentity->currentIdentity() );
- mDictionaryCombo->setCurrentByDictionary( ident.dictionary() );
-
mTransport->clear();
mTransport->insertStringList( KMTransportInfo::availableTransports() );
while ( transportHistory.count() > (uint)GlobalSettings::self()->maxTransportEntries() )
@@ -723,6 +753,12 @@ void KMComposeWin::readConfig( bool reload /* = false */ )
setTransport( currentTransport );
}
+ if ( mBtnDictionary->isChecked() ) {
+ mDictionaryCombo->setCurrentByDictionaryName( GlobalSettings::self()->previousDictionary() );
+ } else {
+ mDictionaryCombo->setCurrentByDictionary( ident.dictionary() );
+ }
+
TQString fccName = "";
if ( mBtnFcc->isChecked() ) {
fccName = GlobalSettings::self()->previousFcc();
@@ -737,12 +773,16 @@ void KMComposeWin::readConfig( bool reload /* = false */ )
void KMComposeWin::writeConfig(void)
{
GlobalSettings::self()->setHeaders( mShowHeaders );
- GlobalSettings::self()->setStickyTransport( mBtnTransport->isChecked() );
- GlobalSettings::self()->setStickyIdentity( mBtnIdentity->isChecked() );
GlobalSettings::self()->setStickyFcc( mBtnFcc->isChecked() );
- GlobalSettings::self()->setPreviousIdentity( mIdentity->currentIdentity() );
- GlobalSettings::self()->setCurrentTransport( mTransport->currentText() );
+ if ( !mIgnoreStickyFields ) {
+ GlobalSettings::self()->setCurrentTransport( mTransport->currentText() );
+ GlobalSettings::self()->setStickyTransport( mBtnTransport->isChecked() );
+ GlobalSettings::self()->setStickyDictionary( mBtnDictionary->isChecked() );
+ GlobalSettings::self()->setStickyIdentity( mBtnIdentity->isChecked() );
+ GlobalSettings::self()->setPreviousIdentity( mIdentity->currentIdentity() );
+ }
GlobalSettings::self()->setPreviousFcc( mFcc->getFolder()->idString() );
+ GlobalSettings::self()->setPreviousDictionary( mDictionaryCombo->currentDictionaryName() );
GlobalSettings::self()->setAutoSpellChecking(
mAutoSpellCheckingAction->isChecked() );
TQStringList transportHistory = GlobalSettings::self()->transportHistory();
@@ -950,7 +990,7 @@ void KMComposeWin::rethinkFields(bool fromSlot)
mGrid->setColStretch(0, 1);
mGrid->setColStretch(1, 100);
mGrid->setColStretch(2, 1);
- mGrid->setRowStretch(mNumHeaders, 100);
+ mGrid->setRowStretch( mNumHeaders + 1, 100 );
row = 0;
kdDebug(5006) << "KMComposeWin::rethinkFields" << endl;
@@ -967,37 +1007,37 @@ void KMComposeWin::rethinkFields(bool fromSlot)
if (!fromSlot) mAllFieldsAction->setChecked(showHeaders==HDR_ALL);
if (!fromSlot) mIdentityAction->setChecked(abs(mShowHeaders)&HDR_IDENTITY);
- rethinkHeaderLine(showHeaders,HDR_IDENTITY, row, i18n("&Identity:"),
+ rethinkHeaderLine(showHeaders,HDR_IDENTITY, row,
mLblIdentity, mIdentity, mBtnIdentity);
if (!fromSlot) mDictionaryAction->setChecked(abs(mShowHeaders)&HDR_DICTIONARY);
- rethinkHeaderLine(showHeaders,HDR_DICTIONARY, row, i18n("&Dictionary:"),
- mDictionaryLabel, mDictionaryCombo, 0 );
+ rethinkHeaderLine(showHeaders,HDR_DICTIONARY, row,
+ mDictionaryLabel, mDictionaryCombo, mBtnDictionary );
if (!fromSlot) mFccAction->setChecked(abs(mShowHeaders)&HDR_FCC);
- rethinkHeaderLine(showHeaders,HDR_FCC, row, i18n("&Sent-Mail folder:"),
+ rethinkHeaderLine(showHeaders,HDR_FCC, row,
mLblFcc, mFcc, mBtnFcc);
if (!fromSlot) mTransportAction->setChecked(abs(mShowHeaders)&HDR_TRANSPORT);
- rethinkHeaderLine(showHeaders,HDR_TRANSPORT, row, i18n("&Mail transport:"),
+ rethinkHeaderLine(showHeaders,HDR_TRANSPORT, row,
mLblTransport, mTransport, mBtnTransport);
if (!fromSlot) mFromAction->setChecked(abs(mShowHeaders)&HDR_FROM);
- rethinkHeaderLine(showHeaders,HDR_FROM, row, i18n("sender address field", "&From:"),
+ rethinkHeaderLine(showHeaders,HDR_FROM, row,
mLblFrom, mEdtFrom /*, mBtnFrom */ );
TQWidget *prevFocus = mEdtFrom;
if (!fromSlot) mReplyToAction->setChecked(abs(mShowHeaders)&HDR_REPLY_TO);
- rethinkHeaderLine(showHeaders,HDR_REPLY_TO,row,i18n("&Reply to:"),
- mLblReplyTo, mEdtReplyTo, mBtnReplyTo);
+ rethinkHeaderLine(showHeaders,HDR_REPLY_TO,row,
+ mLblReplyTo, mEdtReplyTo, 0);
if ( showHeaders & HDR_REPLY_TO ) {
prevFocus = connectFocusMoving( prevFocus, mEdtReplyTo );
}
if ( mClassicalRecipients ) {
if (!fromSlot) mToAction->setChecked(abs(mShowHeaders)&HDR_TO);
- rethinkHeaderLine(showHeaders, HDR_TO, row, i18n("recipient address field", "&To:"),
+ rethinkHeaderLine(showHeaders, HDR_TO, row,
mLblTo, mEdtTo, mBtnTo,
i18n("Primary Recipients"),
i18n("<qt>The email addresses you put "
@@ -1007,7 +1047,7 @@ void KMComposeWin::rethinkFields(bool fromSlot)
}
if (!fromSlot) mCcAction->setChecked(abs(mShowHeaders)&HDR_CC);
- rethinkHeaderLine(showHeaders, HDR_CC, row, i18n("&Copy to (CC):"),
+ rethinkHeaderLine(showHeaders, HDR_CC, row,
mLblCc, mEdtCc, mBtnCc,
i18n("Additional Recipients"),
i18n("<qt>The email addresses you put "
@@ -1022,7 +1062,7 @@ void KMComposeWin::rethinkFields(bool fromSlot)
}
if (!fromSlot) mBccAction->setChecked(abs(mShowHeaders)&HDR_BCC);
- rethinkHeaderLine(showHeaders,HDR_BCC, row, i18n("&Blind copy to (BCC):"),
+ rethinkHeaderLine(showHeaders,HDR_BCC, row,
mLblBcc, mEdtBcc, mBtnBcc,
i18n("Hidden Recipients"),
i18n("<qt>Essentially the same thing "
@@ -1057,7 +1097,7 @@ void KMComposeWin::rethinkFields(bool fromSlot)
prevFocus = mRecipientsEditor;
}
if (!fromSlot) mSubjectAction->setChecked(abs(mShowHeaders)&HDR_SUBJECT);
- rethinkHeaderLine(showHeaders,HDR_SUBJECT, row, i18n("S&ubject:"),
+ rethinkHeaderLine(showHeaders,HDR_SUBJECT, row,
mLblSubject, mEdtSubject);
connectFocusMoving( mEdtSubject, mEditor );
@@ -1100,13 +1140,12 @@ TQWidget *KMComposeWin::connectFocusMoving( TQWidget *prev, TQWidget *next )
//-----------------------------------------------------------------------------
void KMComposeWin::rethinkHeaderLine(int aValue, int aMask, int& aRow,
- const TQString &aLabelStr, TQLabel* aLbl,
+ TQLabel* aLbl,
TQLineEdit* aEdt, TQPushButton* aBtn,
const TQString &toolTip, const TQString &whatsThis )
{
if (aValue & aMask)
{
- aLbl->setText(aLabelStr);
if ( !toolTip.isEmpty() )
TQToolTip::add( aLbl, toolTip );
if ( !whatsThis.isEmpty() )
@@ -1137,12 +1176,11 @@ void KMComposeWin::rethinkHeaderLine(int aValue, int aMask, int& aRow,
//-----------------------------------------------------------------------------
void KMComposeWin::rethinkHeaderLine(int aValue, int aMask, int& aRow,
- const TQString &aLabelStr, TQLabel* aLbl,
+ TQLabel* aLbl,
TQComboBox* aCbx, TQCheckBox* aChk)
{
if (aValue & aMask)
{
- aLbl->setText(aLabelStr);
aLbl->adjustSize();
aLbl->resize((int)aLbl->sizeHint().width(),aLbl->sizeHint().height() + 6);
aLbl->setMinimumSize(aLbl->size());
@@ -1310,11 +1348,15 @@ void KMComposeWin::setupActions(void)
(void) new KAction (i18n("Paste as Attac&hment"),0,this,TQT_SLOT( slotPasteClipboardAsAttachment()),
actionCollection(), "paste_att");
- mAddQuoteChars = new KAction(i18n("Add &Quote Characters"), 0, this,
+ KAction * addq = new KAction(i18n("Add &Quote Characters"), 0, this,
TQT_SLOT(slotAddQuotes()), actionCollection(), "tools_quote");
+ connect( mEditor, TQT_SIGNAL(selectionAvailable(bool)),
+ addq, TQT_SLOT(setEnabled(bool)) );
- mRemQuoteChars = new KAction(i18n("Re&move Quote Characters"), 0, this,
+ KAction * remq = new KAction(i18n("Re&move Quote Characters"), 0, this,
TQT_SLOT(slotRemoveQuotes()), actionCollection(), "tools_unquote");
+ connect( mEditor, TQT_SIGNAL(selectionAvailable(bool)),
+ remq, TQT_SLOT(setEnabled(bool)) );
(void) new KAction (i18n("Cl&ean Spaces"), 0, this, TQT_SLOT(slotCleanSpace()),
@@ -1509,6 +1551,7 @@ void KMComposeWin::setupActions(void)
actionCollection(), "options_select_crypto" );
mCryptoModuleAction->setItems( l );
mCryptoModuleAction->setCurrentItem( format2cb( ident.preferredCryptoMessageFormat() ) );
+ mCryptoModuleAction->setToolTip( i18n( "Select a cryptographic format for this message" ) );
slotSelectCryptoModule( true /* initialize */ );
TQStringList styleItems;
@@ -1523,14 +1566,17 @@ void KMComposeWin::setupActions(void)
listAction = new KSelectAction( i18n( "Select Style" ), 0, actionCollection(),
"text_list" );
listAction->setItems( styleItems );
+ listAction->setToolTip( i18n( "Select a list style" ) );
connect( listAction, TQT_SIGNAL( activated( const TQString& ) ),
TQT_SLOT( slotListAction( const TQString& ) ) );
fontAction = new KFontAction( "Select Font", 0, actionCollection(),
"text_font" );
+ fontAction->setToolTip( i18n( "Select a font" ) );
connect( fontAction, TQT_SIGNAL( activated( const TQString& ) ),
TQT_SLOT( slotFontAction( const TQString& ) ) );
fontSizeAction = new KFontSizeAction( "Select Size", 0, actionCollection(),
"text_size" );
+ fontSizeAction->setToolTip( i18n( "Select a font size" ) );
connect( fontSizeAction, TQT_SIGNAL( fontSizeChanged( int ) ),
TQT_SLOT( slotSizeAction( int ) ) );
@@ -1821,7 +1867,7 @@ void KMComposeWin::setMsg(KMMessage* newMsg, bool mayAutoSign,
}
mEdtSubject->setText(mMsg->subject());
- const bool stickyIdentity = mBtnIdentity->isChecked();
+ const bool stickyIdentity = mBtnIdentity->isChecked() && !mIgnoreStickyFields;
const bool messageHasIdentity = !newMsg->headerField("X-KMail-Identity").isEmpty();
if (!stickyIdentity && messageHasIdentity)
mId = newMsg->headerField("X-KMail-Identity").stripWhiteSpace().toUInt();
@@ -1933,7 +1979,8 @@ void KMComposeWin::setMsg(KMMessage* newMsg, bool mayAutoSign,
!ident.pgpEncryptionKey().isEmpty() );
TQString transport = newMsg->headerField("X-KMail-Transport");
- if (!mBtnTransport->isChecked() && !transport.isEmpty())
+ const bool stickyTransport = mBtnTransport->isChecked() && !mIgnoreStickyFields;
+ if (!stickyTransport && !transport.isEmpty())
setTransport( transport );
if (!mBtnFcc->isChecked())
@@ -1944,7 +1991,10 @@ void KMComposeWin::setMsg(KMMessage* newMsg, bool mayAutoSign,
setFcc(ident.fcc());
}
- mDictionaryCombo->setCurrentByDictionary( ident.dictionary() );
+ const bool stickyDictionary = mBtnDictionary->isChecked() && !mIgnoreStickyFields;
+ if ( !stickyDictionary ) {
+ mDictionaryCombo->setCurrentByDictionary( ident.dictionary() );
+ }
partNode * root = partNode::fromMessage( mMsg );
@@ -1952,10 +2002,6 @@ void KMComposeWin::setMsg(KMMessage* newMsg, bool mayAutoSign,
otp.parseObjectTree( root );
KMail::AttachmentCollector ac;
- ac.setDiveIntoEncryptions( true );
- ac.setDiveIntoSignatures( true );
- ac.setDiveIntoMessages( false );
-
ac.collectAttachmentsFrom( root );
for ( std::vector<partNode*>::const_iterator it = ac.attachments().begin() ; it != ac.attachments().end() ; ++it )
@@ -2122,6 +2168,9 @@ void KMComposeWin::setMsg(KMMessage* newMsg, bool mayAutoSign,
// do this even for new messages
mEditor->setCursorPositionFromStart( (unsigned int) mMsg->getCursorPos() );
+
+ // honor "keep reply in this folder" setting even when the identity is changed later on
+ mPreventFccOverwrite = ( !newMsg->fcc().isEmpty() && ident.fcc() != newMsg->fcc() );
}
@@ -2217,7 +2266,8 @@ bool KMComposeWin::queryClose ()
//-----------------------------------------------------------------------------
bool KMComposeWin::userForgotAttachment()
{
- bool checkForForgottenAttachments = GlobalSettings::self()->showForgottenAttachmentWarning();
+ bool checkForForgottenAttachments =
+ mCheckForForgottenAttachments && GlobalSettings::self()->showForgottenAttachmentWarning();
if ( !checkForForgottenAttachments || ( mAtmList.count() > 0 ) )
return false;
@@ -2482,6 +2532,13 @@ void KMComposeWin::removeAttach(const TQString &aUrl)
void KMComposeWin::removeAttach(int idx)
{
mAtmModified = true;
+
+ KMAtmListViewItem *item = static_cast<KMAtmListViewItem*>( mAtmItemList.at( idx ) );
+ if ( item->itemBelow() )
+ mAtmSelectNew = item->itemBelow();
+ else if ( item->itemAbove() )
+ mAtmSelectNew = item->itemAbove();
+
mAtmList.remove(idx);
delete mAtmItemList.take(idx);
@@ -2692,11 +2749,19 @@ void KMComposeWin::slotAttachFile()
// We will not care about any permissions, existence or whatsoever in
// this function.
- KFileDialog fdlg(TQString::null, TQString::null, this, 0, true);
+ // Handle the case where the last savedir is gone. kolab/issue4057
+ TQString recent;
+ KURL recentURL = KFileDialog::getStartURL( TQString::null, recent );
+ if ( !recentURL.url().isEmpty() &&
+ !KIO::NetAccess::exists( recentURL, true, this ) ) {
+ recentURL = KURL( TQDir::homeDirPath() );
+ }
+
+ KFileDialog fdlg( recentURL.url(), TQString::null, this, 0, true );
fdlg.setOperationMode( KFileDialog::Other );
- fdlg.setCaption(i18n("Attach File"));
- fdlg.okButton()->setGuiItem(KGuiItem(i18n("&Attach"),"fileopen"));
- fdlg.setMode(KFile::Files);
+ fdlg.setCaption( i18n( "Attach File" ) );
+ fdlg.okButton()->setGuiItem( KGuiItem( i18n( "&Attach" ),"fileopen" ) );
+ fdlg.setMode( KFile::Files );
fdlg.exec();
KURL::List files = fdlg.selectedURLs();
@@ -2831,7 +2896,9 @@ void KMComposeWin::slotAttachFileResult(KIO::Job *job)
mMapAtmLoadData.remove(it);
- msgPart->setCharset(partCharset);
+ if ( msgPart->typeStr().lower() == "text" ) {
+ msgPart->setCharset(partCharset);
+ }
// show message part dialog, if not configured away (default):
KConfigGroup composer(KMKernel::config(), "Composer");
@@ -2859,7 +2926,6 @@ void KMComposeWin::slotAttachFileResult(KIO::Job *job)
}
}
mAtmModified = true;
- if (msgPart->typeStr().lower() != "text") msgPart->setCharset(TQCString());
// add the new attachment to the list
addAttach(msgPart);
@@ -3180,7 +3246,6 @@ void KMComposeWin::slotAttachProperties()
if (idx < 0) return;
KMMessagePart* msgPart = mAtmList.at(idx);
- msgPart->setCharset(mCharset);
KMMsgPartDialogCompat dlg(mMainWidget);
dlg.setMsgPart(msgPart);
@@ -3495,7 +3560,9 @@ void KMComposeWin::editAttach(int index, bool openWith)
atmTempFile->file()->flush();
- KMail::EditorWatcher *watcher = new KMail::EditorWatcher( KURL( atmTempFile->name() ), contentTypeStr, openWith, this );
+ KMail::EditorWatcher *watcher =
+ new KMail::EditorWatcher( KURL( atmTempFile->name() ), contentTypeStr, openWith,
+ this, this );
connect( watcher, TQT_SIGNAL(editDone(KMail::EditorWatcher*)), TQT_SLOT(slotEditDone(KMail::EditorWatcher*)) );
if ( watcher->start() ) {
mEditorMap.insert( watcher, msgPart );
@@ -3516,7 +3583,7 @@ void KMComposeWin::slotAttachSave()
pname = msgPart->name();
if (pname.isEmpty()) pname="unnamed";
- KURL url = KFileDialog::getSaveURL(TQString::null, TQString::null, 0, i18n("Save Attachment As"));
+ KURL url = KFileDialog::getSaveURL(pname, TQString::null, 0, i18n("Save Attachment As"));
if( url.isEmpty() )
return;
@@ -3528,6 +3595,7 @@ void KMComposeWin::slotAttachSave()
//-----------------------------------------------------------------------------
void KMComposeWin::slotAttachRemove()
{
+ mAtmSelectNew = 0;
bool attachmentRemoved = false;
int i = 0;
for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ) {
@@ -3544,6 +3612,10 @@ void KMComposeWin::slotAttachRemove()
if ( attachmentRemoved ) {
setModified( true );
slotUpdateAttachActions();
+ if ( mAtmSelectNew ) {
+ mAtmListView->setSelected( mAtmSelectNew, true );
+ mAtmListView->setCurrentItem( mAtmSelectNew );
+ }
}
}
@@ -3861,6 +3933,7 @@ void KMComposeWin::slotEncryptToggled(bool on)
//-----------------------------------------------------------------------------
void KMComposeWin::setEncryption( bool encrypt, bool setByUser )
{
+ bool wasModified = isModified();
if ( setByUser )
setModified( true );
if ( !mEncryptAction->isEnabled() )
@@ -3868,7 +3941,7 @@ void KMComposeWin::setEncryption( bool encrypt, bool setByUser )
// check if the user wants to encrypt messages to himself and if he defined
// an encryption key for the current identity
else if ( encrypt && encryptToSelf() && !mLastIdentityHasEncryptionKey ) {
- if ( setByUser )
+ if ( setByUser ) {
KMessageBox::sorry( this,
i18n("<qt><p>You have requested that messages be "
"encrypted to yourself, but the currently selected "
@@ -3878,6 +3951,8 @@ void KMComposeWin::setEncryption( bool encrypt, bool setByUser )
"in the identity configuration.</p>"
"</qt>"),
i18n("Undefined Encryption Key") );
+ setModified( wasModified );
+ }
encrypt = false;
}
@@ -3912,6 +3987,7 @@ void KMComposeWin::slotSignToggled(bool on)
//-----------------------------------------------------------------------------
void KMComposeWin::setSigning( bool sign, bool setByUser )
{
+ bool wasModified = isModified();
if ( setByUser )
setModified( true );
if ( !mSignAction->isEnabled() )
@@ -3919,7 +3995,7 @@ void KMComposeWin::setSigning( bool sign, bool setByUser )
// check if the user defined a signing key for the current identity
if ( sign && !mLastIdentityHasSigningKey ) {
- if ( setByUser )
+ if ( setByUser ) {
KMessageBox::sorry( this,
i18n("<qt><p>In order to be able to sign "
"this message you first have to "
@@ -3929,6 +4005,8 @@ void KMComposeWin::setSigning( bool sign, bool setByUser )
"in the identity configuration.</p>"
"</qt>"),
i18n("Undefined Signing Key") );
+ setModified( wasModified );
+ }
sign = false;
}
@@ -3966,6 +4044,26 @@ void KMComposeWin::disableWordWrap()
mEditor->setWordWrap( TQTextEdit::NoWrap );
}
+void KMComposeWin::disableRecipientNumberCheck()
+{
+ mCheckForRecipients = false;
+}
+
+void KMComposeWin::disableForgottenAttachmentsCheck()
+{
+ mCheckForForgottenAttachments = false;
+}
+
+void KMComposeWin::ignoreStickyFields()
+{
+ mIgnoreStickyFields = true;
+ mBtnTransport->setChecked( false );
+ mBtnDictionary->setChecked( false );
+ mBtnIdentity->setChecked( false );
+ mBtnTransport->setEnabled( false );
+ mBtnDictionary->setEnabled( false );
+ mBtnIdentity->setEnabled( false );
+}
//-----------------------------------------------------------------------------
void KMComposeWin::slotPrint()
@@ -4275,11 +4373,24 @@ void KMComposeWin::slotContinueDoSend( bool sentOk )
return;
}
+bool KMComposeWin::checkTransport() const
+{
+ if ( KMail::TransportManager::transportNames().isEmpty() ) {
+ KMessageBox::information( mMainWidget,
+ i18n("Please create an account for sending and try again.") );
+ return false;
+ }
+ return true;
+}
//----------------------------------------------------------------------------
void KMComposeWin::slotSendLater()
{
+ if ( !checkTransport() )
+ return;
+ if ( !checkRecipientNumber() )
+ return;
if ( mEditor->checkExternalEditorFinished() )
doSend( KMail::MessageSender::SendLater );
}
@@ -4322,6 +4433,10 @@ void KMComposeWin::slotSendLaterVia( int item )
void KMComposeWin::slotSendNow() {
if ( !mEditor->checkExternalEditorFinished() )
return;
+ if ( !checkTransport() )
+ return;
+ if ( !checkRecipientNumber() )
+ return;
if ( GlobalSettings::self()->confirmBeforeSend() )
{
int rc = KMessageBox::warningYesNoCancel( mMainWidget,
@@ -4339,6 +4454,26 @@ void KMComposeWin::slotSendNow() {
doSend( KMail::MessageSender::SendImmediate );
}
+
+//----------------------------------------------------------------------------
+bool KMComposeWin::checkRecipientNumber() const
+{
+ uint thresHold = GlobalSettings::self()->recipientThreshold();
+ if ( mCheckForRecipients &&
+ GlobalSettings::self()->tooManyRecipients() &&
+ mRecipientsEditor->recipients().count() > thresHold ) {
+ if ( KMessageBox::questionYesNo( mMainWidget,
+ i18n("You are trying to send the mail to more than %1 recipients. Send message anyway?").arg(thresHold),
+ i18n("Too many receipients"),
+ i18n("&Send as Is"),
+ i18n("&Edit Recipients")) == KMessageBox::No ) {
+ return false;
+ }
+ }
+ return true;
+}
+
+
//----------------------------------------------------------------------------
void KMComposeWin::slotAppendSignature()
{
@@ -4348,17 +4483,17 @@ void KMComposeWin::slotAppendSignature()
//----------------------------------------------------------------------------
void KMComposeWin::slotPrependSignature()
{
- insertSignature( false );
+ insertSignature( Prepend );
}
//----------------------------------------------------------------------------
void KMComposeWin::slotInsertSignatureAtCursor()
{
- insertSignature( false, mEditor->currentLine() );
+ insertSignature( AtCursor );
}
//----------------------------------------------------------------------------
-void KMComposeWin::insertSignature( bool append, int pos )
+void KMComposeWin::insertSignature( SignaturePlacement placement )
{
bool mod = mEditor->isModified();
@@ -4370,12 +4505,36 @@ void KMComposeWin::insertSignature( bool append, int pos )
if( !mOldSigText.isEmpty() )
{
- mEditor->sync();
- if ( append ) {
+ mEditor->sync();
+ int paragraph, index;
+ mEditor->getCursorPosition( &paragraph, &index );
+ index = mEditor->indexOfCurrentLineStart( paragraph, index );
+
+ switch( placement ) {
+ case Append:
mEditor->setText( mEditor->text() + mOldSigText );
- } else {
- mOldSigText = "\n\n"+mOldSigText+"\n";
- mEditor->insertAt(mOldSigText, pos, 0);
+ break;
+ case Prepend:
+ mOldSigText = "\n\n" + mOldSigText + "\n";
+ mEditor->insertAt( mOldSigText, paragraph, index );
+ break;
+ case AtCursor:
+
+ // If there is text in the same line, add a newline so that the stuff in
+ // the current line moves after the signature. Also remove a leading newline, it is not
+ // needed here.
+ if ( mEditor->paragraphLength( paragraph ) > 0 )
+ mOldSigText = mOldSigText + "\n";
+ if ( mOldSigText.startsWith( "\n" ) )
+ mOldSigText = mOldSigText.remove( 0, 1 );
+
+ // If we are inserting into a wordwrapped line, add a newline at the start to make
+ // the text edit hard-wrap the line here
+ if ( index != 0 )
+ mOldSigText = "\n" + mOldSigText;
+
+ mEditor->insertAt( mOldSigText, paragraph, index );
+ break;
}
mEditor->update();
mEditor->setModified(mod);
@@ -4390,8 +4549,13 @@ void KMComposeWin::insertSignature( bool append, int pos )
} else {
// for append and prepend, move the cursor to 0,0, for insertAt,
// keep it in the same row, but move to first column
- mEditor->setCursorPosition( pos, 0 );
- if ( !append && pos == 0 )
+ if ( index == 0 ) {
+ mEditor->setCursorPosition( paragraph, 0 );
+ } else {
+ // For word-wrapped lines, we have created a new paragraph, so change to that one
+ mEditor->setCursorPosition( paragraph + 1, 0 );
+ }
+ if ( placement == Prepend || placement == Append )
mEditor->setContentsPos( 0, 0 );
}
mEditor->sync();
@@ -4715,7 +4879,7 @@ void KMComposeWin::slotIdentityChanged( uint uoid )
}
}
- if ( !mBtnTransport->isChecked() ) {
+ if ( !mBtnTransport->isChecked() && !mIgnoreStickyFields ) {
TQString transp = ident.transport();
if ( transp.isEmpty() )
{
@@ -4727,10 +4891,12 @@ void KMComposeWin::slotIdentityChanged( uint uoid )
setTransport( transp );
}
- mDictionaryCombo->setCurrentByDictionary( ident.dictionary() );
+ if ( !mBtnDictionary->isChecked() && !mIgnoreStickyFields ) {
+ mDictionaryCombo->setCurrentByDictionary( ident.dictionary() );
+ }
- if ( !mBtnFcc->isChecked() ) {
- setFcc( ident.fcc() );
+ if ( !mBtnFcc->isChecked() && !mPreventFccOverwrite ) {
+ setFcc( ident.fcc() );
}
TQString edtText = mEditor->text();
@@ -4741,27 +4907,40 @@ void KMComposeWin::slotIdentityChanged( uint uoid )
identityManager()->
identityForUoidOrDefault( mMsg->headerField( "X-KMail-Identity" ).
stripWhiteSpace().toUInt() );
- mOldSigText = id.signatureText();
+ mOldSigText = GlobalSettings::self()->prependSignature() ? id.signature().rawText() : id.signatureText();
}
- // try to truncate the old sig
- // First remove any trailing whitespace
- while ( !edtText.isEmpty() && edtText[edtText.length()-1].isSpace() )
- edtText.truncate( edtText.length() - 1 );
- // From the sig too, just in case
- while ( !mOldSigText.isEmpty() && mOldSigText[mOldSigText.length()-1].isSpace() )
- mOldSigText.truncate( mOldSigText.length() - 1 );
- if( edtText.endsWith( mOldSigText ) )
- edtText.truncate( edtText.length() - mOldSigText.length() );
+ if ( !GlobalSettings::prependSignature() ) {
+ // try to truncate the old sig
+ // First remove any trailing whitespace
+ while ( !edtText.isEmpty() && edtText[edtText.length()-1].isSpace() )
+ edtText.truncate( edtText.length() - 1 );
+ // From the sig too, just in case
+ while ( !mOldSigText.isEmpty() && mOldSigText[mOldSigText.length()-1].isSpace() )
+ mOldSigText.truncate( mOldSigText.length() - 1 );
+
+ if ( edtText.endsWith( mOldSigText ) )
+ edtText.truncate( edtText.length() - mOldSigText.length() );
- // now append the new sig
- mOldSigText = ident.signatureText();
- if( ( !mOldSigText.isEmpty() ) &&
- ( GlobalSettings::self()->autoTextSignature() == "auto" ) ) {
- edtText.append( mOldSigText );
+ // now append the new sig
+ mOldSigText = ident.signatureText();
+ if( ( !mOldSigText.isEmpty() ) &&
+ ( GlobalSettings::self()->autoTextSignature() == "auto" ) ) {
+ edtText.append( mOldSigText );
+ }
+ mEditor->setText( edtText );
+ } else {
+ const int pos = edtText.find( mOldSigText );
+ if ( pos >= 0 && !mOldSigText.isEmpty() ) {
+ const int oldLength = mOldSigText.length();
+ mOldSigText = "\n\n"+ ident.signature().rawText() + "\n"; // see insertSignature()
+ edtText = edtText.replace( pos, oldLength, mOldSigText );
+ mEditor->setText( edtText );
+ } else {
+ insertSignature( Append );
+ }
}
- mEditor->setText( edtText );
// disable certain actions if there is no PGP user identity set
// for this profile
@@ -4897,9 +5076,6 @@ void KMComposeWin::updateAutoSave()
void KMComposeWin::setAutoSaveFilename( const TQString & filename )
{
- if ( !mAutoSaveFilename.isEmpty() )
- KMFolderMaildir::removeFile( KMKernel::localDataPath() + "autosave",
- mAutoSaveFilename );
mAutoSaveFilename = filename;
}
@@ -4957,8 +5133,6 @@ void KMComposeWin::slotFolderRemoved(KMFolder* folder)
void KMComposeWin::editorFocusChanged(bool gained)
{
mPasteQuotation->setEnabled(gained);
- mAddQuoteChars->setEnabled(gained);
- mRemQuoteChars->setEnabled(gained);
}
void KMComposeWin::slotSetAlwaysSend( bool bAlways )
diff --git a/kmail/kmcomposewin.h b/kmail/kmcomposewin.h
index 7f003d44a..f38a8f682 100644
--- a/kmail/kmcomposewin.h
+++ b/kmail/kmcomposewin.h
@@ -96,7 +96,7 @@ namespace GpgME {
}
//-----------------------------------------------------------------------------
-class KMComposeWin : public KMail::Composer, virtual public MailComposerIface
+class KMComposeWin : public KMail::Composer, public MailComposerIface
{
Q_OBJECT
friend class ::KMEdit;
@@ -161,6 +161,32 @@ public: // kmkernel, kmcommands, callback
void disableWordWrap();
+ /** Don't check if there are too many recipients for a mail,
+ * eg. when sending out invitations.
+ */
+ void disableRecipientNumberCheck();
+
+ /** Don't check for forgotten attachments for a mail,
+ * eg. when sending out invitations.
+ */
+ void disableForgottenAttachmentsCheck();
+
+ /**
+ * Ignore the "sticky" setting of the transport combo box and prefer the X-KMail-Transport
+ * header field of the message instead.
+ * Do the same for the identity combo box, don't obey the "sticky" setting but use the
+ * X-KMail-Identity header field instead.
+ *
+ * This is useful when sending out invitations, since you don't see the GUI and want the
+ * identity and transport to be set to the values stored in the messages.
+ */
+ void ignoreStickyFields();
+
+ /**
+ * Returns @c true while the message composing is in progress.
+ */
+ bool isComposing() const { return mComposer != 0; }
+
private: // kmedit
/**
* Returns message of the composer. To apply the user changes to the
@@ -524,14 +550,22 @@ private:
*/
void rethinkHeaderLine( int aValue, int aMask, int& aRow,
- const TQString &aLabelStr, TQLabel* aLbl,
+ TQLabel* aLbl,
TQLineEdit* aEdt, TQPushButton* aBtn = 0,
const TQString &toolTip = TQString::null,
const TQString &whatsThis = TQString::null );
void rethinkHeaderLine( int value, int mask, int& row,
- const TQString& labelStr, TQLabel* lbl,
- TQComboBox* cbx, TQCheckBox *chk );
+ TQLabel* lbl, TQComboBox* cbx, TQCheckBox *chk );
+
+ /**
+ * Checks how many recipients are and warns if there are too many.
+ * @return true, if the user accepted the warning and the message should be sent
+ */
+ bool checkRecipientNumber() const;
+
+
+ bool checkTransport() const;
/**
* Initialization methods
@@ -691,11 +725,13 @@ private:
*/
void setTransport( const TQString & transport );
+ enum SignaturePlacement { Append, Prepend, AtCursor };
+
/**
* Helper to insert the signature of the current identy at the
* beginning or end of the editor.
*/
- void insertSignature( bool append = true, int pos = 0 );
+ void insertSignature( SignaturePlacement placement = Append );
private slots:
/**
* Compress an attachemnt with the given index
@@ -717,11 +753,12 @@ private:
TQLabel *mLblIdentity, *mLblTransport, *mLblFcc;
TQLabel *mLblFrom, *mLblReplyTo, *mLblTo, *mLblCc, *mLblBcc, *mLblSubject;
TQLabel *mDictionaryLabel;
- TQCheckBox *mBtnIdentity, *mBtnTransport, *mBtnFcc;
+ TQCheckBox *mBtnIdentity, *mBtnDictionary, *mBtnTransport, *mBtnFcc;
TQPushButton *mBtnTo, *mBtnCc, *mBtnBcc, /* *mBtnFrom, */ *mBtnReplyTo;
bool mSpellCheckInProgress;
bool mDone;
bool mAtmModified;
+ TQListViewItem *mAtmSelectNew;
KMEdit* mEditor;
TQGridLayout* mGrid;
@@ -906,6 +943,11 @@ private:
* accidentally moving the cursor.
*/
bool mPreserveUserCursorPosition;
+
+ bool mPreventFccOverwrite;
+ bool mCheckForRecipients;
+ bool mCheckForForgottenAttachments;
+ bool mIgnoreStickyFields;
};
#endif
diff --git a/kmail/kmedit.cpp b/kmail/kmedit.cpp
index bb1bb88f6..6fdc3352c 100644
--- a/kmail/kmedit.cpp
+++ b/kmail/kmedit.cpp
@@ -200,10 +200,10 @@ void KMEdit::contentsDropEvent(TQDropEvent *e)
}
else
kdDebug(5006) << "KMEdit::contentsDropEvent, unable to add dropped object" << endl;
- }
+ }
else if( e->provides("text/x-textsnippet") ) {
emit insertSnippet();
- }
+ }
else {
KEdit::contentsDropEvent(e);
}
@@ -214,7 +214,8 @@ KMEdit::KMEdit(TQWidget *parent, KMComposeWin* composer,
const char *name)
: KEdit( parent, name ),
mComposer( composer ),
- mKSpell( 0 ),
+ mKSpellForDialog( 0 ),
+ mSpeller( 0 ),
mSpellConfig( autoSpellConfig ),
mSpellingFilter( 0 ),
mExtEditorTempFile( 0 ),
@@ -222,19 +223,30 @@ KMEdit::KMEdit(TQWidget *parent, KMComposeWin* composer,
mExtEditorProcess( 0 ),
mUseExtEditor( false ),
mWasModifiedBeforeSpellCheck( false ),
- mSpellChecker( 0 ),
+ mHighlighter( 0 ),
mSpellLineEdit( false ),
mPasteMode( QClipboard::Clipboard )
{
+ connect( this, TQT_SIGNAL(selectionChanged()), this, TQT_SLOT(slotSelectionChanged()) );
installEventFilter(this);
KCursor::setAutoHideCursor( this, true, true );
setOverwriteEnabled( true );
+ createSpellers();
+ connect( mSpellConfig, TQT_SIGNAL( configChanged() ),
+ this, TQT_SLOT( createSpellers() ) );
+ connect( mSpeller, TQT_SIGNAL( death() ),
+ this, TQT_SLOT( spellerDied() ) );
}
+void KMEdit::createSpellers()
+{
+ delete mSpeller;
+ mSpeller = new KMSpell( this, TQT_SLOT( spellerReady( KSpell * ) ), mSpellConfig );
+}
void KMEdit::initializeAutoSpellChecking()
{
- if ( mSpellChecker )
+ if ( mHighlighter )
return; // already initialized
TQColor defaultColor1( 0x00, 0x80, 0x00 ); // defaults from kmreaderwin.cpp
TQColor defaultColor2( 0x00, 0x70, 0x00 );
@@ -252,14 +264,14 @@ void KMEdit::initializeAutoSpellChecking()
TQColor col3 = readerConfig.readColorEntry( "QuotedText2", &defaultColor2 );
TQColor col4 = readerConfig.readColorEntry( "QuotedText1", &defaultColor1 );
TQColor misspelled = readerConfig.readColorEntry( "MisspelledColor", &c );
- mSpellChecker = new KDictSpellingHighlighter( this, /*active*/ true,
- /*autoEnabled*/ false,
- /*spellColor*/ misspelled,
- /*colorQuoting*/ true,
- col1, col2, col3, col4,
- mSpellConfig );
-
- connect( mSpellChecker, TQT_SIGNAL(newSuggestions(const TQString&, const TQStringList&, unsigned int)),
+ mHighlighter = new KMSyntaxHighter( this, /*active*/ true,
+ /*autoEnabled*/ false,
+ /*spellColor*/ misspelled,
+ /*colorQuoting*/ true,
+ col1, col2, col3, col4,
+ mSpellConfig );
+
+ connect( mHighlighter, TQT_SIGNAL(newSuggestions(const TQString&, const TQStringList&, unsigned int)),
this, TQT_SLOT(addSuggestion(const TQString&, const TQStringList&, unsigned int)) );
}
@@ -279,8 +291,8 @@ TQPopupMenu *KMEdit::createPopupMenu( const TQPoint& pos )
void KMEdit::deleteAutoSpellChecking()
{ // because the highlighter doesn't support RichText, delete its instance.
- delete mSpellChecker;
- mSpellChecker =0;
+ delete mHighlighter;
+ mHighlighter =0;
}
void KMEdit::addSuggestion(const TQString& text, const TQStringList& lst, unsigned int )
@@ -290,8 +302,8 @@ void KMEdit::addSuggestion(const TQString& text, const TQStringList& lst, unsign
void KMEdit::setSpellCheckingActive(bool spellCheckingActive)
{
- if ( mSpellChecker ) {
- mSpellChecker->setActive(spellCheckingActive);
+ if ( mHighlighter ) {
+ mHighlighter->setActive(spellCheckingActive);
}
}
@@ -300,10 +312,16 @@ KMEdit::~KMEdit()
{
removeEventFilter(this);
- delete mKSpell;
- delete mSpellChecker;
- mSpellChecker = 0;
+ if ( mSpeller ) {
+ // The speller needs some time to clean up, so trigger cleanup and let it delete itself
+ mSpeller->setAutoDelete( true );
+ mSpeller->cleanUp();
+ mSpeller = 0;
+ }
+ delete mKSpellForDialog;
+ delete mHighlighter;
+ mHighlighter = 0;
}
@@ -343,6 +361,55 @@ unsigned int KMEdit::lineBreakColumn() const
return lineBreakColumn;
}
+KMSpell::KMSpell( TQObject *receiver, const char *slot, KSpellConfig *spellConfig )
+ : KSpell( 0, TQString(), receiver, slot, spellConfig )
+{
+}
+
+KMSyntaxHighter::KMSyntaxHighter( TQTextEdit *textEdit,
+ bool spellCheckingActive,
+ bool autoEnable,
+ const TQColor& spellColor,
+ bool colorQuoting,
+ const TQColor& QuoteColor0,
+ const TQColor& QuoteColor1,
+ const TQColor& QuoteColor2,
+ const TQColor& QuoteColor3,
+ KSpellConfig *spellConfig )
+ : KDictSpellingHighlighter( textEdit, spellCheckingActive, autoEnable, spellColor, colorQuoting,
+ QuoteColor0, QuoteColor1, QuoteColor2, QuoteColor3, spellConfig )
+{
+}
+
+bool KMSyntaxHighter::isMisspelled( const TQString &word )
+{
+ if ( mIgnoredWords.contains( word ) ) {
+ return false;
+ }
+ else {
+ return KDictSpellingHighlighter::isMisspelled( word );
+ }
+}
+
+void KMSyntaxHighter::ignoreWord( const TQString &word )
+{
+ mIgnoredWords << word;
+}
+
+TQStringList KMSyntaxHighter::ignoredWords() const
+{
+ return mIgnoredWords;
+}
+
+void KMEdit::spellerDied()
+{
+ mSpeller = 0;
+}
+
+void KMEdit::spellerReady( KSpell *spell )
+{
+ Q_ASSERT( mSpeller == spell );
+}
bool KMEdit::eventFilter(TQObject*o, TQEvent* e)
{
@@ -439,7 +506,6 @@ bool KMEdit::eventFilter(TQObject*o, TQEvent* e)
if( !word.isEmpty() && mReplacements.contains( word ) )
{
KPopupMenu p;
- p.insertTitle( i18n("Suggestions") );
//Add the suggestions to the popup menu
TQStringList reps = mReplacements[word];
@@ -453,13 +519,34 @@ bool KMEdit::eventFilter(TQObject*o, TQEvent* e)
}
else
{
- p.insertItem( TQString::fromLatin1("No Suggestions"), -2 );
+ p.setItemEnabled( p.insertItem( i18n( "No Suggestions" ), -2 ), false );
+ }
+
+ int addToDictionaryId = -42;
+ int ignoreId = -43;
+ if ( mSpeller && mSpeller->status() == KSpell::Running ) {
+ p.insertSeparator();
+ addToDictionaryId = p.insertItem( i18n( "Add to Dictionary" ) );
+ ignoreId = p.insertItem( i18n( "Ignore All" ) );
}
//Execute the popup inline
- int id = p.exec( mapToGlobal( event->pos() ) );
+ const int id = p.exec( mapToGlobal( event->pos() ) );
- if( id > -1 )
+ if ( id == ignoreId ) {
+ mHighlighter->ignoreWord( word );
+ mHighlighter->rehighlight();
+ }
+ if ( id == addToDictionaryId ) {
+ mSpeller->addPersonal( word );
+ mSpeller->writePersonalDictionary();
+ if ( mHighlighter ) {
+ // Wait a bit until reloading the highlighter, the mSpeller first needs to finish saving
+ // the personal word list.
+ TQTimer::singleShot( 200, mHighlighter, TQT_SLOT( slotLocalSpellConfigChanged() ) );
+ }
+ }
+ else if( id > -1 )
{
//Save the cursor position
int parIdx = 1, txtIdx = 1;
@@ -472,6 +559,12 @@ bool KMEdit::eventFilter(TQObject*o, TQEvent* e)
txtIdx += mReplacements[word][id].length() - word.length();
setCursorPosition(parIdx, txtIdx);
}
+
+ if ( id == addToDictionaryId || id == ignoreId ) {
+ // No longer misspelled: Either added to dictionary or ignored
+ mReplacements.remove( word );
+ }
+
//Cancel original event
return true;
}
@@ -494,10 +587,10 @@ int KMEdit::autoSpellChecking( bool on )
KMessageBox::sorry(this, i18n("Automatic spellchecking is not possible on text with markup."));
return -1;
}
- if ( mSpellChecker ) {
+ if ( mHighlighter ) {
// don't autoEnable spell checking if the user turned spell checking off
- mSpellChecker->setAutomatic( on );
- mSpellChecker->setActive( on );
+ mHighlighter->setAutomatic( on );
+ mHighlighter->setActive( on );
}
return 1;
}
@@ -551,54 +644,57 @@ bool KMEdit::checkExternalEditorFinished() {
void KMEdit::spellcheck()
{
- if ( mKSpell )
+ if ( mKSpellForDialog )
return;
mWasModifiedBeforeSpellCheck = isModified();
mSpellLineEdit = !mSpellLineEdit;
// maybe for later, for now plaintext is given to KSpell
// if (textFormat() == Qt::RichText ) {
// kdDebug(5006) << "KMEdit::spellcheck, spellchecking for RichText" << endl;
-// mKSpell = new KSpell(this, i18n("Spellcheck - KMail"), this,
+// mKSpellForDialog = new KSpell(this, i18n("Spellcheck - KMail"), this,
// TQT_SLOT(slotSpellcheck2(KSpell*)),0,true,false,KSpell::HTML);
// }
// else {
- mKSpell = new KSpell(this, i18n("Spellcheck - KMail"), this,
- TQT_SLOT(slotSpellcheck2(KSpell*)));
+
+ // Don't use mSpellConfig here. Reason is that the spell dialog, KSpellDlg, uses its own
+ // spell config, and therefore the two wouldn't be in sync.
+ mKSpellForDialog = new KSpell( this, i18n("Spellcheck - KMail"), this,
+ TQT_SLOT(slotSpellcheck2(KSpell*))/*, mSpellConfig*/ );
// }
TQStringList l = KSpellingHighlighter::personalWords();
for ( TQStringList::Iterator it = l.begin(); it != l.end(); ++it ) {
- mKSpell->addPersonal( *it );
+ mKSpellForDialog->addPersonal( *it );
}
- connect (mKSpell, TQT_SIGNAL( death()),
+ connect (mKSpellForDialog, TQT_SIGNAL( death()),
this, TQT_SLOT (slotSpellDone()));
- connect (mKSpell, TQT_SIGNAL (misspelling (const TQString &, const TQStringList &, unsigned int)),
+ connect (mKSpellForDialog, TQT_SIGNAL (misspelling (const TQString &, const TQStringList &, unsigned int)),
this, TQT_SLOT (slotMisspelling (const TQString &, const TQStringList &, unsigned int)));
- connect (mKSpell, TQT_SIGNAL (corrected (const TQString &, const TQString &, unsigned int)),
+ connect (mKSpellForDialog, TQT_SIGNAL (corrected (const TQString &, const TQString &, unsigned int)),
this, TQT_SLOT (slotCorrected (const TQString &, const TQString &, unsigned int)));
- connect (mKSpell, TQT_SIGNAL (done(const TQString &)),
+ connect (mKSpellForDialog, TQT_SIGNAL (done(const TQString &)),
this, TQT_SLOT (slotSpellResult (const TQString&)));
}
void KMEdit::cut()
{
KEdit::cut();
- if ( textFormat() != Qt::RichText && mSpellChecker )
- mSpellChecker->restartBackgroundSpellCheck();
+ if ( textFormat() != Qt::RichText && mHighlighter )
+ mHighlighter->restartBackgroundSpellCheck();
}
void KMEdit::clear()
{
KEdit::clear();
- if ( textFormat() != Qt::RichText && mSpellChecker )
- mSpellChecker->restartBackgroundSpellCheck();
+ if ( textFormat() != Qt::RichText && mHighlighter )
+ mHighlighter->restartBackgroundSpellCheck();
}
void KMEdit::del()
{
KEdit::del();
- if ( textFormat() != Qt::RichText && mSpellChecker )
- mSpellChecker->restartBackgroundSpellCheck();
+ if ( textFormat() != Qt::RichText && mHighlighter )
+ mHighlighter->restartBackgroundSpellCheck();
}
void KMEdit::paste()
@@ -620,6 +716,54 @@ void KMEdit::contentsMouseReleaseEvent( TQMouseEvent * e )
mPasteMode = QClipboard::Clipboard;
}
+void KMEdit::contentsMouseDoubleClickEvent( TQMouseEvent *e )
+{
+ bool handled = false;
+ if ( e->button() == TQt::LeftButton ) {
+
+ // Get the cursor position for the place where the user clicked to
+ int paragraphPos;
+ int charPos = charAt ( e->pos(), &paragraphPos );
+ TQString paraText = text( paragraphPos );
+
+ // Now select the word under the cursor
+ if ( charPos >= 0 && static_cast<unsigned int>( charPos ) <= paraText.length() ) {
+
+ // Start the selection where the user clicked
+ int start = charPos;
+ unsigned int end = charPos;
+
+ // Extend the selection to the left, until we reach a non-letter and non-digit char
+ for (;;) {
+ if ( ( start - 1 ) < 0 )
+ break;
+ TQChar charToTheLeft = paraText.at( start - 1 );
+ if ( charToTheLeft.isLetter() || charToTheLeft.isDigit() )
+ start--;
+ else
+ break;
+ }
+
+ // Extend the selection to the left, until we reach a non-letter and non-digit char
+ for (;;) {
+ if ( ( end + 1 ) >= paraText.length() )
+ break;
+ TQChar charToTheRight = paraText.at( end + 1 );
+ if ( charToTheRight.isLetter() || charToTheRight.isDigit() )
+ end++;
+ else
+ break;
+ }
+
+ setSelection( paragraphPos, start, paragraphPos, end + 1 );
+ handled = true;
+ }
+ }
+
+ if ( !handled )
+ return KEdit::contentsMouseDoubleClickEvent( e );
+}
+
void KMEdit::slotMisspelling(const TQString &text, const TQStringList &lst, unsigned int pos)
{
kdDebug(5006)<<"void KMEdit::slotMisspelling(const TQString &text, const TQStringList &lst, unsigned int pos) : "<<text <<endl;
@@ -660,6 +804,12 @@ void KMEdit::slotCorrected (const TQString &oldWord, const TQString &newWord, un
void KMEdit::slotSpellcheck2(KSpell*)
{
+ // Make sure words ignored by the highlighter are ignored by KSpell as well
+ if ( mHighlighter ) {
+ for ( uint i = 0; i < mHighlighter->ignoredWords().size(); i++ )
+ mKSpellForDialog->ignore( mHighlighter->ignoredWords()[i] );
+ }
+
if( !mSpellLineEdit)
{
spellcheck_start();
@@ -682,10 +832,10 @@ void KMEdit::slotSpellcheck2(KSpell*)
mSpellingFilter = new SpellingFilter(plaintext.text(), quotePrefix, SpellingFilter::FilterUrls,
SpellingFilter::FilterEmailAddresses);
- mKSpell->check(mSpellingFilter->filteredText());
+ mKSpellForDialog->check(mSpellingFilter->filteredText());
}
else if( mComposer )
- mKSpell->check( mComposer->sujectLineWidget()->text());
+ mKSpellForDialog->check( mComposer->sujectLineWidget()->text());
}
void KMEdit::slotSpellResult(const TQString &s)
@@ -693,7 +843,7 @@ void KMEdit::slotSpellResult(const TQString &s)
if( !mSpellLineEdit)
spellcheck_stop();
- int dlgResult = mKSpell->dlgResult();
+ int dlgResult = mKSpellForDialog->dlgResult();
if ( dlgResult == KS_CANCEL )
{
if( mSpellLineEdit)
@@ -711,7 +861,7 @@ void KMEdit::slotSpellResult(const TQString &s)
setModified(true);
}
}
- mKSpell->cleanUp();
+ mKSpellForDialog->cleanUp();
KDictSpellingHighlighter::dictionaryChanged();
emit spellcheck_done( dlgResult );
@@ -720,9 +870,9 @@ void KMEdit::slotSpellResult(const TQString &s)
void KMEdit::slotSpellDone()
{
kdDebug(5006)<<" void KMEdit::slotSpellDone()\n";
- KSpell::spellStatus status = mKSpell->status();
- delete mKSpell;
- mKSpell = 0;
+ KSpell::spellStatus status = mKSpellForDialog->status();
+ delete mKSpellForDialog;
+ mKSpellForDialog = 0;
kdDebug(5006) << "spelling: delete SpellingFilter" << endl;
delete mSpellingFilter;
@@ -763,4 +913,20 @@ void KMEdit::setCursorPositionFromStart( unsigned int pos ) {
ensureCursorVisible();
}
+int KMEdit::indexOfCurrentLineStart( int paragraph, int index )
+{
+ Q_ASSERT( paragraph >= 0 && paragraph < paragraphs() );
+ Q_ASSERT( index >= 0 && ( index == 0 || index < paragraphLength( paragraph ) ) );
+
+ const int startLine = lineOfChar( paragraph, index );
+ Q_ASSERT( startLine >= 0 && startLine < linesOfParagraph( paragraph ) );
+ for ( int curIndex = index; curIndex >= 0; curIndex-- ) {
+ const int line = lineOfChar( paragraph, curIndex );
+ if ( line != startLine ) {
+ return curIndex + 1;
+ }
+ }
+ return 0;
+}
+
#include "kmedit.moc"
diff --git a/kmail/kmedit.h b/kmail/kmedit.h
index b8419cda8..855c29ead 100644
--- a/kmail/kmedit.h
+++ b/kmail/kmedit.h
@@ -7,20 +7,61 @@
#include <kdeversion.h>
#include <keditcl.h>
+#include <kspell.h>
+#include <ksyntaxhighlighter.h>
#include <tqmap.h>
#include <tqstringlist.h>
#include <tqclipboard.h>
class KMComposeWin;
class KSpellConfig;
-class KSpell;
class SpellingFilter;
class KTempFile;
-class KDictSpellingHighlighter;
class KDirWatch;
class KProcess;
class TQPopupMenu;
+/**
+ * Reimplemented to make writePersonalDictionary() public, which we call everytime after
+ * adding a word to the dictionary (for safety's sake and because the highlighter needs to reload
+ * the personal word list, and for that, it needs to be written to disc)
+ */
+class KMSpell : public KSpell
+{
+ public:
+
+ KMSpell( TQObject *receiver, const char *slot, KSpellConfig *spellConfig );
+ using KSpell::writePersonalDictionary;
+};
+
+/**
+ * Reimplemented to add support for ignored words
+ */
+class KMSyntaxHighter : public KDictSpellingHighlighter
+{
+ public:
+
+ KMSyntaxHighter( TQTextEdit *textEdit,
+ bool spellCheckingActive = true,
+ bool autoEnable = true,
+ const TQColor& spellColor = red,
+ bool colorQuoting = false,
+ const TQColor& QuoteColor0 = black,
+ const TQColor& QuoteColor1 = TQColor( 0x00, 0x80, 0x00 ),
+ const TQColor& QuoteColor2 = TQColor( 0x00, 0x70, 0x00 ),
+ const TQColor& QuoteColor3 = TQColor( 0x00, 0x60, 0x00 ),
+ KSpellConfig *spellConfig = 0 );
+
+ /** Reimplemented */
+ virtual bool isMisspelled( const TQString &word );
+
+ void ignoreWord( const TQString &word );
+
+ TQStringList ignoredWords() const;
+
+ private:
+ TQStringList mIgnoredWords;
+};
class KMEdit : public KEdit {
Q_OBJECT
@@ -74,12 +115,15 @@ public:
/** set cursor to absolute position pos */
void setCursorPositionFromStart(unsigned int pos);
+ int indexOfCurrentLineStart( int paragraph, int index );
+
signals:
void spellcheck_done(int result);
void attachPNGImageData(const TQByteArray &image);
void pasteImage();
void focusUp();
void focusChanged( bool );
+ void selectionAvailable( bool );
void insertSnippet();
public slots:
void initializeAutoSpellChecking();
@@ -100,11 +144,29 @@ protected:
*/
bool eventFilter(TQObject*, TQEvent*);
void keyPressEvent( TQKeyEvent* );
-
+
void contentsMouseReleaseEvent( TQMouseEvent * e );
+ /// Reimplemented to select words under the cursor on double-clicks in our way,
+ /// not the broken TQt way (https://issues.kolab.org/issue4089)
+ virtual void contentsMouseDoubleClickEvent( TQMouseEvent *e );
+
private slots:
void slotExternalEditorTempFileChanged( const TQString & fileName );
+ void slotSelectionChanged() {
+ // use !text.isEmpty() here, as null-selections exist, but make no sense
+ emit selectionAvailable( !selectedText().isEmpty() );
+ }
+
+ /// Called when mSpeller is ready to rumble. Does nothing, but KSpell requires a slot as otherwise
+ /// it will show a dialog itself, which we want to avoid.
+ void spellerReady( KSpell *speller );
+
+ /// Called when mSpeller died for some reason.
+ void spellerDied();
+
+ /// Re-creates the spellers, called when the dictionary is changed
+ void createSpellers();
private:
void killExternalEditor();
@@ -112,7 +174,14 @@ private:
private:
KMComposeWin* mComposer;
- KSpell *mKSpell;
+ // This is the speller used for the spellcheck dialog. It is only active as long as the spellcheck
+ // dialog is shown
+ KSpell *mKSpellForDialog;
+
+ // This is the speller used when right-clicking a word and choosing "add to dictionary". It lives
+ // as long as the composer lives.
+ KMSpell *mSpeller;
+
KSpellConfig *mSpellConfig;
TQMap<TQString,TQStringList> mReplacements;
SpellingFilter* mSpellingFilter;
@@ -122,7 +191,7 @@ private:
bool mUseExtEditor;
TQString mExtEditor;
bool mWasModifiedBeforeSpellCheck;
- KDictSpellingHighlighter *mSpellChecker;
+ KMSyntaxHighter *mHighlighter;
bool mSpellLineEdit;
QClipboard::Mode mPasteMode;
};
diff --git a/kmail/kmfawidgets.cpp b/kmail/kmfawidgets.cpp
index f5426f255..370d796cb 100644
--- a/kmail/kmfawidgets.cpp
+++ b/kmail/kmfawidgets.cpp
@@ -17,6 +17,7 @@
#include <kstandarddirs.h>
#include <tqlayout.h>
+#include <tqtooltip.h>
//=============================================================================
//
@@ -30,14 +31,18 @@ KMFilterActionWithAddressWidget::KMFilterActionWithAddressWidget( TQWidget* pare
TQHBoxLayout *hbl = new TQHBoxLayout(this);
hbl->setSpacing(4);
mLineEdit = new KLineEdit(this);
+ mLineEdit->setName( "addressEdit" );
hbl->addWidget( mLineEdit, 1 /*stretch*/ );
mBtn = new TQPushButton( TQString::null ,this );
mBtn->setPixmap( BarIcon( "contents", KIcon::SizeSmall ) );
mBtn->setFixedHeight( mLineEdit->sizeHint().height() );
+ TQToolTip::add( mBtn, i18n( "Open Address Book" ) );
hbl->addWidget( mBtn );
connect( mBtn, TQT_SIGNAL(clicked()),
- this, TQT_SLOT(slotAddrBook()) );
+ this, TQT_SLOT(slotAddrBook()) );
+ connect( mLineEdit, TQT_SIGNAL( textChanged(const TQString&) ),
+ this, TQT_SIGNAL( textChanged(const TQString&) ) );
}
void KMFilterActionWithAddressWidget::slotAddrBook()
diff --git a/kmail/kmfawidgets.h b/kmail/kmfawidgets.h
index 716cd2aae..5a6990a8b 100644
--- a/kmail/kmfawidgets.h
+++ b/kmail/kmfawidgets.h
@@ -25,6 +25,10 @@ public:
TQString text() const { return mLineEdit->text(); }
void setText( const TQString & aString ) { mLineEdit->setText( aString ); }
+signals:
+ // Forwarded from the internal text edit
+ void textChanged(const TQString&);
+
protected slots:
void slotAddrBook();
diff --git a/kmail/kmfilteraction.cpp b/kmail/kmfilteraction.cpp
index 9fce0565b..9b277d8e7 100644
--- a/kmail/kmfilteraction.cpp
+++ b/kmail/kmfilteraction.cpp
@@ -9,6 +9,8 @@
#include "kmfilteraction.h"
+#include "customtemplates.h"
+#include "customtemplates_kfg.h"
#include "kmcommands.h"
#include "kmmsgpart.h"
#include "kmfiltermgr.h"
@@ -27,7 +29,6 @@ using KPIM::CollectingProcess;
#include "folderrequester.h"
using KMail::FolderRequester;
#include "kmmsgbase.h"
-#include "templateparser.h"
#include "messageproperty.h"
#include "actionscheduler.h"
using KMail::MessageProperty;
@@ -48,6 +49,8 @@ using KMail::RegExpLineEdit;
#include <tqtimer.h>
#include <tqobject.h>
#include <tqstylesheet.h>
+#include <tqtooltip.h>
+#include <tqwhatsthis.h>
#include <assert.h>
@@ -1433,14 +1436,26 @@ bool KMFilterActionCopy::requiresBody(KMMsgBase*) const
//=============================================================================
// KMFilterActionForward - forward to
-// Forward message to another user
+// Forward message to another user, with a defined template
//=============================================================================
class KMFilterActionForward: public KMFilterActionWithAddress
{
public:
KMFilterActionForward();
- virtual ReturnCode process(KMMessage* msg) const;
+ virtual ReturnCode process( KMMessage* msg ) const;
+ virtual TQWidget* createParamWidget( TQWidget* parent ) const;
+ virtual void applyParamWidgetValue( TQWidget* paramWidget );
+ virtual void setParamWidgetValue( TQWidget* paramWidget ) const;
+ virtual void clearParamWidget( TQWidget* paramWidget ) const;
+ virtual void argsFromString( const TQString argsStr );
+ virtual const TQString argsAsString() const;
+ virtual const TQString displayString() const;
+
static KMFilterAction* newAction(void);
+
+private:
+
+ mutable TQString mTemplate;
};
KMFilterAction* KMFilterActionForward::newAction(void)
@@ -1460,89 +1475,152 @@ KMFilterAction::ReturnCode KMFilterActionForward::process(KMMessage* aMsg) const
// avoid endless loops when this action is used in a filter
// which applies to sent messages
- if ( KMMessage::addressIsInAddressList( mParameter, aMsg->to() ) )
+ if ( KMMessage::addressIsInAddressList( mParameter, aMsg->to() ) ) {
+ kdWarning(5006) << "Attempt to forward to receipient of original message, ignoring." << endl;
return ErrorButGoOn;
+ }
+
+ KMMessage *fwdMsg = aMsg->createForward( mTemplate );
+ fwdMsg->setTo( fwdMsg->to() + ',' + mParameter );
+
+ if ( !kmkernel->msgSender()->send( fwdMsg, KMail::MessageSender::SendDefault ) ) {
+ kdWarning(5006) << "KMFilterAction: could not forward message (sending failed)" << endl;
+ return ErrorButGoOn; // error: couldn't send
+ }
+ else
+ sendMDN( aMsg, KMime::MDN::Dispatched );
- // Create the forwarded message by hand to make forwarding of messages with
- // attachments work.
- // Note: This duplicates a lot of code from KMMessage::createForward() and
- // KMComposeWin::applyChanges().
- // ### FIXME: Remove the code duplication again.
+ // (the msgSender takes ownership of the message, so don't delete it here)
- KMMessage* msg = new KMMessage;
+ return GoOn;
+}
- msg->initFromMessage( aMsg );
+TQWidget* KMFilterActionForward::createParamWidget( TQWidget* parent ) const
+{
+ TQWidget *addressAndTemplate = new TQWidget( parent );
+ TQHBoxLayout *hBox = new TQHBoxLayout( addressAndTemplate );
+ TQWidget *addressEdit = KMFilterActionWithAddress::createParamWidget( addressAndTemplate );
+ addressEdit->setName( "addressEdit" );
+ hBox->addWidget( addressEdit );
- // TQString st = TQString::fromUtf8( aMsg->createForwardBody() );
+ KLineEdit *lineEdit = dynamic_cast<KLineEdit*>( addressEdit->child( "addressEdit" ) );
+ Q_ASSERT( lineEdit );
+ TQToolTip::add( lineEdit, i18n( "The addressee the message will be forwarded to" ) );
+ TQWhatsThis::add( lineEdit, i18n( "The filter will forward the message to the addressee entered here." ) );
- TemplateParser parser( msg, TemplateParser::Forward,
- aMsg->body(), false, false, false, false);
- parser.process( aMsg );
+ TQComboBox *templateCombo = new TQComboBox( addressAndTemplate );
+ templateCombo->setName( "templateCombo" );
+ hBox->addWidget( templateCombo );
- QCString
- encoding = KMMsgBase::autoDetectCharset( aMsg->charset(),
- KMMessage::preferredCharsets(),
- msg->body() );
- if( encoding.isEmpty() )
- encoding = "utf-8";
- TQCString str = KMMsgBase::codecForName( encoding )->fromUnicode( msg->body() );
+ templateCombo->insertItem( i18n( "Default Template" ) );
+ TQStringList templateNames = GlobalSettingsBase::self()->customTemplates();
+ for ( TQStringList::const_iterator it = templateNames.begin(); it != templateNames.end();
+ it++ ) {
+ CTemplates templat( *it );
+ if ( templat.type() == CustomTemplates::TForward ||
+ templat.type() == CustomTemplates::TUniversal )
+ templateCombo->insertItem( *it );
+ }
+ templateCombo->setEnabled( templateCombo->count() > 1 );
+ TQToolTip::add( templateCombo, i18n( "The template used when forwarding" ) );
+ TQWhatsThis::add( templateCombo, i18n( "Set the forwarding template that will be used with this filter." ) );
- msg->setCharset( encoding );
- msg->setTo( mParameter );
- msg->setSubject( "Fwd: " + aMsg->subject() );
+ return addressAndTemplate;
+}
- bool isQP = kmkernel->msgSender()->sendQuotedPrintable();
+void KMFilterActionForward::applyParamWidgetValue( TQWidget* paramWidget )
+{
+ // Use findChildren<T> when porting to KDE 4
+ TQWidget *addressEdit = dynamic_cast<TQWidget*>( paramWidget->child( "addressEdit" ) );
+ Q_ASSERT( addressEdit );
+ KMFilterActionWithAddress::applyParamWidgetValue( addressEdit );
- if( aMsg->numBodyParts() == 0 )
- {
- msg->setAutomaticFields( true );
- msg->setHeaderField( "Content-Type", "text/plain" );
- // msg->setCteStr( isQP ? "quoted-printable": "8bit" );
- TQValueList<int> dummy;
- msg->setBodyAndGuessCte(str, dummy, !isQP);
- msg->setCharset( encoding );
- if( isQP )
- msg->setBodyEncoded( str );
- else
- msg->setBody( str );
+ TQComboBox *templateCombo = dynamic_cast<TQComboBox*>( paramWidget->child( "templateCombo" ) );
+ Q_ASSERT( templateCombo );
+
+ if ( templateCombo->currentItem() == 0 ) {
+ // Default template, so don't use a custom one
+ mTemplate = TQString::null;
}
- else
- {
- KMMessagePart bodyPart, msgPart;
-
- msg->removeHeaderField( "Content-Type" );
- msg->removeHeaderField( "Content-Transfer-Encoding" );
- msg->setAutomaticFields( true );
- msg->setBody( "This message is in MIME format.\n\n" );
-
- bodyPart.setTypeStr( "text" );
- bodyPart.setSubtypeStr( "plain" );
- // bodyPart.setCteStr( isQP ? "quoted-printable": "8bit" );
- TQValueList<int> dummy;
- bodyPart.setBodyAndGuessCte(str, dummy, !isQP);
- bodyPart.setCharset( encoding );
- bodyPart.setBodyEncoded( str );
- msg->addBodyPart( &bodyPart );
-
- for( int i = 0; i < aMsg->numBodyParts(); i++ )
- {
- aMsg->bodyPart( i, &msgPart );
- if( i > 0 || qstricmp( msgPart.typeStr(), "text" ) != 0 )
- msg->addBodyPart( &msgPart );
+ else {
+ mTemplate = templateCombo->currentText();
+ }
+}
+
+void KMFilterActionForward::setParamWidgetValue( TQWidget* paramWidget ) const
+{
+ TQWidget *addressEdit = dynamic_cast<TQWidget*>( paramWidget->child( "addressEdit" ) );
+ Q_ASSERT( addressEdit );
+ KMFilterActionWithAddress::setParamWidgetValue( addressEdit );
+
+ TQComboBox *templateCombo = dynamic_cast<TQComboBox*>( paramWidget->child( "templateCombo" ) );
+ Q_ASSERT( templateCombo );
+
+ if ( mTemplate.isEmpty() ) {
+ templateCombo->setCurrentItem( 0 );
+ }
+ else {
+ // WTF: TQt3's combobox has no indexOf? Search it manually, then.
+ int templateIndex = -1;
+ for ( int i = 1; i < templateCombo->count(); i++ ) {
+ if ( templateCombo->text( i ) == mTemplate ) {
+ templateIndex = i;
+ break;
+ }
+ }
+
+ if ( templateIndex != -1 ) {
+ templateCombo->setCurrentItem( templateIndex );
+ }
+ else {
+ mTemplate = TQString::null;
}
}
- msg->cleanupHeader();
- msg->link( aMsg, KMMsgStatusForwarded );
+}
- sendMDN( aMsg, KMime::MDN::Dispatched );
+void KMFilterActionForward::clearParamWidget( TQWidget* paramWidget ) const
+{
+ TQWidget *addressEdit = dynamic_cast<TQWidget*>( paramWidget->child( "addressEdit" ) );
+ Q_ASSERT( addressEdit );
+ KMFilterActionWithAddress::clearParamWidget( addressEdit );
- if ( !kmkernel->msgSender()->send( msg, KMail::MessageSender::SendLater ) ) {
- kdDebug(5006) << "KMFilterAction: could not forward message (sending failed)" << endl;
- return ErrorButGoOn; // error: couldn't send
+ TQComboBox *templateCombo = dynamic_cast<TQComboBox*>( paramWidget->child( "templateCombo" ) );
+ Q_ASSERT( templateCombo );
+
+ templateCombo->setCurrentItem( 0 );
+}
+
+// We simply place a "@$$@" between the two parameters. The template is the last
+// parameter in the string, for compatibility reasons.
+static const TQString forwardFilterArgsSeperator = "@$$@";
+
+void KMFilterActionForward::argsFromString( const TQString argsStr )
+{
+ int seperatorPos = argsStr.find( forwardFilterArgsSeperator );
+
+ if ( seperatorPos == - 1 ) {
+ // Old config, assume that the whole string is the addressee
+ KMFilterActionWithAddress::argsFromString( argsStr );
}
- return GoOn;
+ else {
+ TQString addressee = argsStr.left( seperatorPos );
+ mTemplate = argsStr.mid( seperatorPos + forwardFilterArgsSeperator.length() );
+ KMFilterActionWithAddress::argsFromString( addressee );
+ }
+}
+
+const TQString KMFilterActionForward::argsAsString() const
+{
+ return KMFilterActionWithAddress::argsAsString() + forwardFilterArgsSeperator + mTemplate;
}
+const TQString KMFilterActionForward::displayString() const
+{
+ if ( mTemplate.isEmpty() )
+ return i18n( "Forward to %1 with default template " ).arg( mParameter );
+ else
+ return i18n( "Forward to %1 with template %2" ).arg( mParameter, mTemplate );
+}
//=============================================================================
// KMFilterActionRedirect - redirect to
diff --git a/kmail/kmfilterdlg.cpp b/kmail/kmfilterdlg.cpp
index c5589c943..558031f05 100644
--- a/kmail/kmfilterdlg.cpp
+++ b/kmail/kmfilterdlg.cpp
@@ -15,6 +15,8 @@
using KMail::AccountManager;
#include "filterimporterexporter.h"
using KMail::FilterImporterExporter;
+#include "foldersetselector.h"
+#include "globalsettings.h"
// other KDE headers:
#include <kmessagebox.h>
@@ -45,6 +47,8 @@ using KMail::FilterImporterExporter;
// other headers:
#include <assert.h>
+using namespace KMail;
+
// What's this help texts
const char * _wt_filterlist =
@@ -634,6 +638,14 @@ KMFilterListBox::KMFilterListBox( const TQString & title, TQWidget *parent, cons
TQWhatsThis::add( mBtnDelete, i18n(_wt_filterlist_delete) );
TQWhatsThis::add( mBtnRename, i18n(_wt_filterlist_rename) );
+ // third row
+ if ( !popFilter ) {
+ hb = new TQHBox( this );
+ hb->setSpacing( 4 );
+ TQPushButton *btn = new TQPushButton( i18n("Select Source Folders"), hb );
+ connect( btn, TQT_SIGNAL(clicked()), TQT_SLOT(slotSelectSourceFolders()) );
+ }
+
//----------- now connect everything
connect( mListBox, TQT_SIGNAL(highlighted(int)),
@@ -699,7 +711,7 @@ void KMFilterListBox::slotUpdateFilterName()
if ( mFilterList.at(mIdxSelItem)->isAutoNaming() ) {
// auto-naming of patterns
- if ( p->first() && !p->first()->field().stripWhiteSpace().isEmpty() )
+ if ( !p->isEmpty() && p->first() && !p->first()->field().stripWhiteSpace().isEmpty() )
shouldBeName = TQString( "<%1>: %2" ).arg( p->first()->field() ).arg( p->first()->contents() );
else
shouldBeName = "<" + i18n("unnamed") + ">";
@@ -955,6 +967,17 @@ void KMFilterListBox::slotRename()
slotUpdateFilterName();
}
+void KMFilterListBox::slotSelectSourceFolders()
+{
+ FolderSetSelector dlg( kmkernel->getKMMainWidget()->folderTree(), this );
+ dlg.setCaption( i18n( "Select Folders to Filter" ) );
+ if ( !GlobalSettings::filterSourceFolders().isEmpty() )
+ dlg.setSelectedFolders( GlobalSettings::filterSourceFolders() );
+ if ( dlg.exec() == TQDialog::Accepted ) {
+ GlobalSettings::setFilterSourceFolders( dlg.selectedFolders() );
+ }
+}
+
void KMFilterListBox::enableControls()
{
bool theFirst = ( mIdxSelItem == 0 );
diff --git a/kmail/kmfilterdlg.h b/kmail/kmfilterdlg.h
index 1ab185cab..18da9b568 100644
--- a/kmail/kmfilterdlg.h
+++ b/kmail/kmfilterdlg.h
@@ -149,6 +149,8 @@ protected slots:
dialog prompting to enter the new name. */
void slotRename();
+ void slotSelectSourceFolders();
+
protected:
/** The deep copy of the filter list. */
TQPtrList<KMFilter> mFilterList;
diff --git a/kmail/kmfiltermgr.cpp b/kmail/kmfiltermgr.cpp
index 13e5e0f1e..beb3e60a5 100644
--- a/kmail/kmfiltermgr.cpp
+++ b/kmail/kmfiltermgr.cpp
@@ -42,8 +42,6 @@ KMFilterMgr::KMFilterMgr( bool popFilter )
mBufferedFolderTarget( true ),
mRefCount( 0 )
{
- if (bPopFilter)
- kdDebug(5006) << "pPopFilter set" << endl;
connect( kmkernel, TQT_SIGNAL( folderRemoved( KMFolder* ) ),
this, TQT_SLOT( slotFolderRemoved( KMFolder* ) ) );
}
diff --git a/kmail/kmfolder.cpp b/kmail/kmfolder.cpp
index cae870710..68fb52f04 100644
--- a/kmail/kmfolder.cpp
+++ b/kmail/kmfolder.cpp
@@ -124,6 +124,10 @@ KMFolder::KMFolder( KMFolderDir* aParent, const TQString& aFolderName,
TQT_SIGNAL( numUnreadMsgsChanged( KMFolder* ) ) );
connect( mStorage, TQT_SIGNAL( removed( KMFolder*, bool ) ),
TQT_SIGNAL( removed( KMFolder*, bool ) ) );
+ connect( mStorage, TQT_SIGNAL(noContentChanged()),
+ TQT_SIGNAL(noContentChanged()) );
+ connect( mStorage, TQT_SIGNAL(syncStateChanged()),
+ TQT_SIGNAL(syncStateChanged()) );
connect( mStorage, TQT_SIGNAL( contentsTypeChanged( KMail::FolderContentsType ) ),
this, TQT_SLOT( slotContentsTypeChanged( KMail::FolderContentsType ) ) );
@@ -559,6 +563,21 @@ bool KMFolder::isReadOnly() const
return mStorage->isReadOnly();
}
+bool KMFolder::mailCheckInProgress() const
+{
+ return mStorage->mailCheckInProgress();
+}
+
+bool KMFolder::isWritable() const
+{
+ return !mStorage->isReadOnly() && mStorage->canDeleteMessages();
+}
+
+bool KMFolder::canDeleteMessages() const
+{
+ return mStorage->canDeleteMessages();
+}
+
TQString KMFolder::label() const
{
if ( !mSystemLabel.isEmpty() )
@@ -877,5 +896,44 @@ void KMFolder::slotFolderSizeChanged()
}
}
+bool KMFolder::isValidName( const TQString &folderName, TQString &message )
+{
+ KMFolderType fldType = folderType();
+
+ // names of local folders must not contain a '/'
+ if ( folderName.find( '/' ) != -1 &&
+ fldType != KMFolderTypeImap &&
+ fldType != KMFolderTypeCachedImap ) {
+ message = i18n( "Folder names cannot contain the / (slash) character; please choose another folder name." );
+ return false;
+ }
+
+ // folder names must not start with a '.'
+ if ( folderName.startsWith( "." ) ) {
+ message = i18n( "Folder names cannot start with a . (dot) character; please choose another folder name." );
+ return false;
+ }
+
+ // names of IMAP folders must not contain the folder delimiter
+ if ( fldType == KMFolderTypeImap || fldType == KMFolderTypeCachedImap ) {
+ TQString delimiter;
+ if ( fldType == KMFolderTypeImap ) {
+ KMAcctImap *ai = static_cast<KMFolderImap*>( mStorage )->account();
+ if ( ai ) {
+ delimiter = ai->delimiterForFolder( mStorage );
+ }
+ } else {
+ KMAcctCachedImap *ai = static_cast<KMFolderCachedImap*>( mStorage )->account();
+ if ( ai ) {
+ delimiter = ai->delimiterForFolder( mStorage );
+ }
+ }
+ if ( !delimiter.isEmpty() && folderName.find( delimiter ) != -1 ) {
+ message = i18n( "Your IMAP server does not allow the character '%1'; please choose another folder name." ).arg( delimiter );
+ return false;
+ }
+ }
+ return true;
+}
#include "kmfolder.moc"
diff --git a/kmail/kmfolder.h b/kmail/kmfolder.h
index 32518cd75..3ff1d67de 100644
--- a/kmail/kmfolder.h
+++ b/kmail/kmfolder.h
@@ -353,6 +353,13 @@ public:
/** Is the folder read-only? */
bool isReadOnly() const;
+ /** Can we write into and delete from this folder (on IMAP that's not necessarily !isReadOnly()) */
+ bool isWritable() const;
+
+ bool mailCheckInProgress() const;
+
+ /** Can messages in this folder be deleted? */
+ bool canDeleteMessages() const;
/** Returns true if the folder is a kmail system folder. These are
the folders 'inbox', 'outbox', 'sent', 'trash', 'drafts', 'templates'.
@@ -532,6 +539,13 @@ public:
/** Sets the move-in-progress flag. */
void setMoveInProgress( bool b ) { mMoveInProgress = b; }
+ /**
+ * Returns true if the name is valid for a child of this folder.
+ * If the name contains invalid characters then false is returned and message will contain
+ * an explanation that can be presented to the user.
+ */
+ bool isValidName( const TQString &folderName, TQString &message );
+
signals:
/** Emitted when the status, name, or associated accounts of this
folder changed. */
@@ -590,6 +604,15 @@ signals:
/** Emitted when the folder's size changes. */
void folderSizeChanged( KMFolder * );
+ /** Emitted when the no content state changed. */
+ void noContentChanged();
+
+ /**
+ * Emiitted when the sync state, i.e. mailCheckInProgress(), changes.
+ * Currently only supported for disconnected IMAP.
+ */
+ void syncStateChanged();
+
public slots:
/** Incrementally update the index if possible else call writeIndex */
int updateIndex();
diff --git a/kmail/kmfoldercachedimap.cpp b/kmail/kmfoldercachedimap.cpp
index 05f01b778..a1c71726b 100644
--- a/kmail/kmfoldercachedimap.cpp
+++ b/kmail/kmfoldercachedimap.cpp
@@ -129,11 +129,11 @@ DImapTroubleShootDialog::DImapTroubleShootDialog( TQWidget* parent,
"and all its subfolders.</p>" );
topLayout->addWidget( new TQLabel( txt, page ) );
- TQButtonGroup *group = new TQButtonGroup( 0 );
+ mButtonGroup = new TQButtonGroup( 0 );
mIndexButton = new TQRadioButton( page );
mIndexButton->setText( i18n( "Rebuild &Index" ) );
- group->insert( mIndexButton );
+ mButtonGroup->insert( mIndexButton );
topLayout->addWidget( mIndexButton );
TQHBox *hbox = new TQHBox( page );
@@ -148,15 +148,16 @@ DImapTroubleShootDialog::DImapTroubleShootDialog( TQWidget* parent,
mCacheButton = new TQRadioButton( page );
mCacheButton->setText( i18n( "Refresh &Cache" ) );
- group->insert( mCacheButton );
+ mButtonGroup->insert( mCacheButton );
topLayout->addWidget( mCacheButton );
enableButtonSeparator( true );
connect ( mIndexButton, TQT_SIGNAL(toggled(bool)), mIndexScope, TQT_SLOT(setEnabled(bool)) );
connect ( mIndexButton, TQT_SIGNAL(toggled(bool)), scopeLabel, TQT_SLOT(setEnabled(bool)) );
-
+ connect( mButtonGroup, TQT_SIGNAL( clicked( int ) ), TQT_SLOT( slotChanged() ) );
connect( this, TQT_SIGNAL( okClicked () ), this, TQT_SLOT( slotDone() ) );
+ enableButtonOK( false );
}
int DImapTroubleShootDialog::run()
@@ -166,6 +167,11 @@ int DImapTroubleShootDialog::run()
return d.rc;
}
+void DImapTroubleShootDialog::slotChanged()
+{
+ enableButtonOK( mButtonGroup->selected() != 0 );
+}
+
void DImapTroubleShootDialog::slotDone()
{
rc = None;
@@ -181,17 +187,24 @@ KMFolderCachedImap::KMFolderCachedImap( KMFolder* folder, const char* aName )
mSyncState( SYNC_STATE_INITIAL ), mContentState( imapNoInformation ),
mSubfolderState( imapNoInformation ),
mIncidencesFor( IncForAdmins ),
+ mSharedSeenFlags( false ),
mIsSelected( false ),
mCheckFlags( true ), mReadOnly( false ), mAccount( NULL ), uidMapDirty( true ),
uidWriteTimer( -1 ), mLastUid( 0 ), mTentativeHighestUid( 0 ),
mFoundAnIMAPDigest( false ),
- mUserRights( 0 ), mOldUserRights( 0 ), mSilentUpload( false ),
+ mUserRights( 0 ), mOldUserRights( 0 ), mUserRightsState( KMail::ACLJobs::NotFetchedYet ),
+ mACLListState( KMail::ACLJobs::NotFetchedYet ),
+ mSilentUpload( false ),
/*mHoldSyncs( false ),*/
mFolderRemoved( false ),
mRecurse( true ),
- mStatusChangedLocally( false ), mAnnotationFolderTypeChanged( false ),
- mIncidencesForChanged( false ), mPersonalNamespacesCheckDone( true ),
- mQuotaInfo(), mAlarmsBlocked( false ),
+ mQuotaOnly( false ),
+ mAnnotationFolderTypeChanged( false ),
+ mIncidencesForChanged( false ),
+ mSharedSeenFlagsChanged( false ),
+ mStatusChangedLocally( false ),
+ mPersonalNamespacesCheckDone( true ),
+ mQuotaInfo(), mSomeSubFolderCloseToQuotaChanged( false ), mAlarmsBlocked( false ),
mRescueCommandCount( 0 ),
mPermanentFlags( 31 ) // assume standard flags by default (see imap4/imapinfo.h for bit fields values)
{
@@ -215,6 +228,7 @@ KMFolderCachedImap::KMFolderCachedImap( KMFolder* folder, const char* aName )
KMFolderCachedImap::~KMFolderCachedImap()
{
if (kmkernel->undoStack()) kmkernel->undoStack()->folderDestroyed( folder() );
+ writeConfig();
}
void KMFolderCachedImap::reallyDoClose( const char* owner )
@@ -231,7 +245,7 @@ void KMFolderCachedImap::initializeFrom( KMFolderCachedImap* parent )
// Now that we have an account, tell it that this folder was created:
// if this folder was just removed, then we don't really want to remove it from the server.
mAccount->removeDeletedFolder( imapPath() );
- setUserRights( parent->userRights() );
+ setUserRights( parent->userRights(), parent->userRightsState() );
}
void KMFolderCachedImap::readConfig()
@@ -262,8 +276,11 @@ void KMFolderCachedImap::readConfig()
mAlarmsBlocked = config->readBoolEntry( "AlarmsBlocked", false );
// kdDebug(5006) << ( mImapPath.isEmpty() ? label() : mImapPath )
// << " readConfig: mIncidencesFor=" << mIncidencesFor << endl;
+ mSharedSeenFlags = config->readBoolEntry( "SharedSeenFlags", false );
- mUserRights = config->readNumEntry( "UserRights", 0 ); // default is we don't know
+ mUserRights = config->readNumEntry( "UserRights", 0 );
+ mUserRightsState = static_cast<KMail::ACLJobs::ACLFetchState>(
+ config->readNumEntry( "UserRightsState", KMail::ACLJobs::NotFetchedYet ) );
mOldUserRights = mUserRights;
int storageQuotaUsage = config->readNumEntry( "StorageQuotaUsage", -1 );
@@ -283,19 +300,25 @@ void KMFolderCachedImap::readConfig()
mStatusChangedLocally =
config->readBoolEntry( "StatusChangedLocally", false );
+ TQStringList uidsChanged = config->readListEntry( "UIDStatusChangedLocally" );
+ for ( TQStringList::iterator it = uidsChanged.begin(); it != uidsChanged.end(); it++ ) {
+ mUIDsOfLocallyChangedStatuses.insert( ( *it ).toUInt() );
+ }
mAnnotationFolderTypeChanged = config->readBoolEntry( "AnnotationFolderTypeChanged", false );
mIncidencesForChanged = config->readBoolEntry( "IncidencesForChanged", false );
+ mSharedSeenFlagsChanged = config->readBoolEntry( "SharedSeenFlagsChanged", false );
+
if ( mImapPath.isEmpty() ) {
mImapPathCreation = config->readEntry("ImapPathCreation");
}
- TQStringList uids = config->readListEntry( "UIDSDeletedSinceLastSync" );
+ TQStringList delUids = config->readListEntry( "UIDSDeletedSinceLastSync" );
#if MAIL_LOSS_DEBUGGING
kdDebug( 5006 ) << "READING IN UIDSDeletedSinceLastSync: " << folder()->prettyURL() << endl << uids << endl;
#endif
- for ( TQStringList::iterator it = uids.begin(); it != uids.end(); it++ ) {
- mDeletedUIDsSinceLastSync.insert( (*it).toULong(), 0);
+ for ( TQStringList::iterator it = delUids.begin(); it != delUids.end(); it++ ) {
+ mDeletedUIDsSinceLastSync.insert( (*it).toULong(), 0);
}
}
@@ -311,7 +334,15 @@ void KMFolderCachedImap::writeConfig()
configGroup.writeEntry( "NoContent", mNoContent );
configGroup.writeEntry( "ReadOnly", mReadOnly );
configGroup.writeEntry( "FolderAttributes", mFolderAttributes );
- configGroup.writeEntry( "StatusChangedLocally", mStatusChangedLocally );
+
+ // StatusChangedLocally is always false, as we use UIDStatusChangedLocally now
+ configGroup.writeEntry( "StatusChangedLocally", false );
+ TQStringList uidsToWrite;
+ for( std::set<ulong>::iterator it = mUIDsOfLocallyChangedStatuses.begin();
+ it != mUIDsOfLocallyChangedStatuses.end(); it++ ) {
+ uidsToWrite.append( TQString::number( (*it) ) );
+ }
+ configGroup.writeEntry( "UIDStatusChangedLocally", uidsToWrite );
if ( !mImapPathCreation.isEmpty() ) {
if ( mImapPath.isEmpty() ) {
configGroup.writeEntry( "ImapPathCreation", mImapPathCreation );
@@ -346,7 +377,12 @@ void KMFolderCachedImap::writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig
configGroup.writeEntry( "IncidencesForChanged", mIncidencesForChanged );
configGroup.writeEntry( "IncidencesFor", incidencesForToString( mIncidencesFor ) );
configGroup.writeEntry( "AlarmsBlocked", mAlarmsBlocked );
- configGroup.writeEntry( "UserRights", mUserRights );
+ configGroup.writeEntry( "SharedSeenFlags", mSharedSeenFlags );
+ configGroup.writeEntry( "SharedSeenFlagsChanged", mSharedSeenFlagsChanged );
+ if ( mUserRightsState != KMail::ACLJobs::FetchFailed ) { // No point in overwriting valid results with invalid ones
+ configGroup.writeEntry( "UserRights", mUserRights );
+ configGroup.writeEntry( "UserRightsState", mUserRightsState );
+ }
configGroup.deleteEntry( "StorageQuotaUsage");
configGroup.deleteEntry( "StorageQuotaRoot");
@@ -503,11 +539,22 @@ int KMFolderCachedImap::addMsgInternal( KMMessage* msg, bool newMail,
// Add the message
rc = KMFolderMaildir::addMsg(msg, index_return);
- if( newMail && ( imapPath() == "/INBOX/" || ( !GlobalSettings::self()->filterOnlyDIMAPInbox()
- && (userRights() <= 0 || userRights() & ACLJobs::Administer )
+ if( newMail && ( imapPath() == "/INBOX/" ||
+ ( ( mUserRights != ACLJobs::Ok || userRights() & ACLJobs::Administer)
&& (contentsType() == ContentsTypeMail || GlobalSettings::self()->filterGroupwareFolders()) ) ) )
- // This is a new message. Filter it
- mAccount->processNewMsg( msg );
+ {
+ // This is a new message. Filter it - maybe
+ bool filter = false;
+ if ( GlobalSettings::filterSourceFolders().isEmpty() ) {
+ if ( imapPath() == "/INBOX/" )
+ filter = true;
+ } else {
+ if ( GlobalSettings::filterSourceFolders().contains( folder()->id() ) )
+ filter = true;
+ }
+ if ( filter )
+ mAccount->processNewMsg( msg );
+ }
return rc;
}
@@ -534,6 +581,9 @@ void KMFolderCachedImap::rememberDeletion( int idx )
/* Reimplemented from KMFolderMaildir */
void KMFolderCachedImap::removeMsg(int idx, bool imapQuiet)
{
+ if ( contentsType() != ContentsTypeMail ) {
+ kdDebug(5006) << k_funcinfo << "Deleting message with idx " << idx << " in folder " << label() << endl;
+ }
uidMapDirty = true;
rememberDeletion( idx );
// Remove it from disk
@@ -556,18 +606,20 @@ bool KMFolderCachedImap::canRemoveFolder() const {
int KMFolderCachedImap::rename( const TQString& aName,
KMFolderDir* /*aParent*/ )
{
+ if ( account() == 0 || imapPath().isEmpty() ) {
+ // This can happen when creating a folder and then renaming it without syncing before,
+ // see https://issues.kolab.org/issue3658
+ TQString err = i18n("You must synchronize with the server before renaming IMAP folders.");
+ KMessageBox::error( 0, err );
+ return -1;
+ }
+
TQString oldName = mAccount->renamedFolder( imapPath() );
if ( oldName.isEmpty() ) oldName = name();
if ( aName == oldName )
// Stupid user trying to rename it to it's old name :)
return 0;
- if( account() == 0 || imapPath().isEmpty() ) { // I don't think any of this can happen anymore
- TQString err = i18n("You must synchronize with the server before renaming IMAP folders.");
- KMessageBox::error( 0, err );
- return -1;
- }
-
// Make the change appear to the user with setLabel, but we'll do the change
// on the server during the next sync. The name() is the name at the time of
// the last sync. Only rename if the new one is different. If it's the same,
@@ -719,7 +771,7 @@ void KMFolderCachedImap::slotTroubleshoot()
}
}
-void KMFolderCachedImap::serverSync( bool recurse )
+void KMFolderCachedImap::serverSync( bool recurse, bool quotaOnly )
{
if( mSyncState != SYNC_STATE_INITIAL ) {
if( KMessageBox::warningYesNo( 0, i18n("Folder %1 is not in initial sync state (state was %2). Do you want to reset it to initial sync state and sync anyway?" ).arg( imapPath() ).arg( mSyncState ), TQString::null, i18n("Reset && Sync"), KStdGuiItem::cancel() ) == KMessageBox::Yes ) {
@@ -728,6 +780,7 @@ void KMFolderCachedImap::serverSync( bool recurse )
}
mRecurse = recurse;
+ mQuotaOnly = quotaOnly;
assert( account() );
ProgressItem *progressItem = mAccount->mailCheckProgressItem();
@@ -756,31 +809,33 @@ void KMFolderCachedImap::serverSync( bool recurse )
TQString KMFolderCachedImap::state2String( int state ) const
{
switch( state ) {
- case SYNC_STATE_INITIAL: return "SYNC_STATE_INITIAL";
- case SYNC_STATE_GET_USERRIGHTS: return "SYNC_STATE_GET_USERRIGHTS";
- case SYNC_STATE_PUT_MESSAGES: return "SYNC_STATE_PUT_MESSAGES";
- case SYNC_STATE_UPLOAD_FLAGS: return "SYNC_STATE_UPLOAD_FLAGS";
- case SYNC_STATE_CREATE_SUBFOLDERS: return "SYNC_STATE_CREATE_SUBFOLDERS";
- case SYNC_STATE_LIST_SUBFOLDERS: return "SYNC_STATE_LIST_SUBFOLDERS";
- case SYNC_STATE_LIST_NAMESPACES: return "SYNC_STATE_LIST_NAMESPACES";
- case SYNC_STATE_LIST_SUBFOLDERS2: return "SYNC_STATE_LIST_SUBFOLDERS2";
- case SYNC_STATE_DELETE_SUBFOLDERS: return "SYNC_STATE_DELETE_SUBFOLDERS";
- case SYNC_STATE_LIST_MESSAGES: return "SYNC_STATE_LIST_MESSAGES";
- case SYNC_STATE_DELETE_MESSAGES: return "SYNC_STATE_DELETE_MESSAGES";
- case SYNC_STATE_GET_MESSAGES: return "SYNC_STATE_GET_MESSAGES";
- case SYNC_STATE_EXPUNGE_MESSAGES: return "SYNC_STATE_EXPUNGE_MESSAGES";
- case SYNC_STATE_HANDLE_INBOX: return "SYNC_STATE_HANDLE_INBOX";
- case SYNC_STATE_TEST_ANNOTATIONS: return "SYNC_STATE_TEST_ANNOTATIONS";
- case SYNC_STATE_GET_ANNOTATIONS: return "SYNC_STATE_GET_ANNOTATIONS";
- case SYNC_STATE_SET_ANNOTATIONS: return "SYNC_STATE_SET_ANNOTATIONS";
- case SYNC_STATE_GET_ACLS: return "SYNC_STATE_GET_ACLS";
- case SYNC_STATE_SET_ACLS: return "SYNC_STATE_SET_ACLS";
- case SYNC_STATE_GET_QUOTA: return "SYNC_STATE_GET_QUOTA";
- case SYNC_STATE_FIND_SUBFOLDERS: return "SYNC_STATE_FIND_SUBFOLDERS";
- case SYNC_STATE_SYNC_SUBFOLDERS: return "SYNC_STATE_SYNC_SUBFOLDERS";
- case SYNC_STATE_RENAME_FOLDER: return "SYNC_STATE_RENAME_FOLDER";
- case SYNC_STATE_CHECK_UIDVALIDITY: return "SYNC_STATE_CHECK_UIDVALIDITY";
- default: return "Unknown state";
+ case SYNC_STATE_INITIAL: return "SYNC_STATE_INITIAL";
+ case SYNC_STATE_GET_USERRIGHTS: return "SYNC_STATE_GET_USERRIGHTS";
+ case SYNC_STATE_PUT_MESSAGES: return "SYNC_STATE_PUT_MESSAGES";
+ case SYNC_STATE_UPLOAD_FLAGS: return "SYNC_STATE_UPLOAD_FLAGS";
+ case SYNC_STATE_CREATE_SUBFOLDERS: return "SYNC_STATE_CREATE_SUBFOLDERS";
+ case SYNC_STATE_LIST_SUBFOLDERS: return "SYNC_STATE_LIST_SUBFOLDERS";
+ case SYNC_STATE_LIST_NAMESPACES: return "SYNC_STATE_LIST_NAMESPACES";
+ case SYNC_STATE_LIST_SUBFOLDERS2: return "SYNC_STATE_LIST_SUBFOLDERS2";
+ case SYNC_STATE_DELETE_SUBFOLDERS: return "SYNC_STATE_DELETE_SUBFOLDERS";
+ case SYNC_STATE_LIST_MESSAGES: return "SYNC_STATE_LIST_MESSAGES";
+ case SYNC_STATE_DELETE_MESSAGES: return "SYNC_STATE_DELETE_MESSAGES";
+ case SYNC_STATE_GET_MESSAGES: return "SYNC_STATE_GET_MESSAGES";
+ case SYNC_STATE_EXPUNGE_MESSAGES: return "SYNC_STATE_EXPUNGE_MESSAGES";
+ case SYNC_STATE_HANDLE_INBOX: return "SYNC_STATE_HANDLE_INBOX";
+ case SYNC_STATE_TEST_ANNOTATIONS: return "SYNC_STATE_TEST_ANNOTATIONS";
+ case SYNC_STATE_GET_ANNOTATIONS: return "SYNC_STATE_GET_ANNOTATIONS";
+ case SYNC_STATE_SET_ANNOTATIONS: return "SYNC_STATE_SET_ANNOTATIONS";
+ case SYNC_STATE_GET_ACLS: return "SYNC_STATE_GET_ACLS";
+ case SYNC_STATE_SET_ACLS: return "SYNC_STATE_SET_ACLS";
+ case SYNC_STATE_GET_QUOTA: return "SYNC_STATE_GET_QUOTA";
+ case SYNC_STATE_FIND_SUBFOLDERS: return "SYNC_STATE_FIND_SUBFOLDERS";
+ case SYNC_STATE_SYNC_SUBFOLDERS: return "SYNC_STATE_SYNC_SUBFOLDERS";
+ case SYNC_STATE_RENAME_FOLDER: return "SYNC_STATE_RENAME_FOLDER";
+ case SYNC_STATE_CHECK_UIDVALIDITY: return "SYNC_STATE_CHECK_UIDVALIDITY";
+ case SYNC_STATE_CLOSE: return "SYNC_STATE_CLOSE";
+ case SYNC_STATE_GET_SUBFOLDER_QUOTA: return "SYNC_STATE_GET_SUBFOLDER_QUOTA";
+ default: return "Unknown state";
}
}
@@ -866,11 +921,14 @@ void KMFolderCachedImap::serverSyncInternal()
case SYNC_STATE_GET_USERRIGHTS:
+
+ // Now we have started the sync, emit changed() so that the folder tree can update the status
+ emit syncStateChanged();
//kdDebug(5006) << "===== Syncing " << ( mImapPath.isEmpty() ? label() : mImapPath ) << endl;
mSyncState = SYNC_STATE_RENAME_FOLDER;
- if( !noContent() && mAccount->hasACLSupport() ) {
+ if( !mQuotaOnly && !noContent() && mAccount->hasACLSupport() ) {
// Check the user's own rights. We do this every time in case they changed.
mOldUserRights = mUserRights;
newState( mProgress, i18n("Checking permissions"));
@@ -880,6 +938,14 @@ void KMFolderCachedImap::serverSyncInternal()
break;
}
+ else if ( !mQuotaOnly && noContent() && mAccount->hasACLSupport() ) {
+ // This is a no content folder. The server would simply say that mailbox does not exist when
+ // querying the rights for it. So pretend we have no rights.
+ mUserRights = 0;
+ mUserRightsState = KMail::ACLJobs::Ok;
+ writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
+ }
+
case SYNC_STATE_RENAME_FOLDER:
{
mSyncState = SYNC_STATE_CHECK_UIDVALIDITY;
@@ -890,7 +956,7 @@ void KMFolderCachedImap::serverSyncInternal()
newState( mProgress, i18n("Renaming folder") );
CachedImapJob *job = new CachedImapJob( newName, CachedImapJob::tRenameFolder, this );
connect( job, TQT_SIGNAL( result(KMail::FolderJob *) ), this, TQT_SLOT( slotIncreaseProgress() ) );
- connect( job, TQT_SIGNAL( finished() ), this, TQT_SLOT( serverSyncInternal() ) );
+ connect( job, TQT_SIGNAL( finished() ), this, TQT_SLOT( slotRenameFolderFinished() ) );
job->start();
break;
}
@@ -898,7 +964,7 @@ void KMFolderCachedImap::serverSyncInternal()
case SYNC_STATE_CHECK_UIDVALIDITY:
mSyncState = SYNC_STATE_CREATE_SUBFOLDERS;
- if( !noContent() ) {
+ if( !mQuotaOnly && !noContent() ) {
checkUidValidity();
break;
}
@@ -906,33 +972,36 @@ void KMFolderCachedImap::serverSyncInternal()
case SYNC_STATE_CREATE_SUBFOLDERS:
mSyncState = SYNC_STATE_PUT_MESSAGES;
- createNewFolders();
- break;
+ if ( !mQuotaOnly ) {
+ createNewFolders();
+ break;
+ }
case SYNC_STATE_PUT_MESSAGES:
mSyncState = SYNC_STATE_UPLOAD_FLAGS;
- if( !noContent() ) {
+ if( !mQuotaOnly && !noContent() ) {
uploadNewMessages();
break;
}
// Else carry on
case SYNC_STATE_UPLOAD_FLAGS:
mSyncState = SYNC_STATE_LIST_NAMESPACES;
- if( !noContent() ) {
+ if( !mQuotaOnly && !noContent() ) {
// We haven't downloaded messages yet, so we need to build the map.
if( uidMapDirty )
reloadUidMap();
// Upload flags, unless we know from the ACL that we're not allowed
// to do that or they did not change locally
- if ( mUserRights <= 0 || ( mUserRights & (KMail::ACLJobs::WriteFlags ) ) ) {
- if ( mStatusChangedLocally ) {
+ if ( mUserRightsState != KMail::ACLJobs::Ok ||
+ ( mUserRights & (KMail::ACLJobs::WriteFlags ) ) ) {
+ if ( !mUIDsOfLocallyChangedStatuses.empty() || mStatusChangedLocally ) {
uploadFlags();
break;
} else {
//kdDebug(5006) << "Skipping flags upload, folder unchanged: " << label() << endl;
}
} else if ( mUserRights & KMail::ACLJobs::WriteSeenFlag ) {
- if ( mStatusChangedLocally ) {
+ if ( !mUIDsOfLocallyChangedStatuses.empty() || mStatusChangedLocally ) {
uploadSeenFlags();
break;
}
@@ -941,7 +1010,7 @@ void KMFolderCachedImap::serverSyncInternal()
// Else carry on
case SYNC_STATE_LIST_NAMESPACES:
- if ( this == mAccount->rootFolder() ) {
+ if ( !mQuotaOnly && this == mAccount->rootFolder() ) {
listNamespaces();
break;
}
@@ -951,22 +1020,26 @@ void KMFolderCachedImap::serverSyncInternal()
case SYNC_STATE_LIST_SUBFOLDERS:
newState( mProgress, i18n("Retrieving folderlist"));
mSyncState = SYNC_STATE_LIST_SUBFOLDERS2;
- if( !listDirectory() ) {
- mSyncState = SYNC_STATE_INITIAL;
- KMessageBox::error(0, i18n("Error while retrieving the folderlist"));
+ if ( !mQuotaOnly ) {
+ if( !listDirectory() ) {
+ mSyncState = SYNC_STATE_INITIAL;
+ KMessageBox::error(0, i18n("Error while retrieving the folderlist"));
+ }
+ break;
}
- break;
case SYNC_STATE_LIST_SUBFOLDERS2:
mSyncState = SYNC_STATE_DELETE_SUBFOLDERS;
mProgress += 10;
- newState( mProgress, i18n("Retrieving subfolders"));
- listDirectory2();
- break;
+ if ( !mQuotaOnly ) {
+ newState( mProgress, i18n("Retrieving subfolders"));
+ listDirectory2();
+ break;
+ }
case SYNC_STATE_DELETE_SUBFOLDERS:
mSyncState = SYNC_STATE_LIST_MESSAGES;
- if( !foldersForDeletionOnServer.isEmpty() ) {
+ if( !mQuotaOnly && !foldersForDeletionOnServer.isEmpty() ) {
newState( mProgress, i18n("Deleting folders from server"));
CachedImapJob* job = new CachedImapJob( foldersForDeletionOnServer,
CachedImapJob::tDeleteFolders, this );
@@ -981,7 +1054,7 @@ void KMFolderCachedImap::serverSyncInternal()
case SYNC_STATE_LIST_MESSAGES:
mSyncState = SYNC_STATE_DELETE_MESSAGES;
- if( !noContent() ) {
+ if( !mQuotaOnly && !noContent() ) {
newState( mProgress, i18n("Retrieving message list"));
listMessages();
break;
@@ -990,7 +1063,7 @@ void KMFolderCachedImap::serverSyncInternal()
case SYNC_STATE_DELETE_MESSAGES:
mSyncState = SYNC_STATE_EXPUNGE_MESSAGES;
- if( !noContent() ) {
+ if( !mQuotaOnly && !noContent() ) {
if( deleteMessages() ) {
// Fine, we will continue with the next state
} else {
@@ -1005,7 +1078,7 @@ void KMFolderCachedImap::serverSyncInternal()
case SYNC_STATE_EXPUNGE_MESSAGES:
mSyncState = SYNC_STATE_GET_MESSAGES;
- if( !noContent() ) {
+ if( !mQuotaOnly && !noContent() ) {
newState( mProgress, i18n("Expunging deleted messages"));
CachedImapJob *job = new CachedImapJob( TQString::null,
CachedImapJob::tExpungeFolder, this );
@@ -1018,9 +1091,9 @@ void KMFolderCachedImap::serverSyncInternal()
case SYNC_STATE_GET_MESSAGES:
mSyncState = SYNC_STATE_HANDLE_INBOX;
- if( !noContent() ) {
+ if( !mQuotaOnly && !noContent() ) {
if( !mMsgsForDownload.isEmpty() ) {
- newState( mProgress, i18n("Retrieving new messages"));
+ newState( mProgress, i18n("Retrieving one new message","Retrieving %n new messages",mMsgsForDownload.size()));
CachedImapJob *job = new CachedImapJob( mMsgsForDownload,
CachedImapJob::tGetMessage,
this );
@@ -1061,8 +1134,8 @@ void KMFolderCachedImap::serverSyncInternal()
case SYNC_STATE_TEST_ANNOTATIONS:
mSyncState = SYNC_STATE_GET_ANNOTATIONS;
// The first folder with user rights to write annotations
- if( !mAccount->annotationCheckPassed() &&
- ( mUserRights <= 0 || ( mUserRights & ACLJobs::Administer ) )
+ if( !mQuotaOnly && !mAccount->annotationCheckPassed() &&
+ ( mUserRightsState != KMail::ACLJobs::Ok || ( mUserRights & ACLJobs::Administer ) )
&& !imapPath().isEmpty() && imapPath() != "/" ) {
kdDebug(5006) << "Setting test attribute on folder: "<< folder()->prettyURL() << endl;
newState( mProgress, i18n("Checking annotation support"));
@@ -1088,11 +1161,12 @@ void KMFolderCachedImap::serverSyncInternal()
case SYNC_STATE_GET_ANNOTATIONS: {
#define KOLAB_FOLDERTYPE "/vendor/kolab/folder-type"
#define KOLAB_INCIDENCESFOR "/vendor/kolab/incidences-for"
+#define KOLAB_SHAREDSEEN "/vendor/cmu/cyrus-imapd/sharedseen"
//#define KOLAB_FOLDERTYPE "/comment" //for testing, while cyrus-imap doesn't support /vendor/*
mSyncState = SYNC_STATE_SET_ANNOTATIONS;
bool needToGetInitialAnnotations = false;
- if ( !noContent() ) {
+ if ( !mQuotaOnly && !noContent() ) {
// for a folder we didn't create ourselves: get annotation from server
if ( mAnnotationFolderType == "FROMSERVER" ) {
needToGetInitialAnnotations = true;
@@ -1104,13 +1178,15 @@ void KMFolderCachedImap::serverSyncInternal()
// First retrieve the annotation, so that we know we have to set it if it's not set.
// On the other hand, if the user changed the contentstype, there's no need to get first.
- if ( !noContent() && mAccount->hasAnnotationSupport() &&
+ if ( !mQuotaOnly && !noContent() && mAccount->hasAnnotationSupport() &&
( kmkernel->iCalIface().isEnabled() || needToGetInitialAnnotations ) ) {
TQStringList annotations; // list of annotations to be fetched
if ( !mAnnotationFolderTypeChanged || mAnnotationFolderType.isEmpty() )
annotations << KOLAB_FOLDERTYPE;
if ( !mIncidencesForChanged )
annotations << KOLAB_INCIDENCESFOR;
+ if ( !mSharedSeenFlagsChanged )
+ annotations << KOLAB_SHAREDSEEN;
if ( !annotations.isEmpty() ) {
newState( mProgress, i18n("Retrieving annotations"));
KURL url = mAccount->getUrl();
@@ -1132,8 +1208,8 @@ void KMFolderCachedImap::serverSyncInternal()
case SYNC_STATE_SET_ANNOTATIONS:
mSyncState = SYNC_STATE_SET_ACLS;
- if ( !noContent() && mAccount->hasAnnotationSupport() &&
- ( mUserRights <= 0 || ( mUserRights & ACLJobs::Administer ) ) ) {
+ if ( !mQuotaOnly && !noContent() && mAccount->hasAnnotationSupport() &&
+ ( mUserRightsState != KMail::ACLJobs::Ok || ( mUserRights & ACLJobs::Administer ) ) ) {
newState( mProgress, i18n("Setting annotations"));
KURL url = mAccount->getUrl();
url.setPath( imapPath() );
@@ -1149,6 +1225,12 @@ void KMFolderCachedImap::serverSyncInternal()
annotations.append( attr );
kdDebug(5006) << "Setting incidences-for annotation for " << label() << " to " << val << endl;
}
+ if ( mSharedSeenFlagsChanged ) {
+ const TQString val = mSharedSeenFlags ? "true" : "false";
+ KMail::AnnotationAttribute attr( KOLAB_SHAREDSEEN, "value.shared", val );
+ annotations.append( attr );
+ kdDebug(5006) << k_funcinfo << "Setting sharedseen annotation for " << label() << " to " << val << endl;
+ }
if ( !annotations.isEmpty() ) {
KIO::Job* job =
AnnotationJobs::multiSetAnnotation( mAccount->slave(), url, annotations );
@@ -1167,8 +1249,8 @@ void KMFolderCachedImap::serverSyncInternal()
case SYNC_STATE_SET_ACLS:
mSyncState = SYNC_STATE_GET_ACLS;
- if( !noContent() && mAccount->hasACLSupport() &&
- ( mUserRights <= 0 || ( mUserRights & ACLJobs::Administer ) ) ) {
+ if( !mQuotaOnly && !noContent() && mAccount->hasACLSupport() &&
+ ( mUserRightsState != KMail::ACLJobs::Ok || ( mUserRights & ACLJobs::Administer ) ) ) {
bool hasChangedACLs = false;
ACLList::ConstIterator it = mACLList.begin();
for ( ; it != mACLList.end() && !hasChangedACLs; ++it ) {
@@ -1191,19 +1273,36 @@ void KMFolderCachedImap::serverSyncInternal()
}
case SYNC_STATE_GET_ACLS:
- mSyncState = SYNC_STATE_GET_QUOTA;
+ mSyncState = SYNC_STATE_FIND_SUBFOLDERS;
- if( !noContent() && mAccount->hasACLSupport() ) {
+ if( !mQuotaOnly && !noContent() && mAccount->hasACLSupport() ) {
newState( mProgress, i18n( "Retrieving permissions" ) );
mAccount->getACL( folder(), mImapPath );
connect( mAccount, TQT_SIGNAL(receivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )),
this, TQT_SLOT(slotReceivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )) );
break;
}
+ case SYNC_STATE_FIND_SUBFOLDERS:
+ {
+ mSyncState = SYNC_STATE_SYNC_SUBFOLDERS;
+ mSomeSubFolderCloseToQuotaChanged = false;
+ buildSubFolderList();
+ }
+
+ // Carry on
+ case SYNC_STATE_SYNC_SUBFOLDERS:
+ syncNextSubFolder( false );
+ break;
+ case SYNC_STATE_GET_SUBFOLDER_QUOTA:
+
+ // Sync the subfolders again, so that the quota information is updated for all. This state is
+ // only entered if the close to quota property of one subfolder changed in the previous state.
+ syncNextSubFolder( true );
+ break;
case SYNC_STATE_GET_QUOTA:
- // Continue with the subfolders
- mSyncState = SYNC_STATE_FIND_SUBFOLDERS;
+ mSyncState = SYNC_STATE_CLOSE;
if( !noContent() && mAccount->hasQuotaSupport() ) {
+ mProgress = 98;
newState( mProgress, i18n("Getting quota information"));
KURL url = mAccount->getUrl();
url.setPath( imapPath() );
@@ -1216,79 +1315,114 @@ void KMFolderCachedImap::serverSyncInternal()
TQT_SLOT(slotQuotaResult(KIO::Job *)) );
break;
}
- case SYNC_STATE_FIND_SUBFOLDERS:
+ case SYNC_STATE_CLOSE:
{
- mProgress = 98;
- newState( mProgress, i18n("Updating cache file"));
-
- mSyncState = SYNC_STATE_SYNC_SUBFOLDERS;
- mSubfoldersForSync.clear();
- mCurrentSubfolder = 0;
- if( folder() && folder()->child() ) {
- KMFolderNode *node = folder()->child()->first();
- while( node ) {
- if( !node->isDir() ) {
- KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
- // Only sync folders that have been accepted by the server
- if ( !storage->imapPath().isEmpty()
- // and that were not just deleted from it
- && !foldersForDeletionOnServer.contains( storage->imapPath() ) ) {
- mSubfoldersForSync << storage;
- } else {
- kdDebug(5006) << "Do not add " << storage->label()
- << " to synclist" << endl;
- }
- }
- node = folder()->child()->next();
- }
- }
-
- // All done for this folder.
- mProgress = 100; // all done
- newState( mProgress, i18n("Synchronization done"));
+ mProgress = 100; // all done
+ newState( mProgress, i18n("Synchronization done"));
KURL url = mAccount->getUrl();
url.setPath( imapPath() );
kmkernel->iCalIface().folderSynced( folder(), url );
- }
-
- if ( !mRecurse ) // "check mail for this folder" only
- mSubfoldersForSync.clear();
- // Carry on
- case SYNC_STATE_SYNC_SUBFOLDERS:
- {
- if( mCurrentSubfolder ) {
- disconnect( mCurrentSubfolder, TQT_SIGNAL( folderComplete(KMFolderCachedImap*, bool) ),
- this, TQT_SLOT( slotSubFolderComplete(KMFolderCachedImap*, bool) ) );
- mCurrentSubfolder = 0;
- }
-
- if( mSubfoldersForSync.isEmpty() ) {
- mSyncState = SYNC_STATE_INITIAL;
- mAccount->addUnreadMsgCount( this, countUnread() ); // before closing
- close("cachedimap");
- emit folderComplete( this, true );
- } else {
- mCurrentSubfolder = mSubfoldersForSync.front();
- mSubfoldersForSync.pop_front();
- connect( mCurrentSubfolder, TQT_SIGNAL( folderComplete(KMFolderCachedImap*, bool) ),
- this, TQT_SLOT( slotSubFolderComplete(KMFolderCachedImap*, bool) ) );
-
- //kdDebug(5006) << "Sync'ing subfolder " << mCurrentSubfolder->imapPath() << endl;
- assert( !mCurrentSubfolder->imapPath().isEmpty() );
- mCurrentSubfolder->setAccount( account() );
- bool recurse = mCurrentSubfolder->noChildren() ? false : true;
- mCurrentSubfolder->serverSync( recurse );
- }
+ mSyncState = SYNC_STATE_INITIAL;
+ mAccount->addUnreadMsgCount( this, countUnread() ); // before closing
+ close( "cachedimap" );
+ emit syncStateChanged();
+ emit folderComplete( this, true );
}
break;
default:
kdDebug(5006) << "KMFolderCachedImap::serverSyncInternal() WARNING: no such state "
- << mSyncState << endl;
+ << mSyncState << endl;
}
}
+void KMFolderCachedImap::syncNextSubFolder( bool secondSync )
+{
+ if( mCurrentSubfolder ) {
+ disconnectSubFolderSignals();
+ }
+
+ if( mSubfoldersForSync.isEmpty() ) {
+
+ // Sync finished, and a close to quota property of an subfolder changed, therefore go into
+ // the SYNC_STATE_GET_SUBFOLDER_QUOTA state and sync again
+ if ( mSomeSubFolderCloseToQuotaChanged && mRecurse && !secondSync ) {
+ buildSubFolderList();
+ mSyncState = SYNC_STATE_GET_SUBFOLDER_QUOTA;
+ serverSyncInternal();
+ }
+
+ else {
+
+ // Quota checking has to come after syncing subfolder, otherwise the quota information would
+ // be outdated, since the subfolders can change in size during the syncing.
+ // https://issues.kolab.org/issue4066
+ mSyncState = SYNC_STATE_GET_QUOTA;
+ serverSyncInternal();
+ }
+ } else {
+ mCurrentSubfolder = mSubfoldersForSync.front();
+ mSubfoldersForSync.pop_front();
+ if ( mCurrentSubfolder ) {
+ connect( mCurrentSubfolder, TQT_SIGNAL( folderComplete(KMFolderCachedImap*, bool) ),
+ this, TQT_SLOT( slotSubFolderComplete(KMFolderCachedImap*, bool) ) );
+ connect( mCurrentSubfolder, TQT_SIGNAL( closeToQuotaChanged() ),
+ this, TQT_SLOT( slotSubFolderCloseToQuotaChanged() ) );
+
+ //kdDebug(5006) << "Sync'ing subfolder " << mCurrentSubfolder->imapPath() << endl;
+ assert( !mCurrentSubfolder->imapPath().isEmpty() );
+ mCurrentSubfolder->setAccount( account() );
+ const bool recurse = mCurrentSubfolder->noChildren() ? false : true;
+ const bool quotaOnly = secondSync || mQuotaOnly;
+ mCurrentSubfolder->serverSync( recurse, quotaOnly );
+ }
+ else {
+ // mCurrentSubfolder is empty, probably because it was deleted while syncing. Go on with the
+ // next subfolder instead.
+ syncNextSubFolder( secondSync );
+ }
+ }
+}
+
+void KMFolderCachedImap::buildSubFolderList()
+{
+ mSubfoldersForSync.clear();
+ mCurrentSubfolder = 0;
+ if( folder() && folder()->child() ) {
+ KMFolderNode *node = folder()->child()->first();
+ while( node ) {
+ if( !node->isDir() ) {
+ KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
+ const bool folderIsNew = mNewlyCreatedSubfolders.contains( TQGuardedPtr<KMFolderCachedImap>( storage ) );
+ // Only sync folders that have been accepted by the server
+ if ( !storage->imapPath().isEmpty()
+ // and that were not just deleted from it
+ && !foldersForDeletionOnServer.contains( storage->imapPath() ) ) {
+ if ( mRecurse || folderIsNew ) {
+ mSubfoldersForSync << storage;
+ }
+ } else {
+ kdDebug(5006) << "Do not add " << storage->label()
+ << " to synclist" << endl;
+ }
+ }
+ node = folder()->child()->next();
+ }
+ }
+
+ mNewlyCreatedSubfolders.clear();
+}
+
+void KMFolderCachedImap::disconnectSubFolderSignals()
+{
+ disconnect( mCurrentSubfolder, TQT_SIGNAL( folderComplete(KMFolderCachedImap*, bool) ),
+ this, TQT_SLOT( slotSubFolderComplete(KMFolderCachedImap*, bool) ) );
+ disconnect( mCurrentSubfolder, TQT_SIGNAL( closeToQuotaChanged() ),
+ this, TQT_SLOT( slotSubFolderCloseToQuotaChanged() ) );
+ mCurrentSubfolder = 0;
+}
+
/* Connected to the imap account's connectionResult signal.
Emitted when the slave connected or failed to connect.
*/
@@ -1326,7 +1460,7 @@ void KMFolderCachedImap::uploadNewMessages()
{
TQValueList<unsigned long> newMsgs = findNewMessages();
if( !newMsgs.isEmpty() ) {
- if ( mUserRights <= 0 || ( mUserRights & ( KMail::ACLJobs::Insert ) ) ) {
+ if ( mUserRightsState != KMail::ACLJobs::Ok || ( mUserRights & ( KMail::ACLJobs::Insert ) ) ) {
newState( mProgress, i18n("Uploading messages to server"));
CachedImapJob *job = new CachedImapJob( newMsgs, CachedImapJob::tPutMessage, this );
connect( job, TQT_SIGNAL( progress( unsigned long, unsigned long) ),
@@ -1377,6 +1511,11 @@ void KMFolderCachedImap::uploadFlags()
if( !msg || msg->UID() == 0 )
// Either not a valid message or not one that is on the server yet
continue;
+ if ( mUIDsOfLocallyChangedStatuses.find( msg->UID() ) == mUIDsOfLocallyChangedStatuses.end()
+ && !mStatusChangedLocally ) {
+ // This message has not had its status changed locally
+ continue;
+ }
TQString flags = KMFolderImap::statusToFlags(msg->status(), mPermanentFlags);
// Collect uids for each typem of flags.
@@ -1420,6 +1559,12 @@ void KMFolderCachedImap::uploadSeenFlags()
// Either not a valid message or not one that is on the server yet
continue;
+ if ( mUIDsOfLocallyChangedStatuses.find( msg->UID() ) == mUIDsOfLocallyChangedStatuses.end()
+ && !mStatusChangedLocally ) {
+ // This message has not had its status changed locally
+ continue;
+ }
+
if ( msg->status() & KMMsgStatusOld || msg->status() & KMMsgStatusRead )
seenUids.append( msg->UID() );
else
@@ -1476,13 +1621,21 @@ void KMFolderCachedImap::slotImapStatusChanged(KMFolder* folder, const TQString&
void KMFolderCachedImap::setStatus( int idx, KMMsgStatus status, bool toggle)
{
KMFolderMaildir::setStatus( idx, status, toggle );
- mStatusChangedLocally = true;
+ const KMMsgBase *msg = getMsgBase( idx );
+ Q_ASSERT( msg );
+ if ( msg )
+ mUIDsOfLocallyChangedStatuses.insert( msg->UID() );
}
void KMFolderCachedImap::setStatus(TQValueList<int>& ids, KMMsgStatus status, bool toggle)
{
KMFolderMaildir::setStatus(ids, status, toggle);
- mStatusChangedLocally = true;
+ for (TQValueList<int>::iterator it = ids.begin(); it != ids.end(); it++ ) {
+ const KMMsgBase *msg = getMsgBase( *it );
+ Q_ASSERT( msg );
+ if ( msg )
+ mUIDsOfLocallyChangedStatuses.insert( msg->UID() );
+ }
}
/* Upload new folders to server */
@@ -1528,7 +1681,7 @@ TQValueList<KMFolderCachedImap*> KMFolderCachedImap::findNewFolders()
bool KMFolderCachedImap::deleteMessages()
{
/* Delete messages from cache that are gone from the server */
- TQPtrList<KMMessage> msgsForDeletion;
+ TQPtrList<KMMsgBase> msgsForDeletion;
// It is not possible to just go over all indices and remove
// them one by one because the index list can get resized under
@@ -1540,11 +1693,15 @@ bool KMFolderCachedImap::deleteMessages()
ulong uid ( it.key() );
if( uid!=0 && !uidsOnServer.find( uid ) ) {
uids << TQString::number( uid );
- msgsForDeletion.append( getMsg( *it ) );
+ msgsForDeletion.append( getMsgBase( *it ) );
}
}
if( !msgsForDeletion.isEmpty() ) {
+ if ( contentsType() != ContentsTypeMail ) {
+ kdDebug(5006) << k_funcinfo << label() << " Going to locally delete " << msgsForDeletion.count()
+ << " messages, with the uids " << uids.join( "," ) << endl;
+ }
#if MAIL_LOSS_DEBUGGING
if ( KMessageBox::warningYesNo(
0, i18n( "<qt><p>Mails on the server in folder <b>%1</b> were deleted. "
@@ -1554,7 +1711,7 @@ bool KMFolderCachedImap::deleteMessages()
removeMsg( msgsForDeletion );
}
- if ( mUserRights > 0 && !( mUserRights & KMail::ACLJobs::Delete ) )
+ if ( mUserRightsState == KMail::ACLJobs::Ok && !( mUserRights & KMail::ACLJobs::Delete ) )
return false;
/* Delete messages from the server that we dont have anymore */
@@ -1688,7 +1845,7 @@ void KMFolderCachedImap::slotGetMessagesData(KIO::Job * job, const TQByteArray &
// updated when selecting the folder again, which might not happen if using
// RMB / Check Mail in this folder. We don't need two (potentially conflicting)
// sources for the readonly setting, in any case.
- if (a != -1 && mUserRights == -1 ) {
+ if (a != -1 && mUserRightsState != KMail::ACLJobs::Ok ) {
int b = (*it).cdata.find("\r\n", a + 12);
const TQString access = (*it).cdata.mid(a + 12, b - a - 12);
setReadOnly( access == "Read only" );
@@ -1751,7 +1908,7 @@ void KMFolderCachedImap::slotGetMessagesData(KIO::Job * job, const TQByteArray &
#endif
// double check we deleted it since the last sync
if ( mDeletedUIDsSinceLastSync.contains(uid) ) {
- if ( mUserRights <= 0 || ( mUserRights & KMail::ACLJobs::Delete ) ) {
+ if ( mUserRightsState != KMail::ACLJobs::Ok || ( mUserRights & KMail::ACLJobs::Delete ) ) {
#if MAIL_LOSS_DEBUGGING
kdDebug(5006) << "message with uid " << uid << " is gone from local cache. Must be deleted on server!!!" << endl;
#endif
@@ -1821,7 +1978,8 @@ void KMFolderCachedImap::getMessagesResult( KMail::FolderJob *job, bool lastSet
} else {
if( lastSet ) { // always true here (this comes from online-imap...)
mContentState = imapFinished;
- mStatusChangedLocally = false; // we are up to date again
+ mUIDsOfLocallyChangedStatuses.clear(); // we are up to date again
+ mStatusChangedLocally = false;
}
}
serverSyncInternal();
@@ -1830,10 +1988,13 @@ void KMFolderCachedImap::getMessagesResult( KMail::FolderJob *job, bool lastSet
void KMFolderCachedImap::slotProgress(unsigned long done, unsigned long total)
{
int progressSpan = 100 - 5 - mProgress;
- //kdDebug(5006) << "KMFolderCachedImap::slotProgress done=" << done << " total=" << total << "=> mProgress=" << mProgress + ( progressSpan * done ) / total << endl;
+ int additionalProgress = ( total == 0 ) ?
+ progressSpan :
+ ( progressSpan * done ) / total;
+
// Progress info while retrieving new emails
// (going from mProgress to mProgress+progressSpan)
- newState( mProgress + (progressSpan * done) / total, TQString::null );
+ newState( mProgress + additionalProgress, TQString::null );
}
void KMFolderCachedImap::setAccount(KMAcctCachedImap *aAccount)
@@ -2010,7 +2171,7 @@ void KMFolderCachedImap::slotListResult( const TQStringList& folderNames,
mSubfolderMimeTypes = folderMimeTypes;
mSubfolderState = imapFinished;
mSubfolderAttributes = folderAttributes;
- kdDebug(5006) << "##### setting subfolder attributes: " << mSubfolderAttributes << endl;
+ //kdDebug(5006) << "##### setting subfolder attributes: " << mSubfolderAttributes << endl;
folder()->createChildFolder();
KMFolderNode *node = folder()->child()->first();
@@ -2209,6 +2370,7 @@ void KMFolderCachedImap::createFoldersNewOnServerAndFinishListing( const TQValue
f->setNoChildren(mSubfolderMimeTypes[idx] == "message/digest");
f->setImapPath(mSubfolderPaths[idx]);
f->mFolderAttributes = mSubfolderAttributes[idx];
+ mNewlyCreatedSubfolders.append( TQGuardedPtr<KMFolderCachedImap>( f ) );
kdDebug(5006) << " ####### Attributes: " << f->mFolderAttributes <<endl;
//kdDebug(5006) << subfolderPath << ": mAnnotationFolderType set to FROMSERVER" << endl;
kmkernel->dimapFolderMgr()->contentsChanged();
@@ -2267,18 +2429,26 @@ void KMFolderCachedImap::slotSubFolderComplete(KMFolderCachedImap* sub, bool suc
// success == false means the sync was aborted.
if ( mCurrentSubfolder ) {
Q_ASSERT( sub == mCurrentSubfolder );
- disconnect( mCurrentSubfolder, TQT_SIGNAL( folderComplete(KMFolderCachedImap*, bool) ),
- this, TQT_SLOT( slotSubFolderComplete(KMFolderCachedImap*, bool) ) );
- mCurrentSubfolder = 0;
+ disconnectSubFolderSignals();
}
+ // Next step would be to check quota limits and then to close the folder, but don't bother with
+ // both and close the folder right here, since we aborted.
mSubfoldersForSync.clear();
mSyncState = SYNC_STATE_INITIAL;
close("cachedimap");
+ emit syncStateChanged();
emit folderComplete( this, false );
}
}
+void KMFolderCachedImap::slotSubFolderCloseToQuotaChanged()
+{
+ if ( !mQuotaOnly ) {
+ mSomeSubFolderCloseToQuotaChanged = true;
+ }
+}
+
void KMFolderCachedImap::slotSimpleData(KIO::Job * job, const TQByteArray & data)
{
KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
@@ -2312,9 +2482,10 @@ KMFolderCachedImap::doCreateJob( TQPtrList<KMMessage>& msgList, const TQString&
}
void
-KMFolderCachedImap::setUserRights( unsigned int userRights )
+KMFolderCachedImap::setUserRights( unsigned int userRights, KMail::ACLJobs::ACLFetchState state )
{
mUserRights = userRights;
+ mUserRightsState = state;
writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
}
@@ -2324,10 +2495,9 @@ KMFolderCachedImap::slotReceivedUserRights( KMFolder* folder )
if ( folder->storage() == this ) {
disconnect( mAccount, TQT_SIGNAL( receivedUserRights( KMFolder* ) ),
this, TQT_SLOT( slotReceivedUserRights( KMFolder* ) ) );
- if ( mUserRights == 0 ) // didn't work
- mUserRights = -1; // error code (used in folderdia)
- else
+ if ( mUserRightsState == KMail::ACLJobs::Ok ) {
setReadOnly( ( mUserRights & KMail::ACLJobs::Insert ) == 0 );
+ }
mProgress += 5;
serverSyncInternal();
}
@@ -2343,11 +2513,12 @@ KMFolderCachedImap::setReadOnly( bool readOnly )
}
void
-KMFolderCachedImap::slotReceivedACL( KMFolder* folder, KIO::Job*, const KMail::ACLList& aclList )
+KMFolderCachedImap::slotReceivedACL( KMFolder* folder, KIO::Job* job, const KMail::ACLList& aclList )
{
if ( folder->storage() == this ) {
disconnect( mAccount, TQT_SIGNAL(receivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )),
this, TQT_SLOT(slotReceivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )) );
+ mACLListState = job->error() ? KMail::ACLJobs::FetchFailed : KMail::ACLJobs::Ok;
mACLList = aclList;
serverSyncInternal();
}
@@ -2362,8 +2533,12 @@ KMFolderCachedImap::slotStorageQuotaResult( const QuotaInfo& info )
void KMFolderCachedImap::setQuotaInfo( const QuotaInfo & info )
{
if ( info != mQuotaInfo ) {
+ const bool wasCloseToQuota = isCloseToQuota();
mQuotaInfo = info;
writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
+ if ( wasCloseToQuota != isCloseToQuota() ) {
+ emit closeToQuotaChanged();
+ }
emit folderSizeChanged();
}
}
@@ -2372,6 +2547,7 @@ void
KMFolderCachedImap::setACLList( const ACLList& arr )
{
mACLList = arr;
+ mACLListState = KMail::ACLJobs::Ok;
}
void
@@ -2413,6 +2589,7 @@ void KMFolderCachedImap::resetSyncState()
{
if ( mSyncState == SYNC_STATE_INITIAL ) return;
mSubfoldersForSync.clear();
+ mNewlyCreatedSubfolders.clear();
mSyncState = SYNC_STATE_INITIAL;
close("cachedimap");
// Don't use newState here, it would revert to mProgress (which is < current value when listing messages)
@@ -2421,6 +2598,7 @@ void KMFolderCachedImap::resetSyncState()
if (progressItem)
progressItem->setStatus( str );
emit statusMsg( str );
+ emit syncStateChanged();
}
void KMFolderCachedImap::slotIncreaseProgress()
@@ -2472,6 +2650,16 @@ void KMFolderCachedImap::setImapPath(const TQString &path)
mImapPath = path;
}
+static bool isFolderTypeKnownToUs( const TQString &type )
+{
+ for ( uint i = 0 ; i <= ContentsTypeLast; ++i ) {
+ FolderContentsType contentsType = static_cast<KMail::FolderContentsType>( i );
+ if ( type == KMailICalIfaceImpl::annotationForContentsType( contentsType ) )
+ return true;
+ }
+ return false;
+}
+
// mAnnotationFolderType is the annotation as known to the server (and stored in kmailrc)
// It is updated from the folder contents type and whether it's a standard resource folder.
// This happens during the syncing phase and during initFolder for a new folder.
@@ -2493,12 +2681,18 @@ void KMFolderCachedImap::updateAnnotationFolderType()
newType = KMailICalIfaceImpl::annotationForContentsType( mContentsType );
if ( kmkernel->iCalIface().isStandardResourceFolder( folder() ) )
newSubType = "default";
- else
- newSubType = oldSubType; // preserve unknown subtypes, like drafts etc. And preserve ".default" too.
+ else if ( oldSubType != "default" )
+ newSubType = oldSubType; // preserve unknown subtypes, like drafts etc.
}
+ // We do not want to overwrite custom folder types (which we treat as mail folders).
+ // So only overwrite custom folder types if the user changed the folder type himself to something
+ // other than mail.
+ const bool changingTypeAllowed = isFolderTypeKnownToUs( oldType ) ||
+ ( mContentsType != ContentsTypeMail );
+
//kdDebug(5006) << mImapPath << ": updateAnnotationFolderType: " << newType << " " << newSubType << endl;
- if ( newType != oldType || newSubType != oldSubType ) {
+ if ( ( newType != oldType || newSubType != oldSubType ) && changingTypeAllowed ) {
mAnnotationFolderType = newType + ( newSubType.isEmpty() ? TQString::null : "."+newSubType );
mAnnotationFolderTypeChanged = true; // force a "set annotation" on next sync
kdDebug(5006) << mImapPath << ": updateAnnotationFolderType: '" << mAnnotationFolderType << "', was (" << oldType << " " << oldSubType << ") => mAnnotationFolderTypeChanged set to TRUE" << endl;
@@ -2515,6 +2709,14 @@ void KMFolderCachedImap::setIncidencesFor( IncidencesFor incfor )
}
}
+void KMFolderCachedImap::setSharedSeenFlags(bool b)
+{
+ if ( mSharedSeenFlags != b ) {
+ mSharedSeenFlags = b;
+ mSharedSeenFlagsChanged = true;
+ }
+}
+
void KMFolderCachedImap::slotAnnotationResult(const TQString& entry, const TQString& value, bool found)
{
if ( entry == KOLAB_FOLDERTYPE ) {
@@ -2559,16 +2761,21 @@ void KMFolderCachedImap::slotAnnotationResult(const TQString& entry, const TQStr
if ( contentsType != ContentsTypeMail )
markUnreadAsRead();
- // Ensure that further readConfig()s don't lose mAnnotationFolderType
- writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
break;
}
}
- if ( !foundKnownType && !mReadOnly ) {
- //kdDebug(5006) << "slotGetAnnotationResult: no known type of annotation found, will need to set it" << endl;
- // Case 4: server has strange content-type, set it to what we need
- mAnnotationFolderTypeChanged = true;
+ if ( !foundKnownType ) {
+ //kdDebug(5006) << "slotGetAnnotationResult: no known type of annotation found, leaving it untouched" << endl;
+
+ // Case 4: Server has strange content-type. We must not overwrite it, see https://issues.kolab.org/issue2069.
+ // Treat the content-type as mail until we change it ourselves.
+ mAnnotationFolderTypeChanged = false;
+ mAnnotationFolderType = value;
+ setContentsType( ContentsTypeMail );
}
+
+ // Ensure that further readConfig()s don't lose mAnnotationFolderType
+ writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
// TODO handle subtype (inbox, drafts, sentitems, junkemail)
}
else if ( !mReadOnly ) {
@@ -2581,6 +2788,10 @@ void KMFolderCachedImap::slotAnnotationResult(const TQString& entry, const TQStr
mIncidencesFor = incidencesForFromString( value );
Q_ASSERT( mIncidencesForChanged == false );
}
+ } else if ( entry == KOLAB_SHAREDSEEN ) {
+ if ( found ) {
+ mSharedSeenFlags = value == "true";
+ }
}
}
@@ -2700,6 +2911,8 @@ KMFolderCachedImap::slotAnnotationChanged( const TQString& entry, const TQString
// The incidences-for changed, we must trigger the freebusy creation.
// HACK: in theory we would need a new enum value for this.
kmkernel->iCalIface().addFolderChange( folder(), KMailICalIfaceImpl::ACL );
+ } else if ( entry == KOLAB_SHAREDSEEN ) {
+ mSharedSeenFlagsChanged = false;
}
}
@@ -2989,4 +3202,27 @@ void KMFolderCachedImap::slotRescueDone(KMCommand * command)
serverSyncInternal();
}
+void KMFolderCachedImap::slotRenameFolderFinished()
+{
+ // The syncing code assumes the folder was opened by us, and later closes it. So better
+ // make sure the reference count is correct, since the folder was force-closed by the rename.
+ // Otherwise bad things can happen, see https://issues.kolab.org/issue3853.
+ open( "cachedimap" );
+ serverSyncInternal();
+}
+
+bool KMFolderCachedImap::canDeleteMessages() const
+{
+ if ( isReadOnly() )
+ return false;
+ if ( mUserRightsState == KMail::ACLJobs::Ok && !(userRights() & ACLJobs::Delete) )
+ return false;
+ return true;
+}
+
+bool KMFolderCachedImap::mailCheckInProgress() const
+{
+ return mSyncState != SYNC_STATE_INITIAL;
+}
+
#include "kmfoldercachedimap.moc"
diff --git a/kmail/kmfoldercachedimap.h b/kmail/kmfoldercachedimap.h
index 5ead77b25..21abeabf9 100644
--- a/kmail/kmfoldercachedimap.h
+++ b/kmail/kmfoldercachedimap.h
@@ -47,6 +47,8 @@
#include "cachedimapjob.h"
#include "quotajobs.h"
+#include <set>
+
using KMail::FolderJob;
using KMail::QuotaInfo;
class KMCommand;
@@ -79,10 +81,11 @@ public:
private slots:
void slotDone();
-
+ void slotChanged();
private:
TQRadioButton *mIndexButton, *mCacheButton;
TQComboBox *mIndexScope;
+ TQButtonGroup *mButtonGroup;
int rc;
};
@@ -122,7 +125,7 @@ public:
virtual void remove();
/** Synchronize this folder and it's subfolders with the server */
- virtual void serverSync( bool recurse );
+ virtual void serverSync( bool recurse, bool quotaOnly = false );
/** Force the sync state to be done. */
void resetSyncState( );
@@ -138,7 +141,7 @@ public:
enum imapState { imapNoInformation=0, imapInProgress=1, imapFinished=2 };
- virtual imapState getContentState() { return mContentState; }
+ virtual imapState getContentState() const { return mContentState; }
virtual void setContentState(imapState state) { mContentState = state; }
virtual imapState getSubfolderState() { return mSubfolderState; }
@@ -206,11 +209,12 @@ public:
/* Reimplemented from KMFolderMaildir */
virtual void removeMsg(int i, bool imapQuiet = false);
- virtual void removeMsg(TQPtrList<KMMessage> msgList, bool imapQuiet = false)
+ virtual void removeMsg( const TQPtrList<KMMsgBase> & msgList, bool imapQuiet = false)
{ FolderStorage::removeMsg(msgList, imapQuiet); }
/// Is the folder readonly?
bool isReadOnly() const { return KMFolderMaildir::isReadOnly() || mReadOnly; }
+ bool canDeleteMessages() const;
/**
@@ -249,12 +253,14 @@ public:
/**
* The user's rights on this folder - see bitfield in ACLJobs namespace.
- * @return 0 when not known yet, -1 if there was an error fetching them
+ * Note that the returned value is only valid if userRightsState() returns Ok, so
+ * that should be checked first.
*/
int userRights() const { return mUserRights; }
+ KMail::ACLJobs::ACLFetchState userRightsState() const { return mUserRightsState; }
/// Set the user's rights on this folder - called by getUserRights
- void setUserRights( unsigned int userRights );
+ void setUserRights( unsigned int userRights, KMail::ACLJobs::ACLFetchState state );
/**
* The quota information for this folder.
@@ -271,6 +277,7 @@ public:
/// Return the list of ACL for this folder
typedef TQValueVector<KMail::ACLListEntry> ACLList;
const ACLList& aclList() const { return mACLList; }
+ KMail::ACLJobs::ACLFetchState aclListState() const { return mACLListState; };
/// Set the list of ACL for this folder (for FolderDiaACLTab)
void setACLList( const ACLList& arr );
@@ -298,6 +305,11 @@ public:
/// For the folder properties dialog
void setIncidencesFor( IncidencesFor incfor );
+ /** Returns wether the seen flag is shared among all users or every users has her own seen flags (default). */
+ bool sharedSeenFlags() const { return mSharedSeenFlags; }
+ /** Enable shared seen flags (requires server support). */
+ void setSharedSeenFlags( bool b );
+
/** Returns true if this folder can be moved */
virtual bool isMoveable() const;
@@ -324,6 +336,8 @@ public:
TQString folderAttributes() const { return mFolderAttributes; }
+ virtual bool mailCheckInProgress() const;
+
protected slots:
void slotGetMessagesData(KIO::Job * job, const TQByteArray & data);
void getMessagesResult(KMail::FolderJob *, bool lastSet);
@@ -333,6 +347,7 @@ protected slots:
//virtual void slotCheckValidityResult(KIO::Job * job);
void slotSubFolderComplete(KMFolderCachedImap*, bool);
+ void slotSubFolderCloseToQuotaChanged();
// Connected to the imap account
void slotConnectionResult( int errorCode, const TQString& errorMsg );
@@ -426,15 +441,16 @@ private slots:
void slotUpdateLastUid();
void slotFolderDeletionOnServerFinished();
void slotRescueDone( KMCommand* command );
+ void slotRenameFolderFinished();
signals:
void folderComplete(KMFolderCachedImap *folder, bool success);
void listComplete( KMFolderCachedImap* );
- /** emitted when we enter the state "state" and
- have to process "number" items (for example messages
- */
- void syncState( int state, int number );
+ /**
+ * Emitted when isCloseToQuota() changes during syncing
+ */
+ void closeToQuotaChanged();
private:
void setReadOnly( bool readOnly );
@@ -448,6 +464,24 @@ private:
/** Recursive helper function calling the above method. */
void rescueUnsyncedMessagesAndDeleteFolder( KMFolder *folder, bool root = true );
+ /**
+ * Small helper function that disconnects the signals from the current subfolder, which where
+ * connected when starting the sync of that subfolder
+ */
+ void disconnectSubFolderSignals();
+
+ /**
+ * Sync the next subfolder in the list of subfolders (mSubfoldersForSync).
+ * When finished, this will switch either to the state SYNC_STATE_GET_SUBFOLDER_QUOTA or
+ * to SYNC_STATE_GET_QUOTA.
+ */
+ void syncNextSubFolder( bool secondSync );
+
+ /**
+ * Creates the mSubfoldersForSync list
+ */
+ void buildSubFolderList();
+
/** State variable for the synchronization mechanism */
enum {
SYNC_STATE_INITIAL,
@@ -473,7 +507,9 @@ private:
SYNC_STATE_FIND_SUBFOLDERS,
SYNC_STATE_SYNC_SUBFOLDERS,
SYNC_STATE_CHECK_UIDVALIDITY,
- SYNC_STATE_RENAME_FOLDER
+ SYNC_STATE_RENAME_FOLDER,
+ SYNC_STATE_CLOSE,
+ SYNC_STATE_GET_SUBFOLDER_QUOTA
} mSyncState;
int mProgress;
@@ -487,6 +523,7 @@ private:
TQString mFolderAttributes;
TQString mAnnotationFolderType;
IncidencesFor mIncidencesFor;
+ bool mSharedSeenFlags;
bool mHasInbox;
bool mIsSelected;
@@ -500,7 +537,7 @@ private:
TQValueList<ulong> mUidsForDownload;
TQStringList foldersForDeletionOnServer;
- TQValueList<KMFolderCachedImap*> mSubfoldersForSync;
+ TQValueList< TQGuardedPtr<KMFolderCachedImap> > mSubfoldersForSync;
KMFolderCachedImap* mCurrentSubfolder;
/** Mapping uid -> index
@@ -533,21 +570,36 @@ private:
bool mFoundAnIMAPDigest;
int mUserRights, mOldUserRights;
+ KMail::ACLJobs::ACLFetchState mUserRightsState;
ACLList mACLList;
+ KMail::ACLJobs::ACLFetchState mACLListState;
bool mSilentUpload;
bool mFolderRemoved;
//bool mHoldSyncs;
bool mRecurse;
- /** Set to true by setStatus. Indicates that the client has changed
- the status of at least one mail. The mail flags will therefore be
- uploaded to the server, overwriting the server's notion of the status
- of the mails in this folder. */
- bool mStatusChangedLocally;
+ bool mQuotaOnly;
+
/// Set to true when the foldertype annotation needs to be set on the next sync
bool mAnnotationFolderTypeChanged;
/// Set to true when the "incidences-for" annotation needs to be set on the next sync
bool mIncidencesForChanged;
+ /// Set to true when the "sharedseen" annotation needs to be set on the next sync
+ bool mSharedSeenFlagsChanged;
+
+ /**
+ * UIDs added by setStatus. Indicates that the client has changed
+ * the status of those mails. The mail flags for changed mails will be
+ * uploaded to the server, overwriting the server's notion of the status
+ * of the mails in this folder.
+ */
+ std::set<ulong> mUIDsOfLocallyChangedStatuses;
+
+ /**
+ * Same as above, but uploads the flags of all mails, even if not all changed.
+ * Only still here for config compatibility.
+ */
+ bool mStatusChangedLocally;
TQStringList mNamespacesToList;
int mNamespacesToCheck;
@@ -555,12 +607,18 @@ private:
TQString mImapPathCreation;
QuotaInfo mQuotaInfo;
+
+ /// This is set during syncing of the current subfolder. If true, it means the closeToQuota info
+ /// for the current subfolder has changed during syncing
+ bool mSomeSubFolderCloseToQuotaChanged;
+
TQMap<ulong,void*> mDeletedUIDsSinceLastSync;
bool mAlarmsBlocked;
TQValueList<KMFolder*> mToBeDeletedAfterRescue;
int mRescueCommandCount;
+ TQValueList< TQGuardedPtr<KMFolderCachedImap> > mNewlyCreatedSubfolders;
int mPermanentFlags;
};
diff --git a/kmail/kmfolderdia.cpp b/kmail/kmfolderdia.cpp
index cf02fcddf..533173e5e 100644
--- a/kmail/kmfolderdia.cpp
+++ b/kmail/kmfolderdia.cpp
@@ -32,6 +32,7 @@
#include <config.h>
+#include "acljobs.h"
#include "kmfolderdia.h"
#include "kmacctfolder.h"
#include "kmfoldermgr.h"
@@ -247,20 +248,20 @@ static void addLine( TQWidget *parent, TQVBoxLayout* layout )
KMail::FolderDiaGeneralTab::FolderDiaGeneralTab( KMFolderDialog* dlg,
const TQString& aName,
TQWidget* parent, const char* name )
- : FolderDiaTab( parent, name ), mDlg( dlg )
+ : FolderDiaTab( parent, name ),
+ mSharedSeenFlagsCheckBox( 0 ),
+ mDlg( dlg )
{
-
- mIsLocalSystemFolder = mDlg->folder()->isSystemFolder() &&
- mDlg->folder()->folderType() != KMFolderTypeImap &&
- mDlg->folder()->folderType() != KMFolderTypeCachedImap;
+ mIsLocalSystemFolder = mDlg->folder()->isSystemFolder();
+ mIsResourceFolder = kmkernel->iCalIface().isStandardResourceFolder( mDlg->folder() );
TQLabel *label;
TQVBoxLayout *topLayout = new TQVBoxLayout( this, 0, KDialog::spacingHint() );
- // Musn't be able to edit details for a system folder.
- if ( !mIsLocalSystemFolder ) {
+ // Musn't be able to edit details for a non-resource, system folder.
+ if ( !mIsLocalSystemFolder || mIsResourceFolder ) {
TQHBoxLayout *hl = new TQHBoxLayout( topLayout );
hl->setSpacing( KDialog::spacingHint() );
@@ -268,9 +269,65 @@ KMail::FolderDiaGeneralTab::FolderDiaGeneralTab( KMFolderDialog* dlg,
label = new TQLabel( i18n("&Name:"), this );
hl->addWidget( label );
+ // Determine if we are allowed to rename this folder. Only possible if the folder supports
+ // ACLs.
+ bool nameChangeAllowed = true;
+ if ( mDlg->folder() && mDlg->parentFolder() &&
+ mDlg->folder()->storage() && mDlg->parentFolder()->storage() &&
+ ( mDlg->folder()->folderType() == KMFolderTypeCachedImap ||
+ mDlg->folder()->folderType() == KMFolderTypeImap ) ) {
+ ImapAccountBase *account = 0;
+ KMFolderCachedImap *dimap = 0;
+ KMFolderImap *imap = 0;
+ if ( mDlg->folder()->folderType() == KMFolderTypeCachedImap ) {
+ dimap = static_cast<KMFolderCachedImap*>( mDlg->folder()->storage() );
+ account = dynamic_cast<ImapAccountBase*>( dimap->account() );
+ }
+ if ( mDlg->folder()->folderType() == KMFolderTypeImap ) {
+ imap = static_cast<KMFolderImap*>( mDlg->folder()->storage() );
+ account = dynamic_cast<ImapAccountBase*>( imap->account() );
+ }
+
+ if ( account && account->hasACLSupport() ) {
+ int parentRights = -1;
+ int folderRights = -1;
+ bool parentRightsOk = false;
+ bool folderRightsOk = false;
+ if ( imap ) {
+ KMFolderImap * const parent = dynamic_cast<KMFolderImap*>( mDlg->parentFolder()->storage() );
+ folderRights = imap->userRights();
+ folderRightsOk = imap->userRightsState() == KMail::ACLJobs::Ok;
+ if ( parent ) {
+ parentRights = parent->userRights();
+ parentRightsOk = parent->userRightsState() == KMail::ACLJobs::Ok;
+ }
+ } else if ( dimap ) {
+ KMFolderCachedImap * const parent = dynamic_cast<KMFolderCachedImap*>( mDlg->parentFolder()->storage() );
+ folderRights = dimap->userRights();
+ folderRightsOk = dimap->userRightsState() == KMail::ACLJobs::Ok;
+ if ( parent ) {
+ parentRights = parent->userRights();
+ parentRightsOk = parent->userRightsState() == KMail::ACLJobs::Ok;
+ }
+ }
+
+ // For renaming, we need support for deleting the mailbox and then re-creating it.
+ if ( parentRightsOk && folderRightsOk &&
+ ( !( parentRights & KMail::ACLJobs::Create ) || !( folderRights & KMail::ACLJobs::Delete ) ) ) {
+ nameChangeAllowed = false;
+ }
+ }
+ }
+
mNameEdit = new KLineEdit( this );
- if( !mDlg->folder() )
- mNameEdit->setFocus();
+ if( !mDlg->folder() && nameChangeAllowed )
+ mNameEdit->setFocus();
+ mNameEdit->setEnabled( nameChangeAllowed );
+ if ( !nameChangeAllowed ) {
+ TQToolTip::add( mNameEdit, i18n( "Not enough permissions to rename this folder.\n"
+ "The parent folder doesn't have write support.\n"
+ "A sync is needed after changing the permissions." ) );
+ }
mNameEdit->setText( mDlg->folder() ? mDlg->folder()->label() : i18n("unnamed") );
if (!aName.isEmpty())
mNameEdit->setText(aName);
@@ -433,9 +490,10 @@ KMail::FolderDiaGeneralTab::FolderDiaGeneralTab( KMFolderDialog* dlg,
"automatically. Identities can be set up in the main configuration "
"dialog. (Settings -> Configure KMail)") );
-
// folder contents
- if ( !mIsLocalSystemFolder && kmkernel->iCalIface().isEnabled() ) {
+ if ( ( !mIsLocalSystemFolder || mIsResourceFolder ) &&
+ kmkernel->iCalIface().isEnabled() &&
+ mDlg->folder() && mDlg->folder()->folderType() != KMFolderTypeImap ) {
// Only do make this settable, if the IMAP resource is enabled
// and it's not the personal folders (those must not be changed)
++row;
@@ -455,12 +513,12 @@ KMail::FolderDiaGeneralTab::FolderDiaGeneralTab( KMFolderDialog* dlg,
mContentsComboBox->setCurrentItem( mDlg->folder()->storage()->contentsType() );
connect ( mContentsComboBox, TQT_SIGNAL ( activated( int ) ),
this, TQT_SLOT( slotFolderContentsSelectionChanged( int ) ) );
- if ( mDlg->folder()->isReadOnly() )
+ if ( mDlg->folder()->isReadOnly() || mIsResourceFolder )
mContentsComboBox->setEnabled( false );
} else {
mContentsComboBox = 0;
}
-
+
mIncidencesForComboBox = 0;
mAlarmsBlockedCheckBox = 0;
@@ -478,7 +536,7 @@ KMail::FolderDiaGeneralTab::FolderDiaGeneralTab( KMFolderDialog* dlg,
label->setBuddy( mIncidencesForComboBox );
gl->addWidget( mIncidencesForComboBox, row, 1 );
- const TQString whatsThisForMyOwnFolders =
+ const TQString whatsThisForMyOwnFolders =
i18n( "This setting defines which users sharing "
"this folder should get \"busy\" periods in their freebusy lists "
"and should see the alarms for the events or tasks in this folder. "
@@ -499,13 +557,10 @@ KMail::FolderDiaGeneralTab::FolderDiaGeneralTab( KMFolderDialog* dlg,
mIncidencesForComboBox->insertItem( i18n( "All Readers of This Folder" ) );
++row;
const TQString whatsThisForReadOnlyFolders =
- i18n( "This setting allows you to disable alarms for folders shared by "
- "others. ");
+ i18n( "This setting allows you to disable alarms for folders shared by others. ");
mAlarmsBlockedCheckBox = new TQCheckBox( this );
- gl->addWidget( mAlarmsBlockedCheckBox, row, 0 );
- label = new TQLabel( i18n( "Block free/&busy and alarms locally" ), this );
- gl->addWidget( label, row, 1 );
- label->setBuddy( mAlarmsBlockedCheckBox );
+ mAlarmsBlockedCheckBox->setText( i18n( "Block alarms locally" ) );
+ gl->addMultiCellWidget( mAlarmsBlockedCheckBox, row, row, 0, 1);
TQWhatsThis::add( mAlarmsBlockedCheckBox, whatsThisForReadOnlyFolders );
if ( mDlg->folder()->storage()->contentsType() != KMail::ContentsTypeCalendar
@@ -514,6 +569,17 @@ KMail::FolderDiaGeneralTab::FolderDiaGeneralTab( KMFolderDialog* dlg,
mAlarmsBlockedCheckBox->setEnabled( false );
}
}
+
+ if ( mDlg->folder()->folderType() == KMFolderTypeCachedImap ) {
+ kdDebug() << k_funcinfo << mDlg->folder()->folderType() << endl;
+ mSharedSeenFlagsCheckBox = new TQCheckBox( this );
+ mSharedSeenFlagsCheckBox->setText( i18n( "Share unread state with all users" ) );
+ ++row;
+ gl->addMultiCellWidget( mSharedSeenFlagsCheckBox, row, row, 0, 1 );
+ TQWhatsThis::add( mSharedSeenFlagsCheckBox, i18n( "If enabled, the unread state of messages in this folder will be the same "
+ "for all users having access to this folders. If disabled (the default), every user with access to this folder has her "
+ "own unread state." ) );
+ }
topLayout->addStretch( 100 ); // eat all superfluous space
initializeWithValuesFromFolder( mDlg->folder() );
@@ -568,6 +634,16 @@ void FolderDiaGeneralTab::initializeWithValuesFromFolder( KMFolder* folder ) {
KMFolderCachedImap* dimap = static_cast<KMFolderCachedImap *>( folder->storage() );
mAlarmsBlockedCheckBox->setChecked( dimap->alarmsBlocked() );
}
+ if ( mSharedSeenFlagsCheckBox ) {
+ KMFolderCachedImap *dimap = static_cast<KMFolderCachedImap*>( folder->storage() );
+ ImapAccountBase *account = dynamic_cast<ImapAccountBase*>( dimap->account() );
+ mSharedSeenFlagsCheckBox->setChecked( dimap->sharedSeenFlags() );
+ mSharedSeenFlagsCheckBox->setDisabled( folder->isReadOnly() );
+ if ( account && account->hasCapability( "x-kmail-sharedseen" ) )
+ mSharedSeenFlagsCheckBox->show();
+ else
+ mSharedSeenFlagsCheckBox->hide();
+ }
}
//-----------------------------------------------------------------------------
@@ -614,11 +690,13 @@ bool FolderDiaGeneralTab::save()
folder->setPutRepliesInSameFolder( mKeepRepliesInSameFolderCheckBox->isChecked() );
TQString fldName, oldFldName;
- if ( !mIsLocalSystemFolder )
+ KMFolderCachedImap* dimap = 0;
+ if ( folder->folderType() == KMFolderTypeCachedImap )
+ dimap = static_cast<KMFolderCachedImap *>( mDlg->folder()->storage() );
+
+ if ( !mIsLocalSystemFolder || mIsResourceFolder )
{
- TQString acctName;
oldFldName = mDlg->folder()->name();
-
if (!mNameEdit->text().isEmpty())
fldName = mNameEdit->text();
else
@@ -641,11 +719,11 @@ bool FolderDiaGeneralTab::save()
folder->setIconPaths( "", "" );
}
}
- if ( folder->useCustomIcons() &&
+ if ( folder->useCustomIcons() && (
(( mNormalIconButton->icon() != folder->normalIconPath() ) &&
( !mNormalIconButton->icon().isEmpty())) ||
(( mUnreadIconButton->icon() != folder->unreadIconPath() ) &&
- ( !mUnreadIconButton->icon().isEmpty())) ) {
+ ( !mUnreadIconButton->icon().isEmpty())) ) ) {
folder->setIconPaths( mNormalIconButton->icon(), mUnreadIconButton->icon() );
}
@@ -656,8 +734,7 @@ bool FolderDiaGeneralTab::save()
folder->storage()->setContentsType( type );
}
- if ( folder->folderType() == KMFolderTypeCachedImap ) {
- KMFolderCachedImap* dimap = static_cast<KMFolderCachedImap *>( mDlg->folder()->storage() );
+ if ( dimap ) {
if ( mIncidencesForComboBox ) {
KMFolderCachedImap::IncidencesFor incfor = KMFolderCachedImap::IncForAdmins;
incfor = static_cast<KMFolderCachedImap::IncidencesFor>( mIncidencesForComboBox->currentItem() );
@@ -678,9 +755,23 @@ bool FolderDiaGeneralTab::save()
imapFolder->setIncludeInMailCheck(
mNewMailCheckBox->isChecked() );
}
- // make sure everything is on disk, connected slots will call readConfig()
- // when creating a new folder.
- folder->storage()->writeConfig();
+ }
+
+ if ( dimap && mSharedSeenFlagsCheckBox &&
+ mSharedSeenFlagsCheckBox->isChecked() != dimap->sharedSeenFlags() ) {
+ dimap->setSharedSeenFlags( mSharedSeenFlagsCheckBox->isChecked() );
+ dimap->writeConfig();
+ }
+
+ // make sure everything is on disk, connected slots will call readConfig()
+ // when creating a new folder.
+ folder->storage()->writeConfig();
+
+ TQString msg;
+ if ( !folder->isValidName( fldName, msg ) ) {
+ KMessageBox::sorry( this, msg );
+ return false;
+ } else {
// Renamed an existing folder? We don't check for oldName == newName on
// purpose here. The folder might be pending renaming on the next dimap
// sync already, in which case the old name would still be around and
@@ -694,6 +785,7 @@ bool FolderDiaGeneralTab::save()
kmkernel->folderMgr()->contentsChanged();
}
}
+
return true;
}
@@ -708,9 +800,8 @@ KMail::FolderDiaTemplatesTab::FolderDiaTemplatesTab( KMFolderDialog* dlg,
: FolderDiaTab( parent, 0 ), mDlg( dlg )
{
- mIsLocalSystemFolder = mDlg->folder()->isSystemFolder() &&
- mDlg->folder()->folderType() != KMFolderTypeImap &&
- mDlg->folder()->folderType() != KMFolderTypeCachedImap;
+ mIsLocalSystemFolder = mDlg->folder()->isSystemFolder();
+
TQVBoxLayout *topLayout = new TQVBoxLayout( this, 0, KDialog::spacingHint() );
diff --git a/kmail/kmfolderdia.h b/kmail/kmfolderdia.h
index 913685d85..4db30ab12 100644
--- a/kmail/kmfolderdia.h
+++ b/kmail/kmfolderdia.h
@@ -137,6 +137,7 @@ private:
TQComboBox *mContentsComboBox;
TQComboBox *mIncidencesForComboBox;
TQCheckBox *mAlarmsBlockedCheckBox;
+ TQCheckBox *mSharedSeenFlagsCheckBox;
TQLabel *mNormalIconLabel;
KIconButton *mNormalIconButton;
TQLabel *mUnreadIconLabel;
@@ -151,6 +152,7 @@ private:
KMFolderDialog* mDlg;
bool mIsLocalSystemFolder;
+ bool mIsResourceFolder;
};
/**
diff --git a/kmail/kmfolderdir.cpp b/kmail/kmfolderdir.cpp
index 46aba345c..1ecab637b 100644
--- a/kmail/kmfolderdir.cpp
+++ b/kmail/kmfolderdir.cpp
@@ -163,6 +163,31 @@ TQString KMFolderDir::prettyURL() const
return label();
}
+//-----------------------------------------------------------------------------
+void KMFolderDir::addDirToParent( const TQString &dirName, KMFolder *parentFolder )
+{
+ KMFolderDir* folderDir = new KMFolderDir( parentFolder, this, dirName, mDirType);
+ folderDir->reload();
+ append( folderDir );
+ parentFolder->setChild( folderDir );
+}
+
+// Get the default folder type of the given dir type. This function should only be used when
+// needing to find out what the folder type of a missing folder is.
+KMFolderType dirTypeToFolderType( KMFolderDirType dirType )
+{
+ switch( dirType ) {
+
+ // Use maildir for normal folder dirs, as this function is only called when finding a dir
+ // without a parent folder, which can only happen with maildir-like folders
+ case KMStandardDir: return KMFolderTypeMaildir;
+
+ case KMImapDir: return KMFolderTypeImap;
+ case KMDImapDir: return KMFolderTypeCachedImap;
+ case KMSearchDir: return KMFolderTypeSearch;
+ default: Q_ASSERT( false ); return KMFolderTypeMaildir;
+ }
+}
//-----------------------------------------------------------------------------
bool KMFolderDir::reload(void)
@@ -272,6 +297,7 @@ bool KMFolderDir::reload(void)
}
}
+ TQStringList dirsWithoutFolder = diList;
for (folder=folderList.first(); folder; folder=folderList.next())
{
for(TQStringList::Iterator it = diList.begin();
@@ -279,13 +305,36 @@ bool KMFolderDir::reload(void)
++it)
if (*it == "." + folder->fileName() + ".directory")
{
- KMFolderDir* folderDir = new KMFolderDir( folder, this, *it, mDirType);
- folderDir->reload();
- append(folderDir);
- folder->setChild(folderDir);
+ dirsWithoutFolder.remove( *it );
+ addDirToParent( *it, folder );
break;
}
}
+
+ // Check if the are any dirs without an associated folder. This can happen if the user messes
+ // with the on-disk folder structure, see kolab issue 2972. In that case, we don't want to loose
+ // the subfolders as well, so we recreate the folder so the folder/dir hierachy is OK again.
+ if ( type() == KMDImapDir ) {
+ for ( TQStringList::Iterator it = dirsWithoutFolder.begin();
+ it != dirsWithoutFolder.end(); ++it ) {
+
+ // .foo.directory => foo
+ TQString folderName = *it;
+ int right = folderName.find( ".directory" );
+ int left = folderName.find( "." );
+ Q_ASSERT( left != -1 && right != -1 );
+ folderName = folderName.mid( left + 1, right - 1 );
+
+ kdDebug(5006) << "Found dir without associated folder: " << ( *it ) << ", recreating the folder " << folderName << "." << endl;
+
+ // Recreate the missing folder
+ KMFolder *folder = new KMFolder( this, folderName, KMFolderTypeCachedImap );
+ append( folder );
+ folderList.append( folder );
+
+ addDirToParent( *it, folder );
+ }
+ }
return TRUE;
}
diff --git a/kmail/kmfolderdir.h b/kmail/kmfolderdir.h
index 72f4c4326..c93317e52 100644
--- a/kmail/kmfolderdir.h
+++ b/kmail/kmfolderdir.h
@@ -19,11 +19,16 @@ class KMFolderDir: public KMFolderNode, public KMFolderNodeList
public:
KMFolderDir( KMFolder * owner, KMFolderDir * parent = 0,
const TQString& path = TQString::null,
- KMFolderDirType = KMStandardDir );
+ KMFolderDirType = KMStandardDir );
virtual ~KMFolderDir();
virtual bool isDir() const { return true; }
+ /**
+ * Adds the given subdirectory of this directory to the associated folder.
+ */
+ void addDirToParent( const TQString &dirName, KMFolder *parentFolder );
+
/** Read contents of directory. */
virtual bool reload();
@@ -39,9 +44,9 @@ public:
/** Create a mail folder in this directory with given name. If sysFldr==TRUE
the folder is marked as a (KMail) system folder.
Returns Folder on success. */
- virtual KMFolder* createFolder(const TQString& folderName,
- bool sysFldr=false,
- KMFolderType folderType=KMFolderTypeMbox);
+ virtual KMFolder* createFolder( const TQString& folderName,
+ bool sysFldr=false,
+ KMFolderType folderType=KMFolderTypeMbox );
/** Returns folder with given name or zero if it does not exist */
virtual KMFolderNode* hasNamedFolder(const TQString& name);
@@ -67,9 +72,9 @@ class KMFolderRootDir: public KMFolderDir
Q_OBJECT
public:
- KMFolderRootDir(KMFolderMgr* manager,
- const TQString& path=TQString::null,
- KMFolderDirType dirType = KMStandardDir);
+ KMFolderRootDir( KMFolderMgr* manager,
+ const TQString& path=TQString::null,
+ KMFolderDirType dirType = KMStandardDir );
virtual ~KMFolderRootDir();
virtual TQString path() const;
diff --git a/kmail/kmfolderimap.cpp b/kmail/kmfolderimap.cpp
index f32162f8a..e5c7bd827 100644
--- a/kmail/kmfolderimap.cpp
+++ b/kmail/kmfolderimap.cpp
@@ -49,6 +49,7 @@ using KMail::ListJob;
using KMail::SearchJob;
#include "renamejob.h"
using KMail::RenameJob;
+#include "acljobs.h"
#include <kdebug.h>
#include <kio/scheduler.h>
@@ -73,6 +74,7 @@ KMFolderImap::KMFolderImap(KMFolder* folder, const char* aName)
mCheckMail = true;
mCheckingValidity = false;
mUserRights = 0;
+ mUserRightsState = KMail::ACLJobs::NotFetchedYet;
mAlreadyRemoved = false;
mHasChildren = ChildrenUnknown;
mMailCheckProgressItem = 0;
@@ -108,12 +110,6 @@ KMFolderImap::~KMFolderImap()
//-----------------------------------------------------------------------------
void KMFolderImap::reallyDoClose(const char* owner)
{
- if (isSelected()) {
- kdWarning(5006) << "Trying to close the selected folder " << label() <<
- " - ignoring!" << endl;
- return;
- }
-
// FIXME is this still needed?
if (account())
account()->ignoreJobsForFolder( folder() );
@@ -334,8 +330,6 @@ void KMFolderImap::addMsgQuiet(KMMessage* aMsg)
int idx = aFolder->find( aMsg );
assert( idx != -1 );
aFolder->take( idx );
- } else {
- kdDebug(5006) << k_funcinfo << "no parent" << endl;
}
if ( !account()->hasCapability("uidplus") ) {
// Remember the status with the MD5 as key
@@ -1000,6 +994,13 @@ void KMFolderImap::initializeFrom( KMFolderImap* parent, TQString folderPath,
}
//-----------------------------------------------------------------------------
+bool KMFolderImap::mailCheckInProgress() const
+{
+ return getContentState() != imapNoInformation &&
+ getContentState() != imapFinished;
+}
+
+//-----------------------------------------------------------------------------
void KMFolderImap::setChildrenState( TQString attributes )
{
// update children state
@@ -1188,7 +1189,7 @@ void KMFolderImap::getAndCheckFolder(bool force)
return getFolder(force);
if ( account() )
- account()->processNewMailSingleFolder( folder() );
+ account()->processNewMailInFolder( folder() );
if (force) {
// force an update
mCheckFlags = true;
@@ -2261,10 +2262,10 @@ int KMFolderImap::expungeContents()
//-----------------------------------------------------------------------------
void
-KMFolderImap::setUserRights( unsigned int userRights )
+KMFolderImap::setUserRights( unsigned int userRights, KMail::ACLJobs::ACLFetchState userRightsState )
{
mUserRights = userRights;
- kdDebug(5006) << imapPath() << " setUserRights: " << userRights << endl;
+ mUserRightsState = userRightsState;
}
//-----------------------------------------------------------------------------
@@ -2392,7 +2393,7 @@ bool KMFolderImap::isMoveable() const
}
//-----------------------------------------------------------------------------
-const ulong KMFolderImap::serNumForUID( ulong uid )
+ulong KMFolderImap::serNumForUID( ulong uid )
{
if ( mUidMetaDataMap.find( uid ) ) {
KMMsgMetaData *md = mUidMetaDataMap[uid];
@@ -2431,4 +2432,13 @@ void KMFolderImap::finishMailCheck( const char *dbg, imapState state )
close(dbg);
}
+bool KMFolderImap::canDeleteMessages() const
+{
+ if ( isReadOnly() )
+ return false;
+ if ( mUserRightsState == KMail::ACLJobs::Ok && !(mUserRights & KMail::ACLJobs::Delete) )
+ return false;
+ return true;
+}
+
#include "kmfolderimap.moc"
diff --git a/kmail/kmfolderimap.h b/kmail/kmfolderimap.h
index 7b25520f1..76a3db98d 100644
--- a/kmail/kmfolderimap.h
+++ b/kmail/kmfolderimap.h
@@ -24,6 +24,7 @@
#ifndef kmfolderimap_h
#define kmfolderimap_h
+#include "acljobs.h"
#include "kmacctimap.h"
#include "kmfoldermbox.h"
#include "kmmsgbase.h"
@@ -65,8 +66,8 @@ public:
KMMsgMetaData(KMMsgStatus aStatus, Q_UINT32 aSerNum)
:mStatus(aStatus), mSerNum(aSerNum) {}
~KMMsgMetaData() {};
- const KMMsgStatus status() const { return mStatus; }
- const Q_UINT32 serNum() const { return mSerNum; }
+ KMMsgStatus status() const { return mStatus; }
+ Q_UINT32 serNum() const { return mSerNum; }
private:
KMMsgStatus mStatus;
Q_UINT32 mSerNum;
@@ -91,7 +92,7 @@ public:
imapFinished = 3
};
- virtual imapState getContentState() { return mContentState; }
+ virtual imapState getContentState() const { return mContentState; }
virtual void setContentState(imapState state) { mContentState = state; }
virtual imapState getSubfolderState() { return mSubfolderState; }
@@ -250,7 +251,7 @@ public:
/**
* Get the serial number for the given UID (if available)
*/
- const ulong serNumForUID( ulong uid );
+ ulong serNumForUID( ulong uid );
/**
* Save the metadata for the UID
@@ -294,15 +295,18 @@ public:
/// Is the folder readonly?
bool isReadOnly() const { return KMFolderMbox::isReadOnly() || mReadOnly; }
+ bool canDeleteMessages() const;
/**
* The user's rights on this folder - see bitfield in ACLJobs namespace.
- * @return 0 when not known yet
+ * Note that the returned value is only valid if userRightsState() returns Ok, so
+ * that should be checked first.
*/
unsigned int userRights() const { return mUserRights; }
+ KMail::ACLJobs::ACLFetchState userRightsState() const { return mUserRightsState; }
/** Set the user's rights on this folder - called by getUserRights */
- void setUserRights( unsigned int userRights );
+ void setUserRights( unsigned int userRights, KMail::ACLJobs::ACLFetchState userRightsState );
/**
* Search for messages
@@ -321,6 +325,8 @@ public:
/** Returns the IMAP flags that can be stored on the server. */
int permanentFlags() const { return mPermanentFlags; }
+ virtual bool mailCheckInProgress() const;
+
signals:
void folderComplete(KMFolderImap *folder, bool success);
@@ -515,6 +521,7 @@ protected:
// the current uidvalidity
TQString mUidValidity;
unsigned int mUserRights;
+ KMail::ACLJobs::ACLFetchState mUserRightsState;
private:
// if we're checking validity currently
diff --git a/kmail/kmfolderindex.cpp b/kmail/kmfolderindex.cpp
index 6a3781570..95746ed18 100644
--- a/kmail/kmfolderindex.cpp
+++ b/kmail/kmfolderindex.cpp
@@ -18,6 +18,8 @@
#include "kmfolderindex.h"
#include "kmfolder.h"
+#include "kmfoldertype.h"
+#include "kcursorsaver.h"
#include <config.h>
#include <tqfileinfo.h>
#include <tqtimer.h>
@@ -31,7 +33,7 @@
#endif
// Current version of the table of contents (index) files
-#define INDEX_VERSION 1506
+#define INDEX_VERSION 1507
#ifndef MAX_LINE
#define MAX_LINE 4096
@@ -110,9 +112,13 @@ int KMFolderIndex::updateIndex()
return 0;
bool dirty = mDirty;
mDirtyTimer->stop();
- for (unsigned int i=0; !dirty && i<mMsgList.high(); i++)
- if (mMsgList.at(i))
- dirty = !mMsgList.at(i)->syncIndexString();
+ for ( unsigned int i = 0; !dirty && i < mMsgList.high(); i++ ) {
+ if ( mMsgList.at(i) ) {
+ if ( !mMsgList.at(i)->syncIndexString() ) {
+ dirty = true;
+ }
+ }
+ }
if (!dirty) { // Update successful
touchFolderIdsFile();
return 0;
@@ -209,9 +215,11 @@ int KMFolderIndex::writeIndex( bool createEmptyIndex )
return 0;
}
-
bool KMFolderIndex::readIndex()
{
+ if ( contentsType() != KMail::ContentsTypeMail ) {
+ kdDebug(5006) << k_funcinfo << "Reading index for " << label() << endl;
+ }
Q_INT32 len;
KMMsgInfo* mi;
@@ -224,6 +232,7 @@ bool KMFolderIndex::readIndex()
setDirty( false );
if (!readIndexHeader(&version)) return false;
+ //kdDebug(5006) << "Index version for " << label() << " is " << version << endl;
mUnreadMsgs = 0;
mTotalMsgs = 0;
@@ -234,15 +243,20 @@ bool KMFolderIndex::readIndex()
{
mi = 0;
if(version >= 1505) {
- if(!fread(&len, sizeof(len), 1, mIndexStream))
+ if(!fread(&len, sizeof(len), 1, mIndexStream)) {
+ // Seems to be normal?
+ // kdDebug(5006) << k_funcinfo << " Unable to read length field!" << endl;
break;
+ }
if (mIndexSwapByteOrder)
len = kmail_swap_32(len);
off_t offs = ftell(mIndexStream);
- if(fseek(mIndexStream, len, SEEK_CUR))
+ if(fseek(mIndexStream, len, SEEK_CUR)) {
+ kdDebug(5006) << k_funcinfo << " Unable to seek to the end of the message!" << endl;
break;
+ }
mi = new KMMsgInfo(folder(), offs, len);
}
else
@@ -251,16 +265,18 @@ bool KMFolderIndex::readIndex()
fgets(line.data(), MAX_LINE, mIndexStream);
if (feof(mIndexStream)) break;
if (*line.data() == '\0') {
- fclose(mIndexStream);
- mIndexStream = 0;
- clearIndex();
- return false;
+ fclose(mIndexStream);
+ mIndexStream = 0;
+ clearIndex();
+ return false;
}
mi = new KMMsgInfo(folder());
mi->compat_fromOldIndexString(line, mConvertToUtf8);
}
- if(!mi)
+ if(!mi) {
+ kdDebug(5006) << k_funcinfo << " Unable to create message info object!" << endl;
break;
+ }
if (mi->isDeleted())
{
@@ -290,7 +306,17 @@ bool KMFolderIndex::readIndex()
setDirty( true );
writeIndex();
}
+
+ if ( version < 1507 ) {
+ updateInvitationAndAddressFieldsFromContents();
+ setDirty( true );
+ writeIndex();
+ }
+
mTotalMsgs = mMsgList.count();
+ if ( contentsType() != KMail::ContentsTypeMail ) {
+ kdDebug(5006) << k_funcinfo << "Done reading the index for " << label() << ", we have " << mTotalMsgs << " messages." << endl;
+ }
return true;
}
@@ -316,6 +342,15 @@ bool KMFolderIndex::readIndexHeader(int *gv)
return false; // index file has invalid header
if(gv)
*gv = indexVersion;
+
+ // Check if the index is corrupted ("not compactable") and recreate it if necessary. See
+ // FolderStorage::getMsg() for the detection code.
+ if ( !mCompactable ) {
+ kdWarning(5006) << "Index file " << indexLocation() << " is corrupted!!. Re-creating it." << endl;
+ recreateIndex( false /* don't call readIndex() afterwards */ );
+ return false;
+ }
+
if (indexVersion < 1505 ) {
if(indexVersion == 1503) {
kdDebug(5006) << "Converting old index file " << indexLocation() << " to utf-8" << endl;
@@ -323,7 +358,7 @@ bool KMFolderIndex::readIndexHeader(int *gv)
}
return true;
} else if (indexVersion == 1505) {
- } else if (indexVersion < INDEX_VERSION) {
+ } else if (indexVersion < INDEX_VERSION && indexVersion != 1506) {
kdDebug(5006) << "Index file " << indexLocation() << " is out of date. Re-creating it." << endl;
createIndexFromContents();
return false;
@@ -434,6 +469,9 @@ bool KMFolderIndex::updateIndexStreamPtr(bool)
KMFolderIndex::IndexStatus KMFolderIndex::indexStatus()
{
+ if ( !mCompactable )
+ return IndexCorrupt;
+
TQFileInfo contInfo(location());
TQFileInfo indInfo(indexLocation());
@@ -484,16 +522,56 @@ KMMsgInfo* KMFolderIndex::setIndexEntry( int idx, KMMessage *msg )
return msgInfo;
}
-void KMFolderIndex::recreateIndex()
+void KMFolderIndex::recreateIndex( bool readIndexAfterwards )
{
kapp->setOverrideCursor(KCursor::arrowCursor());
- KMessageBox::error(0,
+ KMessageBox::information(0,
i18n("The mail index for '%1' is corrupted and will be regenerated now, "
- "but some information, including status flags, will be lost.").arg(name()));
+ "but some information, like status flags, might get lost.").arg(name()));
kapp->restoreOverrideCursor();
createIndexFromContents();
- readIndex();
+ if ( readIndexAfterwards ) {
+ readIndex();
+ }
+
+ // Clear the corrupted flag
+ mCompactable = true;
+ writeConfig();
+}
+
+void KMFolderIndex::silentlyRecreateIndex()
+{
+ Q_ASSERT( !isOpened() );
+ open( "silentlyRecreateIndex" );
+ KCursorSaver busy( KBusyPtr::busy() );
+ createIndexFromContents();
+ mCompactable = true;
+ writeConfig();
+ close( "silentlyRecreateIndex" );
}
+void KMFolderIndex::updateInvitationAndAddressFieldsFromContents()
+{
+ kdDebug(5006) << "Updating index for " << label() << ", this might take a while." << endl;
+ for ( uint i = 0; i < mMsgList.size(); i++ ) {
+ KMMsgInfo * const msgInfo = dynamic_cast<KMMsgInfo*>( mMsgList[i] );
+ if ( msgInfo ) {
+ DwString msgString( getDwString( i ) );
+ if ( msgString.size() > 0 ) {
+ KMMessage msg;
+ msg.fromDwString( msgString, false );
+ msg.updateInvitationState();
+ if ( msg.status() & KMMsgStatusHasInvitation ) {
+ msgInfo->setStatus( msgInfo->status() | KMMsgStatusHasInvitation );
+ }
+ if ( msg.status() & KMMsgStatusHasNoInvitation ) {
+ msgInfo->setStatus( msgInfo->status() | KMMsgStatusHasNoInvitation );
+ }
+ msgInfo->setFrom( msg.from() );
+ msgInfo->setTo( msg.to() );
+ }
+ }
+ }
+}
#include "kmfolderindex.moc"
diff --git a/kmail/kmfolderindex.h b/kmail/kmfolderindex.h
index 05453bb68..29039765d 100644
--- a/kmail/kmfolderindex.h
+++ b/kmail/kmfolderindex.h
@@ -48,6 +48,7 @@ public:
*/
enum IndexStatus { IndexOk,
IndexMissing,
+ IndexCorrupt,
IndexTooOld
};
@@ -80,7 +81,16 @@ public:
virtual TQString indexLocation() const;
virtual int writeIndex( bool createEmptyIndex = false );
- void recreateIndex();
+ void recreateIndex( bool readIndexAfterwards = true );
+ void silentlyRecreateIndex();
+
+ /** Tests whether the contents of this folder is newer than the index.
+ Should return IndexTooOld if the index is older than the contents.
+ Should return IndexMissing if there is contents but no index.
+ Should return IndexOk if the folder doesn't exist anymore "physically"
+ or if the index is not older than the contents.
+ */
+ virtual IndexStatus indexStatus() = 0;
public slots:
/** Incrementally update the index if possible else call writeIndex */
@@ -99,14 +109,6 @@ protected:
bool updateIndexStreamPtr(bool just_close=FALSE);
- /** Tests whether the contents of this folder is newer than the index.
- Should return IndexTooOld if the index is older than the contents.
- Should return IndexMissing if there is contents but no index.
- Should return IndexOk if the folder doesn't exist anymore "physically"
- or if the index is not older than the contents.
- */
- virtual IndexStatus indexStatus() = 0;
-
/** Inserts messages into the message dictionary by iterating over the
* message list. The messages will get new serial numbers. This is only
* used on newly appeared folders, where there is no .ids file yet, or
@@ -125,6 +127,10 @@ protected:
int mIndexStreamPtrLength, mIndexId;
bool mIndexSwapByteOrder; // Index file was written with swapped byte order
int mIndexSizeOfLong; // Index file was written with longs of this size
+
+private:
+ void updateInvitationAndAddressFieldsFromContents();
+
};
#endif /*kmfolderindex_h*/
diff --git a/kmail/kmfoldermaildir.cpp b/kmail/kmfoldermaildir.cpp
index bfb606f7e..09800a94d 100644
--- a/kmail/kmfoldermaildir.cpp
+++ b/kmail/kmfoldermaildir.cpp
@@ -224,6 +224,7 @@ int KMFolderMaildir::create()
//-----------------------------------------------------------------------------
void KMFolderMaildir::reallyDoClose(const char* owner)
{
+ Q_UNUSED( owner );
if (mAutoCreateIndex)
{
updateIndex();
@@ -465,9 +466,12 @@ if( fileD0.open( IO_WriteOnly ) ) {
++mTotalMsgs;
mSize = -1;
- if ( aMsg->attachmentState() == KMMsgAttachmentUnknown &&
- aMsg->readyToShow() )
+ if ( aMsg->attachmentState() == KMMsgAttachmentUnknown && aMsg->readyToShow() ) {
aMsg->updateAttachmentState();
+ }
+ if ( aMsg->invitationState() == KMMsgInvitationUnknown && aMsg->readyToShow() ) {
+ aMsg->updateInvitationState();
+ }
// store information about the position in the folder file in the message
aMsg->setParent(folder());
@@ -743,7 +747,7 @@ void KMFolderMaildir::readFileHeaderIntern(const TQString& dir, const TQString&
}
// Is this a long header line?
- if (inHeader && line[0] == '\t' || line[0] == ' ')
+ if (inHeader && ( line[0] == '\t' || line[0] == ' ' ) )
{
int i = 0;
while (line[i] == '\t' || line[i] == ' ')
@@ -901,6 +905,9 @@ int KMFolderMaildir::createIndexFromContents()
KMFolderIndex::IndexStatus KMFolderMaildir::indexStatus()
{
+ if ( !mCompactable )
+ return KMFolderIndex::IndexCorrupt;
+
TQFileInfo new_info(location() + "/new");
TQFileInfo cur_info(location() + "/cur");
TQFileInfo index_info(indexLocation());
diff --git a/kmail/kmfoldermbox.cpp b/kmail/kmfoldermbox.cpp
index dc35328db..c2e60a091 100644
--- a/kmail/kmfoldermbox.cpp
+++ b/kmail/kmfoldermbox.cpp
@@ -94,6 +94,7 @@ KMFolderMbox::~KMFolderMbox()
//-----------------------------------------------------------------------------
int KMFolderMbox::open(const char *owner)
{
+ Q_UNUSED( owner );
int rc = 0;
mOpenCount++;
@@ -258,6 +259,7 @@ int KMFolderMbox::create()
//-----------------------------------------------------------------------------
void KMFolderMbox::reallyDoClose(const char* owner)
{
+ Q_UNUSED( owner );
if (mAutoCreateIndex)
{
if (KMFolderIndex::IndexOk != indexStatus()) {
@@ -521,6 +523,9 @@ int KMFolderMbox::unlock()
//-----------------------------------------------------------------------------
KMFolderIndex::IndexStatus KMFolderMbox::indexStatus()
{
+ if ( !mCompactable )
+ return KMFolderIndex::IndexCorrupt;
+
TQFileInfo contInfo(location());
TQFileInfo indInfo(indexLocation());
@@ -1065,9 +1070,12 @@ if( fileD1.open( IO_WriteOnly ) ) {
++mTotalMsgs;
mSize = -1;
- if ( aMsg->attachmentState() == KMMsgAttachmentUnknown &&
- aMsg->readyToShow() )
+ if ( aMsg->attachmentState() == KMMsgAttachmentUnknown && aMsg->readyToShow() ) {
aMsg->updateAttachmentState();
+ }
+ if ( aMsg->invitationState() == KMMsgInvitationUnknown && aMsg->readyToShow() ) {
+ aMsg->updateInvitationState();
+ }
// store information about the position in the folder file in the message
aMsg->setParent(folder());
@@ -1095,13 +1103,13 @@ if( fileD1.open( IO_WriteOnly ) ) {
revert = ftell(mIndexStream);
KMMsgBase * mb = &aMsg->toMsgBase();
- int len;
- const uchar *buffer = mb->asIndexString(len);
- fwrite(&len,sizeof(len), 1, mIndexStream);
- mb->setIndexOffset( ftell(mIndexStream) );
- mb->setIndexLength( len );
- if(fwrite(buffer, len, 1, mIndexStream) != 1)
- kdDebug(5006) << "Whoa! " << __FILE__ << ":" << __LINE__ << endl;
+ int len;
+ const uchar *buffer = mb->asIndexString(len);
+ fwrite(&len,sizeof(len), 1, mIndexStream);
+ mb->setIndexOffset( ftell(mIndexStream) );
+ mb->setIndexLength( len );
+ if(fwrite(buffer, len, 1, mIndexStream) != 1)
+ kdDebug(5006) << "Whoa! " << __FILE__ << ":" << __LINE__ << endl;
fflush(mIndexStream);
error = ferror(mIndexStream);
diff --git a/kmail/kmfoldersearch.cpp b/kmail/kmfoldersearch.cpp
index 85ba2040f..522785d11 100644
--- a/kmail/kmfoldersearch.cpp
+++ b/kmail/kmfoldersearch.cpp
@@ -547,6 +547,7 @@ void KMFolderSearch::sync()
void KMFolderSearch::reallyDoClose(const char* owner)
{
+ Q_UNUSED( owner );
if (mAutoCreateIndex) {
if (mSearch)
mSearch->write(location());
diff --git a/kmail/kmfolderseldlg.cpp b/kmail/kmfolderseldlg.cpp
index 607b42435..00849b6e7 100644
--- a/kmail/kmfolderseldlg.cpp
+++ b/kmail/kmfolderseldlg.cpp
@@ -2,7 +2,6 @@
#include <config.h>
#include "kmfolderseldlg.h"
-#include "kmfoldertree.h"
#include "kmfolder.h"
#include "kmmainwidget.h"
#include "globalsettings.h"
@@ -14,429 +13,10 @@
#include <tqlayout.h>
#include <tqtoolbutton.h>
-
-namespace KMail {
-
-class FolderItem : public KFolderTreeItem
-{
- public:
- FolderItem( KFolderTree * listView );
- FolderItem( KFolderTreeItem * listViewItem );
-
- void setFolder( KMFolder * folder ) { mFolder = folder; };
- const KMFolder * folder() { return mFolder; };
-
- // Redefine isAlternate() for proper row coloring behavior.
- // KListViewItem::isAlternate() is not virtual! Therefore,
- // it is necessary to overload paintCell() below. If it were
- // made virtual, paintCell() would no longer be necessary.
- bool isAlternate () {
- return mAlternate;
- }
-
- // Set the flag which determines if this is an alternate row
- void setAlternate ( bool alternate ) {
- mAlternate = alternate;
- }
-
- // Must overload paintCell because neither KListViewItem::isAlternate()
- // or KListViewItem::backgroundColor() are virtual!
- virtual void paintCell( TQPainter *p, const TQColorGroup &cg,
- int column, int width, int alignment )
- {
- KListView* view = static_cast< KListView* >( listView() );
-
- // Set alternate background to invalid
- TQColor nocolor;
- TQColor alt = view->alternateBackground();
- view->setAlternateBackground( nocolor );
-
- // Set the base and text to the appropriate colors
- TQColorGroup *cgroup = (TQColorGroup *)&view->viewport()->colorGroup();
- TQColor base = cgroup->base();
- TQColor text = cgroup->text();
- cgroup->setColor( TQColorGroup::Base, isAlternate() ? alt : base );
- cgroup->setColor( TQColorGroup::Text, isEnabled() ? text : Qt::lightGray );
-
- // Call the parent paint routine
- KListViewItem::paintCell( p, cg, column, width, alignment );
-
- // Restore the base and alternate background
- cgroup->setColor( TQColorGroup::Base, base );
- cgroup->setColor( TQColorGroup::Text, text );
- view->setAlternateBackground( alt );
- }
-
- private:
- KMFolder * mFolder;
- bool mAlternate;
-};
-
-//-----------------------------------------------------------------------------
-FolderItem::FolderItem( KFolderTree * listView )
- : KFolderTreeItem( listView ),
- mFolder( 0 )
-{}
-
-//-----------------------------------------------------------------------------
-FolderItem::FolderItem( KFolderTreeItem * listViewItem )
- : KFolderTreeItem( listViewItem ),
- mFolder( 0 )
-{}
-
-//-----------------------------------------------------------------------------
-SimpleFolderTree::SimpleFolderTree( TQWidget * parent,
- KMFolderTree * folderTree,
- const TQString & preSelection,
- bool mustBeReadWrite )
- : KFolderTree( parent ), mFolderTree( folderTree )
-{
- setSelectionModeExt( Single );
- mFolderColumn = addColumn( i18n( "Folder" ), 0 );
- mPathColumn = addColumn( i18n( "Path" ), 0 );
- setAllColumnsShowFocus( true );
- setAlternateBackground( TQColor( 0xf0, 0xf0, 0xf0 ) );
-
- reload( mustBeReadWrite, true, true, preSelection );
- readColorConfig();
-
- applyFilter( "" );
-
- connect(this, TQT_SIGNAL(collapsed(TQListViewItem*)), TQT_SLOT(recolorRows()));
- connect(this, TQT_SIGNAL(expanded(TQListViewItem*)), TQT_SLOT(recolorRows()));
-
- connect( this, TQT_SIGNAL( contextMenuRequested( TQListViewItem*, const TQPoint &, int ) ),
- this, TQT_SLOT( slotContextMenuRequested( TQListViewItem*, const TQPoint & ) ) );
-}
-
-//-----------------------------------------------------------------------------
-void SimpleFolderTree::reload( bool mustBeReadWrite, bool showOutbox,
- bool showImapFolders, const TQString& preSelection )
-{
- mLastMustBeReadWrite = mustBeReadWrite;
- mLastShowOutbox = showOutbox;
- mLastShowImapFolders = showImapFolders;
-
- clear();
- FolderItem * lastItem = 0;
- FolderItem * lastTopItem = 0;
- FolderItem * selectedItem = 0;
- int lastDepth = 0;
-
- TQString selected = preSelection;
- if ( selected.isEmpty() && folder() )
- selected = folder()->idString();
-
- mFilter = "";
- TQString path;
-
- for ( TQListViewItemIterator it( mFolderTree ) ; it.current() ; ++it )
- {
- KMFolderTreeItem * fti = static_cast<KMFolderTreeItem *>( it.current() );
-
- // search folders are never shown
- if ( !fti || fti->protocol() == KFolderTreeItem::Search )
- continue;
-
- // imap folders?
- if ( fti->protocol() == KFolderTreeItem::Imap && !showImapFolders )
- continue;
-
- // the outbox?
- if ( fti->type() == KFolderTreeItem::Outbox && !showOutbox )
- continue;
-
- int depth = fti->depth();// - 1;
- FolderItem * item = 0;
- if ( depth <= 0 ) {
- // top level - first top level item or after last existing top level item
- item = new FolderItem( this );
- if ( lastTopItem )
- item->moveItem( lastTopItem );
- lastTopItem = item;
- depth = 0;
- path = "";
- }
- else {
- if ( depth > lastDepth ) {
- // next lower level - parent node will get opened
- item = new FolderItem( lastItem );
- lastItem->setOpen(true);
- }
- else {
- path = path.section( '/', 0, -2 - (lastDepth-depth) );
-
- if ( depth == lastDepth ) {
- // same level - behind previous item
- item = new FolderItem( static_cast<FolderItem*>(lastItem->parent()) );
- item->moveItem( lastItem );
- } else if ( depth < lastDepth ) {
- // above previous level - might be more than one level difference
- // but highest possibility is top level
- while ( ( depth <= --lastDepth ) && lastItem->parent() ) {
- lastItem = static_cast<FolderItem *>( lastItem->parent() );
- }
- if ( lastItem->parent() ) {
- item = new FolderItem( static_cast<FolderItem*>(lastItem->parent()) );
- item->moveItem( lastItem );
- } else {
- // chain somehow broken - what does cause this ???
- kdDebug( 5006 ) << "You shouldn't get here: depth=" << depth
- << "folder name=" << fti->text( 0 ) << endl;
- item = new FolderItem( this );
- lastTopItem = item;
- }
- }
- }
- }
-
- if ( depth > 0 )
- path += "/";
- path += fti->text( 0 );
-
- item->setText( mFolderColumn, fti->text( 0 ) );
- item->setText( mPathColumn, path );
-
- item->setProtocol( fti->protocol() );
- item->setType( fti->type() );
-
- // Make items without folders and readonly items unselectable
- // if we're told so
- if ( mustBeReadWrite && ( !fti->folder() || fti->folder()->isReadOnly() ) ) {
- item->setSelectable( false );
- } else {
- if ( fti->folder() ) {
- item->setFolder( fti->folder() );
- if ( selected == item->folder()->idString() )
- selectedItem = item;
- }
- }
- lastItem = item;
- lastDepth = depth;
- }
-
- if ( selectedItem ) {
- setSelected( selectedItem, true );
- ensureItemVisible( selectedItem );
- }
-}
-
-//-----------------------------------------------------------------------------
-const KMFolder * SimpleFolderTree::folder() const
-{
- TQListViewItem * item = currentItem();
- if ( item ) {
- const KMFolder * folder = static_cast<FolderItem *>( item )->folder();
- if( folder ) return folder;
- }
- return 0;
-}
-
-//-----------------------------------------------------------------------------
-void SimpleFolderTree::setFolder( KMFolder *folder )
-{
- for ( TQListViewItemIterator it( this ) ; it.current() ; ++it )
- {
- const KMFolder *fld = static_cast<FolderItem *>( it.current() )->folder();
- if ( fld == folder )
- {
- setSelected( it.current(), true );
- ensureItemVisible( it.current() );
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-void SimpleFolderTree::setFolder( const TQString& idString )
-{
- setFolder( kmkernel->findFolderById( idString ) );
-}
-
-//-----------------------------------------------------------------------------
-void SimpleFolderTree::addChildFolder()
-{
- const KMFolder *fld = folder();
- if ( fld ) {
- mFolderTree->addChildFolder( (KMFolder *) fld, parentWidget() );
- reload( mLastMustBeReadWrite, mLastShowOutbox, mLastShowImapFolders );
- setFolder( (KMFolder *) fld );
- }
-}
-
-//-----------------------------------------------------------------------------
-void SimpleFolderTree::slotContextMenuRequested( TQListViewItem *lvi,
- const TQPoint &p )
-{
- if (!lvi)
- return;
- setCurrentItem( lvi );
- setSelected( lvi, TRUE );
-
- const KMFolder * folder = static_cast<FolderItem *>( lvi )->folder();
- if ( !folder || folder->noContent() || folder->noChildren() )
- return;
-
- KPopupMenu *folderMenu = new KPopupMenu;
- folderMenu->insertTitle( folder->label() );
- folderMenu->insertSeparator();
- folderMenu->insertItem(SmallIconSet("folder_new"),
- i18n("&New Subfolder..."), this,
- TQT_SLOT(addChildFolder()));
- kmkernel->setContextMenuShown( true );
- folderMenu->exec (p, 0);
- kmkernel->setContextMenuShown( false );
- delete folderMenu;
- folderMenu = 0;
-}
-
-//-----------------------------------------------------------------------------
-void SimpleFolderTree::readColorConfig (void)
-{
- TQColor c1=TQColor(kapp->palette().active().text());
- TQColor c2=TQColor(kapp->palette().active().base());
-
- mPaintInfo.colFore = c1;
- mPaintInfo.colBack = c2;
-
- TQPalette newPal = kapp->palette();
- newPal.setColor( TQColorGroup::Base, mPaintInfo.colBack );
- newPal.setColor( TQColorGroup::Text, mPaintInfo.colFore );
- setPalette( newPal );
-}
-
-
-//-----------------------------------------------------------------------------
-static int recurseFilter( TQListViewItem * item, const TQString& filter, int column )
-{
- if ( item == 0 )
- return 0;
-
- TQListViewItem * child;
- child = item->firstChild();
-
- int enabled = 0;
- while ( child ) {
- enabled += recurseFilter( child, filter, column );
- child = child->nextSibling();
- }
-
- if ( filter.length() == 0 ||
- item->text( column ).find( filter, 0, false ) >= 0 ) {
- item->setVisible( true );
- ++enabled;
- }
- else {
- item->setVisible( !!enabled );
- item->setEnabled( false );
- }
-
- return enabled;
-}
-
-void SimpleFolderTree::recolorRows()
-{
- // Iterate through the list to set the alternate row flags.
- int alt = 0;
- TQListViewItemIterator it ( this );
- while ( it.current() ) {
- FolderItem * item = static_cast< FolderItem* >( it.current() );
-
- if ( item->isVisible() ) {
- bool visible = true;
- TQListViewItem * parent = item->parent();
- while ( parent ) {
- if (!parent->isOpen()) {
- visible = false;
- break;
- }
- parent = parent->parent();
- }
-
- if ( visible ) {
- item->setAlternate( alt );
- alt = !alt;
- }
- }
-
- ++it;
- }
-}
-
-void SimpleFolderTree::applyFilter( const TQString& filter )
-{
- // Reset all items to visible, enabled, and open
- TQListViewItemIterator clean( this );
- while ( clean.current() ) {
- TQListViewItem * item = clean.current();
- item->setEnabled( true );
- item->setVisible( true );
- item->setOpen( true );
- ++clean;
- }
-
- mFilter = filter;
-
- if ( filter.isEmpty() ) {
- setColumnText( mPathColumn, i18n("Path") );
- return;
- }
-
- // Set the visibility and enabled status of each list item.
- // The recursive algorithm is necessary because visiblity
- // changes are automatically applied to child nodes by Qt.
- TQListViewItemIterator it( this );
- while ( it.current() ) {
- TQListViewItem * item = it.current();
- if ( item->depth() <= 0 )
- recurseFilter( item, filter, mPathColumn );
- ++it;
- }
-
- // Recolor the rows appropriately
- recolorRows();
-
- // Iterate through the list to find the first selectable item
- TQListViewItemIterator first ( this );
- while ( first.current() ) {
- FolderItem * item = static_cast< FolderItem* >( first.current() );
-
- if ( item->isVisible() && item->isSelectable() ) {
- setSelected( item, true );
- ensureItemVisible( item );
- break;
- }
-
- ++first;
- }
-
- // Display and save the current filter
- if ( filter.length() > 0 )
- setColumnText( mPathColumn, i18n("Path") + " ( " + filter + " )" );
- else
- setColumnText( mPathColumn, i18n("Path") );
-
- mFilter = filter;
-}
-
-//-----------------------------------------------------------------------------
-void SimpleFolderTree::keyPressEvent( TQKeyEvent *e ) {
- int ch = e->ascii();
-
- if ( ch >= 32 && ch <= 126 )
- applyFilter( mFilter + ch );
-
- else if ( ch == 8 || ch == 127 ) {
- if ( mFilter.length() > 0 ) {
- mFilter.truncate( mFilter.length()-1 );
- applyFilter( mFilter );
- }
- }
-
- else
- KListView::keyPressEvent( e );
-}
+#include <tqlabel.h>
+using namespace KMail;
//-----------------------------------------------------------------------------
KMFolderSelDlg::KMFolderSelDlg( KMMainWidget * parent, const TQString& caption,
bool mustBeReadWrite, bool useGlobalSettings )
@@ -452,7 +32,9 @@ KMFolderSelDlg::KMFolderSelDlg( KMMainWidget * parent, const TQString& caption,
TQString preSelection = mUseGlobalSettings ?
GlobalSettings::self()->lastSelectedFolder() : TQString::null;
- mTreeView = new KMail::SimpleFolderTree( makeVBoxMainWidget(), ft,
+ TQWidget * container = makeVBoxMainWidget();
+ new TQLabel( i18n("You can start typing to filter the list of folders"), container );
+ mTreeView = new KMail::SimpleFolderTree( container, ft,
preSelection, mustBeReadWrite );
init();
}
@@ -469,7 +51,9 @@ KMFolderSelDlg::KMFolderSelDlg( TQWidget * parent, KMFolderTree * tree,
{
TQString preSelection = mUseGlobalSettings ?
GlobalSettings::self()->lastSelectedFolder() : TQString::null;
- mTreeView = new KMail::SimpleFolderTree( makeVBoxMainWidget(), tree,
+ TQWidget * container = makeVBoxMainWidget();
+ new TQLabel( i18n("You can start typing to filter the list of folders"), container );
+ mTreeView = new KMail::SimpleFolderTree( container, tree,
preSelection, mustBeReadWrite );
init();
}
@@ -547,13 +131,13 @@ void KMFolderSelDlg::readConfig()
TQValueList<int> widths = config->readIntListEntry( "ColumnWidths" );
if ( !widths.isEmpty() ) {
- mTreeView->setColumnWidth(mTreeView->mFolderColumn, widths[0]);
- mTreeView->setColumnWidth(mTreeView->mPathColumn, widths[1]);
+ mTreeView->setColumnWidth(mTreeView->folderColumn(), widths[0]);
+ mTreeView->setColumnWidth(mTreeView->pathColumn(), widths[1]);
}
else {
int colWidth = width() / 2;
- mTreeView->setColumnWidth(mTreeView->mFolderColumn, colWidth);
- mTreeView->setColumnWidth(mTreeView->mPathColumn, colWidth);
+ mTreeView->setColumnWidth(mTreeView->folderColumn(), colWidth);
+ mTreeView->setColumnWidth(mTreeView->pathColumn(), colWidth);
}
}
@@ -564,11 +148,10 @@ void KMFolderSelDlg::writeConfig()
config->writeEntry( "Size", size() );
TQValueList<int> widths;
- widths.push_back(mTreeView->columnWidth(mTreeView->mFolderColumn));
- widths.push_back(mTreeView->columnWidth(mTreeView->mPathColumn));
+ widths.push_back(mTreeView->columnWidth(mTreeView->folderColumn()));
+ widths.push_back(mTreeView->columnWidth(mTreeView->pathColumn()));
config->writeEntry( "ColumnWidths", widths );
}
-} // namespace KMail
#include "kmfolderseldlg.moc"
diff --git a/kmail/kmfolderseldlg.h b/kmail/kmfolderseldlg.h
index 119ceff78..f1637a2f8 100644
--- a/kmail/kmfolderseldlg.h
+++ b/kmail/kmfolderseldlg.h
@@ -7,61 +7,16 @@
#define kmfolderseldlg_h
#include <kdialogbase.h>
-#include <kfoldertree.h>
+#include <simplefoldertree.h>
+#include <tqvaluelist.h>
+#include <tqguardedptr.h>
class KMFolder;
class KMFolderTree;
class KMMainWidget;
+class SimpleFolderTree;
namespace KMail {
-
- class SimpleFolderTree : public KFolderTree
- {
- Q_OBJECT
-
- public:
- SimpleFolderTree( TQWidget * parent, KMFolderTree * folderTree,
- const TQString & preSelection, bool mustBeReadWrite );
-
- /** Reload the tree and select what folders to show and what not */
- void reload( bool mustBeReadWrite, bool showOutbox, bool showImapFolders,
- const TQString& preSelection = TQString::null );
-
- /** Return the current folder */
- const KMFolder * folder() const;
-
- /** Set the current folder */
- void setFolder( KMFolder* );
- void setFolder( const TQString& idString );
-
- /** Apply the given filter. */
- void applyFilter( const TQString& filter );
-
- public slots:
- void addChildFolder();
-
- protected slots:
- void slotContextMenuRequested( TQListViewItem *, const TQPoint & );
- virtual void recolorRows();
-
- protected:
- /** Read color options and set palette. */
- virtual void readColorConfig(void);
- virtual void keyPressEvent( TQKeyEvent *e );
-
- /** Folder and path column IDs. */
- friend class KMFolderSelDlg;
- int mFolderColumn;
- int mPathColumn;
-
- private:
- KMFolderTree* mFolderTree;
- TQString mFilter;
- bool mLastMustBeReadWrite;
- bool mLastShowOutbox;
- bool mLastShowImapFolders;
-};
-
//-----------------------------------------------------------------------------
class KMFolderSelDlg: public KDialogBase
{
diff --git a/kmail/kmfoldertree.cpp b/kmail/kmfoldertree.cpp
index e99e7058b..d2e098b8d 100644
--- a/kmail/kmfoldertree.cpp
+++ b/kmail/kmfoldertree.cpp
@@ -126,7 +126,13 @@ TQPixmap KMFolderTreeItem::normalIcon(int size) const
case Trash: icon = "trashcan_empty"; break;
case Drafts: icon = "edit"; break;
case Templates: icon = "filenew"; break;
- default: icon = kmkernel->iCalIface().folderPixmap( type() ); break;
+ default:
+ {
+ //If not a resource folder don't try to use icalIface folder pixmap
+ if(kmkernel->iCalIface().isResourceFolder( mFolder ))
+ icon = kmkernel->iCalIface().folderPixmap( type() );
+ break;
+ }
}
// non-root search folders
if ( protocol() == KMFolderTreeItem::Search ) {
@@ -177,7 +183,8 @@ TQPixmap KMFolderTreeItem::unreadIcon(int size) const
pm = il->loadIcon( "folder_grey_open", KIcon::Small, size,
KIcon::DefaultState, 0, true );
} else {
- pm = il->loadIcon( kmkernel->iCalIface().folderPixmap( type() ),
+ if( kmkernel->iCalIface().isResourceFolder( mFolder ) )
+ pm = il->loadIcon( kmkernel->iCalIface().folderPixmap( type() ),
KIcon::Small, size, KIcon::DefaultState, 0, true );
if ( pm.isNull() )
pm = il->loadIcon( "folder_open", KIcon::Small, size,
@@ -245,8 +252,15 @@ void KMFolderTreeItem::slotIconsChanged()
{
kdDebug(5006) << k_funcinfo << endl;
// this is prone to change, so better check
+ KFolderTreeItem::Type newType = type();
if( kmkernel->iCalIface().isResourceFolder( mFolder ) )
- setType( kmkernel->iCalIface().folderType(mFolder) );
+ newType = kmkernel->iCalIface().folderType(mFolder);
+
+ // reload the folder tree if the type changed, needed because of the
+ // various type-dependent folder hiding options
+ if ( type() != newType )
+ static_cast<KMFolderTree*>( listView() )->delayedReload();
+ setType( newType );
if ( unreadCount() > 0 )
setPixmap( 0, unreadIcon( iconSize() ) );
@@ -263,6 +277,12 @@ void KMFolderTreeItem::slotNameChanged()
repaint();
}
+void KMFolderTreeItem::slotNoContentChanged()
+{
+ // reload the folder tree if the no content state changed, needed because
+ // we hide no-content folders if their child nodes are hidden
+ TQTimer::singleShot( 0, static_cast<KMFolderTree*>( listView() ), TQT_SLOT(reload()) );
+}
//-----------------------------------------------------------------------------
bool KMFolderTreeItem::acceptDrag(TQDropEvent* e) const
@@ -333,7 +353,7 @@ void KMFolderTreeItem::assignShortcut()
kmkernel->getKMMainWidget(),
listView() );
shorty->exec();
- return;
+ delete shorty;
}
//-----------------------------------------------------------------------------
@@ -362,6 +382,7 @@ KMFolderTree::KMFolderTree( KMMainWidget *mainWidget, TQWidget *parent,
oldSelected = 0;
oldCurrent = 0;
mLastItem = 0;
+ dropItem = 0;
mMainWidget = mainWidget;
mReloading = false;
mCutFolder = false;
@@ -375,7 +396,7 @@ KMFolderTree::KMFolderTree( KMMainWidget *mainWidget, TQWidget *parent,
int namecol = addColumn( i18n("Folder"), 250 );
header()->setStretchEnabled( true, namecol );
-
+ setResizeMode( TQListView::NoColumn );
// connect
connectSignals();
@@ -595,6 +616,16 @@ void KMFolderTree::reload(bool openFolders)
connect(fti->folder(),TQT_SIGNAL(nameChanged()),
fti,TQT_SLOT(slotNameChanged()));
+ disconnect( fti->folder(), TQT_SIGNAL(noContentChanged()),
+ fti, TQT_SLOT(slotNoContentChanged()) );
+ connect( fti->folder(), TQT_SIGNAL(noContentChanged()),
+ fti, TQT_SLOT(slotNoContentChanged()) );
+
+ disconnect( fti->folder(), TQT_SIGNAL(syncStateChanged()),
+ this, TQT_SLOT(slotSyncStateChanged()) );
+ connect( fti->folder(), TQT_SIGNAL(syncStateChanged()),
+ this, TQT_SLOT(slotSyncStateChanged()) );
+
// we want to be noticed of changes to update the unread/total columns
disconnect(fti->folder(), TQT_SIGNAL(msgAdded(KMFolder*,Q_UINT32)),
this,TQT_SLOT(slotUpdateCountsDelayed(KMFolder*)));
@@ -733,6 +764,8 @@ void KMFolderTree::addDirectory( KMFolderDir *fdir, KMFolderTreeItem* parent )
// It is
removeFromFolderToItemMap( folder );
delete fti;
+ // still, it might change in the future, so we better check the change signals
+ connect ( folder, TQT_SIGNAL(noContentChanged()), TQT_SLOT(delayedReload()) );
continue;
}
@@ -986,7 +1019,6 @@ void KMFolderTree::doFolderSelected( TQListViewItem* qlvi, bool keepSelection )
KMFolder* folder = 0;
if (fti) folder = fti->folder();
-
if (mLastItem && mLastItem != fti && mLastItem->folder()
&& (mLastItem->folder()->folderType() == KMFolderTypeImap))
{
@@ -1059,7 +1091,7 @@ void KMFolderTree::slotContextMenuRequested( TQListViewItem *lvi,
TQString createChild = i18n("&New Subfolder...");
if (!fti->folder()) createChild = i18n("&New Folder...");
- if (fti->folder() || (fti->text(0) != i18n("Searches")) && !multiFolder)
+ if ( ( fti->folder() || (fti->text(0) != i18n("Searches")) ) && !multiFolder)
folderMenu->insertItem(SmallIconSet("folder_new"),
createChild, this,
TQT_SLOT(addChildFolder()));
@@ -1086,7 +1118,7 @@ void KMFolderTree::slotContextMenuRequested( TQListViewItem *lvi,
folderToPopupMenu( CopyFolder, this, &mMenuToFolder, copyMenu );
folderMenu->insertItem( i18n("&Copy Folder To"), copyMenu );
- if ( fti->folder()->isMoveable() )
+ if ( fti->folder()->isMoveable() && fti->folder()->canDeleteMessages() )
{
TQPopupMenu *moveMenu = new TQPopupMenu( folderMenu );
folderToPopupMenu( MoveFolder, this, &mMenuToFolder, moveMenu );
@@ -1101,6 +1133,8 @@ void KMFolderTree::slotContextMenuRequested( TQListViewItem *lvi,
if ( !multiFolder )
mMainWidget->action("search_messages")->plug(folderMenu);
+ mMainWidget->action( "archive_folder" )->plug( folderMenu );
+
mMainWidget->action("compact")->plug(folderMenu);
if ( GlobalSettings::self()->enableFavoriteFolderView() ) {
@@ -1123,7 +1157,7 @@ void KMFolderTree::slotContextMenuRequested( TQListViewItem *lvi,
fti->folder()->folderType() == KMFolderTypeCachedImap ))
{
folderMenu->insertItem(SmallIconSet("bookmark_folder"),
- i18n("Subscription..."), mMainWidget,
+ i18n("Serverside Subscription..."), mMainWidget,
TQT_SLOT(slotSubscriptionDialog()));
folderMenu->insertItem(SmallIcon("bookmark_folder"),
i18n("Local Subscription..."), mMainWidget,
@@ -1157,7 +1191,7 @@ void KMFolderTree::slotContextMenuRequested( TQListViewItem *lvi,
fti,
TQT_SLOT(assignShortcut()));
- if ( !fti->folder()->noContent() ) {
+ if ( !fti->folder()->noContent() && fti->folder()->canDeleteMessages() ) {
folderMenu->insertItem( i18n("Expire..."), fti,
TQT_SLOT( slotShowExpiryProperties() ) );
}
@@ -1215,12 +1249,14 @@ static bool folderHasCreateRights( const KMFolder *folder )
bool createRights = true; // we don't have acls for local folders yet
if ( folder && folder->folderType() == KMFolderTypeImap ) {
const KMFolderImap *imapFolder = static_cast<const KMFolderImap*>( folder->storage() );
- createRights = imapFolder->userRights() == 0 || // hack, we should get the acls
- ( imapFolder->userRights() > 0 && ( imapFolder->userRights() & KMail::ACLJobs::Create ) );
+ createRights = imapFolder->userRightsState() != KMail::ACLJobs::Ok || // hack, we should get the acls
+ ( imapFolder->userRightsState() == KMail::ACLJobs::Ok &&
+ ( imapFolder->userRights() & KMail::ACLJobs::Create ) );
} else if ( folder && folder->folderType() == KMFolderTypeCachedImap ) {
const KMFolderCachedImap *dimapFolder = static_cast<const KMFolderCachedImap*>( folder->storage() );
- createRights = dimapFolder->userRights() == 0 ||
- ( dimapFolder->userRights() > 0 && ( dimapFolder->userRights() & KMail::ACLJobs::Create ) );
+ createRights = dimapFolder->userRightsState() != KMail::ACLJobs::Ok ||
+ ( dimapFolder->userRightsState() == KMail::ACLJobs::Ok &&
+ ( dimapFolder->userRights() & KMail::ACLJobs::Create ) );
}
return createRights;
}
@@ -1241,8 +1277,7 @@ void KMFolderTree::addChildFolder( KMFolder *folder, TQWidget * parent )
if (!aFolder->createChildFolder())
return;
if ( !folderHasCreateRights( aFolder ) ) {
- // FIXME: change this message to "Cannot create folder under ..." or similar
- const TQString message = i18n( "<qt>Cannot create folder <b>%1</b> because of insufficient "
+ const TQString message = i18n( "<qt>Cannot create folder under <b>%1</b> because of insufficient "
"permissions on the server. If you think you should be able to create "
"subfolders here, ask your administrator to grant you rights to do so."
"</qt> " ).arg(aFolder->label());
@@ -1953,6 +1988,7 @@ void KMFolderTree::moveOrCopyFolder( TQValueList<TQGuardedPtr<KMFolder> > source
if ( parent->hasNamedFolder( sourceFolderName ) || sourceFolderNames.contains( sourceFolderName ) ) {
KMessageBox::error( this, i18n("<qt>Cannot move or copy folder <b>%1</b> here because a folder with the same name already exists.</qt>")
.arg( sourceFolderName ) );
+ setDragEnabled( true );
return;
}
sourceFolderNames.append( sourceFolderName );
@@ -1963,6 +1999,7 @@ void KMFolderTree::moveOrCopyFolder( TQValueList<TQGuardedPtr<KMFolder> > source
if ( f->moveInProgress() ) {
KMessageBox::error( this, i18n("<qt>Cannot move or copy folder <b>%1</b> because it is not completely copied itself.</qt>")
.arg( sourceFolderName ) );
+ setDragEnabled( true );
return;
}
if ( f->parent() )
@@ -1982,6 +2019,7 @@ void KMFolderTree::moveOrCopyFolder( TQValueList<TQGuardedPtr<KMFolder> > source
if ( folderDir->findRef( source ) != -1 )
{
KMessageBox::error( this, message );
+ setDragEnabled( true );
return;
}
folderDir = folderDir->parent();
@@ -1991,12 +2029,14 @@ void KMFolderTree::moveOrCopyFolder( TQValueList<TQGuardedPtr<KMFolder> > source
if( source && source->child() && parent &&
( parent->path().find( source->child()->path() + "/" ) == 0 ) ) {
KMessageBox::error( this, message );
+ setDragEnabled( true );
return;
}
if( source && source->child()
&& ( parent == source->child() ) ) {
KMessageBox::error( this, message );
+ setDragEnabled( true );
return;
}
}
@@ -2013,6 +2053,7 @@ void KMFolderTree::moveOrCopyFolder( TQValueList<TQGuardedPtr<KMFolder> > source
do {
if ( parentDir == childDir || parentDir->findRef( childDir->owner() ) != -1 ) {
KMessageBox::error( this, i18n("Moving the selected folders is not possible") );
+ setDragEnabled( true );
return;
}
childDir = childDir->parent();
@@ -2106,6 +2147,23 @@ void KMFolderTree::updateCopyActions()
paste->setEnabled( true );
}
+void KMFolderTree::slotSyncStateChanged()
+{
+ // Only emit the signal when a selected folder changes, otherwise the folder menu is updated
+ // too often
+ TQValueList< TQGuardedPtr<KMFolder> > folders = selectedFolders();
+ TQValueList< TQGuardedPtr<KMFolder> >::const_iterator it = folders.constBegin();
+ TQValueList< TQGuardedPtr<KMFolder> >::const_iterator end = folders.constEnd();
+ while ( it != end ) {
+ TQGuardedPtr<KMFolder> folder = *it;
+ if ( folder == sender() ) {
+ emit syncStateChanged();
+ break;
+ }
+ ++it;
+ }
+}
+
void KMFolderTree::slotAddToFavorites()
{
KMail::FavoriteFolderView *favView = mMainWidget->favoriteFolderView();
@@ -2123,4 +2181,9 @@ void KMFolderTree::slotUnhideLocalInbox()
reload();
}
+void KMFolderTree::delayedReload()
+{
+ TQTimer::singleShot( 0, this, TQT_SLOT(reload()) );
+}
+
#include "kmfoldertree.moc"
diff --git a/kmail/kmfoldertree.h b/kmail/kmfoldertree.h
index df23116ab..b7244c6c3 100644
--- a/kmail/kmfoldertree.h
+++ b/kmail/kmfoldertree.h
@@ -88,6 +88,7 @@ public slots:
void slotShowExpiryProperties();
void slotIconsChanged();
void slotNameChanged();
+ void slotNoContentChanged();
void updateCount();
protected:
@@ -115,9 +116,6 @@ public:
/** Save config options */
void writeConfig();
- /** Get/refresh the folder tree */
- virtual void reload(bool openFolders = false);
-
/** Recusively add folders in a folder directory to a listview item. */
virtual void addDirectory( KMFolderDir *fdir, KMFolderTreeItem* parent );
@@ -178,6 +176,9 @@ signals:
/** The selected folder has changed to go to an unread message */
void folderSelectedUnread( KMFolder * );
+ /** The sync state of the _selected_ folder has changed */
+ void syncStateChanged();
+
/** unread/total/size column has changed */
void columnsChanged();
@@ -188,6 +189,9 @@ signals:
void nameChanged( KMFolderTreeItem * );
public slots:
+ /** Get/refresh the folder tree */
+ virtual void reload(bool openFolders = false);
+
/** Select the next folder with unread messages */
void nextUnreadFolder();
@@ -231,6 +235,9 @@ public slots:
/** Pastes a previously copied/cutted folder below the currently selected folder. */
void pasteFolder();
+ /** Reload the folder tree (using a single shot timer) */
+ void delayedReload();
+
protected slots:
// void slotRMB(int, int);
/** called by the folder-manager when the list of folders changed */
@@ -282,6 +289,8 @@ protected slots:
/** Updates copy/cut/paste actions */
void updateCopyActions();
+ void slotSyncStateChanged();
+
protected:
virtual void contentsMousePressEvent( TQMouseEvent *e );
virtual void contentsMouseReleaseEvent(TQMouseEvent* me);
diff --git a/kmail/kmgroupware.cpp b/kmail/kmgroupware.cpp
index 08afc3316..47bcf33b1 100644
--- a/kmail/kmgroupware.cpp
+++ b/kmail/kmgroupware.cpp
@@ -55,8 +55,8 @@ bool vPartFoundAndDecoded( KMMessage* msg, TQString& s )
s = TQString::fromUtf8( msg->bodyDecoded() );
return true;
} else if( DwMime::kTypeMultipart == msg->type() &&
- (DwMime::kSubtypeMixed == msg->subtype() ) ||
- (DwMime::kSubtypeAlternative == msg->subtype() ))
+ ( (DwMime::kSubtypeMixed == msg->subtype() ) ||
+ (DwMime::kSubtypeAlternative == msg->subtype() ) ))
{
// kdDebug(5006) << "KMGroupware looking for TNEF data" << endl;
DwBodyPart* dwPart = msg->findDwBodyPart( DwMime::kTypeApplication,
diff --git a/kmail/kmheaders.cpp b/kmail/kmheaders.cpp
index c0e5c4225..bcfc06f3b 100644
--- a/kmail/kmheaders.cpp
+++ b/kmail/kmheaders.cpp
@@ -85,6 +85,7 @@ TQPixmap* KMHeaders::pixUndefinedEncrypted = 0;
TQPixmap* KMHeaders::pixEncryptionProblematic = 0;
TQPixmap* KMHeaders::pixSignatureProblematic = 0;
TQPixmap* KMHeaders::pixAttachment = 0;
+TQPixmap* KMHeaders::pixInvitation = 0;
TQPixmap* KMHeaders::pixReadFwd = 0;
TQPixmap* KMHeaders::pixReadReplied = 0;
TQPixmap* KMHeaders::pixReadFwdReplied = 0;
@@ -93,7 +94,8 @@ TQPixmap* KMHeaders::pixReadFwdReplied = 0;
//-----------------------------------------------------------------------------
KMHeaders::KMHeaders(KMMainWidget *aOwner, TQWidget *parent,
const char *name) :
- KListView(parent, name)
+ KListView( parent, name ),
+ mIgnoreSortOrderChanges( false )
{
static bool pixmapsLoaded = false;
//qInitImageIO();
@@ -131,6 +133,7 @@ KMHeaders::KMHeaders(KMMainWidget *aOwner, TQWidget *parent,
mPopup->insertItem(i18n("Important"), KPaintInfo::COL_IMPORTANT);
mPopup->insertItem(i18n("Action Item"), KPaintInfo::COL_TODO);
mPopup->insertItem(i18n("Attachment"), KPaintInfo::COL_ATTACHMENT);
+ mPopup->insertItem(i18n("Invitation"), KPaintInfo::COL_INVITATION);
mPopup->insertItem(i18n("Spam/Ham"), KPaintInfo::COL_SPAM_HAM);
mPopup->insertItem(i18n("Watched/Ignored"), KPaintInfo::COL_WATCHED_IGNORED);
mPopup->insertItem(i18n("Signature"), KPaintInfo::COL_SIGNED);
@@ -169,6 +172,7 @@ KMHeaders::KMHeaders(KMMainWidget *aOwner, TQWidget *parent,
pixEncryptionProblematic = new TQPixmap( UserIcon( "kmmsgencryptionproblematic" ) );
pixSignatureProblematic = new TQPixmap( UserIcon( "kmmsgsignatureproblematic" ) );
pixAttachment = new TQPixmap( UserIcon( "kmmsgattachment" ) );
+ pixInvitation = new TQPixmap( UserIcon( "kmmsginvitation" ) );
pixReadFwd = new TQPixmap( UserIcon( "kmmsgread_fwd" ) );
pixReadReplied = new TQPixmap( UserIcon( "kmmsgread_replied" ) );
pixReadFwdReplied = new TQPixmap( UserIcon( "kmmsgread_fwd_replied" ) );
@@ -187,6 +191,7 @@ KMHeaders::KMHeaders(KMMainWidget *aOwner, TQWidget *parent,
mPaintInfo.importantCol = addColumn( *pixFlag , "", 0 );
mPaintInfo.todoCol = addColumn( *pixTodo , "", 0 );
mPaintInfo.attachmentCol = addColumn( *pixAttachment , "", 0 );
+ mPaintInfo.invitationCol = addColumn( *pixInvitation , "", 0 );
mPaintInfo.spamHamCol = addColumn( *pixSpam , "", 0 );
mPaintInfo.watchedIgnoredCol = addColumn( *pixWatched , "", 0 );
mPaintInfo.signedCol = addColumn( *pixFullySigned , "", 0 );
@@ -277,6 +282,15 @@ void KMHeaders::slotToggleColumn(int id, int mode)
moveToCol = 0;
break;
}
+ case KPaintInfo::COL_INVITATION:
+ {
+ show = &mPaintInfo.showInvitation;
+ col = &mPaintInfo.invitationCol;
+ width = pixAttachment->width() + 8;
+ if ( *col == header()->mapToIndex( *col ) )
+ moveToCol = 0;
+ break;
+ }
case KPaintInfo::COL_IMPORTANT:
{
show = &mPaintInfo.showImportant;
@@ -475,6 +489,9 @@ void KMHeaders::readConfig (void)
show = config->readBoolEntry("showAttachmentColumn");
slotToggleColumn(KPaintInfo::COL_ATTACHMENT, show);
+ show = config->readBoolEntry("showInvitationColumn");
+ slotToggleColumn(KPaintInfo::COL_INVITATION, show);
+
show = config->readBoolEntry("showImportantColumn");
slotToggleColumn(KPaintInfo::COL_IMPORTANT, show);
@@ -501,6 +518,7 @@ void KMHeaders::readConfig (void)
mPaintInfo.showCryptoIcons = config->readBoolEntry( "showCryptoIcons", false );
mPaintInfo.showAttachmentIcon = config->readBoolEntry( "showAttachmentIcon", true );
+ mPaintInfo.showInvitationIcon = config->readBoolEntry( "showInvitationIcon", false );
KMime::DateFormatter::FormatType t =
(KMime::DateFormatter::FormatType) config->readNumEntry("dateFormat", KMime::DateFormatter::Fancy ) ;
@@ -538,6 +556,16 @@ void KMHeaders::readConfig (void)
}
}
+//-----------------------------------------------------------------------------
+void KMHeaders::restoreColumnLayout( KConfig *config, const TQString &group )
+{
+ // KListView::restoreLayout() will call setSorting(), which is reimplemented by us.
+ // We don't want to change the sort order, so we set a flag here that is checked in
+ // setSorting().
+ mIgnoreSortOrderChanges = true;
+ restoreLayout( config, group );
+ mIgnoreSortOrderChanges = false;
+}
//-----------------------------------------------------------------------------
void KMHeaders::reset()
@@ -593,7 +621,7 @@ void KMHeaders::readFolderConfig (void)
mCurrentItem = config->readNumEntry("Current", 0);
mCurrentItemSerNum = config->readNumEntry("CurrentSerialNum", 0);
- mPaintInfo.orderOfArrival = config->readBoolEntry( "OrderOfArrival", true );
+ mPaintInfo.orderOfArrival = config->readBoolEntry( "OrderOfArrival", false );
mPaintInfo.status = config->readBoolEntry( "Status", false );
{ //area for config group "Geometry"
@@ -636,6 +664,7 @@ void KMHeaders::writeConfig (void)
KConfigGroupSaver saver(config, "General");
config->writeEntry("showMessageSize" , mPaintInfo.showSize);
config->writeEntry("showAttachmentColumn" , mPaintInfo.showAttachment);
+ config->writeEntry("showInvitationColumn" , mPaintInfo.showInvitation);
config->writeEntry("showImportantColumn" , mPaintInfo.showImportant);
config->writeEntry("showTodoColumn" , mPaintInfo.showTodo);
config->writeEntry("showSpamHamColumn" , mPaintInfo.showSpamHam);
@@ -792,9 +821,19 @@ void KMHeaders::msgChanged()
clear();
return;
}
- int i = topItemIndex();
- int cur = currentItemIndex();
if (!isUpdatesEnabled()) return;
+
+ // Remember selected messages, current message and some scrollbar data, as we have to restore it
+ const TQValueList<int> oldSelectedItems = selectedItems();
+ const int oldCurrentItemIndex = currentItemIndex();
+ const bool scrollbarAtTop = verticalScrollBar() &&
+ verticalScrollBar()->value() == verticalScrollBar()->minValue();
+ const bool scrollbarAtBottom = verticalScrollBar() &&
+ verticalScrollBar()->value() == verticalScrollBar()->maxValue();
+ const HeaderItem * const oldFirstVisibleItem = dynamic_cast<HeaderItem*>( itemAt( TQPoint( 0, 0 ) ) );
+ const int oldOffsetOfFirstVisibleItem = itemRect( oldFirstVisibleItem ).y();
+ const uint oldSerNumOfFirstVisibleItem = oldFirstVisibleItem ? oldFirstVisibleItem->msgSerNum() : 0;
+
TQString msgIdMD5;
TQListViewItem *item = currentItem();
HeaderItem *hi = dynamic_cast<HeaderItem*>(item);
@@ -808,27 +847,26 @@ void KMHeaders::msgChanged()
// prevent IMAP messages from scrolling to top
disconnect(this,TQT_SIGNAL(currentChanged(TQListViewItem*)),
this,TQT_SLOT(highlightMessage(TQListViewItem*)));
- // remember all selected messages
- TQValueList<int> curItems = selectedItems();
+
updateMessageList(); // do not change the selection
- // restore the old state, but move up when there are unread message just out of view
- HeaderItem *topOfList = mItems[i];
- item = firstChild();
- TQListViewItem *unreadItem = 0;
- while(item && item != topOfList) {
- KMMsgBase *msg = mFolder->getMsgBase( static_cast<HeaderItem*>(item)->msgId() );
- if ( msg->isUnread() || msg->isNew() ) {
- if ( !unreadItem )
- unreadItem = item;
- } else
- unreadItem = 0;
- item = item->itemBelow();
- }
- if(unreadItem == 0)
- unreadItem = topOfList;
- setContentsPos( 0, itemPos( unreadItem ));
- setCurrentMsg( cur );
- setSelectedByIndex( curItems, true );
+
+ // Restore scrollbar state and selected and current messages
+ setCurrentMsg( oldCurrentItemIndex );
+ setSelectedByIndex( oldSelectedItems, true );
+ if ( scrollbarAtTop ) {
+ setContentsPos( 0, 0 );
+ } else if ( scrollbarAtBottom ) {
+ setContentsPos( 0, contentsHeight() );
+ } else if ( oldSerNumOfFirstVisibleItem > 0 ) {
+ for ( uint i = 0; i < mItems.size(); ++i ) {
+ const KMMsgBase * const mMsgBase = mFolder->getMsgBase( i );
+ if ( mMsgBase->getMsgSerNum() == oldSerNumOfFirstVisibleItem ) {
+ setContentsPos( 0, itemPos( mItems[i] ) - oldOffsetOfFirstVisibleItem );
+ break;
+ }
+ }
+ }
+
connect(this,TQT_SIGNAL(currentChanged(TQListViewItem*)),
this,TQT_SLOT(highlightMessage(TQListViewItem*)));
@@ -1909,8 +1947,8 @@ void KMHeaders::findUnreadAux( HeaderItem*& item,
if (!msgBase) continue;
if (msgBase->isUnread() || msgBase->isNew())
foundUnreadMessage = true;
- if (!onlyNew && (msgBase->isUnread() || msgBase->isNew())
- || onlyNew && msgBase->isNew())
+ if ( ( !onlyNew && (msgBase->isUnread() || msgBase->isNew()) )
+ || ( onlyNew && msgBase->isNew() ) )
lastUnread = newItem;
if (newItem == item) break;
newItem = static_cast<HeaderItem*>(newItem->itemBelow());
@@ -1941,11 +1979,14 @@ int KMHeaders::findUnread(bool aDirNext, int aStartAt, bool onlyNew, bool accept
if (!item)
return -1;
- if ( !acceptCurrent )
- if (aDirNext)
+ if ( !acceptCurrent ) {
+ if (aDirNext) {
item = static_cast<HeaderItem*>(item->itemBelow());
- else
+ }
+ else {
item = static_cast<HeaderItem*>(item->itemAbove());
+ }
+ }
}
pitem = item;
@@ -2413,9 +2454,7 @@ void KMHeaders::slotRMB()
mOwner->useAction()->plug( menu );
} else {
// show most used actions
- if( !mFolder->isSent() ) {
- mOwner->messageActions()->replyMenu()->plug( menu );
- }
+ mOwner->messageActions()->replyMenu()->plug( menu );
mOwner->forwardMenu()->plug( menu );
if( mOwner->sendAgainAction()->isEnabled() ) {
mOwner->sendAgainAction()->plug( menu );
@@ -2430,7 +2469,7 @@ void KMHeaders::slotRMB()
&mMenuToFolder, msgCopyMenu );
menu->insertItem(i18n("&Copy To"), msgCopyMenu);
- if ( mFolder->isReadOnly() ) {
+ if ( !mFolder->canDeleteMessages() ) {
int id = menu->insertItem( i18n("&Move To") );
menu->setItemEnabled( id, false );
} else {
@@ -2577,6 +2616,9 @@ const KMMsgBase* KMHeaders::getMsgBaseForItem( const TQListViewItem *item ) cons
//-----------------------------------------------------------------------------
void KMHeaders::setSorting( int column, bool ascending )
{
+ if ( mIgnoreSortOrderChanges )
+ return;
+
if (column != -1) {
// carsten: really needed?
// if (column != mSortCol)
@@ -2659,7 +2701,9 @@ void KMHeaders::folderCleared()
void KMHeaders::folderClosed()
{
- mFolder->open( "kmheaders" );
+ if ( mFolder->open( "kmheaders" ) == 0 )
+ updateMessageList();
+ else
folderCleared();
}
@@ -3027,6 +3071,8 @@ bool KMHeaders::readSortOrder( bool set_selection, bool forceJumpToUnread )
bool jumpToUnread = (GlobalSettings::self()->actionEnterFolder() ==
GlobalSettings::EnumActionEnterFolder::SelectFirstUnreadNew) ||
forceJumpToUnread;
+ HeaderItem *oldestItem = 0;
+ HeaderItem *newestItem = 0;
TQMemArray<SortCacheItem *> sortCache(mFolder->count());
bool error = false;
@@ -3330,6 +3376,16 @@ bool KMHeaders::readSortOrder( bool set_selection, bool forceJumpToUnread )
{
unread_exists = true;
}
+
+ if ( !oldestItem || mFolder->getMsgBase( oldestItem->msgId() )->date() >
+ mFolder->getMsgBase( new_kci->id() )->date() ) {
+ oldestItem = khi;
+ }
+
+ if ( !newestItem || mFolder->getMsgBase( newestItem->msgId() )->date() <
+ mFolder->getMsgBase( new_kci->id() )->date() ) {
+ newestItem = khi;
+ }
}
// If we are sorting by date and ascending the top level items are sorted
// ascending and the threads themselves are sorted descending. One wants
@@ -3379,10 +3435,12 @@ bool KMHeaders::readSortOrder( bool set_selection, bool forceJumpToUnread )
}
}
- //show a message
+ // Select a message, depending on the "When entering a folder:" setting
CREATE_TIMER(selection);
START_TIMER(selection);
if(set_selection) {
+
+ // Search for the id of the first unread/new item, should there be any
int first_unread = -1;
if (unread_exists) {
HeaderItem *item = static_cast<HeaderItem*>(firstChild());
@@ -3401,19 +3459,33 @@ bool KMHeaders::readSortOrder( bool set_selection, bool forceJumpToUnread )
}
}
+ // No unread message to select, so either select the newest, oldest or lastest selected
if(first_unread == -1 ) {
- setTopItemByIndex(mTopItem);
- if ( mCurrentItem >= 0 )
+ setTopItemByIndex( mTopItem );
+
+ if ( GlobalSettings::self()->actionEnterFolder() ==
+ GlobalSettings::EnumActionEnterFolder::SelectNewest && newestItem != 0 ) {
+ setCurrentItemByIndex( newestItem->msgId() );
+ }
+ else if ( GlobalSettings::self()->actionEnterFolder() ==
+ GlobalSettings::EnumActionEnterFolder::SelectOldest && oldestItem != 0 ) {
+ setCurrentItemByIndex( oldestItem->msgId() );
+ }
+ else if ( mCurrentItem >= 0 )
setCurrentItemByIndex( mCurrentItem );
else if ( mCurrentItemSerNum > 0 )
setCurrentItemBySerialNum( mCurrentItemSerNum );
else
setCurrentItemByIndex( 0 );
+
+ // There is an unread item to select, so select it
} else {
setCurrentItemByIndex(first_unread);
makeHeaderVisible();
center( contentsX(), itemPos(mItems[first_unread]), 0, 9.0 );
}
+
+ // we are told to not change the selection
} else {
// only reset the selection if we have no current item
if (mCurrentItem <= 0) {
@@ -3503,7 +3575,7 @@ void KMHeaders::updateActions()
cut->setEnabled( false );
} else {
copy->setEnabled( true );
- if ( folder() && folder()->isReadOnly() )
+ if ( folder() && !folder()->canDeleteMessages() )
cut->setEnabled( false );
else
cut->setEnabled( true );
@@ -3534,7 +3606,9 @@ TQValueList< Q_UINT32 > KMHeaders::selectedSernums()
if ( it.current()->isSelected() && it.current()->isVisible() ) {
HeaderItem* item = static_cast<HeaderItem*>( it.current() );
KMMsgBase *msgBase = mFolder->getMsgBase( item->msgId() );
- list.append( msgBase->getMsgSerNum() );
+ if ( msgBase ) {
+ list.append( msgBase->getMsgSerNum() );
+ }
}
}
return list;
@@ -3558,7 +3632,9 @@ TQValueList< Q_UINT32 > KMHeaders::selectedVisibleSernums()
}
HeaderItem *item = static_cast<HeaderItem*>(it.current());
KMMsgBase *msgBase = mFolder->getMsgBase( item->msgId() );
- list.append( msgBase->getMsgSerNum() );
+ if ( msgBase ) {
+ list.append( msgBase->getMsgSerNum() );
+ }
}
++it;
}
diff --git a/kmail/kmheaders.h b/kmail/kmheaders.h
index f0f973d65..4055e3c3b 100644
--- a/kmail/kmheaders.h
+++ b/kmail/kmheaders.h
@@ -133,6 +133,15 @@ public:
/** Read color options and set palette. */
virtual void readColorConfig(void);
+ /**
+ * Same as KListView::restoreLayout(), only that this does _not_ restore the sort order.
+ * This is useful since restoreLayout() doesn't restore the sort order correctly, as
+ * KListView doesn't know about our extended sort order like date of arrival.
+ *
+ * Note that if you want to restore the sort order correctly, call readConfig().
+ */
+ void restoreColumnLayout( KConfig *config, const TQString &group );
+
/** Return the current message */
virtual KMMessage* currentMsg();
/** Return the current list view item */
@@ -197,6 +206,9 @@ public:
*/
bool isMessageCut( Q_UINT32 serNum ) const;
+ /** Write global config options. */
+ virtual void writeConfig(void);
+
signals:
/** emitted when the list view item corresponding to this message
has been selected */
@@ -294,8 +306,8 @@ protected:
*pixFullySigned, *pixPartiallySigned, *pixUndefinedSigned,
*pixFullyEncrypted, *pixPartiallyEncrypted, *pixUndefinedEncrypted,
*pixFiller, *pixEncryptionProblematic,
- *pixSignatureProblematic, *pixAttachment,
- *pixReadFwd, *pixReadReplied, *pixReadFwdReplied,*pixTodo;
+ *pixSignatureProblematic, *pixAttachment, *pixInvitation,
+ *pixReadFwd, *pixReadReplied, *pixReadFwdReplied, *pixTodo;
/** Look for color changes */
virtual bool event(TQEvent *e);
@@ -321,9 +333,6 @@ protected:
/** Write per-folder config options. */
virtual void writeFolderConfig(void);
- /** Write global config options. */
- virtual void writeConfig(void);
-
/** Handle shift and control selection */
virtual void contentsMousePressEvent(TQMouseEvent*);
virtual void contentsMouseReleaseEvent(TQMouseEvent* e);
@@ -389,6 +398,7 @@ private:
NestingPolicy nestingPolicy;
int mSortCol;
bool mSortDescending;
+ bool mIgnoreSortOrderChanges;
struct {
uint ascending : 1;
diff --git a/kmail/kmkernel.cpp b/kmail/kmkernel.cpp
index 9bff9a72c..d0e706f90 100644
--- a/kmail/kmkernel.cpp
+++ b/kmail/kmkernel.cpp
@@ -23,6 +23,7 @@ using KPIM::BroadcastStatus;
#include "kmacctcachedimap.h"
#include "kmfiltermgr.h"
#include "kmfilteraction.h"
+#include "kmheaders.h"
#define REALLY_WANT_KMSENDER
#include "kmsender.h"
#undef REALLY_WANT_KMSENDER
@@ -43,6 +44,7 @@ using KRecentAddress::RecentAddresses;
#include "kmcommands.h"
#include "kmsystemtray.h"
#include "transportmanager.h"
+#include "importarchivedialog.h"
#include <kwin.h>
#include "kmailicalifaceimpl.h"
@@ -91,6 +93,7 @@ using KWallet::Wallet;
#include <kstartupinfo.h>
KMKernel *KMKernel::mySelf = 0;
+static bool s_askingToGoOnline = false;
/********************************************************************/
/* Constructor and destructor */
@@ -316,12 +319,16 @@ bool KMKernel::handleCommandLine( bool noArgsOpensReader )
/********************************************************************/
void KMKernel::checkMail () //might create a new reader but won't show!!
{
+ if ( !kmkernel->askToGoOnline() )
+ return;
kmkernel->acctMgr()->checkMail(false);
}
TQStringList KMKernel::accounts()
{
- return kmkernel->acctMgr()->getAccounts();
+ if( kmkernel->acctMgr() )
+ return kmkernel->acctMgr()->getAccounts();
+ return TQStringList();
}
void KMKernel::checkAccount (const TQString &account) //might create a new reader but won't show!!
@@ -399,8 +406,7 @@ int KMKernel::openComposer (const TQString &to, const TQString &cc,
if( !str.isEmpty() ) {
msg->setBody( TQString::fromLocal8Bit( str ).utf8() );
} else {
- TemplateParser parser( msg, TemplateParser::NewMessage,
- "", false, false, false, false );
+ TemplateParser parser( msg, TemplateParser::NewMessage );
parser.process( NULL, NULL );
}
}
@@ -410,8 +416,7 @@ int KMKernel::openComposer (const TQString &to, const TQString &cc,
}
else
{
- TemplateParser parser( msg, TemplateParser::NewMessage,
- "", false, false, false, false );
+ TemplateParser parser( msg, TemplateParser::NewMessage );
parser.process( NULL, NULL );
}
@@ -481,6 +486,27 @@ int KMKernel::openComposer (const TQString &to, const TQString &cc,
const TQCString &attachContDisp,
const TQCString &attachCharset )
{
+ kdDebug(5006) << "KMKernel::openComposer called (deprecated version)" << endl;
+ return openComposer ( to, cc, bcc, subject, body, hidden,
+ attachName, attachCte, attachData,
+ attachType, attachSubType, attachParamAttr,
+ attachParamValue, attachContDisp, attachCharset, 0 );
+}
+
+int KMKernel::openComposer (const TQString &to, const TQString &cc,
+ const TQString &bcc, const TQString &subject,
+ const TQString &body, int hidden,
+ const TQString &attachName,
+ const TQCString &attachCte,
+ const TQCString &attachData,
+ const TQCString &attachType,
+ const TQCString &attachSubType,
+ const TQCString &attachParamAttr,
+ const TQString &attachParamValue,
+ const TQCString &attachContDisp,
+ const TQCString &attachCharset,
+ unsigned int identity )
+{
kdDebug(5006) << "KMKernel::openComposer()" << endl;
KMMessage *msg = new KMMessage;
@@ -491,11 +517,11 @@ int KMKernel::openComposer (const TQString &to, const TQString &cc,
if ( !bcc.isEmpty() ) msg->setBcc(bcc);
if ( !subject.isEmpty() ) msg->setSubject(subject);
if ( !to.isEmpty() ) msg->setTo(to);
+ if ( identity > 0 ) msg->setHeaderField( "X-KMail-Identity", TQString::number( identity ) );
if ( !body.isEmpty() ) {
msg->setBody(body.utf8());
} else {
- TemplateParser parser( msg, TemplateParser::NewMessage,
- "", false, false, false, false );
+ TemplateParser parser( msg, TemplateParser::NewMessage );
parser.process( NULL, NULL );
}
@@ -557,6 +583,11 @@ int KMKernel::openComposer (const TQString &to, const TQString &cc,
if ( msgPart )
cWin->addAttach(msgPart);
+ if ( isICalInvitation ) {
+ cWin->disableRecipientNumberCheck();
+ cWin->disableForgottenAttachmentsCheck();
+ }
+
if ( hidden == 0 && !iCalAutoSend ) {
cWin->show();
// Activate window - doing this instead of KWin::activateWindow(cWin->winId());
@@ -597,8 +628,7 @@ DCOPRef KMKernel::openComposer(const TQString &to, const TQString &cc,
if (!body.isEmpty()) {
msg->setBody(body.utf8());
} else {
- TemplateParser parser( msg, TemplateParser::NewMessage,
- "", false, false, false, false );
+ TemplateParser parser( msg, TemplateParser::NewMessage );
parser.process( NULL, NULL );
}
@@ -644,13 +674,11 @@ DCOPRef KMKernel::newMessage(const TQString &to,
if (!bcc.isEmpty()) msg->setBcc(bcc);
if ( useFolderId ) {
- TemplateParser parser( msg, TemplateParser::NewMessage,
- "", false, false, false, false );
+ TemplateParser parser( msg, TemplateParser::NewMessage );
parser.process( NULL, folder );
win = makeComposer( msg, id );
} else {
- TemplateParser parser( msg, TemplateParser::NewMessage,
- "", false, false, false, false );
+ TemplateParser parser( msg, TemplateParser::NewMessage );
parser.process( NULL, folder );
win = makeComposer( msg );
}
@@ -1053,6 +1081,14 @@ int KMKernel::dcopAddMessage_fastImport( const TQString & foldername,
return retval;
}
+void KMKernel::showImportArchiveDialog()
+{
+ KMMainWidget *mainWidget = getKMMainWidget();
+ KMail::ImportArchiveDialog *importDialog = new KMail::ImportArchiveDialog( mainWidget, WDestructiveClose );
+ importDialog->setFolder( mainWidget->folderTree()->currentFolder() );
+ importDialog->show();
+}
+
TQStringList KMKernel::folderList() const
{
TQStringList folders;
@@ -1235,7 +1271,13 @@ bool KMKernel::isOffline()
bool KMKernel::askToGoOnline()
{
+ // already asking means we are offline and need to wait anyhow
+ if ( s_askingToGoOnline ) {
+ return false;
+ }
+
if ( kmkernel->isOffline() ) {
+ s_askingToGoOnline = true;
int rc =
KMessageBox::questionYesNo( KMKernel::self()->mainWin(),
i18n("KMail is currently in offline mode. "
@@ -1244,6 +1286,7 @@ bool KMKernel::askToGoOnline()
i18n("Work Online"),
i18n("Work Offline"));
+ s_askingToGoOnline = false;
if( rc == KMessageBox::No ) {
return false;
} else {
@@ -1336,27 +1379,34 @@ void KMKernel::testDir(const char *_name)
// Open a composer for each message found in the dead.letter folder
void KMKernel::recoverDeadLetters()
{
- const TQString pathName = localDataPath();
- TQDir dir( pathName );
- if ( !dir.exists( "autosave" ) )
- return;
-
- KMFolder folder( 0, pathName + "autosave", KMFolderTypeMaildir, false /* no index */ );
- KMFolderOpener openFolder( &folder, "recover" );
- if ( !folder.isOpened() ) {
- perror( "cannot open autosave folder" );
+ TQDir dir( localDataPath() + "autosave/cur" );
+ if ( !dir.exists() ) {
+ kdWarning(5006) << "Autosave directory " << dir.path() << " not found!" << endl;
return;
}
- const int num = folder.count();
- for ( int i = 0; i < num; i++ ) {
- KMMessage *msg = folder.take( 0 );
- if ( msg ) {
- KMail::Composer * win = KMail::makeComposer();
- win->setMsg( msg, false, false, true );
- win->setAutoSaveFilename( msg->fileName() );
- win->show();
+ const TQStringList entryList = dir.entryList( TQDir::Files | TQDir::NoSymLinks, TQDir::Unsorted );
+ for ( unsigned int i = 0; i < entryList.size(); i++ ) {
+ const TQString fileName = entryList[i];
+ TQFile file( dir.path() + '/' + fileName );
+ if ( !file.open( IO_ReadOnly ) ) {
+ kdWarning(5006) << "Unable to open autosave file " << fileName << endl;
+ continue;
}
+ const TQByteArray msgData = file.readAll();
+ file.close();
+
+ if ( msgData.isEmpty() ) {
+ kdWarning(5006) << "autosave file " << fileName << " is empty!" << endl;
+ continue;
+ }
+
+ KMMessage *msg = new KMMessage(); // Composer will take ownership
+ msg->fromByteArray( msgData );
+ KMail::Composer * win = KMail::makeComposer();
+ win->setMsg( msg, false, false, true );
+ win->setAutoSaveFilename( fileName );
+ win->show();
}
}
@@ -1475,6 +1525,7 @@ void KMKernel::init()
the_folderMgr = new KMFolderMgr(foldersPath);
the_imapFolderMgr = new KMFolderMgr( KMFolderImap::cacheLocation(), KMImapDir);
the_dimapFolderMgr = new KMFolderMgr( KMFolderCachedImap::cacheLocation(), KMDImapDir);
+ recreateCorruptIndexFiles();
the_searchFolderMgr = new KMFolderMgr(locateLocal("data","kmail/search"), KMSearchDir);
KMFolder *lsf = the_searchFolderMgr->find( i18n("Last Search") );
@@ -1533,6 +1584,20 @@ void KMKernel::init()
#else
mBackgroundTasksTimer->start( 5 * 60000, true ); // 5 minutes, singleshot
#endif
+
+ TQTextCodec *codec;
+ for ( int i = 0; ( codec = TQTextCodec::codecForIndex ( i ) ); i++ ) {
+ const TQString asciiString( "azAZ19,.-#+!?=()&" );
+ const TQCString encodedString = codec->fromUnicode( asciiString );
+ if ( TQString::fromAscii( encodedString ) != asciiString ) {
+ mNonAsciiCompatibleCodecs.append( codec );
+ }
+ }
+}
+
+bool KMKernel::isCodecAsciiCompatible( const TQTextCodec *codec )
+{
+ return !mNonAsciiCompatibleCodecs.contains( codec );
}
void KMKernel::readConfig()
@@ -1624,6 +1689,43 @@ void KMKernel::cleanupImapFolders()
the_dimapFolderMgr->quiet( false );
}
+void KMKernel::recreateCorruptIndexFiles()
+{
+ TQValueList<TQGuardedPtr<KMFolder> > folders;
+ TQValueList<KMFolderIndex*> foldersWithBrokenIndex;
+ TQStringList strList;
+ the_folderMgr->createFolderList( &strList, &folders );
+ the_imapFolderMgr->createFolderList( &strList, &folders );
+ the_dimapFolderMgr->createFolderList( &strList, &folders );
+ for ( int i = 0; folders.at(i) != folders.end(); i++ ) {
+ KMFolder * const folder = *folders.at(i);
+ if ( !folder || folder->isDir() || folder->isOpened() )
+ continue;
+ KMFolderIndex * const index = dynamic_cast<KMFolderIndex*>( folder->storage() );
+ if ( index && index->indexStatus() != KMFolderIndex::IndexOk ) {
+ foldersWithBrokenIndex.append( index );
+ }
+ }
+
+ if ( !foldersWithBrokenIndex.isEmpty() ) {
+ TQStringList folderNames;
+ for ( uint i = 0; i < foldersWithBrokenIndex.size(); i++ ) {
+ folderNames << foldersWithBrokenIndex[i]->label();
+ }
+
+ KMessageBox::informationList( 0, i18n( "There is a problem with the mail index of the following "
+ "folders, the indices will now be regenerated.\n"
+ "This can happen because the index files are out of date, missing or corrupted.\n"
+ "Contact your administrator if this happens frequently.\n"
+ "Some information, like status flags, might get lost." ),
+ folderNames, i18n( "Problem with mail indices" ) );
+
+ for ( uint i = 0; i < foldersWithBrokenIndex.size(); i++ ) {
+ foldersWithBrokenIndex[i]->silentlyRecreateIndex();
+ }
+ }
+}
+
bool KMKernel::doSessionManagement()
{
@@ -1865,9 +1967,17 @@ void KMKernel::dumpDeadLetters()
if ( !KMainWindow::memberList )
return;
- for ( TQPtrListIterator<KMainWindow> it(*KMainWindow::memberList) ; it.current() != 0; ++it )
- if ( KMail::Composer * win = ::qt_cast<KMail::Composer*>( it.current() ) )
+ for ( TQPtrListIterator<KMainWindow> it(*KMainWindow::memberList) ; it.current() != 0; ++it ) {
+ if ( KMail::Composer * win = ::qt_cast<KMail::Composer*>( it.current() ) ) {
win->autoSaveMessage();
+ // saving the message has to be finished right here, we are called from a dtor,
+ // therefore we have no chance to finish this later
+ // yes, this is ugly and potentially dangerous, but the alternative is losing
+ // currently composed messages...
+ while ( win->isComposing() )
+ qApp->processEvents();
+ }
+ }
}
@@ -1955,7 +2065,7 @@ void KMKernel::slotShowConfigurationDialog()
{
if( !mConfigureDialog ) {
mConfigureDialog = new ConfigureDialog( 0, "configure", false );
- connect( mConfigureDialog, TQT_SIGNAL( configCommitted() ),
+ connect( mConfigureDialog, TQT_SIGNAL( configChanged() ),
this, TQT_SLOT( slotConfigChanged() ) );
}
@@ -1967,9 +2077,11 @@ void KMKernel::slotShowConfigurationDialog()
KMMainWin * win = new KMMainWin;
win->show();
}
-
if( mConfigureDialog->isHidden() )
+ {
+ getKMMainWidget()->headers()->writeConfig();
mConfigureDialog->show();
+ }
else
mConfigureDialog->raise();
}
@@ -2326,7 +2438,7 @@ bool KMKernel::canQueryClose()
if ( systray->mode() == GlobalSettings::EnumSystemTrayPolicy::ShowAlways ) {
systray->hideKMail();
return false;
- } else if ( systray->mode() == GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread ) {
+ } else if ( ( systray->mode() == GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread ) && ( systray->hasUnreadMail() )) {
systray->show();
systray->hideKMail();
return false;
diff --git a/kmail/kmkernel.h b/kmail/kmkernel.h
index 02f3e437b..455e42334 100644
--- a/kmail/kmkernel.h
+++ b/kmail/kmkernel.h
@@ -135,6 +135,9 @@ public:
const TQString &attachParamValue,
const TQCString &attachContDisp);
+ /** For backward compatibility
+ * @deprecated
+ */
int openComposer (const TQString &to, const TQString &cc,
const TQString &bcc, const TQString &subject,
const TQString &body, int hidden,
@@ -148,6 +151,20 @@ public:
const TQCString &attachContDisp,
const TQCString &attachCharset);
+ int openComposer (const TQString &to, const TQString &cc,
+ const TQString &bcc, const TQString &subject,
+ const TQString &body, int hidden,
+ const TQString &attachName,
+ const TQCString &attachCte,
+ const TQCString &attachData,
+ const TQCString &attachType,
+ const TQCString &attachSubType,
+ const TQCString &attachParamAttr,
+ const TQString &attachParamValue,
+ const TQCString &attachContDisp,
+ const TQCString &attachCharset,
+ unsigned int identity);
+
DCOPRef openComposer(const TQString &to, const TQString &cc,
const TQString &bcc, const TQString &subject,
const TQString &body,bool hidden);
@@ -179,6 +196,7 @@ public:
const TQString & MsgStatusFlags = TQString());
int dcopAddMessage_fastImport(const TQString & foldername, const KURL & messagefile,
const TQString & MsgStatusFlags = TQString());
+ void showImportArchiveDialog();
TQStringList folderList() const;
DCOPRef getFolder( const TQString& vpath );
@@ -235,6 +253,7 @@ public:
void init();
void readConfig();
void cleanupImapFolders();
+ void recreateCorruptIndexFiles();
void testDir(const char *_name);
void recoverDeadLetters();
void initFolders(KConfig* cfg);
@@ -389,6 +408,8 @@ public:
void loadProfile( const TQString& path );
void saveToProfile( const TQString& path ) const;
+
+ bool isCodecAsciiCompatible( const TQTextCodec *codec );
public slots:
/// Save contents of all open composer widnows to ~/dead.letter
@@ -488,6 +509,7 @@ private:
bool mContextMenuShown;
TQValueList<const KSystemTray*> systemTrayApplets;
+ TQValueList<const TQTextCodec*> mNonAsciiCompatibleCodecs;
/* Weaver */
KPIM::ThreadWeaver::Weaver *the_weaver;
diff --git a/kmail/kmlineeditspell.cpp b/kmail/kmlineeditspell.cpp
index 835421873..dde827bec 100644
--- a/kmail/kmlineeditspell.cpp
+++ b/kmail/kmlineeditspell.cpp
@@ -8,6 +8,7 @@
#include "recentaddresses.h"
#include "kmkernel.h"
#include "globalsettings.h"
+#include "stringutil.h"
#include <libkdepim/kvcarddrag.h>
#include <libemailfunctions/email.h>
@@ -78,52 +79,74 @@ void KMLineEdit::insertEmails( const TQStringList & emails )
for ( TQStringList::const_iterator it = emails.begin(), end = emails.end() ; it != end; ++it )
menu.insertItem( *it );
const int result = menu.exec( TQCursor::pos() );
- if ( result < 0 )
+ if ( result == -1 )
return;
setText( contents + menu.text( result ) );
}
-void KMLineEdit::dropEvent(TQDropEvent *event)
+void KMLineEdit::dropEvent( TQDropEvent *event )
{
- TQString vcards;
- KVCardDrag::decode( event, vcards );
- if ( !vcards.isEmpty() ) {
- KABC::VCardConverter converter;
- KABC::Addressee::List list = converter.parseVCards( vcards );
+ KURL::List urls;
+
+ // Case one: The user dropped a text/directory (i.e. vcard), so decode its
+ // contents
+ if ( KVCardDrag::canDecode( event ) ) {
+ KABC::Addressee::List list;
+ KVCardDrag::decode( event, list );
+
KABC::Addressee::List::Iterator ait;
for ( ait = list.begin(); ait != list.end(); ++ait ){
insertEmails( (*ait).emails() );
}
- } else {
- KURL::List urls;
- if ( KURLDrag::decode( event, urls) ) {
- //kdDebug(5006) << "urlList" << endl;
- KURL::List::Iterator it = urls.begin();
- KABC::VCardConverter converter;
- KABC::Addressee::List list;
- TQString fileName;
- TQString caption( i18n( "vCard Import Failed" ) );
- for ( it = urls.begin(); it != urls.end(); ++it ) {
- if ( KIO::NetAccess::download( *it, fileName, parentWidget() ) ) {
+ }
+
+ // Case two: The user dropped a list or Urls.
+ // Iterate over that list. For mailto: Urls, just add the addressee to the list,
+ // and for other Urls, download the Url and assume it points to a vCard
+ else if ( KURLDrag::decode( event, urls ) ) {
+ KURL::List::Iterator it = urls.begin();
+ KABC::Addressee::List list;
+ for ( it = urls.begin(); it != urls.end(); ++it ) {
+
+ // First, let's deal with mailto Urls. The path() part contains the
+ // email-address.
+ if ( (*it).protocol() == "mailto" ) {
+ KABC::Addressee addressee;
+ addressee.insertEmail( KMail::StringUtil::decodeMailtoUrl( (*it).path() ), true /* preferred */ );
+ list += addressee;
+ }
+ // Otherwise, download the vCard to which the Url points
+ else {
+ KABC::VCardConverter converter;
+ TQString fileName;
+ if ( KIO::NetAccess::download( (*it), fileName, parentWidget() ) ) {
TQFile file( fileName );
file.open( IO_ReadOnly );
- TQByteArray rawData = file.readAll();
+ const TQByteArray data = file.readAll();
file.close();
- TQString data = TQString::fromUtf8( rawData.data(), rawData.size() + 1 );
+#if defined(KABC_VCARD_ENCODING_FIX)
+ list += converter.parseVCardsRaw( data.data() );
+#else
list += converter.parseVCards( data );
+#endif
KIO::NetAccess::removeTempFile( fileName );
} else {
- TQString text = i18n( "<qt>Unable to access <b>%1</b>.</qt>" );
- KMessageBox::error( parentWidget(), text.arg( (*it).url() ), caption );
+ TQString caption( i18n( "vCard Import Failed" ) );
+ TQString text = i18n( "<qt>Unable to access <b>%1</b>.</qt>" ).arg( (*it).url() );
+ KMessageBox::error( parentWidget(), text, caption );
}
- KABC::Addressee::List::Iterator ait;
- for ( ait = list.begin(); ait != list.end(); ++ait )
- insertEmails((*ait).emails());
}
- } else {
- KPIM::AddresseeLineEdit::dropEvent( event );
+ // Now, let the user choose which addressee to add.
+ KABC::Addressee::List::Iterator ait;
+ for ( ait = list.begin(); ait != list.end(); ++ait )
+ insertEmails( (*ait).emails() );
}
}
+
+ // Case three: Let AddresseeLineEdit deal with the rest
+ else {
+ KPIM::AddresseeLineEdit::dropEvent( event );
+ }
}
TQPopupMenu *KMLineEdit::createPopupMenu()
@@ -156,7 +179,6 @@ void KMLineEdit::editRecentAddresses()
//-----------------------------------------------------------------------------
void KMLineEdit::loadContacts()
{
- // was: KABC::AddressLineEdit::loadAddresses()
AddresseeLineEdit::loadContacts();
if ( GlobalSettings::self()->showRecentAddressesInComposer() ){
@@ -165,13 +187,22 @@ void KMLineEdit::loadContacts()
KRecentAddress::RecentAddresses::self( KMKernel::config() )->addresses();
TQStringList::Iterator it = recent.begin();
TQString name, email;
- int idx = addCompletionSource( i18n( "Recent Addresses" ) );
+
+ KConfig config( "kpimcompletionorder" );
+ config.setGroup( "CompletionWeights" );
+ int weight = config.readEntry( "Recent Addresses", "10" ).toInt();
+ int idx = addCompletionSource( i18n( "Recent Addresses" ), weight );
for ( ; it != recent.end(); ++it ) {
KABC::Addressee addr;
KPIM::getNameAndMail(*it, name, email);
- addr.setNameFromString( KPIM::quoteNameIfNecessary( name ));
+ name = KPIM::quoteNameIfNecessary( name );
+ if ( ( name[0] == '"' ) && ( name[name.length() - 1] == '"' ) ) {
+ name.remove( 0, 1 );
+ name.truncate( name.length() - 1 );
+ }
+ addr.setNameFromString( name );
addr.insertEmail( email, true );
- addContact( addr, 120, idx ); // more weight than kabc entries and more than ldap results
+ addContact( addr, weight, idx );
}
}
}
diff --git a/kmail/kmmainwidget.cpp b/kmail/kmmainwidget.cpp
index 0b847ba64..27b04df0d 100644
--- a/kmail/kmmainwidget.cpp
+++ b/kmail/kmmainwidget.cpp
@@ -18,15 +18,13 @@
#include <tqhbox.h>
#include <tqvbox.h>
#include <tqpopupmenu.h>
-#include <tqpushbutton.h>
#include <tqptrlist.h>
+#include <tqsignalmapper.h>
+#include <tqvaluevector.h>
+#include <tqstylesheet.h>
#include <kopenwith.h>
-
#include <kmessagebox.h>
-#include <klistviewsearchline.h>
-#include <kiconloader.h>
-
#include <kpopupmenu.h>
#include <kaccelmanager.h>
#include <kglobalsettings.h>
@@ -45,8 +43,6 @@
#include <kaccel.h>
#include <kstringhandler.h>
-#include <tqvaluevector.h>
-
#include "globalsettings.h"
#include "kcursorsaver.h"
#include "broadcaststatus.h"
@@ -80,9 +76,6 @@ using KMail::ImapAccountBase;
#include "vacation.h"
using KMail::Vacation;
#include "favoritefolderview.h"
-
-#include <tqsignalmapper.h>
-
#include "subscriptiondialog.h"
using KMail::SubscriptionDialog;
#include "localsubscriptiondialog.h"
@@ -106,6 +99,9 @@ using KMail::HeaderListQuickSearch;
#include "kmheaders.h"
#include "mailinglistpropertiesdialog.h"
#include "templateparser.h"
+#include "archivefolderdialog.h"
+#include "folderutil.h"
+#include "csshelper.h"
#if !defined(NDEBUG)
#include "sievedebugdialog.h"
@@ -129,7 +125,6 @@ using KMime::Types::AddrSpecList;
using KPIM::ProgressManager;
#include "managesievescriptsdialog.h"
-#include <tqstylesheet.h>
#include "customtemplates.h"
#include "customtemplates_kfg.h"
@@ -150,6 +145,7 @@ KMMainWidget::KMMainWidget(TQWidget *parent, const char *name,
mFolderViewParent( 0 ),
mFolderViewSplitter( 0 ),
mQuickSearchLine( 0 ),
+ mArchiveFolderAction( 0 ),
mShowBusySplashTimer( 0 ),
mShowingOfflineScreen( false ),
mMsgActions( 0 ),
@@ -226,6 +222,8 @@ KMMainWidget::KMMainWidget(TQWidget *parent, const char *name,
this, TQT_SLOT(slotChangeCaption(TQListViewItem*)));
connect(mFolderTree, TQT_SIGNAL(selectionChanged()),
TQT_SLOT(updateFolderMenu()) );
+ connect( mFolderTree, TQT_SIGNAL(syncStateChanged()),
+ TQT_SLOT(updateFolderMenu()) );
connect(kmkernel->folderMgr(), TQT_SIGNAL(folderRemoved(KMFolder*)),
this, TQT_SLOT(slotFolderRemoved(KMFolder*)));
@@ -300,8 +298,6 @@ void KMMainWidget::readPreConfig(void)
mHtmlPref = reader.readBoolEntry( "htmlMail", false );
mHtmlLoadExtPref = reader.readBoolEntry( "htmlLoadExternal", false );
mEnableFavoriteFolderView = GlobalSettings::self()->enableFavoriteFolderView();
- mEnableFolderQuickSearch = GlobalSettings::self()->enableFolderQuickSearch();
- mEnableQuickSearch = GlobalSettings::self()->quickSearchActive();
}
@@ -344,8 +340,6 @@ void KMMainWidget::readConfig(void)
bool oldReaderWindowActive = mReaderWindowActive;
bool oldReaderWindowBelow = mReaderWindowBelow;
bool oldFavoriteFolderView = mEnableFavoriteFolderView;
- bool oldFolderQuickSearch = mEnableFolderQuickSearch;
- bool oldQuickSearch = mEnableQuickSearch;
TQString str;
TQSize siz;
@@ -360,9 +354,7 @@ void KMMainWidget::readConfig(void)
bool layoutChanged = ( oldLongFolderList != mLongFolderList )
|| ( oldReaderWindowActive != mReaderWindowActive )
|| ( oldReaderWindowBelow != mReaderWindowBelow )
- || ( oldFavoriteFolderView != mEnableFavoriteFolderView )
- || ( oldFolderQuickSearch != mEnableFolderQuickSearch )
- || ( oldQuickSearch != mEnableQuickSearch );
+ || ( oldFavoriteFolderView != mEnableFavoriteFolderView );
if( layoutChanged ) {
@@ -450,7 +442,7 @@ void KMMainWidget::readConfig(void)
mMsgView->readConfig();
mHeaders->readConfig();
- mHeaders->restoreLayout(KMKernel::config(), "Header-Geometry");
+ mHeaders->restoreColumnLayout( KMKernel::config(), "Header-Geometry" );
if ( mFolderViewSplitter && !GlobalSettings::self()->folderViewSplitterPosition().isEmpty() ) {
mFolderViewSplitter->setSizes( GlobalSettings::self()->folderViewSplitterPosition() );
@@ -493,9 +485,7 @@ void KMMainWidget::readConfig(void)
bool layoutChanged = ( oldLongFolderList != mLongFolderList )
|| ( oldReaderWindowActive != mReaderWindowActive )
|| ( oldReaderWindowBelow != mReaderWindowBelow )
- || ( oldFavoriteFolderView != mEnableFavoriteFolderView )
- || ( oldFolderQuickSearch != mEnableFolderQuickSearch )
- || ( oldQuickSearch != mEnableQuickSearch );
+ || ( oldFavoriteFolderView != mEnableFavoriteFolderView );
if ( layoutChanged ) {
activatePanners();
}
@@ -671,10 +661,10 @@ void KMMainWidget::createWidgets(void)
KAction *action;
- action = new KAction( i18n("Move Message to Folder"), Key_M, this,
+ mMoveMsgToFolderAction = new KAction( i18n("Move Message to Folder"), Key_M, this,
TQT_SLOT(slotMoveMsg()), actionCollection(),
"move_message_to_folder" );
- action->plugAccel( actionCollection()->kaccel() );
+ mMoveMsgToFolderAction->plugAccel( actionCollection()->kaccel() );
action = new KAction( i18n("Copy Message to Folder"), Key_C, this,
TQT_SLOT(slotCopyMsg()), actionCollection(),
@@ -697,25 +687,9 @@ void KMMainWidget::createWidgets(void)
folderTreeParent = mFolderViewSplitter;
mFolderView = mFolderViewSplitter;
}
-
- // the "folder tree" consists of a quicksearch input field and the tree itself
- mSearchAndTree = new TQVBox(folderTreeParent);
- mFolderQuickSearch = new TQHBox(mSearchAndTree);
- TQPushButton *clear = new TQPushButton(TQApplication::reverseLayout()
- ? SmallIcon("clear_left")
- : SmallIcon("locationbar_erase"), "", mFolderQuickSearch);
- clear->setFlat(true);
- KListViewSearchLine *search = new KListViewSearchLine(mFolderQuickSearch);
- mFolderTree = new KMFolderTree(this, mSearchAndTree, "folderTree");
- search->setListView(mFolderTree);
- connect(clear, TQT_SIGNAL(clicked()), search, TQT_SLOT(clear()));
-
- if ( !GlobalSettings::enableFolderQuickSearch() ) {
- mFolderQuickSearch->hide();
- }
-
+ mFolderTree = new KMFolderTree(this, folderTreeParent, "folderTree");
if ( !GlobalSettings::enableFavoriteFolderView() ) {
- mFolderView = mSearchAndTree;
+ mFolderView = mFolderTree;
}
connect( mFolderTree, TQT_SIGNAL(folderSelected(KMFolder*)),
mFavoriteFolderView, TQT_SLOT(folderTreeSelectionChanged(KMFolder*)) );
@@ -1020,14 +994,12 @@ void KMMainWidget::slotCompose()
if ( mFolder ) {
msg->initHeader( mFolder->identity() );
- TemplateParser parser( msg, TemplateParser::NewMessage,
- "", false, false, false, false );
+ TemplateParser parser( msg, TemplateParser::NewMessage );
parser.process( NULL, mFolder );
win = KMail::makeComposer( msg, mFolder->identity() );
} else {
msg->initHeader();
- TemplateParser parser( msg, TemplateParser::NewMessage,
- "", false, false, false, false );
+ TemplateParser parser( msg, TemplateParser::NewMessage );
parser.process( NULL, NULL );
win = KMail::makeComposer( msg );
}
@@ -1128,6 +1100,9 @@ void KMMainWidget::modifyFolder( KMFolderTreeItem* folderItem )
i18n("Properties of Folder %1").arg( folder->label() ) );
props.exec();
updateFolderMenu();
+ //Kolab issue 2152
+ if ( mSystemTray )
+ mSystemTray->foldersChanged();
}
//-----------------------------------------------------------------------------
@@ -1204,6 +1179,13 @@ void KMMainWidget::slotEmptyFolder()
mEmptyFolderAction->setEnabled( false );
}
+//-----------------------------------------------------------------------------
+void KMMainWidget::slotArchiveFolder()
+{
+ KMail::ArchiveFolderDialog archiveDialog;
+ archiveDialog.setFolder( mFolder );
+ archiveDialog.exec();
+}
//-----------------------------------------------------------------------------
void KMMainWidget::slotRemoveFolder()
@@ -1214,6 +1196,13 @@ void KMMainWidget::slotRemoveFolder()
if ( !mFolder ) return;
if ( mFolder->isSystemFolder() ) return;
if ( mFolder->isReadOnly() ) return;
+ if ( mFolder->mailCheckInProgress() ) {
+ KMessageBox::sorry( this, i18n( "It is not possible to delete this folder right now because it "
+ "is being syncronized. Please wait until the syncronization of "
+ "this folder is complete and then try again." ),
+ i18n( "Unable to delete folder" ) );
+ return;
+ }
TQString title;
if ( mFolder->folderType() == KMFolderTypeSearch ) {
@@ -1259,32 +1248,7 @@ void KMMainWidget::slotRemoveFolder()
KGuiItem( i18n("&Delete"), "editdelete"))
== KMessageBox::Continue)
{
- if ( mFolder->hasAccounts() ) {
- // this folder has an account, so we need to change that to the inbox
- for ( AccountList::Iterator it (mFolder->acctList()->begin() ),
- end( mFolder->acctList()->end() ); it != end; ++it ) {
- (*it)->setFolder( kmkernel->inboxFolder() );
- KMessageBox::information(this,
- i18n("<qt>The folder you deleted was associated with the account "
- "<b>%1</b> which delivered mail into it. The folder the account "
- "delivers new mail into was reset to the main Inbox folder.</qt>").arg( (*it)->name()));
- }
- }
- if (mFolder->folderType() == KMFolderTypeImap)
- kmkernel->imapFolderMgr()->remove(mFolder);
- else if (mFolder->folderType() == KMFolderTypeCachedImap) {
- // Deleted by user -> tell the account (see KMFolderCachedImap::listDirectory2)
- KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>( mFolder->storage() );
- KMAcctCachedImap* acct = storage->account();
- if ( acct )
- acct->addDeletedFolder( mFolder );
-
- kmkernel->dimapFolderMgr()->remove(mFolder);
- }
- else if (mFolder->folderType() == KMFolderTypeSearch)
- kmkernel->searchFolderMgr()->remove(mFolder);
- else
- kmkernel->folderMgr()->remove(mFolder);
+ KMail::FolderUtil::deleteFolder( mFolder, this );
}
}
@@ -1328,7 +1292,7 @@ void KMMainWidget::slotRefreshFolder()
imap->getAndCheckFolder();
} else if ( mFolder->folderType() == KMFolderTypeCachedImap ) {
KMFolderCachedImap* f = static_cast<KMFolderCachedImap*>( mFolder->storage() );
- f->account()->processNewMailSingleFolder( mFolder );
+ f->account()->processNewMailInFolder( mFolder );
}
}
}
@@ -1444,6 +1408,18 @@ void KMMainWidget::slotToggleSubjectThreading()
}
//-----------------------------------------------------------------------------
+void KMMainWidget::slotToggleShowQuickSearch()
+{
+ GlobalSettings::self()->setQuickSearchActive( !GlobalSettings::self()->quickSearchActive() );
+ if ( GlobalSettings::self()->quickSearchActive() )
+ mSearchToolBar->show();
+ else {
+ mQuickSearchLine->reset();
+ mSearchToolBar->hide();
+ }
+}
+
+//-----------------------------------------------------------------------------
void KMMainWidget::slotMessageQueuedOrDrafted()
{
if (!kmkernel->folderIsDraftOrOutbox(mFolder))
@@ -1670,6 +1646,7 @@ void KMMainWidget::slotUndo()
{
mHeaders->undo();
updateMessageActions();
+ updateFolderMenu();
}
//-----------------------------------------------------------------------------
@@ -1827,22 +1804,69 @@ void KMMainWidget::slotCopyMsg()
//-----------------------------------------------------------------------------
void KMMainWidget::slotPrintMsg()
{
+ KMMessage *msg = mHeaders->currentMsg();
+ if ( !msg ) {
+ return;
+ }
+
bool htmlOverride = mMsgView ? mMsgView->htmlOverride() : false;
bool htmlLoadExtOverride = mMsgView ? mMsgView->htmlLoadExtOverride() : false;
KConfigGroup reader( KMKernel::config(), "Reader" );
bool useFixedFont = mMsgView ? mMsgView->isFixedFont()
: reader.readBoolEntry( "useFixedFont", false );
- KMCommand *command =
- new KMPrintCommand( this, mHeaders->currentMsg(),
+
+ const HeaderStyle *style;
+ const HeaderStrategy *strategy;
+ if ( mMsgView ) {
+ style = mMsgView->headerStyle();
+ strategy = mMsgView->headerStrategy();
+ } else {
+ style = HeaderStyle::create( reader.readEntry( "header-style", "fancy" ) );
+ strategy = HeaderStrategy::create( reader.readEntry( "header-set-displayed", "rich" ) );
+ }
+
+ KMPrintCommand *command =
+ new KMPrintCommand( this, msg,
+ style, strategy,
htmlOverride, htmlLoadExtOverride,
useFixedFont, overrideEncoding() );
+ if ( mMsgView )
+ command->setOverrideFont( mMsgView->cssHelper()->bodyFont( mMsgView->isFixedFont(), true /*printing*/ ) );
+
command->start();
}
//-----------------------------------------------------------------------------
+void KMMainWidget::setupForwardActions()
+{
+ disconnect( mForwardActionMenu, TQT_SIGNAL( activated() ), 0, 0 );
+ mForwardActionMenu->remove( mForwardInlineAction );
+ mForwardActionMenu->remove( mForwardAttachedAction );
+
+ if ( GlobalSettings::self()->forwardingInlineByDefault() ) {
+ mForwardActionMenu->insert( mForwardInlineAction, 0 );
+ mForwardActionMenu->insert( mForwardAttachedAction, 1 );
+ mForwardInlineAction->setShortcut( Key_F );
+ mForwardAttachedAction->setShortcut( SHIFT+Key_F );
+ connect( mForwardActionMenu, TQT_SIGNAL(activated()), this,
+ TQT_SLOT(slotForwardInlineMsg()) );
+
+ } else {
+ mForwardActionMenu->insert( mForwardAttachedAction, 0 );
+ mForwardActionMenu->insert( mForwardInlineAction, 1 );
+ mForwardInlineAction->setShortcut( SHIFT+Key_F );
+ mForwardAttachedAction->setShortcut( Key_F );
+ connect( mForwardActionMenu, TQT_SIGNAL(activated()), this,
+ TQT_SLOT(slotForwardAttachedMsg()) );
+ }
+}
+
+//-----------------------------------------------------------------------------
void KMMainWidget::slotConfigChanged()
{
readConfig();
+ setupForwardActions();
+ setupForwardingActionsList();
}
//-----------------------------------------------------------------------------
@@ -1888,6 +1912,7 @@ void KMMainWidget::slotOnlineStatus()
kmkernel->stopNetworkJobs();
} else {
kmkernel->resumeNetworkJobs();
+ slotCheckVacation();
}
}
@@ -2396,9 +2421,7 @@ void KMMainWidget::slotMsgPopup(KMMessage&, const KURL &aUrl, const TQPoint& aPo
if ( mFolder->isTemplates() ) {
mUseAction->plug( menu );
} else {
-
- if ( !mFolder->isSent() )
- mMsgActions->replyMenu()->plug( menu );
+ mMsgActions->replyMenu()->plug( menu );
mForwardActionMenu->plug( menu );
}
editAction()->plug(menu);
@@ -2790,6 +2813,10 @@ void KMMainWidget::setupActions()
mRemoveFolderAction = new KAction( "foo" /*set in updateFolderMenu*/, "editdelete", 0, this,
TQT_SLOT(slotRemoveFolder()), actionCollection(), "delete_folder" );
+ mArchiveFolderAction = new KAction( i18n( "&Archive Folder..." ), "filesave", 0, this,
+ TQT_SLOT( slotArchiveFolder() ), actionCollection(),
+ "archive_folder" );
+
mPreferHtmlAction = new KToggleAction( i18n("Prefer &HTML to Plain Text"), 0, this,
TQT_SLOT(slotOverrideHtml()), actionCollection(), "prefer_html" );
@@ -2862,22 +2889,7 @@ void KMMainWidget::setupActions()
"message_forward_redirect" );
- if ( GlobalSettings::self()->forwardingInlineByDefault() ) {
- mForwardActionMenu->insert( mForwardInlineAction );
- mForwardActionMenu->insert( mForwardAttachedAction );
- mForwardInlineAction->setShortcut( Key_F );
- mForwardAttachedAction->setShortcut( SHIFT+Key_F );
- connect( mForwardActionMenu, TQT_SIGNAL(activated()), this,
- TQT_SLOT(slotForwardInlineMsg()) );
-
- } else {
- mForwardActionMenu->insert( mForwardAttachedAction );
- mForwardActionMenu->insert( mForwardInlineAction );
- mForwardInlineAction->setShortcut( SHIFT+Key_F );
- mForwardAttachedAction->setShortcut( Key_F );
- connect( mForwardActionMenu, TQT_SIGNAL(activated()), this,
- TQT_SLOT(slotForwardAttachedMsg()) );
- }
+ setupForwardActions();
mForwardActionMenu->insert( mForwardDigestAction );
mForwardActionMenu->insert( mRedirectAction );
@@ -3114,6 +3126,13 @@ void KMMainWidget::setupActions()
actionCollection(), "go_next_unread_text" );
//----- Settings Menu
+ mToggleShowQuickSearchAction = new KToggleAction(i18n("Show Quick Search"), TQString::null,
+ 0, this, TQT_SLOT(slotToggleShowQuickSearch()),
+ actionCollection(), "show_quick_search");
+ mToggleShowQuickSearchAction->setChecked( GlobalSettings::self()->quickSearchActive() );
+ mToggleShowQuickSearchAction->setWhatsThis(
+ i18n( GlobalSettings::self()->quickSearchActiveItem()->whatsThis().utf8() ) );
+
(void) new KAction( i18n("Configure &Filters..."), 0, this,
TQT_SLOT(slotFilter()), actionCollection(), "filter" );
(void) new KAction( i18n("Configure &POP Filters..."), 0, this,
@@ -3337,8 +3356,8 @@ void KMMainWidget::updateMessageActions()
mMarkThreadAsUnreadAction->setEnabled( thread_actions );
mToggleThreadTodoAction->setEnabled( thread_actions && flags_available );
mToggleThreadFlagAction->setEnabled( thread_actions && flags_available );
- mTrashThreadAction->setEnabled( thread_actions && !mFolder->isReadOnly() );
- mDeleteThreadAction->setEnabled( thread_actions && !mFolder->isReadOnly() );
+ mTrashThreadAction->setEnabled( thread_actions && mFolder->canDeleteMessages() );
+ mDeleteThreadAction->setEnabled( thread_actions && mFolder->canDeleteMessages() );
if (mFolder && mHeaders && mHeaders->currentMsg()) {
if (thread_actions) {
@@ -3349,29 +3368,30 @@ void KMMainWidget::updateMessageActions()
}
}
- mMoveActionMenu->setEnabled( mass_actions && !mFolder->isReadOnly() );
+ mMoveActionMenu->setEnabled( mass_actions && mFolder->canDeleteMessages() );
+ mMoveMsgToFolderAction->setEnabled( mass_actions && mFolder->canDeleteMessages() );
mCopyActionMenu->setEnabled( mass_actions );
- mTrashAction->setEnabled( mass_actions && !mFolder->isReadOnly() );
- mDeleteAction->setEnabled( mass_actions && !mFolder->isReadOnly() );
- mFindInMessageAction->setEnabled( mass_actions );
- mForwardInlineAction->setEnabled( mass_actions );
- mForwardAttachedAction->setEnabled( mass_actions );
- mForwardDigestAction->setEnabled( count > 1 || parent_thread );
+ mTrashAction->setEnabled( mass_actions && mFolder->canDeleteMessages() );
+ mDeleteAction->setEnabled( mass_actions && mFolder->canDeleteMessages() );
+ mFindInMessageAction->setEnabled( mass_actions && !kmkernel->folderIsTemplates( mFolder ) );
+ mForwardInlineAction->setEnabled( mass_actions && !kmkernel->folderIsTemplates( mFolder ));
+ mForwardAttachedAction->setEnabled( mass_actions && !kmkernel->folderIsTemplates( mFolder ) );
+ mForwardDigestAction->setEnabled( ( count > 1 || parent_thread ) && !kmkernel->folderIsTemplates( mFolder ) );
- forwardMenu()->setEnabled( mass_actions );
+ forwardMenu()->setEnabled( mass_actions && !kmkernel->folderIsTemplates( mFolder ));
bool single_actions = count == 1;
mUseAction->setEnabled( single_actions &&
kmkernel->folderIsTemplates( mFolder ) );
filterMenu()->setEnabled( single_actions );
- redirectAction()->setEnabled( single_actions );
+ redirectAction()->setEnabled( single_actions && !kmkernel->folderIsTemplates( mFolder ) );
printAction()->setEnabled( single_actions );
viewSourceAction()->setEnabled( single_actions );
mSendAgainAction->setEnabled( single_actions
- && ( mHeaders->currentMsg() && mHeaders->currentMsg()->isSent() )
- || ( mFolder && mHeaders->currentMsg() &&
- kmkernel->folderIsSentMailFolder( mFolder ) ) );
+ && ( ( mHeaders->currentMsg() && mHeaders->currentMsg()->isSent() )
+ || ( mFolder && mHeaders->currentMsg() &&
+ kmkernel->folderIsSentMailFolder( mFolder ) ) ) );
mSaveAsAction->setEnabled( mass_actions );
bool mails = mFolder && mFolder->count();
bool enable_goto_unread = mails
@@ -3426,13 +3446,27 @@ void KMMainWidget::updateFolderMenu()
|| ( cachedImap && knownImapPath ) ) && !multiFolder );
if ( mTroubleshootFolderAction )
mTroubleshootFolderAction->setEnabled( folderWithContent && ( cachedImap && knownImapPath ) && !multiFolder );
- mEmptyFolderAction->setEnabled( folderWithContent && ( mFolder->count() > 0 ) && !mFolder->isReadOnly() && !multiFolder );
- mEmptyFolderAction->setText( (mFolder && kmkernel->folderIsTrash(mFolder))
- ? i18n("E&mpty Trash") : i18n("&Move All Messages to Trash") );
- mRemoveFolderAction->setEnabled( mFolder && !mFolder->isSystemFolder() && !mFolder->isReadOnly() && !multiFolder);
- mRemoveFolderAction->setText( mFolder && mFolder->folderType() == KMFolderTypeSearch
- ? i18n("&Delete Search") : i18n("&Delete Folder") );
- mExpireFolderAction->setEnabled( mFolder && mFolder->isAutoExpire() && !multiFolder );
+
+ mEmptyFolderAction->setEnabled( folderWithContent &&
+ ( mFolder->count() > 0 ) && mFolder->canDeleteMessages() &&
+ !multiFolder );
+ mEmptyFolderAction->setText( ( mFolder && kmkernel->folderIsTrash( mFolder ) ) ?
+ i18n( "E&mpty Trash" ) :
+ i18n( "&Move All Messages to Trash" ) );
+
+ mRemoveFolderAction->setEnabled( mFolder &&
+ !mFolder->isSystemFolder() &&
+ mFolder->canDeleteMessages() &&
+ !multiFolder && !mFolder->noContent() &&
+ !mFolder->mailCheckInProgress() );
+ mRemoveFolderAction->setText( mFolder &&
+ mFolder->folderType() == KMFolderTypeSearch ?
+ i18n( "&Delete Search" ) :
+ i18n( "&Delete Folder" ) );
+
+ if ( mArchiveFolderAction )
+ mArchiveFolderAction->setEnabled( mFolder && !multiFolder );
+ mExpireFolderAction->setEnabled( mFolder && mFolder->isAutoExpire() && !multiFolder && mFolder->canDeleteMessages() );
updateMarkAsReadAction();
// the visual ones only make sense if we are showing a message list
mPreferHtmlAction->setEnabled( mHeaders->folder() ? true : false );
@@ -3447,8 +3481,8 @@ void KMMainWidget::updateFolderMenu()
mHeaders->folder() ? ( mThreadMessagesAction->isChecked()) : false );
mThreadBySubjectAction->setChecked( mFolderThreadSubjPref );
- mNewFolderAction->setEnabled( !multiFolder );
- mRemoveDuplicatesAction->setEnabled( !multiFolder );
+ mNewFolderAction->setEnabled( !multiFolder && ( mFolder && mFolder->folderType() != KMFolderTypeSearch ));
+ mRemoveDuplicatesAction->setEnabled( !multiFolder && mFolder && mFolder->canDeleteMessages() );
mFolderShortCutCommandAction->setEnabled( !multiFolder );
}
@@ -3849,6 +3883,7 @@ void KMMainWidget::slotFolderTreeColumnsChanged()
mTotalColumnToggle->setChecked( mFolderTree->isTotalActive() );
mUnreadColumnToggle->setChecked( mFolderTree->isUnreadActive() );
mSizeColumnToggle->setChecked( mFolderTree->isSizeActive() );
+ mUnreadTextToggle->setChecked( !mFolderTree->isUnreadActive() );
}
void KMMainWidget::toggleSystemTray()
@@ -3896,6 +3931,7 @@ void KMMainWidget::updateFileMenu()
actionCollection()->action("check_mail")->setEnabled( actList.size() > 0 );
actionCollection()->action("check_mail_in")->setEnabled( actList.size() > 0 );
+ actionCollection()->action("favorite_check_mail")->setEnabled( actList.size() > 0 );
}
@@ -3934,17 +3970,17 @@ void KMMainWidget::setupFolderView()
{
if ( GlobalSettings::self()->enableFavoriteFolderView() ) {
mFolderView = mFolderViewSplitter;
- mSearchAndTree->reparent( mFolderViewSplitter, 0, TQPoint( 0, 0 ) );
+ mFolderTree->reparent( mFolderViewSplitter, 0, TQPoint( 0, 0 ) );
mFolderViewSplitter->show();
mFavoriteFolderView->show();
} else {
- mFolderView = mSearchAndTree;
+ mFolderView = mFolderTree;
mFolderViewSplitter->hide();
mFavoriteFolderView->hide();
}
mFolderView->reparent( mFolderViewParent, 0, TQPoint( 0, 0 ) );
mFolderViewParent->moveToFirst( mFolderView );
- mSearchAndTree->show();
+ mFolderTree->show();
}
diff --git a/kmail/kmmainwidget.h b/kmail/kmmainwidget.h
index 74baaf2a3..20e19a3c6 100644
--- a/kmail/kmmainwidget.h
+++ b/kmail/kmmainwidget.h
@@ -201,7 +201,12 @@ public slots:
/** Select the folder and jump to the next unread msg */
void folderSelectedUnread( KMFolder* );
- void slotMsgSelected(KMMessage*);
+ void slotMsgSelected( KMMessage * );
+ /**
+ Open a separate viewer window containing the specified message.
+ */
+ void slotMsgActivated( KMMessage * );
+
void slotMsgChanged();
/** Change the current folder, select a message in the current folder */
@@ -283,6 +288,7 @@ protected slots:
void slotExpireAll();
void slotInvalidateIMAPFolders();
void slotMarkAllAsRead();
+ void slotArchiveFolder();
void slotRemoveFolder();
void slotEmptyFolder();
void slotCompactFolder();
@@ -360,7 +366,6 @@ protected slots:
/** etc. */
void slotDisplayCurrentMessage();
- void slotMsgActivated( KMMessage* );
void slotShowNewFromTemplate();
void slotNewFromTemplate( int );
@@ -378,6 +383,9 @@ protected slots:
* often the the other updates and is therefor in its own method. */
void updateMarkAsReadAction();
+ /** Settings menu */
+ void slotToggleShowQuickSearch();
+
/** XML-GUI stuff */
void slotEditNotifications();
void slotEditKeys();
@@ -427,6 +435,13 @@ private:
*/
TQString findCurrentImapPath();
+ /**
+ * This function adds or updates the actions of the forward action menu, taking the
+ * preference whether to forward inline or as attachment by default into account.
+ * This has to be called when that preference config has been changed.
+ */
+ void setupForwardActions();
+
void setupFolderView();
private slots:
@@ -439,7 +454,8 @@ private:
*mDeleteThreadAction, *mSaveAsAction, *mUseAction,
*mSendAgainAction, *mApplyAllFiltersAction, *mFindInMessageAction,
*mSaveAttachmentsAction, *mOpenAction, *mViewSourceAction,
- *mFavoritesCheckMailAction;
+ *mFavoritesCheckMailAction,
+ *mMoveMsgToFolderAction;
// Composition actions
KAction *mPrintAction,
*mForwardInlineAction, *mForwardAttachedAction, *mForwardDigestAction,
@@ -476,8 +492,8 @@ private:
KToggleAction* mTotalColumnToggle;
KToggleAction* mSizeColumnToggle;
- TQVBox *mSearchAndTree;
- TQHBox *mFolderQuickSearch;
+ KToggleAction *mToggleShowQuickSearchAction;
+
KMFolderTree *mFolderTree;
KMail::FavoriteFolderView *mFavoriteFolderView;
TQWidget *mFolderView;
@@ -513,8 +529,6 @@ private:
mFolderHtmlPref, mFolderHtmlLoadExtPref, mFolderThreadPref,
mFolderThreadSubjPref, mReaderWindowActive, mReaderWindowBelow;
bool mEnableFavoriteFolderView;
- bool mEnableFolderQuickSearch;
- bool mEnableQuickSearch;
// TQPopupMenu *mMessageMenu;
KMail::SearchWindow *mSearchWin;
@@ -523,7 +537,7 @@ private:
*mCompactFolderAction, *mRefreshFolderAction, *mEmptyFolderAction,
*mMarkAllAsReadAction, *mFolderMailingListPropertiesAction,
*mFolderShortCutCommandAction, *mTroubleshootFolderAction,
- *mRemoveDuplicatesAction;
+ *mRemoveDuplicatesAction, *mArchiveFolderAction;
KToggleAction *mPreferHtmlAction, *mPreferHtmlLoadExtAction, *mThreadMessagesAction;
KToggleAction *mThreadBySubjectAction;
KToggleAction *mFolderAction, *mHeaderAction, *mMimeAction;
diff --git a/kmail/kmmainwin.cpp b/kmail/kmmainwin.cpp
index 7d69e2ee2..994219b0f 100644
--- a/kmail/kmmainwin.cpp
+++ b/kmail/kmmainwin.cpp
@@ -40,7 +40,7 @@ KMMainWin::KMMainWin(TQWidget *)
actionCollection(), "new_mail_client" );
mKMMainWidget = new KMMainWidget( this, "KMMainWidget", this, actionCollection() );
- mKMMainWidget->resize( 725, 700 );
+ mKMMainWidget->resize( 450, 600 );
setCentralWidget(mKMMainWidget);
setupStatusBar();
if (kmkernel->xmlGuiInstance())
diff --git a/kmail/kmmainwin.rc b/kmail/kmmainwin.rc
index 07b9f6c5b..955dabad2 100644
--- a/kmail/kmmainwin.rc
+++ b/kmail/kmmainwin.rc
@@ -2,7 +2,7 @@
the same menu entries at the same place in KMail and Kontact -->
<!DOCTYPE kpartgui>
-<kpartgui version="100" name="kmmainwin" >
+<kpartgui version="102" name="kmmainwin" >
<MenuBar>
<Menu noMerge="1" name="file" >
<text>&amp;File</text>
@@ -103,6 +103,7 @@
<Action name="troubleshoot_folder" />
<Separator/>
<Action name="empty" />
+ <Action name="archive_folder" />
<Action name="delete_folder" />
<Separator/>
<Action name="prefer_html" />
diff --git a/kmail/kmmessage.cpp b/kmail/kmmessage.cpp
index 5a70afdb1..6819d68d9 100644
--- a/kmail/kmmessage.cpp
+++ b/kmail/kmmessage.cpp
@@ -415,7 +415,9 @@ void KMMessage::fromDwString(const DwString& str, bool aSetStatus)
setSignatureStateChar( headerField("X-KMail-SignatureState").at(0) );
setMDNSentState( static_cast<KMMsgMDNSentState>( headerField("X-KMail-MDN-Sent").at(0).latin1() ) );
}
- if (attachmentState() == KMMsgAttachmentUnknown && readyToShow())
+ if ( invitationState() == KMMsgInvitationUnknown && readyToShow() )
+ updateInvitationState();
+ if ( attachmentState() == KMMsgAttachmentUnknown && readyToShow() )
updateAttachmentState();
mNeedsAssembly = false;
@@ -720,11 +722,6 @@ void KMMessage::parseTextStringFromDwPart( partNode * root,
if ( !root ) return;
isHTML = false;
- // initialy parse the complete message to decrypt any encrypted parts
- {
- ObjectTreeParser otp( 0, 0, true, false, true );
- otp.parseObjectTree( root );
- }
partNode * curNode = root->findType( DwMime::kTypeText,
DwMime::kSubtypeUnknown,
true,
@@ -743,15 +740,18 @@ void KMMessage::parseTextStringFromDwPart( partNode * root,
//-----------------------------------------------------------------------------
-TQString KMMessage::asPlainText( bool aStripSignature, bool allowDecryption ) const {
+TQString KMMessage::asPlainTextFromObjectTree( partNode *root, bool aStripSignature,
+ bool allowDecryption ) const
+{
+ Q_ASSERT( root );
+ Q_ASSERT( root->processed() );
+
TQCString parsedString;
bool isHTML = false;
const TQTextCodec * codec = 0;
- partNode * root = partNode::fromMessage( this );
if ( !root ) return TQString::null;
parseTextStringFromDwPart( root, parsedString, codec, isHTML );
- delete root;
if ( mOverrideCodec || !codec )
codec = this->codec();
@@ -767,27 +767,27 @@ TQString KMMessage::asPlainText( bool aStripSignature, bool allowDecryption ) co
TQPtrList<Kpgp::Block> pgpBlocks;
TQStrList nonPgpBlocks;
if ( Kpgp::Module::prepareMessageForDecryption( parsedString,
- pgpBlocks,
- nonPgpBlocks ) ) {
+ pgpBlocks,
+ nonPgpBlocks ) ) {
// Only decrypt/strip off the signature if there is only one OpenPGP
// block in the message
if ( pgpBlocks.count() == 1 ) {
- Kpgp::Block * block = pgpBlocks.first();
- if ( block->type() == Kpgp::PgpMessageBlock ||
- block->type() == Kpgp::ClearsignedBlock ) {
- if ( block->type() == Kpgp::PgpMessageBlock ) {
- // try to decrypt this OpenPGP block
- block->decrypt();
- } else {
- // strip off the signature
- block->verify();
- clearSigned = true;
- }
+ Kpgp::Block * block = pgpBlocks.first();
+ if ( block->type() == Kpgp::PgpMessageBlock ||
+ block->type() == Kpgp::ClearsignedBlock ) {
+ if ( block->type() == Kpgp::PgpMessageBlock ) {
+ // try to decrypt this OpenPGP block
+ block->decrypt();
+ } else {
+ // strip off the signature
+ block->verify();
+ clearSigned = true;
+ }
- result = codec->toUnicode( nonPgpBlocks.first() )
- + codec->toUnicode( block->text() )
- + codec->toUnicode( nonPgpBlocks.last() );
- }
+ result = codec->toUnicode( nonPgpBlocks.first() )
+ + codec->toUnicode( block->text() )
+ + codec->toUnicode( nonPgpBlocks.last() );
+ }
}
}
}
@@ -820,6 +820,21 @@ TQString KMMessage::asPlainText( bool aStripSignature, bool allowDecryption ) co
return result;
}
+//-----------------------------------------------------------------------------
+
+TQString KMMessage::asPlainText( bool aStripSignature, bool allowDecryption ) const
+{
+ partNode *root = partNode::fromMessage( this );
+ if ( !root )
+ return TQString::null;
+
+ ObjectTreeParser otp;
+ otp.parseObjectTree( root );
+ TQString result = asPlainTextFromObjectTree( root, aStripSignature, allowDecryption );
+ delete root;
+ return result;
+}
+
TQString KMMessage::asQuotedString( const TQString& aHeaderStr,
const TQString& aIndentStr,
const TQString& selection /* = TQString::null */,
@@ -852,11 +867,10 @@ KMMessage* KMMessage::createReply( KMail::ReplyStrategy replyStrategy,
TQString selection /* = TQString::null */,
bool noQuote /* = false */,
bool allowDecryption /* = true */,
- bool selectionIsBody /* = false */,
const TQString &tmpl /* = TQString::null */ )
{
KMMessage* msg = new KMMessage;
- TQString str, replyStr, mailingListStr, replyToStr, toStr;
+ TQString mailingListStr, replyToStr, toStr;
TQStringList mailingListAddresses;
TQCString refStr, headerName;
bool replyAll = true;
@@ -881,8 +895,6 @@ KMMessage* KMMessage::createReply( KMail::ReplyStrategy replyStrategy,
}
// use the "On ... Joe User wrote:" header by default
- replyStr = sReplyAllStr;
-
switch( replyStrategy ) {
case KMail::ReplySmart : {
if ( !headerField( "Mail-Followup-To" ).isEmpty() ) {
@@ -898,7 +910,7 @@ KMMessage* KMMessage::createReply( KMail::ReplyStrategy replyStrategy,
else {
// doesn't seem to be a mailing list, reply to From: address
toStr = from();
- replyStr = sReplyStr; // reply to author, so use "On ... you wrote:"
+ //replyStr = sReplyStr; // reply to author, so use "On ... you wrote:"
replyAll = false;
}
// strip all my addresses from the list of recipients
@@ -1028,7 +1040,6 @@ KMMessage* KMMessage::createReply( KMail::ReplyStrategy replyStrategy,
else if ( !from().isEmpty() ) {
toStr = from();
}
- replyStr = sReplyStr; // reply to author, so use "On ... you wrote:"
replyAll = false;
break;
}
@@ -1056,15 +1067,20 @@ KMMessage* KMMessage::createReply( KMail::ReplyStrategy replyStrategy,
// }
msg->setSubject( replySubject() );
-
- TemplateParser parser( msg, (replyAll ? TemplateParser::ReplyAll : TemplateParser::Reply),
- selection, sSmartQuote, noQuote, allowDecryption, selectionIsBody );
- if ( !tmpl.isEmpty() ) {
- parser.process( tmpl, this );
- } else {
- parser.process( this );
+ msg->setHeaderField( "X-KMail-QuotePrefix",
+ formatString( GlobalSettings::self()->quoteString() ) );
+ if( !noQuote ) {
+ TemplateParser parser( msg, ( replyAll ? TemplateParser::ReplyAll : TemplateParser::Reply ) );
+ parser.setAllowDecryption( allowDecryption );
+ if ( GlobalSettings::quoteSelectionOnly() ) {
+ parser.setSelection( selection );
+ }
+ if ( !tmpl.isEmpty() ) {
+ parser.process( tmpl, this );
+ } else {
+ parser.process( this );
+ }
}
-
// setStatus(KMMsgStatusReplied);
msg->link(this, KMMsgStatusReplied);
@@ -1127,12 +1143,12 @@ KMMessage* KMMessage::createRedirect( const TQString &toStr )
TQString strByWayOf = TQString("%1 (by way of %2 <%3>)")
.arg( from() )
.arg( ident.fullName() )
- .arg( ident.emailAddr() );
+ .arg( ident.primaryEmailAddress() );
// Resent-From: content
TQString strFrom = TQString("%1 <%2>")
.arg( ident.fullName() )
- .arg( ident.emailAddr() );
+ .arg( ident.primaryEmailAddress() );
// format the current date to be used in Resent-Date:
TQString origDate = msg->headerField( "Date" );
@@ -1211,7 +1227,6 @@ void KMMessage::sanitizeHeaders( const TQStringList& whiteList )
KMMessage* KMMessage::createForward( const TQString &tmpl /* = TQString::null */ )
{
KMMessage* msg = new KMMessage();
- TQString id;
// If this is a multipart mail or if the main part is only the text part,
// Make an identical copy of the mail, minus headers, so attachments are
@@ -1222,8 +1237,7 @@ KMMessage* KMMessage::createForward( const TQString &tmpl /* = TQString::null */
msg->fromDwString( this->asDwString() );
// remember the type and subtype, initFromMessage sets the contents type to
// text/plain, via initHeader, for unclear reasons
- const int type = msg->type();
- const int subtype = msg->subtype();
+ DwMediaType oldContentType = msg->mMsg->Headers().ContentType();
msg->sanitizeHeaders();
@@ -1240,12 +1254,14 @@ KMMessage* KMMessage::createForward( const TQString &tmpl /* = TQString::null */
}
}
msg->mMsg->Assemble();
-
msg->initFromMessage( this );
+
//restore type
- msg->setType( type );
- msg->setSubtype( subtype );
- } else if( type() == DwMime::kTypeText && subtype() == DwMime::kSubtypeHtml ) {
+ msg->mMsg->Headers().ContentType().FromString( oldContentType.AsString() );
+ msg->mMsg->Headers().ContentType().Parse();
+ msg->mMsg->Assemble();
+ }
+ else if( type() == DwMime::kTypeText && subtype() == DwMime::kSubtypeHtml ) {
// This is non-multipart html mail. Let`s make it text/plain and allow
// template parser do the hard job.
msg->initFromMessage( this );
@@ -1253,7 +1269,8 @@ KMMessage* KMMessage::createForward( const TQString &tmpl /* = TQString::null */
msg->setSubtype( DwMime::kSubtypeHtml );
msg->mNeedsAssembly = true;
msg->cleanupHeader();
- } else {
+ }
+ else {
// This is a non-multipart, non-text mail (e.g. text/calendar). Construct
// a multipart/mixed mail and add the original body as an attachment.
msg->initFromMessage( this );
@@ -1287,9 +1304,7 @@ KMMessage* KMMessage::createForward( const TQString &tmpl /* = TQString::null */
msg->setSubject( forwardSubject() );
- TemplateParser parser( msg, TemplateParser::Forward,
- asPlainText( false, false ),
- false, false, false, false);
+ TemplateParser parser( msg, TemplateParser::Forward );
if ( !tmpl.isEmpty() ) {
parser.process( tmpl, this );
} else {
@@ -1351,25 +1366,27 @@ static const int numMdnMessageBoxes
static int requestAdviceOnMDN( const char * what ) {
- for ( int i = 0 ; i < numMdnMessageBoxes ; ++i )
- if ( !qstrcmp( what, mdnMessageBoxes[i].dontAskAgainID ) )
+ for ( int i = 0 ; i < numMdnMessageBoxes ; ++i ) {
+ if ( !qstrcmp( what, mdnMessageBoxes[i].dontAskAgainID ) ) {
if ( mdnMessageBoxes[i].canDeny ) {
- const KCursorSaver saver( TQCursor::ArrowCursor );
- int answer = TQMessageBox::information( 0,
- i18n("Message Disposition Notification Request"),
- i18n( mdnMessageBoxes[i].text ),
- i18n("&Ignore"), i18n("Send \"&denied\""), i18n("&Send") );
- return answer ? answer + 1 : 0 ; // map to "mode" in createMDN
+ const KCursorSaver saver( TQCursor::ArrowCursor );
+ int answer = TQMessageBox::information( 0,
+ i18n("Message Disposition Notification Request"),
+ i18n( mdnMessageBoxes[i].text ),
+ i18n("&Ignore"), i18n("Send \"&denied\""), i18n("&Send") );
+ return answer ? answer + 1 : 0 ; // map to "mode" in createMDN
} else {
- const KCursorSaver saver( TQCursor::ArrowCursor );
- int answer = TQMessageBox::information( 0,
- i18n("Message Disposition Notification Request"),
- i18n( mdnMessageBoxes[i].text ),
- i18n("&Ignore"), i18n("&Send") );
- return answer ? answer + 2 : 0 ; // map to "mode" in createMDN
+ const KCursorSaver saver( TQCursor::ArrowCursor );
+ int answer = TQMessageBox::information( 0,
+ i18n("Message Disposition Notification Request"),
+ i18n( mdnMessageBoxes[i].text ),
+ i18n("&Ignore"), i18n("&Send") );
+ return answer ? answer + 2 : 0 ; // map to "mode" in createMDN
}
+ }
+ }
kdWarning(5006) << "didn't find data for message box \""
- << what << "\"" << endl;
+ << what << "\"" << endl;
return 0;
}
@@ -2487,28 +2504,38 @@ TQCString KMMessage::contentTransferEncodingStr() const
//-----------------------------------------------------------------------------
-int KMMessage::contentTransferEncoding() const
+int KMMessage::contentTransferEncoding( DwEntity *entity ) const
{
- DwHeaders& header = mMsg->Headers();
- if (header.HasContentTransferEncoding())
+ if ( !entity )
+ entity = mMsg;
+
+ DwHeaders& header = entity->Headers();
+ if ( header.HasContentTransferEncoding() )
return header.ContentTransferEncoding().AsEnum();
else return DwMime::kCteNull;
}
//-----------------------------------------------------------------------------
-void KMMessage::setContentTransferEncodingStr(const TQCString& aStr)
+void KMMessage::setContentTransferEncodingStr( const TQCString& cteString,
+ DwEntity *entity )
{
- mMsg->Headers().ContentTransferEncoding().FromString(aStr);
- mMsg->Headers().ContentTransferEncoding().Parse();
+ if ( !entity )
+ entity = mMsg;
+
+ entity->Headers().ContentTransferEncoding().FromString( cteString );
+ entity->Headers().ContentTransferEncoding().Parse();
mNeedsAssembly = true;
}
//-----------------------------------------------------------------------------
-void KMMessage::setContentTransferEncoding(int aCte)
+void KMMessage::setContentTransferEncoding( int cte, DwEntity *entity )
{
- mMsg->Headers().ContentTransferEncoding().FromEnum(aCte);
+ if ( !entity )
+ entity = mMsg;
+
+ entity->Headers().ContentTransferEncoding().FromEnum( cte );
mNeedsAssembly = true;
}
@@ -2526,6 +2553,16 @@ void KMMessage::setNeedsAssembly()
mNeedsAssembly = true;
}
+//-----------------------------------------------------------------------------
+void KMMessage::assembleIfNeeded()
+{
+ Q_ASSERT( mMsg );
+
+ if ( mNeedsAssembly ) {
+ mMsg->Assemble();
+ mNeedsAssembly = false;
+ }
+}
//-----------------------------------------------------------------------------
TQCString KMMessage::body() const
@@ -2646,22 +2683,16 @@ TQValueList<int> KMMessage::determineAllowedCtes( const CharFreq& cf,
void KMMessage::setBodyAndGuessCte( const TQByteArray& aBuf,
TQValueList<int> & allowedCte,
bool allow8Bit,
- bool willBeSigned )
+ bool willBeSigned,
+ DwEntity *entity )
{
- CharFreq cf( aBuf ); // it's safe to pass null arrays
+ if ( !entity )
+ entity = mMsg;
+ CharFreq cf( aBuf ); // it's safe to pass null arrays
allowedCte = determineAllowedCtes( cf, allow8Bit, willBeSigned );
-
-#ifndef NDEBUG
- DwString dwCte;
- DwCteEnumToStr(allowedCte[0], dwCte);
- kdDebug(5006) << "CharFreq returned " << cf.type() << "/"
- << cf.printableRatio() << " and I chose "
- << dwCte.c_str() << endl;
-#endif
-
- setCte( allowedCte[0] ); // choose best fitting
- setBodyEncodedBinary( aBuf );
+ setCte( allowedCte[0], entity ); // choose best fitting
+ setBodyEncodedBinary( aBuf, entity );
}
@@ -2669,32 +2700,29 @@ void KMMessage::setBodyAndGuessCte( const TQByteArray& aBuf,
void KMMessage::setBodyAndGuessCte( const TQCString& aBuf,
TQValueList<int> & allowedCte,
bool allow8Bit,
- bool willBeSigned )
+ bool willBeSigned,
+ DwEntity *entity )
{
- CharFreq cf( aBuf.data(), aBuf.size()-1 ); // it's safe to pass null strings
+ if ( !entity )
+ entity = mMsg;
+ CharFreq cf( aBuf.data(), aBuf.size()-1 ); // it's safe to pass null strings
allowedCte = determineAllowedCtes( cf, allow8Bit, willBeSigned );
-
-#ifndef NDEBUG
- DwString dwCte;
- DwCteEnumToStr(allowedCte[0], dwCte);
- kdDebug(5006) << "CharFreq returned " << cf.type() << "/"
- << cf.printableRatio() << " and I chose "
- << dwCte.c_str() << endl;
-#endif
-
- setCte( allowedCte[0] ); // choose best fitting
- setBodyEncoded( aBuf );
+ setCte( allowedCte[0], entity ); // choose best fitting
+ setBodyEncoded( aBuf, entity );
}
//-----------------------------------------------------------------------------
-void KMMessage::setBodyEncoded(const TQCString& aStr)
+void KMMessage::setBodyEncoded(const TQCString& aStr, DwEntity *entity )
{
+ if ( !entity )
+ entity = mMsg;
+
DwString dwSrc(aStr.data(), aStr.size()-1 /* not the trailing NUL */);
DwString dwResult;
- switch (cte())
+ switch (cte( entity ))
{
case DwMime::kCteBase64:
DwEncodeBase64(dwSrc, dwResult);
@@ -2707,30 +2735,35 @@ void KMMessage::setBodyEncoded(const TQCString& aStr)
break;
}
- mMsg->Body().FromString(dwResult);
+ entity->Body().FromString(dwResult);
mNeedsAssembly = true;
}
//-----------------------------------------------------------------------------
-void KMMessage::setBodyEncodedBinary(const TQByteArray& aStr)
+void KMMessage::setBodyEncodedBinary( const TQByteArray& aStr, DwEntity *entity )
{
+ if ( !entity )
+ entity = mMsg;
+
DwString dwSrc(aStr.data(), aStr.size());
DwString dwResult;
- switch (cte())
+ switch ( cte( entity ) )
{
case DwMime::kCteBase64:
- DwEncodeBase64(dwSrc, dwResult);
+ DwEncodeBase64( dwSrc, dwResult );
break;
case DwMime::kCteQuotedPrintable:
- DwEncodeQuotedPrintable(dwSrc, dwResult);
+ DwEncodeQuotedPrintable( dwSrc, dwResult );
break;
default:
dwResult = dwSrc;
break;
}
- mMsg->Body().FromString(dwResult);
+ entity->Body().FromString( dwResult );
+ entity->Body().Parse();
+
mNeedsAssembly = true;
}
@@ -2752,6 +2785,7 @@ void KMMessage::setBody(const char* aStr)
mNeedsAssembly = true;
}
+//-----------------------------------------------------------------------------
void KMMessage::setMultiPartBody( const TQCString & aStr ) {
setBody( aStr );
mMsg->Body().Parse();
@@ -3053,7 +3087,8 @@ void applyHeadersToMessagePart( DwHeaders& headers, KMMessagePart* aPart )
// Content-description
if (headers.HasContentDescription())
- aPart->setContentDescription(headers.ContentDescription().AsString().c_str());
+ aPart->setContentDescription( KMMsgBase::decodeRFC2047String(
+ headers.ContentDescription().AsString().c_str() ) );
else
aPart->setContentDescription("");
@@ -3137,6 +3172,44 @@ void KMMessage::deleteBodyParts()
}
//-----------------------------------------------------------------------------
+
+bool KMMessage::deleteBodyPart( int partIndex )
+{
+ KMMessagePart part;
+ DwBodyPart *dwpart = findPart( partIndex );
+ if ( !dwpart )
+ return false;
+ KMMessage::bodyPart( dwpart, &part, true );
+ if ( !part.isComplete() )
+ return false;
+
+ DwBody *parentNode = dynamic_cast<DwBody*>( dwpart->Parent() );
+ if ( !parentNode )
+ return false;
+ parentNode->RemoveBodyPart( dwpart );
+
+ // add dummy part to show that a attachment has been deleted
+ KMMessagePart dummyPart;
+ dummyPart.duplicate( part );
+ TQString comment = i18n("This attachment has been deleted.");
+ if ( !part.fileName().isEmpty() )
+ comment = i18n( "The attachment '%1' has been deleted." ).arg( part.fileName() );
+ dummyPart.setContentDescription( comment );
+ dummyPart.setBodyEncodedBinary( TQByteArray() );
+ TQCString cd = dummyPart.contentDisposition();
+ if ( cd.find( "inline", 0, false ) == 0 ) {
+ cd.replace( 0, 10, "attachment" );
+ dummyPart.setContentDisposition( cd );
+ } else if ( cd.isEmpty() ) {
+ dummyPart.setContentDisposition( "attachment" );
+ }
+ DwBodyPart* newDwPart = createDWBodyPart( &dummyPart );
+ parentNode->AddBodyPart( newDwPart );
+ getTopLevelPart()->Assemble();
+ return true;
+}
+
+//-----------------------------------------------------------------------------
DwBodyPart* KMMessage::createDWBodyPart(const KMMessagePart* aPart)
{
DwBodyPart* part = DwBodyPart::NewBodyPart(emptyString, 0);
@@ -3150,9 +3223,7 @@ DwBodyPart* KMMessage::createDWBodyPart(const KMMessagePart* aPart)
TQCString cte = aPart->cteStr();
TQCString contDesc = aPart->contentDescriptionEncoded();
TQCString contDisp = aPart->contentDisposition();
- TQCString encoding = autoDetectCharset(charset, sPrefCharsets, aPart->name());
- if (encoding.isEmpty()) encoding = "utf-8";
- TQCString name = KMMsgBase::encodeRFC2231String(aPart->name(), encoding);
+ TQCString name = KMMsgBase::encodeRFC2231StringAutoDetectCharset( aPart->name(), charset );
bool RFC2231encoded = aPart->name() != TQString(name);
TQCString paramAttr = aPart->parameterAttribute();
@@ -3229,12 +3300,8 @@ DwBodyPart* KMMessage::createDWBodyPart(const KMMessagePart* aPart)
if (!paramAttr.isEmpty())
{
- TQCString encoding = autoDetectCharset(charset, sPrefCharsets,
- aPart->parameterValue());
- if (encoding.isEmpty()) encoding = "utf-8";
TQCString paramValue;
- paramValue = KMMsgBase::encodeRFC2231String(aPart->parameterValue(),
- encoding);
+ paramValue = KMMsgBase::encodeRFC2231StringAutoDetectCharset( aPart->parameterValue(), charset );
DwParameter *param = new DwParameter;
if (aPart->parameterValue() != TQString(paramValue))
{
@@ -3771,24 +3838,41 @@ TQString KMMessage::emailAddrAsAnchor(const TQString& aEmail, bool stripped, con
return aEmail;
TQStringList addressList = KPIM::splitEmailAddrList( aEmail );
-
TQString result;
for( TQStringList::ConstIterator it = addressList.begin();
( it != addressList.end() );
++it ) {
if( !(*it).isEmpty() ) {
- TQString address = *it;
+
+ // Extract the name, mail and some pretty versions out of the mail address
+ TQString name, mail;
+ KPIM::getNameAndMail( *it, name, mail );
+ TQString pretty;
+ TQString prettyStripped;
+ if ( name.stripWhiteSpace().isEmpty() ) {
+ pretty = mail;
+ prettyStripped = mail;
+ } else {
+ pretty = KPIM::quoteNameIfNecessary( name ) + " <" + mail + ">";
+ prettyStripped = name;
+ }
+
if(aLink) {
- result += "<a href=\"mailto:"
- + KMMessage::encodeMailtoUrl( address )
- + "\" "+cssStyle+">";
+ result += "<a href=\"mailto:"
+ + KMMessage::encodeMailtoUrl( pretty )
+ + "\" "+cssStyle+">";
+ }
+
+ if ( stripped ) {
+ result += KMMessage::quoteHtmlChars( prettyStripped, true );
+ }
+ else {
+ result += KMMessage::quoteHtmlChars( pretty, true );
}
- if( stripped )
- address = KMMessage::stripEmailAddr( address );
- result += KMMessage::quoteHtmlChars( address, true );
+
if(aLink)
- result += "</a>, ";
+ result += "</a>, ";
}
}
// cut of the trailing ", "
@@ -3800,7 +3884,6 @@ TQString KMMessage::emailAddrAsAnchor(const TQString& aEmail, bool stripped, con
return result;
}
-
//-----------------------------------------------------------------------------
//static
TQStringList KMMessage::stripAddressFromAddressList( const TQString& address,
@@ -4023,7 +4106,7 @@ TQCString KMMessage::charset() const
}
//-----------------------------------------------------------------------------
-void KMMessage::setCharset(const TQCString& bStr)
+void KMMessage::setCharset( const TQCString &charset, DwEntity *entity )
{
kdWarning( type() != DwMime::kTypeText )
<< "KMMessage::setCharset(): trying to set a charset for a non-textual mimetype." << endl
@@ -4031,23 +4114,32 @@ void KMMessage::setCharset(const TQCString& bStr)
<< "====================================================================" << endl
<< kdBacktrace( 5 ) << endl
<< "====================================================================" << endl;
- TQCString aStr = bStr;
- KPIM::kAsciiToLower( aStr.data() );
- DwMediaType &mType = dwContentType();
+
+ if ( !entity )
+ entity = mMsg;
+
+ DwMediaType &mType = entity->Headers().ContentType();
mType.Parse();
- DwParameter *param=mType.FirstParameter();
- while(param)
+ DwParameter *param = mType.FirstParameter();
+ while( param ) {
+
// FIXME use the mimelib functions here for comparison.
- if (!kasciistricmp(param->Attribute().c_str(), "charset")) break;
- else param=param->Next();
- if (!param){
- param=new DwParameter;
- param->SetAttribute("charset");
- mType.AddParameter(param);
+ if ( !kasciistricmp( param->Attribute().c_str(), "charset" ) )
+ break;
+
+ param = param->Next();
+ }
+ if ( !param ) {
+ param = new DwParameter;
+ param->SetAttribute( "charset" );
+ mType.AddParameter( param );
}
else
mType.SetModified();
- param->SetValue(DwString(aStr));
+
+ TQCString lowerCharset = charset;
+ KPIM::kAsciiToLower( lowerCharset.data() );
+ param->SetValue( DwString( lowerCharset ) );
mType.Assemble();
}
@@ -4078,7 +4170,8 @@ void KMMessage::setSignatureState(KMMsgSignatureState s, int idx)
KMMsgBase::setSignatureState(s, idx);
}
-void KMMessage::setMDNSentState( KMMsgMDNSentState status, int idx ) {
+void KMMessage::setMDNSentState( KMMsgMDNSentState status, int idx )
+{
if ( mMDNSentState == status )
return;
if ( status == 0 )
@@ -4247,6 +4340,21 @@ void KMMessage::updateBodyPart(const TQString partSpecifier, const TQByteArray &
}
}
+void KMMessage::updateInvitationState()
+{
+ if ( mMsg && mMsg->hasHeaders() && mMsg->Headers().HasContentType() ) {
+ TQString cntType = mMsg->Headers().ContentType().TypeStr().c_str();
+ cntType += '/';
+ cntType += mMsg->Headers().ContentType().SubtypeStr().c_str();
+ if ( cntType.lower() == "text/calendar" ) {
+ setStatus( KMMsgStatusHasInvitation );
+ return;
+ }
+ }
+ setStatus( KMMsgStatusHasNoInvitation );
+ return;
+}
+
//-----------------------------------------------------------------------------
void KMMessage::updateAttachmentState( DwBodyPart* part )
{
@@ -4270,6 +4378,18 @@ void KMMessage::updateAttachmentState( DwBodyPart* part )
filenameEmpty = KMMsgBase::decodeRFC2231String( KMMsgBase::extractRFC2231HeaderField( cd.AsString().c_str(), "filename" ) ).isEmpty();
}
}
+
+ // Filename still empty? Check if the content-type has a "name" parameter and try to use that as
+ // the attachment name
+ if ( filenameEmpty && part->Headers().HasContentType() ) {
+ DwMediaType contentType = part->Headers().ContentType();
+ filenameEmpty = contentType.Name().empty();
+ if ( filenameEmpty ) {
+ // let's try if it is rfc 2231 encoded which mimelib can't handle
+ filenameEmpty = KMMsgBase::decodeRFC2231String( KMMsgBase::extractRFC2231HeaderField(
+ contentType.AsString().c_str(), "name" ) ).isEmpty();
+ }
+ }
}
if ( part->hasHeaders() &&
@@ -4312,15 +4432,17 @@ void KMMessage::updateAttachmentState( DwBodyPart* part )
setStatus( KMMsgStatusHasNoAttach );
}
-void KMMessage::setBodyFromUnicode( const TQString & str ) {
+void KMMessage::setBodyFromUnicode( const TQString &str, DwEntity *entity )
+{
TQCString encoding = KMMsgBase::autoDetectCharset( charset(), KMMessage::preferredCharsets(), str );
if ( encoding.isEmpty() )
encoding = "utf-8";
const TQTextCodec * codec = KMMsgBase::codecForName( encoding );
assert( codec );
TQValueList<int> dummy;
- setCharset( encoding );
- setBodyAndGuessCte( codec->fromUnicode( str ), dummy, false /* no 8bit */ );
+ setCharset( encoding, entity );
+ setBodyAndGuessCte( codec->fromUnicode( str ), dummy, false /* no 8bit */,
+ false, entity );
}
const TQTextCodec * KMMessage::codec() const {
@@ -4371,3 +4493,28 @@ void KMMessage::deleteWhenUnused()
{
sPendingDeletes << this;
}
+
+DwBodyPart* KMMessage::findPart( int index )
+{
+ int accu = 0;
+ return findPartInternal( getTopLevelPart(), index, accu );
+}
+
+DwBodyPart* KMMessage::findPartInternal(DwEntity * root, int index, int & accu)
+{
+ accu++;
+ if ( index < accu ) // should not happen
+ return 0;
+ DwBodyPart *current = dynamic_cast<DwBodyPart*>( root );
+ if ( index == accu )
+ return current;
+ DwBodyPart *rv = 0;
+ if ( root->Body().FirstBodyPart() )
+ rv = findPartInternal( root->Body().FirstBodyPart(), index, accu );
+ if ( !rv && current && current->Next() )
+ rv = findPartInternal( current->Next(), index, accu );
+ if ( !rv && root->Body().Message() )
+ rv = findPartInternal( root->Body().Message(), index, accu );
+ return rv;
+}
+
diff --git a/kmail/kmmessage.h b/kmail/kmmessage.h
index 53c1e4089..958d017e2 100644
--- a/kmail/kmmessage.h
+++ b/kmail/kmmessage.h
@@ -49,6 +49,7 @@ namespace KMail {
class HeaderStrategy;
}
+class DwEntity;
class DwBodyPart;
class DwMediaType;
class DwHeaders;
@@ -161,8 +162,8 @@ public:
required header fields with the proper values. The returned message
is not stored in any folder. Marks this message as replied. */
KMMessage* createReply( KMail::ReplyStrategy replyStrategy = KMail::ReplySmart,
- TQString selection=TQString::null, bool noQuote=false,
- bool allowDecryption=true, bool selectionIsBody=false,
+ TQString selection=TQString::null, bool noQuote = false,
+ bool allowDecryption = true,
const TQString &tmpl = TQString::null );
/** Create a new message that is a redirect to this message, filling all
@@ -503,25 +504,46 @@ public:
the header via headers() function) */
void setNeedsAssembly();
- /** Get or set the 'Content-Transfer-Encoding' header field
- The member functions that involve enumerated types (ints)
- will work only for well-known encodings. */
+ /**
+ * Assemble the internal message. This is done automatically in most
+ * cases, but sometimes still necessary to call this manually.
+ */
+ void assembleIfNeeded();
+
+ /**
+ * Get or set the 'Content-Transfer-Encoding' header field
+ * The member functions that involve enumerated types (ints)
+ * will work only for well-known encodings.
+ * Some functions take a DwEntity as second parameter, which
+ * specifies the body part or message of which the CTE will be changed or
+ * returned. If this is zero, the toplevel message will be taken.
+ */
TQCString contentTransferEncodingStr() const;
- int contentTransferEncoding() const;
- void setContentTransferEncodingStr(const TQCString& aStr);
- void setContentTransferEncoding(int aCte);
+ int contentTransferEncoding( DwEntity *entity = 0 ) const;
+ void setContentTransferEncodingStr( const TQCString& cteString, DwEntity *entity = 0 );
+ void setContentTransferEncoding( int cte, DwEntity *entity = 0 );
- /** Cte is short for ContentTransferEncoding.
- These functions are an alternative to the ones with longer names. */
+ /**
+ * Cte is short for ContentTransferEncoding.
+ * These functions are an alternative to the ones with longer names.
+ */
TQCString cteStr() const { return contentTransferEncodingStr(); }
- int cte() const { return contentTransferEncoding(); }
- void setCteStr(const TQCString& aStr) { setContentTransferEncodingStr(aStr); }
- void setCte(int aCte) { setContentTransferEncoding(aCte); }
+ int cte( DwEntity *entity = 0 ) const { return contentTransferEncoding( entity ); }
+ void setCteStr( const TQCString& aStr, DwEntity *entity = 0 ) {
+ setContentTransferEncodingStr( aStr, entity );
+ }
+ void setCte( int aCte, DwEntity *entity = 0 ) {
+ setContentTransferEncoding( aCte, entity );
+ }
- /** Sets this body part's content to @p str. @p str is subject to
- automatic charset and CTE detection.
- **/
- void setBodyFromUnicode( const TQString & str );
+ /**
+ * Sets this body's content to @p str. @p str is subject to
+ * automatic charset and CTE detection.
+ *
+ * @param entity The body of this entity will be changed. If entity is 0,
+ * the body of the whole message will be changed.
+ */
+ void setBodyFromUnicode( const TQString & str, DwEntity *entity = 0 );
/** Returns the body part decoded to unicode.
**/
@@ -538,11 +560,17 @@ public:
/** Hack to enable structured body parts to be set as flat text... */
void setMultiPartBody( const TQCString & aStr );
- /** Set the message body, encoding it according to the current content
- transfer encoding. The first method for null terminated strings,
- the second for binary data */
- void setBodyEncoded(const TQCString& aStr);
- void setBodyEncodedBinary(const TQByteArray& aStr);
+ /**
+ * Set the message body, encoding it according to the current content
+ * transfer encoding. The first method for null terminated strings,
+ * the second for binary data.
+ *
+ * @param entity Specifies the body part or message of which the body will be
+ * set. If this is 0, the body of the toplevel message will be
+ * set.
+ */
+ void setBodyEncoded( const TQCString& aStr, DwEntity *entity = 0 );
+ void setBodyEncodedBinary( const TQByteArray& aStr, DwEntity *entity = 0 );
/** Returns a list of content-transfer-encodings that can be used with
the given result of the character frequency analysis of a message or
@@ -551,23 +579,29 @@ public:
bool allow8Bit,
bool willBeSigned );
- /** Sets body, encoded in the best fitting
- content-transfer-encoding, which is determined by character
- frequency count.
+ /**
+ * Sets body, encoded in the best fitting
+ * content-transfer-encoding, which is determined by character
+ * frequency count.
+ *
+ * @param aBuf input buffer
+ * @param allowedCte return: list of allowed cte's
+ * @param allow8Bit whether "8bit" is allowed as cte.
+ * @param willBeSigned whether "7bit"/"8bit" is allowed as cte according to RFC 3156
+ * @param entity The body of this message or body part will get changed.
+ * If this is 0, the body of the toplevel message will be
+ * set.
+ */
+ void setBodyAndGuessCte( const TQByteArray& aBuf, TQValueList<int>& allowedCte,
+ bool allow8Bit = false,
+ bool willBeSigned = false,
+ DwEntity *entity = 0 );
- @param aBuf input buffer
- @param allowedCte return: list of allowed cte's
- @param allow8Bit whether "8bit" is allowed as cte.
- @param willBeSigned whether "7bit"/"8bit" is allowed as cte according to RFC 3156
- */
- void setBodyAndGuessCte( const TQByteArray& aBuf,
- TQValueList<int>& allowedCte,
- bool allow8Bit = false,
- bool willBeSigned = false );
void setBodyAndGuessCte( const TQCString& aBuf,
- TQValueList<int>& allowedCte,
- bool allow8Bit = false,
- bool willBeSigned = false );
+ TQValueList<int>& allowedCte,
+ bool allow8Bit = false,
+ bool willBeSigned = false,
+ DwEntity *entity = 0 );
/** Returns a decoded version of the body from the current content transfer
encoding. The first method returns a null terminated string, the second
@@ -627,6 +661,12 @@ public:
/** Delete all body parts. */
void deleteBodyParts();
+ /**
+ * Delete a body part with the specified part index.
+ * A dummy body part with the text "the attachment foo was deleted" will replace the old part.
+ */
+ bool deleteBodyPart( int partIndex );
+
/** Set "Status" and "X-Status" fields of the message from the
* internal message status. */
void setStatusFields();
@@ -725,8 +765,15 @@ public:
/** Get the message charset.*/
TQCString charset() const;
- /** Set the message charset. */
- void setCharset(const TQCString& aStr);
+ /**
+ * Sets the charset of the message or a subpart of the message.
+ * Only call this when the message or the subpart has a textual mimetype.
+ *
+ * @param aStr the MIME-compliant charset name, like 'ISO-88519-15'.
+ * @param entity the body part or message of which the charset should be changed.
+ * If this is 0, the charset of the toplevel message will be changed.
+ */
+ void setCharset( const TQCString& charset, DwEntity *entity = 0 );
/** Get a TQTextCodec suitable for this message part */
const TQTextCodec * codec() const;
@@ -822,7 +869,8 @@ public:
/** Set if the message is ready to be shown */
void setReadyToShow( bool v ) { mReadyToShow = v; }
- void updateAttachmentState(DwBodyPart * part = 0);
+ void updateAttachmentState( DwBodyPart *part = 0 );
+ void updateInvitationState();
/** Return, if the message should not be deleted */
bool transferInProgress() const;
@@ -860,6 +908,15 @@ public:
converting HTML to plain text if necessary. */
TQString asPlainText( bool stripSignature, bool allowDecryption ) const;
+ /**
+ * Same as asPlainText(), only that this method expects an already parsed object tree as
+ * paramter.
+ * By passing an already parsed objecttree, this allows to share the objecttree and therefore
+ * reduce the amount of parsing (which can include decrypting, which can include a passphrase dialog)
+ */
+ TQString asPlainTextFromObjectTree( partNode *root, bool stripSignature,
+ bool allowDecryption ) const;
+
/** Get stored cursor position */
int getCursorPos() { return mCursorPos; };
/** Set cursor position as offset from message start */
@@ -879,6 +936,8 @@ public:
/** Delete this message as soon as it no longer in use. */
void deleteWhenUnused();
+ DwBodyPart* findPart( int index );
+
private:
/** Initialization shared by the ctors. */
@@ -886,10 +945,12 @@ private:
/** Assign the values of @param other to this message. Used in the copy c'tor. */
void assign( const KMMessage& other );
+ DwBodyPart* findPartInternal( DwEntity* root, int index, int &accu );
+
TQString mDrafts;
TQString mTemplates;
mutable DwMessage* mMsg;
- mutable bool mNeedsAssembly :1;
+ mutable bool mNeedsAssembly :1;
bool mDecodeHTML :1;
bool mReadyToShow :1;
bool mComplete :1;
diff --git a/kmail/kmmimeparttree.cpp b/kmail/kmmimeparttree.cpp
index cafef94ec..d7fb9541e 100644
--- a/kmail/kmmimeparttree.cpp
+++ b/kmail/kmmimeparttree.cpp
@@ -129,8 +129,6 @@ void KMMimePartTree::itemRightClicked( TQListViewItem* item,
kdDebug(5006) << "Item was not a KMMimePartTreeItem!" << endl;
}
else {
- kdDebug(5006) << "\n**\n** KMMimePartTree::itemRightClicked() **\n**" << endl;
-
TQPopupMenu* popup = new TQPopupMenu;
if ( mCurrentContextMenuItem->node()->nodeId() > 2 &&
mCurrentContextMenuItem->node()->typeString() != "Multipart" ) {
diff --git a/kmail/kmmsgbase.cpp b/kmail/kmmsgbase.cpp
index df53e6e57..e3d3fec15 100644
--- a/kmail/kmmsgbase.cpp
+++ b/kmail/kmmsgbase.cpp
@@ -243,6 +243,14 @@ void KMMsgBase::setStatus(const KMMsgStatus aStatus, int idx)
mStatus &= ~KMMsgStatusHasAttach;
mStatus |= KMMsgStatusHasNoAttach;
break;
+ case KMMsgStatusHasInvitation:
+ mStatus &= ~KMMsgStatusHasNoInvitation;
+ mStatus |= KMMsgStatusHasInvitation;
+ break;
+ case KMMsgStatusHasNoInvitation:
+ mStatus &= ~KMMsgStatusHasInvitation;
+ mStatus |= KMMsgStatusHasNoInvitation;
+ break;
default:
mStatus = aStatus;
break;
@@ -658,7 +666,8 @@ TQString KMMsgBase::decodeRFC2047String(const TQCString& aStr, TQCString prefCha
return TQString::null;
if ( str.find( "=?" ) < 0 ) {
- if ( !prefCharset.isEmpty() ) {
+ if ( !prefCharset.isEmpty() &&
+ kmkernel->isCodecAsciiCompatible( KMMsgBase::codecForName( prefCharset ) ) ) {
if ( prefCharset == "us-ascii" ) {
// isn`t this foolproof?
return KMMsgBase::codecForName( "utf-8" )->toUnicode( str );
@@ -666,9 +675,15 @@ TQString KMMsgBase::decodeRFC2047String(const TQCString& aStr, TQCString prefCha
return KMMsgBase::codecForName( prefCharset )->toUnicode( str );
}
} else {
- return KMMsgBase::codecForName( GlobalSettings::self()->
+ if ( kmkernel->isCodecAsciiCompatible( KMMsgBase::codecForName(
+ GlobalSettings::self()->fallbackCharacterEncoding().latin1() ) ) ) {
+ return KMMsgBase::codecForName( GlobalSettings::self()->
fallbackCharacterEncoding().latin1() )->toUnicode( str );
+ }
}
+
+ // Not RFC2047 encoded, and codec not ascii-compatible -> interpret as ascii
+ return TQString::fromAscii( str );
}
TQString result;
@@ -917,6 +932,16 @@ TQCString KMMsgBase::encodeRFC2231String( const TQString& _str,
return result;
}
+//-----------------------------------------------------------------------------
+TQCString KMMsgBase::encodeRFC2231StringAutoDetectCharset( const TQString &str,
+ const TQCString &defaultCharset )
+{
+ TQCString encoding = KMMsgBase::autoDetectCharset( defaultCharset,
+ KMMessage::preferredCharsets(), str );
+ if ( encoding.isEmpty() )
+ encoding = "utf-8";
+ return KMMsgBase::encodeRFC2231String( str, encoding );
+}
//-----------------------------------------------------------------------------
TQString KMMsgBase::decodeRFC2231String(const TQCString& _str)
@@ -1077,6 +1102,18 @@ KMMsgAttachmentState KMMsgBase::attachmentState() const
return KMMsgAttachmentUnknown;
}
+
+KMMsgInvitationState KMMsgBase::invitationState() const
+{
+ KMMsgStatus st = status();
+ if (st & KMMsgStatusHasInvitation)
+ return KMMsgHasInvitation;
+ else if (st & KMMsgStatusHasNoInvitation)
+ return KMMsgHasNoInvitation;
+ else
+ return KMMsgInvitationUnknown;
+}
+
//-----------------------------------------------------------------------------
static void swapEndian(TQString &str)
{
@@ -1340,11 +1377,11 @@ const uchar *KMMsgBase::asIndexString(int &length) const
//these are completely arbitrary order
tmp_str = fromStrip().stripWhiteSpace();
- STORE_DATA_LEN(MsgFromPart, tmp_str.unicode(), tmp_str.length() * 2, true);
+ STORE_DATA_LEN(MsgFromStripPart, tmp_str.unicode(), tmp_str.length() * 2, true);
tmp_str = subject().stripWhiteSpace();
STORE_DATA_LEN(MsgSubjectPart, tmp_str.unicode(), tmp_str.length() * 2, true);
tmp_str = toStrip().stripWhiteSpace();
- STORE_DATA_LEN(MsgToPart, tmp_str.unicode(), tmp_str.length() * 2, true);
+ STORE_DATA_LEN(MsgToStripPart, tmp_str.unicode(), tmp_str.length() * 2, true);
tmp_str = replyToIdMD5().stripWhiteSpace();
STORE_DATA_LEN(MsgReplyToIdMD5Part, tmp_str.unicode(), tmp_str.length() * 2, true);
tmp_str = xmark().stripWhiteSpace();
@@ -1376,6 +1413,12 @@ const uchar *KMMsgBase::asIndexString(int &length) const
tmp = UID();
STORE_DATA(MsgUIDPart, tmp);
+ tmp_str = from();
+ STORE_DATA_LEN( MsgFromPart, tmp_str.unicode(), tmp_str.length() * 2, true );
+
+ tmp_str = to();
+ STORE_DATA_LEN( MsgToPart, tmp_str.unicode(), tmp_str.length() * 2, true );
+
return ret;
}
#undef STORE_DATA_LEN
diff --git a/kmail/kmmsgbase.h b/kmail/kmmsgbase.h
index b2d867839..1137bb6e9 100644
--- a/kmail/kmmsgbase.h
+++ b/kmail/kmmsgbase.h
@@ -57,7 +57,9 @@ enum MsgStatus
KMMsgStatusSpam = 0x00002000,
KMMsgStatusHam = 0x00004000,
KMMsgStatusHasAttach = 0x00008000,
- KMMsgStatusHasNoAttach = 0x00010000
+ KMMsgStatusHasNoAttach = 0x00010000,
+ KMMsgStatusHasInvitation = 0x00020000,
+ KMMsgStatusHasNoInvitation = 0x00040000
};
typedef uint KMMsgStatus;
@@ -132,6 +134,13 @@ typedef enum
KMMsgAttachmentUnknown
} KMMsgAttachmentState;
+/** Flags for invitation state */
+typedef enum
+{
+ KMMsgHasInvitation,
+ KMMsgHasNoInvitation,
+ KMMsgInvitationUnknown
+} KMMsgInvitationState;
class KMMsgBase
{
@@ -250,7 +259,9 @@ public:
/** Important header fields of the message that are also kept in the index. */
virtual TQString subject(void) const = 0;
virtual TQString fromStrip(void) const = 0;
+ virtual TQString from() const = 0;
virtual TQString toStrip(void) const = 0;
+ virtual TQString to() const = 0;
virtual TQString replyToIdMD5(void) const = 0;
virtual TQString msgIdMD5(void) const = 0;
virtual TQString replyToAuxIdMD5() const = 0;
@@ -353,11 +364,18 @@ public:
static TQCString encodeRFC2231String(const TQString& aStr,
const TQCString& charset);
+ /**
+ * Just like encodeRFC2231String, only that the encoding is auto-detected.
+ * @param defaultCharset If given, this will be the prefered charset
+ */
+ static TQCString encodeRFC2231StringAutoDetectCharset( const TQString &str,
+ const TQCString &defaultCharset = "" );
+
/** Decode given string as described in RFC2231 */
static TQString decodeRFC2231String(const TQCString& aStr);
/** Extract a given param from the RFC2231-encoded header field, in particular
concatenate possibly multiple entries, which are given as paramname*0=..;
- paramname*1=..; ... or paramname*0*=..; paramname*1*=..; ... and return
+ paramname*1=..; ... or paramname*0*=..; paramname*1*=..; ... and return
their value as one string. That string will still be encoded */
static TQCString extractRFC2231HeaderField( const TQCString &aStr, const TQCString &field );
@@ -385,6 +403,9 @@ public:
/** Return if the message has at least one attachment */
virtual KMMsgAttachmentState attachmentState() const;
+ /** Return if the message contains an invitation */
+ virtual KMMsgInvitationState invitationState() const;
+
/** Check for prefixes @p prefixRegExps in @p str. If none
is found, @p newPrefix + ' ' is prepended to @p str and the
resulting string is returned. If @p replace is true, any
@@ -439,9 +460,9 @@ public:
{
MsgNoPart = 0,
//unicode strings
- MsgFromPart = 1,
+ MsgFromStripPart = 1,
MsgSubjectPart = 2,
- MsgToPart = 3,
+ MsgToStripPart = 3,
MsgReplyToIdMD5Part = 4,
MsgIdMD5Part = 5,
MsgXMarkPart = 6,
@@ -459,7 +480,9 @@ public:
// and another unsigned long
MsgStatusPart = 16,
MsgSizeServerPart = 17,
- MsgUIDPart = 18
+ MsgUIDPart = 18,
+ MsgToPart = 19,
+ MsgFromPart = 20
};
/** access to long msgparts */
off_t getLongPart(MsgPartType) const;
diff --git a/kmail/kmmsgdict.cpp b/kmail/kmmsgdict.cpp
index bedc3bb44..8f9a9551c 100644
--- a/kmail/kmmsgdict.cpp
+++ b/kmail/kmmsgdict.cpp
@@ -458,8 +458,15 @@ int KMMsgDict::readFolderIds( FolderStorage& storage )
return -1;
}
- //if (!msn)
- //kdDebug(5006) << "Dict found zero serial number in folder " << folder->label() << endl;
+ // We found a serial number that is zero. This is not allowed, and would
+ // later cause problems like in bug 149715.
+ // Therefore, use a fresh serial number instead
+ if ( msn == 0 ) {
+ kdWarning(5006) << "readFolderIds(): Found serial number zero at index " << index
+ << " in folder " << filename << endl;
+ msn = getNextMsgSerNum();
+ Q_ASSERT( msn != 0 );
+ }
// Insert into the dict. Don't use dict->replace() as we _know_
// there is no entry with the same msn, we just made sure.
@@ -556,6 +563,10 @@ int KMMsgDict::writeFolderIds( const FolderStorage &storage )
Q_UINT32 msn = rentry->getMsn(index);
if (!fwrite(&msn, sizeof(msn), 1, fp))
return -1;
+ if ( msn == 0 ) {
+ kdWarning(5006) << "writeFolderIds(): Serial number of message at index "
+ << index << " is zero in folder " << storage.label() << endl;
+ }
}
rentry->sync();
diff --git a/kmail/kmmsginfo.cpp b/kmail/kmmsginfo.cpp
index 3b1112dc4..ece847a38 100644
--- a/kmail/kmmsginfo.cpp
+++ b/kmail/kmmsginfo.cpp
@@ -18,16 +18,17 @@ class KMMsgInfo::KMMsgInfoPrivate
{
public:
enum {
- SUBJECT_SET = 0x01, TO_SET = 0x02, REPLYTO_SET = 0x04, MSGID_SET=0x08,
+ SUBJECT_SET = 0x01, TOSTRIP_SET = 0x02, REPLYTO_SET = 0x04, MSGID_SET=0x08,
DATE_SET = 0x10, OFFSET_SET = 0x20, SIZE_SET = 0x40, SIZESERVER_SET = 0x80,
- XMARK_SET=0x100, FROM_SET=0x200, FILE_SET=0x400, ENCRYPTION_SET=0x800,
+ XMARK_SET=0x100, FROMSTRIP_SET=0x200, FILE_SET=0x400, ENCRYPTION_SET=0x800,
SIGNATURE_SET=0x1000, MDN_SET=0x2000, REPLYTOAUX_SET = 0x4000,
STRIPPEDSUBJECT_SET = 0x8000, UID_SET = 0x10000,
+ TO_SET = 0x20000, FROM_SET = 0x40000,
ALL_SET = 0xFFFFFF, NONE_SET = 0x000000
};
uint modifiers;
- TQString subject, from, to, replyToIdMD5, replyToAuxIdMD5,
+ TQString subject, fromStrip, toStrip, replyToIdMD5, replyToAuxIdMD5,
strippedSubjectMD5, msgIdMD5, xmark, file;
off_t folderOffset;
size_t msgSize, msgSizeServer;
@@ -36,6 +37,7 @@ public:
KMMsgSignatureState signatureState;
KMMsgMDNSentState mdnSentState;
ulong UID;
+ TQString to, from;
KMMsgInfoPrivate() : modifiers(NONE_SET) { }
KMMsgInfoPrivate& operator=(const KMMsgInfoPrivate& other) {
@@ -48,17 +50,17 @@ public:
modifiers |= STRIPPEDSUBJECT_SET;
strippedSubjectMD5 = other.strippedSubjectMD5;
}
- if (other.modifiers & FROM_SET) {
- modifiers |= FROM_SET;
- from = other.from;
+ if (other.modifiers & FROMSTRIP_SET) {
+ modifiers |= FROMSTRIP_SET;
+ fromStrip = other.fromStrip;
}
if (other.modifiers & FILE_SET) {
modifiers |= FILE_SET;
- file = other.from;
+ file = other.file;
}
- if (other.modifiers & TO_SET) {
- modifiers |= TO_SET;
- to = other.to;
+ if (other.modifiers & TOSTRIP_SET) {
+ modifiers |= TOSTRIP_SET;
+ toStrip = other.toStrip;
}
if (other.modifiers & REPLYTO_SET) {
modifiers |= REPLYTO_SET;
@@ -109,6 +111,14 @@ public:
modifiers |= UID_SET;
UID = other.UID;
}
+ if (other.modifiers & TO_SET) {
+ modifiers |= TO_SET;
+ to = other.to;
+ }
+ if (other.modifiers & FROM_SET) {
+ modifiers |= FROM_SET;
+ from = other.from;
+ }
return *this;
}
};
@@ -157,8 +167,8 @@ KMMsgInfo& KMMsgInfo::operator=(const KMMessage& msg)
kd = new KMMsgInfoPrivate;
kd->modifiers = KMMsgInfoPrivate::ALL_SET;
kd->subject = msg.subject();
- kd->from = msg.fromStrip();
- kd->to = msg.toStrip();
+ kd->fromStrip = msg.fromStrip();
+ kd->toStrip = msg.toStrip();
kd->replyToIdMD5 = msg.replyToIdMD5();
kd->replyToAuxIdMD5 = msg.replyToAuxIdMD5();
kd->strippedSubjectMD5 = msg.strippedSubjectMD5();
@@ -174,6 +184,8 @@ KMMsgInfo& KMMsgInfo::operator=(const KMMessage& msg)
kd->mdnSentState = msg.mdnSentState();
kd->msgSizeServer = msg.msgSizeServer();
kd->UID = msg.UID();
+ kd->to = msg.to();
+ kd->from = msg.from();
return *this;
}
@@ -187,8 +199,8 @@ void KMMsgInfo::init(const TQCString& aSubject, const TQCString& aFrom,
KMMsgSignatureState signatureState,
KMMsgMDNSentState mdnSentState,
const TQCString& prefCharset,
- off_t aFolderOffset, size_t aMsgSize,
- size_t aMsgSizeServer, ulong aUID)
+ off_t aFolderOffset, size_t aMsgSize,
+ size_t aMsgSizeServer, ulong aUID)
{
mIndexOffset = 0;
mIndexLength = 0;
@@ -196,8 +208,8 @@ void KMMsgInfo::init(const TQCString& aSubject, const TQCString& aFrom,
kd = new KMMsgInfoPrivate;
kd->modifiers = KMMsgInfoPrivate::ALL_SET;
kd->subject = decodeRFC2047String(aSubject, prefCharset);
- kd->from = decodeRFC2047String( KMMessage::stripEmailAddr( aFrom ), prefCharset );
- kd->to = decodeRFC2047String( KMMessage::stripEmailAddr( aTo ), prefCharset );
+ kd->fromStrip = decodeRFC2047String( KMMessage::stripEmailAddr( aFrom ), prefCharset );
+ kd->toStrip = decodeRFC2047String( KMMessage::stripEmailAddr( aTo ), prefCharset );
kd->replyToIdMD5 = base64EncodedMD5( replyToId );
kd->replyToAuxIdMD5 = base64EncodedMD5( replyToAuxId );
kd->strippedSubjectMD5 = base64EncodedMD5( KMMessage::stripOffPrefixes( kd->subject ), true /*utf8*/ );
@@ -213,7 +225,9 @@ void KMMsgInfo::init(const TQCString& aSubject, const TQCString& aFrom,
kd->mdnSentState = mdnSentState;
kd->msgSizeServer = aMsgSizeServer;
kd->UID = aUID;
- mDirty = false;
+ kd->to = aTo;
+ kd->from = aFrom;
+ mDirty = false;
}
void KMMsgInfo::init(const TQCString& aSubject, const TQCString& aFrom,
@@ -245,15 +259,23 @@ TQString KMMsgInfo::subject(void) const
return getStringPart(MsgSubjectPart);
}
-
//-----------------------------------------------------------------------------
TQString KMMsgInfo::fromStrip(void) const
{
+ if (kd && kd->modifiers & KMMsgInfoPrivate::FROMSTRIP_SET)
+ return kd->fromStrip;
+ return getStringPart(MsgFromStripPart);
+}
+
+//-----------------------------------------------------------------------------
+TQString KMMsgInfo::from() const
+{
if (kd && kd->modifiers & KMMsgInfoPrivate::FROM_SET)
return kd->from;
- return getStringPart(MsgFromPart);
+ return getStringPart( MsgFromPart );
}
+
//-----------------------------------------------------------------------------
TQString KMMsgInfo::fileName(void) const
{
@@ -266,9 +288,17 @@ TQString KMMsgInfo::fileName(void) const
//-----------------------------------------------------------------------------
TQString KMMsgInfo::toStrip(void) const
{
+ if (kd && kd->modifiers & KMMsgInfoPrivate::TOSTRIP_SET)
+ return kd->toStrip;
+ return getStringPart(MsgToStripPart);
+}
+
+//-----------------------------------------------------------------------------
+TQString KMMsgInfo::to() const
+{
if (kd && kd->modifiers & KMMsgInfoPrivate::TO_SET)
return kd->to;
- return getStringPart(MsgToPart);
+ return getStringPart( MsgToPart );
}
//-----------------------------------------------------------------------------
@@ -656,6 +686,24 @@ void KMMsgInfo::setDate(time_t aUnixTime)
mDirty = true;
}
+void KMMsgInfo::setFrom( const TQString &from )
+{
+ if ( !kd )
+ kd = new KMMsgInfoPrivate;
+ kd->modifiers |= KMMsgInfoPrivate::FROM_SET;
+ kd->from = from;
+ mDirty = true;
+}
+
+void KMMsgInfo::setTo( const TQString &to )
+{
+ if ( !kd )
+ kd = new KMMsgInfoPrivate;
+ kd->modifiers |= KMMsgInfoPrivate::TO_SET;
+ kd->to = to;
+ mDirty = true;
+}
+
//--- For compatability with old index files
void KMMsgInfo::compat_fromOldIndexString(const TQCString& str, bool toUtf8)
{
@@ -671,8 +719,8 @@ void KMMsgInfo::compat_fromOldIndexString(const TQCString& str, bool toUtf8)
mStatus = (KMMsgStatus)str.at(0);
if (toUtf8) {
kd->subject = str.mid(37, 100).stripWhiteSpace();
- kd->from = str.mid(138, 50).stripWhiteSpace();
- kd->to = str.mid(189, 50).stripWhiteSpace();
+ kd->fromStrip = str.mid(138, 50).stripWhiteSpace();
+ kd->toStrip = str.mid(189, 50).stripWhiteSpace();
} else {
start = offset = str.data() + 37;
while (*start == ' ' && start - offset < 100) start++;
@@ -680,11 +728,11 @@ void KMMsgInfo::compat_fromOldIndexString(const TQCString& str, bool toUtf8)
100 - (start - offset)), 100 - (start - offset));
start = offset = str.data() + 138;
while (*start == ' ' && start - offset < 50) start++;
- kd->from = TQString::fromUtf8(str.mid(start - str.data(),
+ kd->fromStrip = TQString::fromUtf8(str.mid(start - str.data(),
50 - (start - offset)), 50 - (start - offset));
start = offset = str.data() + 189;
while (*start == ' ' && start - offset < 50) start++;
- kd->to = TQString::fromUtf8(str.mid(start - str.data(),
+ kd->toStrip = TQString::fromUtf8(str.mid(start - str.data(),
50 - (start - offset)), 50 - (start - offset));
}
kd->replyToIdMD5 = str.mid(240, 22).stripWhiteSpace();
diff --git a/kmail/kmmsginfo.h b/kmail/kmmsginfo.h
index 043830200..8f557f25b 100644
--- a/kmail/kmmsginfo.h
+++ b/kmail/kmmsginfo.h
@@ -68,7 +68,9 @@ public:
/** Inherited methods (see KMMsgBase for description): */
virtual TQString subject(void) const;
virtual TQString fromStrip(void) const;
+ virtual TQString from() const;
virtual TQString toStrip(void) const;
+ virtual TQString to() const;
virtual TQString xmark(void) const;
virtual TQString replyToIdMD5(void) const;
virtual TQString replyToAuxIdMD5() const;
@@ -101,6 +103,8 @@ public:
virtual void setSignatureState( const KMMsgSignatureState, int idx = -1 );
virtual void setMDNSentState( const KMMsgMDNSentState, int idx = -1 );
virtual void setUID(ulong);
+ virtual void setFrom( const TQString &from );
+ virtual void setTo( const TQString &to );
/** Grr.. c++! */
virtual void setStatus(const char* s1, const char* s2=0) { KMMsgBase::setStatus(s1, s2); }
diff --git a/kmail/kmmsgpart.cpp b/kmail/kmmsgpart.cpp
index 085e36c0f..112236c03 100644
--- a/kmail/kmmsgpart.cpp
+++ b/kmail/kmmsgpart.cpp
@@ -284,6 +284,9 @@ void KMMessagePart::setBodyEncodedBinary(const TQByteArray& aStr)
assert( codec );
// Nice: We can use the convenience function :-)
mBody = codec->encode( aStr );
+ // QP encoding does CRLF -> LF conversion, which can change the size after decoding again
+ // and a size mismatch triggers an assert in various other methods
+ mBodyDecodedSize = -1;
break;
}
default:
@@ -585,7 +588,7 @@ TQString KMMessagePart::fileName(void) const
const TQCString str = mContentDisposition.mid(startOfFilename,
endOfFilename-startOfFilename+1)
.stripWhiteSpace();
- return KMMsgBase::decodeRFC2047String(str, charset());
+ return KMMsgBase::decodeRFC2047String(str);
}
return TQString::null;
diff --git a/kmail/kmmsgpartdlg.cpp b/kmail/kmmsgpartdlg.cpp
index 921c9d55b..4a897291f 100644
--- a/kmail/kmmsgpartdlg.cpp
+++ b/kmail/kmmsgpartdlg.cpp
@@ -390,10 +390,7 @@ void KMMsgPartDialogCompat::applyChanges()
TQString name = fileName();
if ( !name.isEmpty() || !mMsgPart->name().isEmpty()) {
mMsgPart->setName( name );
- TQCString encoding = KMMsgBase::autoDetectCharset( mMsgPart->charset(),
- KMMessage::preferredCharsets(), name );
- if ( encoding.isEmpty() ) encoding = "utf-8";
- TQCString encName = KMMsgBase::encodeRFC2231String( name, encoding );
+ TQCString encName = KMMsgBase::encodeRFC2231StringAutoDetectCharset( name, mMsgPart->charset() );
cDisp += "\n\tfilename";
if ( name != TQString( encName ) )
diff --git a/kmail/kmpopheaders.cpp b/kmail/kmpopheaders.cpp
index 85445abd2..2828a49e0 100644
--- a/kmail/kmpopheaders.cpp
+++ b/kmail/kmpopheaders.cpp
@@ -22,8 +22,7 @@ KMPopHeaders::KMPopHeaders()
}
KMPopHeaders::~KMPopHeaders(){
- if (mHeader)
- delete mHeader;
+ delete mHeader;
}
/** No descriptions */
diff --git a/kmail/kmreadermainwin.cpp b/kmail/kmreadermainwin.cpp
index 8e77ad9d7..2f5227cde 100644
--- a/kmail/kmreadermainwin.cpp
+++ b/kmail/kmreadermainwin.cpp
@@ -140,10 +140,15 @@ void KMReaderMainWin::setUseFixedFont( bool useFixedFont )
}
//-----------------------------------------------------------------------------
-void KMReaderMainWin::showMsg( const TQString & encoding, KMMessage *msg )
+void KMReaderMainWin::showMsg( const TQString & encoding, KMMessage *msg,
+ unsigned long serNumOfOriginalMessage, int nodeIdOffset )
{
mReaderWin->setOverrideEncoding( encoding );
mReaderWin->setMsg( msg, true );
+ if ( serNumOfOriginalMessage != 0 ) {
+ Q_ASSERT( nodeIdOffset != -1 );
+ mReaderWin->setOriginalMsg( serNumOfOriginalMessage, nodeIdOffset );
+ }
mReaderWin->slotTouchMessage();
setCaption( msg->subject() );
mMsg = msg;
@@ -163,6 +168,13 @@ void KMReaderMainWin::slotFolderRemoved( TQObject* folderPtr )
mMsg->setParent( 0 );
}
+void KMReaderMainWin::slotReplyOrForwardFinished()
+{
+ if ( GlobalSettings::self()->closeAfterReplyOrForward() ) {
+ close();
+ }
+}
+
//-----------------------------------------------------------------------------
void KMReaderMainWin::slotTrashMsg()
{
@@ -212,6 +224,7 @@ void KMReaderMainWin::slotMarkAll()
void KMReaderMainWin::slotPrintMsg()
{
KMPrintCommand *command = new KMPrintCommand( this, mReaderWin->message(),
+ mReaderWin->headerStyle(), mReaderWin->headerStrategy(),
mReaderWin->htmlOverride(), mReaderWin->htmlLoadExtOverride(),
mReaderWin->isFixedFont(), mReaderWin->overrideEncoding() );
command->setOverrideFont( mReaderWin->cssHelper()->bodyFont( mReaderWin->isFixedFont(), true /*printing*/ ) );
@@ -228,6 +241,8 @@ void KMReaderMainWin::slotForwardInlineMsg()
} else {
command = new KMForwardInlineCommand( this, mReaderWin->message() );
}
+ connect( command, TQT_SIGNAL( completed( KMCommand * ) ),
+ this, TQT_SLOT( slotReplyOrForwardFinished() ) );
command->start();
}
@@ -241,6 +256,8 @@ void KMReaderMainWin::slotForwardAttachedMsg()
} else {
command = new KMForwardAttachedCommand( this, mReaderWin->message() );
}
+ connect( command, TQT_SIGNAL( completed( KMCommand * ) ),
+ this, TQT_SLOT( slotReplyOrForwardFinished() ) );
command->start();
}
@@ -254,6 +271,8 @@ void KMReaderMainWin::slotForwardDigestMsg()
} else {
command = new KMForwardDigestCommand( this, mReaderWin->message() );
}
+ connect( command, TQT_SIGNAL( completed( KMCommand * ) ),
+ this, TQT_SLOT( slotReplyOrForwardFinished() ) );
command->start();
}
@@ -261,6 +280,8 @@ void KMReaderMainWin::slotForwardDigestMsg()
void KMReaderMainWin::slotRedirectMsg()
{
KMCommand *command = new KMRedirectCommand( this, mReaderWin->message() );
+ connect( command, TQT_SIGNAL( completed( KMCommand * ) ),
+ this, TQT_SLOT( slotReplyOrForwardFinished() ) );
command->start();
}
@@ -276,9 +297,36 @@ void KMReaderMainWin::slotShowMsgSrc()
}
//-----------------------------------------------------------------------------
+void KMReaderMainWin::setupForwardActions()
+{
+ disconnect( mForwardActionMenu, TQT_SIGNAL( activated() ), 0, 0 );
+ mForwardActionMenu->remove( mForwardInlineAction );
+ mForwardActionMenu->remove( mForwardAttachedAction );
+
+ if ( GlobalSettings::self()->forwardingInlineByDefault() ) {
+ mForwardActionMenu->insert( mForwardInlineAction, 0 );
+ mForwardActionMenu->insert( mForwardAttachedAction, 1 );
+ mForwardInlineAction->setShortcut( Key_F );
+ mForwardAttachedAction->setShortcut( SHIFT+Key_F );
+ connect( mForwardActionMenu, TQT_SIGNAL(activated()), this,
+ TQT_SLOT(slotForwardInlineMsg()) );
+
+ } else {
+ mForwardActionMenu->insert( mForwardAttachedAction, 0 );
+ mForwardActionMenu->insert( mForwardInlineAction, 1 );
+ mForwardInlineAction->setShortcut( SHIFT+Key_F );
+ mForwardAttachedAction->setShortcut( Key_F );
+ connect( mForwardActionMenu, TQT_SIGNAL(activated()), this,
+ TQT_SLOT(slotForwardAttachedMsg()) );
+ }
+}
+
+//-----------------------------------------------------------------------------
void KMReaderMainWin::slotConfigChanged()
{
//readConfig();
+ setupForwardActions();
+ setupForwardingActionsList();
}
void KMReaderMainWin::setupAccel()
@@ -288,6 +336,9 @@ void KMReaderMainWin::setupAccel()
mMsgActions = new KMail::MessageActions( actionCollection(), this );
mMsgActions->setMessageView( mReaderWin );
+ connect( mMsgActions, TQT_SIGNAL( replyActionFinished() ),
+ this, TQT_SLOT( slotReplyOrForwardFinished() ) );
+
//----- File Menu
//mOpenAction = KStdAction::open( this, TQT_SLOT( slotOpenMsg() ),
// actionCollection() );
@@ -351,21 +402,7 @@ void KMReaderMainWin::setupAccel()
actionCollection(),
"message_forward_redirect" );
- if ( GlobalSettings::self()->forwardingInlineByDefault() ) {
- mForwardActionMenu->insert( mForwardInlineAction );
- mForwardActionMenu->insert( mForwardAttachedAction );
- mForwardInlineAction->setShortcut( Key_F );
- mForwardAttachedAction->setShortcut( SHIFT+Key_F );
- connect( mForwardActionMenu, TQT_SIGNAL(activated()), this,
- TQT_SLOT(slotForwardInlineMsg()) );
- } else {
- mForwardActionMenu->insert( mForwardAttachedAction );
- mForwardActionMenu->insert( mForwardInlineAction );
- mForwardInlineAction->setShortcut( SHIFT+Key_F );
- mForwardAttachedAction->setShortcut( Key_F );
- connect( mForwardActionMenu, TQT_SIGNAL(activated()), this,
- TQT_SLOT(slotForwardAttachedMsg()) );
- }
+ setupForwardActions();
mForwardActionMenu->insert( mForwardDigestAction );
mForwardActionMenu->insert( mRedirectAction );
@@ -408,7 +445,7 @@ void KMReaderMainWin::slotMsgPopup(KMMessage &aMsg, const KURL &aUrl, const TQPo
mUrl = aUrl;
mMsg = &aMsg;
bool urlMenuAdded=false;
-
+ bool copyAdded = false;
if (!aUrl.isEmpty())
{
if (aUrl.protocol() == "mailto") {
@@ -421,7 +458,8 @@ void KMReaderMainWin::slotMsgPopup(KMMessage &aMsg, const KURL &aUrl, const TQPo
}
mReaderWin->addAddrBookAction()->plug( menu );
mReaderWin->openAddrBookAction()->plug( menu );
- mReaderWin->copyAction()->plug( menu );
+ mReaderWin->copyURLAction()->plug( menu );
+ copyAdded = true;
} else {
// popup on a not-mailto URL
mReaderWin->urlOpenAction()->plug( menu );
@@ -436,8 +474,8 @@ void KMReaderMainWin::slotMsgPopup(KMMessage &aMsg, const KURL &aUrl, const TQPo
menu->insertSeparator();
mMsgActions->replyMenu()->plug( menu );
menu->insertSeparator();
-
- mReaderWin->copyAction()->plug( menu );
+ if( !copyAdded )
+ mReaderWin->copyAction()->plug( menu );
mReaderWin->selectAllAction()->plug( menu );
} else if ( !urlMenuAdded )
{
diff --git a/kmail/kmreadermainwin.h b/kmail/kmreadermainwin.h
index ba458eb0a..a4d8e9725 100644
--- a/kmail/kmreadermainwin.h
+++ b/kmail/kmreadermainwin.h
@@ -36,8 +36,16 @@ public:
void setUseFixedFont( bool useFixedFont );
- // take ownership of and show @param msg
- void showMsg( const TQString & encoding, KMMessage *msg );
+ /**
+ * take ownership of and show @param msg
+ *
+ * The last two paramters, serNumOfOriginalMessage and nodeIdOffset, are needed when @p msg
+ * is derived from another message, e.g. the user views an encapsulated message in this window.
+ * Then, the reader needs to know about that original message, so those to paramters are passed
+ * onto setOriginalMsg() of KMReaderWin.
+ */
+ void showMsg( const TQString & encoding, KMMessage *msg,
+ unsigned long serNumOfOriginalMessage = 0, int nodeIdOffset = -1 );
/**
* Sets up action list for forward menu.
@@ -70,10 +78,19 @@ private slots:
void slotFolderRemoved( TQObject* folderPtr );
+ /// This closes the window if the setting to close the window after replying or
+ /// forwarding is set.
+ void slotReplyOrForwardFinished();
+
private:
void initKMReaderMainWin();
void setupAccel();
+ /**
+ * @see the KMMainWidget function with the same name.
+ */
+ void setupForwardActions();
+
KMReaderWin *mReaderWin;
KMMessage *mMsg;
KURL mUrl;
diff --git a/kmail/kmreaderwin.cpp b/kmail/kmreaderwin.cpp
index b5ee41052..21be5a44a 100644
--- a/kmail/kmreaderwin.cpp
+++ b/kmail/kmreaderwin.cpp
@@ -52,6 +52,7 @@ using KMail::ISubject;
using KMail::URLHandlerManager;
#include "interfaces/observable.h"
#include "util.h"
+#include "kmheaders.h"
#include "broadcaststatus.h"
@@ -86,7 +87,7 @@ using KMail::TeeHtmlWriter;
#include <dom/html_block.h>
#include <dom/html_document.h>
#include <dom/dom_string.h>
-
+#include <dom/dom_exception.h>
#include <kapplication.h>
// for the click on attachment stuff (dnaber):
@@ -208,81 +209,33 @@ void KMReaderWin::objectTreeToDecryptedMsg( partNode* node,
kdDebug(5006) << TQString("-------------------------------------------------" ) << endl;
kdDebug(5006) << TQString("KMReaderWin::objectTreeToDecryptedMsg( %1 ) START").arg( recCount ) << endl;
if( node ) {
+
+ kdDebug(5006) << node->typeString() << '/' << node->subTypeString() << endl;
+
partNode* curNode = node;
partNode* dataNode = curNode;
partNode * child = node->firstChild();
- bool bIsMultipart = false;
+ const bool bIsMultipart = node->type() == DwMime::kTypeMultipart ;
+ bool bKeepPartAsIs = false;
switch( curNode->type() ){
- case DwMime::kTypeText: {
-kdDebug(5006) << "* text *" << endl;
- switch( curNode->subType() ){
- case DwMime::kSubtypeHtml:
-kdDebug(5006) << "html" << endl;
- break;
- case DwMime::kSubtypeXVCard:
-kdDebug(5006) << "v-card" << endl;
- break;
- case DwMime::kSubtypeRichtext:
-kdDebug(5006) << "rich text" << endl;
- break;
- case DwMime::kSubtypeEnriched:
-kdDebug(5006) << "enriched " << endl;
- break;
- case DwMime::kSubtypePlain:
-kdDebug(5006) << "plain " << endl;
- break;
- default:
-kdDebug(5006) << "default " << endl;
- break;
- }
- }
- break;
case DwMime::kTypeMultipart: {
-kdDebug(5006) << "* multipart *" << endl;
- bIsMultipart = true;
switch( curNode->subType() ){
- case DwMime::kSubtypeMixed:
-kdDebug(5006) << "mixed" << endl;
- break;
- case DwMime::kSubtypeAlternative:
-kdDebug(5006) << "alternative" << endl;
- break;
- case DwMime::kSubtypeDigest:
-kdDebug(5006) << "digest" << endl;
- break;
- case DwMime::kSubtypeParallel:
-kdDebug(5006) << "parallel" << endl;
- break;
- case DwMime::kSubtypeSigned:
-kdDebug(5006) << "signed" << endl;
+ case DwMime::kSubtypeSigned: {
+ bKeepPartAsIs = true;
+ }
break;
case DwMime::kSubtypeEncrypted: {
-kdDebug(5006) << "encrypted" << endl;
- if ( child ) {
- /*
- ATTENTION: This code is to be replaced by the new 'auto-detect' feature. --------------------------------------
- */
- partNode* data =
- child->findType( DwMime::kTypeApplication, DwMime::kSubtypeOctetStream, false, true );
- if ( !data )
- data = child->findType( DwMime::kTypeApplication, DwMime::kSubtypePkcs7Mime, false, true );
- if ( data && data->firstChild() )
- dataNode = data;
- }
+ if ( child )
+ dataNode = child;
}
break;
- default :
-kdDebug(5006) << "( unknown subtype )" << endl;
- break;
}
}
break;
case DwMime::kTypeMessage: {
-kdDebug(5006) << "* message *" << endl;
switch( curNode->subType() ){
case DwMime::kSubtypeRfc822: {
-kdDebug(5006) << "RfC 822" << endl;
if ( child )
dataNode = child;
}
@@ -291,25 +244,19 @@ kdDebug(5006) << "RfC 822" << endl;
}
break;
case DwMime::kTypeApplication: {
-kdDebug(5006) << "* application *" << endl;
switch( curNode->subType() ){
- case DwMime::kSubtypePostscript:
-kdDebug(5006) << "postscript" << endl;
- break;
case DwMime::kSubtypeOctetStream: {
-kdDebug(5006) << "octet stream" << endl;
if ( child )
dataNode = child;
}
break;
- case DwMime::kSubtypePgpEncrypted:
-kdDebug(5006) << "pgp encrypted" << endl;
- break;
- case DwMime::kSubtypePgpSignature:
-kdDebug(5006) << "pgp signed" << endl;
+ case DwMime::kSubtypePkcs7Signature: {
+ // note: subtype Pkcs7Signature specifies a signature part
+ // which we do NOT want to remove!
+ bKeepPartAsIs = true;
+ }
break;
case DwMime::kSubtypePkcs7Mime: {
-kdDebug(5006) << "pkcs7 mime" << endl;
// note: subtype Pkcs7Mime can also be signed
// and we do NOT want to remove the signature!
if ( child && curNode->encryptionState() != KMMsgNotEncrypted )
@@ -319,39 +266,6 @@ kdDebug(5006) << "pkcs7 mime" << endl;
}
}
break;
- case DwMime::kTypeImage: {
-kdDebug(5006) << "* image *" << endl;
- switch( curNode->subType() ){
- case DwMime::kSubtypeJpeg:
-kdDebug(5006) << "JPEG" << endl;
- break;
- case DwMime::kSubtypeGif:
-kdDebug(5006) << "GIF" << endl;
- break;
- }
- }
- break;
- case DwMime::kTypeAudio: {
-kdDebug(5006) << "* audio *" << endl;
- switch( curNode->subType() ){
- case DwMime::kSubtypeBasic:
-kdDebug(5006) << "basic" << endl;
- break;
- }
- }
- break;
- case DwMime::kTypeVideo: {
-kdDebug(5006) << "* video *" << endl;
- switch( curNode->subType() ){
- case DwMime::kSubtypeMpeg:
-kdDebug(5006) << "mpeg" << endl;
- break;
- }
- }
- break;
- case DwMime::kTypeModel:
-kdDebug(5006) << "* model *" << endl;
- break;
}
@@ -389,6 +303,10 @@ kdDebug(5006) << " new Content-Type = " << headers->ContentType(
}
}
+ if ( bKeepPartAsIs ) {
+ resultingData += dataNode->encodedBody();
+ } else {
+
// B) Store the body of this part.
if( headers && bIsMultipart && dataNode->firstChild() ) {
kdDebug(5006) << "is valid Multipart, processing children:" << endl;
@@ -424,6 +342,7 @@ kdDebug(5006) << "Multipart processing children - DONE" << endl;
kdDebug(5006) << "is Simple part or invalid Multipart, storing body data .. DONE" << endl;
resultingData += part->Body().AsString().c_str();
}
+ }
} else {
kdDebug(5006) << "dataNode != curNode: Replace curNode by dataNode." << endl;
bool rootNodeReplaceFlag = weAreReplacingTheRootNode || !curNode->parentNode();
@@ -488,6 +407,8 @@ KMReaderWin::KMReaderWin(TQWidget *aParent,
const char *aName,
int aFlags )
: TQWidget(aParent, aName, aFlags | Qt::WDestructiveClose),
+ mSerNumOfOriginalMessage( 0 ),
+ mNodeIdOffset( -1 ),
mAttachmentStrategy( 0 ),
mHeaderStrategy( 0 ),
mHeaderStyle( 0 ),
@@ -511,14 +432,18 @@ KMReaderWin::KMReaderWin(TQWidget *aParent,
mAddBookmarksAction( 0 ),
mStartIMChatAction( 0 ),
mSelectAllAction( 0 ),
+ mHeaderOnlyAttachmentsAction( 0 ),
mSelectEncodingAction( 0 ),
mToggleFixFontAction( 0 ),
+ mCanStartDrag( false ),
mHtmlWriter( 0 ),
mSavedRelativePosition( 0 ),
mDecrytMessageOverwrite( false ),
mShowSignatureDetails( false ),
- mShowAttachmentQuicklist( true )
+ mShowAttachmentQuicklist( true ),
+ mShowRawToltecMail( false )
{
+ mExternalWindow = (aParent == mainWindow );
mSplitterSizes << 180 << 100;
mMimeTreeMode = 1;
mMimeTreeAtBottom = true;
@@ -526,7 +451,6 @@ KMReaderWin::KMReaderWin(TQWidget *aParent,
mLastSerNum = 0;
mWaitingForSerNum = 0;
mMessage = 0;
- mLastStatus = KMMsgStatusUnknown;
mMsgDisplay = true;
mPrinting = false;
mShowColorbar = false;
@@ -642,6 +566,13 @@ void KMReaderWin::createActions( KActionCollection * ac ) {
raction->setExclusiveGroup( "view_attachments_group" );
attachmentMenu->insert( raction );
+ mHeaderOnlyAttachmentsAction = new KRadioAction( i18n( "View->attachments->", "In Header &Only" ), 0,
+ this, TQT_SLOT( slotHeaderOnlyAttachments() ),
+ ac, "view_attachments_headeronly" );
+ mHeaderOnlyAttachmentsAction->setToolTip( i18n( "Show Attachments only in the header of the mail" ) );
+ mHeaderOnlyAttachmentsAction->setExclusiveGroup( "view_attachments_group" );
+ attachmentMenu->insert( mHeaderOnlyAttachmentsAction );
+
// Set Encoding submenu
mSelectEncodingAction = new KSelectAction( i18n( "&Set Encoding" ), "charset", 0,
this, TQT_SLOT( slotSetEncoding() ),
@@ -725,6 +656,8 @@ KRadioAction *KMReaderWin::actionForAttachmentStrategy( const AttachmentStrategy
actionName = "view_attachments_inline";
else if ( as == AttachmentStrategy::hidden() )
actionName = "view_attachments_hide";
+ else if ( as == AttachmentStrategy::headerOnly() )
+ actionName = "view_attachments_headeronly";
if ( actionName )
return static_cast<KRadioAction*>(mActionCollection->action(actionName));
@@ -735,37 +668,46 @@ KRadioAction *KMReaderWin::actionForAttachmentStrategy( const AttachmentStrategy
void KMReaderWin::slotEnterpriseHeaders() {
setHeaderStyleAndStrategy( HeaderStyle::enterprise(),
HeaderStrategy::rich() );
+ if( !mExternalWindow )
+ writeConfig();
}
void KMReaderWin::slotFancyHeaders() {
setHeaderStyleAndStrategy( HeaderStyle::fancy(),
HeaderStrategy::rich() );
+ if( !mExternalWindow )
+ writeConfig();
}
void KMReaderWin::slotBriefHeaders() {
setHeaderStyleAndStrategy( HeaderStyle::brief(),
HeaderStrategy::brief() );
+ if( !mExternalWindow )
+ writeConfig();
}
void KMReaderWin::slotStandardHeaders() {
setHeaderStyleAndStrategy( HeaderStyle::plain(),
HeaderStrategy::standard());
+ writeConfig();
}
void KMReaderWin::slotLongHeaders() {
setHeaderStyleAndStrategy( HeaderStyle::plain(),
HeaderStrategy::rich() );
+ if( !mExternalWindow )
+ writeConfig();
}
void KMReaderWin::slotAllHeaders() {
setHeaderStyleAndStrategy( HeaderStyle::plain(),
HeaderStrategy::all() );
+ if( !mExternalWindow )
+ writeConfig();
}
void KMReaderWin::slotLevelQuote( int l )
{
- kdDebug( 5006 ) << "Old Level: " << mLevelQuote << " New Level: " << l << endl;
-
mLevelQuote = l;
saveRelativePosition();
update(true);
@@ -820,6 +762,10 @@ void KMReaderWin::slotHideAttachments() {
setAttachmentStrategy( AttachmentStrategy::hidden() );
}
+void KMReaderWin::slotHeaderOnlyAttachments() {
+ setAttachmentStrategy( AttachmentStrategy::headerOnly() );
+}
+
void KMReaderWin::slotCycleAttachmentStrategy() {
setAttachmentStrategy( attachmentStrategy()->next() );
KRadioAction * action = actionForAttachmentStrategy( attachmentStrategy() );
@@ -831,6 +777,7 @@ void KMReaderWin::slotCycleAttachmentStrategy() {
//-----------------------------------------------------------------------------
KMReaderWin::~KMReaderWin()
{
+ clearBodyPartMementos();
delete mHtmlWriter; mHtmlWriter = 0;
delete mCSSHelper;
if (mAutoDelete) delete message();
@@ -846,7 +793,7 @@ void KMReaderWin::slotMessageArrived( KMMessage *msg )
if ( msg->getMsgSerNum() == mWaitingForSerNum ) {
setMsg( msg, true );
} else {
- kdDebug( 5006 ) << "KMReaderWin::slotMessageArrived - ignoring update" << endl;
+ //kdDebug( 5006 ) << "KMReaderWin::slotMessageArrived - ignoring update" << endl;
}
}
}
@@ -856,7 +803,7 @@ void KMReaderWin::update( KMail::Interface::Observable * observable )
{
if ( !mAtmUpdate ) {
// reparse the msg
- kdDebug(5006) << "KMReaderWin::update - message" << endl;
+ //kdDebug(5006) << "KMReaderWin::update - message" << endl;
updateReaderWin();
return;
}
@@ -1067,8 +1014,6 @@ void KMReaderWin::initHtmlWidget(void)
connect(mViewer->browserExtension(),
TQT_SIGNAL(createNewWindow(const KURL &, const KParts::URLArgs &)),this,
TQT_SLOT(slotUrlOpen(const KURL &)));
- connect(mViewer,TQT_SIGNAL(onURL(const TQString &)),this,
- TQT_SLOT(slotUrlOn(const TQString &)));
connect(mViewer,TQT_SIGNAL(popupMenu(const TQString &, const TQPoint &)),
TQT_SLOT(slotUrlPopup(const TQString &, const TQPoint &)));
connect( kmkernel->imProxy(), TQT_SIGNAL( sigContactPresenceChanged( const TQString & ) ),
@@ -1105,6 +1050,16 @@ void KMReaderWin::setHeaderStyleAndStrategy( const HeaderStyle * style,
const HeaderStrategy * strategy ) {
mHeaderStyle = style ? style : HeaderStyle::fancy();
mHeaderStrategy = strategy ? strategy : HeaderStrategy::rich();
+ if ( mHeaderOnlyAttachmentsAction ) {
+ const bool styleHasAttachmentQuickList = mHeaderStyle == HeaderStyle::fancy() ||
+ mHeaderStyle == HeaderStyle::enterprise();
+ mHeaderOnlyAttachmentsAction->setEnabled( styleHasAttachmentQuickList );
+ if ( !styleHasAttachmentQuickList && mAttachmentStrategy == AttachmentStrategy::headerOnly() ) {
+ // Style changed to something without an attachment quick list, need to change attachment
+ // strategy
+ setAttachmentStrategy( AttachmentStrategy::smart() );
+ }
+ }
update( true );
}
@@ -1150,7 +1105,6 @@ void KMReaderWin::setPrintFont( const TQFont& font )
//-----------------------------------------------------------------------------
const TQTextCodec * KMReaderWin::overrideCodec() const
{
- kdDebug(5006) << k_funcinfo << " mOverrideEncoding == '" << mOverrideEncoding << "'" << endl;
if ( mOverrideEncoding.isEmpty() || mOverrideEncoding == "Auto" ) // Auto
return 0;
else
@@ -1179,15 +1133,25 @@ void KMReaderWin::readGlobalOverrideCodec()
}
//-----------------------------------------------------------------------------
-void KMReaderWin::setMsg(KMMessage* aMsg, bool force)
+void KMReaderWin::setOriginalMsg( unsigned long serNumOfOriginalMessage, int nodeIdOffset )
{
- if (aMsg)
- kdDebug(5006) << "(" << aMsg->getMsgSerNum() << ", last " << mLastSerNum << ") " << aMsg->subject() << " "
- << aMsg->fromStrip() << ", readyToShow " << (aMsg->readyToShow()) << endl;
+ mSerNumOfOriginalMessage = serNumOfOriginalMessage;
+ mNodeIdOffset = nodeIdOffset;
+}
- //Reset the level quote if the msg has changed.
- if (aMsg && aMsg->getMsgSerNum() != mLastSerNum ){
+//-----------------------------------------------------------------------------
+void KMReaderWin::setMsg( KMMessage* aMsg, bool force, bool updateOnly )
+{
+ if ( aMsg ) {
+ kdDebug(5006) << "(" << aMsg->getMsgSerNum() << ", last " << mLastSerNum << ") " << aMsg->subject() << " "
+ << aMsg->fromStrip() << ", readyToShow " << (aMsg->readyToShow()) << endl;
+ }
+
+ // Reset message-transient state
+ if ( aMsg && aMsg->getMsgSerNum() != mLastSerNum && !updateOnly ){
mLevelQuote = GlobalSettings::self()->collapseQuoteLevelSpin()-1;
+ mShowRawToltecMail = !GlobalSettings::self()->showToltecReplacementText();
+ clearBodyPartMementos();
}
if ( mPrinting )
mLevelQuote = -1;
@@ -1234,14 +1198,11 @@ void KMReaderWin::setMsg(KMMessage* aMsg, bool force)
if (aMsg) {
aMsg->setOverrideCodec( overrideCodec() );
aMsg->setDecodeHTML( htmlMail() );
- mLastStatus = aMsg->status();
// FIXME: workaround to disable DND for IMAP load-on-demand
if ( !aMsg->isComplete() )
mViewer->setDNDEnabled( false );
else
mViewer->setDNDEnabled( true );
- } else {
- mLastStatus = KMMsgStatusUnknown;
}
// only display the msg if it is complete
@@ -1522,17 +1483,16 @@ void KMReaderWin::displayMessage() {
TQTimer::singleShot( 1, this, TQT_SLOT(injectAttachments()) );
}
+static bool message_was_saved_decrypted_before( const KMMessage * msg ) {
+ if ( !msg )
+ return false;
+ //kdDebug(5006) << "msgId = " << msg->msgId() << endl;
+ return msg->msgId().stripWhiteSpace().startsWith( "<DecryptedMsg." );
+}
//-----------------------------------------------------------------------------
void KMReaderWin::parseMsg(KMMessage* aMsg)
{
-#ifndef NDEBUG
- kdDebug( 5006 )
- << "parseMsg(KMMessage* aMsg "
- << ( aMsg == message() ? "==" : "!=" )
- << " aMsg )" << endl;
-#endif
-
KMMessagePart msgPart;
TQCString subtype, contDisp;
TQByteArray str;
@@ -1547,7 +1507,7 @@ void KMReaderWin::parseMsg(KMMessage* aMsg)
return;
} else
delete mRootNode;
- mRootNode = partNode::fromMessage( aMsg );
+ mRootNode = partNode::fromMessage( aMsg, this );
const TQCString mainCntTypeStr = mRootNode->typeString() + '/' + mRootNode->subTypeString();
TQString cntDesc = aMsg->subject();
@@ -1573,24 +1533,38 @@ void KMReaderWin::parseMsg(KMMessage* aMsg)
if( vCardNode ) {
// ### FIXME: We should only do this if the vCard belongs to the sender,
// ### i.e. if the sender's email address is contained in the vCard.
- const TQString vcard = vCardNode->msgPart().bodyToUnicode( overrideCodec() );
KABC::VCardConverter t;
+#if defined(KABC_VCARD_ENCODING_FIX)
+ const TQByteArray vcard = vCardNode->msgPart().bodyDecodedBinary();
+ if ( !t.parseVCardsRaw( vcard.data() ).empty() ) {
+#else
+ const TQString vcard = vCardNode->msgPart().bodyToUnicode( overrideCodec() );
if ( !t.parseVCards( vcard ).empty() ) {
+#endif
hasVCard = true;
- kdDebug(5006) << "FOUND A VALID VCARD" << endl;
writeMessagePartToTempFile( &vCardNode->msgPart(), vCardNode->nodeId() );
}
}
- htmlWriter()->queue( writeMsgHeader(aMsg, hasVCard, true ) );
+
+ if ( !mRootNode || !mRootNode->isToltecMessage() || mShowRawToltecMail ) {
+ htmlWriter()->queue( writeMsgHeader(aMsg, hasVCard ? vCardNode : 0, true ) );
+ }
// show message content
ObjectTreeParser otp( this );
+ otp.setAllowAsync( true );
+ otp.setShowRawToltecMail( mShowRawToltecMail );
otp.parseObjectTree( mRootNode );
// store encrypted/signed status information in the KMMessage
// - this can only be done *after* calling parseObjectTree()
KMMsgEncryptionState encryptionState = mRootNode->overallEncryptionState();
KMMsgSignatureState signatureState = mRootNode->overallSignatureState();
+ // Don't crash when switching message while GPG passphrase entry dialog is shown #53185
+ if (aMsg != message()) {
+ displayMessage();
+ return;
+ }
aMsg->setEncryptionState( encryptionState );
// Don't reset the signature state to "not signed" (e.g. if one canceled the
// decryption of a signed messages which has already been decrypted before).
@@ -1618,22 +1592,23 @@ void KMReaderWin::parseMsg(KMMessage* aMsg)
kdDebug(5006) << "\n\n\nKMReaderWin::parseMsg() - special post-encryption handling:\n1." << endl;
kdDebug(5006) << "(aMsg == msg) = " << (aMsg == message()) << endl;
-kdDebug(5006) << " (KMMsgStatusUnknown == mLastStatus) = " << (KMMsgStatusUnknown == mLastStatus) << endl;
-kdDebug(5006) << "|| (KMMsgStatusNew == mLastStatus) = " << (KMMsgStatusNew == mLastStatus) << endl;
-kdDebug(5006) << "|| (KMMsgStatusUnread == mLastStatus) = " << (KMMsgStatusUnread == mLastStatus) << endl;
-kdDebug(5006) << "(mIdOfLastViewedMessage != aMsg->msgId()) = " << (mIdOfLastViewedMessage != aMsg->msgId()) << endl;
+kdDebug(5006) << "aMsg->parent() && aMsg->parent() != kmkernel->outboxFolder() = " << (aMsg->parent() && aMsg->parent() != kmkernel->outboxFolder()) << endl;
+kdDebug(5006) << "message_was_saved_decrypted_before( aMsg ) = " << message_was_saved_decrypted_before( aMsg ) << endl;
+kdDebug(5006) << "this->decryptMessage() = " << decryptMessage() << endl;
+kdDebug(5006) << "otp.hasPendingAsyncJobs() = " << otp.hasPendingAsyncJobs() << endl;
kdDebug(5006) << " (KMMsgFullyEncrypted == encryptionState) = " << (KMMsgFullyEncrypted == encryptionState) << endl;
kdDebug(5006) << "|| (KMMsgPartiallyEncrypted == encryptionState) = " << (KMMsgPartiallyEncrypted == encryptionState) << endl;
// only proceed if we were called the normal way - not by
// double click on the message (==not running in a separate window)
if( (aMsg == message())
+ // don't remove encryption in the outbox folder :)
+ && ( aMsg->parent() && aMsg->parent() != kmkernel->outboxFolder() )
// only proceed if this message was not saved encryptedly before
- // to make sure only *new* messages are saved in decrypted form
- && ( (KMMsgStatusUnknown == mLastStatus)
- || (KMMsgStatusNew == mLastStatus)
- || (KMMsgStatusUnread == mLastStatus) )
- // avoid endless recursions
- && (mIdOfLastViewedMessage != aMsg->msgId())
+ && !message_was_saved_decrypted_before( aMsg )
+ // only proceed if the message has actually been decrypted
+ && decryptMessage()
+ // only proceed if no pending async jobs are running:
+ && !otp.hasPendingAsyncJobs()
// only proceed if this message is (at least partially) encrypted
&& ( (KMMsgFullyEncrypted == encryptionState)
|| (KMMsgPartiallyEncrypted == encryptionState) ) ) {
@@ -1690,15 +1665,15 @@ kdDebug(5006) << "KMReaderWin - composing unencrypted message" << endl;
//-----------------------------------------------------------------------------
-TQString KMReaderWin::writeMsgHeader(KMMessage* aMsg, bool hasVCard, bool topLevel)
+TQString KMReaderWin::writeMsgHeader( KMMessage* aMsg, partNode *vCardNode, bool topLevel )
{
kdFatal( !headerStyle(), 5006 )
<< "trying to writeMsgHeader() without a header style set!" << endl;
kdFatal( !headerStrategy(), 5006 )
<< "trying to writeMsgHeader() without a header strategy set!" << endl;
TQString href;
- if (hasVCard)
- href = TQString("file:") + KURL::encode_string( mTempFiles.last() );
+ if ( vCardNode )
+ href = vCardNode->asHREF( "body" );
return headerStyle()->format( aMsg, headerStrategy(), href, mPrinting, topLevel );
}
@@ -1763,10 +1738,14 @@ TQString KMReaderWin::createTempDir( const TQString &param )
}
//-----------------------------------------------------------------------------
-void KMReaderWin::showVCard( KMMessagePart * msgPart ) {
+void KMReaderWin::showVCard( KMMessagePart *msgPart )
+{
+#if defined(KABC_VCARD_ENCODING_FIX)
+ const TQByteArray vCard = msgPart->bodyDecodedBinary();
+#else
const TQString vCard = msgPart->bodyToUnicode( overrideCodec() );
-
- VCardViewer *vcv = new VCardViewer(this, vCard, "vCardDialog");
+#endif
+ VCardViewer *vcv = new VCardViewer( this, vCard, "vCardDialog" );
vcv->show();
}
@@ -1782,19 +1761,13 @@ void KMReaderWin::printMsg()
int KMReaderWin::msgPartFromUrl(const KURL &aUrl)
{
if (aUrl.isEmpty()) return -1;
-
- bool ok;
- if ( aUrl.url().startsWith( "#att" ) ) {
- int res = aUrl.url().mid( 4 ).toInt( &ok );
- if ( ok ) return res;
- }
-
if (!aUrl.isLocalFile()) return -1;
TQString path = aUrl.path();
uint right = path.findRev('/');
uint left = path.findRev('.', right);
+ bool ok;
int res = path.mid(left + 1, right - left - 1).toInt(&ok);
return (ok) ? res : -1;
}
@@ -1910,7 +1883,8 @@ bool foundSMIMEData( const TQString aUrl,
void KMReaderWin::slotUrlOn(const TQString &aUrl)
{
const KURL url(aUrl);
- if ( url.protocol() == "kmail" || url.protocol() == "x-kmail"
+
+ if ( url.protocol() == "kmail" || url.protocol() == "x-kmail" || url.protocol() == "attachment"
|| (url.protocol().isEmpty() && url.path().isEmpty()) ) {
mViewer->setDNDEnabled( false );
} else {
@@ -1919,10 +1893,12 @@ void KMReaderWin::slotUrlOn(const TQString &aUrl)
if ( aUrl.stripWhiteSpace().isEmpty() ) {
KPIM::BroadcastStatus::instance()->reset();
+ mHoveredUrl = KURL();
+ mLastClickImagePath = TQString();
return;
}
- mUrlClicked = url;
+ mHoveredUrl = url;
const TQString msg = URLHandlerManager::instance()->statusBarMessage( url, this );
@@ -1934,7 +1910,7 @@ void KMReaderWin::slotUrlOn(const TQString &aUrl)
//-----------------------------------------------------------------------------
void KMReaderWin::slotUrlOpen(const KURL &aUrl, const KParts::URLArgs &)
{
- mUrlClicked = aUrl;
+ mClickedUrl = aUrl;
if ( URLHandlerManager::instance()->handleClick( aUrl, this ) )
return;
@@ -1947,17 +1923,43 @@ void KMReaderWin::slotUrlOpen(const KURL &aUrl, const KParts::URLArgs &)
void KMReaderWin::slotUrlPopup(const TQString &aUrl, const TQPoint& aPos)
{
const KURL url( aUrl );
- mUrlClicked = url;
+ mClickedUrl = url;
+
+ if ( url.protocol() == "mailto" ) {
+ mCopyURLAction->setText( i18n( "Copy Email Address" ) );
+ } else {
+ mCopyURLAction->setText( i18n( "Copy Link Address" ) );
+ }
if ( URLHandlerManager::instance()->handleContextMenuRequest( url, aPos, this ) )
return;
if ( message() ) {
kdWarning( 5006 ) << "KMReaderWin::slotUrlPopup(): Unhandled URL right-click!" << endl;
- emit popupMenu( *message(), url, aPos );
+ emitPopupMenu( url, aPos );
}
}
+// Checks if the given node has a parent node that is a DIV which has an ID attribute
+// with the value specified here
+static bool hasParentDivWithId( const DOM::Node &start, const TQString &id )
+{
+ if ( start.isNull() )
+ return false;
+
+ if ( start.nodeName().string() == "div" ) {
+ for ( unsigned int i = 0; i < start.attributes().length(); i++ ) {
+ if ( start.attributes().item( i ).nodeName().string() == "id" &&
+ start.attributes().item( i ).nodeValue().string() == id )
+ return true;
+ }
+ }
+
+ if ( !start.parentNode().isNull() )
+ return hasParentDivWithId( start.parentNode(), id );
+ else return false;
+}
+
//-----------------------------------------------------------------------------
void KMReaderWin::showAttachmentPopup( int id, const TQString & name, const TQPoint & p )
{
@@ -1969,14 +1971,22 @@ void KMReaderWin::showAttachmentPopup( int id, const TQString & name, const TQPo
menu->insertItem(i18n("to view something", "View"), 3);
menu->insertItem(SmallIcon("filesaveas"),i18n("Save As..."), 4);
menu->insertItem(SmallIcon("editcopy"), i18n("Copy"), 9 );
- if ( GlobalSettings::self()->allowAttachmentEditing() )
+ const bool canChange = message()->parent() ? !message()->parent()->isReadOnly() : false;
+ if ( GlobalSettings::self()->allowAttachmentEditing() && canChange )
menu->insertItem(SmallIcon("edit"), i18n("Edit Attachment"), 8 );
- if ( GlobalSettings::self()->allowAttachmentDeletion() )
+ if ( GlobalSettings::self()->allowAttachmentDeletion() && canChange )
menu->insertItem(SmallIcon("editdelete"), i18n("Delete Attachment"), 7 );
if ( name.endsWith( ".xia", false ) &&
Kleo::CryptoBackendFactory::instance()->protocol( "Chiasmus" ) )
menu->insertItem( i18n( "Decrypt With Chiasmus..." ), 6 );
menu->insertItem(i18n("Properties"), 5);
+
+ const bool attachmentInHeader = hasParentDivWithId( mViewer->nodeUnderMouse(), "attachmentInjectionPoint" );
+ const bool hasScrollbar = mViewer->view()->verticalScrollBar()->isVisible();
+ if ( attachmentInHeader && hasScrollbar ) {
+ menu->insertItem( i18n("Scroll To"), 10 );
+ }
+
connect(menu, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotHandleAttachment(int)));
menu->exec( p ,0 );
delete menu;
@@ -2032,6 +2042,8 @@ void KMReaderWin::slotHandleAttachment( int choice )
urls.append( url );
KURLDrag* drag = new KURLDrag( urls, this );
TQApplication::clipboard()->setData( drag, QClipboard::Clipboard );
+ } else if ( choice == 10 ) { // Scroll To
+ scrollToAttachment( node );
}
}
@@ -2064,7 +2076,7 @@ void KMReaderWin::slotCopySelectedText()
//-----------------------------------------------------------------------------
-void KMReaderWin::atmViewMsg(KMMessagePart* aMsgPart)
+void KMReaderWin::atmViewMsg( KMMessagePart* aMsgPart, int nodeId )
{
assert(aMsgPart!=0);
KMMessage* msg = new KMMessage;
@@ -2076,7 +2088,7 @@ void KMReaderWin::atmViewMsg(KMMessagePart* aMsgPart)
msg->setUID(message()->UID());
msg->setReadyToShow(true);
KMReaderMainWin *win = new KMReaderMainWin();
- win->showMsg( overrideEncoding(), msg );
+ win->showMsg( overrideEncoding(), msg, message()->getMsgSerNum(), nodeId );
win->show();
}
@@ -2168,6 +2180,7 @@ void KMReaderWin::setMsgPart( KMMessagePart* aMsgPart, bool aHTML,
htmlWriter()->end();
setCaption( i18n("View Attachment: %1").arg( pname ) );
show();
+ delete iio;
} else {
htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
htmlWriter()->queue( mCSSHelper->htmlHead( isFixedFont() ) );
@@ -2208,7 +2221,7 @@ void KMReaderWin::slotAtmView( int id, const TQString& name )
if (pname.isEmpty()) pname="unnamed";
// image Attachment is saved already
if (kasciistricmp(msgPart.typeStr(), "message")==0) {
- atmViewMsg(&msgPart);
+ atmViewMsg( &msgPart,id );
} else if ((kasciistricmp(msgPart.typeStr(), "text")==0) &&
(kasciistricmp(msgPart.subtypeStr(), "x-vcard")==0)) {
setMsgPart( &msgPart, htmlMail(), name, pname );
@@ -2239,7 +2252,7 @@ void KMReaderWin::openAttachment( int id, const TQString & name )
KMMessagePart& msgPart = node->msgPart();
if (kasciistricmp(msgPart.typeStr(), "message")==0)
{
- atmViewMsg(&msgPart);
+ atmViewMsg( &msgPart, id );
return;
}
@@ -2431,7 +2444,7 @@ void KMReaderWin::update( bool force )
{
KMMessage* msg = message();
if ( msg )
- setMsg( msg, force );
+ setMsg( msg, force, true /* updateOnly */ );
}
@@ -2467,7 +2480,7 @@ void KMReaderWin::slotUrlClicked()
identity = message()->parent()->identity();
}
- KMCommand *command = new KMUrlClickedCommand( mUrlClicked, identity, this,
+ KMCommand *command = new KMUrlClickedCommand( mClickedUrl, identity, this,
false, mainWidget );
command->start();
}
@@ -2475,14 +2488,14 @@ void KMReaderWin::slotUrlClicked()
//-----------------------------------------------------------------------------
void KMReaderWin::slotMailtoCompose()
{
- KMCommand *command = new KMMailtoComposeCommand( mUrlClicked, message() );
+ KMCommand *command = new KMMailtoComposeCommand( mClickedUrl, message() );
command->start();
}
//-----------------------------------------------------------------------------
void KMReaderWin::slotMailtoForward()
{
- KMCommand *command = new KMMailtoForwardCommand( mMainWindow, mUrlClicked,
+ KMCommand *command = new KMMailtoForwardCommand( mMainWindow, mClickedUrl,
message() );
command->start();
}
@@ -2490,7 +2503,7 @@ void KMReaderWin::slotMailtoForward()
//-----------------------------------------------------------------------------
void KMReaderWin::slotMailtoAddAddrBook()
{
- KMCommand *command = new KMMailtoAddAddrBookCommand( mUrlClicked,
+ KMCommand *command = new KMMailtoAddAddrBookCommand( mClickedUrl,
mMainWindow);
command->start();
}
@@ -2498,7 +2511,7 @@ void KMReaderWin::slotMailtoAddAddrBook()
//-----------------------------------------------------------------------------
void KMReaderWin::slotMailtoOpenAddrBook()
{
- KMCommand *command = new KMMailtoOpenAddrBookCommand( mUrlClicked,
+ KMCommand *command = new KMMailtoOpenAddrBookCommand( mClickedUrl,
mMainWindow );
command->start();
}
@@ -2509,7 +2522,7 @@ void KMReaderWin::slotUrlCopy()
// we don't necessarily need a mainWidget for KMUrlCopyCommand so
// it doesn't matter if the dynamic_cast fails.
KMCommand *command =
- new KMUrlCopyCommand( mUrlClicked,
+ new KMUrlCopyCommand( mClickedUrl,
dynamic_cast<KMMainWidget*>( mMainWindow ) );
command->start();
}
@@ -2518,30 +2531,30 @@ void KMReaderWin::slotUrlCopy()
void KMReaderWin::slotUrlOpen( const KURL &url )
{
if ( !url.isEmpty() )
- mUrlClicked = url;
- KMCommand *command = new KMUrlOpenCommand( mUrlClicked, this );
+ mClickedUrl = url;
+ KMCommand *command = new KMUrlOpenCommand( mClickedUrl, this );
command->start();
}
//-----------------------------------------------------------------------------
void KMReaderWin::slotAddBookmarks()
{
- KMCommand *command = new KMAddBookmarksCommand( mUrlClicked, this );
+ KMCommand *command = new KMAddBookmarksCommand( mClickedUrl, this );
command->start();
}
//-----------------------------------------------------------------------------
void KMReaderWin::slotUrlSave()
{
- KMCommand *command = new KMUrlSaveCommand( mUrlClicked, mMainWindow );
+ KMCommand *command = new KMUrlSaveCommand( mClickedUrl, mMainWindow );
command->start();
}
//-----------------------------------------------------------------------------
void KMReaderWin::slotMailtoReply()
{
- KMCommand *command = new KMMailtoReplyCommand( mMainWindow, mUrlClicked,
- message(), copyText() );
+ KMCommand *command = new KMMailtoReplyCommand( mMainWindow, mClickedUrl,
+ message(), copyText() );
command->start();
}
@@ -2585,6 +2598,14 @@ void KMReaderWin::slotSaveAttachments()
}
//-----------------------------------------------------------------------------
+void KMReaderWin::saveAttachment( const KURL &tempFileName )
+{
+ mAtmCurrent = msgPartFromUrl( tempFileName );
+ mAtmCurrentName = mClickedUrl.path();
+ slotHandleAttachment( KMHandleAttachmentCommand::Save ); // save
+}
+
+//-----------------------------------------------------------------------------
void KMReaderWin::slotSaveMsg()
{
KMSaveMsgCommand *saveCommand = new KMSaveMsgCommand( mMainWindow, message() );
@@ -2597,28 +2618,123 @@ void KMReaderWin::slotSaveMsg()
//-----------------------------------------------------------------------------
void KMReaderWin::slotIMChat()
{
- KMCommand *command = new KMIMChatCommand( mUrlClicked, message() );
+ KMCommand *command = new KMIMChatCommand( mClickedUrl, message() );
command->start();
}
//-----------------------------------------------------------------------------
+static TQString linkForNode( const DOM::Node &node )
+{
+ try {
+ if ( node.isNull() )
+ return TQString();
+
+ const DOM::NamedNodeMap attributes = node.attributes();
+ if ( !attributes.isNull() ) {
+ const DOM::Node href = attributes.getNamedItem( DOM::DOMString( "href" ) );
+ if ( !href.isNull() ) {
+ return href.nodeValue().string();
+ }
+ }
+ if ( !node.parentNode().isNull() ) {
+ return linkForNode( node.parentNode() );
+ } else {
+ return TQString();
+ }
+ } catch ( DOM::DOMException &e ) {
+ kdWarning(5006) << "Got an exception when trying to determine link under cursor!" << endl;
+ return TQString();
+ }
+}
+
+//-----------------------------------------------------------------------------
bool KMReaderWin::eventFilter( TQObject *, TQEvent *e )
{
if ( e->type() == TQEvent::MouseButtonPress ) {
TQMouseEvent* me = static_cast<TQMouseEvent*>(e);
if ( me->button() == LeftButton && ( me->state() & ShiftButton ) ) {
// special processing for shift+click
- mAtmCurrent = msgPartFromUrl( mUrlClicked );
- if ( mAtmCurrent < 0 ) return false; // not an attachment
- mAtmCurrentName = mUrlClicked.path();
- slotHandleAttachment( KMHandleAttachmentCommand::Save ); // save
- return true; // eat event
+ URLHandlerManager::instance()->handleShiftClick( mHoveredUrl, this );
+ return true;
+ }
+
+ if ( me->button() == LeftButton ) {
+
+ TQString imagePath;
+ const DOM::Node nodeUnderMouse = mViewer->nodeUnderMouse();
+ if ( !nodeUnderMouse.isNull() ) {
+ const DOM::NamedNodeMap attributes = nodeUnderMouse.attributes();
+ if ( !attributes.isNull() ) {
+ const DOM::Node src = attributes.getNamedItem( DOM::DOMString( "src" ) );
+ if ( !src.isNull() ) {
+ imagePath = src.nodeValue().string();
+ }
+ }
+ }
+
+ mCanStartDrag = URLHandlerManager::instance()->willHandleDrag( mHoveredUrl, imagePath, this );
+ mLastClickPosition = me->pos();
+ mLastClickImagePath = imagePath;
}
}
+
+ if ( e->type() == TQEvent::MouseButtonRelease ) {
+ mCanStartDrag = false;
+ }
+
+ if ( e->type() == TQEvent::MouseMove ) {
+ TQMouseEvent* me = static_cast<TQMouseEvent*>( e );
+
+ // Handle this ourselves instead of connecting to mViewer::onURL(), since KHTML misses some
+ // notifications in case we started a drag ourselves
+ slotUrlOn( linkForNode( mViewer->nodeUnderMouse() ) );
+
+ if ( ( mLastClickPosition - me->pos() ).manhattanLength() > KGlobalSettings::dndEventDelay() ) {
+ if ( mCanStartDrag && ( !( mHoveredUrl.isEmpty() && mLastClickImagePath.isEmpty() ) ) ) {
+ if ( URLHandlerManager::instance()->handleDrag( mHoveredUrl, mLastClickImagePath, this ) ) {
+ mCanStartDrag = false;
+ slotUrlOn( TQString() );
+
+ // HACK: Send a mouse release event to the KHTMLView, as otherwise that will be missed in
+ // case we started a drag. If the event is missed, the HTML view gets into a wrong
+ // state, in which funny things like unsolicited drags start to happen.
+ TQMouseEvent mouseEvent( TQEvent::MouseButtonRelease, me->pos(), TQt::NoButton, TQt::NoButton );
+ static_cast<TQObject*>( mViewer->view() )->eventFilter( mViewer->view()->viewport(),
+ &mouseEvent );
+ return true;
+ }
+ }
+ }
+ }
+
// standard event processing
return false;
}
+void KMReaderWin::fillCommandInfo( partNode *node, KMMessage **msg, int *nodeId )
+{
+ Q_ASSERT( msg && nodeId );
+
+ if ( mSerNumOfOriginalMessage != 0 ) {
+ KMFolder *folder = 0;
+ int index = -1;
+ KMMsgDict::instance()->getLocation( mSerNumOfOriginalMessage, &folder, &index );
+ if ( folder && index != -1 )
+ *msg = folder->getMsg( index );
+
+ if ( !( *msg ) ) {
+ kdWarning( 5006 ) << "Unable to find the original message, aborting attachment deletion!" << endl;
+ return;
+ }
+
+ *nodeId = node->nodeId() + mNodeIdOffset;
+ }
+ else {
+ *nodeId = node->nodeId();
+ *msg = message();
+ }
+}
+
void KMReaderWin::slotDeleteAttachment(partNode * node)
{
if ( KMessageBox::warningContinueCancel( this,
@@ -2627,8 +2743,52 @@ void KMReaderWin::slotDeleteAttachment(partNode * node)
!= KMessageBox::Continue ) {
return;
}
- KMDeleteAttachmentCommand* command = new KMDeleteAttachmentCommand( node, message(), this );
- command->start();
+
+ int nodeId = -1;
+ KMMessage *msg = 0;
+ fillCommandInfo( node, &msg, &nodeId );
+ if ( msg && nodeId != -1 ) {
+ KMDeleteAttachmentCommand* command = new KMDeleteAttachmentCommand( nodeId, msg, this );
+ command->start();
+ connect( command, TQT_SIGNAL( completed( KMCommand * ) ),
+ this, TQT_SLOT( updateReaderWin() ) );
+ connect( command, TQT_SIGNAL( completed( KMCommand * ) ),
+ this, TQT_SLOT( disconnectMsgAdded() ) );
+
+ // ### HACK: Since the command will do delete + add, a new message will arrive. However, we don't
+ // want the selection to change. Therefore, as soon as a new message arrives, select it, and then
+ // disconnect.
+ // Of course the are races, another message can arrive before ours, but we take the risk.
+ // And it won't work properly with multiple main windows
+ const KMHeaders * const headers = KMKernel::self()->getKMMainWidget()->headers();
+ connect( headers, TQT_SIGNAL( msgAddedToListView( TQListViewItem* ) ),
+ this, TQT_SLOT( msgAdded( TQListViewItem* ) ) );
+ }
+
+ // If we are operating on a copy of parts of the message, make sure to update the copy as well.
+ if ( mSerNumOfOriginalMessage != 0 && message() ) {
+ message()->deleteBodyPart( node->nodeId() );
+ update( true );
+ }
+}
+
+void KMReaderWin::msgAdded( TQListViewItem *item )
+{
+ // A new message was added to the message list view. Select it.
+ // This is only connected right after we started a attachment delete command, so we expect a new
+ // message. Disconnect right afterwards, we only want this particular message to be selected.
+ disconnectMsgAdded();
+ KMHeaders * const headers = KMKernel::self()->getKMMainWidget()->headers();
+ headers->setCurrentItem( item );
+ headers->clearSelection();
+ headers->setSelected( item, true );
+}
+
+void KMReaderWin::disconnectMsgAdded()
+{
+ const KMHeaders *const headers = KMKernel::self()->getKMMainWidget()->headers();
+ disconnect( headers, TQT_SIGNAL( msgAddedToListView( TQListViewItem* ) ),
+ this, TQT_SLOT( msgAdded( TQListViewItem* ) ) );
}
void KMReaderWin::slotEditAttachment(partNode * node)
@@ -2639,8 +2799,16 @@ void KMReaderWin::slotEditAttachment(partNode * node)
!= KMessageBox::Continue ) {
return;
}
- KMEditAttachmentCommand* command = new KMEditAttachmentCommand( node, message(), this );
- command->start();
+
+ int nodeId = -1;
+ KMMessage *msg = 0;
+ fillCommandInfo( node, &msg, &nodeId );
+ if ( msg && nodeId != -1 ) {
+ KMEditAttachmentCommand* command = new KMEditAttachmentCommand( nodeId, msg, this );
+ command->start();
+ }
+
+ // FIXME: If we are operating on a copy of parts of the message, make sure to update the copy as well.
}
KMail::CSSHelper* KMReaderWin::cssHelper()
@@ -2655,6 +2823,42 @@ bool KMReaderWin::decryptMessage() const
return true;
}
+void KMReaderWin::scrollToAttachment( const partNode *node )
+{
+ DOM::Document doc = mViewer->htmlDocument();
+
+ // The anchors for this are created in ObjectTreeParser::parseObjectTree()
+ mViewer->gotoAnchor( TQString::fromLatin1( "att%1" ).arg( node->nodeId() ) );
+
+ // Remove any old color markings which might be there
+ const partNode *root = node->topLevelParent();
+ for ( int i = 0; i <= root->totalChildCount() + 1; i++ ) {
+ DOM::Element attachmentDiv = doc.getElementById( TQString( "attachmentDiv%1" ).arg( i + 1 ) );
+ if ( !attachmentDiv.isNull() )
+ attachmentDiv.removeAttribute( "style" );
+ }
+
+ // Don't mark hidden nodes, that would just produce a strange yellow line
+ if ( node->isDisplayedHidden() )
+ return;
+
+ // Now, color the div of the attachment in yellow, so that the user sees what happened.
+ // We created a special marked div for this in writeAttachmentMarkHeader() in ObjectTreeParser,
+ // find and modify that now.
+ DOM::Element attachmentDiv = doc.getElementById( TQString( "attachmentDiv%1" ).arg( node->nodeId() ) );
+ if ( attachmentDiv.isNull() ) {
+ kdWarning( 5006 ) << "Could not find attachment div for attachment " << node->nodeId() << endl;
+ return;
+ }
+
+ attachmentDiv.setAttribute( "style", TQString( "border:2px solid %1" )
+ .arg( cssHelper()->pgpWarnColor().name() ) );
+
+ // Update rendering, otherwise the rendering is not updated when the user clicks on an attachment
+ // that causes scrolling and the open attachment dialog
+ doc.updateRendering();
+}
+
void KMReaderWin::injectAttachments()
{
// inject attachments in header view
@@ -2668,30 +2872,33 @@ void KMReaderWin::injectAttachments()
TQString visibility;
TQString urlHandle;
TQString imgSrc;
- if( !showAttachmentQuicklist() )
- {
- urlHandle.append( "kmail:showAttachmentQuicklist" );
- imgSrc.append( "attachmentQuicklistClosed.png" );
- } else {
- urlHandle.append( "kmail:hideAttachmentQuicklist" );
- imgSrc.append( "attachmentQuicklistOpened.png" );
- }
+ if( !showAttachmentQuicklist() ) {
+ urlHandle.append( "kmail:showAttachmentQuicklist" );
+ imgSrc.append( "attachmentQuicklistClosed.png" );
+ } else {
+ urlHandle.append( "kmail:hideAttachmentQuicklist" );
+ imgSrc.append( "attachmentQuicklistOpened.png" );
+ }
TQString html = renderAttachments( mRootNode, TQApplication::palette().active().background() );
if ( html.isEmpty() )
return;
- if ( headerStyle() == HeaderStyle::fancy() )
- html.prepend( TQString::fromLatin1("<div style=\"float:left;\">%1&nbsp;</div>" ).arg(i18n("Attachments:")) );
-
- if ( headerStyle() == HeaderStyle::enterprise() ) {
- TQString link("");
- link += "<div style=\"text-align: right;\"><a href=\""+urlHandle+"\"><img src=\""+imgpath+imgSrc+"\"/></a></div>";
- html.prepend( link );
- }
+ TQString link("");
+ if ( headerStyle() == HeaderStyle::fancy() ) {
+ link += "<div style=\"text-align: left;\"><a href=\"" + urlHandle + "\"><img src=\"" +
+ imgpath + imgSrc + "\"/></a></div>";
+ html.prepend( link );
+ html.prepend( TQString::fromLatin1( "<div style=\"float:left;\">%1&nbsp;</div>" ).
+ arg( i18n( "Attachments:" ) ) );
+ } else {
+ link += "<div style=\"text-align: right;\"><a href=\"" + urlHandle + "\"><img src=\"" +
+ imgpath + imgSrc + "\"/></a></div>";
+ html.prepend( link );
+ }
- assert( injectionPoint.tagName() == "div" );
- static_cast<DOM::HTMLElement>( injectionPoint ).setInnerHTML( html );
+ assert( injectionPoint.tagName() == "div" );
+ static_cast<DOM::HTMLElement>( injectionPoint ).setInnerHTML( html );
}
static TQColor nextColor( const TQColor & c )
@@ -2712,48 +2919,45 @@ TQString KMReaderWin::renderAttachments(partNode * node, const TQColor &bgColor
if ( !subHtml.isEmpty() ) {
TQString visibility;
- if( !showAttachmentQuicklist() )
- {
- visibility.append( "display:none;" );
- }
+ if ( !showAttachmentQuicklist() ) {
+ visibility.append( "display:none;" );
+ }
TQString margin;
if ( node != mRootNode || headerStyle() != HeaderStyle::enterprise() )
margin = "padding:2px; margin:2px; ";
- if ( node->msgPart().typeStr() == "message" || node == mRootNode )
+ TQString align = "left";
+ if ( headerStyle() == HeaderStyle::enterprise() )
+ align = "right";
+ if ( node->msgPart().typeStr().lower() == "message" || node == mRootNode )
html += TQString::fromLatin1("<div style=\"background:%1; %2"
- "vertical-align:middle; float:left; %3\">").arg( bgColor.name() ).arg( margin ).arg( visibility );
+ "vertical-align:middle; float:%3; %4\">").arg( bgColor.name() ).arg( margin )
+ .arg( align ).arg( visibility );
html += subHtml;
- if ( node->msgPart().typeStr() == "message" || node == mRootNode )
+ if ( node->msgPart().typeStr().lower() == "message" || node == mRootNode )
html += "</div>";
}
} else {
- TQString label, icon;
- icon = node->msgPart().iconName( KIcon::Small );
- label = node->msgPart().contentDescription();
- if( label.isEmpty() )
- label = node->msgPart().name().stripWhiteSpace();
- if( label.isEmpty() )
- label = node->msgPart().fileName();
- bool typeBlacklisted = node->msgPart().typeStr() == "multipart";
- if ( !typeBlacklisted && node->msgPart().typeStr() == "application" ) {
- typeBlacklisted = node->msgPart().subtypeStr() == "pgp-encrypted"
- || node->msgPart().subtypeStr() == "pgp-signature"
- || node->msgPart().subtypeStr() == "pkcs7-mime"
- || node->msgPart().subtypeStr() == "pkcs7-signature";
- }
- typeBlacklisted = typeBlacklisted || node == mRootNode;
- if ( !label.isEmpty() && !icon.isEmpty() && !typeBlacklisted ) {
+ partNode::AttachmentDisplayInfo info = node->attachmentDisplayInfo();
+ if ( info.displayInHeader ) {
html += "<div style=\"float:left;\">";
html += TQString::fromLatin1( "<span style=\"white-space:nowrap; border-width: 0px; border-left-width: 5px; border-color: %1; 2px; border-left-style: solid;\">" ).arg( bgColor.name() );
- html += TQString::fromLatin1( "<a href=\"#att%1\">" ).arg( node->nodeId() );
- html += "<img style=\"vertical-align:middle;\" src=\"" + icon + "\"/>&nbsp;";
+ TQString fileName = writeMessagePartToTempFile( &node->msgPart(), node->nodeId() );
+ TQString href = node->asHREF( "header" );
+ html += TQString::fromLatin1( "<a href=\"" ) + href +
+ TQString::fromLatin1( "\">" );
+ html += "<img style=\"vertical-align:middle;\" src=\"" + info.icon + "\"/>&nbsp;";
if ( headerStyle() == HeaderStyle::enterprise() ) {
TQFont bodyFont = mCSSHelper->bodyFont( isFixedFont() );
TQFontMetrics fm( bodyFont );
- html += KStringHandler::rPixelSqueeze( label, fm, 140 );
- } else
- html += label;
+ html += KStringHandler::rPixelSqueeze( info.label, fm, 140 );
+ } else if ( headerStyle() == HeaderStyle::fancy() ) {
+ TQFont bodyFont = mCSSHelper->bodyFont( isFixedFont() );
+ TQFontMetrics fm( bodyFont );
+ html += KStringHandler::rPixelSqueeze( info.label, fm, 640 );
+ } else {
+ html += info.label;
+ }
html += "</a></span></div> ";
}
}
@@ -2762,6 +2966,67 @@ TQString KMReaderWin::renderAttachments(partNode * node, const TQColor &bgColor
return html;
}
+using namespace KMail::Interface;
+
+void KMReaderWin::setBodyPartMemento( const partNode * node, const TQCString & which, BodyPartMemento * memento )
+{
+ const TQCString index = node->path() + ':' + which.lower();
+
+ const std::map<TQCString,BodyPartMemento*>::iterator it = mBodyPartMementoMap.lower_bound( index );
+ if ( it != mBodyPartMementoMap.end() && it->first == index ) {
+
+ if ( memento && memento == it->second )
+ return;
+
+ delete it->second;
+
+ if ( memento ) {
+ it->second = memento;
+ }
+ else {
+ mBodyPartMementoMap.erase( it );
+ }
+
+ } else {
+ if ( memento ) {
+ mBodyPartMementoMap.insert( it, std::make_pair( index, memento ) );
+ }
+ }
+
+ if ( Observable * o = memento ? memento->asObservable() : 0 )
+ o->attach( this );
+}
+
+BodyPartMemento * KMReaderWin::bodyPartMemento( const partNode * node, const TQCString & which ) const
+{
+ const TQCString index = node->path() + ':' + which.lower();
+ const std::map<TQCString,BodyPartMemento*>::const_iterator it = mBodyPartMementoMap.find( index );
+ if ( it == mBodyPartMementoMap.end() ) {
+ return 0;
+ }
+ else {
+ return it->second;
+ }
+}
+
+static void detach_and_delete( BodyPartMemento * memento, KMReaderWin * obs ) {
+ if ( Observable * const o = memento ? memento->asObservable() : 0 )
+ o->detach( obs );
+ delete memento;
+}
+
+void KMReaderWin::clearBodyPartMementos()
+{
+ for ( std::map<TQCString,BodyPartMemento*>::const_iterator it = mBodyPartMementoMap.begin(), end = mBodyPartMementoMap.end() ; it != end ; ++it )
+ // Detach the memento from the reader. When cancelling it, it might trigger an update of the
+ // reader, which we are not interested in, and which is dangerous, since half the mementos are
+ // already deleted.
+ // https://issues.kolab.org/issue4187
+ detach_and_delete( it->second, this );
+
+ mBodyPartMementoMap.clear();
+}
+
#include "kmreaderwin.moc"
diff --git a/kmail/kmreaderwin.h b/kmail/kmreaderwin.h
index da7029366..32c7abdf6 100644
--- a/kmail/kmreaderwin.h
+++ b/kmail/kmreaderwin.h
@@ -14,6 +14,8 @@
#include "kmmimeparttree.h" // Needed for friend declaration.
#include "interfaces/observer.h"
+#include <map>
+
class TQFrame;
class TQSplitter;
class TQHBox;
@@ -42,6 +44,7 @@ class KMMessagePart;
namespace KMail {
namespace Interface {
class Observable;
+ class BodyPartMemento;
}
class PartMetaData;
class ObjectTreeParser;
@@ -139,7 +142,20 @@ public:
/** Set the message that shall be shown. If msg is 0, an empty page is
displayed. */
- virtual void setMsg(KMMessage* msg, bool force = false);
+ virtual void setMsg( KMMessage* msg, bool force = false, bool updateOnly = false );
+
+ /**
+ * This should be called when setting a message that was constructed from another message, which
+ * is the case when viewing encapsulated messages in the seperate reader window.
+ * We need to know the serial number of the original message, and at which part index the encapsulated
+ * message was at that original message, so that deleting and editing attachments can work on the
+ * original message.
+ *
+ * This is a HACK. There really shouldn't be a copy of the original mail.
+ *
+ * @see slotDeleteAttachment, slotEditAttachment, fillCommandInfo
+ */
+ void setOriginalMsg( unsigned long serNumOfOriginalMessage, int nodeIdOffset );
/** Instead of settings a message to be shown sets a message part
to be shown */
@@ -210,8 +226,12 @@ public:
/** Enable the displaying of messages again after an URL was displayed */
void enableMsgDisplay();
- /** View message part of type message/RFC822 in extra viewer window. */
- void atmViewMsg(KMMessagePart* msgPart);
+ /**
+ * View message part of type message/RFC822 in extra viewer window.
+ * @param msgPart the part to display
+ * @param nodeId the part index of the message part that is displayed
+ */
+ void atmViewMsg( KMMessagePart* msgPart, int nodeId );
bool atBottom() const;
@@ -266,6 +286,7 @@ public:
KMMessage* message(KMFolder** folder=0) const;
void openAttachment( int id, const TQString & name );
+ void saveAttachment( const KURL &tempFileName );
void emitUrlClicked( const KURL & url, int button ) {
emit urlClicked( url, button );
@@ -302,6 +323,27 @@ public:
/* show or hide the list that points to the attachments */
void setShowAttachmentQuicklist( bool showAttachmentQuicklist = true ) { mShowAttachmentQuicklist = showAttachmentQuicklist; }
+ // This controls whether a Toltec invitation is shown in its raw form or as a replacement text.
+ // This can be toggled with the "kmail:showRawToltecMail" link.
+ bool showRawToltecMail() const { return mShowRawToltecMail; }
+ void setShowRawToltecMail( bool showRawToltecMail ) { mShowRawToltecMail = showRawToltecMail; }
+
+ /* retrieve BodyPartMemento of id \a which for partNode \a node */
+ KMail::Interface::BodyPartMemento * bodyPartMemento( const partNode * node, const TQCString & which ) const;
+
+ /* set/replace BodyPartMemento \a memento of id \a which for
+ partNode \a node. If there was a BodyPartMemento registered
+ already, replaces (deletes) that one. */
+ void setBodyPartMemento( const partNode * node, const TQCString & which, KMail::Interface::BodyPartMemento * memento );
+
+ /// Scrolls to the given attachment and marks it with a yellow border
+ void scrollToAttachment( const partNode *node );
+
+private:
+ /* deletes all BodyPartMementos. Use this when skipping to another
+ message (as opposed to re-loading the same one again). */
+ void clearBodyPartMementos();
+
signals:
/** Emitted after parsing of a message to have it stored
in unencrypted state in it's folder. */
@@ -383,6 +425,15 @@ public slots:
void slotLevelQuote( int l );
void slotTouchMessage();
+ /**
+ * Find the node ID and the message of the attachment that should be edited or deleted.
+ * This is used when setOriginalMsg() was called before, in that case we want to operate
+ * on the original message instead of our copy.
+ *
+ * @see setOriginalMsg
+ */
+ void fillCommandInfo( partNode *node, KMMessage **msg, int *nodeId );
+
void slotDeleteAttachment( partNode* node );
void slotEditAttachment( partNode* node );
@@ -402,12 +453,19 @@ protected slots:
void slotSmartAttachments();
void slotInlineAttachments();
void slotHideAttachments();
+ void slotHeaderOnlyAttachments();
/** Some attachment operations. */
void slotAtmView( int id, const TQString& name );
void slotDelayedResize();
void slotHandleAttachment( int );
+ /** Helper functions used to change message selection in the message list after deleting
+ * an attachment, see slotDeleteAttachment()
+ */
+ void disconnectMsgAdded();
+ void msgAdded( TQListViewItem *item );
+
protected:
/** reimplemented in order to update the frame width in case of a changed
GUI style */
@@ -432,7 +490,7 @@ protected:
/** Creates a nice mail header depending on the current selected
header style. */
- TQString writeMsgHeader(KMMessage* aMsg, bool hasVCard=false, bool topLevel=false);
+ TQString writeMsgHeader(KMMessage* aMsg, partNode *vCardNode = 0, bool topLevel=false );
/** Writes the given message part to a temporary file and returns the
name of this file or TQString::null if writing failed.
@@ -485,6 +543,11 @@ private:
int mAtmCurrent;
TQString mAtmCurrentName;
KMMessage *mMessage;
+
+ // See setOriginalMsg() for an explaination for those two.
+ unsigned long mSerNumOfOriginalMessage;
+ int mNodeIdOffset;
+
// widgets:
TQSplitter * mSplitter;
TQHBox *mBox;
@@ -507,7 +570,6 @@ private:
bool mMsgDisplay;
bool mNoMDNsWhenEncrypted;
unsigned long mLastSerNum;
- KMMsgStatus mLastStatus;
KMail::CSSHelper * mCSSHelper;
bool mUseFixedFont;
@@ -526,19 +588,29 @@ private:
KAction *mMailToComposeAction, *mMailToReplyAction, *mMailToForwardAction,
*mAddAddrBookAction, *mOpenAddrBookAction, *mCopyAction, *mCopyURLAction,
*mUrlOpenAction, *mUrlSaveAsAction, *mAddBookmarksAction, *mStartIMChatAction, *mSelectAllAction;
+ KToggleAction *mHeaderOnlyAttachmentsAction;
KSelectAction *mSelectEncodingAction;
KToggleAction *mToggleFixFontAction;
- KURL mUrlClicked;
+
+ KURL mHoveredUrl;
+ KURL mClickedUrl;
+ TQPoint mLastClickPosition;
+ TQString mLastClickImagePath;
+ bool mCanStartDrag;
+
KMail::HtmlWriter * mHtmlWriter;
+ std::map<TQCString,KMail::Interface::BodyPartMemento*> mBodyPartMementoMap;
// an attachment should be updated
bool mAtmUpdate;
int mChoice;
unsigned long mWaitingForSerNum;
float mSavedRelativePosition;
- int mLevelQuote;
+ int mLevelQuote;
bool mDecrytMessageOverwrite;
bool mShowSignatureDetails;
bool mShowAttachmentQuicklist;
+ bool mShowRawToltecMail;
+ bool mExternalWindow;
};
diff --git a/kmail/kmsearchpattern.cpp b/kmail/kmsearchpattern.cpp
index bec476ef6..3d97a2b31 100644
--- a/kmail/kmsearchpattern.cpp
+++ b/kmail/kmsearchpattern.cpp
@@ -27,6 +27,8 @@ using KMail::FilterLog;
#include <mimelib/string.h>
#include <mimelib/boyermor.h>
+#include <mimelib/field.h>
+#include <mimelib/headers.h>
#include <assert.h>
@@ -58,7 +60,8 @@ static struct _statusNames statusNames[] = {
{ "To Do", KMMsgStatusTodo },
{ "Spam", KMMsgStatusSpam },
{ "Ham", KMMsgStatusHam },
- { "Has Attachment", KMMsgStatusHasAttach }
+ { "Has Attachment", KMMsgStatusHasAttach },
+ { "Invitation", KMMsgStatusHasInvitation }
};
static const int numStatusNames = sizeof statusNames / sizeof ( struct _statusNames );
@@ -280,7 +283,7 @@ bool KMSearchRuleString::matches( const DwString & aStr, KMMessage & msg,
start += headerLen;
size_t stop = aStr.find( '\n', start );
char ch = '\0';
- while ( stop != DwString::npos && ( ch = aStr.at( stop + 1 ) ) == ' ' || ch == '\t' )
+ while ( stop != DwString::npos && ( ( ch = aStr.at( stop + 1 ) ) == ' ' || ch == '\t' ) )
stop = aStr.find( '\n', stop + 1 );
const int len = stop == DwString::npos ? aStr.length() - start : stop - start ;
const TQCString codedValue( aStr.data() + start, len + 1 );
@@ -333,7 +336,19 @@ bool KMSearchRuleString::matches( const KMMessage * msg ) const
bool logContents = true;
if( field() == "<message>" ) {
- msgContents = msg->asString();
+
+ // When searching in the complete message, we can't simply use msg->asString() here,
+ // as that wouldn't decode the body. Therefore we use the decoded body and all decoded
+ // header fields and add all to the one big search string.
+ msgContents += msg->bodyToUnicode();
+ const DwHeaders& headers = msg->headers();
+ const DwField * dwField = headers.FirstField();
+ while( dwField != 0 ) {
+ const char * const fieldName = dwField->FieldNameStr().c_str();
+ const TQString fieldValue = msg->headerFields( fieldName ).join( " " );
+ msgContents += " " + fieldValue;
+ dwField = dwField->Next();
+ }
logContents = false;
} else if ( field() == "<body>" ) {
msgContents = msg->bodyToUnicode();
diff --git a/kmail/kmsearchpattern.h b/kmail/kmsearchpattern.h
index 00a26c7b4..45ffe6808 100644
--- a/kmail/kmsearchpattern.h
+++ b/kmail/kmsearchpattern.h
@@ -230,7 +230,8 @@ namespace KMail {
{ I18N_NOOP( "Spam" ), "kmmsgspam" },
{ I18N_NOOP( "Ham" ), "kmmsgham" },
{ I18N_NOOP( "To Do" ), "kmmsgtodo" },
- { I18N_NOOP( "Has Attachment"), "kmmsgattachment" }
+ { I18N_NOOP( "Invitation" ), "kmmsginvitation" },
+ { I18N_NOOP( "Has Attachment"), "kmmsgattachment" } //must be last
};
// If you change the ordering here; also do it in the array above
enum StatusValueTypes {
@@ -249,7 +250,8 @@ namespace KMail {
StatusSpam = 12,
StatusHam = 13,
StatusToDo = 14,
- StatusHasAttachment = 15
+ StatusInvitation = 15,
+ StatusHasAttachment = 16 //must be last
};
static const int StatusValueCount =
@@ -291,7 +293,7 @@ public:
KConfig group and there is a constructor, mainly used by KMFilter
to initialize from a preset KConfig-Group.
- From a class hierarchy point of view, it is a TQPtrList of
+ From a class hierarchy point of view, it is a TQPtrList of
KMSearchRule's that adds the boolean operators (see Operator)
'and' and 'or' that connect the rules logically, and has a name
under which it could be stored in the config file.
diff --git a/kmail/kmsearchpatternedit.cpp b/kmail/kmsearchpatternedit.cpp
index a928e57f3..399bc0e15 100644
--- a/kmail/kmsearchpatternedit.cpp
+++ b/kmail/kmsearchpatternedit.cpp
@@ -37,7 +37,13 @@ static const struct {
{ "<recipients>", I18N_NOOP( "All Recipients" ) },
{ "<size>", I18N_NOOP( "Size in Bytes" ) },
{ "<age in days>", I18N_NOOP( "Age in Days" ) },
- { "<status>", I18N_NOOP( "Message Status" ) }
+ { "<status>", I18N_NOOP( "Message Status" ) },
+ { "Subject", I18N_NOOP( "Subject" ) },
+ { "From", I18N_NOOP( "From" ) },
+ { "To", I18N_NOOP( "To" ) },
+ { "CC", I18N_NOOP( "CC" ) },
+ { "Reply-To", I18N_NOOP( "Reply To" ) },
+ { "Organization", I18N_NOOP( "Organization" ) }
};
static const int SpecialRuleFieldsCount =
sizeof( SpecialRuleFields ) / sizeof( *SpecialRuleFields );
@@ -247,16 +253,16 @@ void KMSearchRuleWidget::initFieldList( bool headersOnly, bool absoluteDates )
mFilterFieldList.append( i18n( SpecialRuleFields[Size].displayName ) );
if ( !absoluteDates )
mFilterFieldList.append( i18n( SpecialRuleFields[AgeInDays].displayName ) );
- mFilterFieldList.append( i18n( SpecialRuleFields[Status].displayName ) );
+ mFilterFieldList.append( i18n( SpecialRuleFields[Subject].displayName ) );
+ mFilterFieldList.append( i18n( SpecialRuleFields[From].displayName ) );
+ mFilterFieldList.append( i18n( SpecialRuleFields[To].displayName ) );
+ mFilterFieldList.append( i18n( SpecialRuleFields[CC].displayName ) );
+ mFilterFieldList.append( i18n( SpecialRuleFields[ReplyTo].displayName ) );
+ mFilterFieldList.append( i18n( SpecialRuleFields[Organization].displayName ) );
+
// these others only represent message headers and you can add to
// them as you like
- mFilterFieldList.append("Subject");
- mFilterFieldList.append("From");
- mFilterFieldList.append("To");
- mFilterFieldList.append("CC");
- mFilterFieldList.append("Reply-To");
mFilterFieldList.append("List-Id");
- mFilterFieldList.append("Organization");
mFilterFieldList.append("Resent-From");
mFilterFieldList.append("X-Loop");
mFilterFieldList.append("X-Mailing-List");
diff --git a/kmail/kmsearchpatternedit.h b/kmail/kmsearchpatternedit.h
index a6ffd641f..3fee81e1b 100644
--- a/kmail/kmsearchpatternedit.h
+++ b/kmail/kmsearchpatternedit.h
@@ -45,7 +45,8 @@ public:
be used to initialize the widget. */
KMSearchRuleWidget( TQWidget* parent=0, KMSearchRule* aRule=0, const char* name=0, bool headersOnly = false, bool absoluteDates = false );
- enum { Message, Body, AnyHeader, Recipients, Size, AgeInDays, Status };
+ enum { Message, Body, AnyHeader, Recipients, Size, AgeInDays, Status,
+ Subject, From, To, CC, ReplyTo, Organization };
/** Set whether only header fields can be searched. If @p is true only
header fields can be searched otherwise \<message\> and \<body\> searches
diff --git a/kmail/kmsender.cpp b/kmail/kmsender.cpp
index a79da268f..7f7730daf 100644
--- a/kmail/kmsender.cpp
+++ b/kmail/kmsender.cpp
@@ -317,6 +317,7 @@ void KMSender::doSendMsg()
mCurrentMsg->setStatus(KMMsgStatusSent);
mCurrentMsg->setStatus(KMMsgStatusRead); // otherwise it defaults to new on imap
mCurrentMsg->updateAttachmentState();
+ mCurrentMsg->updateInvitationState();
const KPIM::Identity & id = kmkernel->identityManager()
->identityForUoidOrDefault( mCurrentMsg->headerField( "X-KMail-Identity" ).stripWhiteSpace().toUInt() );
@@ -421,10 +422,10 @@ void KMSender::doSendMsg()
// empty
const KPIM::Identity & id = kmkernel->identityManager()
->identityForUoidOrDefault( mCurrentMsg->headerField( "X-KMail-Identity" ).stripWhiteSpace().toUInt() );
- if ( !id.emailAddr().isEmpty() ) {
+ if ( !id.primaryEmailAddress().isEmpty() ) {
mCurrentMsg->setFrom( id.fullEmailAddr() );
}
- else if ( !kmkernel->identityManager()->defaultIdentity().emailAddr().isEmpty() ) {
+ else if ( !kmkernel->identityManager()->defaultIdentity().primaryEmailAddress().isEmpty() ) {
mCurrentMsg->setFrom( kmkernel->identityManager()->defaultIdentity().fullEmailAddr() );
}
else {
diff --git a/kmail/kmsystemtray.cpp b/kmail/kmsystemtray.cpp
index e4d3a9879..8dc4eee94 100644
--- a/kmail/kmsystemtray.cpp
+++ b/kmail/kmsystemtray.cpp
@@ -110,7 +110,6 @@ void KMSystemTray::buildPopupMenu()
{
// Delete any previously created popup menu
delete mPopupMenu;
- mPopupMenu = 0;
mPopupMenu = new KPopupMenu();
KMMainWidget * mainWidget = kmkernel->getKMMainWidget();
@@ -293,6 +292,9 @@ void KMSystemTray::foldersChanged()
/** Check all new folders to see if we started with any new messages */
updateNewMessageNotification(currentFolder);
}
+ else {
+ disconnect(currentFolder, TQT_SIGNAL(numUnreadMsgsChanged(KMFolder *)), this, TQT_SLOT(updateNewMessageNotification(KMFolder *)) );
+ }
}
}
@@ -588,4 +590,9 @@ void KMSystemTray::selectedAccount(int id)
ft->selectCurrentFolder();
}
+bool KMSystemTray::hasUnreadMail() const
+{
+ return ( mCount != 0 );
+}
+
#include "kmsystemtray.moc"
diff --git a/kmail/kmsystemtray.h b/kmail/kmsystemtray.h
index ab80f362a..62707464c 100644
--- a/kmail/kmsystemtray.h
+++ b/kmail/kmsystemtray.h
@@ -51,10 +51,13 @@ public:
int mode() const;
void hideKMail();
+ bool hasUnreadMail() const;
+
+public slots:
+ void foldersChanged();
private slots:
void updateNewMessageNotification(KMFolder * folder);
- void foldersChanged();
void selectedAccount(int);
void updateNewMessages();
void tray_quit();
diff --git a/kmail/kmversion.h b/kmail/kmversion.h
index 8a7e68586..98706ae1b 100644
--- a/kmail/kmversion.h
+++ b/kmail/kmversion.h
@@ -3,6 +3,6 @@
#ifndef kmversion_h
#define kmversion_h
-#define KMAIL_VERSION "1.9.10"
+#define KMAIL_VERSION "1.9.10 (enterprise35 0.20100827.1168748)"
#endif /*kmversion_h*/
diff --git a/kmail/managesievescriptsdialog.cpp b/kmail/managesievescriptsdialog.cpp
index a089c94a6..3bec71323 100644
--- a/kmail/managesievescriptsdialog.cpp
+++ b/kmail/managesievescriptsdialog.cpp
@@ -83,10 +83,15 @@ static KURL findUrlForAccount( const KMail::ImapAccountBase * a ) {
u.setPass( a->passwd() );
u.setPort( sieve.port() );
// Translate IMAP LOGIN to PLAIN:
- u.setQuery( "x-mech=" + ( a->auth() == "*" ? "PLAIN" : a->auth() ) );
+ u.addQueryItem( "x-mech", a->auth() == "*" ? "PLAIN" : a->auth() );
+ if ( !a->useSSL() && !a->useTLS() )
+ u.addQueryItem( "x-allow-unencrypted", "true" );
return u;
} else {
- return sieve.alternateURL();
+ KURL u = sieve.alternateURL();
+ if ( u.protocol().lower() == "sieve" && !a->useSSL() && !a->useTLS() && u.queryItem("x-allow-unencrypted").isEmpty() )
+ u.addQueryItem( "x-allow-unencrypted", "true" );
+ return u;
}
}
@@ -159,6 +164,7 @@ void KMail::ManageSieveScriptsDialog::slotContextMenuRequested( TQListViewItem *
// script items:
menu.insertItem( i18n( "Delete Script" ), this, TQT_SLOT(slotDeleteScript()) );
menu.insertItem( i18n( "Edit Script..." ), this, TQT_SLOT(slotEditScript()) );
+ menu.insertItem( i18n( "Deactivate Script" ), this, TQT_SLOT(slotDeactivateScript()) );
} else {
// top-levels:
menu.insertItem( i18n( "New Script..." ), this, TQT_SLOT(slotNewScript()) );
@@ -167,6 +173,20 @@ void KMail::ManageSieveScriptsDialog::slotContextMenuRequested( TQListViewItem *
mContextMenuItem = 0;
}
+
+void KMail::ManageSieveScriptsDialog::slotDeactivateScript() {
+ if ( !mContextMenuItem )
+ return;
+
+ TQCheckListItem * parent = qcli_cast( mContextMenuItem->parent() );
+ if ( !parent )
+ return;
+ if ( mContextMenuItem->isOn()) {
+ mSelectedItems[parent] = mContextMenuItem;
+ changeActiveScript( parent,false );
+ }
+}
+
void KMail::ManageSieveScriptsDialog::slotSelectionChanged( TQListViewItem * i ) {
TQCheckListItem * item = qcli_cast( i );
if ( !item )
@@ -176,11 +196,11 @@ void KMail::ManageSieveScriptsDialog::slotSelectionChanged( TQListViewItem * i )
return;
if ( item->isOn() && mSelectedItems[parent] != item ) {
mSelectedItems[parent] = item;
- changeActiveScript( parent );
+ changeActiveScript( parent,true );
}
}
-void KMail::ManageSieveScriptsDialog::changeActiveScript( TQCheckListItem * item ) {
+void KMail::ManageSieveScriptsDialog::changeActiveScript( TQCheckListItem * item , bool activate) {
if ( !item )
return;
if ( !mUrls.count( item ) )
@@ -194,8 +214,11 @@ void KMail::ManageSieveScriptsDialog::changeActiveScript( TQCheckListItem * item
if ( !selected )
return;
u.setFileName( selected->text( 0 ) );
-
- SieveJob * job = SieveJob::activate( u );
+ SieveJob * job;
+ if ( activate )
+ job = SieveJob::activate( u );
+ else
+ job = SieveJob::desactivate( u );
connect( job, TQT_SIGNAL(result(KMail::SieveJob*,bool,const TQString&,bool)),
this, TQT_SLOT(slotRefresh()) );
}
@@ -235,7 +258,6 @@ void KMail::ManageSieveScriptsDialog::slotDeleteScript() {
KStdGuiItem::del() )
!= KMessageBox::Continue )
return;
-
SieveJob * job = SieveJob::del( u );
connect( job, TQT_SIGNAL(result(KMail::SieveJob*,bool,const TQString&,bool)),
this, TQT_SLOT(slotRefresh()) );
@@ -295,15 +317,22 @@ KMail::SieveEditor::SieveEditor( TQWidget * parent, const char * name )
TQVBoxLayout * vlay = new TQVBoxLayout( plainPage(), 0, spacingHint() );
mTextEdit = new TQTextEdit( plainPage() );
vlay->addWidget( mTextEdit );
+ mTextEdit->setFocus();
mTextEdit->setTextFormat( TQTextEdit::PlainText );
mTextEdit->setWordWrap( TQTextEdit::NoWrap );
mTextEdit->setFont( KGlobalSettings::fixedFont() );
-
+ connect( mTextEdit, TQT_SIGNAL( textChanged () ), TQT_SLOT( slotTextChanged() ) );
resize( 3 * sizeHint() );
}
KMail::SieveEditor::~SieveEditor() {}
+
+void KMail::SieveEditor::slotTextChanged()
+{
+ enableButtonOK( !script().isEmpty() );
+}
+
void KMail::ManageSieveScriptsDialog::slotGetResult( KMail::SieveJob *, bool success, const TQString & script, bool isActive ) {
if ( !success )
return;
@@ -330,6 +359,7 @@ void KMail::ManageSieveScriptsDialog::slotSieveEditorOkClicked() {
void KMail::ManageSieveScriptsDialog::slotSieveEditorCancelClicked() {
mSieveEditor->deleteLater(); mSieveEditor = 0;
mCurrentURL = KURL();
+ slotRefresh();
}
void KMail::ManageSieveScriptsDialog::slotPutResult( KMail::SieveJob *, bool success ) {
diff --git a/kmail/managesievescriptsdialog.h b/kmail/managesievescriptsdialog.h
index 2195e911e..70c4f6978 100644
--- a/kmail/managesievescriptsdialog.h
+++ b/kmail/managesievescriptsdialog.h
@@ -28,6 +28,7 @@ private slots:
void slotSelectionChanged( TQListViewItem * );
void slotNewScript();
void slotEditScript();
+ void slotDeactivateScript();
void slotDeleteScript();
void slotGetResult( KMail::SieveJob *, bool, const TQString &, bool );
void slotPutResult( KMail::SieveJob *, bool );
@@ -36,7 +37,7 @@ private slots:
private:
void killAllJobs();
- void changeActiveScript( TQCheckListItem * );
+ void changeActiveScript( TQCheckListItem *, bool activate = true );
private:
TQListView * mListView;
diff --git a/kmail/managesievescriptsdialog_p.h b/kmail/managesievescriptsdialog_p.h
index 83fde06b0..2ae12ff53 100644
--- a/kmail/managesievescriptsdialog_p.h
+++ b/kmail/managesievescriptsdialog_p.h
@@ -16,7 +16,8 @@ public:
TQString script() const { return mTextEdit->text(); }
void setScript( const TQString & script ) { mTextEdit->setText( script ); }
-
+private slots:
+ void slotTextChanged();
private:
TQTextEdit * mTextEdit;
};
diff --git a/kmail/messageactions.cpp b/kmail/messageactions.cpp
index b900b7b59..cc5431954 100644
--- a/kmail/messageactions.cpp
+++ b/kmail/messageactions.cpp
@@ -138,7 +138,11 @@ void MessageActions::setSelectedVisibleSernums(const TQValueList< Q_UINT32 > & s
void MessageActions::updateActions()
{
- const bool singleMsg = (mCurrentMessage != 0);
+ bool singleMsg = (mCurrentMessage != 0);
+ if ( mCurrentMessage && mCurrentMessage->parent() ) {
+ if ( mCurrentMessage->parent()->isTemplates() )
+ singleMsg = false;
+ }
const bool multiVisible = mVisibleSernums.count() > 0 || mCurrentMessage;
const bool flagsAvailable = GlobalSettings::self()->allowLocalFlags() ||
!((mCurrentMessage && mCurrentMessage->parent()) ? mCurrentMessage->parent()->isReadOnly() : true);
@@ -164,6 +168,18 @@ void MessageActions::updateActions()
mEditAction->setEnabled( singleMsg );
}
+template<typename T> void MessageActions::replyCommand()
+{
+ if ( !mCurrentMessage )
+ return;
+ const TQString text = mMessageView ? mMessageView->copyText() : "";
+ KMCommand *command = new T( mParent, mCurrentMessage, text );
+ connect( command, TQT_SIGNAL( completed( KMCommand * ) ),
+ this, TQT_SIGNAL( replyActionFinished() ) );
+ command->start();
+}
+
+
void MessageActions::slotCreateTodo()
{
if ( !mCurrentMessage )
diff --git a/kmail/messageactions.h b/kmail/messageactions.h
index 39e9f937e..41279c552 100644
--- a/kmail/messageactions.h
+++ b/kmail/messageactions.h
@@ -55,19 +55,20 @@ class MessageActions : public QObject
KAction* editAction() const { return mEditAction; }
+ signals:
+
+ // This signal is emitted when a reply is triggered and the
+ // action has finished.
+ // This is useful for the stand-alone reader, it might want to close the window in
+ // that case.
+ void replyActionFinished();
+
public slots:
void editCurrentMessage();
private:
void updateActions();
- template<typename T> void replyCommand()
- {
- if ( !mCurrentMessage )
- return;
- const TQString text = mMessageView ? mMessageView->copyText() : "";
- KMCommand *command = new T( mParent, mCurrentMessage, text );
- command->start();
- }
+ template<typename T> void replyCommand();
void setMessageStatus( KMMsgStatus status, bool toggle = false );
private slots:
diff --git a/kmail/messagecomposer.cpp b/kmail/messagecomposer.cpp
index 8d9950738..8b3f1c5c4 100644
--- a/kmail/messagecomposer.cpp
+++ b/kmail/messagecomposer.cpp
@@ -86,6 +86,7 @@
#include <gpgmepp/context.h>
#include <algorithm>
+#include <sstream>
#include <memory>
// ## keep default values in sync with configuredialog.cpp, Security::CryptoTab::setup()
@@ -612,11 +613,8 @@ void MessageComposer::chiasmusEncryptAllAttachments() {
part->setTypeStr( "application" );
part->setSubtypeStr( "vnd.de.bund.bsi.chiasmus" );
part->setName( filename + ".xia" );
- // this is taken from kmmsgpartdlg.cpp:
- TQCString encoding = KMMsgBase::autoDetectCharset( part->charset(), KMMessage::preferredCharsets(), filename );
- if ( encoding.isEmpty() )
- encoding = "utf-8";
- const TQCString enc_name = KMMsgBase::encodeRFC2231String( filename + ".xia", encoding );
+ const TQCString enc_name = KMMsgBase::encodeRFC2231StringAutoDetectCharset(
+ filename + ".xia", part->charset() );
const TQCString cDisp = "attachment;\n\tfilename"
+ ( TQString( enc_name ) != filename + ".xia"
? "*=" + enc_name
@@ -2146,8 +2144,14 @@ void MessageComposer::pgpSignedMsg( const TQByteArray& cText, Kleo::CryptoMessag
mSignature = TQByteArray();
const std::vector<GpgME::Key> signingKeys = mKeyResolver->signingKeys( format );
-
- assert( !signingKeys.empty() );
+ if ( signingKeys.empty() ) {
+ KMessageBox::sorry( mComposeWin,
+ i18n("This message could not be signed, "
+ "since no valid signing keys have been found; "
+ "this should actually never happen, "
+ "please report this bug.") );
+ return;
+ }
// TODO: ASync call? Likely, yes :-)
const Kleo::CryptoBackendFactory * cpf = Kleo::CryptoBackendFactory::instance();
@@ -2171,6 +2175,11 @@ void MessageComposer::pgpSignedMsg( const TQByteArray& cText, Kleo::CryptoMessag
TQByteArray signature;
const GpgME::SigningResult res =
job->exec( signingKeys, cText, signingMode( format ), signature );
+ {
+ std::stringstream ss;
+ ss << res;
+ kdDebug(5006) << ss.str().c_str() << endl;
+ }
if ( res.error().isCanceled() ) {
kdDebug() << "signing was canceled by user" << endl;
return;
@@ -2182,6 +2191,7 @@ void MessageComposer::pgpSignedMsg( const TQByteArray& cText, Kleo::CryptoMessag
}
if ( GlobalSettings::showGnuPGAuditLogAfterSuccessfulSignEncrypt() )
+ if ( Kleo::MessageBox::showAuditLogButton( job.get() ) )
Kleo::MessageBox::auditLog( 0, job.get(), i18n("GnuPG Audit Log for Signing Operation") );
mSignature = signature;
@@ -2219,6 +2229,11 @@ Kpgp::Result MessageComposer::pgpEncryptedMsg( TQByteArray & encryptedBody,
const GpgME::EncryptionResult res =
job->exec( encryptionKeys, cText, true /* we do ownertrust ourselves */, encryptedBody );
+ {
+ std::stringstream ss;
+ ss << res;
+ kdDebug(5006) << ss.str().c_str() << endl;
+ }
if ( res.error().isCanceled() ) {
kdDebug() << "encryption was canceled by user" << endl;
return Kpgp::Canceled;
@@ -2230,6 +2245,7 @@ Kpgp::Result MessageComposer::pgpEncryptedMsg( TQByteArray & encryptedBody,
}
if ( GlobalSettings::showGnuPGAuditLogAfterSuccessfulSignEncrypt() )
+ if ( Kleo::MessageBox::showAuditLogButton( job.get() ) )
Kleo::MessageBox::auditLog( 0, job.get(), i18n("GnuPG Audit Log for Encryption Operation") );
return Kpgp::Ok;
@@ -2261,6 +2277,11 @@ Kpgp::Result MessageComposer::pgpSignedAndEncryptedMsg( TQByteArray & encryptedB
const std::pair<GpgME::SigningResult,GpgME::EncryptionResult> res =
job->exec( signingKeys, encryptionKeys, cText, false, encryptedBody );
+ {
+ std::stringstream ss;
+ ss << res.first << '\n' << res.second;
+ kdDebug(5006) << ss.str().c_str() << endl;
+ }
if ( res.first.error().isCanceled() || res.second.error().isCanceled() ) {
kdDebug() << "encrypt/sign was canceled by user" << endl;
return Kpgp::Canceled;
@@ -2275,6 +2296,7 @@ Kpgp::Result MessageComposer::pgpSignedAndEncryptedMsg( TQByteArray & encryptedB
}
if ( GlobalSettings::showGnuPGAuditLogAfterSuccessfulSignEncrypt() )
+ if ( Kleo::MessageBox::showAuditLogButton( job.get() ) )
Kleo::MessageBox::auditLog( 0, job.get(), i18n("GnuPG Audit Log for Encryption Operation") );
return Kpgp::Ok;
diff --git a/kmail/messageproperty.cpp b/kmail/messageproperty.cpp
index 7de13eb35..b1e02161b 100644
--- a/kmail/messageproperty.cpp
+++ b/kmail/messageproperty.cpp
@@ -1,5 +1,5 @@
/* Message Property
-
+
This file is part of KMail, the KDE mail client.
Copyright (c) Don Sanders <sanders@kde.org>
@@ -66,14 +66,13 @@ void MessageProperty::setFiltering( const KMMsgBase *msgBase, bool filter )
KMFolder* MessageProperty::filterFolder( Q_UINT32 serNum )
{
- if (sFolders.contains(serNum))
- return sFolders[serNum].operator->();
- return 0;
+ TQMap<Q_UINT32, TQGuardedPtr<KMFolder> >::const_iterator it = sFolders.find( serNum );
+ return it == sFolders.constEnd() ? 0 : (*it).operator->();
}
void MessageProperty::setFilterFolder( Q_UINT32 serNum, KMFolder* folder )
{
- sFolders.replace(serNum, TQGuardedPtr<KMFolder>(folder) );
+ sFolders.insert(serNum, TQGuardedPtr<KMFolder>(folder) );
}
KMFolder* MessageProperty::filterFolder( const KMMsgBase *msgBase )
@@ -88,15 +87,14 @@ void MessageProperty::setFilterFolder( const KMMsgBase *msgBase, KMFolder* folde
ActionScheduler* MessageProperty::filterHandler( Q_UINT32 serNum )
{
- if ( sHandlers.contains( serNum ))
- return sHandlers[serNum].operator->();
- return 0;
+ TQMap<Q_UINT32, TQGuardedPtr<ActionScheduler> >::const_iterator it = sHandlers.find( serNum );
+ return it == sHandlers.constEnd() ? 0 : (*it).operator->();
}
void MessageProperty::setFilterHandler( Q_UINT32 serNum, ActionScheduler* handler )
{
if (handler)
- sHandlers.replace( serNum, TQGuardedPtr<ActionScheduler>(handler) );
+ sHandlers.insert( serNum, TQGuardedPtr<ActionScheduler>(handler) );
else
sHandlers.remove( serNum );
}
@@ -113,16 +111,16 @@ void MessageProperty::setFilterHandler( const KMMsgBase *msgBase, ActionSchedule
bool MessageProperty::transferInProgress( Q_UINT32 serNum )
{
- if (sTransfers.contains(serNum))
- return sTransfers[serNum];
- return false;
+ TQMap<Q_UINT32, int >::const_iterator it = sTransfers.find( serNum );
+ return it == sTransfers.constEnd() ? false : *it;
}
void MessageProperty::setTransferInProgress( Q_UINT32 serNum, bool transfer, bool force )
{
int transferInProgress = 0;
- if (sTransfers.contains(serNum))
- transferInProgress = sTransfers[serNum];
+ TQMap<Q_UINT32, int >::const_iterator it = sTransfers.find( serNum );
+ if (it != sTransfers.constEnd())
+ transferInProgress = *it;
if ( force && !transfer )
transferInProgress = 0;
else
@@ -130,7 +128,7 @@ void MessageProperty::setTransferInProgress( Q_UINT32 serNum, bool transfer, boo
if ( transferInProgress < 0 )
transferInProgress = 0;
if (transferInProgress)
- sTransfers.replace( serNum, transferInProgress );
+ sTransfers.insert( serNum, transferInProgress );
else
sTransfers.remove( serNum );
}
@@ -147,15 +145,14 @@ void MessageProperty::setTransferInProgress( const KMMsgBase *msgBase, bool tran
Q_UINT32 MessageProperty::serialCache( const KMMsgBase *msgBase )
{
- if (sSerialCache.contains( msgBase ))
- return sSerialCache[msgBase];
- return 0;
+ TQMap<const KMMsgBase*, long >::const_iterator it = sSerialCache.find( msgBase );
+ return it == sSerialCache.constEnd() ? 0 : *it;
}
void MessageProperty::setSerialCache( const KMMsgBase *msgBase, Q_UINT32 serNum )
{
if (serNum)
- sSerialCache.replace( msgBase, serNum );
+ sSerialCache.insert( msgBase, serNum );
else
sSerialCache.remove( msgBase );
}
diff --git a/kmail/messageproperty.h b/kmail/messageproperty.h
index 4809cd7ad..91168e6f3 100644
--- a/kmail/messageproperty.h
+++ b/kmail/messageproperty.h
@@ -91,6 +91,7 @@ public:
static bool transferInProgress( const KMMsgBase* );
static void setTransferInProgress( Q_UINT32, bool, bool = false );
static bool transferInProgress( Q_UINT32 );
+
/** Some properties, namely complete, transferInProgress, and
serialCache must be forgotten when a message class instance is
destructed or assigned a new value */
@@ -99,10 +100,13 @@ public:
private:
// The folder a message is to be moved into once filtering is finished if any
static TQMap<Q_UINT32, TQGuardedPtr<KMFolder> > sFolders;
+
// The action scheduler currently processing a message if any
static TQMap<Q_UINT32, TQGuardedPtr<ActionScheduler> > sHandlers;
+
// The transferInProgres state of a message if any.
static TQMap<Q_UINT32, int > sTransfers;
+
// The cached serial number of a message if any.
static TQMap<const KMMsgBase*, long > sSerialCache;
};
diff --git a/kmail/newfolderdialog.cpp b/kmail/newfolderdialog.cpp
index 78294e5f9..99051222e 100644
--- a/kmail/newfolderdialog.cpp
+++ b/kmail/newfolderdialog.cpp
@@ -40,6 +40,7 @@
#include <kdialogbase.h>
#include <kmessagebox.h>
+#include "folderutil.h"
#include "newfolderdialog.h"
#include "kmfolder.h"
#include "folderstorage.h"
@@ -58,6 +59,9 @@ NewFolderDialog::NewFolderDialog( TQWidget* parent, KMFolder *folder )
: KDialogBase( parent, "new_folder_dialog", false, i18n( "New Folder" ),
KDialogBase::Ok|KDialogBase::Cancel,
KDialogBase::Ok, true ),
+ mFormatComboBox( 0 ),
+ mContentsComboBox( 0 ),
+ mNamespacesComboBox( 0 ),
mFolder( folder )
{
setWFlags( getWFlags() | WDestructiveClose );
@@ -112,7 +116,8 @@ NewFolderDialog::NewFolderDialog( TQWidget* parent, KMFolder *folder )
}
// --- contents -----
- if ( kmkernel->iCalIface().isEnabled() ) {
+ if ( kmkernel->iCalIface().isEnabled() &&
+ mFolder && mFolder->folderType() != KMFolderTypeImap ) {
mContentsHBox = new TQHBoxLayout( 0, 0, 6, "mContentsHBox");
mContentsLabel = new TQLabel( privateLayoutWidget, "mContentsLabel" );
@@ -190,41 +195,12 @@ void NewFolderDialog::slotOk()
return;
}
- // names of local folders must not contain a '/'
- if ( fldName.find( '/' ) != -1 &&
- ( !mFolder ||
- ( mFolder->folderType() != KMFolderTypeImap &&
- mFolder->folderType() != KMFolderTypeCachedImap ) ) ) {
- KMessageBox::error( this, i18n( "Folder names cannot contain the / (slash) character; please choose another folder name." ) );
+ TQString msg;
+ if ( mFolder && !mFolder->isValidName( fldName, msg ) ) {
+ KMessageBox::error( this, msg );
return;
}
- // folder names must not start with a '.'
- if ( fldName.startsWith( "." ) ) {
- KMessageBox::error( this, i18n( "Folder names cannot start with a . (dot) character; please choose another folder name." ) );
- return;
- }
-
- // names of IMAP folders must not contain the folder delimiter
- if ( mFolder &&
- ( mFolder->folderType() == KMFolderTypeImap ||
- mFolder->folderType() == KMFolderTypeCachedImap ) ) {
- TQString delimiter;
- if ( mFolder->folderType() == KMFolderTypeImap ) {
- KMAcctImap* ai = static_cast<KMFolderImap*>( mFolder->storage() )->account();
- if ( ai )
- delimiter = ai->delimiterForFolder( mFolder->storage() );
- } else {
- KMAcctCachedImap* ai = static_cast<KMFolderCachedImap*>( mFolder->storage() )->account();
- if ( ai )
- delimiter = ai->delimiterForFolder( mFolder->storage() );
- }
- if ( !delimiter.isEmpty() && fldName.find( delimiter ) != -1 ) {
- KMessageBox::error( this, i18n( "Your IMAP server does not allow the character '%1'; please choose another folder name." ).arg( delimiter ) );
- return;
- }
- }
-
// default parent is Top Level local folders
KMFolderDir * selectedFolderDir = &(kmkernel->folderMgr()->dir());
// we got a parent, let's use that
@@ -245,55 +221,21 @@ void NewFolderDialog::slotOk()
/* Ok, obvious errors caught, let's try creating it for real. */
const TQString message = i18n( "<qt>Failed to create folder <b>%1</b>."
"</qt> " ).arg(fldName);
- bool success = false;
- KMFolder *newFolder = 0;
- if ( mFolder && mFolder->folderType() == KMFolderTypeImap ) {
- KMFolderImap* selectedStorage = static_cast<KMFolderImap*>( mFolder->storage() );
- KMAcctImap *anAccount = selectedStorage->account();
- // check if a connection is available BEFORE creating the folder
- if (anAccount->makeConnection() == ImapAccountBase::Connected) {
- newFolder = kmkernel->imapFolderMgr()->createFolder( fldName, false, KMFolderTypeImap, selectedFolderDir );
- if ( newFolder ) {
- TQString imapPath, parent;
- if ( mNamespacesComboBox ) {
- // create folder with namespace
- parent = anAccount->addPathToNamespace( mNamespacesComboBox->currentText() );
- imapPath = anAccount->createImapPath( parent, fldName );
- } else {
- imapPath = anAccount->createImapPath( selectedStorage->imapPath(), fldName );
- }
- KMFolderImap* newStorage = static_cast<KMFolderImap*>( newFolder->storage() );
- selectedStorage->createFolder(fldName, parent); // create it on the server
- newStorage->initializeFrom( selectedStorage, imapPath, TQString::null );
- static_cast<KMFolderImap*>(mFolder->storage())->setAccount( selectedStorage->account() );
- success = true;
- }
- }
- } else if ( mFolder && mFolder->folderType() == KMFolderTypeCachedImap ) {
- newFolder = kmkernel->dimapFolderMgr()->createFolder( fldName, false, KMFolderTypeCachedImap, selectedFolderDir );
- if ( newFolder ) {
- KMFolderCachedImap* selectedStorage = static_cast<KMFolderCachedImap*>( mFolder->storage() );
- KMFolderCachedImap* newStorage = static_cast<KMFolderCachedImap*>( newFolder->storage() );
- newStorage->initializeFrom( selectedStorage );
- if ( mNamespacesComboBox ) {
- // create folder with namespace
- TQString path = selectedStorage->account()->createImapPath(
- mNamespacesComboBox->currentText(), fldName );
- newStorage->setImapPathForCreation( path );
- }
- success = true;
- }
- } else {
- // local folder
- if (mFormatComboBox->currentItem() == 1)
- newFolder = kmkernel->folderMgr()->createFolder(fldName, false, KMFolderTypeMaildir, selectedFolderDir );
- else
- newFolder = kmkernel->folderMgr()->createFolder(fldName, false, KMFolderTypeMbox, selectedFolderDir );
- if ( newFolder )
- success = true;
+ TQString namespaceName;
+ if ( mNamespacesComboBox ) {
+ namespaceName = mNamespacesComboBox->currentText();
}
- if ( !success ) {
+
+ KMFolderType folderType = KMFolderTypeUnknown;
+ if ( mFormatComboBox && mFormatComboBox->currentItem() == 1 )
+ folderType = KMFolderTypeMaildir;
+ else if ( mFormatComboBox )
+ folderType = KMFolderTypeMbox;
+
+ KMFolder *newFolder = KMail::FolderUtil::createSubFolder( mFolder, selectedFolderDir, fldName,
+ namespaceName, folderType );
+ if ( !newFolder ) {
KMessageBox::error( this, message );
return;
}
diff --git a/kmail/newfolderdialog.h b/kmail/newfolderdialog.h
index 96f4421eb..4744db3e2 100644
--- a/kmail/newfolderdialog.h
+++ b/kmail/newfolderdialog.h
@@ -69,7 +69,7 @@ class NewFolderDialog : public KDialogBase
TQHBoxLayout* mNamespacesHBox;
protected slots:
void slotOk();
- void slotFolderNameChanged( const TQString & _text);
+ void slotFolderNameChanged( const TQString & _text);
private:
KMFolder* mFolder;
diff --git a/kmail/objecttreeparser.cpp b/kmail/objecttreeparser.cpp
index 4c56a7bd4..d8b98f24d 100644
--- a/kmail/objecttreeparser.cpp
+++ b/kmail/objecttreeparser.cpp
@@ -34,6 +34,7 @@
// my header file
#include "objecttreeparser.h"
+#include "objecttreeparser_p.h"
// other KMail headers
#include "kmkernel.h"
@@ -52,6 +53,7 @@
#include "interfaces/bodypartformatter.h"
#include "globalsettings.h"
#include "util.h"
+#include "callback.h"
// other module headers
#include <mimelib/enum.h>
@@ -108,9 +110,11 @@
// other headers
#include <memory>
+#include <sstream>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
+#include <cassert>
#include "chiasmuskeyselector.h"
namespace KMail {
@@ -145,6 +149,9 @@ namespace KMail {
mShowOnlyOneMimePart( showOnlyOneMimePart ),
mKeepEncryptions( keepEncryptions ),
mIncludeSignatures( includeSignatures ),
+ mHasPendingAsyncJobs( false ),
+ mAllowAsync( false ),
+ mShowRawToltecMail( false ),
mAttachmentStrategy( strategy ),
mHtmlWriter( htmlWriter ),
mCSSHelper( cssHelper )
@@ -164,6 +171,8 @@ namespace KMail {
mShowOnlyOneMimePart( other.showOnlyOneMimePart() ),
mKeepEncryptions( other.keepEncryptions() ),
mIncludeSignatures( other.includeSignatures() ),
+ mHasPendingAsyncJobs( other.hasPendingAsyncJobs() ),
+ mAllowAsync( other.allowAsync() ),
mAttachmentStrategy( other.attachmentStrategy() ),
mHtmlWriter( other.htmlWriter() ),
mCSSHelper( other.cssHelper() )
@@ -176,7 +185,7 @@ namespace KMail {
void ObjectTreeParser::insertAndParseNewChildNode( partNode& startNode,
const char* content,
const char* cntDesc,
- bool append )
+ bool append, bool addToTextualContent )
{
DwBodyPart* myBody = new DwBodyPart( DwString( content ), 0 );
myBody->Parse();
@@ -201,6 +210,11 @@ namespace KMail {
partNode* parentNode = &startNode;
partNode* newNode = new partNode(false, myBody);
+
+ // Build the object tree of the new node before setting the parent, as otherwise
+ // buildObjectTree() would erronously modify the parents as well
+ newNode->buildObjectTree( false );
+
if ( append && parentNode->firstChild() ) {
parentNode = parentNode->firstChild();
while( parentNode->nextSibling() )
@@ -209,40 +223,37 @@ namespace KMail {
} else
parentNode->setFirstChild( newNode );
- newNode->buildObjectTree( false );
-
if ( startNode.mimePartTreeItem() ) {
- kdDebug(5006) << "\n -----> Inserting items into MimePartTree\n" << endl;
newNode->fillMimePartTree( startNode.mimePartTreeItem(), 0,
TQString::null, TQString::null, TQString::null, 0,
append );
- kdDebug(5006) << "\n <----- Finished inserting items into MimePartTree\n" << endl;
} else {
- kdDebug(5006) << "\n ------ Sorry, node.mimePartTreeItem() returns ZERO so"
- << "\n we cannot insert new lines into MimePartTree. :-(\n" << endl;
}
- kdDebug(5006) << "\n -----> Now parsing the MimePartTree\n" << endl;
ObjectTreeParser otp( mReader, cryptoProtocol() );
otp.parseObjectTree( newNode );
- mRawReplyString += otp.rawReplyString();
- mTextualContent += otp.textualContent();
- if ( !otp.textualContentCharset().isEmpty() )
- mTextualContentCharset = otp.textualContentCharset();
- kdDebug(5006) << "\n <----- Finished parsing the MimePartTree in insertAndParseNewChildNode()\n" << endl;
+ if ( addToTextualContent ) {
+ mRawReplyString += otp.rawReplyString();
+ mTextualContent += otp.textualContent();
+ if ( !otp.textualContentCharset().isEmpty() )
+ mTextualContentCharset = otp.textualContentCharset();
+ }
}
//-----------------------------------------------------------------------------
void ObjectTreeParser::parseObjectTree( partNode * node ) {
- kdDebug(5006) << "ObjectTreeParser::parseObjectTree( "
- << (node ? "node OK, " : "no node, ")
- << "showOnlyOneMimePart: " << (showOnlyOneMimePart() ? "TRUE" : "FALSE")
- << " )" << endl;
+ //kdDebug(5006) << "ObjectTreeParser::parseObjectTree( "
+ // << (node ? "node OK, " : "no node, ")
+ // << "showOnlyOneMimePart: " << (showOnlyOneMimePart() ? "TRUE" : "FALSE")
+ // << " )" << endl;
if ( !node )
return;
+ // reset pending async jobs state (we'll rediscover pending jobs as we go)
+ mHasPendingAsyncJobs = false;
+
// reset "processed" flags for...
if ( showOnlyOneMimePart() ) {
// ... this node and all descendants
@@ -260,29 +271,38 @@ namespace KMail {
ProcessResult processResult;
- if ( mReader )
+ if ( mReader ) {
htmlWriter()->queue( TQString::fromLatin1("<a name=\"att%1\"/>").arg( node->nodeId() ) );
+ }
+
if ( const Interface::BodyPartFormatter * formatter
= BodyPartFormatterFactory::instance()->createFor( node->typeString(), node->subTypeString() ) ) {
- PartNodeBodyPart part( *node, codecFor( node ) );
- // Set the default display strategy for this body part relying on the
- // identity of KMail::Interface::BodyPart::Display and AttachmentStrategy::Display
- part.setDefaultDisplay( (KMail::Interface::BodyPart::Display) attachmentStrategy()->defaultDisplay( node ) );
- const Interface::BodyPartFormatter::Result result = formatter->format( &part, htmlWriter() );
- if ( mReader && node->bodyPartMemento() )
- if ( Interface::Observable * obs = node->bodyPartMemento()->asObservable() )
- obs->attach( mReader );
- switch ( result ) {
- case Interface::BodyPartFormatter::AsIcon:
- processResult.setNeverDisplayInline( true );
- // fall through:
- case Interface::BodyPartFormatter::Failed:
- defaultHandling( node, processResult );
- break;
- case Interface::BodyPartFormatter::Ok:
- case Interface::BodyPartFormatter::NeedContent:
- // FIXME: incomplete content handling
- ;
+
+ // Only use the external plugin if we have a reader. Otherwise, just do nothing for this
+ // node.
+ if ( mReader ) {
+ PartNodeBodyPart part( *node, codecFor( node ) );
+ // Set the default display strategy for this body part relying on the
+ // identity of KMail::Interface::BodyPart::Display and AttachmentStrategy::Display
+ part.setDefaultDisplay( (KMail::Interface::BodyPart::Display) attachmentStrategy()->defaultDisplay( node ) );
+
+ writeAttachmentMarkHeader( node );
+ node->setDisplayedEmbedded( true );
+ Callback callback( mReader->message(), mReader );
+ const Interface::BodyPartFormatter::Result result = formatter->format( &part, htmlWriter(), callback );
+ writeAttachmentMarkFooter();
+ switch ( result ) {
+ case Interface::BodyPartFormatter::AsIcon:
+ processResult.setNeverDisplayInline( true );
+ // fall through:
+ case Interface::BodyPartFormatter::Failed:
+ defaultHandling( node, processResult );
+ break;
+ case Interface::BodyPartFormatter::Ok:
+ case Interface::BodyPartFormatter::NeedContent:
+ // FIXME: incomplete content handling
+ ;
+ }
}
} else {
const BodyPartFormatter * bpf
@@ -291,9 +311,13 @@ namespace KMail {
<< node->typeString() << '/' << node->subTypeString()
<< ')' << endl;
- if ( bpf && !bpf->process( this, node, processResult ) )
+ writeAttachmentMarkHeader( node );
+ if ( bpf && !bpf->process( this, node, processResult ) ) {
defaultHandling( node, processResult );
+ }
+ writeAttachmentMarkFooter();
}
+
node->setProcessed( true, false );
// adjust signed/encrypted flags if inline PGP was found
@@ -309,10 +333,15 @@ namespace KMail {
// ### bodypartformatters.
if ( !mReader )
return;
- if ( attachmentStrategy() == AttachmentStrategy::hidden() &&
+
+
+ const AttachmentStrategy * as = attachmentStrategy();
+ if ( as && as->defaultDisplay( node ) == AttachmentStrategy::None &&
!showOnlyOneMimePart() &&
- node->parentNode() /* message is not an attachment */ )
+ node->parentNode() /* message is not an attachment */ ) {
+ node->setDisplayedHidden( true );
return;
+ }
bool asIcon = true;
if ( showOnlyOneMimePart() )
@@ -321,25 +350,32 @@ namespace KMail {
// window!
asIcon = !node->hasContentDispositionInline();
else if ( !result.neverDisplayInline() )
- if ( const AttachmentStrategy * as = attachmentStrategy() )
+ if ( as )
asIcon = as->defaultDisplay( node ) == AttachmentStrategy::AsIcon;
// neither image nor text -> show as icon
- if ( !result.isImage()
- && node->type() != DwMime::kTypeText )
+ if ( !result.isImage() && node->type() != DwMime::kTypeText )
asIcon = true;
// if the image is not complete do not try to show it inline
if ( result.isImage() && !node->msgPart().isComplete() )
asIcon = true;
if ( asIcon ) {
- if ( attachmentStrategy() != AttachmentStrategy::hidden()
- || showOnlyOneMimePart() )
+ if ( !( as && as->defaultDisplay( node ) == AttachmentStrategy::None ) ||
+ showOnlyOneMimePart() ) {
writePartIcon( &node->msgPart(), node->nodeId() );
- } else if ( result.isImage() )
+ }
+ else {
+ node->setDisplayedHidden( true );
+ }
+ } else if ( result.isImage() ) {
+ node->setDisplayedEmbedded( true );
writePartIcon( &node->msgPart(), node->nodeId(), true );
- else
+ }
+ else {
+ node->setDisplayedEmbedded( true );
writeBodyString( node->msgPart().bodyDecoded(),
node->trueFromAddress(),
codecFor( node ), result, false );
+ }
// end of ###
}
@@ -380,7 +416,7 @@ namespace KMail {
const TQString& fromAddress,
bool doCheck,
TQCString* cleartextData,
- std::vector<GpgME::Signature> paramSignatures,
+ const std::vector<GpgME::Signature> & paramSignatures,
bool hideErrors )
{
bool bIsOpaqueSigned = false;
@@ -397,18 +433,22 @@ namespace KMail {
}
#ifndef NDEBUG
- if ( !doCheck )
- kdDebug(5006) << "ObjectTreeParser::writeOpaqueOrMultipartSignedData: showing OpenPGP (Encrypted+Signed) data" << endl;
- else
- if ( data )
- kdDebug(5006) << "ObjectTreeParser::writeOpaqueOrMultipartSignedData: processing Multipart Signed data" << endl;
- else
- kdDebug(5006) << "ObjectTreeParser::writeOpaqueOrMultipartSignedData: processing Opaque Signed data" << endl;
+ if ( !doCheck ) {
+ //kdDebug(5006) << "ObjectTreeParser::writeOpaqueOrMultipartSignedData: showing OpenPGP (Encrypted+Signed) data" << endl;
+ }
+ else {
+ if ( data ) {
+ //kdDebug(5006) << "ObjectTreeParser::writeOpaqueOrMultipartSignedData: processing Multipart Signed data" << endl;
+ }
+ else {
+ //kdDebug(5006) << "ObjectTreeParser::writeOpaqueOrMultipartSignedData: processing Opaque Signed data" << endl;
+ }
+ }
#endif
if ( doCheck && cryptProto ) {
- kdDebug(5006) << "ObjectTreeParser::writeOpaqueOrMultipartSignedData: going to call CRYPTPLUG "
- << cryptPlugLibName << endl;
+ //kdDebug(5006) << "ObjectTreeParser::writeOpaqueOrMultipartSignedData: going to call CRYPTPLUG "
+ // << cryptPlugLibName << endl;
}
TQCString cleartext;
@@ -423,9 +463,9 @@ namespace KMail {
// replace simple LFs by CRLSs
// according to RfC 2633, 3.1.1 Canonicalization
- kdDebug(5006) << "Converting LF to CRLF (see RfC 2633, 3.1.1 Canonicalization)" << endl;
+ //kdDebug(5006) << "Converting LF to CRLF (see RfC 2633, 3.1.1 Canonicalization)" << endl;
cleartext = Util::lf2crlf( cleartext );
- kdDebug(5006) << " done." << endl;
+ //kdDebug(5006) << " done." << endl;
}
dumpToFile( "dat_02_reader_signedtext_after_canonicalization",
@@ -437,7 +477,7 @@ namespace KMail {
}
std::vector<GpgME::Signature> signatures;
- if ( doCheck )
+ if ( !doCheck )
signatures = paramSignatures;
PartMetaData messagePart;
@@ -450,36 +490,100 @@ namespace KMail {
messagePart.status = i18n("Wrong Crypto Plug-In.");
messagePart.status_code = GPGME_SIG_STAT_NONE;
+ GpgME::Key key;
+
if ( doCheck && cryptProto ) {
GpgME::VerificationResult result;
if ( data ) { // detached
- if ( Kleo::VerifyDetachedJob * const job = cryptProto->verifyDetachedJob() ) {
- TQByteArray plainData = cleartext;
- plainData.resize( cleartext.size() - 1 );
- result = job->exec( signaturetext, plainData );
- messagePart.auditLog = job->auditLogAsHtml();
- } else {
- cryptPlugError = CANT_VERIFY_SIGNATURES;
+ const VerifyDetachedBodyPartMemento * m
+ = dynamic_cast<VerifyDetachedBodyPartMemento*>( sign.bodyPartMemento( "verifydetached" ) );
+ if ( !m ) {
+ Kleo::VerifyDetachedJob * job = cryptProto->verifyDetachedJob();
+ if ( !job ) {
+ cryptPlugError = CANT_VERIFY_SIGNATURES;
+ // PENDING(marc) cryptProto = 0 here?
+ } else {
+ TQByteArray plainData = cleartext;
+ plainData.resize( cleartext.size() - 1 );
+ VerifyDetachedBodyPartMemento * newM
+ = new VerifyDetachedBodyPartMemento( job, cryptProto->keyListJob(), signaturetext, plainData );
+ if ( allowAsync() ) {
+ if ( newM->start() ) {
+ messagePart.inProgress = true;
+ mHasPendingAsyncJobs = true;
+ } else {
+ m = newM;
+ }
+ } else {
+ newM->exec();
+ m = newM;
+ }
+ sign.setBodyPartMemento( "verifydetached", newM );
+ }
+ } else if ( m->isRunning() ) {
+ messagePart.inProgress = true;
+ mHasPendingAsyncJobs = true;
+ m = 0;
+ }
+
+ if ( m ) {
+ result = m->verifyResult();
+ messagePart.auditLogError = m->auditLogError();
+ messagePart.auditLog = m->auditLogAsHtml();
+ key = m->signingKey();
}
} else { // opaque
- if ( Kleo::VerifyOpaqueJob * const job = cryptProto->verifyOpaqueJob() ) {
- TQByteArray plainData;
- result = job->exec( signaturetext, plainData );
+ const VerifyOpaqueBodyPartMemento * m
+ = dynamic_cast<VerifyOpaqueBodyPartMemento*>( sign.bodyPartMemento( "verifyopaque" ) );
+ if ( !m ) {
+ Kleo::VerifyOpaqueJob * job = cryptProto->verifyOpaqueJob();
+ if ( !job ) {
+ cryptPlugError = CANT_VERIFY_SIGNATURES;
+ // PENDING(marc) cryptProto = 0 here?
+ } else {
+ VerifyOpaqueBodyPartMemento * newM
+ = new VerifyOpaqueBodyPartMemento( job, cryptProto->keyListJob(), signaturetext );
+ if ( allowAsync() ) {
+ if ( newM->start() ) {
+ messagePart.inProgress = true;
+ mHasPendingAsyncJobs = true;
+ } else {
+ m = newM;
+ }
+ } else {
+ newM->exec();
+ m = newM;
+ }
+ sign.setBodyPartMemento( "verifyopaque", newM );
+ }
+ } else if ( m->isRunning() ) {
+ messagePart.inProgress = true;
+ mHasPendingAsyncJobs = true;
+ m = 0;
+ }
+
+ if ( m ) {
+ result = m->verifyResult();
+ const TQByteArray & plainData = m->plainText();
cleartext = TQCString( plainData.data(), plainData.size() + 1 );
- messagePart.auditLog = job->auditLogAsHtml();
- } else {
- cryptPlugError = CANT_VERIFY_SIGNATURES;
+ messagePart.auditLogError = m->auditLogError();
+ messagePart.auditLog = m->auditLogAsHtml();
+ key = m->signingKey();
}
}
+ std::stringstream ss;
+ ss << result;
+ //kdDebug(5006) << ss.str().c_str() << endl;
signatures = result.signatures();
}
- if ( doCheck )
- kdDebug(5006) << "\nObjectTreeParser::writeOpaqueOrMultipartSignedData: returned from CRYPTPLUG" << endl;
+ if ( doCheck ) {
+ //kdDebug(5006) << "\nObjectTreeParser::writeOpaqueOrMultipartSignedData: returned from CRYPTPLUG" << endl;
+ }
// ### only one signature supported
if ( signatures.size() > 0 ) {
- kdDebug(5006) << "\nObjectTreeParser::writeOpaqueOrMultipartSignedData: found signature" << endl;
+ //kdDebug(5006) << "\nObjectTreeParser::writeOpaqueOrMultipartSignedData: found signature" << endl;
GpgME::Signature signature = signatures[0];
messagePart.status_code = signatureToStatus( signature );
@@ -493,16 +597,6 @@ namespace KMail {
if ( messagePart.status_code & GPGME_SIG_STAT_GOOD )
messagePart.isGoodSignature = true;
- // get key for this signature
- Kleo::KeyListJob *job = cryptProto->keyListJob();
- std::vector<GpgME::Key> keys;
- GpgME::KeyListResult keyListRes = job->exec( TQString::fromLatin1( signature.fingerprint() ), false, keys );
- GpgME::Key key;
- if ( keys.size() == 1 )
- key = keys[0];
- else if ( keys.size() > 1 )
- assert( false ); // ### wtf, what should we do in this case??
-
// save extended signature status flags
messagePart.sigSummary = signature.summary();
@@ -543,9 +637,9 @@ namespace KMail {
}
}
- kdDebug(5006) << "\n key id: " << messagePart.keyId
- << "\n key trust: " << messagePart.keyTrust
- << "\n signer: " << messagePart.signer << endl;
+ //kdDebug(5006) << "\n key id: " << messagePart.keyId
+ // << "\n key trust: " << messagePart.keyTrust
+ // << "\n signer: " << messagePart.signer << endl;
} else {
messagePart.creationTime = TQDateTime();
@@ -631,11 +725,51 @@ namespace KMail {
htmlWriter()->queue( writeSigstatFooter( messagePart ) );
}
- kdDebug(5006) << "\nObjectTreeParser::writeOpaqueOrMultipartSignedData: done, returning "
- << ( bIsOpaqueSigned ? "TRUE" : "FALSE" ) << endl;
+ //kdDebug(5006) << "\nObjectTreeParser::writeOpaqueOrMultipartSignedData: done, returning "
+ // << ( bIsOpaqueSigned ? "TRUE" : "FALSE" ) << endl;
return bIsOpaqueSigned;
}
+void ObjectTreeParser::writeDecryptionInProgressBlock() {
+ assert( mReader );
+ // PENDING(marc) find an animated icon here:
+ //const TQString iconName = KGlobal::instance()->iconLoader()->iconPath( "decrypted", KIcon::Small );
+ const TQString decryptedData = i18n("Encrypted data not shown");
+ PartMetaData messagePart;
+ messagePart.isDecryptable = true;
+ messagePart.isEncrypted = true;
+ messagePart.isSigned = false;
+ messagePart.inProgress = true;
+ htmlWriter()->queue( writeSigstatHeader( messagePart,
+ cryptoProtocol(),
+ TQString() ) );
+ //htmlWriter()->queue( decryptedData );
+ htmlWriter()->queue( writeSigstatFooter( messagePart ) );
+}
+
+void ObjectTreeParser::writeDeferredDecryptionBlock() {
+ assert( mReader );
+ const TQString iconName = KGlobal::instance()->iconLoader()->iconPath( "decrypted", KIcon::Small );
+ const TQString decryptedData =
+ "<div style=\"font-size:large; text-align:center;padding-top:20pt;\">" +
+ i18n("This message is encrypted.") +
+ "</div>"
+ "<div style=\"text-align:center; padding-bottom:20pt;\">"
+ "<a href=\"kmail:decryptMessage\">"
+ "<img src=\"" + iconName + "\"/>" +
+ i18n("Decrypt Message") +
+ "</a></div>";
+ PartMetaData messagePart;
+ messagePart.isDecryptable = true;
+ messagePart.isEncrypted = true;
+ messagePart.isSigned = false;
+ mRawReplyString += decryptedData.utf8();
+ htmlWriter()->queue( writeSigstatHeader( messagePart,
+ cryptoProtocol(),
+ TQString() ) );
+ htmlWriter()->queue( decryptedData );
+ htmlWriter()->queue( writeSigstatFooter( messagePart ) );
+}
bool ObjectTreeParser::okDecryptMIME( partNode& data,
TQCString& decryptedData,
@@ -644,11 +778,15 @@ bool ObjectTreeParser::okDecryptMIME( partNode& data,
bool showWarning,
bool& passphraseError,
bool& actuallyEncrypted,
+ bool& decryptionStarted,
TQString& aErrorText,
+ GpgME::Error & auditLogError,
TQString& auditLog )
{
passphraseError = false;
+ decryptionStarted = false;
aErrorText = TQString::null;
+ auditLogError = GpgME::Error();
auditLog = TQString::null;
bool bDecryptionOk = false;
enum { NO_PLUGIN, NOT_INITIALIZED, CANT_DECRYPT }
@@ -660,19 +798,7 @@ bool ObjectTreeParser::okDecryptMIME( partNode& data,
if ( cryptProto )
cryptPlugLibName = cryptProto->name();
- if ( mReader && !mReader->decryptMessage() ) {
- TQString iconName = KGlobal::instance()->iconLoader()->iconPath( "decrypted", KIcon::Small );
- decryptedData = "<div style=\"font-size:large; text-align:center;"
- "padding-top:20pt;\">"
- + i18n("This message is encrypted.").utf8()
- + "</div>"
- "<div style=\"text-align:center; padding-bottom:20pt;\">"
- "<a href=\"kmail:decryptMessage\">"
- "<img src=\"" + iconName.utf8() + "\"/>"
- + i18n("Decrypt Message").utf8()
- + "</a></div>";
- return false;
- }
+ assert( !mReader || mReader->decryptMessage() );
if ( cryptProto && !kmkernel->contextMenuShown() ) {
TQByteArray ciphertext( data.msgPart().bodyDecodedBinary() );
@@ -698,20 +824,48 @@ bool ObjectTreeParser::okDecryptMIME( partNode& data,
#endif
- kdDebug(5006) << "ObjectTreeParser::decryptMIME: going to call CRYPTPLUG "
- << cryptPlugLibName << endl;
+ //kdDebug(5006) << "ObjectTreeParser::decryptMIME: going to call CRYPTPLUG "
+ // << cryptPlugLibName << endl;
if ( mReader )
emit mReader->noDrag(); // in case pineentry pops up, don't let kmheaders start a drag afterwards
- Kleo::DecryptVerifyJob* job = cryptProto->decryptVerifyJob();
- if ( !job ) {
- cryptPlugError = CANT_DECRYPT;
- cryptProto = 0;
- } else {
- TQByteArray plainText;
- const std::pair<GpgME::DecryptionResult,GpgME::VerificationResult> res = job->exec( ciphertext, plainText );
- const GpgME::DecryptionResult & decryptResult = res.first;
- const GpgME::VerificationResult & verifyResult = res.second;
+ // Check whether the memento contains a result from last time:
+ const DecryptVerifyBodyPartMemento * m
+ = dynamic_cast<DecryptVerifyBodyPartMemento*>( data.bodyPartMemento( "decryptverify" ) );
+ if ( !m ) {
+ Kleo::DecryptVerifyJob * job = cryptProto->decryptVerifyJob();
+ if ( !job ) {
+ cryptPlugError = CANT_DECRYPT;
+ cryptProto = 0;
+ } else {
+ DecryptVerifyBodyPartMemento * newM
+ = new DecryptVerifyBodyPartMemento( job, ciphertext );
+ if ( allowAsync() ) {
+ if ( newM->start() ) {
+ decryptionStarted = true;
+ mHasPendingAsyncJobs = true;
+ } else {
+ m = newM;
+ }
+ } else {
+ newM->exec();
+ m = newM;
+ }
+ data.setBodyPartMemento( "decryptverify", newM );
+ }
+ } else if ( m->isRunning() ) {
+ decryptionStarted = true;
+ mHasPendingAsyncJobs = true;
+ m = 0;
+ }
+
+ if ( m ) {
+ const TQByteArray & plainText = m->plainText();
+ const GpgME::DecryptionResult & decryptResult = m->decryptResult();
+ const GpgME::VerificationResult & verifyResult = m->verifyResult();
+ std::stringstream ss;
+ ss << decryptResult << '\n' << verifyResult;
+ //kdDebug(5006) << ss.str().c_str() << endl;
signatureFound = verifyResult.signatures().size() > 0;
signatures = verifyResult.signatures();
bDecryptionOk = !decryptResult.error();
@@ -719,10 +873,11 @@ bool ObjectTreeParser::okDecryptMIME( partNode& data,
|| decryptResult.error().code() == GPG_ERR_NO_SECKEY;
actuallyEncrypted = decryptResult.error().code() != GPG_ERR_NO_DATA;
aErrorText = TQString::fromLocal8Bit( decryptResult.error().asString() );
- auditLog = job->auditLogAsHtml();
+ auditLogError = m->auditLogError();
+ auditLog = m->auditLogAsHtml();
- kdDebug(5006) << "ObjectTreeParser::decryptMIME: returned from CRYPTPLUG"
- << endl;
+ //kdDebug(5006) << "ObjectTreeParser::decryptMIME: returned from CRYPTPLUG"
+ // << endl;
if ( bDecryptionOk )
decryptedData = TQCString( plainText.data(), plainText.size() + 1 );
else if ( mReader && showWarning ) {
@@ -819,6 +974,7 @@ bool ObjectTreeParser::okDecryptMIME( partNode& data,
showOnlyOneMimePart() )
{
if ( mReader->htmlMail() ) {
+ curNode->setDisplayedEmbedded( true );
// ---Sven's strip </BODY> and </HTML> from end of attachment start-
// We must fo this, or else we will see only 1st inlined html
// attachment. It is IMHO enough to search only for </BODY> and
@@ -909,7 +1065,7 @@ namespace KMail {
if ( nextDelim < 0)
return false;
- kdDebug(5006) << " processing old style Mailman digest" << endl;
+ //kdDebug(5006) << " processing old style Mailman digest" << endl;
//if ( curNode->mRoot )
// curNode = curNode->mRoot;
@@ -952,7 +1108,7 @@ namespace KMail {
if ( -1 < thisEoL )
subject.truncate( thisEoL );
}
- kdDebug(5006) << " embedded message found: \"" << subject << "\"" << endl;
+ //kdDebug(5006) << " embedded message found: \"" << subject << "\"" << endl;
insertAndParseNewChildNode( *curNode,
&*partStr,
subject, true );
@@ -1029,8 +1185,7 @@ namespace KMail {
TQString htmlStr = "<table cellspacing=\"1\" class=\"textAtm\">"
"<tr class=\"textAtmH\"><td dir=\"" + dir + "\">";
if ( !fileName.isEmpty() )
- htmlStr += "<a href=\"" + TQString("file:")
- + KURL::encode_string( fileName ) + "\">"
+ htmlStr += "<a href=\"" + curNode->asHREF( "body" ) + "\">"
+ label + "</a>";
else
htmlStr += label;
@@ -1043,9 +1198,11 @@ namespace KMail {
// process old style not-multipart Mailman messages to
// enable verification of the embedded messages' signatures
if ( !isMailmanMessage( curNode ) ||
- !processMailmanMessage( curNode ) )
+ !processMailmanMessage( curNode ) ) {
writeBodyString( mRawReplyString, curNode->trueFromAddress(),
codecFor( curNode ), result, !bDrawFrame );
+ curNode->setDisplayedEmbedded( true );
+ }
if ( bDrawFrame )
htmlWriter()->queue( "</td></tr></table>" );
@@ -1065,7 +1222,30 @@ namespace KMail {
mTextualContentCharset = otp.textualContentCharset();
}
+ TQString ObjectTreeParser::defaultToltecReplacementText()
+ {
+ return i18n( "This message is a <i>Toltec</i> Groupware object, it can only be viewed with "
+ "Microsoft Outlook in combination with the Toltec connector." );
+ }
+
+ bool ObjectTreeParser::processToltecMail( partNode *node )
+ {
+ if ( !node || !mHtmlWriter || !GlobalSettings::self()->showToltecReplacementText() ||
+ !node->isToltecMessage() || mShowRawToltecMail )
+ return false;
+
+ htmlWriter()->queue( GlobalSettings::self()->toltecReplacementText() );
+ htmlWriter()->queue( "<br><br><a href=\"kmail:showRawToltecMail\">" +
+ i18n( "Show Raw Message" ) + "</a>" );
+ return true;
+ }
+
bool ObjectTreeParser::processMultiPartMixedSubtype( partNode * node, ProcessResult & ) {
+
+ if ( processToltecMail( node ) ) {
+ return true;
+ }
+
partNode * child = node->firstChild();
if ( !child )
return false;
@@ -1203,20 +1383,28 @@ namespace KMail {
CryptoProtocolSaver cpws( this, useThisCryptProto );
if ( partNode * dataChild = data->firstChild() ) {
- kdDebug(5006) << "\n-----> Calling parseObjectTree( curNode->mChild )\n" << endl;
+ //kdDebug(5006) << "\n-----> Calling parseObjectTree( curNode->mChild )\n" << endl;
stdChildHandling( dataChild );
- kdDebug(5006) << "\n-----> Returning from parseObjectTree( curNode->mChild )\n" << endl;
+ //kdDebug(5006) << "\n-----> Returning from parseObjectTree( curNode->mChild )\n" << endl;
return true;
}
- kdDebug(5006) << "\n-----> Initially processing encrypted data\n" << endl;
- PartMetaData messagePart;
node->setEncryptionState( KMMsgFullyEncrypted );
+
+ if ( mReader && !mReader->decryptMessage() ) {
+ writeDeferredDecryptionBlock();
+ data->setProcessed( true, false ); // Set the data node to done to prevent it from being processed
+ return true;
+ }
+
+ //kdDebug(5006) << "\n-----> Initially processing encrypted data\n" << endl;
+ PartMetaData messagePart;
TQCString decryptedData;
bool signatureFound;
std::vector<GpgME::Signature> signatures;
bool passphraseError;
bool actuallyEncrypted = true;
+ bool decryptionStarted;
bool bOkDecrypt = okDecryptMIME( *data,
decryptedData,
@@ -1225,9 +1413,16 @@ namespace KMail {
true,
passphraseError,
actuallyEncrypted,
+ decryptionStarted,
messagePart.errorText,
+ messagePart.auditLogError,
messagePart.auditLog );
+ if ( decryptionStarted ) {
+ writeDecryptionInProgressBlock();
+ return true;
+ }
+
// paint the frame
if ( mReader ) {
messagePart.isDecryptable = bOkDecrypt;
@@ -1287,17 +1482,17 @@ namespace KMail {
return false;
if ( partNode * child = node->firstChild() ) {
- kdDebug(5006) << "\n-----> Calling parseObjectTree( curNode->mChild )\n" << endl;
+ //kdDebug(5006) << "\n-----> Calling parseObjectTree( curNode->mChild )\n" << endl;
ObjectTreeParser otp( mReader, cryptoProtocol() );
otp.parseObjectTree( child );
mRawReplyString += otp.rawReplyString();
mTextualContent += otp.textualContent();
if ( !otp.textualContentCharset().isEmpty() )
mTextualContentCharset = otp.textualContentCharset();
- kdDebug(5006) << "\n<----- Returning from parseObjectTree( curNode->mChild )\n" << endl;
+ //kdDebug(5006) << "\n<----- Returning from parseObjectTree( curNode->mChild )\n" << endl;
return true;
}
- kdDebug(5006) << "\n-----> Initially processing data of embedded RfC 822 message\n" << endl;
+ //kdDebug(5006) << "\n-----> Initially processing data of embedded RfC 822 message\n" << endl;
// paint the frame
PartMetaData messagePart;
if ( mReader ) {
@@ -1310,7 +1505,7 @@ namespace KMail {
htmlWriter()->queue( writeSigstatHeader( messagePart,
cryptoProtocol(),
node->trueFromAddress(),
- filename ) );
+ node ) );
}
TQCString rfc822messageStr( node->msgPart().bodyDecoded() );
// display the headers of the encapsulated message
@@ -1319,14 +1514,16 @@ namespace KMail {
rfc822DwMessage->Parse();
KMMessage rfc822message( rfc822DwMessage );
node->setFromAddress( rfc822message.from() );
- kdDebug(5006) << "\n-----> Store RfC 822 message header \"From: " << rfc822message.from() << "\"\n" << endl;
+ //kdDebug(5006) << "\n-----> Store RfC 822 message header \"From: " << rfc822message.from() << "\"\n" << endl;
if ( mReader )
htmlWriter()->queue( mReader->writeMsgHeader( &rfc822message ) );
//mReader->parseMsgHeader( &rfc822message );
// display the body of the encapsulated message
insertAndParseNewChildNode( *node,
&*rfc822messageStr,
- "encapsulated message" );
+ "encapsulated message", false /*append*/,
+ false /*add to textual content*/ );
+ node->setDisplayedEmbedded( true );
if ( mReader )
htmlWriter()->queue( writeSigstatFooter( messagePart ) );
return true;
@@ -1335,14 +1532,14 @@ namespace KMail {
bool ObjectTreeParser::processApplicationOctetStreamSubtype( partNode * node, ProcessResult & result ) {
if ( partNode * child = node->firstChild() ) {
- kdDebug(5006) << "\n-----> Calling parseObjectTree( curNode->mChild )\n" << endl;
+ //kdDebug(5006) << "\n-----> Calling parseObjectTree( curNode->mChild )\n" << endl;
ObjectTreeParser otp( mReader, cryptoProtocol() );
otp.parseObjectTree( child );
mRawReplyString += otp.rawReplyString();
mTextualContent += otp.textualContent();
if ( !otp.textualContentCharset().isEmpty() )
mTextualContentCharset = otp.textualContentCharset();
- kdDebug(5006) << "\n<----- Returning from parseObjectTree( curNode->mChild )\n" << endl;
+ //kdDebug(5006) << "\n<----- Returning from parseObjectTree( curNode->mChild )\n" << endl;
return true;
}
@@ -1350,7 +1547,7 @@ namespace KMail {
if ( node->parentNode()
&& DwMime::kTypeMultipart == node->parentNode()->type()
&& DwMime::kSubtypeEncrypted == node->parentNode()->subType() ) {
- kdDebug(5006) << "\n-----> Initially processing encrypted data\n" << endl;
+ //kdDebug(5006) << "\n-----> Initially processing encrypted data\n" << endl;
node->setEncryptionState( KMMsgFullyEncrypted );
if ( keepEncryptions() ) {
const TQCString cstr = node->msgPart().bodyDecoded();
@@ -1358,6 +1555,8 @@ namespace KMail {
writeBodyString( cstr, node->trueFromAddress(),
codecFor( node ), result, false );
mRawReplyString += cstr;
+ } else if ( mReader && !mReader->decryptMessage() ) {
+ writeDeferredDecryptionBlock();
} else {
/*
ATTENTION: This code is to be replaced by the planned 'auto-detect' feature.
@@ -1369,6 +1568,7 @@ namespace KMail {
std::vector<GpgME::Signature> signatures;
bool passphraseError;
bool actuallyEncrypted = true;
+ bool decryptionStarted;
bool bOkDecrypt = okDecryptMIME( *node,
decryptedData,
@@ -1377,9 +1577,16 @@ namespace KMail {
true,
passphraseError,
actuallyEncrypted,
+ decryptionStarted,
messagePart.errorText,
+ messagePart.auditLogError,
messagePart.auditLog );
+ if ( decryptionStarted ) {
+ writeDecryptionInProgressBlock();
+ return true;
+ }
+
// paint the frame
if ( mReader ) {
messagePart.isDecryptable = bOkDecrypt;
@@ -1415,18 +1622,18 @@ namespace KMail {
bool ObjectTreeParser::processApplicationPkcs7MimeSubtype( partNode * node, ProcessResult & result ) {
if ( partNode * child = node->firstChild() ) {
- kdDebug(5006) << "\n-----> Calling parseObjectTree( curNode->mChild )\n" << endl;
+ //kdDebug(5006) << "\n-----> Calling parseObjectTree( curNode->mChild )\n" << endl;
ObjectTreeParser otp( mReader, cryptoProtocol() );
otp.parseObjectTree( child );
mRawReplyString += otp.rawReplyString();
mTextualContent += otp.textualContent();
if ( !otp.textualContentCharset().isEmpty() )
mTextualContentCharset = otp.textualContentCharset();
- kdDebug(5006) << "\n<----- Returning from parseObjectTree( curNode->mChild )\n" << endl;
+ //kdDebug(5006) << "\n<----- Returning from parseObjectTree( curNode->mChild )\n" << endl;
return true;
}
- kdDebug(5006) << "\n-----> Initially processing signed and/or encrypted data\n" << endl;
+ //kdDebug(5006) << "\n-----> Initially processing signed and/or encrypted data\n" << endl;
if ( !node->dwPart() || !node->dwPart()->hasHeaders() )
return false;
@@ -1445,7 +1652,7 @@ namespace KMail {
const TQByteArray certData = node->msgPart().bodyDecodedBinary();
- Kleo::ImportJob *import = smimeCrypto->importJob();
+ const STD_NAMESPACE_PREFIX auto_ptr<Kleo::ImportJob> import( smimeCrypto->importJob() );
const GpgME::ImportResult res = import->exec( certData );
if ( res.error() ) {
htmlWriter()->queue( i18n( "Sorry, certificate could not be imported.<br>"
@@ -1491,11 +1698,14 @@ namespace KMail {
htmlWriter()->queue( i18n( "Failed: %1 (%2)" )
.arg( (*it).fingerprint(),
TQString::fromLocal8Bit( (*it).error().asString() ) ) );
- else if ( (*it).status() & ~GpgME::Import::ContainedSecretKey )
- if ( (*it).status() & GpgME::Import::ContainedSecretKey )
+ else if ( (*it).status() & ~GpgME::Import::ContainedSecretKey ) {
+ if ( (*it).status() & GpgME::Import::ContainedSecretKey ) {
htmlWriter()->queue( i18n( "New or changed: %1 (secret key available)" ).arg( (*it).fingerprint() ) );
- else
+ }
+ else {
htmlWriter()->queue( i18n( "New or changed: %1" ).arg( (*it).fingerprint() ) );
+ }
+ }
htmlWriter()->queue( "<br>" );
}
@@ -1520,10 +1730,12 @@ namespace KMail {
// if we either *know* that it is an encrypted message part
// or there is neither signed nor encrypted parameter.
if ( !isSigned ) {
- if ( isEncrypted )
- kdDebug(5006) << "pkcs7 mime == S/MIME TYPE: enveloped (encrypted) data" << endl;
- else
- kdDebug(5006) << "pkcs7 mime - type unknown - enveloped (encrypted) data ?" << endl;
+ if ( isEncrypted ) {
+ //kdDebug(5006) << "pkcs7 mime == S/MIME TYPE: enveloped (encrypted) data" << endl;
+ }
+ else {
+ //kdDebug(5006) << "pkcs7 mime - type unknown - enveloped (encrypted) data ?" << endl;
+ }
TQCString decryptedData;
PartMetaData messagePart;
messagePart.isEncrypted = true;
@@ -1532,57 +1744,69 @@ namespace KMail {
std::vector<GpgME::Signature> signatures;
bool passphraseError;
bool actuallyEncrypted = true;
+ bool decryptionStarted;
- if ( okDecryptMIME( *node,
+ if ( mReader && !mReader->decryptMessage() ) {
+ writeDeferredDecryptionBlock();
+ isEncrypted = true;
+ signTestNode = 0; // PENDING(marc) to be abs. sure, we'd need to have to look at the content
+ } else {
+ const bool bOkDecrypt = okDecryptMIME( *node,
decryptedData,
signatureFound,
signatures,
false,
passphraseError,
actuallyEncrypted,
+ decryptionStarted,
messagePart.errorText,
- messagePart.auditLog ) ) {
- kdDebug(5006) << "pkcs7 mime - encryption found - enveloped (encrypted) data !" << endl;
- isEncrypted = true;
- node->setEncryptionState( KMMsgFullyEncrypted );
- signTestNode = 0;
- // paint the frame
- messagePart.isDecryptable = true;
- if ( mReader )
- htmlWriter()->queue( writeSigstatHeader( messagePart,
- cryptoProtocol(),
- node->trueFromAddress() ) );
- insertAndParseNewChildNode( *node,
- &*decryptedData,
- "encrypted data" );
- if ( mReader )
- htmlWriter()->queue( writeSigstatFooter( messagePart ) );
- } else {
- // decryption failed, which could be because the part was encrypted but
- // decryption failed, or because we didn't know if it was encrypted, tried,
- // and failed. If the message was not actually encrypted, we continue
- // assuming it's signed
- if ( passphraseError || ( smimeType.isEmpty() && actuallyEncrypted ) ) {
+ messagePart.auditLogError,
+ messagePart.auditLog );
+ if ( decryptionStarted ) {
+ writeDecryptionInProgressBlock();
+ return true;
+ }
+ if ( bOkDecrypt ) {
+ //kdDebug(5006) << "pkcs7 mime - encryption found - enveloped (encrypted) data !" << endl;
isEncrypted = true;
+ node->setEncryptionState( KMMsgFullyEncrypted );
signTestNode = 0;
- }
-
- if ( isEncrypted ) {
- kdDebug(5006) << "pkcs7 mime - ERROR: COULD NOT DECRYPT enveloped data !" << endl;
// paint the frame
- messagePart.isDecryptable = false;
- if ( mReader ) {
+ messagePart.isDecryptable = true;
+ if ( mReader )
htmlWriter()->queue( writeSigstatHeader( messagePart,
cryptoProtocol(),
node->trueFromAddress() ) );
- if ( mReader->decryptMessage() )
- writePartIcon( &node->msgPart(), node->nodeId() );
- else
- htmlWriter()->queue( TQString::fromUtf8( decryptedData ) );
+ insertAndParseNewChildNode( *node,
+ &*decryptedData,
+ "encrypted data" );
+ if ( mReader )
htmlWriter()->queue( writeSigstatFooter( messagePart ) );
- }
} else {
- kdDebug(5006) << "pkcs7 mime - NO encryption found" << endl;
+ // decryption failed, which could be because the part was encrypted but
+ // decryption failed, or because we didn't know if it was encrypted, tried,
+ // and failed. If the message was not actually encrypted, we continue
+ // assuming it's signed
+ if ( passphraseError || ( smimeType.isEmpty() && actuallyEncrypted ) ) {
+ isEncrypted = true;
+ signTestNode = 0;
+ }
+
+ if ( isEncrypted ) {
+ //kdDebug(5006) << "pkcs7 mime - ERROR: COULD NOT DECRYPT enveloped data !" << endl;
+ // paint the frame
+ messagePart.isDecryptable = false;
+ if ( mReader ) {
+ htmlWriter()->queue( writeSigstatHeader( messagePart,
+ cryptoProtocol(),
+ node->trueFromAddress() ) );
+ assert( mReader->decryptMessage() ); // handled above
+ writePartIcon( &node->msgPart(), node->nodeId() );
+ htmlWriter()->queue( writeSigstatFooter( messagePart ) );
+ }
+ } else {
+ //kdDebug(5006) << "pkcs7 mime - NO encryption found" << endl;
+ }
}
}
if ( isEncrypted )
@@ -1591,10 +1815,12 @@ namespace KMail {
// We now try signature verification if necessarry.
if ( signTestNode ) {
- if ( isSigned )
- kdDebug(5006) << "pkcs7 mime == S/MIME TYPE: opaque signed data" << endl;
- else
- kdDebug(5006) << "pkcs7 mime - type unknown - opaque signed data ?" << endl;
+ if ( isSigned ) {
+ //kdDebug(5006) << "pkcs7 mime == S/MIME TYPE: opaque signed data" << endl;
+ }
+ else {
+ //kdDebug(5006) << "pkcs7 mime - type unknown - opaque signed data ?" << endl;
+ }
bool sigFound = writeOpaqueOrMultipartSignedData( 0,
*signTestNode,
@@ -1605,14 +1831,14 @@ namespace KMail {
isEncrypted );
if ( sigFound ) {
if ( !isSigned ) {
- kdDebug(5006) << "pkcs7 mime - signature found - opaque signed data !" << endl;
+ //kdDebug(5006) << "pkcs7 mime - signature found - opaque signed data !" << endl;
isSigned = true;
}
signTestNode->setSignatureState( KMMsgFullySigned );
if ( signTestNode != node )
node->setSignatureState( KMMsgFullySigned );
} else {
- kdDebug(5006) << "pkcs7 mime - NO signature found :-(" << endl;
+ //kdDebug(5006) << "pkcs7 mime - NO signature found :-(" << endl;
}
}
@@ -1666,8 +1892,8 @@ bool ObjectTreeParser::decryptChiasmus( const TQByteArray& data, TQByteArray& bo
GlobalSettings::setChiasmusDecryptionKey( selectorDlg.key() );
assert( !GlobalSettings::chiasmusDecryptionKey().isEmpty() );
- Kleo::SpecialJob * job = chiasmus->specialJob( "x-decrypt", TQMap<TQString,TQVariant>() );
- if ( !job ) {
+ const STD_NAMESPACE_PREFIX auto_ptr<Kleo::SpecialJob> job( chiasmus->specialJob( "x-decrypt", TQMap<TQString,TQVariant>() ) );
+ if ( !job.get() ) {
errorText = i18n( "Chiasmus backend does not offer the "
"\"x-decrypt\" function. Please report this bug." );
return false;
@@ -1761,8 +1987,7 @@ bool ObjectTreeParser::processApplicationMsTnefSubtype( partNode *node, ProcessR
TQString htmlStr = "<table cellspacing=\"1\" class=\"textAtm\">"
"<tr class=\"textAtmH\"><td dir=\"" + dir + "\">";
if ( !fileName.isEmpty() )
- htmlStr += "<a href=\"" + TQString("file:")
- + KURL::encode_string( fileName ) + "\">"
+ htmlStr += "<a href=\"" + node->asHREF( "body" ) + "\">"
+ label + "</a>";
else
htmlStr += label;
@@ -1816,8 +2041,6 @@ bool ObjectTreeParser::processApplicationMsTnefSubtype( partNode *node, ProcessR
if ( !mReader || !msgPart )
return;
- kdDebug(5006) << "writePartIcon: PartNum: " << partNum << endl;
-
TQString label = msgPart->fileName();
if( label.isEmpty() )
label = msgPart->name();
@@ -1831,9 +2054,7 @@ bool ObjectTreeParser::processApplicationMsTnefSubtype( partNode *node, ProcessR
TQString fileName = mReader->writeMessagePartToTempFile( msgPart, partNum );
- TQString href = fileName.isEmpty() ?
- "part://" + TQString::number( partNum + 1 ) :
- "file:" + KURL::encode_string( fileName ) ;
+ TQString href = TQString( "attachment:%1?place=body" ).arg( partNum );
TQString iconName;
if( inlineImage )
@@ -1854,13 +2075,13 @@ bool ObjectTreeParser::processApplicationMsTnefSubtype( partNode *node, ProcessR
if( inlineImage )
// show the filename of the image below the embedded image
htmlWriter()->queue( "<div><a href=\"" + href + "\">"
- "<img src=\"" + iconName + "\" border=\"0\" style=\"max-width: 100%\"></a>"
+ "<img src=\"" + fileName + "\" border=\"0\" style=\"max-width: 100%\"></a>"
"</div>"
"<div><a href=\"" + href + "\">" + label + "</a>"
"</div>"
"<div>" + comment + "</div><br>" );
else
- // show the filename next to the image
+ // show the filename next to the icon
htmlWriter()->queue( "<div><a href=\"" + href + "\"><img src=\"" +
iconName + "\" border=\"0\" style=\"max-width: 100%\">" + label +
"</a></div>"
@@ -2077,16 +2298,29 @@ static TQString beginVerboseSigstatHeader()
return "<table cellspacing=\"0\" cellpadding=\"0\" width=\"100%\"><tr><td rowspan=\"2\">";
}
-static TQString makeShowAuditLogLink( const TQString & auditLog ) {
- if ( auditLog.isEmpty() )
- return i18n("No Audit Log available");
+static TQString makeShowAuditLogLink( const GpgME::Error & err, const TQString & auditLog ) {
+ if ( const unsigned int code = err.code() ) {
+ if ( code == GPG_ERR_NOT_IMPLEMENTED ) {
+ //kdDebug(5006) << "makeShowAuditLogLink: not showing link (not implemented)" << endl;
+ return TQString();
+ } else if ( code == GPG_ERR_NO_DATA ) {
+ //kdDebug(5006) << "makeShowAuditLogLink: not showing link (not available)" << endl;
+ return i18n("No Audit Log available");
+ } else {
+ return i18n("Error Retrieving Audit Log: %1").arg( TQString::fromLocal8Bit( err.asString() ) );
+ }
+ }
- KURL url;
- url.setProtocol( "kmail" );
- url.setPath( "showAuditLog" );
- url.addQueryItem( "log", auditLog );
+ if ( !auditLog.isEmpty() ) {
+ KURL url;
+ url.setProtocol( "kmail" );
+ url.setPath( "showAuditLog" );
+ url.addQueryItem( "log", auditLog );
- return "<a href=\"" + url.htmlURL() + "\">" + i18n("The Audit Log is a detailed error log from the gnupg backend", "Show Audit Log") + "</a>";
+ return "<a href=\"" + url.htmlURL() + "\">" + i18n("The Audit Log is a detailed error log from the gnupg backend", "Show Audit Log") + "</a>";
+ }
+
+ return TQString::null;
}
static TQString endVerboseSigstatHeader( const PartMetaData & pmd )
@@ -2097,7 +2331,7 @@ static TQString endVerboseSigstatHeader( const PartMetaData & pmd )
html += i18n( "Hide Details" );
html += "</a></td></tr>";
html += "<tr><td align=\"right\" valign=\"bottom\" nowrap=\"nowrap\">";
- html += makeShowAuditLogLink( pmd.auditLog );
+ html += makeShowAuditLogLink( pmd.auditLogError, pmd.auditLog );
html += "</td></tr></table>";
return html;
}
@@ -2105,7 +2339,7 @@ static TQString endVerboseSigstatHeader( const PartMetaData & pmd )
TQString ObjectTreeParser::writeSigstatHeader( PartMetaData & block,
const Kleo::CryptoBackend::Protocol * cryptProto,
const TQString & fromAddress,
- const TQString & filename )
+ partNode *node )
{
const bool isSMIME = cryptProto && ( cryptProto == Kleo::CryptoBackendFactory::instance()->smime() );
TQString signer = block.signer;
@@ -2118,12 +2352,11 @@ TQString ObjectTreeParser::writeSigstatHeader( PartMetaData & block,
{
htmlStr += "<table cellspacing=\"1\" "+cellPadding+" class=\"rfc822\">"
"<tr class=\"rfc822H\"><td dir=\"" + dir + "\">";
- if( !filename.isEmpty() )
- htmlStr += "<a href=\"" + TQString("file:")
- + KURL::encode_string( filename ) + "\">"
+ if ( node )
+ htmlStr += "<a href=\"" + node->asHREF( "body" ) + "\">"
+ i18n("Encapsulated message") + "</a>";
else
- htmlStr += i18n("Encapsulated message");
+ htmlStr += i18n("Encapsulated message");
htmlStr += "</td></tr><tr class=\"rfc822B\"><td>";
}
@@ -2131,7 +2364,9 @@ TQString ObjectTreeParser::writeSigstatHeader( PartMetaData & block,
{
htmlStr += "<table cellspacing=\"1\" "+cellPadding+" class=\"encr\">"
"<tr class=\"encrH\"><td dir=\"" + dir + "\">";
- if( block.isDecryptable )
+ if ( block.inProgress )
+ htmlStr += i18n("Please wait while the message is being decrypted...");
+ else if ( block.isDecryptable )
htmlStr += i18n("Encrypted message");
else {
htmlStr += i18n("Encrypted message (decryption not possible)");
@@ -2140,9 +2375,18 @@ TQString ObjectTreeParser::writeSigstatHeader( PartMetaData & block,
}
htmlStr += "</td></tr><tr class=\"encrB\"><td>";
}
+
+ if ( block.isSigned && block.inProgress )
+ {
+ block.signClass = "signInProgress";
+ htmlStr += "<table cellspacing=\"1\" "+cellPadding+" class=\"signInProgress\">"
+ "<tr class=\"signInProgressH\"><td dir=\"" + dir + "\">";
+ htmlStr += i18n("Please wait while the signature is being verified...");
+ htmlStr += "</td></tr><tr class=\"signInProgressB\"><td>";
+ }
simpleHtmlStr = htmlStr;
- if( block.isSigned ) {
+ if ( block.isSigned && !block.inProgress ) {
TQStringList& blockAddrs( block.signerMailAddresses );
// note: At the moment frameColor and showKeyInfos are
// used for CMS only but not for PGP signatures
@@ -2232,7 +2476,7 @@ TQString ObjectTreeParser::writeSigstatHeader( PartMetaData & block,
if( block.keyId.isEmpty() )
certificate = i18n("certificate");
else
- certificate = startKeyHREF + i18n("certificate") + "</a>";
+ certificate = startKeyHREF + i18n("certificate") + "</a>";
if( !blockAddrs.empty() ){
if( blockAddrs.grep(
msgFrom,
@@ -2513,6 +2757,26 @@ TQString ObjectTreeParser::writeSigstatFooter( PartMetaData& block )
}
//-----------------------------------------------------------------------------
+
+void ObjectTreeParser::writeAttachmentMarkHeader( partNode *node )
+{
+ if ( !mReader )
+ return;
+
+ htmlWriter()->queue( TQString( "<div id=\"attachmentDiv%1\">\n" ).arg( node->nodeId() ) );
+}
+
+//-----------------------------------------------------------------------------
+
+void ObjectTreeParser::writeAttachmentMarkFooter()
+{
+ if ( !mReader )
+ return;
+
+ htmlWriter()->queue( TQString( "</div>" ) );
+}
+
+//-----------------------------------------------------------------------------
void ObjectTreeParser::writeBodyStr( const TQCString& aStr, const TQTextCodec *aCodec,
const TQString& fromAddress )
{
@@ -2562,8 +2826,8 @@ void ObjectTreeParser::writeBodyStr( const TQCString& aStr, const TQTextCodec *a
TQCString str( *npbit );
if( !str.isEmpty() ) {
htmlStr += quotedHTML( aCodec->toUnicode( str ), decorate );
- kdDebug( 5006 ) << "Non-empty Non-OpenPGP block found: '" << str
- << "'" << endl;
+ //kdDebug( 5006 ) << "Non-empty Non-OpenPGP block found: '" << str
+ // << "'" << endl;
// treat messages with empty lines before the first clearsigned
// block as fully signed/encrypted
if( firstNonPgpBlock ) {
@@ -2706,7 +2970,7 @@ TQString ObjectTreeParser::quotedHTML( const TQString& s, bool decorate )
const unsigned int length = s.length();
// skip leading empty lines
- for ( pos = 0; pos < length && s[pos] <= ' '; pos++ );
+ for ( pos = 0; pos < length && s[pos] <= ' '; pos++ ) { ; }
while (pos > 0 && (s[pos-1] == ' ' || s[pos-1] == '\t')) pos--;
beg = pos;
@@ -2836,10 +3100,6 @@ TQString ObjectTreeParser::quotedHTML( const TQString& s, bool decorate )
else
htmlStr.append( quoteEnd );
- //kdDebug(5006) << "KMReaderWin::quotedHTML:\n"
- // << "========================================\n"
- // << htmlStr
- // << "\n======================================\n";
return htmlStr;
}
diff --git a/kmail/objecttreeparser.h b/kmail/objecttreeparser.h
index 2edc406f9..ad980edaf 100644
--- a/kmail/objecttreeparser.h
+++ b/kmail/objecttreeparser.h
@@ -40,12 +40,18 @@
#include <kleo/cryptobackend.h>
#include <gpgmepp/verificationresult.h>
+#include <cassert>
+
class KMReaderWin;
class KMMessagePart;
class TQString;
class TQWidget;
class partNode;
+namespace GpgME {
+ class Error;
+}
+
namespace KMail {
class AttachmentStrategy;
@@ -110,6 +116,11 @@ namespace KMail {
KMail::CSSHelper * cssHelper=0 );
virtual ~ObjectTreeParser();
+ void setAllowAsync( bool allow ) { assert( !mHasPendingAsyncJobs ); mAllowAsync = allow; }
+ bool allowAsync() const { return mAllowAsync; }
+
+ bool hasPendingAsyncJobs() const { return mHasPendingAsyncJobs; }
+
TQCString rawReplyString() const { return mRawReplyString; }
/*! @return the text of the message, ie. what would appear in the
@@ -140,6 +151,15 @@ namespace KMail {
mIncludeSignatures = include;
}
+ // Controls whether Toltec invitations are displayed in their raw form or as a replacement text,
+ // which is used in processToltecMail().
+ void setShowRawToltecMail( bool showRawToltecMail ) { mShowRawToltecMail = showRawToltecMail; }
+ bool showRawToltecMail() const { return mShowRawToltecMail; }
+
+ /// default text for processToltecMail(), which is used in kmail.kcfg, therefore it
+ /// needs to be static here.
+ static TQString defaultToltecReplacementText();
+
const KMail::AttachmentStrategy * attachmentStrategy() const {
return mAttachmentStrategy;
}
@@ -161,16 +181,24 @@ namespace KMail {
void defaultHandling( partNode * node, ProcessResult & result );
- /** 1. Create a new partNode using 'content' data and Content-Description
- found in 'cntDesc'.
- 2. Make this node the child of 'node'.
- 3. Insert the respective entries in the Mime Tree Viewer.
- 3. Parse the 'node' to display the content. */
+ /**
+ * 1. Create a new partNode using 'content' data and Content-Description
+ * found in 'cntDesc'.
+ * 2. Make this node the child of 'node'.
+ * 3. Insert the respective entries in the Mime Tree Viewer.
+ * 3. Parse the 'node' to display the content.
+ *
+ * @param addToTextualContent If true, this will add the textual content of the parsed node
+ * to the textual content of the current object tree parser.
+ * Setting this to false is useful for encapsulated messages, as we
+ * do not want the text in those to appear in the editor
+ */
// Function will be replaced once KMime is alive.
void insertAndParseNewChildNode( partNode & node,
const char * content,
const char * cntDesc,
- bool append=false );
+ bool append=false,
+ bool addToTextualContent = true );
/** if data is 0:
Feeds the HTML widget with the contents of the opaque signed
data found in partNode 'sign'.
@@ -186,9 +214,17 @@ namespace KMail {
const TQString & fromAddress,
bool doCheck=true,
TQCString * cleartextData=0,
- std::vector<GpgME::Signature> paramSignatures = std::vector<GpgME::Signature>(),
+ const std::vector<GpgME::Signature> & paramSignatures = std::vector<GpgME::Signature>(),
bool hideErrors=false );
+ /** Writes out the block that we use when the node is encrypted,
+ but we're deferring decryption for later. */
+ void writeDeferredDecryptionBlock();
+
+ /** Writes out the block that we use when the node is encrypted,
+ but we've just kicked off async decryption. */
+ void writeDecryptionInProgressBlock();
+
/** Returns the contents of the given multipart/encrypted
object. Data is decypted. May contain body parts. */
bool okDecryptMIME( partNode& data,
@@ -198,11 +234,24 @@ namespace KMail {
bool showWarning,
bool& passphraseError,
bool& actuallyEncrypted,
+ bool& decryptionStarted,
TQString& aErrorText,
+ GpgME::Error & auditLogError,
TQString& auditLog );
bool processMailmanMessage( partNode * node );
+ /**
+ * This is called for all multipart/mixed nodes. It checks if that belongs to a Toltec mail,
+ * by checking various criteria.
+ * If it is a toltec mail, a special text, instead of the confusing toltec text, will be
+ * displayed.
+ *
+ * @return true if the mail was indeed a toltec mail, in which case the node should not be
+ * processed further
+ */
+ bool processToltecMail( partNode * node );
+
/** Checks whether @p str contains external references. To be precise,
we only check whether @p str contains 'xxx="http[s]:' where xxx is
not href. Obfuscated external references are ignored on purpose.
@@ -245,9 +294,15 @@ namespace KMail {
TQString writeSigstatHeader( KMail::PartMetaData & part,
const Kleo::CryptoBackend::Protocol * cryptProto,
const TQString & fromAddress,
- const TQString & filename = TQString::null );
+ partNode *node = 0 );
TQString writeSigstatFooter( KMail::PartMetaData & part );
+ // The attachment mark is a div that is placed around the attchment. It is used for drawing
+ // a yellow border around the attachment when scrolling to it. When scrolling to it, the border
+ // color of the div is changed, see KMReaderWin::scrollToAttachment().
+ void writeAttachmentMarkHeader( partNode *node );
+ void writeAttachmentMarkFooter();
+
void writeBodyStr( const TQCString & bodyString,
const TQTextCodec * aCodec,
const TQString & fromAddress,
@@ -281,6 +336,9 @@ namespace KMail {
bool mShowOnlyOneMimePart;
bool mKeepEncryptions;
bool mIncludeSignatures;
+ bool mHasPendingAsyncJobs;
+ bool mAllowAsync;
+ bool mShowRawToltecMail;
const KMail::AttachmentStrategy * mAttachmentStrategy;
KMail::HtmlWriter * mHtmlWriter;
KMail::CSSHelper * mCSSHelper;
diff --git a/kmail/objecttreeparser_p.cpp b/kmail/objecttreeparser_p.cpp
new file mode 100644
index 000000000..a645b3989
--- /dev/null
+++ b/kmail/objecttreeparser_p.cpp
@@ -0,0 +1,350 @@
+/* -*- mode: C++; c-file-style: "gnu" -*-
+ objecttreeparser_p.cpp
+
+ This file is part of KMail, the KDE mail client.
+ Copyright (c) 2009 Klarälvdalens Datakonsult AB
+ Authors: Marc Mutz <marc@kdab.net>
+
+ KMail 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.
+
+ KMail is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), 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
+ TQt. 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 <config.h>
+
+#include "objecttreeparser_p.h"
+
+#include <kleo/decryptverifyjob.h>
+#include <kleo/verifydetachedjob.h>
+#include <kleo/verifyopaquejob.h>
+#include <kleo/keylistjob.h>
+
+#include <gpgmepp/keylistresult.h>
+
+#include <tqtimer.h>
+#include <tqstringlist.h>
+
+#include <cassert>
+
+using namespace KMail;
+using namespace Kleo;
+using namespace GpgME;
+
+CryptoBodyPartMemento::CryptoBodyPartMemento()
+ : TQObject( 0 ),
+ Interface::BodyPartMemento(),
+ ISubject(),
+ m_running( false )
+{
+
+}
+
+CryptoBodyPartMemento::~CryptoBodyPartMemento() {}
+
+void CryptoBodyPartMemento::setAuditLog( const GpgME::Error & err, const TQString & log ) {
+ m_auditLogError = err;
+ m_auditLog = log;
+}
+
+void CryptoBodyPartMemento::setRunning( bool running ) {
+ m_running = running;
+}
+
+DecryptVerifyBodyPartMemento::DecryptVerifyBodyPartMemento( DecryptVerifyJob * job, const TQByteArray & cipherText )
+ : CryptoBodyPartMemento(),
+ m_cipherText( cipherText ),
+ m_job( job )
+{
+ assert( m_job );
+}
+
+DecryptVerifyBodyPartMemento::~DecryptVerifyBodyPartMemento() {
+ if ( m_job )
+ m_job->slotCancel();
+}
+
+bool DecryptVerifyBodyPartMemento::start() {
+ assert( m_job );
+ if ( const GpgME::Error err = m_job->start( m_cipherText ) ) {
+ m_dr = DecryptionResult( err );
+ return false;
+ }
+ connect( m_job, TQT_SIGNAL(result(const GpgME::DecryptionResult&,const GpgME::VerificationResult&,const TQByteArray&)),
+ this, TQT_SLOT(slotResult(const GpgME::DecryptionResult&,const GpgME::VerificationResult&,const TQByteArray&)) );
+ setRunning( true );
+ return true;
+}
+
+void DecryptVerifyBodyPartMemento::exec() {
+ assert( m_job );
+ TQByteArray plainText;
+ setRunning( true );
+ const std::pair<DecryptionResult,VerificationResult> p = m_job->exec( m_cipherText, plainText );
+ saveResult( p.first, p.second, plainText );
+ m_job->deleteLater(); // exec'ed jobs don't delete themselves
+ m_job = 0;
+}
+
+void DecryptVerifyBodyPartMemento::saveResult( const DecryptionResult & dr,
+ const VerificationResult & vr,
+ const TQByteArray & plainText )
+{
+ assert( m_job );
+ setRunning( false );
+ m_dr = dr;
+ m_vr = vr;
+ m_plainText = plainText;
+ setAuditLog( m_job->auditLogError(), m_job->auditLogAsHtml() );
+}
+
+void DecryptVerifyBodyPartMemento::slotResult( const DecryptionResult & dr,
+ const VerificationResult & vr,
+ const TQByteArray & plainText )
+{
+ saveResult( dr, vr, plainText );
+ m_job = 0;
+ notify();
+}
+
+
+
+
+VerifyDetachedBodyPartMemento::VerifyDetachedBodyPartMemento( VerifyDetachedJob * job,
+ KeyListJob * klj,
+ const TQByteArray & signature,
+ const TQByteArray & plainText )
+ : CryptoBodyPartMemento(),
+ m_signature( signature ),
+ m_plainText( plainText ),
+ m_job( job ),
+ m_keylistjob( klj )
+{
+ assert( m_job );
+}
+
+VerifyDetachedBodyPartMemento::~VerifyDetachedBodyPartMemento() {
+ if ( m_job )
+ m_job->slotCancel();
+ if ( m_keylistjob )
+ m_keylistjob->slotCancel();
+}
+
+bool VerifyDetachedBodyPartMemento::start() {
+ assert( m_job );
+ if ( const GpgME::Error err = m_job->start( m_signature, m_plainText ) ) {
+ m_vr = VerificationResult( err );
+ return false;
+ }
+ connect( m_job, TQT_SIGNAL(result(const GpgME::VerificationResult&)),
+ this, TQT_SLOT(slotResult(const GpgME::VerificationResult&)) );
+ setRunning( true );
+ return true;
+}
+
+void VerifyDetachedBodyPartMemento::exec() {
+ assert( m_job );
+ setRunning( true );
+ saveResult( m_job->exec( m_signature, m_plainText ) );
+ m_job->deleteLater(); // exec'ed jobs don't delete themselves
+ m_job = 0;
+ if ( canStartKeyListJob() ) {
+ std::vector<GpgME::Key> keys;
+ m_keylistjob->exec( keyListPattern(), /*secretOnly=*/false, keys );
+ if ( !keys.empty() )
+ m_key = keys.back();
+ }
+ if ( m_keylistjob )
+ m_keylistjob->deleteLater(); // exec'ed jobs don't delete themselves
+ m_keylistjob = 0;
+ setRunning( false );
+}
+
+bool VerifyDetachedBodyPartMemento::canStartKeyListJob() const
+{
+ if ( !m_keylistjob )
+ return false;
+ const char * const fpr = m_vr.signature( 0 ).fingerprint();
+ return fpr && *fpr;
+}
+
+TQStringList VerifyDetachedBodyPartMemento::keyListPattern() const
+{
+ assert( canStartKeyListJob() );
+ return TQStringList( TQString::fromLatin1( m_vr.signature( 0 ).fingerprint() ) );
+}
+
+void VerifyDetachedBodyPartMemento::saveResult( const VerificationResult & vr )
+{
+ assert( m_job );
+ m_vr = vr;
+ setAuditLog( m_job->auditLogError(), m_job->auditLogAsHtml() );
+}
+
+void VerifyDetachedBodyPartMemento::slotResult( const VerificationResult & vr )
+{
+ saveResult( vr );
+ m_job = 0;
+ if ( canStartKeyListJob() && startKeyListJob() )
+ return;
+ if ( m_keylistjob )
+ m_keylistjob->deleteLater();
+ m_keylistjob = 0;
+ setRunning( false );
+ notify();
+}
+
+bool VerifyDetachedBodyPartMemento::startKeyListJob()
+{
+ assert( canStartKeyListJob() );
+ if ( const GpgME::Error err = m_keylistjob->start( keyListPattern() ) )
+ return false;
+ connect( m_keylistjob, TQT_SIGNAL(done()), this, TQT_SLOT(slotKeyListJobDone()) );
+ connect( m_keylistjob, TQT_SIGNAL(nextKey(const GpgME::Key&)),
+ this, TQT_SLOT(slotNextKey(const GpgME::Key&)) );
+ return true;
+}
+
+void VerifyDetachedBodyPartMemento::slotNextKey( const GpgME::Key & key )
+{
+ m_key = key;
+}
+
+void VerifyDetachedBodyPartMemento::slotKeyListJobDone()
+{
+ m_keylistjob = 0;
+ setRunning( false );
+ notify();
+}
+
+
+VerifyOpaqueBodyPartMemento::VerifyOpaqueBodyPartMemento( VerifyOpaqueJob * job,
+ KeyListJob * klj,
+ const TQByteArray & signature )
+ : CryptoBodyPartMemento(),
+ m_signature( signature ),
+ m_job( job ),
+ m_keylistjob( klj )
+{
+ assert( m_job );
+}
+
+VerifyOpaqueBodyPartMemento::~VerifyOpaqueBodyPartMemento() {
+ if ( m_job )
+ m_job->slotCancel();
+ if ( m_keylistjob )
+ m_keylistjob->slotCancel();
+}
+
+bool VerifyOpaqueBodyPartMemento::start() {
+ assert( m_job );
+ if ( const GpgME::Error err = m_job->start( m_signature ) ) {
+ m_vr = VerificationResult( err );
+ return false;
+ }
+ connect( m_job, TQT_SIGNAL(result(const GpgME::VerificationResult&,const TQByteArray&)),
+ this, TQT_SLOT(slotResult(const GpgME::VerificationResult&,const TQByteArray&)) );
+ setRunning( true );
+ return true;
+}
+
+void VerifyOpaqueBodyPartMemento::exec() {
+ assert( m_job );
+ setRunning( true );
+ TQByteArray plainText;
+ saveResult( m_job->exec( m_signature, plainText ), plainText );
+ m_job->deleteLater(); // exec'ed jobs don't delete themselves
+ m_job = 0;
+ if ( canStartKeyListJob() ) {
+ std::vector<GpgME::Key> keys;
+ m_keylistjob->exec( keyListPattern(), /*secretOnly=*/false, keys );
+ if ( !keys.empty() )
+ m_key = keys.back();
+ }
+ if ( m_keylistjob )
+ m_keylistjob->deleteLater(); // exec'ed jobs don't delete themselves
+ m_keylistjob = 0;
+ setRunning( false );
+}
+
+bool VerifyOpaqueBodyPartMemento::canStartKeyListJob() const
+{
+ if ( !m_keylistjob )
+ return false;
+ const char * const fpr = m_vr.signature( 0 ).fingerprint();
+ return fpr && *fpr;
+}
+
+TQStringList VerifyOpaqueBodyPartMemento::keyListPattern() const
+{
+ assert( canStartKeyListJob() );
+ return TQStringList( TQString::fromLatin1( m_vr.signature( 0 ).fingerprint() ) );
+}
+
+void VerifyOpaqueBodyPartMemento::saveResult( const VerificationResult & vr,
+ const TQByteArray & plainText )
+{
+ assert( m_job );
+ m_vr = vr;
+ m_plainText = plainText;
+ setAuditLog( m_job->auditLogError(), m_job->auditLogAsHtml() );
+}
+
+void VerifyOpaqueBodyPartMemento::slotResult( const VerificationResult & vr,
+ const TQByteArray & plainText )
+{
+ saveResult( vr, plainText );
+ m_job = 0;
+ if ( canStartKeyListJob() && startKeyListJob() )
+ return;
+ if ( m_keylistjob )
+ m_keylistjob->deleteLater();
+ m_keylistjob = 0;
+ setRunning( false );
+ notify();
+}
+
+bool VerifyOpaqueBodyPartMemento::startKeyListJob()
+{
+ assert( canStartKeyListJob() );
+ if ( const GpgME::Error err = m_keylistjob->start( keyListPattern() ) )
+ return false;
+ connect( m_keylistjob, TQT_SIGNAL(done()), this, TQT_SLOT(slotKeyListJobDone()) );
+ connect( m_keylistjob, TQT_SIGNAL(nextKey(const GpgME::Key&)),
+ this, TQT_SLOT(slotNextKey(const GpgME::Key&)) );
+ return true;
+}
+
+void VerifyOpaqueBodyPartMemento::slotNextKey( const GpgME::Key & key )
+{
+ m_key = key;
+}
+
+void VerifyOpaqueBodyPartMemento::slotKeyListJobDone()
+{
+ m_keylistjob = 0;
+ setRunning( false );
+ notify();
+}
+
+
+#include "objecttreeparser_p.moc"
diff --git a/kmail/objecttreeparser_p.h b/kmail/objecttreeparser_p.h
new file mode 100644
index 000000000..d70cd8c70
--- /dev/null
+++ b/kmail/objecttreeparser_p.h
@@ -0,0 +1,203 @@
+/* -*- mode: C++; c-file-style: "gnu" -*-
+ objecttreeparser_p.h
+
+ This file is part of KMail, the KDE mail client.
+ Copyright (c) 2009 Klarälvdalens Datakonsult AB
+
+ KMail 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.
+
+ KMail is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), 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
+ TQt. 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 _KMAIL_OBJECTTREEPARSER_P_H_
+#define _KMAIL_OBJECTTREEPARSER_P_H_
+
+#include <gpgmepp/verificationresult.h>
+#include <gpgmepp/decryptionresult.h>
+#include <gpgmepp/key.h>
+
+#include <tqobject.h>
+#include <tqcstring.h>
+#include <tqstring.h>
+#include <tqguardedptr.h>
+
+#include "isubject.h"
+#include "interfaces/bodypart.h"
+
+namespace Kleo {
+ class DecryptVerifyJob;
+ class VerifyDetachedJob;
+ class VerifyOpaqueJob;
+ class KeyListJob;
+}
+
+class TQStringList;
+
+namespace KMail {
+
+ class CryptoBodyPartMemento
+ : public TQObject,
+ public KMail::Interface::BodyPartMemento,
+ public KMail::ISubject
+ {
+ Q_OBJECT
+ public:
+ CryptoBodyPartMemento();
+ ~CryptoBodyPartMemento();
+
+ /* reimp */ Interface::Observer * asObserver() { return 0; }
+ /* reimp */ Interface::Observable * asObservable() { return this; }
+
+ bool isRunning() const { return m_running; }
+
+ const TQString & auditLogAsHtml() const { return m_auditLog; }
+ GpgME::Error auditLogError() const { return m_auditLogError; }
+
+ protected:
+ void setAuditLog( const GpgME::Error & err, const TQString & log );
+ void setRunning( bool running );
+
+ private:
+ bool m_running;
+ TQString m_auditLog;
+ GpgME::Error m_auditLogError;
+ };
+
+ class DecryptVerifyBodyPartMemento
+ : public CryptoBodyPartMemento
+ {
+ Q_OBJECT
+ public:
+ DecryptVerifyBodyPartMemento( Kleo::DecryptVerifyJob * job, const TQByteArray & cipherText );
+ ~DecryptVerifyBodyPartMemento();
+
+ bool start();
+ void exec();
+
+ const TQByteArray & plainText() const { return m_plainText; }
+ const GpgME::DecryptionResult & decryptResult() const { return m_dr; }
+ const GpgME::VerificationResult & verifyResult() const { return m_vr; }
+
+ private slots:
+ void slotResult( const GpgME::DecryptionResult & dr,
+ const GpgME::VerificationResult & vr,
+ const TQByteArray & plainText );
+
+ private:
+ void saveResult( const GpgME::DecryptionResult &,
+ const GpgME::VerificationResult &,
+ const TQByteArray & );
+ private:
+ // input:
+ const TQByteArray m_cipherText;
+ TQGuardedPtr<Kleo::DecryptVerifyJob> m_job;
+ // output:
+ GpgME::DecryptionResult m_dr;
+ GpgME::VerificationResult m_vr;
+ TQByteArray m_plainText;
+ };
+
+
+ class VerifyDetachedBodyPartMemento
+ : public CryptoBodyPartMemento
+ {
+ Q_OBJECT
+ public:
+ VerifyDetachedBodyPartMemento( Kleo::VerifyDetachedJob * job,
+ Kleo::KeyListJob * klj,
+ const TQByteArray & signature,
+ const TQByteArray & plainText );
+ ~VerifyDetachedBodyPartMemento();
+
+ bool start();
+ void exec();
+
+ const GpgME::VerificationResult & verifyResult() const { return m_vr; }
+ const GpgME::Key & signingKey() const { return m_key; }
+
+ private slots:
+ void slotResult( const GpgME::VerificationResult & vr );
+ void slotKeyListJobDone();
+ void slotNextKey( const GpgME::Key & );
+
+ private:
+ void saveResult( const GpgME::VerificationResult & );
+ bool canStartKeyListJob() const;
+ TQStringList keyListPattern() const;
+ bool startKeyListJob();
+ private:
+ // input:
+ const TQByteArray m_signature;
+ const TQByteArray m_plainText;
+ TQGuardedPtr<Kleo::VerifyDetachedJob> m_job;
+ TQGuardedPtr<Kleo::KeyListJob> m_keylistjob;
+ // output:
+ GpgME::VerificationResult m_vr;
+ GpgME::Key m_key;
+ };
+
+
+ class VerifyOpaqueBodyPartMemento
+ : public CryptoBodyPartMemento
+ {
+ Q_OBJECT
+ public:
+ VerifyOpaqueBodyPartMemento( Kleo::VerifyOpaqueJob * job,
+ Kleo::KeyListJob * klj,
+ const TQByteArray & signature );
+ ~VerifyOpaqueBodyPartMemento();
+
+ bool start();
+ void exec();
+
+ const TQByteArray & plainText() const { return m_plainText; }
+ const GpgME::VerificationResult & verifyResult() const { return m_vr; }
+ const GpgME::Key & signingKey() const { return m_key; }
+
+ private slots:
+ void slotResult( const GpgME::VerificationResult & vr,
+ const TQByteArray & plainText );
+ void slotKeyListJobDone();
+ void slotNextKey( const GpgME::Key & );
+
+ private:
+ void saveResult( const GpgME::VerificationResult &,
+ const TQByteArray & );
+ bool canStartKeyListJob() const;
+ TQStringList keyListPattern() const;
+ bool startKeyListJob();
+ private:
+ // input:
+ const TQByteArray m_signature;
+ TQGuardedPtr<Kleo::VerifyOpaqueJob> m_job;
+ TQGuardedPtr<Kleo::KeyListJob> m_keylistjob;
+ // output:
+ GpgME::VerificationResult m_vr;
+ TQByteArray m_plainText;
+ GpgME::Key m_key;
+ };
+
+
+} // namespace KMail
+
+#endif // _KMAIL_OBJECTTREEPARSER_H_
diff --git a/kmail/partNode.cpp b/kmail/partNode.cpp
index 80e0545bf..dbd5442ca 100644
--- a/kmail/partNode.cpp
+++ b/kmail/partNode.cpp
@@ -30,7 +30,10 @@
*/
#include <config.h>
+
#include "partNode.h"
+#include "kmreaderwin.h"
+
#include <klocale.h>
#include <kdebug.h>
#include "kmmimeparttree.h"
@@ -64,12 +67,14 @@ partNode::partNode()
mEncodedOk( false ),
mDeleteDwBodyPart( false ),
mMimePartTreeItem( 0 ),
- mBodyPartMemento( 0 )
+ mBodyPartMementoMap(),
+ mReader( 0 ),
+ mDisplayedEmbedded( false )
{
adjustDefaultType( this );
}
-partNode::partNode( DwBodyPart* dwPart, int explicitType, int explicitSubType,
+partNode::partNode( KMReaderWin * win, DwBodyPart* dwPart, int explicitType, int explicitSubType,
bool deleteDwBodyPart )
: mRoot( 0 ), mNext( 0 ), mChild( 0 ),
mWasProcessed( false ),
@@ -80,13 +85,15 @@ partNode::partNode( DwBodyPart* dwPart, int explicitType, int explicitSubType,
mEncodedOk( false ),
mDeleteDwBodyPart( deleteDwBodyPart ),
mMimePartTreeItem( 0 ),
- mBodyPartMemento( 0 )
+ mBodyPartMementoMap(),
+ mReader( win ),
+ mDisplayedEmbedded( false ),
+ mDisplayedHidden( false )
{
if ( explicitType != DwMime::kTypeUnknown ) {
mType = explicitType; // this happens e.g. for the Root Node
mSubType = explicitSubType; // representing the _whole_ message
} else {
-// kdDebug(5006) << "\n partNode::partNode() explicitType == DwMime::kTypeUnknown\n" << endl;
if(dwPart && dwPart->hasHeaders() && dwPart->Headers().HasContentType()) {
mType = (!dwPart->Headers().ContentType().Type())?DwMime::kTypeUnknown:dwPart->Headers().ContentType().Type();
mSubType = dwPart->Headers().ContentType().Subtype();
@@ -95,17 +102,9 @@ partNode::partNode( DwBodyPart* dwPart, int explicitType, int explicitSubType,
mSubType = DwMime::kSubtypeUnknown;
}
}
-#ifdef DEBUG
- {
- DwString type, subType;
- DwTypeEnumToStr( mType, type );
- DwSubtypeEnumToStr( mSubType, subType );
- kdDebug(5006) << "\npartNode::partNode() " << type.c_str() << "/" << subType.c_str() << "\n" << endl;
- }
-#endif
}
-partNode * partNode::fromMessage( const KMMessage * msg ) {
+partNode * partNode::fromMessage( const KMMessage * msg, KMReaderWin * win ) {
if ( !msg )
return 0;
@@ -124,11 +123,11 @@ partNode * partNode::fromMessage( const KMMessage * msg ) {
// as just another DwBodyPart...
DwBodyPart * mainBody = new DwBodyPart( *msg->getTopLevelPart() );
- partNode * root = new partNode( mainBody, mainType, mainSubType, true );
+ partNode * root = new partNode( win, mainBody, mainType, mainSubType, true );
root->buildObjectTree();
root->setFromAddress( msg->from() );
- root->dump();
+ //root->dump();
return root;
}
@@ -142,7 +141,9 @@ partNode::partNode( bool deleteDwBodyPart, DwBodyPart* dwPart )
mEncodedOk( false ),
mDeleteDwBodyPart( deleteDwBodyPart ),
mMimePartTreeItem( 0 ),
- mBodyPartMemento( 0 )
+ mBodyPartMementoMap(),
+ mReader( 0 ),
+ mDisplayedEmbedded( false )
{
if ( dwPart && dwPart->hasHeaders() && dwPart->Headers().HasContentType() ) {
mType = (!dwPart->Headers().ContentType().Type())?DwMime::kTypeUnknown:dwPart->Headers().ContentType().Type();
@@ -159,13 +160,16 @@ partNode::~partNode() {
mDwPart = 0;
delete mChild; mChild = 0;
delete mNext; mNext = 0;
- delete mBodyPartMemento; mBodyPartMemento = 0;
+ for ( std::map<TQCString,KMail::Interface::BodyPartMemento*>::const_iterator it = mBodyPartMementoMap.begin(), end = mBodyPartMementoMap.end() ; it != end ; ++it )
+ delete it->second;
+ mBodyPartMementoMap.clear();
}
#ifndef NDEBUG
void partNode::dump( int chars ) const {
- kdDebug(5006) << TQString().fill( ' ', chars ) << "+ "
- << typeString() << '/' << subTypeString() << endl;
+ kdDebug(5006) << nodeId() << " " << TQString().fill( ' ', chars ) << "+ "
+ << typeString() << '/' << subTypeString() << " embedded:" << mDisplayedEmbedded
+ << " address:" << this << endl;
if ( mChild )
mChild->dump( chars + 1 );
if ( mNext )
@@ -194,7 +198,7 @@ void partNode::buildObjectTree( bool processSiblings )
while( curNode && curNode->dwPart() ) {
//dive into multipart messages
while( DwMime::kTypeMultipart == curNode->type() ) {
- partNode * newNode = new partNode( curNode->dwPart()->Body().FirstBodyPart() );
+ partNode * newNode = new partNode( mReader, curNode->dwPart()->Body().FirstBodyPart() );
curNode->setFirstChild( newNode );
curNode = newNode;
}
@@ -210,7 +214,7 @@ void partNode::buildObjectTree( bool processSiblings )
return;
// store next node
if( curNode && curNode->dwPart() && curNode->dwPart()->Next() ) {
- partNode* nextNode = new partNode( curNode->dwPart()->Next() );
+ partNode* nextNode = new partNode( mReader, curNode->dwPart()->Next() );
curNode->setNext( nextNode );
curNode = nextNode;
} else
@@ -230,6 +234,13 @@ TQCString partNode::subTypeString() const {
return s.c_str();
}
+const partNode* partNode::topLevelParent() const {
+ const partNode *ret = this;
+ while ( ret->parentNode() )
+ ret = ret->parentNode();
+ return ret;
+}
+
int partNode::childCount() const {
int count = 0;
for ( partNode * child = firstChild() ; child ; child = child->nextSibling() )
@@ -237,6 +248,15 @@ int partNode::childCount() const {
return count;
}
+int partNode::totalChildCount() const {
+ int count = 0;
+ for ( partNode * child = firstChild() ; child ; child = child->nextSibling() ) {
+ ++count;
+ count += child->totalChildCount();
+ }
+ return count;
+}
+
TQString partNode::contentTypeParameter( const char * name ) const {
if ( !mDwPart || !mDwPart->hasHeaders() )
return TQString::null;
@@ -292,8 +312,6 @@ KMMsgEncryptionState partNode::overallEncryptionState() const
}
}
-//kdDebug(5006) << "\n\n KMMsgEncryptionState: " << myState << endl;
-
return myState;
}
@@ -335,11 +353,24 @@ KMMsgSignatureState partNode::overallSignatureState() const
}
}
-//kdDebug(5006) << "\n\n KMMsgSignatureState: " << myState << endl;
-
return myState;
}
+TQCString partNode::path() const
+{
+ if ( !parentNode() )
+ return ':';
+ const partNode * p = parentNode();
+
+ // count number of siblings with the same type as us:
+ int nth = 0;
+ for ( const partNode * c = p->firstChild() ; c != this ; c = c->nextSibling() )
+ if ( c->type() == type() && c->subType() == subType() )
+ ++nth;
+
+ return p->path() + TQCString().sprintf( ":%X/%X[%X]", type(), subType(), nth );
+}
+
int partNode::nodeId() const
{
@@ -392,13 +423,6 @@ int partNode::calcNodeIdOrFindNode( int &curId, const partNode* findNode, int fi
partNode* partNode::findType( int type, int subType, bool deep, bool wide )
{
-#ifndef NDEBUG
- DwString typeStr, subTypeStr;
- DwTypeEnumToStr( mType, typeStr );
- DwSubtypeEnumToStr( mSubType, subTypeStr );
- kdDebug(5006) << "partNode::findType() is looking at " << typeStr.c_str()
- << "/" << subTypeStr.c_str() << endl;
-#endif
if( (mType != DwMime::kTypeUnknown)
&& ( (type == DwMime::kTypeUnknown)
|| (type == mType) )
@@ -471,11 +495,11 @@ void partNode::fillMimePartTree( KMMimePartTreeItem* parentItem,
else
cntType = "text/plain";
if( cntDesc.isEmpty() )
- cntDesc = msgPart().contentDescription();
- if( cntDesc.isEmpty() )
cntDesc = msgPart().name().stripWhiteSpace();
if( cntDesc.isEmpty() )
cntDesc = msgPart().fileName();
+ if( cntDesc.isEmpty() )
+ cntDesc = msgPart().contentDescription();
if( cntDesc.isEmpty() ) {
if( mRoot && mRoot->mRoot )
cntDesc = i18n("internal part");
@@ -494,8 +518,6 @@ void partNode::fillMimePartTree( KMMimePartTreeItem* parentItem,
// remove linebreak+whitespace from folded Content-Description
cntDesc.replace( TQRegExp("\\n\\s*"), " " );
-kdDebug(5006) << " Inserting one item into MimePartTree" << endl;
-kdDebug(5006) << " Content-Type: " << cntType << endl;
if( parentItem )
mMimePartTreeItem = new KMMimePartTreeItem( parentItem,
this,
@@ -547,6 +569,13 @@ bool partNode::isAttachment() const
if ( !dwPart()->hasHeaders() )
return false;
DwHeaders& headers = dwPart()->Headers();
+ if ( headers.HasContentType() &&
+ headers.ContentType().Type() == DwMime::kTypeMessage &&
+ headers.ContentType().Subtype() == DwMime::kSubtypeRfc822 ) {
+ // Messages are always attachments. Normally message attachments created from KMail have a content
+ // disposition, but some mail clients omit that.
+ return true;
+ }
if( !headers.HasContentDisposition() )
return false;
return ( headers.ContentDisposition().DispositionType()
@@ -591,6 +620,47 @@ bool partNode::isFirstTextPart() const {
return false; // make comiler happy
}
+bool partNode::isToltecMessage() const
+{
+ if ( type() != DwMime::kTypeMultipart || subType() != DwMime::kSubtypeMixed )
+ return false;
+
+ if ( childCount() != 3 )
+ return false;
+
+ const DwField* library = dwPart()->Headers().FindField( "X-Library" );
+ if ( !library )
+ return false;
+
+ if ( !library->FieldBody() ||
+ TQString( library->FieldBody()->AsString().c_str() ) != TQString( "Toltec" ) )
+ return false;
+
+ const DwField* kolabType = dwPart()->Headers().FindField( "X-Kolab-Type" );
+ if ( !kolabType )
+ return false;
+
+ if ( !kolabType->FieldBody() ||
+ !TQString( kolabType->FieldBody()->AsString().c_str() ).startsWith( "application/x-vnd.kolab" ) )
+ return false;
+
+ return true;
+}
+
+bool partNode::isInEncapsulatedMessage() const
+{
+ const partNode * const topLevel = topLevelParent();
+ const partNode *cur = this;
+ while ( cur && cur != topLevel ) {
+ const bool parentIsMessage = cur->parentNode() &&
+ cur->parentNode()->msgPart().typeStr().lower() == "message";
+ if ( parentIsMessage && cur->parentNode() != topLevel )
+ return true;
+ cur = cur->parentNode();
+ }
+ return false;
+}
+
bool partNode::hasContentDispositionInline() const
{
if( !dwPart() )
@@ -610,3 +680,97 @@ const TQString& partNode::trueFromAddress() const
node = node->mRoot;
return node->mFromAddress;
}
+
+KMail::Interface::BodyPartMemento * partNode::bodyPartMemento( const TQCString & which ) const
+{
+ if ( const KMReaderWin * r = reader() )
+ return r->bodyPartMemento( this, which );
+ else
+ return internalBodyPartMemento( which );
+}
+
+KMail::Interface::BodyPartMemento * partNode::internalBodyPartMemento( const TQCString & which ) const
+{
+ assert( !reader() );
+
+ const std::map<TQCString,KMail::Interface::BodyPartMemento*>::const_iterator it = mBodyPartMementoMap.find( which.lower() );
+ return it != mBodyPartMementoMap.end() ? it->second : 0 ;
+}
+
+void partNode::setBodyPartMemento( const TQCString & which, KMail::Interface::BodyPartMemento * memento )
+{
+ if ( KMReaderWin * r = reader() )
+ r->setBodyPartMemento( this, which, memento );
+ else
+ internalSetBodyPartMemento( which, memento );
+}
+
+void partNode::internalSetBodyPartMemento( const TQCString & which, KMail::Interface::BodyPartMemento * memento )
+{
+ assert( !reader() );
+
+ const std::map<TQCString,KMail::Interface::BodyPartMemento*>::iterator it = mBodyPartMementoMap.lower_bound( which.lower() );
+ if ( it != mBodyPartMementoMap.end() && it->first == which.lower() ) {
+ delete it->second;
+ if ( memento ) {
+ it->second = memento;
+ }
+ else {
+ mBodyPartMementoMap.erase( it );
+ }
+ } else {
+ mBodyPartMementoMap.insert( it, std::make_pair( which.lower(), memento ) );
+ }
+}
+
+bool partNode::isDisplayedEmbedded() const
+{
+ return mDisplayedEmbedded;
+}
+
+void partNode::setDisplayedEmbedded( bool displayedEmbedded )
+{
+ mDisplayedEmbedded = displayedEmbedded;
+}
+
+bool partNode::isDisplayedHidden() const
+{
+ return mDisplayedHidden;
+}
+
+void partNode::setDisplayedHidden( bool displayedHidden )
+{
+ mDisplayedHidden = displayedHidden;
+}
+
+
+TQString partNode::asHREF( const TQString &place ) const
+{
+ return TQString( "attachment:%1?place=%2" ).arg( nodeId() ).arg( place );
+}
+
+partNode::AttachmentDisplayInfo partNode::attachmentDisplayInfo() const
+{
+ AttachmentDisplayInfo info;
+ info.icon = msgPart().iconName( KIcon::Small );
+ info.label = msgPart().name().stripWhiteSpace();
+ if ( info.label.isEmpty() )
+ info.label = msgPart().fileName();
+ if ( info.label.isEmpty() )
+ info.label = msgPart().contentDescription();
+ bool typeBlacklisted = msgPart().typeStr().lower() == "multipart";
+ if ( !typeBlacklisted && msgPart().typeStr().lower() == "application" ) {
+ typeBlacklisted = msgPart().subtypeStr() == "pgp-encrypted"
+ || msgPart().subtypeStr().lower() == "pgp-signature"
+ || msgPart().subtypeStr().lower() == "pkcs7-mime"
+ || msgPart().subtypeStr().lower() == "pkcs7-signature";
+ }
+ typeBlacklisted = typeBlacklisted || this == topLevelParent();
+ bool firstTextChildOfEncapsulatedMsg = msgPart().typeStr().lower() == "text" &&
+ msgPart().subtypeStr().lower() == "plain" &&
+ parentNode() &&
+ parentNode()->msgPart().typeStr().lower() == "message";
+ typeBlacklisted = typeBlacklisted || firstTextChildOfEncapsulatedMsg;
+ info.displayInHeader = !info.label.isEmpty() && !info.icon.isEmpty() && !typeBlacklisted;
+ return info;
+}
diff --git a/kmail/partNode.h b/kmail/partNode.h
index d53977035..ddc76aa62 100644
--- a/kmail/partNode.h
+++ b/kmail/partNode.h
@@ -45,9 +45,13 @@
#include <kio/global.h>
#include <kdebug.h>
+#include <map>
+
class KMMimePartTreeItem;
class KMMimePartTree;
+class KMReaderWin;
+
/*
===========================================================================
@@ -67,14 +71,22 @@ class partNode
int calcNodeIdOrFindNode( int& curId, const partNode* calcNode,
int findId, partNode** findNode );
-public:
- static partNode * fromMessage( const KMMessage * msg );
-
- partNode( DwBodyPart* dwPart,
+ partNode( KMReaderWin * win, DwBodyPart* dwPart,
int explicitType = DwMime::kTypeUnknown,
int explicitSubType = DwMime::kSubtypeUnknown,
bool deleteDwBodyPart = false );
+public:
+
+ struct AttachmentDisplayInfo
+ {
+ TQString label;
+ TQString icon;
+ bool displayInHeader;
+ };
+
+ static partNode * fromMessage( const KMMessage * msg, KMReaderWin * win=0 );
+
partNode( bool deleteDwBodyPart,
DwBodyPart* dwPart );
@@ -151,6 +163,11 @@ public:
return mSignatureState;
}
+ // path is a hierarchical path to this partNode. It is designed to
+ // be stable under decryption, where new child nodes are
+ // added. Treat it as an opaque string.
+ TQCString path() const;
+
int nodeId() const; // node ids start at 1 (this is the top level root node)
partNode* findId( int id ); // returns the node which has the given id (or 0, resp.)
@@ -202,7 +219,7 @@ public:
mMimePartTreeItem = item;
}
- KMMimePartTreeItem* mimePartTreeItem() {
+ KMMimePartTreeItem* mimePartTreeItem() const {
return mMimePartTreeItem;
}
@@ -217,23 +234,52 @@ public:
*/
bool isFirstTextPart() const;
+ bool isToltecMessage() const;
+
+ /**
+ * @return true if this node is a child or an encapsulated message
+ */
+ bool isInEncapsulatedMessage() const;
+
bool hasContentDispositionInline() const;
TQString contentTypeParameter( const char * name ) const;
const TQString& trueFromAddress() const;
+ const partNode * topLevelParent() const;
partNode * parentNode() const { return mRoot; }
partNode * nextSibling() const { return mNext; }
partNode * firstChild() const { return mChild; }
partNode * next( bool allowChildren=true ) const;
int childCount() const;
+ int totalChildCount() const;
bool processed() const { return mWasProcessed; }
- KMail::Interface::BodyPartMemento * bodyPartMemento() const { return mBodyPartMemento; };
- void setBodyPartMemento( KMail::Interface::BodyPartMemento * memento ) {
- mBodyPartMemento = memento;
- };
+ KMail::Interface::BodyPartMemento * bodyPartMemento( const TQCString & which ) const;
+ void setBodyPartMemento( const TQCString & which, KMail::Interface::BodyPartMemento * memento );
+
+ // A flag to remember if the node was embedded. This is useful for attachment nodes, the reader
+ // needs to know if they were displayed inline or not.
+ bool isDisplayedEmbedded() const;
+ void setDisplayedEmbedded( bool displayedEmbedded );
+
+ // Same as above, but this time determines if the node was hidden or not
+ bool isDisplayedHidden() const;
+ void setDisplayedHidden( bool displayedHidden );
+
+ // Get a href in the form attachment:<nodeId>?place=<place>, used by ObjectTreeParser and
+ // UrlHandlerManager.
+ TQString asHREF( const TQString &place ) const;
+
+ AttachmentDisplayInfo attachmentDisplayInfo() const;
+
+private:
+ KMReaderWin * reader() const {
+ return mReader ? mReader : mRoot ? mRoot->reader() : 0 ;
+ }
+ KMail::Interface::BodyPartMemento * internalBodyPartMemento( const TQCString & ) const;
+ void internalSetBodyPartMemento( const TQCString & which, KMail::Interface::BodyPartMemento * memento );
private:
partNode* mRoot;
@@ -253,7 +299,10 @@ private:
bool mEncodedOk;
bool mDeleteDwBodyPart;
KMMimePartTreeItem* mMimePartTreeItem;
- KMail::Interface::BodyPartMemento * mBodyPartMemento;
+ std::map<TQCString,KMail::Interface::BodyPartMemento*> mBodyPartMementoMap;
+ KMReaderWin * mReader;
+ bool mDisplayedEmbedded;
+ bool mDisplayedHidden;
};
#endif
diff --git a/kmail/partmetadata.h b/kmail/partmetadata.h
index 1bc93d81e..ee6f51d34 100644
--- a/kmail/partmetadata.h
+++ b/kmail/partmetadata.h
@@ -18,6 +18,7 @@
#define _KMAIL_PARTMETADATA_H_
#include <gpgmepp/verificationresult.h>
+#include <gpgmepp/context.h>
#include <kpgp.h>
#include <tqstring.h>
@@ -34,6 +35,7 @@ namespace KMail {
isGoodSignature( false ),
isEncrypted( false ),
isDecryptable( false ),
+ inProgress( false ),
technicalProblem( false ),
isEncapsulatedRfc822Message( false )
{
@@ -50,10 +52,12 @@ namespace KMail {
TQDateTime creationTime;
TQString decryptionError;
TQString auditLog;
+ GpgME::Error auditLogError;
bool isSigned : 1;
bool isGoodSignature : 1;
bool isEncrypted : 1;
bool isDecryptable : 1;
+ bool inProgress : 1;
bool technicalProblem : 1;
bool isEncapsulatedRfc822Message : 1;
};
diff --git a/kmail/partnodebodypart.cpp b/kmail/partnodebodypart.cpp
index 37e37353f..f9a56316b 100644
--- a/kmail/partnodebodypart.cpp
+++ b/kmail/partnodebodypart.cpp
@@ -82,11 +82,11 @@ bool KMail::PartNodeBodyPart::hasCompleteBody() const {
}
KMail::Interface::BodyPartMemento * KMail::PartNodeBodyPart::memento() const {
- return mPartNode.bodyPartMemento();
+ return mPartNode.bodyPartMemento( "__plugin__" );
}
void KMail::PartNodeBodyPart::setBodyPartMemento( Interface::BodyPartMemento * memento ) {
- mPartNode.setBodyPartMemento( memento );
+ mPartNode.setBodyPartMemento( "__plugin__", memento );
}
KMail::Interface::BodyPart::Display KMail::PartNodeBodyPart::defaultDisplay() const {
diff --git a/kmail/pics/Makefile.am b/kmail/pics/Makefile.am
index b1e1c368b..8c185ddb9 100644
--- a/kmail/pics/Makefile.am
+++ b/kmail/pics/Makefile.am
@@ -9,7 +9,7 @@ pics_DATA = kmmsgdel.png kmmsgnew.png kmmsgunseen.png kmmsgread.png \
kmmsgpartiallysigned.png kmmsgfullyencrypted.png \
kmmsgfullysigned.png kmmsgundefinedencrypted.png \
kmmsgundefinedsigned.png \
- kmmsgspam.png kmmsgham.png kmmsgattachment.png \
+ kmmsgspam.png kmmsgham.png kmmsgattachment.png kmmsginvitation.png \
kmwizard.png \
quotecollapse.png quoteexpand.png \
enterprise_bottom_left.png \
diff --git a/kmail/pics/kmmsginvitation.png b/kmail/pics/kmmsginvitation.png
new file mode 100644
index 000000000..82c9a67ba
--- /dev/null
+++ b/kmail/pics/kmmsginvitation.png
Binary files differ
diff --git a/kmail/profiles/profile-default-rc.desktop b/kmail/profiles/profile-default-rc.desktop
index 7a75c8bb5..b8ba7e96f 100644
--- a/kmail/profiles/profile-default-rc.desktop
+++ b/kmail/profiles/profile-default-rc.desktop
@@ -31,7 +31,6 @@ Name[id]=Standar
Name[is]=Sjálfgefið
Name[it]=Predefinito
Name[ja]=標準
-Name[ka]=ნაგულისხმევი
Name[kk]=Әдетті
Name[km]=លំនាំដើម
Name[lt]=Numatytasis
@@ -62,8 +61,7 @@ Name[tg]=Пешфарзӣ
Name[th]=ค่าปริยาย
Name[tr]=Öntanımlı
Name[uk]=Типовий
-Name[uz]=Andoza
-Name[uz@cyrillic]=Андоза
+Name[uz]=Андоза
Name[ven]=Zwi si zwavhudi
Name[vi]=Mặc định
Name[xh]=Engagqibekanga
@@ -99,7 +97,6 @@ Comment[hu]=Standard profil
Comment[is]=Venjulegt snið
Comment[it]=Profilo standard
Comment[ja]=標準プロファイル
-Comment[ka]=სტანდარტული პროფილი
Comment[kk]=Стандартты профилі
Comment[km]=ទម្រង់​ខ្នាត​គំរូ
Comment[lt]=Standartinis profilis
@@ -127,8 +124,7 @@ Comment[tg]=Профили оддӣ
Comment[th]=โปรไฟล์มาตรฐาน
Comment[tr]=Standart profil
Comment[uk]=Типовий профіль
-Comment[uz]=Andoza profili
-Comment[uz@cyrillic]=Андоза профили
+Comment[uz]=Андоза профили
Comment[ven]=Zwithu zwo doweleaho
Comment[vi]=Hồ sơ chuẩn
Comment[xh]=Imboniselo yabucala esezantsi
diff --git a/kmail/profiles/profile-high-contrast-rc.desktop b/kmail/profiles/profile-high-contrast-rc.desktop
index 8c5b7cee0..a744ff1f4 100644
--- a/kmail/profiles/profile-high-contrast-rc.desktop
+++ b/kmail/profiles/profile-high-contrast-rc.desktop
@@ -27,7 +27,6 @@ Name[hu]=Kontrasztos
Name[is]=Mikil birtuskil
Name[it]=Alto contrasto
Name[ja]=ハイコントラスト
-Name[ka]=მაღალი კონტრასტი
Name[kk]=Контрастығы жоғары
Name[km]=កម្រិត​ពណ៌​ខ្ពស់
Name[lt]=Didelis kontrastas
@@ -82,7 +81,6 @@ Comment[hu]=Nagyobb betűméretek látáscsökkent felhasználóknak
Comment[is]=Stærra letur fyrir notendur með slæma sjón
Comment[it]=Dimensioni più grandi dei caratteri per chi ha problemi di vista
Comment[ja]=視力障害者のために大きなフォントを使用します
-Comment[ka]=შრიფტის გაზრდილი ზომა მხედველობაშეზღუდული მომხმარებლებისთვის
Comment[kk]=Көру қабілеті нашарларға арналған ірі қаріпті көрініс
Comment[km]=បង្កើន​ទំហំពុម្ពអក្សរ ដើម្បី​បង្ក​លក្ខណៈ​ងាយស្រួល​ដល់​ជន​ពិការ​ភ្នែក
Comment[lt]=Padidinti šriftų dydžiai blogai matantiems naudotojams
diff --git a/kmail/profiles/profile-html-rc.desktop b/kmail/profiles/profile-html-rc.desktop
index e609c50d7..f9655c91b 100644
--- a/kmail/profiles/profile-html-rc.desktop
+++ b/kmail/profiles/profile-html-rc.desktop
@@ -21,7 +21,7 @@ Comment[et]=Standardprofiil HTML-i eelvaatlusega - pole nii turvaline!
Comment[eu]=HTML aurrebista gaituta duen profil estandarra - sekuritate gutxiago du
Comment[fa]=profile استاندارد با پیش‌نمایش زنگام فعال‌شده - با ایمنی کمتر!
Comment[fi]=Normaali profiili HTML-esikatselua käyttäville - vähemmän turvallinen.
-Comment[fr]=Profil standard avec l'aperçu HTML activé - Moins sécurisé !
+Comment[fr]=Profil standard avec l'aperçu HTML activé - Moins sécurisé !
Comment[fy]=Standertprofyl mei HTML-foarbyld aktivearre - minder feilich!
Comment[gl]=Perfil estándar con previsualización HTML activada - menos seguro!
Comment[hi]=एचटीएमएल पूर्वावलोकन के साथ मानक प्रोफ़ाइल सक्षम है - कम सुरक्षित!
@@ -30,7 +30,6 @@ Comment[hu]=Standard profil, HTML-előnézettel (kevésbé biztonságos)
Comment[is]=Staðlað snið með HTML forsýn - minna öryggi!
Comment[it]=Profilo standard con l'anteprima HTML abilitata - meno sicuro!
Comment[ja]=HTML プレビューを有効にした標準プロファイル - 安全度は下がります!
-Comment[ka]=სტანდარტული პროფილი HTML ესკიზით - ნაკლებად უსაფრთხო!
Comment[kk]=Стандартты, HTML көрінісі бар профилі - қауіпсізігі төмен!
Comment[km]=ទម្រង់​ខ្នាត​គំរូ​ដែល​អាច​មើល HTML ជាមុន - មិន​សូវ​មាន​សុវត្ថិភាព​ឡើយ !
Comment[lt]=Standartinis profilis su HTML peržiūra – mažiau saugus!
diff --git a/kmail/profiles/profile-purist-rc.desktop b/kmail/profiles/profile-purist-rc.desktop
index c77f2808c..fed413958 100644
--- a/kmail/profiles/profile-purist-rc.desktop
+++ b/kmail/profiles/profile-purist-rc.desktop
@@ -18,7 +18,6 @@ Name[hr]=Čistunski
Name[hu]=Egyszerűsített
Name[it]=Purista
Name[ja]=純正
-Name[ka]=პურისტი
Name[kk]=Пурист
Name[km]=បរិសុទ្ធ
Name[lt]=Itin paprastas
@@ -72,7 +71,6 @@ Comment[hu]=A legtöbb extra kikapcsolva, a KDE alapértelmezéseinek felhaszná
Comment[is]=Slökkt á flestum aukahlutum, notast við víðværar stillingar KDE
Comment[it]=La maggior parte delle funzioni sono disabilitate, vengono usate le impostazioni globali di KDE
Comment[ja]=ほとんどの機能を無効にし、KDE の全体設定を使用します
-Comment[ka]=უმეტესობა შესაძლებლობებისა ამორთულია, გამოიყენება KDE-ს ზოგადი პარამეტრები
Comment[kk]=Мүмкіндіктердің көбі, KDE жалпылары ғана қалдырып, өшірілген
Comment[km]=លក្ខណៈ​ពិសេស​ភាគ​ច្រើន​ត្រូវ​បាន​បិទ ដោយ​ប្រើ​តែ​ការ​កំណត់​សកល​របស់ KDE ប៉ុណ្ណោះ
Comment[lt]=Dauguma savybių išjungta, naudojami globalūs KDE nustatymai
@@ -83,7 +81,7 @@ Comment[nb]=De fleste funksjoner slått av, KDEs globale innstillinger er i bruk
Comment[nds]=Mehrste Funkschonen utmaakt, globaal KDE-Vörinstellen warrt bruukt
Comment[ne]=धेरै विशेषता बन्द गरिएका छन, केडीई विश्वव्यापी सेटिङ प्रयोग गरिएका छन्
Comment[nl]=Meeste mogelijkheden uitgezet, de globale KDE-instellingen worden gebruikt
-Comment[nn]=Dei fleste funksjonar er slått av, globale KDE-innstillingar vert bruka
+Comment[nn]=Dei fleste funksjonar er slått av, globale KDE-innstillingar vert brukt
Comment[pl]=Większość opcji wyłączona, używane są domyślne ustawienia KDE
Comment[pt]=A maioria das funcionalidades desligada, sendo usadas as opções globais do KDE
Comment[pt_BR]=Maioria dos recursos desligados, são usadas configurações globais do KDE
diff --git a/kmail/profiles/profile-secure-rc.desktop b/kmail/profiles/profile-secure-rc.desktop
index fbc14b915..3cfc3cf2c 100644
--- a/kmail/profiles/profile-secure-rc.desktop
+++ b/kmail/profiles/profile-secure-rc.desktop
@@ -26,7 +26,6 @@ Name[hu]=Maximális biztonság
Name[is]=Öruggast
Name[it]=Massima sicurezza
Name[ja]=最も安全
-Name[ka]=ყველაზე უსაფრთხო
Name[kk]=Ең қауіпсіз
Name[km]=សុវត្ថិភាព​បំផុត
Name[lt]=Saugiausias
@@ -52,8 +51,7 @@ Name[ta]=மிகவும் பாதுகாப்பான
Name[tg]=Аз ҳама бехавфнокаш
Name[tr]=En Güvenli
Name[uk]=Найбільш безпечний
-Name[uz]=Juda xavfsiz
-Name[uz@cyrillic]=Жуда хавфсиз
+Name[uz]=Жуда хавфсиз
Name[zh_CN]=最安全
Name[zh_TW]=最安全
Comment=Sets all necessary options to achieve maximum security
@@ -81,7 +79,6 @@ Comment[hu]=Az összes beállítás a legbiztonságosabb értékre állítva
Comment[is]=Setur allar stillingar þannig að öryggið sé mest
Comment[it]=Imposta tutte le opzioni necessario per ottenere la massima sicurezza
Comment[ja]=最大のセキュリティ確保のために必要なすべてのオプションを設定します
-Comment[ka]=აყენებს ყველა საჭირო ოპციას მაქსიმალური უსაფრთხოების მისაღწევად
Comment[kk]=Қауіпсіздігі мейілінше арттырып бапталғаны
Comment[km]=កំណត់​ជម្រើស​ចាំបាច់​ទាំងអស់ ដើម្បី​ទទួល​បាន​សុវត្ថិភាព​ខ្ពស់​បំផុត
Comment[lt]=Nustato visas būtinas maksimaliam saugumui parinktis
diff --git a/kmail/recipientseditor.cpp b/kmail/recipientseditor.cpp
index 5ca2d7355..fe7b85ca9 100644
--- a/kmail/recipientseditor.cpp
+++ b/kmail/recipientseditor.cpp
@@ -159,6 +159,8 @@ RecipientLine::RecipientLine( TQWidget *parent )
TQToolTip::add( mCombo, i18n("Select type of recipient") );
mEdit = new RecipientLineEdit( this );
+ TQToolTip::add( mEdit,
+ i18n( "Set the list of email addresses to receive this message" ) );
topLayout->addWidget( mEdit );
connect( mEdit, TQT_SIGNAL( returnPressed() ), TQT_SLOT( slotReturnPressed() ) );
connect( mEdit, TQT_SIGNAL( deleteMe() ), TQT_SLOT( slotPropagateDeletion() ) );
@@ -891,7 +893,8 @@ void RecipientsEditor::saveDistributionList()
{
DistributionListDialog *dlg = new DistributionListDialog( this );
dlg->setRecipients( mRecipientsView->recipients() );
- dlg->show();
+ dlg->exec();
+ delete dlg;
}
Recipient::List RecipientsEditor::recipients() const
diff --git a/kmail/recipientspicker.cpp b/kmail/recipientspicker.cpp
index 839898cbf..c1d2b3aed 100644
--- a/kmail/recipientspicker.cpp
+++ b/kmail/recipientspicker.cpp
@@ -772,7 +772,7 @@ void RecipientsPicker::pick( Recipient::Type type )
kdDebug() << "RecipientsPicker::pick " << int( type ) << endl;
int count = 0;
- TQListViewItemIterator it( mRecipientList ,
+ TQListViewItemIterator it( mRecipientList ,
TQListViewItemIterator::Visible | TQListViewItemIterator::Selected );
for ( ; it.current(); ++it )
++count;
@@ -787,7 +787,7 @@ void RecipientsPicker::pick( Recipient::Type type )
return;
}
- it = TQListViewItemIterator( mRecipientList ,
+ it = TQListViewItemIterator( mRecipientList ,
TQListViewItemIterator::Visible | TQListViewItemIterator::Selected );
for ( ; it.current(); ++it ) {
RecipientViewItem *item = static_cast<RecipientViewItem *>( it.current() );
@@ -855,7 +855,7 @@ void RecipientsPicker::slotSearchLDAP()
void RecipientsPicker::ldapSearchResult()
{
- TQStringList emails = TQStringList::split(',', mLdapSearchDialog->selectedEMails() );
+ TQStringList emails = KPIM::splitEmailAddrList( mLdapSearchDialog->selectedEMails() );
TQStringList::iterator it( emails.begin() );
TQStringList::iterator end( emails.end() );
for ( ; it != end; ++it ){
diff --git a/kmail/redirectdialog.cpp b/kmail/redirectdialog.cpp
index 150e6a5d5..bf8fe51ce 100644
--- a/kmail/redirectdialog.cpp
+++ b/kmail/redirectdialog.cpp
@@ -76,14 +76,23 @@ RedirectDialog::RedirectDialog( TQWidget *parent, const char *name,
connect( mBtnTo, TQT_SIGNAL(clicked()), TQT_SLOT(slotAddrBook()) );
+ connect( mEditTo, TQT_SIGNAL( textChanged ( const TQString & ) ), TQT_SLOT( slotEmailChanged( const TQString & ) ) );
mLabelTo->setBuddy( mBtnTo );
mEditTo->setFocus();
setButtonGuiItem( User1, KGuiItem( i18n("&Send Now"), "mail_send" ) );
setButtonGuiItem( User2, KGuiItem( i18n("Send &Later"), "queue" ) );
+ enableButton( User1, false );
+ enableButton( User2, false );
}
+void RedirectDialog::slotEmailChanged( const TQString & text )
+{
+ enableButton( User1, !text.isEmpty() );
+ enableButton( User2, !text.isEmpty() );
+}
+
//-----------------------------------------------------------------------------
void RedirectDialog::slotUser1()
{
diff --git a/kmail/redirectdialog.h b/kmail/redirectdialog.h
index a89714a04..9be9f272e 100644
--- a/kmail/redirectdialog.h
+++ b/kmail/redirectdialog.h
@@ -78,7 +78,7 @@ namespace KMail {
void slotUser1();
void slotUser2();
-
+ void slotEmailChanged( const TQString & );
private:
TQLabel *mLabelTo;
KMLineEdit *mEditTo;
diff --git a/kmail/searchwindow.cpp b/kmail/searchwindow.cpp
index 81d64167f..b32dd96e0 100644
--- a/kmail/searchwindow.cpp
+++ b/kmail/searchwindow.cpp
@@ -181,7 +181,6 @@ SearchWindow::SearchWindow(KMMainWidget* w, const char* name,
} else {
mChkbxAllFolders->setChecked(true);
}
- mFolder = searchFolder;
}
mPatternEdit->setSearchPattern( mSearchPattern );
TQObjectList *list = mPatternEdit->queryList( 0, "mRuleField" );
@@ -237,13 +236,15 @@ SearchWindow::SearchWindow(KMMainWidget* w, const char* name,
mLbxMatches->setDragEnabled( true );
- connect(mLbxMatches, TQT_SIGNAL(doubleClicked(TQListViewItem *)),
- this, TQT_SLOT(slotShowMsg(TQListViewItem *)));
- connect(mLbxMatches, TQT_SIGNAL(currentChanged(TQListViewItem *)),
- this, TQT_SLOT(slotCurrentChanged(TQListViewItem *)));
- connect( mLbxMatches, TQT_SIGNAL( contextMenuRequested( TQListViewItem*, const TQPoint &, int )),
- this, TQT_SLOT( slotContextMenuRequested( TQListViewItem*, const TQPoint &, int )));
- vbl->addWidget(mLbxMatches);
+ connect( mLbxMatches, TQT_SIGNAL(clicked(TQListViewItem *)),
+ this, TQT_SLOT(slotShowMsg(TQListViewItem *)) );
+ connect( mLbxMatches, TQT_SIGNAL(doubleClicked(TQListViewItem *)),
+ this, TQT_SLOT(slotViewMsg(TQListViewItem *)) );
+ connect( mLbxMatches, TQT_SIGNAL(currentChanged(TQListViewItem *)),
+ this, TQT_SLOT(slotCurrentChanged(TQListViewItem *)) );
+ connect( mLbxMatches, TQT_SIGNAL(contextMenuRequested(TQListViewItem *,const TQPoint &,int)),
+ this, TQT_SLOT(slotContextMenuRequested(TQListViewItem *,const TQPoint &,int)) );
+ vbl->addWidget( mLbxMatches );
TQHBoxLayout *hbl2 = new TQHBoxLayout( vbl, spacingHint(), "kmfs_hbl2" );
mSearchFolderLbl = new TQLabel(i18n("Search folder &name:"), searchWidget);
@@ -269,7 +270,7 @@ SearchWindow::SearchWindow(KMMainWidget* w, const char* name,
mSearchResultOpenBtn->setEnabled(false);
hbl2->addWidget(mSearchResultOpenBtn);
connect( mSearchResultOpenBtn, TQT_SIGNAL( clicked() ),
- this, TQT_SLOT( slotShowSelectedMsg() ));
+ this, TQT_SLOT( slotViewSelectedMsg() ));
mStatusBar = new KStatusBar(searchWidget);
mStatusBar->insertFixedItem(i18n("AMiddleLengthText..."), 0, true);
mStatusBar->changeItem(i18n("Ready."), 0);
@@ -472,6 +473,9 @@ void SearchWindow::slotSearch()
mFetchingInProgress = 0;
mSearchFolderOpenBtn->setEnabled(true);
+ if ( mSearchFolderEdt->text().isEmpty() ) {
+ mSearchFolderEdt->setText( i18n("Last Search") );
+ }
mBtnSearch->setEnabled(false);
mBtnStop->setEnabled(true);
@@ -486,8 +490,6 @@ void SearchWindow::slotSearch()
// create one.
if (!mFolder) {
KMFolderMgr *mgr = kmkernel->searchFolderMgr();
- if (mSearchFolderEdt->text().isEmpty())
- mSearchFolderEdt->setText(i18n("Last Search"));
TQString baseName = mSearchFolderEdt->text();
TQString fullName = baseName;
int count = 0;
@@ -630,12 +632,12 @@ void SearchWindow::closeEvent(TQCloseEvent *e)
//-----------------------------------------------------------------------------
void SearchWindow::scheduleRename( const TQString &s)
{
- if (!s.isEmpty() && s != i18n("Last Search")) {
+ if (!s.isEmpty() ) {
mRenameTimer.start(250, true);
mSearchFolderOpenBtn->setEnabled(false);
} else {
mRenameTimer.stop();
- mSearchFolderOpenBtn->setEnabled(true);
+ mSearchFolderOpenBtn->setEnabled(!s.isEmpty());
}
}
@@ -656,11 +658,13 @@ void SearchWindow::renameSearchFolder()
++i;
}
}
- mSearchFolderOpenBtn->setEnabled(true);
+ if ( mFolder )
+ mSearchFolderOpenBtn->setEnabled(true);
}
void SearchWindow::openSearchFolder()
{
+ Q_ASSERT( mFolder );
renameSearchFolder();
mKMMainWidget->slotSelectFolder( mFolder->folder() );
slotClose();
@@ -680,32 +684,51 @@ void SearchWindow::folderInvalidated(KMFolder *folder)
}
//-----------------------------------------------------------------------------
-bool SearchWindow::slotShowMsg(TQListViewItem *item)
+KMMessage *SearchWindow::indexToMessage( TQListViewItem *item )
{
- if(!item)
- return false;
+ if( !item ) {
+ return 0;
+ }
- KMFolder* folder;
- int msgIndex;
- KMMsgDict::instance()->getLocation(item->text(MSGID_COLUMN).toUInt(),
- &folder, &msgIndex);
+ KMFolder *folder;
+ int msgIndex;
+ KMMsgDict::instance()->getLocation( item->text( MSGID_COLUMN ).toUInt(),
+ &folder, &msgIndex );
- if (!folder || msgIndex < 0)
- return false;
+ if ( !folder || msgIndex < 0 ) {
+ return 0;
+ }
- mKMMainWidget->slotSelectFolder(folder);
- KMMessage* message = folder->getMsg(msgIndex);
- if (!message)
- return false;
+ mKMMainWidget->slotSelectFolder( folder );
+ return folder->getMsg( msgIndex );
+}
- mKMMainWidget->slotSelectMessage(message);
+//-----------------------------------------------------------------------------
+bool SearchWindow::slotShowMsg( TQListViewItem *item )
+{
+ KMMessage *message = indexToMessage( item );
+ if ( message ) {
+ mKMMainWidget->slotSelectMessage( message );
return true;
+ }
+ return false;
}
//-----------------------------------------------------------------------------
-void SearchWindow::slotShowSelectedMsg()
+void SearchWindow::slotViewSelectedMsg()
{
- slotShowMsg(mLbxMatches->currentItem());
+ slotViewMsg( mLbxMatches->currentItem() );
+}
+
+//-----------------------------------------------------------------------------
+bool SearchWindow::slotViewMsg( TQListViewItem *item )
+{
+ KMMessage *message = indexToMessage( item );
+ if ( message ) {
+ mKMMainWidget->slotMsgActivated( message );
+ return true;
+ }
+ return false;
}
//-----------------------------------------------------------------------------
@@ -720,8 +743,8 @@ void SearchWindow::enableGUI()
KMSearch const *search = (mFolder) ? (mFolder->search()) : 0;
bool searching = (search) ? (search->running()) : false;
actionButton(KDialogBase::Close)->setEnabled(!searching);
- mCbxFolders->setEnabled(!searching);
- mChkSubFolders->setEnabled(!searching);
+ mCbxFolders->setEnabled(!searching && !mChkbxAllFolders->isChecked());
+ mChkSubFolders->setEnabled(!searching && !mChkbxAllFolders->isChecked());
mChkbxAllFolders->setEnabled(!searching);
mChkbxSpecificFolders->setEnabled(!searching);
mPatternEdit->setEnabled(!searching);
diff --git a/kmail/searchwindow.h b/kmail/searchwindow.h
index c94b263e5..836553ae8 100644
--- a/kmail/searchwindow.h
+++ b/kmail/searchwindow.h
@@ -113,9 +113,10 @@ protected slots:
void renameSearchFolder();
void openSearchFolder();
void folderInvalidated(KMFolder *);
- virtual bool slotShowMsg(TQListViewItem *);
- void slotShowSelectedMsg();
- void slotCurrentChanged(TQListViewItem *);
+ virtual bool slotShowMsg( TQListViewItem * );
+ void slotViewSelectedMsg();
+ virtual bool slotViewMsg( TQListViewItem * );
+ void slotCurrentChanged( TQListViewItem * );
virtual void updateContextMenuActions();
virtual void slotContextMenuRequested( TQListViewItem*, const TQPoint &, int );
virtual void copySelectedToFolder( int menuId );
@@ -189,6 +190,9 @@ protected:
KMSearchPattern *mSearchPattern;
static const int MSGID_COLUMN;
+
+private:
+ KMMessage *indexToMessage( TQListViewItem *item );
};
} // namespace KMail
diff --git a/kmail/sievedebugdialog.cpp b/kmail/sievedebugdialog.cpp
index 5ab305e83..bc5d2cca0 100644
--- a/kmail/sievedebugdialog.cpp
+++ b/kmail/sievedebugdialog.cpp
@@ -219,6 +219,32 @@ SieveDebugDialog::~SieveDebugDialog()
kdDebug( 5006 ) << k_funcinfo << endl;
}
+static KURL urlFromAccount( const KMail::ImapAccountBase * a ) {
+ const SieveConfig sieve = a->sieveConfig();
+ if ( !sieve.managesieveSupported() )
+ return KURL();
+
+ KURL u;
+ if ( sieve.reuseConfig() ) {
+ // assemble Sieve url from the settings of the account:
+ u.setProtocol( "sieve" );
+ u.setHost( a->host() );
+ u.setUser( a->login() );
+ u.setPass( a->passwd() );
+ u.setPort( sieve.port() );
+
+ // Translate IMAP LOGIN to PLAIN:
+ u.addQueryItem( "x-mech", a->auth() == "*" ? "PLAIN" : a->auth() );
+ if ( !a->useSSL() && !a->useTLS() )
+ u.addQueryItem( "x-allow-unencrypted", "true" );
+ } else {
+ u = sieve.alternateURL();
+ if ( u.protocol().lower() == "sieve" && !a->useSSL() && !a->useTLS() && u.queryItem("x-allow-unencrypted").isEmpty() )
+ u.addQueryItem( "x-allow-unencrypted", "true" );
+ }
+ return u;
+}
+
void SieveDebugDialog::slotDiagNextAccount()
{
if ( mAccountList.isEmpty() )
@@ -233,26 +259,12 @@ void SieveDebugDialog::slotDiagNextAccount()
if ( mAccountBase )
{
// Detect URL for this IMAP account
- SieveConfig sieve = mAccountBase->sieveConfig();
- if ( !sieve.managesieveSupported() )
+ const KURL url = urlFromAccount( mAccountBase );
+ if ( !url.isValid() )
{
mEdit->append( i18n( "(Account does not support Sieve)\n\n" ) );
} else {
- if ( sieve.reuseConfig() )
- {
- // assemble Sieve url from the settings of the account:
- mUrl.setProtocol( "sieve" );
- mUrl.setHost( mAccountBase->host() );
- mUrl.setUser( mAccountBase->login() );
- mUrl.setPass( mAccountBase->passwd() );
- mUrl.setPort( sieve.port() );
-
- // Translate IMAP LOGIN to PLAIN:
- mUrl.setQuery( "x-mech=" + ( mAccountBase->auth() == "*" ? "PLAIN" : mAccountBase->auth() ) );
- } else {
- sieve.alternateURL();
- mUrl.setFileName( sieve.vacationFileName() );
- }
+ mUrl = url;
mSieveJob = SieveJob::list( mUrl );
@@ -284,22 +296,9 @@ void SieveDebugDialog::slotDiagNextScript()
mScriptList.pop_front();
mEdit->append( i18n( "Contents of script '%1':\n" ).arg( scriptFile ) );
- SieveConfig sieve = mAccountBase->sieveConfig();
- if ( sieve.reuseConfig() )
- {
- // assemble Sieve url from the settings of the account:
- mUrl.setProtocol( "sieve" );
- mUrl.setHost( mAccountBase->host() );
- mUrl.setUser( mAccountBase->login() );
- mUrl.setPass( mAccountBase->passwd() );
- mUrl.setPort( sieve.port() );
- // Translate IMAP LOGIN to PLAIN
- mUrl.setQuery( "x-mech=" + ( mAccountBase->auth() == "*" ? "PLAIN" : mAccountBase->auth() ) );
- mUrl.setFileName( scriptFile );
- } else {
- sieve.alternateURL();
- mUrl.setFileName( scriptFile );
- }
+
+ mUrl = urlFromAccount( mAccountBase );
+ mUrl.setFileName( scriptFile );
mSieveJob = SieveJob::get( mUrl );
diff --git a/kmail/sievejob.cpp b/kmail/sievejob.cpp
index ade08b1da..0ce073d93 100644
--- a/kmail/sievejob.cpp
+++ b/kmail/sievejob.cpp
@@ -275,6 +275,12 @@ namespace KMail {
return new SieveJob( url, TQString::null, commands );
}
+ SieveJob * SieveJob::desactivate( const KURL & url ) {
+ TQValueStack<Command> commands;
+ commands.push( Deactivate );
+ return new SieveJob( url, TQString(), commands );
+ }
+
SieveJob * SieveJob::activate( const KURL & url ) {
TQValueStack<Command> commands;
commands.push( Activate );
diff --git a/kmail/sievejob.h b/kmail/sievejob.h
index ef9f4a504..ed8fb5d8c 100644
--- a/kmail/sievejob.h
+++ b/kmail/sievejob.h
@@ -68,6 +68,8 @@ namespace KMail {
static SieveJob * activate( const KURL & url );
+ static SieveJob * desactivate( const KURL & url );
+
void kill( bool quiet=true );
const TQStringList & sieveCapabilities() const {
diff --git a/kmail/simplefoldertree.h b/kmail/simplefoldertree.h
new file mode 100644
index 000000000..6bfc3eb33
--- /dev/null
+++ b/kmail/simplefoldertree.h
@@ -0,0 +1,249 @@
+/*
+ Copyright (c) 2007 Volker Krause <vkrause@kde.org>
+ Copyright (c) 2003 Andreas Gungl <a.gungl@gmx.de>
+ Copyright (c) Stefan Taferner <taferner@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 KMAIL_SIMPLEFOLDERTREE_H
+#define KMAIL_SIMPLEFOLDERTREE_H
+
+#include "kmfolder.h"
+#include "kmfoldertree.h"
+#include "treebase.h"
+
+#include <kdebug.h>
+#include <klistview.h>
+#include <kpopupmenu.h>
+#include <kiconloader.h>
+
+class KMFolder;
+class KMFolderTree;
+
+namespace KMail {
+
+static int recurseFilter( TQListViewItem * item, const TQString& filter, int column )
+{
+ if ( item == 0 )
+ return 0;
+
+ TQListViewItem * child;
+ child = item->firstChild();
+
+ int enabled = 0;
+ while ( child ) {
+ enabled += recurseFilter( child, filter, column );
+ child = child->nextSibling();
+ }
+
+ if ( filter.length() == 0 ||
+ item->text( column ).find( filter, 0, false ) >= 0 ) {
+ item->setVisible( true );
+ ++enabled;
+ }
+ else {
+ item->setVisible( !!enabled );
+ item->setEnabled( false );
+ }
+
+ return enabled;
+}
+
+class TreeItemBase
+{
+ public :
+ TreeItemBase()
+ : mFolder( 0 )
+ {
+ kdDebug(5006) << k_funcinfo << endl;
+ }
+ virtual ~TreeItemBase() { }
+
+ void setFolder( KMFolder * folder ) { mFolder = folder; };
+ const KMFolder * folder() { return mFolder; };
+
+ // Set the flag which determines if this is an alternate row
+ void setAlternate ( bool alternate ) {
+ mAlternate = alternate;
+ }
+
+ private:
+ KMFolder * mFolder;
+ bool mAlternate;
+
+};
+
+template <class T> class SimpleFolderTreeItem : public T, public TreeItemBase
+{
+ public:
+ SimpleFolderTreeItem( TQListView * listView ) :
+ T( listView ), TreeItemBase()
+ {
+ kdDebug(5006) << k_funcinfo << endl;
+ }
+ SimpleFolderTreeItem( TQListView * listView, TQListViewItem * afterListViewItem ) :
+ T( listView, afterListViewItem ) , TreeItemBase()
+ {
+ kdDebug(5006) << k_funcinfo << endl;
+ }
+ SimpleFolderTreeItem( TQListViewItem * listViewItem ) : T( listViewItem ) , TreeItemBase()
+ {
+ kdDebug(5006) << k_funcinfo << endl;
+ }
+
+ SimpleFolderTreeItem( TQListViewItem * listViewItem, TQListViewItem * afterListViewItem ) :
+ T( listViewItem, afterListViewItem ) , TreeItemBase()
+ {
+ kdDebug(5006) << k_funcinfo << endl;
+ }
+
+};
+
+template <> class SimpleFolderTreeItem<TQCheckListItem> : public TQCheckListItem, public TreeItemBase
+{
+ public:
+ SimpleFolderTreeItem( TQListView * listView ) :
+ TQCheckListItem( listView, TQString(), CheckBox ), TreeItemBase() {}
+ SimpleFolderTreeItem( TQListView * listView, TQListViewItem * afterListViewItem ) :
+ TQCheckListItem( listView, afterListViewItem, TQString(), CheckBox ), TreeItemBase() {}
+ SimpleFolderTreeItem( TQListViewItem * listViewItem ) :
+ TQCheckListItem( listViewItem, TQString(), CheckBox ) {}
+ SimpleFolderTreeItem( TQListViewItem * listViewItem, TQListViewItem * afterListViewItem ) :
+ TQCheckListItem( listViewItem, afterListViewItem, TQString(), CheckBox ) {}
+
+};
+
+
+template <class T> class SimpleFolderTreeBase : public TreeBase
+{
+
+ public:
+
+
+ inline SimpleFolderTreeBase( TQWidget * parent, KMFolderTree *folderTree,
+ const TQString &preSelection, bool mustBeReadWrite )
+ : TreeBase( parent, folderTree, preSelection, mustBeReadWrite )
+ {
+ assert( folderTree );
+ setFolderColumn( addColumn( i18n( "Folder" ) ) );
+ setPathColumn( addColumn( i18n( "Path" ) ) );
+
+ setRootIsDecorated( true );
+ setSorting( -1 );
+
+ reload( mustBeReadWrite, true, true, preSelection );
+
+ }
+
+ virtual SimpleFolderTreeItem<T>* createItem( TQListView * parent )
+ {
+ return new SimpleFolderTreeItem<T>( parent );
+ }
+
+ virtual SimpleFolderTreeItem<T>* createItem( TQListView * parent, TQListViewItem* afterListViewItem )
+ {
+ return new SimpleFolderTreeItem<T>( parent, afterListViewItem );
+ }
+
+ virtual SimpleFolderTreeItem<T>* createItem( TQListViewItem * parent, TQListViewItem* afterListViewItem )
+ {
+ return new SimpleFolderTreeItem<T>( parent, afterListViewItem );
+ }
+
+ virtual SimpleFolderTreeItem<T>* createItem( TQListViewItem * parent )
+ {
+ return new SimpleFolderTreeItem<T>( parent );
+ }
+
+ inline void keyPressEvent( TQKeyEvent *e )
+ {
+ const char ascii = e->ascii();
+ if ( ascii == 8 || ascii == 127 ) {
+ if ( mFilter.length() > 0 ) {
+ mFilter.truncate( mFilter.length()-1 );
+ applyFilter( mFilter );
+ }
+ } else if ( !e->text().isEmpty() && e->text().length() == 1 && e->text().at( 0 ).isPrint() ) {
+ applyFilter( mFilter + e->text() );
+ } else {
+ KListView::keyPressEvent( e );
+ }
+ }
+
+ void applyFilter( const TQString& filter )
+ {
+ kdDebug(5006) << k_funcinfo << filter << endl ;
+ // Reset all items to visible, enabled, and open
+ TQListViewItemIterator clean( this );
+ while ( clean.current() ) {
+ TQListViewItem * item = clean.current();
+ item->setEnabled( true );
+ item->setVisible( true );
+ item->setOpen( true );
+ ++clean;
+ }
+
+ mFilter = filter;
+
+ if ( filter.isEmpty() ) {
+ setColumnText( pathColumn(), i18n("Path") );
+ return;
+ }
+
+ // Set the visibility and enabled status of each list item.
+ // The recursive algorithm is necessary because visiblity
+ // changes are automatically applied to child nodes by TQt.
+ TQListViewItemIterator it( this );
+ while ( it.current() ) {
+ TQListViewItem * item = it.current();
+ if ( item->depth() <= 0 )
+ recurseFilter( item, filter, pathColumn() );
+ ++it;
+ }
+
+ // Recolor the rows appropriately
+ recolorRows();
+
+ // Iterate through the list to find the first selectable item
+ TQListViewItemIterator first ( this );
+ while ( first.current() ) {
+ SimpleFolderTreeItem<T> * item = static_cast< SimpleFolderTreeItem<T> * >( first.current() );
+
+ if ( item->isVisible() && item->isSelectable() ) {
+ setSelected( item, true );
+ ensureItemVisible( item );
+ break;
+ }
+
+ ++first;
+ }
+
+ // Display and save the current filter
+ if ( filter.length() > 0 )
+ setColumnText( pathColumn(), i18n("Path") + " ( " + filter + " )" );
+ else
+ setColumnText( pathColumn(), i18n("Path") );
+
+ mFilter = filter;
+ }
+
+};
+
+typedef SimpleFolderTreeBase<KListViewItem> SimpleFolderTree;
+
+}
+
+#endif
diff --git a/kmail/simplestringlisteditor.cpp b/kmail/simplestringlisteditor.cpp
index 8d71e2215..4be67e6e4 100644
--- a/kmail/simplestringlisteditor.cpp
+++ b/kmail/simplestringlisteditor.cpp
@@ -166,6 +166,15 @@ TQStringList SimpleStringListEditor::stringList() const {
return result;
}
+bool SimpleStringListEditor::containsString( const TQString & str ) {
+ for ( TQListBoxItem * item = mListBox->firstItem() ;
+ item ; item = item->next() ) {
+ if ( item->text() == str )
+ return true;
+ }
+ return false;
+}
+
void SimpleStringListEditor::setButtonText( ButtonCode button,
const TQString & text ) {
switch ( button ) {
@@ -207,9 +216,10 @@ void SimpleStringListEditor::slotAdd() {
&ok, this );
// let the user verify the string before adding
emit aboutToAdd( newEntry );
- if ( ok && !newEntry.isEmpty() )
- mListBox->insertItem( newEntry );
- emit changed();
+ if ( ok && !newEntry.isEmpty() && !containsString( newEntry )) {
+ mListBox->insertItem( newEntry );
+ emit changed();
+ }
}
void SimpleStringListEditor::slotRemove() {
diff --git a/kmail/simplestringlisteditor.h b/kmail/simplestringlisteditor.h
index 47c6f6c9a..115a9a05e 100644
--- a/kmail/simplestringlisteditor.h
+++ b/kmail/simplestringlisteditor.h
@@ -91,6 +91,7 @@ protected slots:
void slotSelectionChanged();
protected:
+ bool containsString( const TQString & str );
TQListBox *mListBox;
TQPushButton *mAddButton;
TQPushButton *mRemoveButton;
diff --git a/kmail/snippetdlg.cpp b/kmail/snippetdlg.cpp
index 61c75db88..93478d13f 100644
--- a/kmail/snippetdlg.cpp
+++ b/kmail/snippetdlg.cpp
@@ -1,6 +1,6 @@
/***************************************************************************
* snippet feature from kdevelop/plugins/snippet/ *
- * *
+ * *
* Copyright (C) 2007 by Robert Gruber *
* rgruber@users.sourceforge.net *
* *
@@ -14,6 +14,7 @@
#include "snippetdlg.h"
#include <kdialog.h>
+#include <klineedit.h>
#include <klocale.h>
#include <tqlabel.h>
@@ -42,6 +43,12 @@ SnippetDlg::SnippetDlg( KActionCollection* ac, TQWidget* parent, const char* nam
connect( keyButton, TQT_SIGNAL( capturedShortcut( const KShortcut& ) ),
this, TQT_SLOT( slotCapturedShortcut( const KShortcut& ) ) );
+ btnAdd->setEnabled( false );
+ connect( snippetName, TQT_SIGNAL(textChanged(const TQString &)),
+ this, TQT_SLOT(slotTextChanged(const TQString &)) );
+ connect( snippetName, TQT_SIGNAL(returnPressed()),
+ this, TQT_SLOT(slotReturnPressed()) );
+
layout3->addWidget( textLabel3, 7, 0 );
layout3->addWidget( keyButton, 7, 1 );
@@ -68,7 +75,7 @@ SnippetDlg::~SnippetDlg()
*/
void SnippetDlg::languageChange()
{
- textLabel3->setText( tr2i18n( "Sh&ortcut:" ) );
+ textLabel3->setText( i18n( "Sh&ortcut:" ) );
}
static bool shortcutIsValid( const KActionCollection* actionCollection, const KShortcut &sc )
@@ -105,4 +112,16 @@ void SnippetDlg::setShowShortcut( bool show )
keyButton->setShown( show );
}
+void SnippetDlg::slotTextChanged( const TQString &text )
+{
+ btnAdd->setEnabled( !text.isEmpty() );
+}
+
+void SnippetDlg::slotReturnPressed()
+{
+ if ( !snippetName->text().isEmpty() ) {
+ accept();
+ }
+}
+
#include "snippetdlg.moc"
diff --git a/kmail/snippetdlg.h b/kmail/snippetdlg.h
index fd990539f..efd7bc534 100644
--- a/kmail/snippetdlg.h
+++ b/kmail/snippetdlg.h
@@ -20,7 +20,7 @@ class SnippetDlg : public SnippetDlgBase
{
Q_OBJECT
-public:
+ public:
SnippetDlg( KActionCollection* ac, TQWidget* parent = 0, const char* name = 0, bool modal = FALSE, WFlags fl = 0 );
~SnippetDlg();
@@ -31,12 +31,13 @@ public:
KKeyButton* keyButton;
KActionCollection* actionCollection;
-private slots:
- void slotCapturedShortcut( const KShortcut& );
-
-protected slots:
+ protected slots:
+ void slotTextChanged( const TQString& );
+ void slotReturnPressed();
virtual void languageChange();
+ private slots:
+ void slotCapturedShortcut( const KShortcut& );
};
#endif // SNIPPETDLG_H
diff --git a/kmail/snippetdlgbase.ui b/kmail/snippetdlgbase.ui
index 5d87b564b..a5a28a72a 100644
--- a/kmail/snippetdlgbase.ui
+++ b/kmail/snippetdlgbase.ui
@@ -124,6 +124,9 @@
<property name="text">
<string>Group:</string>
</property>
+ <property name="buddy" stdset="0">
+ <cstring>cbGroup</cstring>
+ </property>
</widget>
<widget class="KComboBox" row="1" column="1">
<property name="name">
diff --git a/kmail/snippetitem.cpp b/kmail/snippetitem.cpp
index 206114ace..f9f3aa871 100644
--- a/kmail/snippetitem.cpp
+++ b/kmail/snippetitem.cpp
@@ -1,6 +1,6 @@
/***************************************************************************
* snippet feature from kdevelop/plugins/snippet/ *
- * *
+ * *
* Copyright (C) 2007 by Robert Gruber *
* rgruber@users.sourceforge.net *
* *
@@ -23,6 +23,7 @@ SnippetItem::SnippetItem(TQListView * parent, TQString name, TQString text )
strName = name;
strText = text;
iParent = -1;
+ setOpen( true );
}
SnippetItem::SnippetItem(TQListViewItem * parent, TQString name, TQString text)
@@ -31,6 +32,7 @@ SnippetItem::SnippetItem(TQListViewItem * parent, TQString name, TQString text)
strName = name;
strText = text;
iParent = ((SnippetGroup *)parent)->getId();
+ setOpen( true );
}
SnippetItem::~SnippetItem()
@@ -86,7 +88,7 @@ void SnippetItem::resetParent()
KAction* SnippetItem::getAction()
-{
+{
return action;
}
@@ -128,7 +130,7 @@ Deklaration for class SnippetGroup
int SnippetGroup::iMaxId = 1;
SnippetGroup::SnippetGroup(TQListView * parent, TQString name, int id)
- : SnippetItem(parent, name, "GROUP")
+ : SnippetItem(parent, name, i18n("GROUP"))
{
if (id > 0) {
iId = id;
@@ -146,7 +148,7 @@ SnippetGroup::~SnippetGroup()
void SnippetGroup::setId(int id)
{
- iId = id;
+ iId = id;
if (iId >= iMaxId)
iMaxId = iId+1;
}
diff --git a/kmail/snippetwidget.cpp b/kmail/snippetwidget.cpp
index 617021748..800a98e55 100644
--- a/kmail/snippetwidget.cpp
+++ b/kmail/snippetwidget.cpp
@@ -1,6 +1,6 @@
/***************************************************************************
* snippet feature from kdevelop/plugins/snippet/ *
- * *
+ * *
* Copyright (C) 2007 by Robert Gruber *
* rgruber@users.sourceforge.net *
* *
@@ -168,7 +168,7 @@ void SnippetWidget::slotAddGroup()
SnippetDlg dlg( mActionCollection, this, "SnippetDlg");
dlg.setShowShortcut( false );
dlg.snippetText->setEnabled(false);
- dlg.snippetText->setText("GROUP");
+ dlg.snippetText->setText(i18n("GROUP"));
dlg.setCaption(i18n("Add Group"));
dlg.cbGroup->insertItem(i18n("All"));
dlg.cbGroup->setCurrentText(i18n("All"));
diff --git a/kmail/stl_util.h b/kmail/stl_util.h
index 69963df7b..5e3e5ce6f 100644
--- a/kmail/stl_util.h
+++ b/kmail/stl_util.h
@@ -32,6 +32,8 @@
#ifndef __KDEPIM__KMAIL__STL_UTIL_H__
#define __KDEPIM__KMAIL__STL_UTIL_H__
+#include <algorithm>
+
template <typename T>
struct DeleteAndSetToZero {
void operator()( const T * & t ) { delete t; t = 0; }
@@ -44,4 +46,19 @@ static inline void deleteAll( T & c ) {
}
}
+namespace kdtools {
+
+ template <typename Iterator, typename UnaryPredicate>
+ bool any( Iterator first, Iterator last, UnaryPredicate p )
+ {
+ while ( first != last )
+ if ( p( *first ) )
+ return true;
+ else
+ ++first;
+ return false;
+ }
+
+} // namespace kdtools
+
#endif // __KDEPIM__KMAIL__STL_UTIL_H__
diff --git a/kmail/stringutil.cpp b/kmail/stringutil.cpp
new file mode 100644
index 000000000..907c5e1fb
--- /dev/null
+++ b/kmail/stringutil.cpp
@@ -0,0 +1,49 @@
+/* Copyright 2009 Thomas McGuire <mcguire@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) version 3 or any later version
+ accepted by the membership of KDE e.V. (or its successor approved
+ by the membership of KDE e.V.), which shall act as a proxy
+ defined in Section 14 of version 3 of the license.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "stringutil.h"
+#include "kmmsgbase.h"
+#include <kurl.h>
+
+namespace KMail
+{
+
+namespace StringUtil
+{
+#ifndef KMAIL_UNITTESTS
+TQString encodeMailtoUrl( const TQString& str )
+{
+ TQString result;
+ result = TQString::fromLatin1( KMMsgBase::encodeRFC2047String( str,
+ "utf-8" ) );
+ result = KURL::encode_string( result );
+ return result;
+}
+
+TQString decodeMailtoUrl( const TQString& url )
+{
+ TQString result;
+ result = KURL::decode_string( url.latin1() );
+ result = KMMsgBase::decodeRFC2047String( result.latin1() );
+ return result;
+}
+#endif
+
+}
+
+}
diff --git a/kmail/stringutil.h b/kmail/stringutil.h
new file mode 100644
index 000000000..2528bdced
--- /dev/null
+++ b/kmail/stringutil.h
@@ -0,0 +1,43 @@
+/* Copyright 2009 Thomas McGuire <mcguire@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) version 3 or any later version
+ accepted by the membership of KDE e.V. (or its successor approved
+ by the membership of KDE e.V.), which shall act as a proxy
+ defined in Section 14 of version 3 of the license.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef KMAIL_STRINGUTIL_H
+#define KMAIL_STRINGUTIL_H
+
+#include <tqstring.h>
+
+namespace KMail
+{
+/**
+ * This namespace contain helper functions for string manipulation
+ */
+namespace StringUtil
+{
+ /** Encodes an email address as mailto URL
+ */
+ TQString encodeMailtoUrl( const TQString& str );
+
+ /** Decodes a mailto URL
+ */
+ TQString decodeMailtoUrl( const TQString& url );
+}
+
+}
+#endif
+
+
diff --git a/kmail/subscriptiondialog.cpp b/kmail/subscriptiondialog.cpp
index 725317437..58d00b24a 100644
--- a/kmail/subscriptiondialog.cpp
+++ b/kmail/subscriptiondialog.cpp
@@ -373,7 +373,7 @@ void SubscriptionDialog::doSave()
KMail::ImapAccountBase *a = static_cast<KMail::ImapAccountBase*>(mAcct);
if( !a->onlySubscribedFolders() ) {
int result = KMessageBox::questionYesNoCancel( this,
- i18n("Currently subscriptions are not used for server %1\ndo you want to enable subscriptions?")
+ i18n("Currently subscriptions are not used for server. %1\nDo you want to enable subscriptions?")
.arg( a->name() ),
i18n("Enable Subscriptions?"), i18n("Enable"), i18n("Do Not Enable"));
switch(result) {
diff --git a/kmail/templateparser.cpp b/kmail/templateparser.cpp
index 4112b58ed..79df85094 100644
--- a/kmail/templateparser.cpp
+++ b/kmail/templateparser.cpp
@@ -43,21 +43,46 @@
#include "kmkernel.h"
#include <libkpimidentities/identity.h>
#include <libkpimidentities/identitymanager.h>
+#include "partNode.h"
+#include "attachmentcollector.h"
+#include "objecttreeparser.h"
+#include "util.h"
#include "templateparser.h"
+#include <mimelib/bodypart.h>
-TemplateParser::TemplateParser( KMMessage *amsg, const Mode amode,
- const TQString aselection,
- bool asmartQuote, bool anoQuote,
- bool aallowDecryption, bool aselectionIsBody ) :
- mMode( amode ), mFolder( 0 ), mIdentity( 0 ), mSelection( aselection ),
- mSmartQuote( asmartQuote ), mNoQuote( anoQuote ),
- mAllowDecryption( aallowDecryption ), mSelectionIsBody( aselectionIsBody ),
- mDebug( false ), mQuoteString( "> " ), mAppend( false )
+using namespace KMail;
+
+TemplateParser::TemplateParser( KMMessage *amsg, const Mode amode ) :
+ mMode( amode ), mFolder( 0 ), mIdentity( 0 ),
+ mAllowDecryption( false ),
+ mDebug( false ), mQuoteString( "> " ), mAppend( false ), mOrigRoot( 0 )
{
mMsg = amsg;
}
+void TemplateParser::setSelection( const TQString &selection )
+{
+ mSelection = selection;
+}
+
+void TemplateParser::setAllowDecryption( const bool allowDecryption )
+{
+ mAllowDecryption = allowDecryption;
+}
+
+bool TemplateParser::shouldStripSignature() const
+{
+ // Only strip the signature when replying, it should be preserved when forwarding
+ return ( mMode == Reply || mMode == ReplyAll) && GlobalSettings::stripSignature();
+}
+
+TemplateParser::~TemplateParser()
+{
+ delete mOrigRoot;
+ mOrigRoot = 0;
+}
+
int TemplateParser::parseQuotes( const TQString &prefix, const TQString &str,
TQString &quote ) const
{
@@ -279,36 +304,36 @@ void TemplateParser::processWithTemplate( const TQString &tmpl )
int len = parseQuotes( "QUOTEPIPE=", cmd, q );
i += len;
TQString pipe_cmd = q;
- if ( mOrigMsg && !mNoQuote ) {
- TQString str = pipe( pipe_cmd, mSelection );
+ if ( mOrigMsg ) {
+ TQString str = pipe( pipe_cmd, messageText( false ) );
TQString quote = mOrigMsg->asQuotedString( "", mQuoteString, str,
- mSmartQuote, mAllowDecryption );
+ shouldStripSignature(), mAllowDecryption );
body.append( quote );
}
} else if ( cmd.startsWith( "QUOTE" ) ) {
kdDebug() << "Command: QUOTE" << endl;
i += strlen( "QUOTE" );
- if ( mOrigMsg && !mNoQuote ) {
- TQString quote = mOrigMsg->asQuotedString( "", mQuoteString, mSelection,
- mSmartQuote, mAllowDecryption );
+ if ( mOrigMsg ) {
+ TQString quote = mOrigMsg->asQuotedString( "", mQuoteString, messageText( true ),
+ shouldStripSignature(), mAllowDecryption );
body.append( quote );
}
} else if ( cmd.startsWith( "QHEADERS" ) ) {
kdDebug() << "Command: QHEADERS" << endl;
i += strlen( "QHEADERS" );
- if ( mOrigMsg && !mNoQuote ) {
+ if ( mOrigMsg ) {
TQString quote = mOrigMsg->asQuotedString( "", mQuoteString,
mOrigMsg->headerAsSendableString(),
- mSmartQuote, false );
+ false, false );
body.append( quote );
}
} else if ( cmd.startsWith( "HEADERS" ) ) {
kdDebug() << "Command: HEADERS" << endl;
i += strlen( "HEADERS" );
- if ( mOrigMsg && !mNoQuote ) {
+ if ( mOrigMsg ) {
TQString str = mOrigMsg->headerAsSendableString();
body.append( str );
}
@@ -321,7 +346,7 @@ void TemplateParser::processWithTemplate( const TQString &tmpl )
i += len;
TQString pipe_cmd = q;
if ( mOrigMsg ) {
- TQString str = pipe(pipe_cmd, mSelection );
+ TQString str = pipe(pipe_cmd, messageText( false ) );
body.append( str );
}
@@ -363,7 +388,7 @@ void TemplateParser::processWithTemplate( const TQString &tmpl )
kdDebug() << "Command: TEXT" << endl;
i += strlen( "TEXT" );
if ( mOrigMsg ) {
- TQString quote = mOrigMsg->asPlainText( false, mAllowDecryption );
+ TQString quote = messageText( false );
body.append( quote );
}
@@ -379,10 +404,22 @@ void TemplateParser::processWithTemplate( const TQString &tmpl )
kdDebug() << "Command: OTEXT" << endl;
i += strlen( "OTEXT" );
if ( mOrigMsg ) {
- TQString quote = mOrigMsg->asPlainText( false, mAllowDecryption );
+ TQString quote = messageText( false );
body.append( quote );
}
+ } else if ( cmd.startsWith( "OADDRESSEESADDR" ) ) {
+ kdDebug() << "Command: OADDRESSEESADDR" << endl;
+ i += strlen( "OADDRESSEESADDR" );
+ const TQString to = mOrigMsg->to();
+ const TQString cc = mOrigMsg->cc();
+ if ( !to.isEmpty() )
+ body.append( i18n( "To:" ) + ' ' + to );
+ if ( !to.isEmpty() && !cc.isEmpty() )
+ body.append( '\n' );
+ if ( !cc.isEmpty() )
+ body.append( i18n( "CC:" ) + ' ' + cc );
+
} else if ( cmd.startsWith( "CCADDR" ) ) {
kdDebug() << "Command: CCADDR" << endl;
i += strlen( "CCADDR" );
@@ -829,20 +866,124 @@ void TemplateParser::processWithTemplate( const TQString &tmpl )
}
}
- // kdDebug() << "Message body: " << body << endl;
+ addProcessedBodyToMessage( body );
+}
+
+TQString TemplateParser::messageText( bool allowSelectionOnly )
+{
+ if ( !mSelection.isEmpty() && allowSelectionOnly )
+ return mSelection;
+
+ // No selection text, therefore we need to parse the object tree ourselves to get
+ partNode *root = parsedObjectTree();
+ return mOrigMsg->asPlainTextFromObjectTree( root, shouldStripSignature(), mAllowDecryption );
+}
+partNode* TemplateParser::parsedObjectTree()
+{
+ if ( mOrigRoot )
+ return mOrigRoot;
+
+ mOrigRoot = partNode::fromMessage( mOrigMsg );
+ ObjectTreeParser otp; // all defaults are ok
+ otp.parseObjectTree( mOrigRoot );
+ return mOrigRoot;
+}
+
+void TemplateParser::addProcessedBodyToMessage( const TQString &body )
+{
if ( mAppend ) {
+
+ // ### What happens here if the body is multipart or in some way encoded?
TQCString msg_body = mMsg->body();
msg_body.append( body.utf8() );
mMsg->setBody( msg_body );
- } else {
- mMsg->setBodyFromUnicode( body );
+ }
+ else {
+
+ // Get the attachments of the original mail
+ partNode *root = parsedObjectTree();
+ AttachmentCollector ac;
+ ac.collectAttachmentsFrom( root );
+
+ // Now, delete the old content and set the new content, which
+ // is either only the new text or the new text with some attachments.
+ mMsg->deleteBodyParts();
+
+ // Set To and CC from the template
+ if ( mMode == Forward ) {
+ if ( !mTo.isEmpty() ) {
+ mMsg->setTo( mMsg->to() + ',' + mTo );
+ }
+ if ( !mCC.isEmpty() )
+ mMsg->setCc( mMsg->cc() + ',' + mCC );
+ }
+
+ // If we have no attachment, simply create a text/plain part and
+ // set the processed template text as the body
+ if ( ac.attachments().empty() || mMode != Forward ) {
+ mMsg->headers().ContentType().FromString( DwString() ); // to get rid of old boundary
+ mMsg->headers().ContentType().Parse();
+ mMsg->headers().ContentType().SetType( DwMime::kTypeText );
+ mMsg->headers().ContentType().SetSubtype( DwMime::kSubtypePlain );
+ mMsg->headers().Assemble();
+ mMsg->setBodyFromUnicode( body );
+ mMsg->assembleIfNeeded();
+ }
+
+ // If we have some attachments, create a multipart/mixed mail and
+ // add the normal body as well as the attachments
+ else
+ {
+ mMsg->headers().ContentType().SetType( DwMime::kTypeMultipart );
+ mMsg->headers().ContentType().SetSubtype( DwMime::kSubtypeMixed );
+ mMsg->headers().ContentType().CreateBoundary( 0 );
+
+ KMMessagePart textPart;
+ textPart.setBodyFromUnicode( body );
+ mMsg->addDwBodyPart( mMsg->createDWBodyPart( &textPart ) );
+ mMsg->assembleIfNeeded();
+
+ int attachmentNumber = 1;
+ for ( std::vector<partNode*>::const_iterator it = ac.attachments().begin();
+ it != ac.attachments().end(); ++it, attachmentNumber++ ) {
+
+ // When adding this body part, make sure to _not_ add the next bodypart
+ // as well, which mimelib would do, therefore creating a mail with many
+ // duplicate attachments (so many that KMail runs out of memory, in fact).
+ // Body::AddBodyPart is very misleading here...
+ ( *it )->dwPart()->SetNext( 0 );
+
+ DwBodyPart *cloned = static_cast<DwBodyPart*>( ( *it )->dwPart()->Clone() );
+
+ // If the content type has no name or filename parameter, add one, since otherwise the name
+ // would be empty in the attachment view of the composer, which looks confusing
+ if ( cloned->Headers().HasContentType() ) {
+ DwMediaType &ct = cloned->Headers().ContentType();
+
+ // Converting to a string here, since DwMediaType does not have a HasParameter() function
+ TQString ctStr = ct.AsString().c_str();
+ if ( !ctStr.lower().contains( "name=" ) && !ctStr.lower().contains( "filename=" ) ) {
+ DwParameter *nameParameter = new DwParameter;
+ nameParameter->SetAttribute( "name" );
+ nameParameter->SetValue( Util::dwString( KMMsgBase::encodeRFC2231StringAutoDetectCharset(
+ i18n( "Attachment %1" ).arg( attachmentNumber ) ) ) );
+ ct.AddParameter( nameParameter );
+ }
+ }
+
+ mMsg->addDwBodyPart( cloned );
+ mMsg->assembleIfNeeded();
+ }
+ }
}
}
TQString TemplateParser::findCustomTemplate( const TQString &tmplName )
{
CTemplates t( tmplName );
+ mTo = t.to();
+ mCC = t.cC();
TQString content = t.content();
if ( !content.isEmpty() ) {
return content;
diff --git a/kmail/templateparser.h b/kmail/templateparser.h
index 7e432ac31..3cb53ac11 100644
--- a/kmail/templateparser.h
+++ b/kmail/templateparser.h
@@ -29,7 +29,29 @@ class KMFolder;
class TQObject;
class KProcess;
-class TemplateParser : public QObject
+/**
+ * The TemplateParser transforms a message with a given template.
+ *
+ * A template contains text and commands, such as %QUOTE or %ODATE, which will be
+ * replaced with the real values in process().
+ *
+ * The message given in the constructor is the message that is being transformed.
+ * The message text will be replaced by the processed text of the template, but other
+ * properties, such as the attachments or the subject, are preserved.
+ *
+ * There are two different kind of commands: Those that work on the message that is
+ * to be transformed and those that work on an 'original message'.
+ * Those that work on the message that is to be transformed have no special prefix, e.g.
+ * '%DATE'. Those that work on the original message have an 'O' prefix, for example
+ * '%ODATE'.
+ * This means that the %DATE command will take the date of the message passed in the
+ * constructor, the message which is to be transformed, whereas the %ODATE command will
+ * take the date of the message that is being passed in process(), the original message.
+ *
+ * TODO: What is the usecase of the commands that work on the message to be transformed?
+ * In general you only use the commands that work on the original message...
+ */
+class TemplateParser : public TQObject
{
Q_OBJECT
@@ -44,16 +66,43 @@ class TemplateParser : public QObject
static const int PipeTimeout = 15;
public:
- TemplateParser( KMMessage *amsg, const Mode amode, const TQString aselection,
- bool aSmartQuote, bool anoQuote, bool aallowDecryption,
- bool aselectionIsBody );
+ TemplateParser( KMMessage *amsg, const Mode amode );
+ ~TemplateParser();
+
+ /**
+ * Sets the selection. If this is set, only the selection will be added to commands such
+ * as %QUOTE. Otherwise, the whole message is quoted.
+ * If this is not called at all, the whole message is quoted as well.
+ * Call this before calling process().
+ */
+ void setSelection( const TQString &selection );
+
+ /**
+ * Sets whether the template parser is allowed to decrypt the original message when needing
+ * its message text, for example for the %QUOTE command.
+ * If true, it will tell the ObjectTreeParser it uses internally to decrypt the message,
+ * and that will possibly show a password request dialog to the user.
+ *
+ * The default is false.
+ */
+ void setAllowDecryption( const bool allowDecryption );
- virtual void process( KMMessage *aorig_msg, KMFolder *afolder = NULL, bool append = false );
+ virtual void process( KMMessage *aorig_msg, KMFolder *afolder = 0, bool append = false );
virtual void process( const TQString &tmplName, KMMessage *aorig_msg,
- KMFolder *afolder = NULL, bool append = false );
+ KMFolder *afolder = 0, bool append = false );
virtual void processWithTemplate( const TQString &tmpl );
+
+ /// This finds the template to use. Either the one from the folder, identity or
+ /// finally the global template.
+ /// This also reads the To and CC address of the template
+ /// @return the contents of the template
virtual TQString findTemplate();
+
+ /// Finds the template with the given name.
+ /// This also reads the To and CC address of the template
+ /// @return the contents of the template
virtual TQString findCustomTemplate( const TQString &tmpl );
+
virtual TQString pipe( const TQString &cmd, const TQString &buf );
virtual TQString getFName( const TQString &str );
@@ -66,16 +115,48 @@ class TemplateParser : public QObject
KMMessage *mMsg;
KMMessage *mOrigMsg;
TQString mSelection;
- bool mSmartQuote;
- bool mNoQuote;
bool mAllowDecryption;
- bool mSelectionIsBody;
int mPipeRc;
TQString mPipeOut;
TQString mPipeErr;
bool mDebug;
TQString mQuoteString;
bool mAppend;
+ TQString mTo, mCC;
+ partNode *mOrigRoot;
+
+ /**
+ * If there was a text selection set in the constructor, that will be returned.
+ * Otherwise, returns the plain text of the original message, as in KMMessage::asPlainText().
+ * The only difference is that this uses the cached object tree from parsedObjectTree()
+ *
+ * @param allowSelectionOnly if false, it will always return the complete mail text
+ */
+ TQString messageText( bool allowSelectionOnly );
+
+ /**
+ * Returns the parsed object tree of the original message.
+ * The result is cached in mOrigRoot, therefore calling this multiple times will only parse
+ * the tree once.
+ */
+ partNode* parsedObjectTree();
+
+ /**
+ * Called by processWithTemplate(). This adds the completely processed body to
+ * the message.
+ *
+ * In append mode, this will simply append the text to the body.
+ *
+ * Otherwise, the content of the old message is deleted and replaced with @p body.
+ * Attachments of the original message are also added back to the new message.
+ */
+ void addProcessedBodyToMessage( const TQString &body );
+
+ /**
+ * Determines whether the signature should be stripped when getting the text of the original
+ * message, e.g. for commands such as %QUOTE
+ */
+ bool shouldStripSignature() const;
int parseQuotes( const TQString &prefix, const TQString &str,
TQString &quote ) const;
diff --git a/kmail/templatesconfiguration.cpp b/kmail/templatesconfiguration.cpp
index 1e2d74cbd..8b4f37e8f 100644
--- a/kmail/templatesconfiguration.cpp
+++ b/kmail/templatesconfiguration.cpp
@@ -394,9 +394,9 @@ void TemplatesConfiguration::importFromPhrases()
"---------- %1 ----------\n"
"\n"
"Subject: %OFULLSUBJECT\n"
- "Date: %ODATE\n"
+ "Date: %ODATE, %OTIMELONG\n"
"From: %OFROMADDR\n"
- "To: %OTOADDR\n"
+ "%OADDRESSEESADDR\n"
"\n"
"%TEXT\n"
"-------------------------------------------------------\n"
@@ -509,38 +509,43 @@ void TemplatesConfiguration::slotInsertCommand( TQString cmd, int adjustCursor )
TQString TemplatesConfiguration::defaultNewMessage() {
return i18n(
"%REM=\"Default new message template\"%-\n"
- "%BLANK"
+ "%BLANK\n"
+ "%BLANK\n"
+ "%BLANK\n"
);
}
TQString TemplatesConfiguration::defaultReply() {
return i18n(
+ "%CURSOR\n"
+ "%BLANK\n"
"%REM=\"Default reply template\"%-\n"
"On %ODATEEN %OTIMELONGEN you wrote:\n"
"%QUOTE\n"
- "%CURSOR\n"
);
}
TQString TemplatesConfiguration::defaultReplyAll() {
return i18n(
+ "%CURSOR\n"
+ "%BLANK\n"
"%REM=\"Default reply all template\"%-\n"
"On %ODATEEN %OTIMELONGEN %OFROMNAME wrote:\n"
"%QUOTE\n"
- "%CURSOR\n"
);
}
-TQString TemplatesConfiguration::defaultForward() {
+TQString TemplatesConfiguration::defaultForward()
+{
return i18n(
"%REM=\"Default forward template\"%-\n"
"\n"
"---------- Forwarded Message ----------\n"
"\n"
"Subject: %OFULLSUBJECT\n"
- "Date: %ODATE\n"
+ "Date: %ODATE, %OTIMELONG\n"
"From: %OFROMADDR\n"
- "To: %OTOADDR\n"
+ "%OADDRESSEESADDR\n"
"\n"
"%TEXT\n"
"-------------------------------------------------------\n"
diff --git a/kmail/templatesinsertcommand.cpp b/kmail/templatesinsertcommand.cpp
index ee07c375b..45bd81fca 100644
--- a/kmail/templatesinsertcommand.cpp
+++ b/kmail/templatesinsertcommand.cpp
@@ -139,6 +139,9 @@ TemplatesInsertCommand::TemplatesInsertCommand( TQWidget *parent,
0, mapper, TQT_SLOT( map() ), menu );
mapper->setMapping( action, COFromLName );
menu->insert( action );
+ action = new KAction( i18n( "Addresses of all original recipients" ),
+ 0, mapper, TQT_SLOT( map() ), menu );
+ mapper->setMapping( action, COAddresseesAddr );
action = new KAction( i18n( "Subject" ),
0, mapper, TQT_SLOT( map() ), menu );
mapper->setMapping( action, COFullSubject );
@@ -365,6 +368,7 @@ void TemplatesInsertCommand::slotMapped( int cmd )
case TemplatesInsertCommand::CTime: emit insertCommand("%TIME"); break;
case TemplatesInsertCommand::CTimeLong: emit insertCommand("%TIMELONG"); break;
case TemplatesInsertCommand::CTimeLongEn: emit insertCommand("%TIMELONGEN"); break;
+ case TemplatesInsertCommand::COAddresseesAddr: emit insertCommand("%OADDRESSEESADDR"); break;
case TemplatesInsertCommand::CToAddr: emit insertCommand("%TOADDR"); break;
case TemplatesInsertCommand::CToName: emit insertCommand("%TONAME"); break;
case TemplatesInsertCommand::CToFName: emit insertCommand("%TOFNAME"); break;
diff --git a/kmail/templatesinsertcommand.h b/kmail/templatesinsertcommand.h
index 4a94a979b..04878136f 100644
--- a/kmail/templatesinsertcommand.h
+++ b/kmail/templatesinsertcommand.h
@@ -44,7 +44,8 @@ class TemplatesInsertCommand : public QPushButton
CODateEn, CODateShort, CODate, CODow, COTimeLongEn, COTimeLong, COTime,
CBlank, CNop, CClear, CDebug, CDebugOff, CToFName, CToLName, CFromFName, CFromLName,
COToFName, COToLName, COFromFName, COFromLName, CCursor,
- CCCAddr, CCCName, CCCFName, CCCLName, COCCAddr, COCCName, COCCFName, COCCLName };
+ CCCAddr, CCCName, CCCFName, CCCLName, COCCAddr, COCCName, COCCFName, COCCLName,
+ COAddresseesAddr };
signals:
void insertCommand( TemplatesInsertCommand::Command cmd );
diff --git a/kmail/treebase.cpp b/kmail/treebase.cpp
new file mode 100644
index 000000000..19aff3155
--- /dev/null
+++ b/kmail/treebase.cpp
@@ -0,0 +1,235 @@
+/*
+ Copyright (c) 2008 Pradeepto K. Bhattacharya <pradeepto@kde.org>
+ ( adapted from kdepim/kmail/kmfolderseldlg.cpp and simplefoldertree.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.
+*/
+
+#include "treebase.h"
+#include "kmfolder.h"
+#include "kmfoldertree.h"
+#include "simplefoldertree.h"
+
+#include <kdebug.h>
+#include <klistview.h>
+
+using namespace KMail;
+
+TreeBase::TreeBase( TQWidget *parent, KMFolderTree *folderTree,
+ const TQString &preSelection, bool mustBeReadWrite )
+ : KListView( parent ), mFolderTree( folderTree )
+{
+ Q_UNUSED( preSelection );
+ Q_UNUSED( mustBeReadWrite );
+ kdDebug(5006) << k_funcinfo << endl;
+
+ connect(this, TQT_SIGNAL(collapsed(TQListViewItem*)), TQT_SLOT(recolorRows()));
+ connect(this, TQT_SIGNAL(expanded(TQListViewItem*)), TQT_SLOT(recolorRows()));
+ connect( this, TQT_SIGNAL( contextMenuRequested( TQListViewItem*, const TQPoint &, int ) ),
+ this, TQT_SLOT( slotContextMenuRequested( TQListViewItem*, const TQPoint & ) ) );
+
+}
+
+const KMFolder * TreeBase::folder() const
+{
+ TQListViewItem * item = currentItem();
+ if( item ) {
+ TreeItemBase *base = dynamic_cast<TreeItemBase*>( item );
+ assert(base);
+ const KMFolder * folder = base->folder();
+ return folder;
+ }
+ return 0;
+}
+
+void TreeBase::setFolder( KMFolder *folder )
+ {
+ for ( TQListViewItemIterator it( this ) ; it.current() ; ++it )
+ {
+ const KMFolder *fld = dynamic_cast<TreeItemBase*>( it.current() )->folder();
+ if ( fld == folder )
+ {
+ setSelected( it.current(), true );
+ ensureItemVisible( it.current() );
+ }
+ }
+}
+
+void TreeBase::addChildFolder()
+{
+ kdDebug(5006) << k_funcinfo << endl;
+
+ const KMFolder *fld = folder();
+ if ( fld ) {
+ mFolderTree->addChildFolder( (KMFolder *) fld, parentWidget() );
+ reload( mLastMustBeReadWrite, mLastShowOutbox, mLastShowImapFolders );
+ setFolder( (KMFolder *) fld );
+ }
+}
+
+void TreeBase::slotContextMenuRequested( TQListViewItem *lvi, const TQPoint &p )
+{
+ kdDebug(5006) << k_funcinfo << endl;
+
+ if (!lvi)
+ return;
+ setCurrentItem( lvi );
+ setSelected( lvi, TRUE );
+
+ const KMFolder * folder = dynamic_cast<TreeItemBase*>( lvi )->folder();
+ if ( !folder || folder->noContent() || folder->noChildren() )
+ return;
+
+ KPopupMenu *folderMenu = new KPopupMenu;
+ folderMenu->insertTitle( folder->label() );
+ folderMenu->insertSeparator();
+ folderMenu->insertItem(SmallIconSet("folder_new"),
+ i18n("&New Subfolder..."), this,
+ TQT_SLOT(addChildFolder()));
+ kmkernel->setContextMenuShown( true );
+ folderMenu->exec (p, 0);
+ kmkernel->setContextMenuShown( false );
+ delete folderMenu;
+
+}
+
+void TreeBase::recolorRows()
+{
+ kdDebug(5006) << k_funcinfo << endl;
+
+ // Iterate through the list to set the alternate row flags.
+ int alt = 0;
+ TQListViewItemIterator it ( this );
+ while ( it.current() ) {
+ TQListViewItem * item = it.current() ;
+ if ( item->isVisible() ) {
+ bool visible = true;
+ TQListViewItem * parent = item->parent();
+ while ( parent ) {
+ if (!parent->isOpen()) {
+ visible = false;
+ break;
+ }
+ parent = parent->parent();
+ }
+
+ if ( visible ) {
+ TreeItemBase * treeItemBase = dynamic_cast<TreeItemBase*>( item );
+ treeItemBase->setAlternate( alt );
+ alt = !alt;
+ }
+ }
+ ++it;
+ }
+}
+
+void TreeBase::reload( bool mustBeReadWrite, bool showOutbox, bool showImapFolders,
+ const TQString& preSelection )
+{
+ clear();
+
+ mLastMustBeReadWrite = mustBeReadWrite;
+ mLastShowOutbox = showOutbox;
+ mLastShowImapFolders = showImapFolders;
+
+ TQListViewItem * lastItem = 0;
+ TQListViewItem * lastTopItem = 0;
+ TQListViewItem * selectedItem = 0;
+ int lastDepth = 0;
+
+ mFilter = "";
+ TQString path;
+
+ for ( TQListViewItemIterator it( mFolderTree ) ; it.current() ; ++it ) {
+ KMFolderTreeItem * fti = dynamic_cast<KMFolderTreeItem *>( it.current() );
+
+ if ( !fti || fti->protocol() == KFolderTreeItem::Search )
+ continue;
+
+ int depth = fti->depth();// - 1;
+ //kdDebug( 5006 ) << "LastDepth=" << lastDepth << "\tdepth=" << depth
+ // << "\tname=" << fti->text( 0 ) << endl;
+ TQListViewItem * item = 0;
+ if ( depth <= 0 ) {
+ // top level - first top level item or after last existing top level item
+ if ( lastTopItem )
+ item = createItem( this, lastTopItem );
+ else
+ item = createItem( this );
+ lastTopItem = item;
+ depth = 0;
+ path = "";
+ }
+ else {
+ if ( depth > lastDepth ) {
+ // next lower level - parent node will get opened
+ item = createItem( lastItem );
+ lastItem->setOpen( true );
+ }
+ else {
+
+ path = path.section( '/', 0, -2 - (lastDepth-depth) );
+ if ( depth == lastDepth )
+ // same level - behind previous item
+ item = createItem( lastItem->parent(), lastItem );
+ else if ( depth < lastDepth ) {
+ // above previous level - might be more than one level difference
+ // but highest possibility is top level
+ while ( ( depth <= --lastDepth ) && lastItem->parent() ) {
+ lastItem = static_cast<TQListViewItem *>( lastItem->parent() );
+ }
+ if ( lastItem->parent() )
+ item = createItem( lastItem->parent(), lastItem );
+ else {
+ // chain somehow broken - what does cause this ???
+ kdDebug( 5006 ) << "You shouldn't get here: depth=" << depth
+ << "folder name=" << fti->text( 0 ) << endl;
+ item = createItem( this );
+ lastTopItem = item;
+ }
+ }
+ }
+ }
+
+ if ( depth > 0 )
+ path += "/";
+ path += fti->text( 0 );
+
+
+ item->setText( mFolderColumn, fti->text( 0 ) );
+ item->setText( mPathColumn, path );
+ // Make items without folders and top level items unselectable
+ // (i.e. root item Local Folders and IMAP accounts)
+ if ( !fti->folder() || depth == 0 || ( mustBeReadWrite && fti->folder()->isReadOnly() ) ) {
+ item->setSelectable( false );
+ } else {
+ TreeItemBase * treeItemBase = dynamic_cast<TreeItemBase*>( item );
+ assert(treeItemBase);
+ treeItemBase->setFolder( fti->folder() );
+ if ( preSelection == treeItemBase->folder()->idString() )
+ selectedItem = item;
+ }
+ lastItem = item;
+ lastDepth = depth;
+ }
+
+ if ( selectedItem ) {
+ setSelected( selectedItem, true );
+ ensureItemVisible( selectedItem );
+ }
+
+}
+
+#include "treebase.moc"
diff --git a/kmail/treebase.h b/kmail/treebase.h
new file mode 100644
index 000000000..3822add20
--- /dev/null
+++ b/kmail/treebase.h
@@ -0,0 +1,83 @@
+/*
+ Copyright (c) 2008 Pradeepto K. Bhattacharya <pradeepto@kde.org>
+ ( adapted from kdepim/kmail/kmfolderseldlg.cpp and simplefoldertree.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 KMAIL_TREEBASE_H
+#define KMAIL_TREEBASE_H
+
+#include "kmfolder.h"
+#include "kmfoldertree.h"
+
+#include <kdebug.h>
+#include <klistview.h>
+
+namespace KMail {
+
+class TreeItemBase;
+
+class TreeBase : public KListView
+{
+ Q_OBJECT
+ public:
+ TreeBase( TQWidget * parent, KMFolderTree *folderTree,
+ const TQString &preSelection, bool mustBeReadWrite );
+
+ virtual ~TreeBase() {}
+
+ const KMFolder * folder() const;
+ /** Set the current folder */
+ void setFolder( KMFolder *folder );
+
+ inline void setFolder( const TQString& idString )
+ {
+ setFolder( kmkernel->findFolderById( idString ) );
+ }
+
+ void reload( bool mustBeReadWrite, bool showOutbox, bool showImapFolders,
+ const TQString& preSelection = TQString::null );
+
+ int folderColumn() const { return mFolderColumn; }
+ void setFolderColumn( const int folderCol ) { mFolderColumn = folderCol; }
+ int pathColumn() const { return mPathColumn; }
+ void setPathColumn( const int pathCol ) { mPathColumn = pathCol; }
+
+ public slots:
+ void addChildFolder();
+ protected slots:
+ void slotContextMenuRequested( TQListViewItem *lvi,
+ const TQPoint &p );
+ void recolorRows();
+protected:
+ virtual TQListViewItem* createItem( TQListView* ) = 0;
+ virtual TQListViewItem* createItem( TQListView*, TQListViewItem* ) = 0;
+ virtual TQListViewItem* createItem( TQListViewItem* ) = 0;
+ virtual TQListViewItem* createItem( TQListViewItem*, TQListViewItem* ) = 0;
+
+ protected:
+ KMFolderTree* mFolderTree;
+ TQString mFilter;
+ bool mLastMustBeReadWrite;
+ bool mLastShowOutbox;
+ bool mLastShowImapFolders;
+ /** Folder and path column IDs. */
+ int mFolderColumn;
+ int mPathColumn;
+
+};
+}
+#endif
diff --git a/kmail/urlhandlermanager.cpp b/kmail/urlhandlermanager.cpp
index 100009faa..8ab2a25fc 100644
--- a/kmail/urlhandlermanager.cpp
+++ b/kmail/urlhandlermanager.cpp
@@ -2,7 +2,7 @@
urlhandlermanager.cpp
This file is part of KMail, the KDE mail client.
- Copyright (c) 2002-2003 Klar�vdalens Datakonsult AB
+ Copyright (c) 2002-2003 Klar�lvdalens Datakonsult AB
Copyright (c) 2003 Marc Mutz <mutz@kde.org>
KMail is free software; you can redistribute it and/or modify it
@@ -43,9 +43,11 @@
#include "kmreaderwin.h"
#include "kmkernel.h"
#include "callback.h"
+#include "stl_util.h"
+#include <kstandarddirs.h>
+#include <kurldrag.h>
#include <kimproxy.h>
-#include "stl_util.h"
#include <kurl.h>
#include <algorithm>
@@ -123,8 +125,14 @@ namespace {
~AttachmentURLHandler() {}
bool handleClick( const KURL &, KMReaderWin * ) const;
+ bool handleShiftClick( const KURL &url, KMReaderWin *window ) const;
+ bool handleDrag( const KURL &url, const TQString& imagePath, KMReaderWin *window ) const;
+ bool willHandleDrag( const KURL &url, const TQString& imagePath, KMReaderWin *window ) const;
bool handleContextMenuRequest( const KURL &, const TQPoint &, KMReaderWin * ) const;
TQString statusBarMessage( const KURL &, KMReaderWin * ) const;
+ private:
+ partNode* partNodeForUrl( const KURL &url, KMReaderWin *w ) const;
+ bool attachmentIsInHeader( const KURL &url ) const;
};
class ShowAuditLogURLHandler : public KMail::URLHandler {
@@ -137,6 +145,24 @@ namespace {
TQString statusBarMessage( const KURL &, KMReaderWin * ) const;
};
+ // Handler that prevents dragging of internal images added by KMail, such as the envelope image
+ // in the enterprise header
+ class InternalImageURLHandler : public KMail::URLHandler {
+ public:
+ InternalImageURLHandler() : KMail::URLHandler()
+ {}
+ ~InternalImageURLHandler()
+ {}
+ bool handleDrag( const KURL &url, const TQString& imagePath, KMReaderWin *window ) const;
+ bool willHandleDrag( const KURL &url, const TQString& imagePath, KMReaderWin *window ) const;
+ bool handleClick( const KURL &, KMReaderWin * ) const
+ { return false; }
+ bool handleContextMenuRequest( const KURL &, const TQPoint &, KMReaderWin * ) const
+ { return false; }
+ TQString statusBarMessage( const KURL &, KMReaderWin * ) const
+ { return TQString(); }
+ };
+
class FallBackURLHandler : public KMail::URLHandler {
public:
FallBackURLHandler() : KMail::URLHandler() {}
@@ -212,7 +238,7 @@ static partNode * partNodeFromXKMailUrl( const KURL & url, KMReaderWin * w, TQSt
const int part_id = urlParts[1].toInt( &ok );
if ( !ok )
return 0;
- *path = KURL::decode_string( urlParts[2], 106 );
+ *path = KURL::decode_string( urlParts[2] );
return w->partNodeForId( part_id );
}
@@ -274,6 +300,7 @@ KMail::URLHandlerManager::URLHandlerManager() {
registerHandler( new AttachmentURLHandler() );
registerHandler( mBodyPartURLHandlerManager = new BodyPartURLHandlerManager() );
registerHandler( new ShowAuditLogURLHandler() );
+ registerHandler( new InternalImageURLHandler );
registerHandler( new FallBackURLHandler() );
}
@@ -311,6 +338,32 @@ bool KMail::URLHandlerManager::handleClick( const KURL & url, KMReaderWin * w )
return false;
}
+bool KMail::URLHandlerManager::handleShiftClick( const KURL &url, KMReaderWin *window ) const
+{
+ for ( HandlerList::const_iterator it = mHandlers.begin() ; it != mHandlers.end() ; ++it )
+ if ( (*it)->handleShiftClick( url, window ) )
+ return true;
+ return false;
+}
+
+bool KMail::URLHandlerManager::willHandleDrag( const KURL &url, const TQString& imagePath,
+ KMReaderWin *window ) const
+{
+ for ( HandlerList::const_iterator it = mHandlers.begin() ; it != mHandlers.end() ; ++it )
+ if ( (*it)->willHandleDrag( url, imagePath, window ) )
+ return true;
+ return false;
+}
+
+bool KMail::URLHandlerManager::handleDrag( const KURL &url, const TQString& imagePath,
+ KMReaderWin *window ) const
+{
+ for ( HandlerList::const_iterator it = mHandlers.begin() ; it != mHandlers.end() ; ++it )
+ if ( (*it)->handleDrag( url, imagePath, window ) )
+ return true;
+ return false;
+}
+
bool KMail::URLHandlerManager::handleContextMenuRequest( const KURL & url, const TQPoint & p, KMReaderWin * w ) const {
for ( HandlerList::const_iterator it = mHandlers.begin() ; it != mHandlers.end() ; ++it )
if ( (*it)->handleContextMenuRequest( url, p, w ) )
@@ -405,6 +458,13 @@ namespace {
return true;
}
+ if ( url.path() == "showRawToltecMail" ) {
+ w->saveRelativePosition();
+ w->setShowRawToltecMail( true );
+ w->update( true );
+ return true;
+ }
+
// if ( url.path() == "startIMApp" )
// {
// kmkernel->imProxy()->startPreferredApp();
@@ -430,6 +490,10 @@ namespace {
return i18n("Show signature details.");
if ( url.path() == "hideSignatureDetails" )
return i18n("Hide signature details.");
+ if ( url.path() == "hideAttachmentQuicklist" )
+ return i18n( "Hide attachment list" );
+ if ( url.path() == "showAttachmentQuicklist" )
+ return i18n( "Show attachment list" );
}
return TQString::null ;
}
@@ -459,11 +523,14 @@ namespace {
if ( url.protocol() == "kmail" && url.path() == "levelquote" )
{
TQString query= url.query();
- if ( query.length()>=2 )
- if ( query[ 1 ] =='-' )
+ if ( query.length()>=2 ) {
+ if ( query[ 1 ] =='-' ) {
return i18n("Expand all quoted text.");
- else
+ }
+ else {
return i18n("Collapse quoted text.");
+ }
+ }
}
return TQString::null ;
}
@@ -517,32 +584,106 @@ namespace {
}
namespace {
- bool AttachmentURLHandler::handleClick( const KURL & url, KMReaderWin * w ) const {
+
+ partNode* AttachmentURLHandler::partNodeForUrl( const KURL &url, KMReaderWin *w ) const
+ {
if ( !w || !w->message() )
+ return 0;
+ if ( url.protocol() != "attachment" )
+ return 0;
+
+ bool ok;
+ int nodeId = url.path().toInt( &ok );
+ if ( !ok )
+ return 0;
+
+ partNode * node = w->partNodeForId( nodeId );
+ return node;
+ }
+
+ bool AttachmentURLHandler::attachmentIsInHeader( const KURL &url ) const
+ {
+ bool inHeader = false;
+ const TQString place = url.queryItem( "place" ).lower();
+ if ( place != TQString::null ) {
+ inHeader = ( place == "header" );
+ }
+ return inHeader;
+ }
+
+ bool AttachmentURLHandler::handleClick( const KURL & url, KMReaderWin * w ) const
+ {
+ partNode * node = partNodeForUrl( url, w );
+ if ( !node )
+ return false;
+
+ const bool inHeader = attachmentIsInHeader( url );
+ const bool shouldShowDialog = !node->isDisplayedEmbedded() || !inHeader;
+ if ( inHeader )
+ w->scrollToAttachment( node );
+ if ( shouldShowDialog )
+ w->openAttachment( node->nodeId(), w->tempFileUrlFromPartNode( node ).path() );
+ return true;
+ }
+
+ bool AttachmentURLHandler::handleShiftClick( const KURL &url, KMReaderWin *window ) const
+ {
+ partNode * node = partNodeForUrl( url, window );
+ if ( !node )
return false;
- const int id = KMReaderWin::msgPartFromUrl( url );
- if ( id <= 0 )
+ if ( !window )
return false;
- w->openAttachment( id, url.path() );
+ window->saveAttachment( window->tempFileUrlFromPartNode( node ) );
return true;
}
- bool AttachmentURLHandler::handleContextMenuRequest( const KURL & url, const TQPoint & p, KMReaderWin * w ) const {
- if ( !w || !w->message() )
+ bool AttachmentURLHandler::willHandleDrag( const KURL &url, const TQString& imagePath,
+ KMReaderWin *window ) const
+ {
+ Q_UNUSED( imagePath );
+ return partNodeForUrl( url, window ) != 0;
+ }
+
+ bool AttachmentURLHandler::handleDrag( const KURL &url, const TQString& imagePath,
+ KMReaderWin *window ) const
+ {
+ Q_UNUSED( imagePath );
+ const partNode * node = partNodeForUrl( url, window );
+ if ( !node )
return false;
- const int id = KMReaderWin::msgPartFromUrl( url );
- if ( id <= 0 )
+
+ KURL file = window->tempFileUrlFromPartNode( node ).path();
+ if ( !file.isEmpty() ) {
+ TQString icon = node->msgPart().iconName( KIcon::Small );
+ KURLDrag* urlDrag = new KURLDrag( file, window );
+ if ( !icon.isEmpty() ) {
+ TQPixmap iconMap( icon );
+ urlDrag->setPixmap( iconMap );
+ }
+ urlDrag->drag();
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+ bool AttachmentURLHandler::handleContextMenuRequest( const KURL & url, const TQPoint & p, KMReaderWin * w ) const
+ {
+ partNode * node = partNodeForUrl( url, w );
+ if ( !node )
return false;
- w->showAttachmentPopup( id, url.path(), p );
+
+ w->showAttachmentPopup( node->nodeId(), w->tempFileUrlFromPartNode( node ).path(), p );
return true;
}
- TQString AttachmentURLHandler::statusBarMessage( const KURL & url, KMReaderWin * w ) const {
- if ( !w || !w->message() )
- return TQString::null;
- const partNode * node = w->partNodeFromUrl( url );
+ TQString AttachmentURLHandler::statusBarMessage( const KURL & url, KMReaderWin * w ) const
+ {
+ partNode * node = partNodeForUrl( url, w );
if ( !node )
return TQString::null;
+
const KMMessagePart & msgPart = node->msgPart();
TQString name = msgPart.fileName();
if ( name.isEmpty() )
@@ -569,7 +710,9 @@ namespace {
return true;
}
- bool ShowAuditLogURLHandler::handleContextMenuRequest( const KURL & url, const TQPoint &, KMReaderWin * w ) const {
+ bool ShowAuditLogURLHandler::handleContextMenuRequest( const KURL & url, const TQPoint &, KMReaderWin * w ) const
+ {
+ Q_UNUSED( w );
// disable RMB for my own links:
return !extractAuditLog( url ).isEmpty();
}
@@ -583,6 +726,30 @@ namespace {
}
namespace {
+ bool InternalImageURLHandler::handleDrag( const KURL &url, const TQString& imagePath,
+ KMReaderWin *window ) const
+ {
+ Q_UNUSED( window );
+ Q_UNUSED( url );
+ const TQString kmailImagePath = locate( "data", "kmail/pics/" );
+ if ( imagePath.contains( kmailImagePath ) ) {
+ // Do nothing, don't start a drag
+ return true;
+ }
+ return false;
+ }
+
+ bool InternalImageURLHandler::willHandleDrag( const KURL &url, const TQString& imagePath,
+ KMReaderWin *window ) const
+ {
+ Q_UNUSED( window );
+ Q_UNUSED( url );
+ const TQString kmailImagePath = locate( "data", "kmail/pics/" );
+ return imagePath.contains( kmailImagePath );
+ }
+}
+
+namespace {
bool FallBackURLHandler::handleClick( const KURL & url, KMReaderWin * w ) const {
if ( w )
w->emitUrlClicked( url, Qt::LeftButton );
diff --git a/kmail/urlhandlermanager.h b/kmail/urlhandlermanager.h
index acd9f2844..815952593 100644
--- a/kmail/urlhandlermanager.h
+++ b/kmail/urlhandlermanager.h
@@ -72,7 +72,10 @@ namespace KMail {
void unregisterHandler( const Interface::BodyPartURLHandler * handler );
bool handleClick( const KURL & url, KMReaderWin * w=0 ) const;
+ bool handleShiftClick( const KURL &url, KMReaderWin *window = 0 ) const;
bool handleContextMenuRequest( const KURL & url, const TQPoint & p, KMReaderWin * w=0 ) const;
+ bool willHandleDrag( const KURL &url, const TQString& imagePath, KMReaderWin *window = 0 ) const;
+ bool handleDrag( const KURL &url, const TQString& imagePath, KMReaderWin *window = 0 ) const;
TQString statusBarMessage( const KURL & url, KMReaderWin * w=0 ) const;
private:
diff --git a/kmail/vacation.cpp b/kmail/vacation.cpp
index d0cdedf85..0b9222f48 100644
--- a/kmail/vacation.cpp
+++ b/kmail/vacation.cpp
@@ -500,11 +500,15 @@ namespace KMail {
u.setUser( a->login() );
u.setPass( a->passwd() );
u.setPort( sieve.port() );
- u.setQuery( "x-mech=" + (a->auth() == "*" ? "PLAIN" : a->auth()) ); //translate IMAP LOGIN to PLAIN
+ u.addQueryItem( "x-mech", a->auth() == "*" ? "PLAIN" : a->auth() ); //translate IMAP LOGIN to PLAIN
+ if ( !a->useSSL() && !a->useTLS() )
+ u.addQueryItem( "x-allow-unencrypted", "true" );
u.setFileName( sieve.vacationFileName() );
return u;
} else {
KURL u = sieve.alternateURL();
+ if ( u.protocol().lower() == "sieve" && !a->useSSL() && !a->useTLS() && u.queryItem("x-allow-unencrypted").isEmpty() )
+ u.addQueryItem( "x-allow-unencrypted", "true" );
u.setFileName( sieve.vacationFileName() );
return u;
}
@@ -579,9 +583,11 @@ namespace KMail {
TQStringList Vacation::defaultMailAliases() {
TQStringList sl;
for ( KPIM::IdentityManager::ConstIterator it = kmkernel->identityManager()->begin() ;
- it != kmkernel->identityManager()->end() ; ++it )
- if ( !(*it).emailAddr().isEmpty() )
- sl.push_back( (*it).emailAddr() );
+ it != kmkernel->identityManager()->end() ; ++it ) {
+ if ( !(*it).primaryEmailAddress().isEmpty() )
+ sl.push_back( (*it).primaryEmailAddress() );
+ sl += (*it).emailAliases();
+ }
return sl;
}
@@ -666,6 +672,7 @@ namespace KMail {
mDialog->setMailAliases( defaultMailAliases().join(", ") );
mDialog->setSendForSpam( defaultSendForSpam() );
mDialog->setDomainName( defaultDomainName() );
+ mDialog->setDomainCheck( false );
}
void Vacation::slotDialogOk() {
diff --git a/kmail/vacationdialog.cpp b/kmail/vacationdialog.cpp
index a2dabe9b1..50dea24e2 100644
--- a/kmail/vacationdialog.cpp
+++ b/kmail/vacationdialog.cpp
@@ -71,7 +71,9 @@ namespace KMail {
// "Resent only after" spinbox and label:
++row;
- mIntervalSpin = new KIntSpinBox( 1, 356, 1, 7, 10, plainPage(), "mIntervalSpin" );
+ int defDayInterval = 7; //default day interval
+ mIntervalSpin = new KIntSpinBox( 1, 356, 1, defDayInterval, 10, plainPage(), "mIntervalSpin" );
+ mIntervalSpin->setSuffix( i18n(" day", " days", defDayInterval) );
connect(mIntervalSpin, TQT_SIGNAL( valueChanged( int )), TQT_SLOT( slotIntervalSpinChanged( int ) ) );
glay->addWidget( new TQLabel( mIntervalSpin, i18n("&Resend notification only after:"), plainPage() ), row, 0 );
glay->addWidget( mIntervalSpin, row, 1 );
@@ -168,28 +170,40 @@ namespace KMail {
}
void VacationDialog::setDomainName( const TQString & domain ) {
- mDomainEdit->setText( domain );
- if ( !domain.isEmpty() )
+ if ( !domain.isEmpty() ) {
+ mDomainEdit->setText( domain );
mDomainCheck->setChecked( true );
+ }
+ }
+
+ bool VacationDialog::domainCheck() const
+ {
+ return mDomainCheck->isChecked();
+ }
+
+ void VacationDialog::setDomainCheck( bool check )
+ {
+ mDomainCheck->setChecked( check );
}
- bool VacationDialog::sendForSpam() const {
+ bool VacationDialog::sendForSpam() const
+ {
return !mSpamCheck->isChecked();
}
- void VacationDialog::setSendForSpam( bool enable ) {
+ void VacationDialog::setSendForSpam( bool enable )
+ {
mSpamCheck->setChecked( !enable );
}
-
/* virtual*/
- void KMail::VacationDialog::enableDomainAndSendForSpam( bool enable ) {
- mDomainCheck->setEnabled( enable );
- mDomainEdit->setEnabled( enable );
- mSpamCheck->setEnabled( enable );
+ void KMail::VacationDialog::enableDomainAndSendForSpam( bool enable )
+ {
+ mDomainCheck->setEnabled( enable );
+ mDomainEdit->setEnabled( enable && mDomainCheck->isChecked() );
+ mSpamCheck->setEnabled( enable );
}
-
} // namespace KMail
#include "vacationdialog.moc"
diff --git a/kmail/vacationdialog.h b/kmail/vacationdialog.h
index 2ce076ff6..a971b1182 100644
--- a/kmail/vacationdialog.h
+++ b/kmail/vacationdialog.h
@@ -46,6 +46,9 @@ namespace KMail {
bool activateVacation() const;
virtual void setActivateVacation( bool activate );
+ bool domainCheck() const;
+ virtual void setDomainCheck( bool check );
+
TQString messageText() const;
virtual void setMessageText( const TQString & text );
@@ -55,14 +58,14 @@ namespace KMail {
KMime::Types::AddrSpecList mailAliases() const;
virtual void setMailAliases( const KMime::Types::AddrSpecList & aliases );
virtual void setMailAliases( const TQString & aliases );
-
+
TQString domainName() const;
virtual void setDomainName( const TQString & domain );
bool sendForSpam() const;
virtual void setSendForSpam( bool enable );
-
+
private slots:
void slotIntervalSpinChanged( int value );
diff --git a/kmail/vcardviewer.cpp b/kmail/vcardviewer.cpp
index ff4a3b86e..0e34f72cc 100644
--- a/kmail/vcardviewer.cpp
+++ b/kmail/vcardviewer.cpp
@@ -37,7 +37,11 @@ using KABC::Addressee;
#include <tqstring.h>
-KMail::VCardViewer::VCardViewer(TQWidget *parent, const TQString& vCard, const char* name)
+#if defined(KABC_VCARD_ENCODING_FIX)
+KMail::VCardViewer::VCardViewer( TQWidget *parent, const TQByteArray &vCard, const char *name )
+#else
+KMail::VCardViewer::VCardViewer( TQWidget *parent, const TQString &vCard, const char *name )
+#endif
: KDialogBase( parent, name, false, i18n("VCard Viewer"), User1|User2|User3|Close, Close,
true, i18n("&Import"), i18n("&Next Card"), i18n("&Previous Card") )
{
@@ -47,7 +51,11 @@ KMail::VCardViewer::VCardViewer(TQWidget *parent, const TQString& vCard, const c
setMainWidget(mAddresseeView);
VCardConverter vcc;
+#if defined(KABC_VCARD_ENCODING_FIX)
+ mAddresseeList = vcc.parseVCardsRaw( vCard.data() );
+#else
mAddresseeList = vcc.parseVCards( vCard );
+#endif
if ( !mAddresseeList.empty() ) {
itAddresseeList = mAddresseeList.begin();
mAddresseeView->setAddressee( *itAddresseeList );
diff --git a/kmail/vcardviewer.h b/kmail/vcardviewer.h
index 2fdcd090a..48da60ba3 100644
--- a/kmail/vcardviewer.h
+++ b/kmail/vcardviewer.h
@@ -22,6 +22,7 @@
#include <kdialogbase.h>
#include <kabc/addressee.h>
+#include <kabc/vcardparser.h> // for KABC_VCARD_ENCODING_FIX define
#include <tqvaluelist.h>
@@ -33,24 +34,28 @@ namespace KPIM {
namespace KMail {
- class VCardViewer : public KDialogBase
- {
- Q_OBJECT
- public:
- VCardViewer(TQWidget *parent, const TQString& vCard, const char* name);
- virtual ~VCardViewer();
-
- protected:
- virtual void slotUser1();
- virtual void slotUser2();
- virtual void slotUser3();
-
- private:
- KPIM::AddresseeView * mAddresseeView;
- KABC::Addressee::List mAddresseeList;
-
- TQValueListIterator<KABC::Addressee> itAddresseeList;
- };
+class VCardViewer : public KDialogBase
+{
+ Q_OBJECT
+ public:
+#if defined(KABC_VCARD_ENCODING_FIX)
+ VCardViewer( TQWidget *parent, const TQByteArray &vCard, const char *name );
+#else
+ VCardViewer( TQWidget *parent, const TQString &vCard, const char *name );
+#endif
+ virtual ~VCardViewer();
+
+ protected:
+ virtual void slotUser1();
+ virtual void slotUser2();
+ virtual void slotUser3();
+
+ private:
+ KPIM::AddresseeView *mAddresseeView;
+ KABC::Addressee::List mAddresseeList;
+
+ TQValueListIterator<KABC::Addressee> itAddresseeList;
+};
}
diff --git a/kmailcvt/Makefile.am b/kmailcvt/Makefile.am
index 2ae9b9169..b5e48e83c 100644
--- a/kmailcvt/Makefile.am
+++ b/kmailcvt/Makefile.am
@@ -6,7 +6,7 @@ kmailcvt_SOURCES = kimportpagedlg.ui kimportpage.cpp kselfilterpagedlg.ui \
filter_mbox.cxx filter_evolution.cxx filter_mailapp.cxx \
filter_evolution_v2.cxx filter_opera.cxx filter_thunderbird.cxx \
filter_kmail_maildir.cxx filter_sylpheed.cxx filter_thebat.cxx \
- filter_lnotes.cxx
+ filter_lnotes.cxx filter_kmail_archive.cxx
kmailcvt_LDADD = $(LIB_KFILE)
@@ -25,7 +25,8 @@ EXTRA_DIST = main.cpp kmailcvt.cpp kimportpage.cpp kimportpage.h \
filter_thunderbird.hxx filter_thunderbird.cxx \
filter_kmail_maildir.hxx filter_kmail_maildir.cxx \
filter_sylpheed.hxx filter_sylpheed.cxx \
- filter_thebat.hxx filter_thebat.cxx filter_lnotes.hxx filter_lnotes.cxx
+ filter_thebat.hxx filter_thebat.cxx filter_lnotes.hxx filter_lnotes.cxx \
+ filter_kmail_archive.cxx fitler_kmail_archive.hxx
install-data-local: uninstall.desktop
$(mkinstalldirs) $(DESTDIR)$(kde_appsdir)/Utilities
diff --git a/kmailcvt/filter_evolution.cxx b/kmailcvt/filter_evolution.cxx
index abc602a21..a07a6f084 100644
--- a/kmailcvt/filter_evolution.cxx
+++ b/kmailcvt/filter_evolution.cxx
@@ -39,7 +39,6 @@ FilterEvolution::FilterEvolution(void) :
/** Destructor. */
FilterEvolution::~FilterEvolution(void)
{
- endImport();
}
/** Recursive import of Evolution's mboxes. */
diff --git a/kmailcvt/filter_evolution_v2.cxx b/kmailcvt/filter_evolution_v2.cxx
index 16c3093a6..dd69ee7b5 100644
--- a/kmailcvt/filter_evolution_v2.cxx
+++ b/kmailcvt/filter_evolution_v2.cxx
@@ -39,7 +39,6 @@ FilterEvolution_v2::FilterEvolution_v2(void) :
/** Destructor. */
FilterEvolution_v2::~FilterEvolution_v2(void)
{
- endImport();
}
/** Recursive import of Evolution's mboxes. */
@@ -61,6 +60,7 @@ void FilterEvolution_v2::import(FilterInfo *info)
kfd->setMode(KFile::Directory | KFile::LocalOnly);
kfd->exec();
mailDir = kfd->selectedFile();
+ delete kfd;
if (mailDir.isEmpty()) {
info->alert(i18n("No directory selected."));
diff --git a/kmailcvt/filter_kmail_archive.cxx b/kmailcvt/filter_kmail_archive.cxx
new file mode 100644
index 000000000..2fca99bdc
--- /dev/null
+++ b/kmailcvt/filter_kmail_archive.cxx
@@ -0,0 +1,35 @@
+/* Copyright 2009 Klarälvdalens 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) version 3 or any later version
+ accepted by the membership of KDE e.V. (or its successor approved
+ by the membership of KDE e.V.), which shall act as a proxy
+ defined in Section 14 of version 3 of the license.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "filter_kmail_archive.hxx"
+
+#include <klocale.h>
+
+FilterKMailArchive::FilterKMailArchive()
+ : Filter( i18n( "Import KMail Archive File" ),
+ "Klar\xE4lvdalens Datakonsult AB",
+ i18n( "<p><b>KMail Archive File Import Filter</b></p>"
+ "<p>This filter will import archives files previously exported by KMail.</p>"
+ "<p>Archive files contain a complete folder subtree compressed into a single file.</p>" ) )
+{
+}
+
+void FilterKMailArchive::import( FilterInfo *info )
+{
+ showKMailImportArchiveDialog( info );
+}
diff --git a/kmailcvt/filter_kmail_archive.hxx b/kmailcvt/filter_kmail_archive.hxx
new file mode 100644
index 000000000..755d3cc28
--- /dev/null
+++ b/kmailcvt/filter_kmail_archive.hxx
@@ -0,0 +1,32 @@
+/* Copyright 2009 Klarälvdalens 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) version 3 or any later version
+ accepted by the membership of KDE e.V. (or its successor approved
+ by the membership of KDE e.V.), which shall act as a proxy
+ defined in Section 14 of version 3 of the license.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef FILTER_KMAIL_ARCHIVE_HXX
+#define FILTER_KMAIL_ARCHIVE_HXX
+
+#include "filters.hxx"
+
+class FilterKMailArchive : public Filter
+{
+public:
+ FilterKMailArchive();
+ void import( FilterInfo *info );
+ virtual bool needsSecondPage() { return false; }
+};
+
+#endif
diff --git a/kmailcvt/filter_kmail_maildir.cxx b/kmailcvt/filter_kmail_maildir.cxx
index 5ea7d4fc7..2a1961567 100644
--- a/kmailcvt/filter_kmail_maildir.cxx
+++ b/kmailcvt/filter_kmail_maildir.cxx
@@ -38,7 +38,6 @@ FilterKMail_maildir::FilterKMail_maildir( void ) :
/** Destructor. */
FilterKMail_maildir::~FilterKMail_maildir( void )
{
- endImport();
}
/** Recursive import of KMail maildir. */
@@ -52,6 +51,7 @@ void FilterKMail_maildir::import( FilterInfo *info )
kfd->setMode( KFile::Directory | KFile::LocalOnly );
kfd->exec();
mailDir = kfd->selectedFile();
+ delete kfd;
if ( mailDir.isEmpty() ) {
info->alert( i18n( "No directory selected." ) );
diff --git a/kmailcvt/filter_lnotes.cxx b/kmailcvt/filter_lnotes.cxx
index 69a48167a..4bd3c423f 100644
--- a/kmailcvt/filter_lnotes.cxx
+++ b/kmailcvt/filter_lnotes.cxx
@@ -40,7 +40,6 @@ FilterLNotes::FilterLNotes() :
/** Destructor. */
FilterLNotes::~FilterLNotes() {
- endImport();
}
/**
diff --git a/kmailcvt/filter_mailapp.cxx b/kmailcvt/filter_mailapp.cxx
index 2121badb0..901fa6982 100644
--- a/kmailcvt/filter_mailapp.cxx
+++ b/kmailcvt/filter_mailapp.cxx
@@ -37,7 +37,6 @@ FilterMailApp::FilterMailApp() :
FilterMailApp::~FilterMailApp()
{
- endImport();
}
void FilterMailApp::import(FilterInfo *info)
diff --git a/kmailcvt/filter_mbox.cxx b/kmailcvt/filter_mbox.cxx
index 3777cd7e9..76b376683 100644
--- a/kmailcvt/filter_mbox.cxx
+++ b/kmailcvt/filter_mbox.cxx
@@ -37,7 +37,6 @@ FilterMBox::FilterMBox() :
FilterMBox::~FilterMBox()
{
- endImport();
}
void FilterMBox::import(FilterInfo *info)
diff --git a/kmailcvt/filter_oe.cxx b/kmailcvt/filter_oe.cxx
index e1465d141..bde399b62 100644
--- a/kmailcvt/filter_oe.cxx
+++ b/kmailcvt/filter_oe.cxx
@@ -50,7 +50,6 @@ FilterOE::FilterOE() :
FilterOE::~FilterOE()
{
- endImport();
}
void FilterOE::import(FilterInfo *info)
diff --git a/kmailcvt/filter_opera.cxx b/kmailcvt/filter_opera.cxx
index 3b2fff176..65e2eae4b 100644
--- a/kmailcvt/filter_opera.cxx
+++ b/kmailcvt/filter_opera.cxx
@@ -37,7 +37,6 @@ FilterOpera::FilterOpera() :
FilterOpera::~FilterOpera()
{
- endImport();
}
void FilterOpera::import(FilterInfo *info)
@@ -55,6 +54,7 @@ void FilterOpera::import(FilterInfo *info)
kfd->setMode(KFile::Directory | KFile::LocalOnly);
kfd->exec();
TQString operaDir = kfd->selectedFile();
+ delete kfd;
if (operaDir.isEmpty()) {
info->alert(i18n("No directory selected."));
diff --git a/kmailcvt/filter_outlook.cxx b/kmailcvt/filter_outlook.cxx
index 0dad8fde7..a5a9f407c 100644
--- a/kmailcvt/filter_outlook.cxx
+++ b/kmailcvt/filter_outlook.cxx
@@ -37,7 +37,6 @@ FilterOutlook::FilterOutlook() :
FilterOutlook::~FilterOutlook()
{
- endImport();
}
void FilterOutlook::import(FilterInfo *info)
diff --git a/kmailcvt/filter_plain.cxx b/kmailcvt/filter_plain.cxx
index 0246c8c63..04abea3d3 100644
--- a/kmailcvt/filter_plain.cxx
+++ b/kmailcvt/filter_plain.cxx
@@ -34,7 +34,6 @@ FilterPlain::FilterPlain() :
FilterPlain::~FilterPlain()
{
- endImport();
}
void FilterPlain::import(FilterInfo *info)
diff --git a/kmailcvt/filter_pmail.cxx b/kmailcvt/filter_pmail.cxx
index 5fcc1256e..23617f912 100644
--- a/kmailcvt/filter_pmail.cxx
+++ b/kmailcvt/filter_pmail.cxx
@@ -38,7 +38,6 @@ FilterPMail::FilterPMail() :
FilterPMail::~FilterPMail()
{
- endImport();
}
void FilterPMail::import(FilterInfo *info)
@@ -51,6 +50,7 @@ void FilterPMail::import(FilterInfo *info)
kfd->setMode(KFile::Directory | KFile::LocalOnly);
kfd->exec();
chosenDir = kfd->selectedFile();
+ delete kfd;
if (chosenDir.isEmpty()) {
info->alert(i18n("No directory selected."));
diff --git a/kmailcvt/filter_sylpheed.cxx b/kmailcvt/filter_sylpheed.cxx
index fcf53f74a..489083f04 100644
--- a/kmailcvt/filter_sylpheed.cxx
+++ b/kmailcvt/filter_sylpheed.cxx
@@ -37,7 +37,6 @@ FilterSylpheed::FilterSylpheed( void ) :
/** Destructor. */
FilterSylpheed::~FilterSylpheed( void )
{
- endImport();
}
/** Recursive import of Sylpheed maildir. */
@@ -51,6 +50,7 @@ void FilterSylpheed::import( FilterInfo *info )
kfd->setMode( KFile::Directory | KFile::LocalOnly );
kfd->exec();
mailDir = kfd->selectedFile();
+ delete kfd;
if ( mailDir.isEmpty() ) {
info->alert( i18n( "No directory selected." ) );
diff --git a/kmailcvt/filter_thebat.cxx b/kmailcvt/filter_thebat.cxx
index fa00b915d..de6e5c6b3 100644
--- a/kmailcvt/filter_thebat.cxx
+++ b/kmailcvt/filter_thebat.cxx
@@ -44,7 +44,6 @@ FilterTheBat::FilterTheBat( void ) :
/** Destructor. */
FilterTheBat::~FilterTheBat( void )
{
- endImport();
}
/** Recursive import of The Bat! maildir. */
@@ -57,6 +56,7 @@ void FilterTheBat::import( FilterInfo *info )
kfd->setMode( KFile::Directory | KFile::LocalOnly );
kfd->exec();
mailDir = kfd->selectedFile();
+ delete kfd;
if ( mailDir.isEmpty() ) {
info->alert( i18n( "No directory selected." ) );
diff --git a/kmailcvt/filter_thunderbird.cxx b/kmailcvt/filter_thunderbird.cxx
index a9e091d9b..6ada68098 100644
--- a/kmailcvt/filter_thunderbird.cxx
+++ b/kmailcvt/filter_thunderbird.cxx
@@ -39,7 +39,6 @@ FilterThunderbird::FilterThunderbird(void) :
/** Destructor. */
FilterThunderbird::~FilterThunderbird(void)
{
- endImport();
}
/** Recursive import of Evolution's mboxes. */
@@ -60,6 +59,7 @@ void FilterThunderbird::import(FilterInfo *info)
kfd->setMode(KFile::Directory | KFile::LocalOnly);
kfd->exec();
mailDir = kfd->selectedFile();
+ delete kfd;
if (mailDir.isEmpty()) {
info->alert(i18n("No directory selected."));
diff --git a/kmailcvt/filters.cxx b/kmailcvt/filters.cxx
index 5e163e191..56e69d371 100644
--- a/kmailcvt/filters.cxx
+++ b/kmailcvt/filters.cxx
@@ -134,12 +134,12 @@ bool Filter::addMessage( FilterInfo* info, const TQString& folderName,
{
KURL msgURL;
msgURL.setPath( msgPath );
-
+
if ( !kapp->dcopClient()->isApplicationRegistered( "kmail" ) )
KApplication::startServiceByDesktopName( "kmail", TQString::null ); // Will wait until kmail is started
DCOPReply reply = DCOPRef( "kmail", "KMailIface" ).call( "dcopAddMessage", folderName, msgURL, msgStatusFlags );
-
+
if ( !reply.isValid() )
{
info->alert( i18n( "<b>Fatal:</b> Unable to start KMail for DCOP communication. "
@@ -170,7 +170,7 @@ bool Filter::addMessage_fastImport( FilterInfo* info, const TQString& folderName
{
KURL msgURL;
msgURL.setPath( msgPath );
-
+
if ( !kapp->dcopClient()->isApplicationRegistered( "kmail" ) )
KApplication::startServiceByDesktopName( "kmail", TQString::null ); // Will wait until kmail is started
@@ -197,17 +197,22 @@ bool Filter::addMessage_fastImport( FilterInfo* info, const TQString& folderName
return true;
}
-bool Filter::endImport()
+void Filter::showKMailImportArchiveDialog( FilterInfo* info )
{
- if ( !kapp->dcopClient()->isApplicationRegistered( "kmail" ) )
+ if ( !kapp->dcopClient()->isApplicationRegistered( "kmail" ) )
KApplication::startServiceByDesktopName( "kmail", TQString::null ); // Will wait until kmail is started
- DCOPReply reply = DCOPRef( "kmail", "KMailIface" ).call( "dcopAddMessage", TQString::null, TQString::null);
- if ( !reply.isValid() ) return false;
-
- reply = DCOPRef( "kmail", "KMailIface" ).call( "dcopResetAddMessage" );
- if ( !reply.isValid() ) return false;
+ DCOPReply reply = DCOPRef( "kmail", "KMailIface" ).call( "showImportArchiveDialog" );
+ if ( !reply.isValid() )
+ {
+ info->alert( i18n( "<b>Fatal:</b> Unable to start KMail for DCOP communication. "
+ "Make sure <i>kmail</i> is installed." ) );
+ }
+}
- return true;
+bool Filter::needsSecondPage()
+{
+ return true;
}
+
// vim: ts=2 sw=2 et
diff --git a/kmailcvt/filters.hxx b/kmailcvt/filters.hxx
index 203f3d7bb..dc51f8c94 100644
--- a/kmailcvt/filters.hxx
+++ b/kmailcvt/filters.hxx
@@ -67,10 +67,13 @@ class Filter
TQString author() const { return m_author; }
TQString name() const { return m_name; }
TQString info() const { return m_info; }
-
+
+ virtual bool needsSecondPage();
+
int count_duplicates; //to count all duplicate messages
-
+
protected:
+ void showKMailImportArchiveDialog( FilterInfo* info );
bool addMessage( FilterInfo* info,
const TQString& folder,
const TQString& msgFile,
@@ -79,7 +82,6 @@ class Filter
const TQString& folder,
const TQString& msgFile,
const TQString& msgStatusFlags = TQString());
- bool endImport();
private:
TQString m_name;
TQString m_author;
@@ -112,7 +114,7 @@ public:
for(unsigned int i=0; i<size; i++) d[i]=s[i];
} ;
- /** Assignment operator. Does the same thing as
+ /** Assignment operator. Does the same thing as
* the copy constructor.
*/
FolderStructureBase &operator =(const FolderStructureBase &s)
diff --git a/kmailcvt/kmailcvt.cpp b/kmailcvt/kmailcvt.cpp
index 08dabe830..d56577f4d 100644
--- a/kmailcvt/kmailcvt.cpp
+++ b/kmailcvt/kmailcvt.cpp
@@ -17,7 +17,9 @@
#include "kmailcvt.h"
#include <kaboutapplication.h>
#include <tqpushbutton.h>
-
+#include <dcopclient.h>
+#include <dcopref.h>
+#include <kdebug.h>
#include "filters.hxx"
KMailCVT::KMailCVT(TQWidget *parent, const char *name)
@@ -34,6 +36,19 @@ KMailCVT::KMailCVT(TQWidget *parent, const char *name)
}
KMailCVT::~KMailCVT() {
+ endImport();
+}
+
+void KMailCVT::endImport() {
+ if ( !kapp->dcopClient()->isApplicationRegistered( "kmail" ) )
+ KApplication::startServiceByDesktopName( "kmail", TQString::null ); // Will wait until kmail is started
+
+ DCOPReply reply = DCOPRef( "kmail", "KMailIface" ).call( "dcopAddMessage", TQString::null, TQString::null, TQString::null);
+ if ( !reply.isValid() )
+ return;
+ reply = DCOPRef( "kmail", "KMailIface" ).call( "dcopResetAddMessage" );
+ if ( !reply.isValid() )
+ return;
}
void KMailCVT::next() {
@@ -41,24 +56,33 @@ void KMailCVT::next() {
// Save selected filter
Filter *selectedFilter = selfilterpage->getSelectedFilter();
// without filter don't go next
- if (!selectedFilter)
+ if ( !selectedFilter )
return;
- // Goto next page
- KWizard::next();
- // Disable back & finish
- setBackEnabled( currentPage(), false );
- setFinishEnabled( currentPage(), false );
- // Start import
- FilterInfo *info = new FilterInfo(importpage, this, selfilterpage->removeDupMsg_checked());
- info->setStatusMsg(i18n("Import in progress"));
- info->clear(); // Clear info from last time
- selectedFilter->import(info);
- info->setStatusMsg(i18n("Import finished"));
- // Cleanup
- delete info;
- // Enable finish & back buttons
- setFinishEnabled( currentPage(), true );
- setBackEnabled( currentPage(), true );
+
+ if ( !selectedFilter->needsSecondPage() ) {
+ FilterInfo *info = new FilterInfo( importpage, this, selfilterpage->removeDupMsg_checked() );
+ selectedFilter->import( info );
+ accept();
+ delete info;
+ }
+ else {
+ // Goto next page
+ KWizard::next();
+ // Disable back & finish
+ setBackEnabled( currentPage(), false );
+ setFinishEnabled( currentPage(), false );
+ // Start import
+ FilterInfo *info = new FilterInfo(importpage, this, selfilterpage->removeDupMsg_checked());
+ info->setStatusMsg(i18n("Import in progress"));
+ info->clear(); // Clear info from last time
+ selectedFilter->import(info);
+ info->setStatusMsg(i18n("Import finished"));
+ // Cleanup
+ delete info;
+ // Enable finish & back buttons
+ setFinishEnabled( currentPage(), true );
+ setBackEnabled( currentPage(), true );
+ }
} else KWizard::next();
}
diff --git a/kmailcvt/kmailcvt.h b/kmailcvt/kmailcvt.h
index b4ff16ac5..34907bcc8 100644
--- a/kmailcvt/kmailcvt.h
+++ b/kmailcvt/kmailcvt.h
@@ -23,7 +23,7 @@
#include "kimportpage.h"
#include "kselfilterpage.h"
-
+
/** KMailCVT is the base class of the project */
class KMailCVT : public KWizard {
Q_OBJECT
@@ -36,6 +36,7 @@ public:
public slots:
void help();
private:
+ void endImport();
KSelFilterPage* selfilterpage;
KImportPage* importpage;
};
diff --git a/kmailcvt/kselfilterpage.cpp b/kmailcvt/kselfilterpage.cpp
index a3f1a9b9d..b8af0d0b3 100644
--- a/kmailcvt/kselfilterpage.cpp
+++ b/kmailcvt/kselfilterpage.cpp
@@ -32,6 +32,7 @@
#include "filter_opera.hxx"
#include "filter_thunderbird.hxx"
#include "filter_kmail_maildir.hxx"
+#include "filter_kmail_archive.hxx"
#include "filter_sylpheed.hxx"
#include "filter_thebat.hxx"
#include "filter_lnotes.hxx"
@@ -49,6 +50,8 @@ KSelFilterPage::KSelFilterPage(TQWidget *parent, const char *name ) : KSelFilter
// For now, we have to live without the warm and fuzzy feeling a refactoring might give.
// Patches appreciated. (danimo)
+ addFilter(new FilterKMailArchive);
+ addFilter(new FilterMBox);
addFilter(new FilterEvolution);
addFilter(new FilterEvolution_v2);
addFilter(new FilterKMail_maildir);
@@ -60,7 +63,6 @@ KSelFilterPage::KSelFilterPage(TQWidget *parent, const char *name ) : KSelFilter
addFilter(new FilterOE);
// addFilter(new FilterOutlook);
addFilter(new FilterPMail);
- addFilter(new FilterMBox);
addFilter(new FilterLNotes);
addFilter(new FilterPlain);
}
diff --git a/kmailcvt/main.cpp b/kmailcvt/main.cpp
index aea1edde5..87ab0c819 100644
--- a/kmailcvt/main.cpp
+++ b/kmailcvt/main.cpp
@@ -48,8 +48,10 @@ int main(int argc, char *argv[])
DCOPClient *client=a.dcopClient();
if (!client->attach()) {
+ delete kmailcvt;
return 1;
}
-
- return a.exec();
+ int ret = a.exec();
+ delete kmailcvt;
+ return ret;
}
diff --git a/kmobile/devices/digicam/libkmobile_digicam.desktop b/kmobile/devices/digicam/libkmobile_digicam.desktop
index b00b8d702..adb3c9ab9 100644
--- a/kmobile/devices/digicam/libkmobile_digicam.desktop
+++ b/kmobile/devices/digicam/libkmobile_digicam.desktop
@@ -27,7 +27,6 @@ Name[hu]=Fényképezőgép
Name[is]=Stafræn myndavél
Name[it]=Macchina fotografica digitale
Name[ja]=デジタルカメラ
-Name[ka]=ციფრული კამერა
Name[kk]=Цифрлық камера
Name[km]=ម៉ាស៊ីន​ថត​រូប​ឌីជីថល
Name[lt]=Skaitmeninė kamera
@@ -54,8 +53,7 @@ Name[ta]=டிஜிடல் காமரா
Name[tg]=Камераи digital
Name[tr]=Dijital Kamera
Name[uk]=Цифровий фотоапарат
-Name[uz]=Fotoaparat
-Name[uz@cyrillic]=Фотоапарат
+Name[uz]=Фотоапарат
Name[zh_CN]=数码相机
Name[zh_TW]=數位相機
Comment=This driver supports many digital cameras
@@ -82,7 +80,6 @@ Comment[hu]=Ez a meghajtó különféle digitális fényképezőgépek kezelés
Comment[is]=Þessi rekill styður margar stafrænar myndavélar
Comment[it]=Questo driver supporta molte fotocamere digitali
Comment[ja]=このドライバは多種のデジタルカメラをサポートします
-Comment[ka]=ეს დრაივერი უჭერს მხარს მრავალ ციფრულ კამერას
Comment[kk]=Бұл бірспыра цифрлық камераларды қамтитын драйвер
Comment[km]=កម្មវិធី​បញ្ជា​នេះ​គាំទ្រ​ម៉ាស៊ីន​ថត​រូប​ឌីជីថល​ជាច្រើន
Comment[lt]=Ši tvarkyklė palaiko daugelį skaitmeninių kamerų
diff --git a/kmobile/devices/gammu/libkmobile_gammu.desktop b/kmobile/devices/gammu/libkmobile_gammu.desktop
index 4dd6e5060..925e6facd 100644
--- a/kmobile/devices/gammu/libkmobile_gammu.desktop
+++ b/kmobile/devices/gammu/libkmobile_gammu.desktop
@@ -27,7 +27,6 @@ Name[hu]=Mobiltelefon/határidőnapló-kezelő (Gammu)
Name[is]=Farsími eða lófatölva (gammu)
Name[it]=Organizer o telefono cellulare (gammu)
Name[ja]=携帯電話またはスケジュール管理 (gammu)
-Name[ka]=მობილური ტელეფონი ან ორგანიზატორი(gammu)
Name[kk]=Қалта телефон не Ұйымдастырғыш (gammu)
Name[km]=កម្មវិធី​រៀបចំ​ទូរស័ព្ទ​ចល័ត (gammu)
Name[lt]=Mobilus telefonas ar asmeninės info tvarkyklė (gammu)
@@ -50,8 +49,7 @@ Name[ta]=செல்பேசி அல்லது ஒருங்கிணை
Name[tg]=Телефони мобилӣ ё органайзер (gammu)
Name[tr]=Cep Telefonu ya da Organizer (gammu)
Name[uk]=Мобільний телефон та тижневик (gammu)
-Name[uz]=Uyali telefon yoki organayzer (gammu)
-Name[uz@cyrillic]=Уяли телефон ёки органайзер (gammu)
+Name[uz]=Уяли телефон ёки органайзер (gammu)
Name[zh_CN]=移动电话或 PDA(gammu)
Name[zh_TW]=行動電話或數位助理(gammu)
Comment=This driver supports many NOKIA and other mobile phones via the gammu library
@@ -78,7 +76,6 @@ Comment[hu]=Ez a meghajtó mobiltelefonok (elsősorban Nokia gyártmányúak) ke
Comment[is]=Þessi rekill styður marga NOKIA og aðra farsíma gegnum gammu aðgerðasafnið
Comment[it]=Questo driver supporta molti NOKIA e altri telefoni cellulari tramite la libreria gammu.
Comment[ja]=このドライバは gammu ライブラリを介して NOKIA および他社製の携帯電話を幅広くサポートします
-Comment[ka]=ეს დრაივერი მხარს უჭერს Nokia-ს მრავალ და სხვა ტელეფონებს gammu ბიბლიოთეკის საშუალებით
Comment[kk]=Бұл көп NOKIA мен басқа қалта құрылғыларды, gammu жиыны арқылы, қамтитын драйвер
Comment[km]=កម្មវិធី​បញ្ជា​នេះ​គាំទ្រ​ប្រភេទ​ទូរស័ព្ទ​ណូគៀ និងទូរស័ព្ទ​ផ្សេងៗ​ទៀត​ជាច្រើន​តាម​រយៈ​បណ្ណាល័យ gammu
Comment[lt]=Ši tvarkyklė palaiko daugelį NOKIA ir kitų telefonų pasinaudodama gammu biblioteka
@@ -88,7 +85,7 @@ Comment[nds]=Disse Driever ünnerstütt vele Nokia- un anner Mobiltelefonen öve
Comment[ne]=यो ड्राइभरले गामु लाइब्रेरीबाट धेरै नोकिया र अन्य मोबाइल फोन समर्थन गर्छ
Comment[nl]=Dit stuurprogramma biedt ondersteuning voor veel Nokia- en andere mobiele telefoons via de gammu-bibliotheek
Comment[nn]=Denne drivaren støttar mange NOKIA og andre mobiltelefonar via gammu-biblioteket
-Comment[pl]=Ten sterownik obsługuje wiele telefonów komórkowych Nokia i innych za pomocą biblioteki gammu
+Comment[pl]=Ten sterownik obsługuje wiele telefonów komórkowychNokia i innych za pomocą biblioteki gammu
Comment[pt]=Este controlador suportar muitos NOKIAs, bem como outros telemóveis, com a biblioteca 'gammu'
Comment[pt_BR]=Este driver suporta muitos telefones móveis, NOKIA e outros, via biblioteca gammu
Comment[ru]=Этот драйвер поддерживает множество моделей мобильных телефонов Nokia и других производителей через библиотеку gammu
diff --git a/kmobile/devices/gnokii/libkmobile_gnokii.desktop b/kmobile/devices/gnokii/libkmobile_gnokii.desktop
index 6479e480a..f6ec4b96e 100644
--- a/kmobile/devices/gnokii/libkmobile_gnokii.desktop
+++ b/kmobile/devices/gnokii/libkmobile_gnokii.desktop
@@ -27,7 +27,6 @@ Name[hu]=Mobiltelefon/határidőnapló-kezelő (Gnokii)
Name[is]=Farsími eða lófatölva (gnokii)
Name[it]=Telefono cellulare o organizer (gnokii)
Name[ja]=携帯電話またはスケジュール管理 (gnokii)
-Name[ka]=მობილური ტელეფონი ან ორგანიზატორი(gnokii)
Name[kk]=Қалта телефон не Ұйымдастырғыш (gnokii)
Name[km]=កម្មវិធី​រៀបចំ​ទូរស័ព្ទ​ចល័ត (gnokii)
Name[lt]=Mobilus telefonas ar asmeninės info tvarkyklė (gnokii)
@@ -50,8 +49,7 @@ Name[ta]=செல்பேசி அல்லது ஒருங்கிணை
Name[tg]=Телефони мобилӣ ё органайзери (gnokii)
Name[tr]=Cep Telefonu ya da Organizer (gnokii)
Name[uk]=Мобільний телефон та тижневик (gnokii)
-Name[uz]=Uyali telefon yoki organayzer (gnokii)
-Name[uz@cyrillic]=Уяли телефон ёки органайзер (gnokii)
+Name[uz]=Уяли телефон ёки органайзер (gnokii)
Name[zh_CN]=移动电话或 PDA(gnokii)
Name[zh_TW]=行動電話或數位助理(gnokii)
Comment=This driver supports many NOKIA and other mobile phones via the gnokii library
@@ -78,7 +76,6 @@ Comment[hu]=Ez a meghajtó mobiltelefonok (elsősorban Nokia gyártmányúak) ke
Comment[is]=Þessi rekill styður marga farsíma frá NOKIA og fleiri gegnum gnokii aðgerðasafnið
Comment[it]=Questo driver supporta molti NOKIA e altri telefoni cellulari tramite la libreria gnokii
Comment[ja]=このドライバは gnokii ライブラリを介して NOKIA および他社製の携帯電話を幅広くサポートします
-Comment[ka]=ეს დრაივერი მხარს უჭერს Nokia-ს მრავალ და სხვა ტელეფონებს gnokii ბიბლიოთეკის საშუალებით
Comment[kk]=Бұл көп NOKIA мен басқа қалта құрылғыларды, gnokii жиыны арқылы, қамтитын драйвер
Comment[km]=កម្មវិធី​បញ្ជា​នេះ​គាំទ្រ​ប្រភេទ​ទូរស័ព្ទ​ណូគៀ និង​ទូរស័ព្ទ​ផ្សេងៗ​ទៀត​ជាច្រើន​តាម​រយៈ​បណ្ណាល័យ gnokii
Comment[lt]=Ši tvarkyklė palaiko daugelį NOKIA ir kitų telefonų pasinaudodama gnokii biblioteka
@@ -88,7 +85,7 @@ Comment[nds]=Disse Driever ünnerstütt vele Nokia- un anner Mobiltelefonen öve
Comment[ne]=यो ड्राइभरले जिनोकी लाइब्रेरीबाट धेरै नोकिया र अन्य मोबाइल फोन समर्थन गर्छ
Comment[nl]=Dit stuurprogramma biedt ondersteuning voor veel Nokia- en andere mobiele telefoons via de gnokii-bibliotheek
Comment[nn]=Denne drivaren støttar mange NOKIA og andre mobiltelefonar via gnokii-biblioteket
-Comment[pl]=Ten sterownik obsługuje wiele telefonów komórkowych Nokia i innych za pomocą biblioteki gnokii
+Comment[pl]=Ten sterownik obsługuje wiele telefonów komórkowychNokia i innych za pomocą biblioteki gnokii
Comment[pt]=Este controlador suportar muitos NOKIAs, bem como outros telemóveis, com a biblioteca 'gnokii'
Comment[pt_BR]=Este driver suporta muitos telefones móveis, NOKIA e outros, via biblioteca gnokii
Comment[ru]=Этот драйвер поддерживает множество моделей мобильных телефонов Nokia и других производителей через библиотеку gnokii
diff --git a/kmobile/devices/skeleton/libkmobile_skeleton.desktop b/kmobile/devices/skeleton/libkmobile_skeleton.desktop
index 06f59c101..72943d15a 100644
--- a/kmobile/devices/skeleton/libkmobile_skeleton.desktop
+++ b/kmobile/devices/skeleton/libkmobile_skeleton.desktop
@@ -26,7 +26,6 @@ Name[hu]=Skeleton eszköz
Name[is]=Grunntæki
Name[it]=Dispositivo skeleton
Name[ja]=スケルトンデバイス
-Name[ka]=მოწყობილობის ჩონჩხი
Name[kk]=Қаңқалы құрылғы
Name[km]=ឧបករណ៍​គ្រោង
Name[lt]=Įrenginio skeletas
@@ -78,7 +77,6 @@ Comment[hu]=Hordozható skeleton eszköz
Comment[is]=Grunn farsími eða lófatölva
Comment[it]=Dispositivo portatile skeleton
Comment[ja]=モバイルスケルトンデバイス
-Comment[ka]=მობილურის ჩონჩხის მოწყობილობა
Comment[kk]=Қалта қаңқалы құрылғы
Comment[km]=ឧបករណ៍​គ្រោង​ចល័ត
Comment[lt]=Mobilaus įrenginio skeletas
diff --git a/kmobile/kioslave/mimetypes/mobile_addressbook.desktop b/kmobile/kioslave/mimetypes/mobile_addressbook.desktop
index 53a041c1f..44c03dafd 100644
--- a/kmobile/kioslave/mimetypes/mobile_addressbook.desktop
+++ b/kmobile/kioslave/mimetypes/mobile_addressbook.desktop
@@ -26,7 +26,6 @@ Comment[hu]=Címbejegyzések a mobiltelefonon
Comment[is]=Tengiliðir í farsíma eða lófatölvu
Comment[it]=Contatti nel dispositivo portatile
Comment[ja]=モバイル機器内の連絡先
-Comment[ka]=კონტაქტები მობილურ მოწყობილობაზ
Comment[kk]=Қалта құрылғыдағы контакттар
Comment[km]=ទំនាក់​ទំនង​ក្នុង​ឧបករណ៍​ចល័ត
Comment[lt]=Kontaktai mobiliajame įrenginyje
diff --git a/kmobile/kioslave/mimetypes/mobile_calendar.desktop b/kmobile/kioslave/mimetypes/mobile_calendar.desktop
index 35fa7b9ba..935e0d885 100644
--- a/kmobile/kioslave/mimetypes/mobile_calendar.desktop
+++ b/kmobile/kioslave/mimetypes/mobile_calendar.desktop
@@ -26,7 +26,6 @@ Comment[hu]=Naptár a mobiltelefonon
Comment[is]=Dagatal í farsíma eða lófatölvu
Comment[it]=Calendari nel dispositivo portatile
Comment[ja]=モバイル機器内のカレンダー
-Comment[ka]=კალენდარი მობილურ მოწყობილობაზე
Comment[kk]=Қалта құрылғыдағы күнтізбе
Comment[km]=ប្រតិទិន​ក្នុង​ឧបករណ៍​ចល័ត
Comment[lt]=Kalendorius mobiliajame įrenginyje
diff --git a/kmobile/kioslave/mimetypes/mobile_device.desktop b/kmobile/kioslave/mimetypes/mobile_device.desktop
index 025d5d5d8..4462b124d 100644
--- a/kmobile/kioslave/mimetypes/mobile_device.desktop
+++ b/kmobile/kioslave/mimetypes/mobile_device.desktop
@@ -28,7 +28,6 @@ Comment[hu]=Mobil eszköz
Comment[is]=Farsími eða lófatölva
Comment[it]=Dispositivo portatile
Comment[ja]=モバイル機器
-Comment[ka]=მობილური მოწყობილობა
Comment[kk]=Қалта құрылғысы
Comment[km]=ឧបករណ៍​ចល័ត
Comment[lt]=Mobilusis įrenginys
diff --git a/kmobile/kioslave/mimetypes/mobile_notes.desktop b/kmobile/kioslave/mimetypes/mobile_notes.desktop
index 12dc25c0c..fa68bad6f 100644
--- a/kmobile/kioslave/mimetypes/mobile_notes.desktop
+++ b/kmobile/kioslave/mimetypes/mobile_notes.desktop
@@ -25,7 +25,6 @@ Comment[hu]=Feljegyzések a mobiltelefonon
Comment[is]=Áminningar í farsíma eða lófatölvu
Comment[it]=Note nel dispositivo portatile
Comment[ja]=モバイル機器内のメモ
-Comment[ka]=ჩანიშვნები მობილურ ტელეფონზე
Comment[kk]=Қалта құрылғыдағы жазбалар
Comment[km]=ចំណាំ​ក្នុង​ឧបករណ៍​ចល័ត
Comment[lt]=Užrašai mobiliajame įrenginyje
diff --git a/kmobile/kmobile.desktop b/kmobile/kmobile.desktop
index f8f0d5a10..aac1904ab 100644
--- a/kmobile/kmobile.desktop
+++ b/kmobile/kmobile.desktop
@@ -43,7 +43,6 @@ GenericName[hu]=Mobilkezelő
GenericName[is]=Sýsla með lófatölvur og farsíma
GenericName[it]=Gestisce dispositivi portatili
GenericName[ja]=モバイル機器の管理
-GenericName[ka]=მობილური მოწყობილობების მართვა
GenericName[kk]=Қалта құрылғыларды басқару
GenericName[km]=គ្រប់គ្រង​ឧបករណ៍​ចល័ត
GenericName[lt]=Mobiliųjų įrenginių tvarkymas
@@ -99,7 +98,6 @@ Comment[hu]=KDE-alapú mobiltelefon-kezelő
Comment[is]=KDE stjórnforrit fyrir lófatölvur og farsíma
Comment[it]=Un gestore di dispositivi portatili di KDE
Comment[ja]=KDE モバイル機器マネージャ
-Comment[ka]=KDE-ს მობილურ მოწყობილობათა მმართველი
Comment[kk]=KDE-нің қалта құрылғылар менеджері
Comment[km]=កម្មវិធី​គ្រប់គ្រង​ឧបករណ៍​ចល័ត KDE
Comment[lt]=KDE mobiliųjų įrenginių tvarkyklė
diff --git a/kmobile/libkmobile.desktop b/kmobile/libkmobile.desktop
index 6f195ed94..b6444d2a8 100644
--- a/kmobile/libkmobile.desktop
+++ b/kmobile/libkmobile.desktop
@@ -24,7 +24,6 @@ Name[hu]=Alacsony szintű KDE-s eszközmeghajtó mobiltelefonok kezeléséhez
Name[is]=Hrár KDE vélbúnaðarrekill fyrir farsíma og lófatölvur
Name[it]=KDE driver hardware di basso livello per dispositivi portatili
Name[ja]=KDE モバイル機器低レベルハードウェアドライバ
-Name[ka]=KDE მობილური მოწყობილობის დაბალდონიანი ხისტი დრაივერი
Name[kk]=KDE-нің қалта құрылғы жабдықтың төмен деңгейлі драйвері
Name[km]=កម្មវិធី​បញ្ជា​ផ្នែករឹង​កម្រិត​ទាប​របស់​ឧបករណ៍​ចល័ត KDE
Name[lt]=KDE mobiliųjų įrenginių žemo lygmens aparatinės įrangos tvarkyklė
diff --git a/knode/KNode.desktop b/knode/KNode.desktop
index dda0bb6b9..99e5d8674 100644
--- a/knode/KNode.desktop
+++ b/knode/KNode.desktop
@@ -44,7 +44,6 @@ GenericName[id]=Pembaca Berita
GenericName[is]=Fréttaforrit
GenericName[it]=Lettore newsgroup
GenericName[ja]=ニュースリーダー
-GenericName[ka]=სიახლეების წამკითხველი
GenericName[kk]=Жаңалықтарды оқу құралы
GenericName[km]=កម្មវិធី​អាន​ព័ត៌មាន
GenericName[lt]=Naujienų skaityklė
diff --git a/knode/articlewidget.cpp b/knode/articlewidget.cpp
index 1bb7527fe..357a9c009 100644
--- a/knode/articlewidget.cpp
+++ b/knode/articlewidget.cpp
@@ -278,10 +278,12 @@ void ArticleWidget::disableActions()
void ArticleWidget::readConfig()
{
- mFixedFontToggle->setChecked( knGlobals.configManager()->readNewsViewer()->useFixedFont() );
- mFancyToggle->setChecked( knGlobals.configManager()->readNewsViewer()->interpretFormatTags() );
+ KNConfigManager *cfgMgr = knGlobals.configManager();
- mShowHtml = knGlobals.configManager()->readNewsViewer()->alwaysShowHTML();
+ mFixedFontToggle->setChecked( cfgMgr->readNewsViewer()->useFixedFont() );
+ mFancyToggle->setChecked( cfgMgr->readNewsViewer()->interpretFormatTags() );
+
+ mShowHtml = cfgMgr->readNewsViewer()->alwaysShowHTML();
KConfig *conf = knGlobals.config();
conf->setGroup( "READNEWS" );
@@ -296,7 +298,7 @@ void ArticleWidget::readConfig()
delete mCSSHelper;
mCSSHelper = new CSSHelper( TQPaintDeviceMetrics( mViewer->view() ) );
- if ( !knGlobals.configManager()->readNewsGeneral()->autoMark() )
+ if ( !cfgMgr->readNewsGeneral()->autoMark() )
mTimer->stop();
}
@@ -312,8 +314,9 @@ void ArticleWidget::writeConfig()
conf->writeEntry( "attachmentStyle", mAttachmentStyle );
conf->writeEntry( "headerStyle", mHeaderStyle );
- knGlobals.configManager()->readNewsViewer()->setUseFixedFont( mFixedFontToggle->isChecked() );
- knGlobals.configManager()->readNewsViewer()->setInterpretFormatTags( mFancyToggle->isChecked() );
+ KNConfigManager *cfgMgr = knGlobals.configManager();
+ cfgMgr->readNewsViewer()->setUseFixedFont( mFixedFontToggle->isChecked() );
+ cfgMgr->readNewsViewer()->setInterpretFormatTags( mFancyToggle->isChecked() );
}
@@ -324,7 +327,8 @@ void ArticleWidget::setArticle( KNArticle *article )
if ( mArticle && mArticle->isOrphant() )
delete mArticle;
- mShowHtml = knGlobals.configManager()->readNewsViewer()->alwaysShowHTML();
+ KNConfigManager *cfgMgr = knGlobals.configManager();
+ mShowHtml = cfgMgr->readNewsViewer()->alwaysShowHTML();
mRot13 = false;
mRot13Toggle->setChecked( false );
mTimer->stop();
@@ -380,7 +384,8 @@ void ArticleWidget::displayArticle()
mArticle->setForceDefaultCS( mForceCharset );
}
- KNConfig::ReadNewsViewer *rnv = knGlobals.configManager()->readNewsViewer();
+ KNConfigManager *cfgMgr = knGlobals.configManager();
+ KNConfig::ReadNewsViewer *rnv = cfgMgr->readNewsViewer();
removeTempFiles();
mViewer->begin();
@@ -460,12 +465,12 @@ void ArticleWidget::displayArticle()
mViewer->write( i18n("<br/><b>This article has the MIME type &quot;message/partial&quot;, which KNode cannot handle yet.<br>Meanwhile you can save the article as a text file and reassemble it by hand.</b>") );
}
- // display body text
+ // display body text
if ( text && text->hasContent() && !ct->isPartial() ) {
// handle HTML messages
if ( text->contentType()->isHTMLText() ) {
TQString htmlTxt;
- text->decodedText( htmlTxt, true, knGlobals.configManager()->readNewsViewer()->removeTrailingNewlines() );
+ text->decodedText( htmlTxt, true, cfgMgr->readNewsViewer()->removeTrailingNewlines() );
if ( mShowHtml ) {
// strip </html> & </body>
int i = kMin( htmlTxt.findRev( "</html>", -1, false ), htmlTxt.findRev( "</body>", -1, false ) );
@@ -487,7 +492,7 @@ void ArticleWidget::displayArticle()
else {
if ( !containsPGP ) {
TQStringList lines;
- text->decodedText( lines, true, knGlobals.configManager()->readNewsViewer()->removeTrailingNewlines() );
+ text->decodedText( lines, true, cfgMgr->readNewsViewer()->removeTrailingNewlines() );
displayBodyBlock( lines );
}
}
@@ -508,8 +513,8 @@ void ArticleWidget::displayArticle()
mViewer->end();
enableActions();
- if( mArticle->type() == KMime::Base::ATremote && knGlobals.configManager()->readNewsGeneral()->autoMark() )
- mTimer->start( knGlobals.configManager()->readNewsGeneral()->autoMarkSeconds() * 1000, true );
+ if( mArticle->type() == KMime::Base::ATremote && cfgMgr->readNewsGeneral()->autoMark() )
+ mTimer->start( cfgMgr->readNewsGeneral()->autoMarkSeconds() * 1000, true );
}
@@ -527,7 +532,8 @@ void ArticleWidget::displayErrorMessage( const TQString &msg )
mViewer->end();
// mark article as read if there is a negative reply from the server
- if ( knGlobals.configManager()->readNewsGeneral()->autoMark() &&
+ KNConfigManager *cfgMgr = knGlobals.configManager();
+ if ( cfgMgr->readNewsGeneral()->autoMark() &&
mArticle && mArticle->type() == KMime::Base::ATremote && !mArticle->isOrphant() &&
( msg.find("430") != -1 || msg.find("423") != -1 ) ) {
KNRemoteArticle::List l;
@@ -569,7 +575,8 @@ void ArticleWidget::displayHeader()
// standard & fancy header style
KMime::Headers::Base *hb;
- TQValueList<KNDisplayedHeader*> dhs = knGlobals.configManager()->displayedHeaders()->headers();
+ KNConfigManager *cfgMgr = knGlobals.configManager();
+ TQValueList<KNDisplayedHeader*> dhs = cfgMgr->displayedHeaders()->headers();
for ( TQValueList<KNDisplayedHeader*>::Iterator it = dhs.begin(); it != dhs.end(); ++it ) {
KNDisplayedHeader *dh = (*it);
hb = mArticle->getHeaderByType(dh->header().latin1());
@@ -648,7 +655,7 @@ void ArticleWidget::displayHeader()
// references
KMime::Headers::References *refs = mArticle->references( false );
if ( mArticle->type() == KMime::Base::ATremote && refs
- && knGlobals.configManager()->readNewsViewer()->showRefBar() ) {
+ && cfgMgr->readNewsViewer()->showRefBar() ) {
html += "<div class=\"spamheader\">";
int refCnt = refs->count(), i = 1;
TQCString id = refs->first();
@@ -674,7 +681,8 @@ void ArticleWidget::displayBodyBlock( const TQStringList &lines )
int oldLevel = -2, newLevel = -2;
bool isSig = false;
TQString line, html;
- KNConfig::ReadNewsViewer *rnv = knGlobals.configManager()->readNewsViewer();
+ KNConfigManager *cfgMgr = knGlobals.configManager();
+ KNConfig::ReadNewsViewer *rnv = cfgMgr->readNewsViewer();
TQString quoteChars = rnv->quoteCharacters().simplifyWhiteSpace();
if (quoteChars.isEmpty())
quoteChars = ">";
@@ -1160,7 +1168,8 @@ void ArticleWidget::slotURLClicked( const KURL &url, bool forceOpen)
if ( !c )
return;
// TODO: replace with message box as done in KMail
- if ( forceOpen || knGlobals.configManager()->readNewsViewer()->openAttachmentsOnClick() )
+ KNConfigManager *cfgMgr = knGlobals.configManager();
+ if ( forceOpen || cfgMgr->readNewsViewer()->openAttachmentsOnClick() )
knGlobals.articleManager()->openContent( c );
else
knGlobals.articleManager()->saveContentToFile( c, this );
diff --git a/knode/kncomposer.cpp b/knode/kncomposer.cpp
index 111bdf19e..53520e29d 100644
--- a/knode/kncomposer.cpp
+++ b/knode/kncomposer.cpp
@@ -2069,7 +2069,7 @@ bool KNComposer::Editor::eventFilter(TQObject*o, TQEvent* e)
}
else
{
- p.insertItem( TQString::fromLatin1("No Suggestions"), -2 );
+ p.insertItem( i18n( "No Suggestions" ), -2 );
}
//Execute the popup inline
diff --git a/knode/knglobals.cpp b/knode/knglobals.cpp
index be9bb1488..eaf026e8d 100644
--- a/knode/knglobals.cpp
+++ b/knode/knglobals.cpp
@@ -32,6 +32,33 @@
#include "knmainwidget.h"
#include "knwidgets.h"
+KNGlobals::KNGlobals() :
+ mNetAccess( 0 ),
+ mCfgManager( 0 ),
+ mAccManager( 0 ),
+ mGrpManager( 0 ),
+ mArtManager( 0 ),
+ mFilManager( 0 ),
+ mFolManager( 0 ),
+ mMemManager( 0 )
+{
+}
+
+KNGlobals::~KNGlobals( )
+{
+#if 0
+// hmm.. something in here is causing an 'impossible' crash. let's ignore the cleanup then.
+ delete mNetAccess;
+ delete mCfgManager;
+ delete mAccManager;
+ delete mGrpManager;
+ delete mArtManager;
+ delete mFilManager;
+ delete mFolManager;
+ delete mMemManager;
+#endif
+}
+
KConfig* KNGlobals::config()
{
if (!c_onfig) {
diff --git a/knode/knglobals.h b/knode/knglobals.h
index 3a6aa10a1..605f956c6 100644
--- a/knode/knglobals.h
+++ b/knode/knglobals.h
@@ -51,6 +51,9 @@ namespace KNode {
(knode.h isn't include everywhere) */
class KDE_EXPORT KNGlobals {
public:
+ KNGlobals();
+ ~KNGlobals();
+
/** topWidget == top, used for message boxes, */
TQWidget *topWidget;
/** no need to include knode.h everywhere */
diff --git a/knode/knode_config_accounts.desktop b/knode/knode_config_accounts.desktop
index 9d0716f64..f311b260d 100644
--- a/knode/knode_config_accounts.desktop
+++ b/knode/knode_config_accounts.desktop
@@ -39,7 +39,6 @@ Name[hu]=Fiókok
Name[is]=Tengingar
Name[it]=Account
Name[ja]=アカウント
-Name[ka]=ანგარიშები
Name[kk]=Тіркелгілері
Name[km]=គណនី
Name[lt]=Paskyros
@@ -64,8 +63,7 @@ Name[ta]=கணக்குகள்
Name[tg]=Қайдҳои баҳисобгирӣ
Name[tr]=Hesaplar
Name[uk]=Рахунки
-Name[uz]=Hisoblar
-Name[uz@cyrillic]=Ҳисоблар
+Name[uz]=Ҳисоблар
Name[zh_CN]=账户
Name[zh_TW]=帳號
Comment=Setup for Newsgroup and Mail Servers
@@ -89,7 +87,6 @@ Comment[hu]=Hír- és levelezési kiszolgálók beállítása
Comment[is]=Uppsetning fyrir fréttahópa og póstþjóna
Comment[it]=Impostazioni per newsgroup e server di posta
Comment[ja]=ニュースグループとメールサーバの設定
-Comment[ka]=სიახლეთა ჯგუფებისა და საფოსტო სერვერის კონფიგურაცია
Comment[kk]=Жаңалық топтар мен Пошта серверлері
Comment[km]=រៀបចំម៉ាស៊ីន​បម្រើ​វេទិកា​ព័ត៌មាន និង​សំបុត្រ
Comment[lt]=Naujienų grupių ir pašto serverių nustatymai
diff --git a/knode/knode_config_appearance.desktop b/knode/knode_config_appearance.desktop
index bbd2ec26d..2e734de40 100644
--- a/knode/knode_config_appearance.desktop
+++ b/knode/knode_config_appearance.desktop
@@ -39,7 +39,6 @@ Name[hu]=Megjelenés
Name[is]=Útlit
Name[it]=Aspetto
Name[ja]=外観
-Name[ka]=იერსახე
Name[kk]=Сыртқы көрінісі
Name[km]=រូបរាង
Name[ko]=모양
@@ -66,8 +65,7 @@ Name[ta]=தோற்றம்
Name[tg]=Намуди зоҳирӣ
Name[tr]=Görünüm
Name[uk]=Вигляд
-Name[uz]=Koʻrinishi
-Name[uz@cyrillic]=Кўриниши
+Name[uz]=Кўриниши
Name[zh_CN]=外观
Comment=Customize Visual Appearance
Comment[af]=Pasmaak die visuele voorkoms
@@ -93,7 +91,6 @@ Comment[hu]=A grafikai megjelenés testreszabása
Comment[is]=Stilla útlit
Comment[it]=Personalizza l'aspetto
Comment[ja]=外観をカスタマイズ
-Comment[ka]=ვიზუალური იერსახის დაყენება
Comment[kk]=Сыртқы көрінісін ыңғайлау
Comment[km]=ប្ដូរ​រូបរាង​មើល​ឃើញ​តាម​បំណង
Comment[lt]=Derinti vizualinę išvaizdą
diff --git a/knode/knode_config_cleanup.desktop b/knode/knode_config_cleanup.desktop
index 5f08bbe29..e6afc8cca 100644
--- a/knode/knode_config_cleanup.desktop
+++ b/knode/knode_config_cleanup.desktop
@@ -35,7 +35,6 @@ Name[hu]=Tisztítás
Name[is]=Hreinsun
Name[it]=Pulizia
Name[ja]=整理
-Name[ka]=გაწმენდა
Name[kk]=Тазалау
Name[km]=សម្អាត
Name[lt]=Išvalymas
@@ -85,7 +84,6 @@ Comment[hu]=A lemezterület megőrzése
Comment[is]=Varðveita diskpláss
Comment[it]=Risparmia lo spazio su disco
Comment[ja]=ディスクスペースを維持
-Comment[ka]=სივრცის შენახვა დისკზე
Comment[kk]=Дискідегі орынды үнемдеу
Comment[km]=បង្ការ​ទំហំ​ថាស
Comment[lt]=Disko erdvės išsaugojimas
diff --git a/knode/knode_config_identity.desktop b/knode/knode_config_identity.desktop
index 2fda0f69b..f7c0fae9c 100644
--- a/knode/knode_config_identity.desktop
+++ b/knode/knode_config_identity.desktop
@@ -38,7 +38,6 @@ Name[hu]=Azonosító
Name[is]=Auðkenni
Name[it]=Identità
Name[ja]=個人情報
-Name[ka]=პროფილი
Name[kk]=Іс-әлпеті
Name[km]=អត្តសញ្ញាណ
Name[lt]=Tapatybė
@@ -63,8 +62,7 @@ Name[ta]=அடையாளம்
Name[tg]=Профил
Name[tr]=Kimlik
Name[uk]=Профіль
-Name[uz]=Shaxsiyat
-Name[uz@cyrillic]=Шахсият
+Name[uz]=Шахсият
Name[zh_CN]=身份
Name[zh_TW]=身份
Comment=Personal Information
@@ -94,7 +92,6 @@ Comment[hu]=Személyi adatok
Comment[is]=Persónuupplýsingar
Comment[it]=Informazioni personali
Comment[ja]=個人の情報
-Comment[ka]=პირადი ინფორმაცია
Comment[kk]=Дербес мәліметтер
Comment[km]=ព័ត៌មាន​ផ្ទាល់​ខ្លួន
Comment[lt]=Asmeninė informacija
diff --git a/knode/knode_config_post_news.desktop b/knode/knode_config_post_news.desktop
index 784b7c39c..8d1658b11 100644
--- a/knode/knode_config_post_news.desktop
+++ b/knode/knode_config_post_news.desktop
@@ -33,7 +33,6 @@ Name[hu]=Hírek írása
Name[is]=Senda fréttir
Name[it]=Invio news
Name[ja]=ニュースを投稿
-Name[ka]=სიახლეების განთავსება
Name[kk]=Жариялау
Name[km]=ប្រកាស​ព័ត៌មាន​
Name[lt]=Naujienų skelbimas
diff --git a/knode/knode_config_privacy.desktop b/knode/knode_config_privacy.desktop
index 21bdddb6f..e2ab8fcfc 100644
--- a/knode/knode_config_privacy.desktop
+++ b/knode/knode_config_privacy.desktop
@@ -34,7 +34,6 @@ Name[hu]=Aláírás/ellenőrzés
Name[is]=Undirrita/staðfesta
Name[it]=Firma/verifica
Name[ja]=署名/検証
-Name[ka]=ხელმოწერა/დამოწმება
Name[kk]=Қолтаңбалау/Тексеру
Name[km]=ចុះហត្ថលេខា/ផ្ទៀងផ្ទាត់
Name[lt]=Pasirašoma/tikrinama
@@ -81,7 +80,6 @@ Comment[hu]=Az adatok védelme az üzenetek elektronikus aláírásával, titkos
Comment[is]=Verndaðu einkalífið þitt með því að undirrita og staðfesta sendingar
Comment[it]=Proteggi la tua privacy firmando e verificando i messaggi
Comment[ja]=投稿の署名と検証によりあなたのプライバシーを保護します
-Comment[ka]=დაიცავით თქვენი პირადულობა ხელმოწერითა და განთავსებული სტატიების დამოწმებით
Comment[kk]=Жарияланғанды қолтаңбалап/тексеріп қорғану
Comment[km]=ការពារ​ភាព​ឯកជន​របស់​អ្នក​ដោយ​ចុះហត្ថលេខា និង​​ផ្ទៀងផ្ទាត់​ការ​ប្រកាស
Comment[lt]=Saugokite savo privatumą pasirašydami ir patikrindami skelbimus
diff --git a/knode/knode_config_read_news.desktop b/knode/knode_config_read_news.desktop
index a4ad37183..a8ba3e2d7 100644
--- a/knode/knode_config_read_news.desktop
+++ b/knode/knode_config_read_news.desktop
@@ -35,7 +35,6 @@ Name[hu]=Hírek olvasása
Name[is]=Lestur frétta
Name[it]=Lettura News
Name[ja]=ニュースを読む
-Name[ka]=სიახლეების კითხვა
Name[kk]=Жаңалықтарды оқу
Name[km]=អាន​ព័ត៌មាន
Name[lt]=Naujienų skaitymas
@@ -59,8 +58,7 @@ Name[ta]=செய்திகளைப் படித்தல்
Name[tg]=Хондани ахборот
Name[tr]=Haber Okuma
Name[uk]=Читання новин
-Name[uz]=Yangiliklarni oʻqish
-Name[uz@cyrillic]=Янгиликларни ўқиш
+Name[uz]=Янгиликларни ўқиш
Name[zh_CN]=阅读新闻
Name[zh_TW]=閱讀新聞
diff --git a/knotes/knote.cpp b/knotes/knote.cpp
index 1e55dd14c..9e644d7a6 100644
--- a/knotes/knote.cpp
+++ b/knotes/knote.cpp
@@ -30,6 +30,7 @@
#include <tqobjectlist.h>
#include <tqfile.h>
#include <tqcheckbox.h>
+#include <tqtimer.h>
#include <kapplication.h>
#include <kdebug.h>
@@ -84,7 +85,8 @@ KNote::KNote( TQDomDocument buildDoc, Journal *j, TQWidget *parent, const char *
: TQFrame( parent, name, WStyle_Customize | WStyle_NoBorder | WDestructiveClose ),
m_label( 0 ), m_pushpin( 0 ), m_fold( 0 ), m_button( 0 ), m_tool( 0 ), m_editor( 0 ),
m_config( 0 ), m_journal( j ), m_find( 0 ),
- m_kwinConf( KSharedConfig::openConfig( "kwinrc", true ) )
+ m_kwinConf( KSharedConfig::openConfig( "kwinrc", true ) ),
+ m_busy( 0 ), m_deleteWhenIdle( false ), m_blockEmitDataChanged( false )
{
setAcceptDrops( true );
actionCollection()->setWidget( this );
@@ -105,7 +107,7 @@ KNote::KNote( TQDomDocument buildDoc, Journal *j, TQWidget *parent, const char *
// create the menu items for the note - not the editor...
// rename, mail, print, save as, insert date, alarm, close, delete, new note
new KAction( i18n("New"), "filenew", 0,
- this, TQT_SIGNAL(sigRequestNewNote()), actionCollection(), "new_note" );
+ this,TQT_SLOT(slotRequestNewNote()) , actionCollection(), "new_note" );
new KAction( i18n("Rename..."), "text", 0,
this, TQT_SLOT(slotRename()), actionCollection(), "rename_note" );
m_readOnly = new KToggleAction( i18n("Lock"), "lock" , 0,
@@ -159,6 +161,7 @@ KNote::KNote( TQDomDocument buildDoc, Journal *j, TQWidget *parent, const char *
// create the note editor
m_editor = new KNoteEdit( actionCollection(), this );
+ m_editor->setNote( this );
m_editor->installEventFilter( this ); // receive events (for modified)
m_editor->viewport()->installEventFilter( this );
connect( m_editor, TQT_SIGNAL(contentsMoving( int, int )), this, TQT_SLOT(slotUpdateViewport( int, int )));
@@ -369,11 +372,27 @@ KNote::~KNote()
delete m_config;
}
+void KNote::slotRequestNewNote()
+{
+ //Be sure to save before to request a new note
+ saveConfig();
+ saveData();
+ emit sigRequestNewNote();
+}
+
+void KNote::changeJournal(KCal::Journal *journal)
+{
+ m_journal = journal;
+ m_editor->setText( m_journal->description() );
+ m_label->setText( m_journal->summary() );
+ updateLabelAlignment();
+}
// -------------------- public slots -------------------- //
void KNote::slotKill( bool force )
{
+ m_blockEmitDataChanged = true;
if ( !force &&
KMessageBox::warningContinueCancel( this,
i18n("<qt>Do you really want to delete note <b>%1</b>?</qt>").arg( m_label->text() ),
@@ -382,9 +401,10 @@ void KNote::slotKill( bool force )
)
!= KMessageBox::Continue )
{
+ m_blockEmitDataChanged = false;
return;
}
-
+ aboutToEnterEventLoop();
// delete the configuration first, then the corresponding file
delete m_config;
m_config = 0;
@@ -396,21 +416,24 @@ void KNote::slotKill( bool force )
kdError(5500) << "Can't remove the note config: " << configFile << endl;
emit sigKillNote( m_journal );
+ eventLoopLeft();
+
}
// -------------------- public member functions -------------------- //
-void KNote::saveData()
+void KNote::saveData(bool update)
{
m_journal->setSummary( m_label->text() );
m_journal->setDescription( m_editor->text() );
m_journal->setCustomProperty( "KNotes", "FgColor", m_config->fgColor().name() );
m_journal->setCustomProperty( "KNotes", "BgColor", m_config->bgColor().name() );
m_journal->setCustomProperty( "KNotes", "RichText", m_config->richText() ? "true" : "false" );
-
- emit sigDataChanged();
+ if(update) {
+ emit sigDataChanged( noteId() );
m_editor->setModified( false );
+ }
}
void KNote::saveConfig() const
@@ -498,7 +521,7 @@ void KNote::setColor( const TQColor& fg, const TQColor& bg )
m_config->setBgColor( bg );
m_journal->updated(); // because setCustomProperty() doesn't call it!!
- emit sigDataChanged();
+ emit sigDataChanged(noteId());
m_config->writeConfig();
TQPalette newpalette = palette();
@@ -684,11 +707,16 @@ void KNote::setStyle( int style )
void KNote::slotRename()
{
+ m_blockEmitDataChanged = true;
// pop up dialog to get the new name
bool ok;
+ aboutToEnterEventLoop();
+ TQString oldName = m_label->text();
TQString newName = KInputDialog::getText( TQString::null,
i18n("Please enter the new name:"), m_label->text(), &ok, this );
- if ( !ok ) // handle cancel
+ eventLoopLeft();
+ m_blockEmitDataChanged = false;
+ if ( !ok || ( oldName == newName) ) // handle cancel
return;
setName( newName );
@@ -711,6 +739,21 @@ void KNote::slotUpdateReadOnly()
actionCollection()->action( "edit_cut" )->setEnabled( !readOnly && m_editor->hasSelectedText() );
actionCollection()->action( "edit_paste" )->setEnabled( !readOnly );
actionCollection()->action( "edit_clear" )->setEnabled( !readOnly );
+ actionCollection()->action( "rename_note" )->setEnabled( !readOnly );
+
+ actionCollection()->action( "format_bold" )->setEnabled( !readOnly );
+ actionCollection()->action( "format_italic" )->setEnabled( !readOnly );
+ actionCollection()->action( "format_underline" )->setEnabled( !readOnly );
+ actionCollection()->action( "format_strikeout" )->setEnabled( !readOnly );
+ actionCollection()->action( "format_alignleft" )->setEnabled( !readOnly );
+ actionCollection()->action( "format_aligncenter" )->setEnabled( !readOnly );
+ actionCollection()->action( "format_alignright" )->setEnabled( !readOnly );
+ actionCollection()->action( "format_alignblock" )->setEnabled( !readOnly );
+ actionCollection()->action( "format_list" )->setEnabled( !readOnly );
+ actionCollection()->action( "format_super" )->setEnabled( !readOnly );
+ actionCollection()->action( "format_sub" )->setEnabled( !readOnly );
+ actionCollection()->action( "format_size" )->setEnabled( !readOnly );
+ actionCollection()->action( "format_color" )->setEnabled( !readOnly );
updateFocus();
}
@@ -724,7 +767,7 @@ void KNote::slotClose()
m_editor->clearFocus();
m_config->setHideNote( true );
m_config->setPosition( pos() );
-
+ m_config->writeConfig();
// just hide the note so it's still available from the dock window
hide();
}
@@ -736,11 +779,15 @@ void KNote::slotInsDate()
void KNote::slotSetAlarm()
{
+ m_blockEmitDataChanged = true;
KNoteAlarmDlg dlg( name(), this );
dlg.setIncidence( m_journal );
+ aboutToEnterEventLoop();
if ( dlg.exec() == TQDialog::Accepted )
- emit sigDataChanged();
+ emit sigDataChanged(noteId());
+ eventLoopLeft();
+ m_blockEmitDataChanged = false;
}
void KNote::slotPreferences()
@@ -760,11 +807,12 @@ void KNote::slotSend()
{
// pop up dialog to get the IP
KNoteHostDlg hostDlg( i18n("Send \"%1\"").arg( name() ), this );
+ aboutToEnterEventLoop();
bool ok = (hostDlg.exec() == TQDialog::Accepted);
- TQString host = hostDlg.host();
-
+ eventLoopLeft();
if ( !ok ) // handle cancel
return;
+ TQString host = hostDlg.host();
if ( host.isEmpty() )
{
@@ -782,11 +830,11 @@ void KNote::slotSend()
void KNote::slotMail()
{
// get the mail action command
- TQStringList cmd_list = TQStringList::split( TQChar(' '), KNotesGlobalConfig::mailAction() );
+ const TQStringList cmd_list = TQStringList::split( TQChar(' '), KNotesGlobalConfig::mailAction() );
KProcess mail;
- for ( TQStringList::Iterator it = cmd_list.begin();
- it != cmd_list.end(); ++it )
+ for ( TQStringList::ConstIterator it = cmd_list.constBegin();
+ it != cmd_list.constEnd(); ++it )
{
if ( *it == "%f" )
mail << plainText().local8Bit(); // convert rich text to plain text
@@ -802,8 +850,6 @@ void KNote::slotMail()
void KNote::slotPrint()
{
- saveData();
-
TQString content;
if ( m_editor->textFormat() == PlainText )
content = TQStyleSheet::convertFromPlainText( m_editor->text() );
@@ -821,6 +867,7 @@ void KNote::slotPrint()
void KNote::slotSaveAs()
{
+ m_blockEmitDataChanged = true;
TQCheckBox *convert = 0;
if ( m_editor->textFormat() == RichText )
@@ -832,12 +879,16 @@ void KNote::slotSaveAs()
KFileDialog dlg( TQString::null, TQString::null, this, "filedialog", true, convert );
dlg.setOperationMode( KFileDialog::Saving );
dlg.setCaption( i18n("Save As") );
+ aboutToEnterEventLoop();
dlg.exec();
+ eventLoopLeft();
TQString fileName = dlg.selectedFile();
if ( fileName.isEmpty() )
+ {
+ m_blockEmitDataChanged = false;
return;
-
+ }
TQFile file( fileName );
if ( file.exists() &&
@@ -845,6 +896,7 @@ void KNote::slotSaveAs()
"Are you sure you want to overwrite it?</qt>").arg( TQFileInfo(file).fileName() ) )
!= KMessageBox::Continue )
{
+ m_blockEmitDataChanged = false;
return;
}
@@ -857,6 +909,7 @@ void KNote::slotSaveAs()
else
stream << text();
}
+ m_blockEmitDataChanged = false;
}
void KNote::slotPopupActionToDesktop( int id )
@@ -993,19 +1046,20 @@ void KNote::updateFocus()
{
m_label->setBackgroundColor( palette().active().shadow() );
m_button->show();
- m_editor->cornerWidget()->show();
if ( !m_editor->isReadOnly() )
{
if ( m_tool && m_tool->isHidden() && m_editor->textFormat() == TQTextEdit::RichText )
{
m_tool->show();
+ m_editor->cornerWidget()->show();
setGeometry( x(), y(), width(), height() + m_tool->height() );
}
}
else if ( m_tool && !m_tool->isHidden() )
{
m_tool->hide();
+ m_editor->cornerWidget()->hide();
setGeometry( x(), y(), width(), height() - m_tool->height() );
updateLayout(); // to update the minimum height
}
@@ -1210,8 +1264,9 @@ void KNote::resizeEvent( TQResizeEvent *qre )
updateLayout();
}
-void KNote::closeEvent( TQCloseEvent * )
+void KNote::closeEvent( TQCloseEvent *event )
{
+ event->ignore(); //We don't want to close (and delete the widget). Just hide it
slotClose();
}
@@ -1268,8 +1323,10 @@ bool KNote::eventFilter( TQObject *o, TQEvent *ev )
TQMouseEvent *e = (TQMouseEvent *)ev;
if ( ev->type() == TQEvent::MouseButtonDblClick )
- slotRename();
-
+ {
+ if( !m_editor->isReadOnly())
+ slotRename();
+ }
if ( ev->type() == TQEvent::MouseButtonPress &&
(e->button() == LeftButton || e->button() == MidButton))
{
@@ -1301,21 +1358,21 @@ bool KNote::eventFilter( TQObject *o, TQEvent *ev )
return false;
}
- if ( o == m_editor )
- {
- if ( ev->type() == TQEvent::FocusOut )
- {
+ if ( o == m_editor ) {
+ if ( ev->type() == TQEvent::FocusOut ) {
TQFocusEvent *fe = static_cast<TQFocusEvent *>(ev);
if ( fe->reason() != TQFocusEvent::Popup &&
- fe->reason() != TQFocusEvent::Mouse )
- {
+ fe->reason() != TQFocusEvent::Mouse ) {
updateFocus();
- if ( m_editor->isModified() )
- saveData();
+ if ( isModified() ) {
+ saveConfig();
+ if ( !m_blockEmitDataChanged )
+ saveData();
+ }
}
- }
- else if ( ev->type() == TQEvent::FocusIn )
+ } else if ( ev->type() == TQEvent::FocusIn ) {
updateFocus();
+ }
return false;
}
@@ -1334,6 +1391,31 @@ bool KNote::eventFilter( TQObject *o, TQEvent *ev )
return false;
}
+void KNote::slotSaveData()
+{
+ saveData();
+}
+
+void KNote::deleteWhenIdle()
+{
+ if ( m_busy <= 0 )
+ deleteLater();
+ else
+ m_deleteWhenIdle = true;
+}
+
+void KNote::aboutToEnterEventLoop()
+{
+ ++m_busy;
+}
+
+void KNote::eventLoopLeft()
+{
+ --m_busy;
+ if ( m_busy <= 0 && m_deleteWhenIdle )
+ deleteLater();
+}
+
#include "knote.moc"
#include "knotebutton.moc"
diff --git a/knotes/knote.h b/knotes/knote.h
index a3bfd7b3e..6bb2ffe84 100644
--- a/knotes/knote.h
+++ b/knotes/knote.h
@@ -56,7 +56,8 @@ public:
const char *name = 0 );
~KNote();
- void saveData();
+ void changeJournal(KCal::Journal *);
+ void saveData( bool update = true);
void saveConfig() const;
TQString noteId() const;
@@ -82,6 +83,8 @@ public:
static void setStyle( int style );
+ void deleteWhenIdle();
+ void blockEmitDataChanged( bool _b ) { m_blockEmitDataChanged = _b;}
public slots:
void slotKill( bool force = false );
@@ -89,7 +92,7 @@ signals:
void sigRequestNewNote();
void sigShowNextNote();
void sigNameChanged();
- void sigDataChanged();
+ void sigDataChanged(const TQString &);
void sigColorChanged();
void sigKillNote( KCal::Journal* );
@@ -108,6 +111,10 @@ protected:
virtual bool focusNextPrevChild( bool );
+ /// Protect against deletion while we are running a sub-eventloop
+ void aboutToEnterEventLoop();
+ void eventLoopLeft();
+
private slots:
void slotRename();
void slotUpdateReadOnly();
@@ -133,7 +140,8 @@ private slots:
void slotUpdateDesktopActions();
void slotUpdateViewport( int, int );
-
+ void slotRequestNewNote();
+ void slotSaveData();
private:
void updateFocus();
void updateMask();
@@ -170,6 +178,10 @@ private:
KSharedConfig::Ptr m_kwinConf;
static int s_ppOffset;
+
+ int m_busy;
+ bool m_deleteWhenIdle;
+ bool m_blockEmitDataChanged;
};
#endif
diff --git a/knotes/knotealarmdlg.cpp b/knotes/knotealarmdlg.cpp
index ef71c0f51..2652af633 100644
--- a/knotes/knotealarmdlg.cpp
+++ b/knotes/knotealarmdlg.cpp
@@ -70,7 +70,8 @@ KNoteAlarmDlg::KNoteAlarmDlg( const TQString& caption, TQWidget *parent, const c
TQLabel *in_min = new TQLabel( i18n("hours/minutes"), in );
label_in->setEnabled( false ); // TODO
-
+ in->hide(); //show it and enable it when feature will implement
+
connect( m_buttons, TQT_SIGNAL(clicked( int )), TQT_SLOT(slotButtonChanged( int )) );
}
diff --git a/knotes/knoteedit.cpp b/knotes/knoteedit.cpp
index 7df68149c..7b99254b0 100644
--- a/knotes/knoteedit.cpp
+++ b/knotes/knoteedit.cpp
@@ -27,24 +27,26 @@
#include <kurldrag.h>
#include <kstdaction.h>
#include <kcolordialog.h>
-
+#include <tqpopupmenu.h>
+#include <kiconloader.h>
#include "knoteedit.h"
+#include "knote.h"
static const short SEP = 5;
static const short ICON_SIZE = 10;
KNoteEdit::KNoteEdit( KActionCollection *actions, TQWidget *parent, const char *name )
- : KTextEdit( parent, name )
+ : KTextEdit( parent, name ), m_note( 0 )
{
setAcceptDrops( true );
setWordWrap( WidgetWidth );
setWrapPolicy( AtWhiteSpace );
setLinkUnderline( true );
-
+ setCheckSpellingEnabled(false);
// create the actions for the RMB menu
- KAction* undo = KStdAction::undo( this, TQT_SLOT(undo()), actions );
- KAction* redo = KStdAction::redo( this, TQT_SLOT(redo()), actions );
+ undo = KStdAction::undo( this, TQT_SLOT(undo()), actions );
+ redo = KStdAction::redo( this, TQT_SLOT(redo()), actions );
undo->setEnabled( isUndoAvailable() );
redo->setEnabled( isRedoAvailable() );
@@ -56,10 +58,10 @@ KNoteEdit::KNoteEdit( KActionCollection *actions, TQWidget *parent, const char *
m_copy->setEnabled( false );
m_paste->setEnabled( true );
- connect( this, TQT_SIGNAL(undoAvailable(bool)), undo, TQT_SLOT(setEnabled(bool)) );
- connect( this, TQT_SIGNAL(redoAvailable(bool)), redo, TQT_SLOT(setEnabled(bool)) );
+ connect( this, TQT_SIGNAL(undoAvailable(bool)), this, TQT_SLOT(setEnabledUndo(bool)) );
+ connect( this, TQT_SIGNAL(redoAvailable(bool)), this, TQT_SLOT(setEnabledRedo(bool)) );
- connect( this, TQT_SIGNAL(copyAvailable(bool)), m_cut, TQT_SLOT(setEnabled(bool)) );
+ connect( this, TQT_SIGNAL(copyAvailable(bool)), this, TQT_SLOT( slotCutEnabled( bool ) ) );
connect( this, TQT_SIGNAL(copyAvailable(bool)), m_copy, TQT_SLOT(setEnabled(bool)) );
new KAction( KStdGuiItem::clear(), 0, this, TQT_SLOT(clear()), actions, "edit_clear" );
@@ -156,6 +158,21 @@ KNoteEdit::~KNoteEdit()
{
}
+void KNoteEdit::setEnabledRedo( bool b )
+{
+ redo->setEnabled( b && !isReadOnly() );
+}
+
+void KNoteEdit::setEnabledUndo( bool b )
+{
+ undo->setEnabled( b && !isReadOnly() );
+}
+
+void KNoteEdit::slotCutEnabled( bool b )
+{
+ m_cut->setEnabled( b && !isReadOnly() );
+}
+
void KNoteEdit::setText( const TQString& text )
{
// to update the font and font size combo box - TQTextEdit stopped
@@ -269,10 +286,14 @@ void KNoteEdit::textStrikeOut( bool s )
void KNoteEdit::textColor()
{
+ if ( m_note )
+ m_note->blockEmitDataChanged( true );
TQColor c = color();
int ret = KColorDialog::getColor( c, this );
if ( ret == TQDialog::Accepted )
setTextColor( c );
+ if ( m_note )
+ m_note->blockEmitDataChanged( false );
}
void KNoteEdit::textAlignLeft()
@@ -347,13 +368,17 @@ void KNoteEdit::contentsDropEvent( TQDropEvent *e )
KURL::List list;
if ( KURLDrag::decode( e, list ) )
- for ( KURL::List::Iterator it = list.begin(); it != list.end(); ++it )
+ {
+ KURL::List::ConstIterator begin = list.constBegin();
+ KURL::List::ConstIterator end = list.constEnd();
+ for ( KURL::List::ConstIterator it = begin; it != end; ++it )
{
- if ( it != list.begin() )
+ if ( it != begin )
insert( ", " );
insert( (*it).prettyURL() );
}
+ }
else
KTextEdit::contentsDropEvent( e );
}
@@ -492,4 +517,41 @@ void KNoteEdit::disableRichTextActions()
// m_textDecreaseIndent->setEnabled( false );
}
+void KNoteEdit::slotAllowTab()
+{
+ setTabChangesFocus(!tabChangesFocus());
+}
+
+TQPopupMenu *KNoteEdit::createPopupMenu( const TQPoint &pos )
+{
+ enum { IdUndo, IdRedo, IdSep1, IdCut, IdCopy, IdPaste, IdClear, IdSep2, IdSelectAll };
+
+ TQPopupMenu *menu = TQTextEdit::createPopupMenu( pos );
+
+ if ( isReadOnly() )
+ menu->changeItem( menu->idAt(0), SmallIconSet("editcopy"), menu->text( menu->idAt(0) ) );
+ else {
+ int id = menu->idAt(0);
+ menu->changeItem( id - IdUndo, SmallIconSet("undo"), menu->text( id - IdUndo) );
+ menu->changeItem( id - IdRedo, SmallIconSet("redo"), menu->text( id - IdRedo) );
+ menu->changeItem( id - IdCut, SmallIconSet("editcut"), menu->text( id - IdCut) );
+ menu->changeItem( id - IdCopy, SmallIconSet("editcopy"), menu->text( id - IdCopy) );
+ menu->changeItem( id - IdPaste, SmallIconSet("editpaste"), menu->text( id - IdPaste) );
+ menu->changeItem( id - IdClear, SmallIconSet("editclear"), menu->text( id - IdClear) );
+
+ menu->insertSeparator();
+ id = menu->insertItem( SmallIconSet( "spellcheck" ), i18n( "Check Spelling..." ),
+ this, TQT_SLOT( checkSpelling() ) );
+
+ if( text().isEmpty() )
+ menu->setItemEnabled( id, false );
+
+ menu->insertSeparator();
+ id=menu->insertItem(i18n("Allow Tabulations"),this,TQT_SLOT(slotAllowTab()));
+ menu->setItemChecked(id, !tabChangesFocus());
+ }
+
+ return menu;
+}
+
#include "knoteedit.moc"
diff --git a/knotes/knoteedit.h b/knotes/knoteedit.h
index 862aa38ba..0e6a6e4b4 100644
--- a/knotes/knoteedit.h
+++ b/knotes/knoteedit.h
@@ -24,7 +24,7 @@
#include <tqwidget.h>
#include <ktextedit.h>
-
+class KNote;
class TQFont;
class TQColor;
class TQPushButton;
@@ -41,7 +41,9 @@ class KNoteEdit : public KTextEdit
public:
KNoteEdit( KActionCollection *actions, TQWidget *parent=0, const char *name=0 );
~KNoteEdit();
-
+ void setNote( KNote *_note ) {
+ m_note = _note;
+ }
void setText( const TQString& text );
void setTextFont( const TQFont& font );
void setTextColor( const TQColor& color );
@@ -67,10 +69,12 @@ public slots:
//void textIncreaseIndent();
//void textDecreaseIndent();
+ void slotCutEnabled( bool );
protected:
virtual void contentsDragEnterEvent( TQDragEnterEvent *e );
virtual void contentsDropEvent( TQDropEvent *e );
+ virtual TQPopupMenu *createPopupMenu( const TQPoint &pos );
private slots:
void slotReturnPressed();
@@ -79,6 +83,10 @@ private slots:
void colorChanged( const TQColor &c );
void alignmentChanged( int a );
void verticalAlignmentChanged( VerticalAlignment a );
+ void slotAllowTab();
+
+ void setEnabledRedo( bool b );
+ void setEnabledUndo( bool b );
private:
void autoIndent();
@@ -114,8 +122,10 @@ private:
KAction *m_textColor;
KFontAction *m_textFont;
KFontSizeAction *m_textSize;
-
+ KAction* undo;
+ KAction* redo;
bool m_autoIndentMode;
+ KNote *m_note;
};
#endif
diff --git a/knotes/knoteprinter.cpp b/knotes/knoteprinter.cpp
index 0bd6ef8a7..c58031671 100644
--- a/knotes/knoteprinter.cpp
+++ b/knotes/knoteprinter.cpp
@@ -4,7 +4,7 @@
#include <klocale.h>
#include <kprinter.h>
-
+#include <kdebug.h>
#include <tqfont.h>
#include <tqpaintdevicemetrics.h>
#include <tqpainter.h>
@@ -79,6 +79,9 @@ void KNotePrinter::doPrint( KPrinter& printer, TQPainter& painter,
metrics.width() - marginX * 2,
metrics.height() - marginY * 2 );
+ kdDebug()<<" content :"<<content<<endl;
+ kdDebug()<<" m_styleSheet :"<<m_styleSheet<<endl;
+ //kdDebug()<<" m_font :"<<m_font;
TQSimpleRichText text( content, m_font, m_context,
m_styleSheet, m_mimeSourceFactory,
body.height() /*, linkColor, linkUnderline? */ );
@@ -136,8 +139,8 @@ void KNotePrinter::printNotes( const TQValueList<KCal::Journal*>& journals ) con
TQPainter painter;
painter.begin( &printer );
TQString content;
- TQValueListConstIterator<KCal::Journal*> it( journals.begin() );
- TQValueListConstIterator<KCal::Journal*> end( journals.end() );
+ TQValueListConstIterator<KCal::Journal*> it( journals.constBegin() );
+ TQValueListConstIterator<KCal::Journal*> end( journals.constEnd() );
while ( it != end ) {
KCal::Journal *j = *it;
it++;
diff --git a/knotes/knotes.desktop b/knotes/knotes.desktop
index a455e07da..6a099e585 100644
--- a/knotes/knotes.desktop
+++ b/knotes/knotes.desktop
@@ -32,7 +32,6 @@ GenericName[hu]=Jegyzettömb
GenericName[is]=Litlir gulir miðar
GenericName[it]=Note a comparsa
GenericName[ja]=ポップアップメモ
-GenericName[ka]=მოტივტივე შენიშვნები
GenericName[kk]=Қалқымалы жазбалар
GenericName[km]=ចំណាំ​លេចឡើង
GenericName[lt]=Pastabos lapeliuose
diff --git a/knotes/knotes_manager.desktop b/knotes/knotes_manager.desktop
index adce2afb5..d193bcbbe 100644
--- a/knotes/knotes_manager.desktop
+++ b/knotes/knotes_manager.desktop
@@ -27,7 +27,6 @@ Name[hu]=Feljegyzések
Name[is]=Minnismiðar
Name[it]=Note
Name[ja]=メモ
-Name[ka]=ჩანიშვნები
Name[kk]=Жазбалар
Name[km]=ចំណាំ
Name[lt]=Užrašai
@@ -53,8 +52,7 @@ Name[tg]=Ахборот
Name[th]=บันทึกช่วยจำ
Name[tr]=Notlar
Name[uk]=Примітки
-Name[uz]=Yozma xotira
-Name[uz@cyrillic]=Ёзма хотира
+Name[uz]=Ёзма хотира
Name[zh_CN]=便笺
Name[zh_TW]=備忘錄
Type=Service
diff --git a/knotes/knotesalarm.cpp b/knotes/knotesalarm.cpp
index c653d80ca..616c83b7c 100644
--- a/knotes/knotesalarm.cpp
+++ b/knotes/knotesalarm.cpp
@@ -61,10 +61,11 @@ void KNotesAlarm::checkAlarms()
KNotesGlobalConfig::self()->setAlarmsLastChecked( TQDateTime::currentDateTime() );
TQValueList<KCal::Alarm *> alarms = m_manager->alarms( from, KNotesGlobalConfig::self()->alarmsLastChecked() );
-
+ if( alarms.isEmpty())
+ return;
TQStringList notes;
TQValueList<KCal::Alarm *>::ConstIterator it;
- for ( it = alarms.begin(); it != alarms.end(); ++it )
+ for ( it = alarms.constBegin(); it != alarms.constEnd(); ++it )
{
KCal::Incidence *incidence = (*it)->parent();
notes += incidence->summary();
diff --git a/knotes/knotesapp.cpp b/knotes/knotesapp.cpp
index 858cbb795..72b1ecce1 100644
--- a/knotes/knotesapp.cpp
+++ b/knotes/knotesapp.cpp
@@ -121,7 +121,7 @@ KNotesApp::KNotesApp()
this, TQT_SLOT(hideAllNotes()), actionCollection(), "hide_all_notes" );
new KHelpMenu( this, kapp->aboutData(), false, actionCollection() );
- KStdAction::find( this, TQT_SLOT(slotOpenFindDialog()), actionCollection() );
+ m_findAction = KStdAction::find( this, TQT_SLOT(slotOpenFindDialog()), actionCollection() );
KStdAction::preferences( this, TQT_SLOT(slotPreferences()), actionCollection() );
KStdAction::keyBindings( this, TQT_SLOT(slotConfigureAccels()), actionCollection() );
//FIXME: no shortcut removing!?
@@ -188,7 +188,7 @@ KNotesApp::KNotesApp()
{
KCal::Journal::List notes = calendar.journals();
KCal::Journal::List::ConstIterator it;
- for ( it = notes.begin(); it != notes.end(); ++it )
+ for ( it = notes.constBegin(); it != notes.constEnd(); ++it )
m_manager->addNewNote( *it );
m_manager->save();
@@ -258,10 +258,9 @@ TQString KNotesApp::newNote( const TQString& name, const TQString& text )
// the body of the note
journal->setDescription( text );
- m_manager->addNewNote( journal );
-
- showNote( journal->uid() );
-
+ if ( m_manager->addNewNote( journal ) ) {
+ showNote( journal->uid() );
+ }
return journal->uid();
}
@@ -284,7 +283,6 @@ void KNotesApp::showAllNotes() const
for ( ; *it; ++it )
{
(*it)->show();
- (*it)->setFocus();
}
}
@@ -516,7 +514,7 @@ void KNotesApp::slotOpenFindDialog()
findDia.setHasCursor( false );
findDia.setSupportsBackwardsFind( false );
- if ( findDia.exec() != TQDialog::Accepted )
+ if ( (findDia.exec() != TQDialog::Accepted) || findDia.pattern().isEmpty() )
return;
delete m_findPos;
@@ -596,6 +594,7 @@ void KNotesApp::slotConfigureAccels()
void KNotesApp::slotNoteKilled( KCal::Journal *journal )
{
+ m_noteUidModify="";
m_manager->deleteNote( journal );
saveNotes();
}
@@ -606,7 +605,7 @@ void KNotesApp::slotQuit()
for ( ; *it; ++it )
if ( (*it)->isModified() )
- (*it)->saveData();
+ (*it)->saveData(false);
saveConfigs();
kapp->quit();
@@ -625,6 +624,15 @@ void KNotesApp::showNote( KNote* note ) const
void KNotesApp::createNote( KCal::Journal *journal )
{
+ if( journal->uid() == m_noteUidModify)
+ {
+ KNote *note = m_noteList[m_noteUidModify];
+ if ( note )
+ note->changeJournal(journal);
+
+ return;
+ }
+ m_noteUidModify = journal->uid();
KNote *newNote = new KNote( m_noteGUI, journal, 0, journal->uid().utf8() );
m_noteList.insert( newNote->noteId(), newNote );
@@ -633,7 +641,7 @@ void KNotesApp::createNote( KCal::Journal *journal )
connect( newNote, TQT_SIGNAL(sigKillNote( KCal::Journal* )),
TQT_SLOT(slotNoteKilled( KCal::Journal* )) );
connect( newNote, TQT_SIGNAL(sigNameChanged()), TQT_SLOT(updateNoteActions()) );
- connect( newNote, TQT_SIGNAL(sigDataChanged()), TQT_SLOT(saveNotes()) );
+ connect( newNote, TQT_SIGNAL(sigDataChanged(const TQString &)), TQT_SLOT(saveNotes(const TQString &)) );
connect( newNote, TQT_SIGNAL(sigColorChanged()), TQT_SLOT(updateNoteActions()) );
connect( newNote, TQT_SIGNAL(sigFindFinished()), TQT_SLOT(slotFindNext()) );
@@ -644,9 +652,17 @@ void KNotesApp::createNote( KCal::Journal *journal )
void KNotesApp::killNote( KCal::Journal *journal )
{
+ if(m_noteUidModify == journal->uid())
+ {
+ return;
+ }
// this kills the KNote object
- m_noteList.remove( journal->uid() );
- updateNoteActions();
+ KNote *note = m_noteList.take( journal->uid() );
+ if ( note )
+ {
+ note->deleteWhenIdle();
+ updateNoteActions();
+ }
}
void KNotesApp::acceptConnection()
@@ -661,6 +677,12 @@ void KNotesApp::acceptConnection()
}
}
+void KNotesApp::saveNotes( const TQString & uid )
+{
+ m_noteUidModify = uid;
+ saveNotes();
+}
+
void KNotesApp::saveNotes()
{
KNotesGlobalConfig::writeConfig();
@@ -692,14 +714,21 @@ void KNotesApp::updateNoteActions()
m_noteActions.append( action );
}
- m_noteActions.sort();
-
if ( m_noteActions.isEmpty() )
{
+ actionCollection()->action( "hide_all_notes" )->setEnabled( false );
+ actionCollection()->action( "show_all_notes" )->setEnabled( false );
+ m_findAction->setEnabled( false );
KAction *action = new KAction( i18n("No Notes") );
m_noteActions.append( action );
}
-
+ else
+ {
+ actionCollection()->action( "hide_all_notes" )->setEnabled( true );
+ actionCollection()->action( "show_all_notes" )->setEnabled( true );
+ m_findAction->setEnabled( true );
+ m_noteActions.sort();
+ }
plugActionList( "notes", m_noteActions );
}
diff --git a/knotes/knotesapp.h b/knotes/knotesapp.h
index ba156cca4..3048958dd 100644
--- a/knotes/knotesapp.h
+++ b/knotes/knotesapp.h
@@ -125,6 +125,7 @@ private:
private slots:
void acceptConnection();
void saveNotes();
+ void saveNotes( const TQString & uid );
void updateNoteActions();
void updateGlobalAccels();
void updateNetworkListener();
@@ -159,6 +160,8 @@ private:
KXMLGUIBuilder *m_guiBuilder;
TQDomDocument m_noteGUI;
+ KAction *m_findAction;
+ TQString m_noteUidModify;
};
#endif
diff --git a/knotes/knoteslegacy.cpp b/knotes/knoteslegacy.cpp
index 8cb57d4ce..6dd80368f 100644
--- a/knotes/knoteslegacy.cpp
+++ b/knotes/knoteslegacy.cpp
@@ -72,8 +72,8 @@ bool KNotesLegacy::convert( CalendarLocal *calendar )
bool converted = false;
TQDir noteDir( KGlobal::dirs()->saveLocation( "appdata", "notes/" ) );
- TQStringList notes = noteDir.entryList( TQDir::Files, TQDir::Name );
- for ( TQStringList::Iterator note = notes.begin(); note != notes.end(); note++ )
+ const TQStringList notes = noteDir.entryList( TQDir::Files, TQDir::Name );
+ for ( TQStringList::ConstIterator note = notes.constBegin(); note != notes.constEnd(); ++note )
{
TQString file = noteDir.absFilePath( *note );
KSimpleConfig* test = new KSimpleConfig( file );
@@ -82,7 +82,6 @@ bool KNotesLegacy::convert( CalendarLocal *calendar )
if ( version < 3.0 )
{
- delete test;
// create the new note
Journal *journal = new Journal();
@@ -109,8 +108,8 @@ bool KNotesLegacy::convert( CalendarLocal *calendar )
test->writeEntry( "ShowInTaskbar", (state & NET::SkipTaskbar) ? false : true );
test->writeEntry( "KeepAbove", (state & NET::KeepAbove) ? true : false );
test->deleteEntry( "state" );
- delete test;
}
+ delete test;
}
return converted;
diff --git a/knotes/local.desktop b/knotes/local.desktop
index 514145a81..c0748995b 100644
--- a/knotes/local.desktop
+++ b/knotes/local.desktop
@@ -26,7 +26,6 @@ Name[hu]=Helyi fájlban tárolt feljegyzések
Name[is]=Minnismiðar í staðbundinni skrá
Name[it]=Note in file locale
Name[ja]=ローカルファイルのメモ
-Name[ka]=ჩანიშვნები ლოკალურ ფაილში
Name[kk]=Жергілікті файлдағы жазбалар
Name[km]=ចំណាំ​ក្នុង​ឯកសារ​មូលដ្ឋាន
Name[lt]=Užrašai vietinėje byloje
diff --git a/knotes/resourcelocal.cpp b/knotes/resourcelocal.cpp
index a6e4b9a3f..91e6d2d9f 100644
--- a/knotes/resourcelocal.cpp
+++ b/knotes/resourcelocal.cpp
@@ -75,7 +75,7 @@ bool ResourceLocal::load()
KCal::Journal::List notes = mCalendar.journals();
KCal::Journal::List::ConstIterator it;
- for ( it = notes.begin(); it != notes.end(); ++it )
+ for ( it = notes.constBegin(); it != notes.constEnd(); ++it )
manager()->registerNote( this, *it );
return true;
@@ -98,14 +98,12 @@ bool ResourceLocal::save()
bool ResourceLocal::addNote( KCal::Journal *journal )
{
- mCalendar.addJournal( journal );
- return true;
+ return mCalendar.addJournal( journal );
}
bool ResourceLocal::deleteNote( KCal::Journal *journal )
{
- mCalendar.deleteJournal( journal );
- return true;
+ return mCalendar.deleteJournal( journal );
}
KCal::Alarm::List ResourceLocal::alarms( const TQDateTime& from, const TQDateTime& to )
@@ -113,11 +111,11 @@ KCal::Alarm::List ResourceLocal::alarms( const TQDateTime& from, const TQDateTim
KCal::Alarm::List alarms;
KCal::Journal::List notes = mCalendar.journals();
KCal::Journal::List::ConstIterator note;
- for ( note = notes.begin(); note != notes.end(); ++note )
+ for ( note = notes.constBegin(); note != notes.constEnd(); ++note )
{
TQDateTime preTime = from.addSecs( -1 );
KCal::Alarm::List::ConstIterator it;
- for( it = (*note)->alarms().begin(); it != (*note)->alarms().end(); ++it )
+ for( it = (*note)->alarms().constBegin(); it != (*note)->alarms().constEnd(); ++it )
{
if ( (*it)->enabled() )
{
diff --git a/knotes/resourcemanager.cpp b/knotes/resourcemanager.cpp
index 112ec03f8..226d90005 100644
--- a/knotes/resourcemanager.cpp
+++ b/knotes/resourcemanager.cpp
@@ -64,6 +64,11 @@ void KNotesResourceManager::load()
KRES::Manager<ResourceNotes>::ActiveIterator it;
for ( it = m_manager->activeBegin(); it != m_manager->activeEnd(); ++it )
{
+ if ( (*it)->isOpen() ) {
+ kdDebug(5500) << (*it)->resourceName() << " is already open" << endl;
+ continue;
+ }
+
kdDebug(5500) << "Opening resource " + (*it)->resourceName() << endl;
(*it)->setManager( this );
if ( (*it)->open() )
@@ -80,17 +85,19 @@ void KNotesResourceManager::save()
// when adding a new note, make sure a config file exists!!
-void KNotesResourceManager::addNewNote( KCal::Journal *journal )
+bool KNotesResourceManager::addNewNote( KCal::Journal *journal )
{
// TODO: Make this configurable
ResourceNotes *resource = m_manager->standardResource();
- if ( resource )
- {
- resource->addNote( journal );
- registerNote( resource, journal );
- }
- else
+ if ( resource ) {
+ if ( resource->addNote( journal ) ) {
+ registerNote( resource, journal );
+ return true;
+ }
+ } else {
kdWarning(5500) << k_funcinfo << "no resource!" << endl;
+ }
+ return false;
}
void KNotesResourceManager::registerNote( ResourceNotes *resource,
@@ -103,15 +110,21 @@ void KNotesResourceManager::registerNote( ResourceNotes *resource,
void KNotesResourceManager::deleteNote( KCal::Journal *journal )
{
+ if ( !journal )
+ return;
+
TQString uid = journal->uid();
// Remove the journal from the resource it came from
- m_resourceMap[ uid ]->deleteNote( journal );
- m_resourceMap.remove( uid );
-
- // libkcal does not delete the journal immediately, therefore it is ok to
- // emit the journal here
- emit sigDeregisteredNote( journal );
+ ResourceNotes *res = m_resourceMap[ uid ];
+ if ( res ) {
+ res->deleteNote( journal );
+ m_resourceMap.remove( uid );
+
+ // libkcal does not delete the journal immediately, therefore it is ok to
+ // emit the journal here
+ emit sigDeregisteredNote( journal );
+ }
}
KCal::Alarm::List KNotesResourceManager::alarms( const TQDateTime& from, const TQDateTime& to )
@@ -122,8 +135,8 @@ KCal::Alarm::List KNotesResourceManager::alarms( const TQDateTime& from, const T
for ( it = m_manager->activeBegin(); it != m_manager->activeEnd(); ++it )
{
KCal::Alarm::List list = (*it)->alarms( from, to );
- KCal::Alarm::List::Iterator it;
- for ( it = list.begin(); it != list.end(); ++it )
+ KCal::Alarm::List::ConstIterator it;
+ for ( it = list.constBegin(); it != list.constEnd(); ++it )
result.append( *it );
}
@@ -137,6 +150,11 @@ void KNotesResourceManager::resourceAdded( ResourceNotes *resource )
if ( !resource->isActive() )
return;
+ if ( resource->isOpen() ) {
+ kdDebug(5500) << resource->resourceName() << " is already open" << endl;
+ return;
+ }
+
resource->setManager( this );
if ( resource->open() )
resource->load();
diff --git a/knotes/resourcemanager.h b/knotes/resourcemanager.h
index 0ba70b4b5..a864fc380 100644
--- a/knotes/resourcemanager.h
+++ b/knotes/resourcemanager.h
@@ -57,7 +57,7 @@ public:
void load();
void save();
- void addNewNote( KCal::Journal *journal );
+ bool addNewNote( KCal::Journal *journal );
void registerNote( ResourceNotes *resource, KCal::Journal *journal );
void deleteNote( KCal::Journal *journal );
diff --git a/konsolekalendar/main.cpp b/konsolekalendar/main.cpp
index 6343144e2..59b9a2f86 100644
--- a/konsolekalendar/main.cpp
+++ b/konsolekalendar/main.cpp
@@ -799,13 +799,13 @@ int main( int argc, char *argv[] )
if ( !args->isSet( "time" ) && !args->isSet( "epoch-start" ) &&
!args->isSet( "end-time" ) && !args->isSet( "epoch-end" ) ) {
// set default start date/time
- startdatetime = TQDateTime::TQDateTime( startdate, starttime );
+ startdatetime = TQDateTime( startdate, starttime );
kdDebug() << "main | datetimestamp | "
<< "setting startdatetime from "
<< "default startdate (today) and starttime"
<< endl;
// set default end date/time
- enddatetime = TQDateTime::TQDateTime( enddate, endtime );
+ enddatetime = TQDateTime( enddate, endtime );
kdDebug() << "main | datetimestamp | "
<< "setting enddatetime from "
<< "default enddate (today) and endtime"
@@ -814,13 +814,13 @@ int main( int argc, char *argv[] )
// Set startdatetime, enddatetime if still necessary
if ( startdatetime.isNull() ) {
- startdatetime = TQDateTime::TQDateTime( startdate, starttime );
+ startdatetime = TQDateTime( startdate, starttime );
kdDebug() << "main | datetimestamp | "
<< "setting startdatetime from startdate and starttime"
<< endl;
}
if ( enddatetime.isNull() ) {
- enddatetime = TQDateTime::TQDateTime( enddate, endtime );
+ enddatetime = TQDateTime( enddate, endtime );
kdDebug() << "main | datetimestamp | "
<< "setting enddatetime from enddate and endtime"
<< endl;
diff --git a/kontact/interfaces/kontactplugin.desktop b/kontact/interfaces/kontactplugin.desktop
index 28803bc6d..11787765a 100644
--- a/kontact/interfaces/kontactplugin.desktop
+++ b/kontact/interfaces/kontactplugin.desktop
@@ -28,7 +28,6 @@ Name[hu]=Kontact-bővítőmodul
Name[is]=Kontact íforrit
Name[it]=Plugin Kontact
Name[ja]=Kontact プラグイン
-Name[ka]=Kontact მოდული
Name[kk]=Kontact модулі
Name[km]=កម្មវិធី​ជំនួយ Kontact
Name[lt]=Kontact priedas
@@ -52,8 +51,7 @@ Name[ta]=சொருகுப்பொருளை தொடர்புக்
Name[tg]=Модули Kontact
Name[tr]=Kontact Eklentisi
Name[uk]=Втулок Kontact
-Name[uz]=Kontact uchun plagin
-Name[uz@cyrillic]=Kontact учун плагин
+Name[uz]=Kontact учун плагин
Name[zh_CN]=Kontact 插件
Name[zh_TW]=Kontack 外掛程式
diff --git a/kontact/interfaces/plugin.h b/kontact/interfaces/plugin.h
index e94c0315e..13f14c580 100644
--- a/kontact/interfaces/plugin.h
+++ b/kontact/interfaces/plugin.h
@@ -125,7 +125,7 @@ class KDE_EXPORT Plugin : public TQObject, virtual public KXMLGUIClient
virtual bool createDCOPInterface( const TQString& /*serviceType*/ ) { return false; }
/**
- Reimplement this method and return wether a standalone application is still running
+ Reimplement this method and return whether a standalone application is still running
This is only required if your part is also available as standalone application.
*/
virtual bool isRunningStandalone() { return false; }
@@ -174,7 +174,7 @@ class KDE_EXPORT Plugin : public TQObject, virtual public KXMLGUIClient
virtual Summary *createSummaryWidget( TQWidget * /*parent*/ ) { return 0; }
/**
- Returns wether the plugin provides a part that should be shown in the sidebar.
+ Returns whether the plugin provides a part that should be shown in the sidebar.
*/
virtual bool showInSideBar() const;
diff --git a/kontact/interfaces/uniqueapphandler.cpp b/kontact/interfaces/uniqueapphandler.cpp
index 34de01807..5dd9e72d0 100644
--- a/kontact/interfaces/uniqueapphandler.cpp
+++ b/kontact/interfaces/uniqueapphandler.cpp
@@ -188,6 +188,8 @@ static KCmdLineOptions options[] =
{ "module <module>", I18N_NOOP( "Start with a specific Kontact module" ), 0 },
{ "iconify", I18N_NOOP( "Start in iconified (minimized) mode" ), 0 },
{ "list", I18N_NOOP( "List all possible modules and exit" ), 0 },
+ { "listprofiles", I18N_NOOP( "List all possible profiles and exit" ), 0 },
+ { "profile <profile>", I18N_NOOP( "Start with a specific Kontact profile" ), 0 },
KCmdLineLastOption
};
diff --git a/kontact/plugins/akregator/akregator_plugin.h b/kontact/plugins/akregator/akregator_plugin.h
index 428084646..6689a5a30 100644
--- a/kontact/plugins/akregator/akregator_plugin.h
+++ b/kontact/plugins/akregator/akregator_plugin.h
@@ -57,7 +57,7 @@ class Plugin : public Kontact::Plugin
const TQStringList & );
~Plugin();
- int weight() const { return 700; }
+ int weight() const { return 475; }
AkregatorPartIface_stub *interface();
diff --git a/kontact/plugins/akregator/akregatorplugin.desktop b/kontact/plugins/akregator/akregatorplugin.desktop
index 015ae80a1..6b44fbc4a 100644
--- a/kontact/plugins/akregator/akregatorplugin.desktop
+++ b/kontact/plugins/akregator/akregatorplugin.desktop
@@ -17,24 +17,17 @@ Comment=Feed Reader Component (Akregator Plugin)
Comment[bg]=Приставка за Akregator
Comment[ca]=Component lector d'enllaços (endollable de l'Akregator)
Comment[da]=Feed-læserkomponent (Akregator-plugin)
-Comment[de]=News-Leser (Akregator-Modul)
+Comment[de]=Feedreader Komponente
Comment[el]=Συστατικό ανάγνωσης ροών (Πρόσθετο του Akregator)
-Comment[es]=Componente de lectura de fuentes (complemento de Akregator)
Comment[et]=Uudistevoogude plugin (Akregator)
-Comment[fr]=Composant du lecteur de flux (Module pour Akregator)
-Comment[is]=Fréttastraumalestur (Akregator íforrit)
Comment[it]=Componente lettore fonti (plugin Akregator)
Comment[ja]=フィードリーダーコンポーネント (Akregator プラグイン)
-Comment[km]=មមាសភាគ​កម្មវិធី​អាន​មតិព័ត៌មាន (កម្មវិធី​ជំនួយ Akregator​)
Comment[nds]=Stroomleser-Komponent (Akregator-Moduul)
Comment[nl]=Component om feeds te lezen (Akregator-plugin)
-Comment[pl]=Składnik do czytania kanałów RSS (wtyczka Akregator)
-Comment[ru]=Просмотр лент новостей (модуль Akregator)
-Comment[sk]=Komponent na čítanie kanálov (Modul pre Akregator)
+Comment[pl]=Składnik do czytania niusów (wtyczka Akregator)
Comment[sr]=Компонента читања довода (прикључак Akregator-а)
Comment[sr@Latn]=Komponenta čitanja dovoda (priključak Akregator-a)
Comment[sv]=Komponent för läsning av kanaler (Akregator-insticksprogram)
-Comment[tr]=Kaynak Okuyucu Bileşeni (Akregator Eklentisi)
Comment[zh_CN]=新闻源阅读器组件(Akregator 插件)
Comment[zh_TW]=Feed 閱讀器組件(Akregator 外掛程式)
Name=Feeds
@@ -43,7 +36,7 @@ Name[bg]=Новини
Name[ca]=Enllaços
Name[cs]=Kanály
Name[da]=Kilder
-Name[de]=Nachrichten
+Name[de]=Feeds
Name[el]=Ροές
Name[eo]=Fluoj
Name[es]=Orígenes
@@ -60,7 +53,6 @@ Name[hu]=Hírforrások
Name[is]=Fréttastraumar
Name[it]=Fonti
Name[ja]=フィード
-Name[ka]=კვება
Name[kk]=Ақпарлар
Name[km]=មតិព័ត៌មាន
Name[lt]=Kanalai
@@ -73,7 +65,7 @@ Name[pl]=Kanały
Name[pt]=Fontes
Name[pt_BR]=Fontes de Notícias
Name[ru]=Ленты новостей
-Name[sk]=Kanály
+Name[sk]=Kŕmitka
Name[sl]=Viri
Name[sr]=Доводи
Name[sr@Latn]=Dovodi
@@ -81,7 +73,6 @@ Name[sv]=Kanaler
Name[ta]=உள்ளீடுகள்
Name[tr]=Haberler
Name[uk]=Подачі
-Name[uz]=Yangiliklar tasmalari
-Name[uz@cyrillic]=Янгиликлар тасмалари
+Name[uz]=Янгиликлар тасмалари
Name[zh_CN]=种子
diff --git a/kontact/plugins/akregator/akregatorplugin3.2.desktop b/kontact/plugins/akregator/akregatorplugin3.2.desktop
index 7bd29ffbc..81f9f074b 100644
--- a/kontact/plugins/akregator/akregatorplugin3.2.desktop
+++ b/kontact/plugins/akregator/akregatorplugin3.2.desktop
@@ -35,7 +35,6 @@ Comment[hu]=Akregator bővítőmodul
Comment[is]=Akregator íforrit
Comment[it]=Plugin aKregator
Comment[ja]=Akregator プラグイン
-Comment[ka]=Akregator-ის მოდული
Comment[kk]=Akregator модулі
Comment[km]=កម្មវិធី​ជំនួយ Akregator
Comment[lt]=Akregator priedas
@@ -58,8 +57,7 @@ Comment[sv]=Akregator-insticksprogram
Comment[ta]=Akregator சொருகுப்பொருள்
Comment[tr]=Akregator Eklentisi
Comment[uk]=Втулок Akregator
-Comment[uz]=Akregator plagini
-Comment[uz@cyrillic]=Akregator плагини
+Comment[uz]=Akregator плагини
Comment[zh_CN]=Akregator 插件
Comment[zh_TW]=Akregator 外掛程式
Name=Feeds
@@ -85,7 +83,6 @@ Name[hu]=Hírforrások
Name[is]=Fréttastraumar
Name[it]=Fonti
Name[ja]=フィード
-Name[ka]=კვება
Name[kk]=Ақпарлар
Name[km]=មតិព័ត៌មាន
Name[lt]=Kanalai
@@ -98,7 +95,7 @@ Name[pl]=Kanały
Name[pt]=Fontes
Name[pt_BR]=Fontes de Notícias
Name[ru]=Ленты новостей
-Name[sk]=Kanály
+Name[sk]=Kŕmitka
Name[sl]=Viri
Name[sr]=Доводи
Name[sr@Latn]=Dovodi
@@ -106,7 +103,6 @@ Name[sv]=Kanaler
Name[ta]=உள்ளீடுகள்
Name[tr]=Haberler
Name[uk]=Подачі
-Name[uz]=Yangiliklar tasmalari
-Name[uz@cyrillic]=Янгиликлар тасмалари
+Name[uz]=Янгиликлар тасмалари
Name[zh_CN]=种子
diff --git a/kontact/plugins/kaddressbook/kaddressbook_plugin.cpp b/kontact/plugins/kaddressbook/kaddressbook_plugin.cpp
index e3128cdfb..d0493f1d0 100644
--- a/kontact/plugins/kaddressbook/kaddressbook_plugin.cpp
+++ b/kontact/plugins/kaddressbook/kaddressbook_plugin.cpp
@@ -145,8 +145,7 @@ bool KAddressbookPlugin::isRunningStandalone()
bool KAddressbookPlugin::canDecodeDrag( TQMimeSource *mimeSource )
{
- return TQTextDrag::canDecode( mimeSource ) ||
- KPIM::MailListDrag::canDecode( mimeSource );
+ return KPIM::MailListDrag::canDecode( mimeSource );
}
#include <dcopref.h>
diff --git a/kontact/plugins/kaddressbook/kaddressbookplugin.desktop b/kontact/plugins/kaddressbook/kaddressbookplugin.desktop
index f5208ea52..29e5cb23f 100644
--- a/kontact/plugins/kaddressbook/kaddressbookplugin.desktop
+++ b/kontact/plugins/kaddressbook/kaddressbookplugin.desktop
@@ -19,23 +19,17 @@ Comment=Contacts Component (KAdressbook Plugin)
Comment[bg]=Приставка за адресника
Comment[ca]=Component de contactes (endollable del KAdressbook)
Comment[da]=Kontaktkomponent (KAddressbook-plugin)
-Comment[de]=Kontakte-Komponente (Adressbuch-Modul)
+Comment[de]=Adressbuch-Komponente (KAddressbook-Modul)
Comment[el]=Συστατικό επαφών (Πρόσθετο του KAdressbook)
-Comment[es]=Componente de contactos (complemento de KAddressbook)
Comment[et]=Kontaktide plugin (KDE aadressiraamat)
-Comment[fr]=Composant des contacts (module externe KAdressBook)
-Comment[is]=Vistfangaskráreining (KAddressBook íforrit)
Comment[it]=Componente contatti (plugin KAddressbook)
Comment[ja]=アドレス帳コンポーネント (KAddressbook プラグイン)
-Comment[km]=សមាសភាគ​ទំនាក់ទំន​ង (កម្មវិធី​ជំនួយ KAdressbook​)
Comment[nds]=Kontakten-Komponent (KAddressbook-Moduul)
Comment[nl]=Adresboekcomponent (KAddressbook-plugin)
Comment[pl]=Składnik wizytówek (wtyczka KAddressBook)
-Comment[ru]=Контакты (модуль KAddressBook)
Comment[sr]=Компонента контаката (прикључак KAddressBook-а)
Comment[sr@Latn]=Komponenta kontakata (priključak KAddressBook-a)
Comment[sv]=Kontaktkomponent (adressboksinsticksprogram)
-Comment[tr]=Kişiler Bileşeni (KAdresDefteri Eklentisi)
Comment[zh_CN]=联系人组件(KAddressbook 插件)
Comment[zh_TW]=聯絡人組件(KAddressBook 外掛程式)
Name=Contacts
@@ -66,7 +60,6 @@ Name[hu]=Névjegyek
Name[is]=Tengiliðir
Name[it]=Contatti
Name[ja]=コンタクト
-Name[ka]=კონტაქტები
Name[kk]=Контакттар
Name[km]=ទំនាក់ទំនង
Name[lt]=Kontaktai
@@ -92,9 +85,8 @@ Name[sv]=Kontakter
Name[ta]=தொடர்புகள்
Name[tg]=Алоқот
Name[th]=ที่อยู่ติดต่อ
-Name[tr]=Kişiler
+Name[tr]=Bağlantılar
Name[uk]=Контакти
-Name[uz]=Aloqalar
-Name[uz@cyrillic]=Алоқалар
+Name[uz]=Алоқалар
Name[zh_CN]=联系人
Name[zh_TW]=聯絡人
diff --git a/kontact/plugins/karm/karmplugin.desktop b/kontact/plugins/karm/karmplugin.desktop
index 469989fe6..c6b39dfc3 100644
--- a/kontact/plugins/karm/karmplugin.desktop
+++ b/kontact/plugins/karm/karmplugin.desktop
@@ -16,23 +16,17 @@ Comment=Time Tracker Component (KArm Plugin)
Comment[bg]=Приставка за KArm
Comment[ca]=Component de seguiment dels temps (endollable del KArm)
Comment[da]=Time Tracker-komponent (KArm-plugin)
-Comment[de]=Zeitplaner-Komponente (KArm-Modul)
+Comment[de]=Zeiterfassungskomponente (KArm-Modul)
Comment[el]=Συστατικό γραμμής χρόνου (Πρόσθετο του KArm)
-Comment[es]=Componente de seguimiento de tiempos (complemento de KArm)
Comment[et]=Ajaarvestaja plugin (KArm)
-Comment[fr]=Composant de suivi temporel (Module pour KArm)
-Comment[is]=Tímastjórnunareining (KArm íforrit)
Comment[it]=Componente segna-tempo (plugin Karm)
Comment[ja]=タイムトラッカーコンポーネント (KArm プラグイン)
-Comment[km]=សមាសភាគ​កម្មវិធី​តាមដាន​ពេលវេលា (កម្មវិធី​ជំនួយ KArm​)
Comment[nds]=Tietlogbook-Komponent (KArm-Moduul)
Comment[nl]=Tijdsregistratiecomponent (KArm-plugin)
Comment[pl]=Składnik śledzenia czasu (wtyczka KArm)
-Comment[ru]=Отслеживание времени (модуль KArm)
Comment[sr]=Компонента праћења времена (прикључак KArm-а)
Comment[sr@Latn]=Komponenta praćenja vremena (priključak KArm-a)
Comment[sv]=Komponent för tidmätning (Karm-insticksprogram)
-Comment[tr]=Zaman İzleyici Bileşeni (KArm Eklentisi)
Comment[zh_CN]=时间追踪组件(KArm 插件)
Comment[zh_TW]=時間追蹤器組件(KArm 外掛程式)
@@ -41,17 +35,11 @@ Name[bg]=Таймер
Name[ca]=Cronòmetre
Name[de]=Stoppuhr
Name[el]=Χρονόμετρο
-Name[es]=Temporizador
Name[et]=Ajaarvestaja
-Name[fr]=Minuteur
-Name[is]=Tímamælir
Name[ja]=タイマー
-Name[km]=កម្មវិធី​កំណត់​ពេលវេលា
Name[nds]=Tietgever
Name[nl]=Tijdklok
Name[pl]=Stoper
-Name[ru]=Таймер
-Name[sk]=Časovač
Name[sr]=Тајмер
Name[sr@Latn]=Tajmer
Name[sv]=Tidmätning
diff --git a/kontact/plugins/kitchensync/kitchensync.desktop b/kontact/plugins/kitchensync/kitchensync.desktop
index 0b1ac5078..8b8fd76b3 100644
--- a/kontact/plugins/kitchensync/kitchensync.desktop
+++ b/kontact/plugins/kitchensync/kitchensync.desktop
@@ -16,25 +16,17 @@ Comment=Synchronization Component (Kitchensynk Plugin)
Comment[bg]=Приставка за синхронизация
Comment[ca]=Component de sincronització (endollable del KitchenSync)
Comment[da]=Synkronisergingskomponent (Kitchensync-plugin)
-Comment[de]=Abgleich-Komponente (KitchenSync-Modul)
+Comment[de]=Synchronisationskomponente (KitchenSync-Modul)
Comment[el]=Συστατικό συγχρονισμού (Πρόσθετο του Kitchensynk)
-Comment[en_GB]=Synchronisation Component (Kitchensynk Plugin)
-Comment[es]=Componente de sincronización (complemento de KitchenSync)
Comment[et]=Sünkroniseerimise plugin (KitchenSync)
-Comment[fr]=Composant de synchronisation (Module KitchenSync)
-Comment[is]=Samstillingareining (KitchenSync íforrit)
Comment[it]=Componente di sincronizzazione (plugin KitchenSync)
Comment[ja]=同期コンポーネント (KitchenSync プラグイン)
-Comment[km]=ការ​ធ្វើ​សមកាលកម្ម​សមាសភាគ (កម្មវិធី​ជំនួយ Kitchensynk​)
Comment[nds]=Synkroniseer-Komponent (Kitchensynk-Moduul)
Comment[nl]=Synchronisatiecomponent (Kitchensynk-plugin)
Comment[pl]=Składnik synchronizacji (wtyczka KitchenSync)
-Comment[ru]=Синхронизация (модуль KitchenSync)
-Comment[sk]=Synchronizačný komponent (Modul pre Kitchensynk)
Comment[sr]=Компонента синхронизације (прикључак KitchenSync-а)
Comment[sr@Latn]=Komponenta sinhronizacije (priključak KitchenSync-a)
Comment[sv]=Synkroniseringskomponent (Kitchensynk-insticksprogram)
-Comment[tr]=Eşzamanlama Eklentisi (Kitchensynk Eklentisi)
Comment[zh_CN]=同步组件(KitchenSync 插件)
Comment[zh_TW]=同步組件(KitchenSynk 外掛程式)
Name=Sync
@@ -42,11 +34,8 @@ Name[bg]=Синхронизация
Name[de]=Abgleich
Name[el]=Συγχρονισμός
Name[et]=Sünkroniseerimine
-Name[fr]=Synchroniser
-Name[is]=Samstilling
Name[ja]=同期
Name[nds]=Synkroniseren
Name[pl]=Synchronizacja
-Name[ru]=Синхронизация
Name[sv]=Synkronisering
Name[zh_TW]=同步
diff --git a/kontact/plugins/kmail/Makefile.am b/kontact/plugins/kmail/Makefile.am
index d176693a3..f390aff4e 100644
--- a/kontact/plugins/kmail/Makefile.am
+++ b/kontact/plugins/kmail/Makefile.am
@@ -1,5 +1,7 @@
INCLUDES = -I$(top_srcdir)/kontact/interfaces -I$(top_srcdir)/kmail -I$(top_builddir)/kmail \
-I$(top_srcdir)/libkdepim \
+ -I$(top_srcdir)/libkdenetwork \
+ -I$(top_srcdir)/certmanager/lib \
-I$(top_srcdir) $(all_includes)
kde_module_LTLIBRARIES = libkontact_kmailplugin.la kcm_kmailsummary.la
diff --git a/kontact/plugins/kmail/kcmkmailsummary.desktop b/kontact/plugins/kmail/kcmkmailsummary.desktop
index 2b8c7d99e..d616429e7 100644
--- a/kontact/plugins/kmail/kcmkmailsummary.desktop
+++ b/kontact/plugins/kmail/kcmkmailsummary.desktop
@@ -16,22 +16,15 @@ Name[ca]=Resum de correu
Name[da]=Oversigt over e-mail
Name[de]=E-Mail-Übersicht
Name[el]=Επισκόπηση αλληλογραφίας
-Name[es]=Resumen de correo electrónico
Name[et]=E-posti ülevaade
-Name[fr]=Aperçu du courriel
-Name[is]=Yfirsýn á tölvupóst
Name[it]=Panoramica posta elettronica
Name[ja]=メールの要約
-Name[km]=ទិដ្ឋភាព​ទូទៅ​របស់​អ៊ីមែល
Name[nds]=Nettpost-Översicht
Name[nl]=E-mailoverzicht
Name[pl]=Poczta
-Name[ru]=Сведения о почте
-Name[sk]=Prehľad pošty
Name[sr]=Преглед е-поште
Name[sr@Latn]=Pregled e-pošte
Name[sv]=E-postöversikt
-Name[tr]=E-Postalara Genel Bakış
Name[zh_CN]=邮件概览
Name[zh_TW]=郵件概要
Comment=E-Mail Summary Setup
@@ -40,22 +33,15 @@ Comment[ca]=Configuració del resum de correu
Comment[da]=Opsætning af post-opsummering
Comment[de]=Einstellungen für E-Mail-Übersicht
Comment[el]=Ρύθμιση σύνοψης αλληλογραφίας
-Comment[es]=Configuración del resumen de correo electrónico
Comment[et]=E-posti kokkuvõtte seadistus
-Comment[fr]=Configuration du résumé des courriels
-Comment[is]=Uppsetning póstyfirlits
Comment[it]=Impostazioni sommario posta elettronica
Comment[ja]=メール要約の設定
-Comment[km]=រៀបចំ​សេចក្ដី​សង្ខេប​អ៊ីមែល
Comment[nds]=Instellen för Nettpost-Översicht
Comment[nl]=Instellingen voor e-mailoverzicht
Comment[pl]=Ustawienia podsumowania e-maili
-Comment[ru]=Настройка сводки почты
-Comment[sk]=Nastavenie súhrnu pošty
Comment[sr]=Подешавање сажетка е-поште
Comment[sr@Latn]=Podešavanje sažetka e-pošte
Comment[sv]=Inställning av e-postöversikt
-Comment[tr]=E-Posta Özet Yapılandırması
Comment[zh_CN]=邮件摘要设置
Comment[zh_TW]=郵件摘要設定
Keywords=email, summary, configure, settings
@@ -72,7 +58,7 @@ Keywords[et]=e-post, meil, seadistamine, seadistused
Keywords[eu]=eposta, laburpena, konfiguratu, ezarpenak
Keywords[fa]=email، خلاصه، پیکربندی، تنظیمات
Keywords[fi]=sähköposti, yhteenveto, asetukset
-Keywords[fr]=message,messagerie,courriel,résumé,vue,configurer,paramètres,paramètre
+Keywords[fr]=message,messagerie,courrier,résumé,vue,configurer,paramètres,paramètre
Keywords[fy]=email,e-mail,e-post,oersicht,gearfetting,ynstellings, konfiguraasje
Keywords[ga]=ríomhphost, achoimre, cumraigh, socruithe
Keywords[gl]=email, resumo, configurar, opcións
@@ -81,7 +67,6 @@ Keywords[hu]=e-mail,áttekintés,konfigurálás,beállítások
Keywords[is]=tölvupóstur, yfirlit, stillingar, stilla
Keywords[it]=posta elettronica, email, sommario, configura, impostazioni
Keywords[ja]=メール,要約,設定,設定
-Keywords[ka]=ელფოსტა,დაიჯესტი,კონფიგურაცია,პარამეტრები
Keywords[km]=អ៊ីមែល,សង្ខេប,កំណត់​រចនាសម្ព័ន្ធ,ការ​កំណត់
Keywords[lt]=email, summary, configure, settings, e. paštas, santrauka, konfigūruoti, nustatymai
Keywords[mk]=email, summary, configure, settings, е-пошта, преглед, конфигурација, поставувања
@@ -91,10 +76,10 @@ Keywords[nds]=Nettpost,Nettbreef,Översicht,instellen
Keywords[ne]=इमेल, सारांश, कन्फिगर, सेटिङ
Keywords[nl]=email,e-mail,overzicht,samenvatting,instellingen,configuratie
Keywords[nn]=e-post,samandrag,oppsett,innstillingar
-Keywords[pl]=e-mail,list,podsumowanie,konfiguracja,ustawienia
+Keywords[pl]=email,list,podsumowanie,konfiguracja,ustawienia
Keywords[pt]=e-mail, sumário, configurar, configuração
Keywords[pt_BR]=e-mail, resumo, configurar, configurações
-Keywords[ru]=email,summary,configure,settings,настройки,сводка,почта
+Keywords[ru]=email,summary,configure,settings,настройки,дайджест,почта
Keywords[sk]=email,súhrn,nastavenie
Keywords[sl]=e-pošta,pošta,povzetek,nastavi,nastavitve
Keywords[sr]=емаил, сажетак, подеси, поставке
diff --git a/kontact/plugins/kmail/kmailplugin.desktop b/kontact/plugins/kmail/kmailplugin.desktop
index 55ba5e97b..7758a8e2a 100644
--- a/kontact/plugins/kmail/kmailplugin.desktop
+++ b/kontact/plugins/kmail/kmailplugin.desktop
@@ -22,46 +22,31 @@ Comment[ca]=Component de correu (endollable del KMail)
Comment[da]=Post-komponent (KMail-plugin)
Comment[de]=E-Mail-Komponente (KMail-Modul)
Comment[el]=Συστατικό αλληλογραφίας (Πρόσθετο του KMail)
-Comment[es]=Componente de correo electrónico (complemento de KMail)
Comment[et]=E-posti plugin (KMail)
-Comment[fr]=Composant de courriel (Module pour KMail)
-Comment[is]=Pósteining (KMail íforrit)
Comment[it]=Componente posta elettronica (plugin KMail)
Comment[ja]=メールコンポーネント (KMail プラグイン)
-Comment[km]=សមាសភាគ​អ៊ីមែល (កម្មវិធី​ជំនួយ KMail)
Comment[nds]=Nettpost-Komponent (KMail-Moduul)
Comment[nl]=E-mailcomponent (KMail-plugin)
Comment[pl]=Składnik poczty (wtyczka KMail)
-Comment[pt_BR]=Componente de e-mail (plug-in do KMail)
-Comment[ru]=Электронная почта (модуль KMail)
-Comment[sk]=Poštový komponent (Model pre KMail)
Comment[sr]=Компонента е-поште (прикључак KMail-а)
Comment[sr@Latn]=Komponenta e-pošte (priključak KMail-a)
Comment[sv]=E-postkomponent (Kmail-insticksprogram)
-Comment[tr]=E-Posta Bileşeni (KMail Eklentisi)
Comment[zh_CN]=邮件组件(KMail 插件)
Comment[zh_TW]=電子郵件組件(KMail 外掛程式)
Name=E-Mail
Name[bg]=Е-поща
Name[ca]=Correu
Name[da]=E-mail
+Name[de]=E-Mail
Name[el]=Αλληλογραφία
-Name[es]=Correo electrónico
Name[et]=E-post
-Name[fr]=Courriel
-Name[is]=Tölvupóstur
Name[it]=Posta elettronica
Name[ja]=メール
-Name[km]=អ៊ីមែល
Name[nds]=Nettpost
Name[nl]=E-mail
Name[pl]=E-mail
-Name[pt_BR]=E-mail
-Name[ru]=Электронная почта
-Name[sk]=Pošta
Name[sr]=Е-пошта
Name[sr@Latn]=E-pošta
Name[sv]=E-post
-Name[tr]=E-Posta
Name[zh_CN]=邮件
Name[zh_TW]=電子郵件
diff --git a/kontact/plugins/knode/knodeplugin.desktop b/kontact/plugins/knode/knodeplugin.desktop
index d84c16f7e..559eaadde 100644
--- a/kontact/plugins/knode/knodeplugin.desktop
+++ b/kontact/plugins/knode/knodeplugin.desktop
@@ -19,21 +19,15 @@ Comment[ca]=Component de notícies (endollable del KNode)
Comment[da]=Nyhedskomponent (KNode-plugin)
Comment[de]=News-Komponente (KNode-Modul)
Comment[el]=Συστατικό ανάγνωσης νέων (Πρόσθετο του KNode)
-Comment[es]=Componente de noticias (complemento de KNode)
Comment[et]=Uudistelugeja plugin (KNode)
-Comment[fr]=Composant de lecteur de nouvelles (Module pour KNode)
-Comment[is]=Fréttaeining (KNode íforrit)
Comment[it]=Componente lettore di news (plugin KNode)
Comment[ja]=ニュースリーダーコンポーネント (KNode プラグイン)
-Comment[km]=សមាសភាគ Newsreader (កម្មវិធី​ជំនួយ KNode)
Comment[nds]=Narichtenkieker-Komponent (KNode-Moduul)
Comment[nl]=Nieuwscomponent (KNode-plugin)
Comment[pl]=Składnik wiadomości (wtyczka KNode)
-Comment[ru]=Новости (модуль KNode)
Comment[sr]=Компонента вести (прикључак KNode-а)
Comment[sr@Latn]=Komponenta vesti (priključak KNode-a)
Comment[sv]=Komponent för läsning av diskussionsgrupper (Knode-insticksprogram)
-Comment[tr]=Haber Okuyucu Bileşeni (KNode Eklentisi)
Comment[zh_CN]=新闻组阅读器组件(KNode 插件)
Comment[zh_TW]=新聞閱讀器組件(KNode 外掛程式)
Name=News
@@ -64,7 +58,6 @@ Name[hi]=समाचार
Name[hu]=Hírek
Name[is]=Fréttir
Name[ja]=ニュース
-Name[ka]=სიახლეები
Name[kk]=Жаңалықтар
Name[km]=ព័ត៌មាន
Name[lt]=Naujienos
@@ -92,7 +85,6 @@ Name[tg]=Ахборот
Name[th]=ข่าว
Name[tr]=Haberler
Name[uk]=Новини
-Name[uz]=Yangiliklar
-Name[uz@cyrillic]=Янгиликлар
+Name[uz]=Янгиликлар
Name[zh_CN]=新闻
Name[zh_TW]=新聞
diff --git a/kontact/plugins/knotes/knotes_part.cpp b/kontact/plugins/knotes/knotes_part.cpp
index 4702eb2d2..d4a5e8547 100644
--- a/kontact/plugins/knotes/knotes_part.cpp
+++ b/kontact/plugins/knotes/knotes_part.cpp
@@ -386,12 +386,14 @@ void KNotesPart::editNote( TQIconViewItem *item )
void KNotesPart::renameNote()
{
+ mOldName = mNotesView->currentItem()->text();
mNotesView->currentItem()->rename();
}
void KNotesPart::renamedNote( TQIconViewItem* )
{
- mManager->save();
+ if ( mOldName != mNotesView->currentItem()->text() )
+ mManager->save();
}
void KNotesPart::slotOnCurrentChanged( TQIconViewItem* )
diff --git a/kontact/plugins/knotes/knotes_part.h b/kontact/plugins/knotes/knotes_part.h
index de41f9aae..764bb4849 100644
--- a/kontact/plugins/knotes/knotes_part.h
+++ b/kontact/plugins/knotes/knotes_part.h
@@ -96,6 +96,7 @@ class KNotesPart : public KParts::ReadOnlyPart, virtual public KNotesIface
KNotesResourceManager *mManager;
TQDict<KNotesIconViewItem> mNoteList;
+ TQString mOldName;
};
#endif
diff --git a/kontact/plugins/knotes/knotesplugin.desktop b/kontact/plugins/knotes/knotesplugin.desktop
index e7fe8fc0c..71068d94f 100644
--- a/kontact/plugins/knotes/knotesplugin.desktop
+++ b/kontact/plugins/knotes/knotesplugin.desktop
@@ -19,21 +19,15 @@ Comment[ca]=Component de notes (endollable del KNotes)
Comment[da]=Notatkomponent (KNotes-plugin)
Comment[de]=Notizen-Komponente (KNotes-Modul)
Comment[el]=Συσταικό σημειώσεων (Πρόσθετο του KNotes)
-Comment[es]=Componente de notas (complemento de KNotes)
Comment[et]=Märkmete plugin (KNotes)
-Comment[fr]=Composant de notes (Module KNotes)
-Comment[is]=Minnismiðaeining (KNotes íforrit)
Comment[it]=Componente note (plugin KNotes)
Comment[ja]=メモコンポーネント (KNotes プラグイン)
-Comment[km]=សមាសភាគ​ចំណាំ (កម្មវិធី​ជំនួយ KNotes​)
Comment[nds]=Notizen-Komponent (KNotes-Moduul)
Comment[nl]=Notitiecomponent (KNotes-plugin)
Comment[pl]=Składnik notatek (wtyczka KNotes)
-Comment[ru]=Заметки (модуль KNotes)
Comment[sr]=Компонента белешки (прикључак KNotes-а)
Comment[sr@Latn]=Komponenta beleški (priključak KNotes-a)
Comment[sv]=Anteckningskomponent (Knotes-insticksprogram)
-Comment[tr]=Notlar Bileşeni (KNotes Eklentisi)
Comment[zh_CN]=便笺组件(KNotes 插件)
Comment[zh_TW]=便條組件(KNotes 外掛程式)
Name=Notes
@@ -63,7 +57,6 @@ Name[hu]=Feljegyzések
Name[is]=Minnismiðar
Name[it]=Note
Name[ja]=メモ
-Name[ka]=ჩანიშვნები
Name[kk]=Жазбалар
Name[km]=ចំណាំ
Name[lt]=Užrašai
@@ -89,7 +82,6 @@ Name[tg]=Ахборот
Name[th]=บันทึกช่วยจำ
Name[tr]=Notlar
Name[uk]=Примітки
-Name[uz]=Yozma xotira
-Name[uz@cyrillic]=Ёзма хотира
+Name[uz]=Ёзма хотира
Name[zh_CN]=便笺
Name[zh_TW]=備忘錄
diff --git a/kontact/plugins/korganizer/journalplugin.desktop b/kontact/plugins/korganizer/journalplugin.desktop
index 8f33753ed..f24c1206c 100644
--- a/kontact/plugins/korganizer/journalplugin.desktop
+++ b/kontact/plugins/korganizer/journalplugin.desktop
@@ -21,21 +21,15 @@ Comment[ca]=Component de diari (endollable del KOrganizer)
Comment[da]=Journalkomponent (KOrganizer-plugin)
Comment[de]=Journal-Komponente (KOrganizer-Modul)
Comment[el]=Συστατικό χρονικών (Πρόσθετο του KOrganizer)
-Comment[es]=Componente de diario (Complemento de KOrganizer)
Comment[et]=Päevikuplugin (KOrganizer)
-Comment[fr]= Composant de journal (Module KOrganizer)
-Comment[is]=Dagbókareining (Journal KOrganizer íforrit)
Comment[it]=Componente diario (plugin KOrganizer)
Comment[ja]=ジャーナルコンポーネント (KOrganizer プラグイン)
-Comment[km]=សមាភាគទិនានុប្បវត្តិ (កម្មវិធី​ជំនួយ KOrganizer​)
Comment[nds]=Daagböker-Komponent (KOrganizer-Moduul)
Comment[nl]=Journaalcomponent (KOrganizer-plugin)
Comment[pl]=Składnik dziennika (wtyczka Korganizer)
-Comment[ru]=Журнал (модуль KOrganizer)
Comment[sr]=Компонента дневника (прикључак KOrganizer-а)
Comment[sr@Latn]=Komponenta dnevnika (priključak KOrganizer-a)
Comment[sv]=Journalkomponent (Korganizer-insticksprogram)
-Comment[tr]=Günlük Bileşeni (KOrganizer Eklentisi)
Comment[zh_CN]=日记组件(KOrganizer 插件)
Comment[zh_TW]=日誌組件(KOrganizer 外掛程式)
Name=Journal
@@ -61,7 +55,6 @@ Name[hu]=Napló
Name[is]=Dagbók
Name[it]=Diario
Name[ja]=ジャーナル
-Name[ka]=ჟურნალი
Name[kk]=Күнделік
Name[km]=ទិនានុប្បវត្តិ
Name[lt]=Dienynas
@@ -83,7 +76,6 @@ Name[ta]=பத்திரிகை
Name[th]=วารสาร
Name[tr]=Günlük
Name[uk]=Журнал
-Name[uz]=Kundalik
-Name[uz@cyrillic]=Кундалик
+Name[uz]=Кундалик
Name[zh_CN]=日记
Name[zh_TW]=日誌
diff --git a/kontact/plugins/korganizer/journalplugin.h b/kontact/plugins/korganizer/journalplugin.h
index 2aeca3544..beb4c2e95 100644
--- a/kontact/plugins/korganizer/journalplugin.h
+++ b/kontact/plugins/korganizer/journalplugin.h
@@ -40,7 +40,7 @@ class JournalPlugin : public Kontact::Plugin
virtual bool createDCOPInterface( const TQString& serviceType );
virtual bool isRunningStandalone();
- int weight() const { return 500; }
+ int weight() const { return 525; }
virtual TQStringList invisibleToolbarActions() const;
diff --git a/kontact/plugins/korganizer/kcmkorgsummary.desktop b/kontact/plugins/korganizer/kcmkorgsummary.desktop
index 2f657852e..175ed6242 100644
--- a/kontact/plugins/korganizer/kcmkorgsummary.desktop
+++ b/kontact/plugins/korganizer/kcmkorgsummary.desktop
@@ -16,21 +16,15 @@ Name[ca]=Resum de cites i tasques pendents
Name[da]=Oversigt over møder og gøremål
Name[de]=Übersicht über Termine und Aufgaben
Name[el]=Επισκόπηση ραντεβού και προς υλοποίηση εργασιών
-Name[es]=Resumen de citas y tareas pendientes
Name[et]=Kohtumised ja ülesannete ülevaade
-Name[fr]=Aperçu des rendez-vous et des tâches
-Name[is]=Yfirlit um fundi og verkþætti
Name[it]=Panoramica appuntamenti e cose da fare
Name[ja]=約束と To-Do の要約
-Name[km]=ទិដ្ឋភាព​ការ​ណាត់ និង​ការងារ​ត្រូវ​ធ្វើ
Name[nds]=Termin- un Opgaven-Översicht
Name[nl]=Overzicht van evenementen en taken
Name[pl]=Spotkania i zadania
-Name[ru]=Сводка встреч и задач
Name[sr]=Преглед састанака и обавеза
Name[sr@Latn]=Pregled sastanaka i obaveza
Name[sv]=Översikt av möten och uppgifter
-Name[tr]=Randevulara ve Yapılacaklara Genel Bakış
Name[zh_CN]=约会和待办概览
Name[zh_TW]=約會與待辦事項概觀
Comment=Appointments and To-dos Summary Setup
@@ -50,10 +44,9 @@ Comment[fr]=Configuration du résumé des évènements et des tâches
Comment[fy]=Oersichtsynstellings foar eveneminten en taken
Comment[gl]=Configuración de sumarios de tarefas e notas
Comment[hu]=A találkozók és feladatok áttekintőjének beállítása
-Comment[is]=Uppsetning á yfirliti yfir fundi og verkefni
+Comment[is]=Uppsetning á yfirliti yfir fundi og verkþætti
Comment[it]=Impostazioni sommario appuntamenti e cose da fare
Comment[ja]=約束と To-Do の要約設定
-Comment[ka]=შეხვედრათა და გასაკეთებელთა რეზიუმეს დაყენება
Comment[kk]=Кездесулер мен Жоспарлар тұжырымының баптау
Comment[km]=រៀបចំ​សេចក្ដី​សង្ខេប​ការ​ណាត់ និង​ការងារ​ត្រូវ​ធ្វើ
Comment[lt]=Susitikimų ir užduočių santraukos nustatymai
@@ -66,7 +59,7 @@ Comment[nn]=Oppsett av samandrag av avtalar og oppgåver
Comment[pl]=Ustawienia podsumowania spotkań i zadań
Comment[pt]=Configuração do Sumário de Compromissos e A-fazeres
Comment[pt_BR]=Configuração do Resumo de Compromissos e Tarefas
-Comment[ru]=Настройка сводки встреч и задач
+Comment[ru]=Настройка показа встреч и задач
Comment[sk]=Nastavenie súhrnu pripomienok a úloh
Comment[sl]=Nastavitve povzetka sestankov in opravil
Comment[sr]=Подешавање сажетка састанака и обавеза
@@ -97,10 +90,9 @@ Keywords[ga]=féilire, tascanna, cumraigh, socruithe
Keywords[gl]=calendario, pendentes, configurar, opcións
Keywords[he]=calendar, todos, configure, settings, יומן, יומנים, משימות, מטלות, הגדרות, תצורה
Keywords[hu]=naptár,feladatok,konfigurálás,beállítások
-Keywords[is]=dagatal, verkefni, stillingar, stilla
+Keywords[is]=dagatal, verkþættir, stillingar, stilla
Keywords[it]=calendario, cose da fare, configura, impostazioni
Keywords[ja]=カレンダー, To-Do, 設定
-Keywords[ka]=კალენდარი,გასაკეთებლები,კონფიგურაცია,პარამეტრები
Keywords[km]=ប្រតិទិន,ការងារ​ត្រូវ​ធ្វើ,កំណត់​រចនាសម្ព័ន្ធ,ការ​កំណត់
Keywords[lt]=calendar, todos, configure, settings, kalendorius, darbai, konfigūruoti, nustatymai
Keywords[ms]=kalendar, tugasan, konfigur, seting
diff --git a/kontact/plugins/korganizer/korg_uniqueapp.cpp b/kontact/plugins/korganizer/korg_uniqueapp.cpp
index b70042353..42a7adcae 100644
--- a/kontact/plugins/korganizer/korg_uniqueapp.cpp
+++ b/kontact/plugins/korganizer/korg_uniqueapp.cpp
@@ -20,19 +20,40 @@
*/
#include "korg_uniqueapp.h"
-#include <kdebug.h>
#include "../../korganizer/korganizer_options.h"
+#include "core.h"
+#include <dcopref.h>
+#include <kapplication.h>
+#include <kstartupinfo.h>
+#include <kwin.h>
+
void KOrganizerUniqueAppHandler::loadCommandLineOptions()
{
- KCmdLineArgs::addCmdLineOptions( korganizer_options );
+ KCmdLineArgs::addCmdLineOptions( korganizer_options );
}
int KOrganizerUniqueAppHandler::newInstance()
{
- //kdDebug(5602) << k_funcinfo << endl;
- // Ensure part is loaded
- (void)plugin()->part();
- // TODO handle command line options
- return Kontact::UniqueAppHandler::newInstance();
+ // Ensure part is loaded
+ (void)plugin()->part();
+ DCOPRef korganizer( "korganizer", "KOrganizerIface" );
+ korganizer.send( "handleCommandLine" );
+
+ // Bring korganizer's plugin to front
+ // This bit is duplicated from KUniqueApplication::newInstance()
+ if ( kapp->mainWidget() ) {
+ kapp->mainWidget()->show();
+ KWin::forceActiveWindow( kapp->mainWidget()->winId() );
+ KStartupInfo::appStarted();
+ }
+
+ // Then ensure the part appears in kontact.
+ // ALWAYS use the korganizer plugin; i.e. never show the todo nor journal
+ // plugins when creating a new instance via the command line, even if
+ // the command line options are empty; else we'd need to examine the
+ // options and then figure out which plugin we should show.
+ // kolab/issue3971
+ plugin()->core()->selectPlugin( "kontact_korganizerplugin" );
+ return 0;
}
diff --git a/kontact/plugins/korganizer/korganizerplugin.cpp b/kontact/plugins/korganizer/korganizerplugin.cpp
index f0f88c7ca..cd590ec96 100644
--- a/kontact/plugins/korganizer/korganizerplugin.cpp
+++ b/kontact/plugins/korganizer/korganizerplugin.cpp
@@ -42,6 +42,10 @@
#include <libkdepim/kvcarddrag.h>
#include <libkdepim/maillistdrag.h>
+#include <libkdepim/kpimprefs.h>
+
+#include <libkcal/calendarlocal.h>
+#include <libkcal/icaldrag.h>
#include "core.h"
#include "summarywidget.h"
@@ -78,6 +82,11 @@ KOrganizerPlugin::~KOrganizerPlugin()
Kontact::Summary *KOrganizerPlugin::createSummaryWidget( TQWidget *parent )
{
+ // korg part must be loaded, otherwise when starting kontact on summary view
+ // it won't display our stuff.
+ // If the part is already loaded loadPart() is harmless and just returns
+ loadPart();
+
return new SummaryWidget( this, parent );
}
@@ -160,27 +169,43 @@ bool KOrganizerPlugin::canDecodeDrag( TQMimeSource *mimeSource )
void KOrganizerPlugin::processDropEvent( TQDropEvent *event )
{
- TQString text;
-
- KABC::VCardConverter converter;
- if ( KVCardDrag::canDecode( event ) && KVCardDrag::decode( event, text ) ) {
- KABC::Addressee::List contacts = converter.parseVCards( text );
- KABC::Addressee::List::Iterator it;
-
+ KABC::Addressee::List list;
+ if ( KVCardDrag::decode( event, list ) ) {
TQStringList attendees;
- for ( it = contacts.begin(); it != contacts.end(); ++it ) {
+ KABC::Addressee::List::Iterator it;
+ for ( it = list.begin(); it != list.end(); ++it ) {
TQString email = (*it).fullEmail();
- if ( email.isEmpty() )
+ if ( email.isEmpty() ) {
attendees.append( (*it).realName() + "<>" );
- else
+ } else {
attendees.append( email );
+ }
}
-
interface()->openEventEditor( i18n( "Meeting" ), TQString::null, TQString::null,
attendees );
return;
}
+ if ( KCal::ICalDrag::canDecode( event) ) {
+ KCal::CalendarLocal cal( KPimPrefs::timezone() );
+ if ( KCal::ICalDrag::decode( event, &cal ) ) {
+ KCal::Incidence::List incidences = cal.incidences();
+ if ( !incidences.isEmpty() ) {
+ event->accept();
+ KCal::Incidence *i = incidences.first();
+ TQString summary;
+ if ( dynamic_cast<KCal::Journal*>( i ) )
+ summary = i18n( "Note: %1" ).arg( i->summary() );
+ else
+ summary = i->summary();
+ interface()->openEventEditor( summary, i->description(), TQString() );
+ return;
+ }
+ // else fall through to text decoding
+ }
+ }
+
+ TQString text;
if ( TQTextDrag::decode( event, text ) ) {
kdDebug(5602) << "DROP:" << text << endl;
interface()->openEventEditor( text );
diff --git a/kontact/plugins/korganizer/korganizerplugin.desktop b/kontact/plugins/korganizer/korganizerplugin.desktop
index 7a29913c1..896320c15 100644
--- a/kontact/plugins/korganizer/korganizerplugin.desktop
+++ b/kontact/plugins/korganizer/korganizerplugin.desktop
@@ -21,22 +21,15 @@ Comment[ca]=Component de calendari (endollable del KOrganizer)
Comment[da]=Kalenderkomponent (KOrganizer-plugin)
Comment[de]=Kalender-Komponente (KOrganizer-Modul)
Comment[el]=Συστατικό ημερολογίου (Πρόσθετο του KOrganizer)
-Comment[es]=Componente de calendario (complemento de KOrganizer)
Comment[et]=Kalendriplugin (KOrganizer)
-Comment[fr]= Composant de calendrier (Module KOrganizer)
-Comment[is]=Dagatalseining (KOrganizer íforrit)
Comment[it]=Componente calendario (plugin KOrganizer)
Comment[ja]=カレンダーコンポーネント (KOrganizer プラグイン)
-Comment[km]=សមាសភាគ​ប្រតិទិន (កម្មវិធីជំនួយ​ KOrganizer​)
Comment[nds]=Kalenner-Komponent (KOrganizer-Moduul)
Comment[nl]=Agendacomponent (KOrganizer-plugin)
Comment[pl]=Składnik kalendarza (wtyczka KOrganizer)
-Comment[ru]=Календарь (модуль KOrganizer)
-Comment[sk]=Kalendárový komponent (Modeul pre KOrganizer)
Comment[sr]=Компонента календара (прикључак KOrganizer-а)
Comment[sr@Latn]=Komponenta kalendara (priključak KOrganizer-a)
Comment[sv]=Kalenderkomponent (Korganizer-insticksprogram)
-Comment[tr]=Takvim Bileşeni (KOrganizer Eklentisi)
Comment[zh_CN]=日历组件(KOrganizer 插件)
Comment[zh_TW]=行事曆組件(KOrganizer 外掛程式)
Name=Calendar
@@ -68,7 +61,6 @@ Name[hu]=Naptár
Name[is]=Dagatal
Name[it]=Calendario
Name[ja]=カレンダー
-Name[ka]=კალენდარი
Name[kk]=Күнтізбе
Name[km]=ប្រតិទិន
Name[lt]=Kalendorius
@@ -95,7 +87,6 @@ Name[tg]=Тақвим
Name[th]=บันทึกประจำวัน
Name[tr]=Takvim
Name[uk]=Календар
-Name[uz]=Kalendar
-Name[uz@cyrillic]=Календар
+Name[uz]=Календар
Name[zh_CN]=日历
Name[zh_TW]=行事曆
diff --git a/kontact/plugins/korganizer/summarywidget.cpp b/kontact/plugins/korganizer/summarywidget.cpp
index ff3d5da9d..cab7788f9 100644
--- a/kontact/plugins/korganizer/summarywidget.cpp
+++ b/kontact/plugins/korganizer/summarywidget.cpp
@@ -65,7 +65,6 @@ SummaryWidget::SummaryWidget( KOrganizerPlugin *plugin, TQWidget *parent,
mLayout->setRowStretch( 6, 1 );
mCalendar = KOrg::StdCalendar::self();
- mCalendar->load();
connect( mCalendar, TQT_SIGNAL( calendarChanged() ), TQT_SLOT( updateView() ) );
connect( mPlugin->core(), TQT_SIGNAL( dayChanged( const TQDate& ) ),
@@ -94,6 +93,8 @@ void SummaryWidget::updateView()
TQLabel *label = 0;
int counter = 0;
TQPixmap pm = loader.loadIcon( "appointment", KIcon::Small );
+ TQPixmap pmb = loader.loadIcon( "calendarbirthday", KIcon::Small );
+ TQPixmap pma = loader.loadIcon( "calendaranniversary", KIcon::Small );
TQDate dt;
TQDate currentDate = TQDate::currentDate();
@@ -101,38 +102,22 @@ void SummaryWidget::updateView()
dt<=currentDate.addDays( days - 1 );
dt=dt.addDays(1) ) {
- KCal::Event *ev;
-
- KCal::Event::List events_orig = mCalendar->events( dt );
- KCal::Event::List::ConstIterator it = events_orig.begin();
-
- KCal::Event::List events;
- events.setAutoDelete( true );
- TQDateTime qdt;
-
- // prevent implicitely sharing while finding recurring events
- // replacing the TQDate with the currentDate
- for ( ; it != events_orig.end(); ++it ) {
- ev = (*it)->clone();
- if ( ev->recursOn( dt ) ) {
- qdt = ev->dtStart();
- qdt.setDate( dt );
- ev->setDtStart( qdt );
- }
- events.append( ev );
- }
+ KCal::Event::List events = mCalendar->events( dt );
// sort the events for this date by summary
- events = KCal::Calendar::sortEvents( &events,
- KCal::EventSortSummary,
- KCal::SortDirectionAscending );
+ events = KCal::Calendar::sortEventsForDate( &events,
+ dt,
+ KCal::EventSortSummary,
+ KCal::SortDirectionAscending );
// sort the events for this date by start date
- events = KCal::Calendar::sortEvents( &events,
- KCal::EventSortStartDate,
- KCal::SortDirectionAscending );
+ events = KCal::Calendar::sortEventsForDate( &events,
+ dt,
+ KCal::EventSortStartDate,
+ KCal::SortDirectionAscending );
+ KCal::Event::List::ConstIterator it = events.begin();
for ( it=events.begin(); it!=events.end(); ++it ) {
- ev = *it;
+ KCal::Event *ev = *it;
// Count number of days remaining in multiday event
int span=1; int dayof=1;
@@ -156,7 +141,13 @@ void SummaryWidget::updateView()
// Fill Appointment Pixmap Field
label = new TQLabel( this );
- label->setPixmap( pm );
+ if ( ev->categories().contains( "Birthday" ) ) {
+ label->setPixmap( pmb );
+ } else if ( ev->categories().contains( "Anniversary" ) ) {
+ label->setPixmap( pma );
+ } else {
+ label->setPixmap( pm );
+ }
label->setMaximumWidth( label->minimumSizeHint().width() );
label->setAlignment( AlignVCenter );
mLayout->addWidget( label, counter, 0 );
@@ -167,7 +158,7 @@ void SummaryWidget::updateView()
TQString datestr;
// Modify event date for printing
- TQDate sD = TQDate::TQDate( dt.year(), dt.month(), dt.day() );
+ TQDate sD = TQDate( dt.year(), dt.month(), dt.day() );
if ( ( sD.month() == currentDate.month() ) &&
( sD.day() == currentDate.day() ) ) {
datestr = i18n( "Today" );
@@ -216,7 +207,7 @@ void SummaryWidget::updateView()
connect( urlLabel, TQT_SIGNAL( rightClickedURL( const TQString& ) ),
this, TQT_SLOT( popupMenu( const TQString& ) ) );
- TQString tipText( KCal::IncidenceFormatter::toolTipString( ev, true ) );
+ TQString tipText( KCal::IncidenceFormatter::toolTipStr( mCalendar, ev, dt, true ) );
if ( !tipText.isEmpty() ) {
TQToolTip::add( urlLabel, tipText );
}
@@ -227,10 +218,10 @@ void SummaryWidget::updateView()
TQTime sET = ev->dtEnd().time();
if ( ev->isMultiDay() ) {
if ( ev->dtStart().date() < dt ) {
- sST = TQTime::TQTime( 0, 0 );
+ sST = TQTime( 0, 0 );
}
if ( ev->dtEnd().date() > dt ) {
- sET = TQTime::TQTime( 23, 59 );
+ sET = TQTime( 23, 59 );
}
}
datestr = i18n( "Time from - to", "%1 - %2" )
diff --git a/kontact/plugins/korganizer/todoplugin.cpp b/kontact/plugins/korganizer/todoplugin.cpp
index 3b6ab214f..bc76205c2 100644
--- a/kontact/plugins/korganizer/todoplugin.cpp
+++ b/kontact/plugins/korganizer/todoplugin.cpp
@@ -161,22 +161,18 @@ bool TodoPlugin::isRunningStandalone()
void TodoPlugin::processDropEvent( TQDropEvent *event )
{
- TQString text;
-
- KABC::VCardConverter converter;
- if ( KVCardDrag::canDecode( event ) && KVCardDrag::decode( event, text ) ) {
- KABC::Addressee::List contacts = converter.parseVCards( text );
- KABC::Addressee::List::Iterator it;
-
+ KABC::Addressee::List list;
+ if ( KVCardDrag::decode( event, list ) ) {
TQStringList attendees;
- for ( it = contacts.begin(); it != contacts.end(); ++it ) {
+ KABC::Addressee::List::Iterator it;
+ for ( it = list.begin(); it != list.end(); ++it ) {
TQString email = (*it).fullEmail();
- if ( email.isEmpty() )
+ if ( email.isEmpty() ) {
attendees.append( (*it).realName() + "<>" );
- else
+ } else {
attendees.append( email );
+ }
}
-
interface()->openTodoEditor( i18n( "Meeting" ), TQString::null, TQString::null,
attendees );
return;
@@ -185,17 +181,23 @@ void TodoPlugin::processDropEvent( TQDropEvent *event )
if ( KCal::ICalDrag::canDecode( event) ) {
KCal::CalendarLocal cal( KPimPrefs::timezone() );
if ( KCal::ICalDrag::decode( event, &cal ) ) {
- KCal::Journal::List journals = cal.journals();
- if ( !journals.isEmpty() ) {
+ KCal::Incidence::List incidences = cal.incidences();
+ if ( !incidences.isEmpty() ) {
event->accept();
- KCal::Journal *j = journals.first();
- interface()->openTodoEditor( i18n("Note: %1").arg( j->summary() ), j->description(), TQString() );
+ KCal::Incidence *i = incidences.first();
+ TQString summary;
+ if ( dynamic_cast<KCal::Journal*>( i ) )
+ summary = i18n( "Note: %1" ).arg( i->summary() );
+ else
+ summary = i->summary();
+ interface()->openTodoEditor( summary, i->description(), TQString() );
return;
}
// else fall through to text decoding
}
}
+ TQString text;
if ( TQTextDrag::decode( event, text ) ) {
interface()->openTodoEditor( text );
return;
@@ -217,8 +219,8 @@ void TodoPlugin::processDropEvent( TQDropEvent *event )
mail.messageId();
tf.file()->writeBlock( event->encodedData( "message/rfc822" ) );
tf.close();
- interface()->openTodoEditor( i18n("Mail: %1").arg( mail.subject() ), txt,
- uri, tf.name(), TQStringList(), "message/rfc822" );
+ interface()->openTodoEditor( i18n("Mail: %1").arg( mail.subject() ),
+ txt, uri, tf.name(), TQStringList(), "message/rfc822", false );
}
return;
}
diff --git a/kontact/plugins/korganizer/todoplugin.desktop b/kontact/plugins/korganizer/todoplugin.desktop
index a571539d8..dde1a0c1b 100644
--- a/kontact/plugins/korganizer/todoplugin.desktop
+++ b/kontact/plugins/korganizer/todoplugin.desktop
@@ -21,22 +21,15 @@ Comment[ca]=Component de llista de pendents (endollable del KOrganizer)
Comment[da]=Komponent til gøremålsliste (KOrganizer-plugin)
Comment[de]=Aufgabenlisten-Komponente (KOrganizer-Modul)
Comment[el]=Συστατικό λίστα προς υλοποίηση εργασιών (Πρόσθετο του KOrganizer)
-Comment[es]=Componente de tareas pendientes (complemento de KOrganizer)
Comment[et]=Ülesannete nimekirja plugin (KOrganizer)
-Comment[fr]=Composant de la liste des tâches (Module KOrganizer)
-Comment[is]=Verkefnaeining (KOrganizer íforrit)
Comment[it]=Componente elenco delle cose da fare (plugin KOrganizer)
Comment[ja]=To-Do リストコンポーネント (KOrganizer プラグイン)
-Comment[km]=សមាសភាគ​បញ្ជី​ការងារ​ត្រូវ​ធ្វើ (កម្មវិធី​ជំនួយ KOrganizer​)
Comment[nds]=Opgavenlist-Komponent (KOrganizer-Moduul)
Comment[nl]=Takenlijstcomponent (KOrganizer-plugin)
Comment[pl]=Składnik zadań (wtyczka KOrganizer)
-Comment[ru]=Задачи (модуль KOrganizer)
-Comment[sk]=Komponent zoznamu úloh (Modul pre KOrganizer)
Comment[sr]=Прикључак листе обавеза (прикључак KOrganizer-а)
Comment[sr@Latn]=Priključak liste obaveza (priključak KOrganizer-a)
Comment[sv]=Uppgiftslistkomponent (Korganizer-insticksprogram)
-Comment[tr]=Yapılacak İşler Bileşeni (KOrganizer eklentisi)
Comment[zh_CN]=待办清单组件(KOrganizer 插件)
Comment[zh_TW]=待辦事項清單組件(KOrganizer 外掛程式)
Name=To-do
@@ -45,21 +38,14 @@ Name[ca]=Pendents
Name[da]=Gøremål
Name[de]=Aufgaben
Name[el]=Προς υλοποίηση εργασίες
-Name[es]=Tareas pendientes
Name[et]=Ülesanded
-Name[fr]=Tâches
-Name[is]=Verkefni
Name[it]=Cose da fare
Name[ja]=To-Do
-Name[km]=​ការងារ​ត្រូវ​ធ្វើ
Name[nds]=Opgaav
Name[nl]=Takenlijst
Name[pl]=Lista zadań
-Name[ru]=Задачи
-Name[sk]=Zoznam úloh
Name[sr]=Обавезе
Name[sr@Latn]=Obaveze
Name[sv]=Uppgift
-Name[tr]=Yapılacak Ögeleri
Name[zh_CN]=待办清单
Name[zh_TW]=待辦事項
diff --git a/kontact/plugins/korganizer/todosummarywidget.cpp b/kontact/plugins/korganizer/todosummarywidget.cpp
index e58ee6aa0..953aa42cb 100644
--- a/kontact/plugins/korganizer/todosummarywidget.cpp
+++ b/kontact/plugins/korganizer/todosummarywidget.cpp
@@ -67,7 +67,6 @@ TodoSummaryWidget::TodoSummaryWidget( TodoPlugin *plugin,
mLayout->setRowStretch( 6, 1 );
mCalendar = KOrg::StdCalendar::self();
- mCalendar->load();
connect( mCalendar, TQT_SIGNAL( calendarChanged() ), TQT_SLOT( updateView() ) );
connect( mPlugin->core(), TQT_SIGNAL( dayChanged( const TQDate& ) ),
@@ -169,7 +168,7 @@ void TodoSummaryWidget::updateView()
connect( urlLabel, TQT_SIGNAL( rightClickedURL( const TQString& ) ),
this, TQT_SLOT( popupMenu( const TQString& ) ) );
- TQString tipText( KCal::IncidenceFormatter::toolTipString( todo, true ) );
+ TQString tipText( KCal::IncidenceFormatter::toolTipStr( mCalendar, todo, currentDate, true ) );
if ( !tipText.isEmpty() ) {
TQToolTip::add( urlLabel, tipText );
}
@@ -213,11 +212,11 @@ void TodoSummaryWidget::completeTodo( const TQString &uid )
{
KCal::Todo *todo = mCalendar->todo( uid );
IncidenceChanger *changer = new IncidenceChanger( mCalendar, this );
- if ( !todo->isReadOnly() && changer->beginChange( todo ) ) {
+ if ( !todo->isReadOnly() && changer->beginChange( todo, 0, TQString() ) ) {
KCal::Todo *oldTodo = todo->clone();
todo->setCompleted( TQDateTime::currentDateTime() );
- changer->changeIncidence( oldTodo, todo, KOGlobals::COMPLETION_MODIFIED );
- changer->endChange( todo );
+ changer->changeIncidence( oldTodo, todo, KOGlobals::COMPLETION_MODIFIED, this );
+ changer->endChange( todo, 0, TQString() );
delete oldTodo;
updateView();
}
diff --git a/kontact/plugins/kpilot/kpilotplugin.desktop b/kontact/plugins/kpilot/kpilotplugin.desktop
index 7ad217fd9..68f8d9d29 100644
--- a/kontact/plugins/kpilot/kpilotplugin.desktop
+++ b/kontact/plugins/kpilot/kpilotplugin.desktop
@@ -19,26 +19,21 @@ Comment=Palm Tools Component (KPilot Plugin)
Comment[bg]=Приставка за KPilot
Comment[ca]=Component d'eines de la Palm (endollable del KPilot)
Comment[da]=Komponent til palm-værktøjer (KPilot-plugin)
-Comment[de]=Palm-Komponente (KPilot-Modul)
+Comment[de]=Palm Werkzeuge (KPilot-Modul)
Comment[el]=Συστατικό εργαλείων Palm (Πρόσθετο του KPilot)
-Comment[es]=Componente de herramientas de Palm (complemento KPilot)
Comment[et]=Palmi tööriistade plugin (KPilot)
-Comment[fr]=Composant d'outils pour Palms (Module KPilot)
-Comment[is]=Palm verkfæraeining (KPilot íforrit)
Comment[it]=Componente strumenti Palm (plugin KPilot)
Comment[ja]=Palm ツールコンポーネント (KPilot プラグイン)
-Comment[km]=សមាសភាគ​ឧបករណ៍ Palm (កម្មវិធី​ជំនួយ KPilot​)
Comment[nds]=Palmreekner-Warktüüchkomponent (KPilot-Moduul)
Comment[nl]=Component met hulpmiddelen voor PalmOS(tm)-apparaten (KPilot-plugin)
Comment[pl]=Składnik narzędzi Palma (wtyczka KPilot)
-Comment[ru]=Синхронизация с Palm (модуль KPilot)
Comment[sr]=Компонента алата за Palm (прикључак KPilot-а)
Comment[sr@Latn]=Komponenta alata za Palm (priključak KPilot-a)
Comment[sv]=Palm Pilot-verktygskomponent (Kpilot-insticksprogram)
-Comment[tr]=Palm Araçları Bileşeni (KPilot Eklentisi)
Comment[zh_CN]=Palm 工具组件(KPilot 插件)
Comment[zh_TW]=Palm 工具組件(KPilot 外掛程式)
Name=Palm
+Name[de]=KPilot-Einrichtung
Name[nds]=Palmreekner
Name[nl]=PalmOS(tm)-apparaat
Name[sv]=Palm Pilot
diff --git a/kontact/plugins/newsticker/kcmkontactknt.desktop b/kontact/plugins/newsticker/kcmkontactknt.desktop
index d866e252a..3e57621c1 100644
--- a/kontact/plugins/newsticker/kcmkontactknt.desktop
+++ b/kontact/plugins/newsticker/kcmkontactknt.desktop
@@ -36,7 +36,6 @@ Name[id]=Ticker Berita
Name[is]=Fréttastrimill
Name[it]=Ticker notizie
Name[ja]=ニュースティッカー
-Name[ka]=სიახლეთა ტიკერი
Name[kk]=Жаңалық таспасы
Name[km]=កម្មវិធី​ទទួល​ព័ត៌មាន
Name[lt]=News pranešėjas
@@ -88,7 +87,6 @@ Comment[hu]=A hírmegjelenítő áttekintőjének beállításai
Comment[is]=Uppsetning á yfirliti yfir fréttastrimla
Comment[it]=Impostazioni sommario ticker notizie
Comment[ja]=ニュースティッカーの設定
-Comment[ka]=სიახლეთა ტიკერის დაიჯესტის კონფიგურაცია
Comment[kk]=Жаңалық таспасының тұжырымынын баптау
Comment[km]=រៀបចំ​សេចក្ដី​សង្ខេប​កម្មវិធី​ទទួល​ព័ត៌មាន
Comment[lt]=News Ticker santraukos nustatymai
@@ -100,7 +98,7 @@ Comment[nn]=Oppsett av nyhendetelegrafsamandrag
Comment[pl]=Ustawienia podsumowania wiadomości
Comment[pt]=Configuração do Sumário do Extractor de Notícias
Comment[pt_BR]=Configuração de Resumo de Notícias
-Comment[ru]=Настройка сводки новостей
+Comment[ru]=Настройка дайджеста новостей
Comment[sk]=Nastavenie súhrnu správ
Comment[sl]=Nastavitve povzetka novic
Comment[sr]=Подешавање сажетка приказивања вести
@@ -131,7 +129,6 @@ Keywords[hu]=hírmegjelenítő,konfigurálás,beállítások
Keywords[is]=fréttastrimill, stillingar, stilla
Keywords[it]=ticker notizie, configura, impostazioni
Keywords[ja]=ニュースティッカー,設定,設定
-Keywords[ka]=სიახლეთა ტიკერი, კონფიგურაცია, პარამეტრები
Keywords[km]=កម្មវិធី​ទទួល​ព័ត៌មាន,កំណត់​រចនាសម្ព័ន្ធ,ការ​កំណត់
Keywords[lt]=news ticker, configure, settings, konfigūravimas, nustatymai, naujienų pranešėjas
Keywords[ms]=Pengetik berita, konfigur, seting
diff --git a/kontact/plugins/newsticker/newstickerplugin.desktop b/kontact/plugins/newsticker/newstickerplugin.desktop
index 18a34cda9..079f90079 100644
--- a/kontact/plugins/newsticker/newstickerplugin.desktop
+++ b/kontact/plugins/newsticker/newstickerplugin.desktop
@@ -20,21 +20,15 @@ Comment[ca]=Component de teletip de notícies
Comment[da]=Nyhedstelegraf-komponent
Comment[de]=Newsticker-Komponente
Comment[el]=Συστατικό προβολέα ειδήσεων
-Comment[es]=Componente de teletipo de noticias
Comment[et]=Uudistejälgija plugin
-Comment[fr]=Composant Newsticker
-Comment[is]=Fréttastrimilseining
Comment[it]=Componente ticker notizie
Comment[ja]=ニュースティッカーコンポーネント
-Comment[km]=សមាសភាគ Newsticker
Comment[nds]=Narichtentelegraaf-Komponent
Comment[nl]=Nieuwstickercomponent
Comment[pl]=Składnik paska wiadomości
-Comment[ru]=Компонент новостей
Comment[sr]=Компонента откуцавача вести
Comment[sr@Latn]=Komponenta otkucavača vesti
Comment[sv]=Nyhetsövervakningskomponent
-Comment[tr]=Haber İzleyici Bileşeni
Comment[zh_CN]=新闻点点通组件
Comment[zh_TW]=新聞顯示組件
Name=News
@@ -48,7 +42,7 @@ Name[ca]=Notícies
Name[cs]=Novinky
Name[cy]=Newyddion
Name[da]=Nyheder
-Name[de]=Usenet
+Name[de]=Newsticker
Name[el]=Νέα
Name[eo]=Novaĵoj
Name[es]=Noticias
@@ -65,7 +59,6 @@ Name[hi]=समाचार
Name[hu]=Hírek
Name[is]=Fréttir
Name[ja]=ニュース
-Name[ka]=სიახლეები
Name[kk]=Жаңалықтар
Name[km]=ព័ត៌មាន
Name[lt]=Naujienos
@@ -93,7 +86,6 @@ Name[tg]=Ахборот
Name[th]=ข่าว
Name[tr]=Haberler
Name[uk]=Новини
-Name[uz]=Yangiliklar
-Name[uz@cyrillic]=Янгиликлар
+Name[uz]=Янгиликлар
Name[zh_CN]=新闻
Name[zh_TW]=新聞
diff --git a/kontact/plugins/specialdates/kcmsdsummary.desktop b/kontact/plugins/specialdates/kcmsdsummary.desktop
index f294c3835..6835ce8fd 100644
--- a/kontact/plugins/specialdates/kcmsdsummary.desktop
+++ b/kontact/plugins/specialdates/kcmsdsummary.desktop
@@ -16,22 +16,15 @@ Name[ca]=Resum de dates especials
Name[da]=Oversigt over særlige datoer
Name[de]=Übersicht über besondere Termine
Name[el]=Επισκόπηση σημαντικών ημερομηνιών
-Name[es]=Resumen de fechas especiales
Name[et]=Tähtpäevade ülevaade
-Name[fr]=Aperçu des dates importantes
-Name[is]=Yfirlit sérstakra daga
Name[it]=Panoramica delle date speciali
Name[ja]=特別な日の要約
-Name[km]=ទិដ្ឋភាព​កាលបរិច្ឆេទ​ពិសេស
Name[nds]=Översicht besünner Daten
Name[nl]=Overzicht van speciale data
Name[pl]=Daty specjalne
-Name[pt_BR]=Resumo de Datas Especiais
-Name[ru]=Сводка особых дат
Name[sr]=Преглед посебних датума
Name[sr@Latn]=Pregled posebnih datuma
Name[sv]=Översikt av speciella datum
-Name[tr]=Özel Tarihlere Genel Bakış
Name[zh_CN]=特殊日期概览
Name[zh_TW]=特殊日期概觀
Comment=Special Dates Summary Setup
@@ -55,7 +48,6 @@ Comment[hu]=A fontos dátumok áttekintőjének beállításai
Comment[is]=Yfirlitsuppsetning sérstakra daga
Comment[it]=Impostazioni per le date speciali
Comment[ja]=特別な日の要約設定
-Comment[ka]=განსაკუთრებულ თარიღთა დაიჯესტის კონფიგურაცია
Comment[kk]=Ерекше күндер тұжырымының баптауы
Comment[km]=រៀបចំ​សេចក្ដី​សង្ខេប​ថ្ងៃ​ពិសេស
Comment[lt]=Ypatingų datų santraukos sąranka
@@ -102,7 +94,6 @@ Keywords[hu]=születésnap,évforduló,szabadság,konfigurálás,beállítások
Keywords[is]=afmæli, frídagar, stillingar, stilla
Keywords[it]=compleanno, anniversario, vacanze, configura, impostazioni
Keywords[ja]=誕生日,記念日,休日,設定,設定
-Keywords[ka]=დაბადების დღე,სახელობის დღე,დასვენების დღე,კონფიგურაცია,პარამეტრები
Keywords[km]=ថ្ងៃ​ខួប​កំណើត,បុណ្យ​ខួប,វិស្សមកាល,កំណត់​រចនាសម្ព័ន្ធ,ការ​កំណត់
Keywords[lt]=birthday, anniversary, holiday, configure, settings, konfigūruoti, nustatymai, gimtadieniai, išeiginės,sukaktys
Keywords[mk]=birthday, anniversary, holiday, configure, settings, роденден, годишнина, конфигурирање, конфигурација, поставувања
diff --git a/kontact/plugins/specialdates/sdsummarywidget.cpp b/kontact/plugins/specialdates/sdsummarywidget.cpp
index 44c671559..2967e889c 100644
--- a/kontact/plugins/specialdates/sdsummarywidget.cpp
+++ b/kontact/plugins/specialdates/sdsummarywidget.cpp
@@ -127,7 +127,6 @@ SDSummaryWidget::SDSummaryWidget( Kontact::Plugin *plugin, TQWidget *parent,
manager->setStandardResource( defaultResource );
}
mCalendar = KOrg::StdCalendar::self();
- mCalendar->load();
connect( mCalendar, TQT_SIGNAL( calendarChanged() ),
this, TQT_SLOT( updateView() ) );
@@ -220,6 +219,8 @@ void SDSummaryWidget::updateView()
mLabels.clear();
mLabels.setAutoDelete( false );
+ KIconLoader loader( "kdepim" );
+
KABC::StdAddressBook *ab = KABC::StdAddressBook::self( true );
TQValueList<SDEntry> dates;
TQLabel *label = 0;
@@ -391,9 +392,9 @@ void SDSummaryWidget::updateView()
TQImage icon_img;
TQString icon_name;
KABC::Picture pic;
- switch( (*addrIt).category ) { // TODO: better icons
+ switch( (*addrIt).category ) {
case CategoryBirthday:
- icon_name = "cookie";
+ icon_name = "calendarbirthday";
pic = (*addrIt).addressee.photo();
if ( pic.isIntern() && !pic.data().isNull() ) {
TQImage img = pic.data();
@@ -405,7 +406,7 @@ void SDSummaryWidget::updateView()
}
break;
case CategoryAnniversary:
- icon_name = "kdmconfig";
+ icon_name = "calendaranniversary";
pic = (*addrIt).addressee.photo();
if ( pic.isIntern() && !pic.data().isNull() ) {
TQImage img = pic.data();
@@ -417,7 +418,7 @@ void SDSummaryWidget::updateView()
}
break;
case CategoryHoliday:
- icon_name = "kdmconfig"; break;
+ icon_name = "calendarholiday"; break;
case CategoryOther:
icon_name = "cookie"; break;
}
@@ -438,8 +439,7 @@ void SDSummaryWidget::updateView()
//Muck with the year -- change to the year 'daysTo' days away
int year = currentDate.addDays( (*addrIt).daysTo ).year();
- TQDate sD = TQDate::TQDate( year,
- (*addrIt).date.month(), (*addrIt).date.day() );
+ TQDate sD = TQDate( year, (*addrIt).date.month(), (*addrIt).date.day() );
if ( (*addrIt).daysTo == 0 ) {
datestr = i18n( "Today" );
diff --git a/kontact/plugins/specialdates/sdsummarywidget.h b/kontact/plugins/specialdates/sdsummarywidget.h
index 6ef29eff3..5c52c77cf 100644
--- a/kontact/plugins/specialdates/sdsummarywidget.h
+++ b/kontact/plugins/specialdates/sdsummarywidget.h
@@ -78,7 +78,7 @@ class SDSummaryWidget : public Kontact::Summary
bool mShowHolidays;
bool mShowSpecialsFromCal;
- KHolidays::KHolidays *mHolidays;
+ KHolidays *mHolidays;
};
#endif
diff --git a/kontact/plugins/specialdates/specialdates_plugin.cpp b/kontact/plugins/specialdates/specialdates_plugin.cpp
index 9f78de3f6..c8a816c2f 100644
--- a/kontact/plugins/specialdates/specialdates_plugin.cpp
+++ b/kontact/plugins/specialdates/specialdates_plugin.cpp
@@ -24,6 +24,7 @@
#include <kaboutdata.h>
#include <kgenericfactory.h>
+#include <kiconloader.h>
#include <klocale.h>
#include <kparts/componentfactory.h>
@@ -41,6 +42,7 @@ SpecialdatesPlugin::SpecialdatesPlugin( Kontact::Core *core, const char *name, c
mAboutData( 0 )
{
setInstance( SpecialdatesPluginFactory::instance() );
+ instance()->iconLoader()->addAppDir( "kdepim" );
}
SpecialdatesPlugin::~SpecialdatesPlugin()
diff --git a/kontact/plugins/specialdates/specialdatesplugin.desktop b/kontact/plugins/specialdates/specialdatesplugin.desktop
index bceb13ada..cb6a691c0 100644
--- a/kontact/plugins/specialdates/specialdatesplugin.desktop
+++ b/kontact/plugins/specialdates/specialdatesplugin.desktop
@@ -29,7 +29,7 @@ Name[et]=Tähtpäevad
Name[eu]=Data bereziak
Name[fa]=تاریخهای ویژه
Name[fi]=Erikoispäivät
-Name[fr]=Dates importantes
+Name[fr]=Dates particulières
Name[fy]=Spesjale datums
Name[ga]=Dátaí Speisialta
Name[gl]=Datas Especiais
@@ -38,7 +38,6 @@ Name[hu]=Fontos dátumok
Name[is]=Sérstakir dagar
Name[it]=Date speciali
Name[ja]=特別な日
-Name[ka]=განსაკუტრებული თარიღები
Name[kk]=Ерекше күндер
Name[km]=ថ្ងៃ​ពិសេស
Name[lt]=Ypatingos datos
@@ -62,8 +61,7 @@ Name[ta]=விசேஷ தேதிகள்
Name[th]=วันพิเศษ
Name[tr]=Özel Tarihler
Name[uk]=Особливі дати
-Name[uz]=Maxsus kunlar
-Name[uz@cyrillic]=Махсус кунлар
+Name[uz]=Махсус кунлар
Name[zh_CN]=特殊日期
Name[zh_TW]=特殊日期
Comment=Special Dates Component
@@ -72,21 +70,14 @@ Comment[ca]=Component de dates especials
Comment[da]=Komponent til særlige datoer
Comment[de]=Komponente für Übersicht über besondere Termine
Comment[el]=Συστατικό σημαντικών ημερομηνιών
-Comment[es]=Componente de fechas especiales
Comment[et]=Tähtpäevade plugin
-Comment[fr]=Composant des dates importantes
-Comment[is]=Eining fyrir sérstaka daga
Comment[it]=Componente per le date speciali
Comment[ja]=特別な日コンポーネント
-Comment[km]=សមាសភាគ​កាលបរិច្ឆេទ​ពិសេស
Comment[nds]=Komponent för besünner Daten
Comment[nl]=Component voor overzicht van speciale data
Comment[pl]=Składnik dat specjalnych
-Comment[pt_BR]=Componente de Datas Especiais
-Comment[ru]=Особые даты
Comment[sr]=Компонента посебних датума
Comment[sr@Latn]=Komponenta posebnih datuma
Comment[sv]=Speciella datumkomponent
-Comment[tr]=Özel Tarihler Bileşeni
Comment[zh_CN]=特殊日期组件
Comment[zh_TW]=特殊日期組件
diff --git a/kontact/plugins/summary/kcmkontactsummary.cpp b/kontact/plugins/summary/kcmkontactsummary.cpp
index cf8154168..f21a2bb35 100644
--- a/kontact/plugins/summary/kcmkontactsummary.cpp
+++ b/kontact/plugins/summary/kcmkontactsummary.cpp
@@ -142,8 +142,10 @@ void KCMKontactSummary::load()
mPluginList = KPluginInfo::fromServices( offers, &config, "Plugins" );
KPluginInfo::List::Iterator it;
+ KConfig *conf = new KConfig("kontactrc");
+ KConfigGroup *cg = new KConfigGroup( conf, "Plugins" );
for ( it = mPluginList.begin(); it != mPluginList.end(); ++it ) {
- (*it)->load();
+ (*it)->load( cg );
if ( !(*it)->isPluginEnabled() )
continue;
diff --git a/kontact/plugins/summary/kcmkontactsummary.desktop b/kontact/plugins/summary/kcmkontactsummary.desktop
index 5442d5c0b..b4100a59f 100644
--- a/kontact/plugins/summary/kcmkontactsummary.desktop
+++ b/kontact/plugins/summary/kcmkontactsummary.desktop
@@ -13,23 +13,17 @@ X-KDE-CfgDlgHierarchy=KontactSummary
Name=Summary View Items
Name[bg]=Обобщение
Name[ca]=Vista resum d'elements
-Name[da]=Elementer i opsummeringsvisning
-Name[de]=Elemente der Zusammenfassungsansicht
+Name[de]=Übersichtseinträge
Name[el]=Αντικείμενα προβολής σύνοψης
-Name[es]=Elementos de la vista de sumario
Name[et]=Kokkuvõttevaate elemendid
Name[it]=Elementi vista sommario
Name[ja]=要約ビューの項目
-Name[km]=ធាតុ​ទិដ្ឋភាព​សង្ខេប
Name[nds]=Översicht-Indrääg
Name[nl]=Overzichtsweergave-items
-Name[pl]=Elementy widoku podsumowania
Name[sr]=Ставке приказа сажетка
Name[sr@Latn]=Stavke prikaza sažetka
Name[sv]=Objekt i översiktsvy
-Name[tr]=Özet Görünüm Ögeleri
Name[zh_CN]=摘要视图项目
-Name[zh_TW]=摘要檢視項目
Comment=General Configuration of Kontact's Summary View
Comment[af]=Algemene opstelling van Kontact se opsomming aansig
Comment[bg]=Настройка на обобщението
@@ -51,7 +45,6 @@ Comment[hu]=A Kontact áttekintő nézetének beállításai
Comment[is]=Almennar stillingar fyrir Kontact yfirlitssýn
Comment[it]=Configurazione generale della vista sommario di Kontact
Comment[ja]=Kontact の要約表示の一般的な設定
-Comment[ka]=Kontact დაიჯესტის ხედის ზოგადი პარამეტრები
Comment[kk]=Тұжырымдаманың жалпы параметрлері
Comment[km]=ការ​កំណត់​រចនាសម្ព័ន្ធ​ទូទៅ​នៃ​ទិដ្ឋភាព​សង្ខេប​របស់ Kontact
Comment[lt]=Kontact Santraukos vaizdo bendrasis konfigūravimas
@@ -65,7 +58,7 @@ Comment[nn]=Generelt oppsett av samandragsvisinga i Kontact
Comment[pl]=Ogólna konfiguracja widoku podsumowania w Kontact
Comment[pt]=Configuração Geral da Vista Sumária do Kontact
Comment[pt_BR]=Configuração Geral da Visão de Resumo do Kontact
-Comment[ru]=Настройка сводок Kontact
+Comment[ru]=Общие настройки дайджеста Kontact
Comment[sk]=Všeobecné nastavenie súhrnu Kontact
Comment[sl]=Splošne nastavitve za prikaz povzetka v Kontract
Comment[sr]=Опште подешавање Kontact-овог приказа сажетка
diff --git a/kontact/plugins/summary/summaryplugin.desktop b/kontact/plugins/summary/summaryplugin.desktop
index d2aa1c956..79f8119de 100644
--- a/kontact/plugins/summary/summaryplugin.desktop
+++ b/kontact/plugins/summary/summaryplugin.desktop
@@ -15,23 +15,17 @@ Comment=Summary View Component
Comment[bg]=Обобщение
Comment[ca]=Component de vista resum
Comment[da]=Komponent for opsummeringsvisning
-Comment[de]=Zusammenfassungsansicht-Komponente
+Comment[de]=Übersichtskomponente
Comment[el]=Συστατικό προβολής σύνοψης
-Comment[es]=Componente Vista de resumen
Comment[et]=Kokkuvõttevaate plugin
-Comment[fr]=Composant de la vue résumée
-Comment[is]=Eining fyrir yfirlitssýn
Comment[it]=Componente vista sommario
Comment[ja]=要約ビューコンポーネント
-Comment[km]=សមាសភាគ​ទិដ្ឋភាព​សង្ខេប
Comment[nds]=Översicht-Komponent
Comment[nl]=Overzichtsweergaveitem
-Comment[pl]=Składnik widoku podsumowania
-Comment[ru]=Просмотр сводок
+Comment[pl]=Składnik podsumowania
Comment[sr]=Компонента приказа сажетка
Comment[sr@Latn]=Komponenta prikaza sažetka
Comment[sv]=Översiktsvykomponent
-Comment[tr]=Özet Görünüm Bileşeni
Comment[zh_CN]=摘要视图组件
Comment[zh_TW]=摘要檢視組件
Name=Summary
@@ -62,7 +56,6 @@ Name[hu]=Áttekintő
Name[is]=Yfirlit
Name[it]=Sommario
Name[ja]=要約
-Name[ka]=დაიჯესტი
Name[kk]=Тұжырым
Name[km]=សង្ខេប
Name[lt]=Santrauka
@@ -77,7 +70,7 @@ Name[pl]=Podsumowanie
Name[pt]=Resumo
Name[pt_BR]=Resumo
Name[ro]=Sumar
-Name[ru]=Сводки
+Name[ru]=Дайджест
Name[se]=Čoahkkáigeassu
Name[sk]=Súhrn
Name[sl]=Povzetek
@@ -89,8 +82,7 @@ Name[tg]=Дайджест
Name[th]=หน้าสรุป
Name[tr]=Özet
Name[uk]=Зведення
-Name[uz]=Hisobot
-Name[uz@cyrillic]=Ҳисобот
+Name[uz]=Ҳисобот
Name[zh_CN]=概览
Name[zh_TW]=摘要
#Always last
diff --git a/kontact/plugins/summary/summaryview_plugin.cpp b/kontact/plugins/summary/summaryview_plugin.cpp
index 9f9073808..555d79544 100644
--- a/kontact/plugins/summary/summaryview_plugin.cpp
+++ b/kontact/plugins/summary/summaryview_plugin.cpp
@@ -39,8 +39,8 @@ SummaryView::SummaryView( Kontact::Core *core, const char *name, const TQStringL
{
setInstance( SummaryViewFactory::instance() );
- mSyncAction = new KSelectAction( i18n( "Synchronize All" ), "reload", 0, this,
- TQT_SLOT( doSync() ), actionCollection(),
+ mSyncAction = new KSelectAction( i18n( "Synchronize All" ), "reload", 0, 0,
+ 0, actionCollection(),
"kontact_summary_sync" );
connect( mSyncAction, TQT_SIGNAL( activated( const TQString& ) ), this, TQT_SLOT( syncAccount( const TQString& ) ) );
connect( mSyncAction->popupMenu(), TQT_SIGNAL( aboutToShow() ), this, TQT_SLOT( fillSyncActionSubEntries() ) );
@@ -68,9 +68,12 @@ void SummaryView::fillSyncActionSubEntries()
void SummaryView::syncAccount( const TQString& account )
{
- const TQString acc = account == i18n("All") ? TQString() : account;
- DCOPRef ref( "kmail", "KMailIface" );
- ref.send( "checkAccount", acc );
+ if ( account == i18n("All") ) {
+ doSync();
+ } else {
+ DCOPRef ref( "kmail", "KMailIface" );
+ ref.send( "checkAccount", account );
+ }
fillSyncActionSubEntries();
}
diff --git a/kontact/plugins/test/kptestplugin.desktop b/kontact/plugins/test/kptestplugin.desktop
index 17a3e52e9..75e0988e4 100644
--- a/kontact/plugins/test/kptestplugin.desktop
+++ b/kontact/plugins/test/kptestplugin.desktop
@@ -35,7 +35,6 @@ Comment[hu]=Kontact tesztmodul
Comment[is]=Kontact prufu íforrit
Comment[it]=Plugin test Kontact
Comment[ja]=Kontact テストプラグイン
-Comment[ka]=Kontact სატესტო მოდული
Comment[kk]=Сынақ модулі
Comment[km]=កម្មវិធី​ជំនួយ​ការ​សាកល្បង​ក្នុង Kontact
Comment[lt]=Kontact bandymo priedas
@@ -60,8 +59,7 @@ Comment[ta]=பரிசோதனை சொருகுப்பொருளை
Comment[tg]=Модули матнии Kontact
Comment[tr]=Kontact Test Eklentisi
Comment[uk]=Тестовий втулок Kontact
-Comment[uz]=Kontact uchun sinash plagini
-Comment[uz@cyrillic]=Kontact учун синаш плагини
+Comment[uz]=Kontact учун синаш плагини
Comment[zh_CN]=Kontact Test 插件
Comment[zh_TW]=Kontact 測試外掛程式
Name=TestPlugin
@@ -83,7 +81,6 @@ Name[hu]=Tesztmodul
Name[is]=Prufu íforrit
Name[it]=Plugin Test
Name[ja]=テストプラグイン
-Name[ka]=სატესტო მოდული
Name[kk]=Сынақ модулі
Name[km]=កម្មវិធី​ជំនួយ​ការ​សាកល្បង
Name[mk]=Приклучок за тест
diff --git a/kontact/plugins/weather/weatherplugin.desktop b/kontact/plugins/weather/weatherplugin.desktop
index 68c1924e3..80d9be8e4 100644
--- a/kontact/plugins/weather/weatherplugin.desktop
+++ b/kontact/plugins/weather/weatherplugin.desktop
@@ -21,21 +21,15 @@ Comment[ca]=Component del temps del Kontact
Comment[da]=Vejrkomponent til Kontact
Comment[de]=Wetter-Komponente für Kontact
Comment[el]=Συστατικό καιρού του Kontact
-Comment[es]=Extensión de meteorología para Kontact
Comment[et]=Kontacti ilmaplugin
-Comment[fr]=Composant météo pour Kontact
-Comment[is]=Kontact veðurfréttaeining
Comment[it]=Componente meteorologico di Kontact
Comment[ja]=Kontact 気象情報コンポーネント
-Comment[km]=សមាសភាគ​អាកាសធាតុ Kontact
Comment[nds]=Kontact-Wederkomponent
Comment[nl]=Kontact Weercomponent
Comment[pl]=Składnik Kontaktu wiadomości o pogodzie
-Comment[ru]=Компонент информации о погоде для Kontact
Comment[sr]=Компонента времена за Kontact
Comment[sr@Latn]=Komponenta vremena za Kontact
Comment[sv]=Kontacts väderkomponent
-Comment[tr]=Kontact Hava Durumu Bileşeni
Comment[zh_CN]=Kontact 天气插件
Comment[zh_TW]=Kontact 天氣組件
Name=Weather Service
@@ -64,7 +58,6 @@ Name[hu]=Időjárás
Name[is]=Veðurþjónusta
Name[it]=Servizio meteorologico
Name[ja]=気象サービス
-Name[ka]=ამინდის მომსახურება
Name[kk]=Ауа райы қызметі
Name[km]=សេវា​អាកាសធាតុ
Name[lt]=Orų tarnyba
@@ -86,7 +79,6 @@ Name[sv]=Väderleksprognos
Name[th]=รายงานอากาศ
Name[tr]=Hava Durumu Servisi
Name[uk]=Служба погоди
-Name[uz]=Ob-havo xizmati
-Name[uz@cyrillic]=Об-ҳаво хизмати
+Name[uz]=Об-ҳаво хизмати
Name[zh_CN]=天气服务
Name[zh_TW]=天氣服務
diff --git a/kontact/src/Kontact.desktop b/kontact/src/Kontact.desktop
index 6cd9d0d3a..a4127aac0 100644
--- a/kontact/src/Kontact.desktop
+++ b/kontact/src/Kontact.desktop
@@ -36,7 +36,6 @@ GenericName[hu]=Információkezelő
GenericName[is]=Persónulegur upplýsingastjórnandi
GenericName[it]=Gestione informazioni personali
GenericName[ja]=個人情報マネージャ
-GenericName[ka]=პირადი ინფორმაციის მმართველი
GenericName[kk]=Дербес Ақпарат Менеджері
GenericName[km]=កម្មវិធី​គ្រប់គ្រង​ព័ត៌មាន​ផ្ទាល់​ខ្លួន
GenericName[lt]=Asmeninės informacijos tvarkyklė
@@ -61,8 +60,7 @@ GenericName[ta]=அந்தரங்க தகவல் மேலாளர்
GenericName[tg]=Мудири маълумоти шахсӣ
GenericName[tr]=Kişisel Bilgi Yöneticisi
GenericName[uk]=Менеджер особистої інформації
-GenericName[uz]=Shaxsiy maʼlumot boshqaruvchisi
-GenericName[uz@cyrillic]=Шахсий маълумот бошқарувчиси
+GenericName[uz]=Шахсий маълумот бошқарувчиси
GenericName[zh_CN]=个人信息管理器
GenericName[zh_TW]=個人資訊管理者
Terminal=false
diff --git a/kontact/src/about/kontact.css b/kontact/src/about/kontact.css
index 18aa0ddcd..2366a9741 100644
--- a/kontact/src/about/kontact.css
+++ b/kontact/src/about/kontact.css
@@ -15,13 +15,6 @@
right: 125px;
}
-#boxCenter {
- background-image: url(box-center-kontact.png);
- background-repeat: no-repeat;
- background-color: #dfe7f3;
- background-position: bottom right;
-}
-
#subtext {
font-style: italic;
}
diff --git a/kontact/src/iconsidepane.cpp b/kontact/src/iconsidepane.cpp
index d56513aeb..4303175f6 100644
--- a/kontact/src/iconsidepane.cpp
+++ b/kontact/src/iconsidepane.cpp
@@ -113,8 +113,8 @@ void EntryItem::reloadPixmap()
if ( size != 0 )
mPixmap = KGlobal::iconLoader()->loadIcon( mPlugin->icon(),
KIcon::Desktop, size,
- mPlugin->disabled() ?
- KIcon::DisabledState
+ mPlugin->disabled() ?
+ KIcon::DisabledState
: KIcon::DefaultState);
else
mPixmap = TQPixmap();
@@ -250,7 +250,7 @@ void EntryItem::setPaintActive( bool paintActive )
mPaintActive = paintActive;
}
-Navigator::Navigator( SidePaneBase *parent, const char *name )
+Navigator::Navigator( IconSidePane *parent, const char *name )
: KListBox( parent, name ), mSidePane( parent ),
mShowIcons( true ), mShowText( true )
{
@@ -328,7 +328,6 @@ void Navigator::updatePlugins( TQValueList<Kontact::Plugin*> plugins_ )
mActions.clear();
mActions.setAutoDelete( false );
- int counter = 0;
int minWidth = 0;
qBubbleSort( plugins );
TQValueList<Kontact::PluginProxy>::ConstIterator end = plugins.end();
@@ -343,14 +342,6 @@ void Navigator::updatePlugins( TQValueList<Kontact::Plugin*> plugins_ )
if ( item->width( this ) > minWidth )
minWidth = item->width( this );
-
- TQString name = TQString( "CTRL+%1" ).arg( counter + 1 );
- KAction *action = new KAction( plugin->title(), plugin->icon(), KShortcut( name ),
- mMapper, TQT_SLOT( map() ),
- mSidePane->actionCollection(), name.latin1() );
- mActions.append( action );
- mMapper->setMapping( action, counter );
- counter++;
}
parentWidget()->setFixedWidth( minWidth );
diff --git a/kontact/src/iconsidepane.h b/kontact/src/iconsidepane.h
index 03f838c97..674980c01 100644
--- a/kontact/src/iconsidepane.h
+++ b/kontact/src/iconsidepane.h
@@ -37,6 +37,7 @@ namespace Kontact
{
class Core;
+class IconSidePane;
class Plugin;
class Navigator;
@@ -118,7 +119,7 @@ class Navigator : public KListBox
{
Q_OBJECT
public:
- Navigator( SidePaneBase *parent = 0, const char *name = 0 );
+ Navigator( IconSidePane *parent = 0, const char *name = 0 );
virtual void setSelected( TQListBoxItem *, bool );
@@ -156,7 +157,7 @@ class Navigator : public KListBox
void slotStopHighlight();
private:
- SidePaneBase *mSidePane;
+ IconSidePane *mSidePane;
IconViewMode mViewMode;
TQListBoxItem* mMouseOn;
diff --git a/kontact/src/kontact.setdlg b/kontact/src/kontact.setdlg
index a90778a21..872457ade 100644
--- a/kontact/src/kontact.setdlg
+++ b/kontact/src/kontact.setdlg
@@ -5,21 +5,15 @@ Name[ca]=Vista de resum
Name[da]=Opsummeringsvisning
Name[de]=Übersicht
Name[el]=Προβολή σύνοψης
-Name[es]=Vista de resumen
Name[et]=Kokkuvõttevaade
-Name[fr]=Vue résumée
-Name[is]=Yfirlitssýn
Name[it]=Vista sommario
Name[ja]=要約ビュー
-Name[km]=ទិដ្ឋភាព​សង្ខេប
Name[nds]=Översicht
Name[nl]=Overzichtsweergave
Name[pl]=Podsumowanie
-Name[ru]=Просмотр сводок
Name[sr]=Приказ сажетка
Name[sr@Latn]=Prikaz sažetka
Name[sv]=Översiktsvy
-Name[tr]=Özet Görünümü
Name[zh_CN]=摘要视图
Name[zh_TW]=摘要檢視
Comment=Configuration of Kontact's <b>Summary View</b>. Some plugins provide <i>Summary View</i> items, choose the ones you would like to list.
@@ -28,17 +22,12 @@ Comment[ca]=Configuració de la <b>vista de resum</b> del Kontact. Alguns endoll
Comment[da]=Konfiguration af Kontacts <b>Opsummeringsvisning</b>. Nogle plugins giver <i>Opsummeringsvisning</i>-elementer, vælg dem du ønsker på listen.
Comment[de]=Einrichtung der <b>Zusammenfassungsansicht</b> von Kontact. Einige Kontact-Module stellen Elemente für die <i>Zusammenfassungsansicht</i> zur Verfügung. Wählen Sie hier, welche Elemente angezeigt werden sollen.
Comment[el]=Ρύθμιση της <b>Προβολής σύνοψης</b> του Kontact. Κάποια πρόσθετα παρέχουν αντικείμενα <i>Προβολή σύνοψης</i>· επιλέξτε αυτά που θέλετε να εμφανίζονται.
-Comment[es]=Configuración de Kontact <b>Vista de resumen</b>. Algunos complementos proveen elementos para la <i>Vista de resumen</i>, elija los que quiera listar.
Comment[et]=Kontacti <b>kokkuvõttevaate</b> seadistamine. Mõned pluginad pakuvad <i>kokkuvõttevaate</i> elemente. Vali nimekirjas need, mida soovid näha.
-Comment[fr]=Configuration de Kontact <b> Vue résumée</b>. Certains modules fournissent des éléments de <i>Vue Résumée</i>, choisissez ceux que vous voulez voir listés.
-Comment[is]=Stillingar á <b>Yfirlitssýn</b>í Kontact. Sum íforrit koma með hluti í <i>Yfirlitssýn</i>, veldu þá sem þú vilt hafa á síðunni.
Comment[it]=Configurazione della <b>vista sommario</b> di Kontact. Alcuni plugin forniscono elementi di <i>vista sommario</i>, scegli quelli che desideri vedere nell'elenco.
Comment[ja]=Kontact の要約ビューの設定。要約ビューの項目を提供するプラグインがいくつかあります。要約ビューに表示させる項目を選択してください。
-Comment[km]=កា​រកំណត់​រចនាសម្ព័ន្ធ​របស់ Kontact <b>ទិដ្ឋភាព​សង្ខេប</b> ។ កម្មវិធី​ជំនួយ​មួយ​ចំនួនផ្ដល់​នូវ​ធាតុ<i>ទិដ្ឋភាព​សង្ខេប</i> ជ្រើស​ទិដ្ឋភាព​មួយ​ក្នុង​ចំណោម​ទិដ្ឋភាព​ទាំងនេះ​ដែល​អ្នក​ចង់​រាយ ។
Comment[nds]=Kontact sien <b>Översicht</b> instellen. En Reeg Modulen stellt Indrääg för de <i>Översicht</i> praat. Hier kannst Du de utsöken, de Du hebben wullt.
Comment[nl]=Configuratie van Kontacts <b>Overzichtsweergave</b>. Sommige plugins bieden ook items aan voor de <i>Overzichtweergave</i>, kies welke u wilt zien.
Comment[pl]=Konfiguracja <b>Podsumowania</b> Kontaktu. Niektóre wtyczki zapewniają elementy <i>Widok podsumowania</i>, wybierz te które chcesz zobaczyć.
-Comment[ru]=Настройка показа сводок различных компонентов.
Comment[sr]=Подешавање Kontact-овог <b>приказа сажетка</b>. Неки прикључци дају ставке <i>приказа сажетка</i>, изаберите оне које желите.
Comment[sr@Latn]=Podešavanje Kontact-ovog <b>prikaza sažetka</b>. Neki priključci daju stavke <i>prikaza sažetka</i>, izaberite one koje želite.
Comment[sv]=Inställning av Kontacts <b>översiktsvy</b>. Vissa insticksprogram tillhandahåller objekt för <i>översiktsvyn</i>. Välj de du skulle vilja visa.
@@ -52,24 +41,17 @@ Name=E-Mail
Name[bg]=Е-поща
Name[ca]=Correu
Name[da]=E-mail
+Name[de]=E-Mail
Name[el]=Αλληλογραφία
-Name[es]=Correo electrónico
Name[et]=E-post
-Name[fr]=Courriel
-Name[is]=Tölvupóstur
Name[it]=Posta elettronica
Name[ja]=メール
-Name[km]=អ៊ីមែល
Name[nds]=Nettpost
Name[nl]=E-mail
Name[pl]=E-mail
-Name[pt_BR]=E-mail
-Name[ru]=Электронная почта
-Name[sk]=Pošta
Name[sr]=Е-пошта
Name[sr@Latn]=E-pošta
Name[sv]=E-post
-Name[tr]=E-Posta
Name[zh_CN]=邮件
Name[zh_TW]=電子郵件
Comment=Configuration of Kontact's E-Mail Plugin <b>KMail</b>, includes a <i>Summary View Item</i> and represents a <i>Kontact Component</i>.
@@ -78,16 +60,11 @@ Comment[ca]=Configuració de l'endollable de correu <b>KMail</b> del Kontact, in
Comment[da]=Konfiguration af Kontacts e-mail-plugin <b>KMail</b>, inkluderer et <i>Opsummeringsvisnings-element</i> og repræsenterer en <i>Kontact-komponent</i>.
Comment[de]=Einrichtung des E-Mail-Moduls <b>KMail</b> für Kontact. Die E-Mail-Komponente kann als <i>Kontact-Komponente<i> in die <i>Zusammenfassungsansicht</i> integriert werden.
Comment[el]=Η ρύθμιση του προσθέτου αλληλογραφίας <b>KMail</b> του Kontact, περιέχει ένα <i>Αντικείμενο προβολής σύνοψης</i> και αντιπροσωπεύει ένα <i>Συστατικό του Kontact</i>.
-Comment[es]=Configuración del complemento de correo-e de Kontact <b>KMail</b>, incluye una <i>Vista de resumen</i> y representa un <i>Componente de Kontact</i>.
Comment[et]=Kontacti e-posti plugina <b>KMaili</b> seadistamine, mis sisaldab <i>kokkuvõttevaate elementi</i>.
-Comment[fr]=Configuration du Module de Courriel de Kontact <b>KMail</b>, inclut un <i>Élément de Vue Résumée</i> et correspond à un <i>Composant de Kontact</i>.
-Comment[is]=Stillingar fyrir tölvupóstíforrit Kontact <b>KMail</b>, inniheldur <i>yfirlitssýnarhlut</i> sem stendur fyrir <i>Kontact einingu</i>.
Comment[it]=Configurazione del plugin di posta elettronica <b>KMail</b> di Kontact, include una <i>vista sommario</i> e rappresenta un <i>componente Kontact</i>.
-Comment[km]=ការ​កំណត់​រចនាសម្ព័ន្ធ​របស់​កម្មវិធី​ជំនួយ​​អ៊ីមែល​របស់ Kontact​ <b>KMail</b> រួម​មាន<i>ធាតុ​ទិដ្ឋភាព​សង្ខេប</i> និង​បង្ហាញ <i>សមាសភាគ Kontact​</i> ។
Comment[nds]=Kontact sien Nettpost-Moduul <b>KMail</b> instellen. Stellt en <i>Översicht-Indrag</i> praat un is en <i>Kontact-Komponent</i>.
Comment[nl]=Instellingen voor Kontacts e-mailplugin <b>KMail</b>. Bevat een <i>Overzichtsweergaveplugin</i> en een <i>Kontact-component</i>.
Comment[pl]=Konfiguracja wtyczki poczty Kontaktu <b>KMail</b>, zawiera <i>element Podsumowanie</i> i jest <i>Składnikiem Kontaktu</i>.
-Comment[ru]=Настройка модуля электронной почты <b>KMail</b> для показа в виде сводки.
Comment[sr]=Подешавање Kontact-овог прикључка за е-пошту преко <b>KMail-</b>, укључујући <i>приказ сажетка</i>, и дат као <i>компонента Kontact-а</i>.
Comment[sr@Latn]=Podešavanje Kontact-ovog priključka za e-poštu preko <b>KMail-</b>, uključujući <i>prikaz sažetka</i>, i dat kao <i>komponenta Kontact-a</i>.
Comment[sv]=Inställning av Kontacts e-postinsticksprogram <b>Kmail</b>, omfattar ett objekt för <i>översiktsvyn</i> och representerar en <i>Kontactkomponent</i>.
@@ -125,7 +102,6 @@ Name[hu]=Névjegyek
Name[is]=Tengiliðir
Name[it]=Contatti
Name[ja]=コンタクト
-Name[ka]=კონტაქტები
Name[kk]=Контакттар
Name[km]=ទំនាក់ទំនង
Name[lt]=Kontaktai
@@ -151,10 +127,9 @@ Name[sv]=Kontakter
Name[ta]=தொடர்புகள்
Name[tg]=Алоқот
Name[th]=ที่อยู่ติดต่อ
-Name[tr]=Kişiler
+Name[tr]=Bağlantılar
Name[uk]=Контакти
-Name[uz]=Aloqalar
-Name[uz@cyrillic]=Алоқалар
+Name[uz]=Алоқалар
Name[zh_CN]=联系人
Name[zh_TW]=聯絡人
Comment=Configuration of Kontact's Adress Book Plugin <b>KAdressbook</b> which represents a <i>Kontact Component</i>.
@@ -163,16 +138,11 @@ Comment[ca]=Configuració de l'endollable de la llibreta d'adreces <b>KAdressboo
Comment[da]=Konfiguration af Kontacts adressebog-plugin <b>KAdressbook</b> som repræsenterer en <i>Kontact-komponent</i>.
Comment[de]=Einrichtung des Adressbuch-Moduls für Kontact, welches eine <i>Kontact-Komponente</i> repräsentiert.
Comment[el]=Ρύθμιση του πρόσθετου βιβλίου διευθύνσεων <b>KAdressbook</b> του Kontact που αντιπροσωπεύει ένα <i>Συστατικό του Kontact</i>.
-Comment[es]=Configuración del complemento de libreta de direcciones de Kontact <b> KAddressbok</b>, el cual representa un <i>Componente de Kontact</i>.
Comment[et]=Kontacti aadressiraamatu plugina <b>KAdressbook</b> seaditamine.
-Comment[fr]=Configuration du Module de Carnet d'Adresses de Kontact <b> KAdressbook</b> qui correspond à un <i>Composant de Kontact</i>.
-Comment[is]=Stillingar fyrir vistfangaskráríforrit Kontact <b>KAdressbook</b>, inniheldur <i>yfirlitssýnarhlut</i> sem stendur fyrir <i>Kontact einingu</i>.
Comment[it]=Configurazione del plugin rubrica di <b>KAddressbook</b> che rappresenta un <i>componente Kontact</i>.
-Comment[km]=កា​រកំណត់​រចនាសម្ព័ន្ធ​របស់​កម្មវិធី​ជំនួយ​សៀវភៅ​អាសយដ្ឋាន​របស់ Kontact <b>KAdressbook</b> ដែល​បង្ហាញ <i>សមាសភាគ Kontact​</i> ។
Comment[nds]=Kontact sien Adressbook-Moduul <b>KAddressbook</b> instellende, dat en <i>Kontact-Komponent</i> is.
Comment[nl]=Instellingen voor Kontacts adresboekplugin <b>KMail</b>. Bevat een <i>Kontact-component</i>.
Comment[pl]=Konfiguracja wtyczki książki adresowej Kontaktu <b>KAddressBook</b>, która jest <i>Składnikiem Kontaktu</i>.
-Comment[ru]=Настройка модуля адресной книги <b>KAdressbook</b> для показа в виде сводки.
Comment[sr]=Подешавање Kontact-овог прикључка за адресар преко <b>KAdressbook</b> у облику <i>компоненте Kontact-а</i>.
Comment[sr@Latn]=Podešavanje Kontact-ovog priključka za adresar preko <b>KAdressbook</b> u obliku <i>komponente Kontact-a</i>.
Comment[sv]=Inställning av Kontacts adressboksinsticksprogram <b>Kaddressbook</b>, som representerar en <i>Kontactkomponent</i>.
@@ -205,7 +175,6 @@ Name[hu]=A fontos dátumok áttekintője
Name[is]=Yfirlit sérstakra daga
Name[it]=Sommario date speciali
Name[ja]=特別な日の要約
-Name[ka]=განსაკუთრებულ თარიღთა დაიჯესტი
Name[kk]=Ерекше күндер тұжырымы
Name[km]=សង្ខេប​ថ្ងៃ​ពិសេស
Name[lt]=Ypatingų dienų santrauka
@@ -219,7 +188,7 @@ Name[nn]=Samandrag for spesielle datoar
Name[pl]=Podsumowanie dat specjalnych
Name[pt]=Sumário de Datas Especiais
Name[pt_BR]=Resumo de Datas Especiais
-Name[ru]=Сводка особых дат
+Name[ru]=Дайджест особых дат
Name[sk]=Súhrn špeciálnych dátumov
Name[sl]=Povzetek posebnih datumov
Name[sr]=Сажетак посебних датума
@@ -253,7 +222,6 @@ Comment[hu]=A fontos dátumok áttekintő komponense
Comment[is]=Yfirlitshluti sérstakra daga
Comment[it]=Componente sommario per le date speciali
Comment[ja]=特別な日の要約コンポーネント
-Comment[ka]=განაკუთრებულ თარიღთა დაიჯესტის კომპონენტი
Comment[kk]=Ерекше күндер тұжырымының компоненті
Comment[km]=សមាសភាគ​សង្ខេប​នៃ​ថ្ងៃ​ពិសេស
Comment[lt]=Ypatingų dienų santraukos komponentas
@@ -267,7 +235,7 @@ Comment[nn]=Komponent for samandrag for spesielle datoar
Comment[pl]=Składnik podsumowania dat specjalnych
Comment[pt]=Componente de Sumário de Datas Especiais
Comment[pt_BR]=Componente de Datas Especiais
-Comment[ru]=Компонент сводки особых дат
+Comment[ru]=Компонент дайджеста особых дат
Comment[sk]=Komponent súhrnu špeciálnych dátumov
Comment[sl]=Komponenta za povzetke posebnih datumov
Comment[sr]=Компонента сажетка посебних датума
@@ -311,7 +279,6 @@ Name[hu]=Naptár
Name[is]=Dagatal
Name[it]=Calendario
Name[ja]=カレンダー
-Name[ka]=კალენდარი
Name[kk]=Күнтізбе
Name[km]=ប្រតិទិន
Name[lt]=Kalendorius
@@ -338,8 +305,7 @@ Name[tg]=Тақвим
Name[th]=บันทึกประจำวัน
Name[tr]=Takvim
Name[uk]=Календар
-Name[uz]=Kalendar
-Name[uz@cyrillic]=Календар
+Name[uz]=Календар
Name[zh_CN]=日历
Name[zh_TW]=行事曆
Comment=Configuration of Kontact's Calendar Plugin <b>KOrganizer</b>, includes a <i>Summary View Item</i> and represents a <i>Kontact Component</i>.
@@ -348,16 +314,11 @@ Comment[ca]=Configuració de l'endollable de calendari <b>KOrganizer</b> del Kon
Comment[da]=Konfiguration af Kontacts kalender-plugin <b>KOrganizer</b>, inkluderer et <i>Opsummeringsvisningselement</i> og repræsenterer en <i>Kontact-komponent</i>.
Comment[de]=Einrichtung des Kalender-Moduls <b>KOrganizer</b> für Kontact, einschließlich der <i>Zusammenfassungsansicht</i>; repräsentiert eine <i>Kontact-Komponente</i>
Comment[el]=Η ρύθμιση του προσθέτου ημερολογίου του <b>KOrganizer</b> του Kontact, περιέχει ένα <i>Αντικείμενο προβολής σύνοψης</i> και αντιπροσωπεύει ένα <i>Συστατικό του Kontact</i>.
-Comment[es]=Configuración del complemento de calendario de Kontact, <b> KOrganizer</b>, incluye una <i>Vista de resumen</i> y representa un <i>Componente de Kontact</i>.
Comment[et]=Kontacti kalendriplugina <b>KOrganizeri</b> seadistamine, mis sisaldab <i>kokkuvõttevaate elementi</i>.
-Comment[fr]=Configuration du Module de Calendrier de Kontact <b>KOrganizer</b>, inclut un <i>Élément de Vue Résumée</i> et correspond à un <i>Composant de Kontact</i>.
-Comment[is]=Stillingar fyrir dagatalsíforrit Kontact <b>KOrganizer</b>, inniheldur <i>yfirlitssýnarhlut</i> sem stendur fyrir <i>Kontact einingu</i>.
Comment[it]=Configurazione del plugin calendario <b>KOrganizer</b> di Kontact, include una <i>vista sommario</i> e rappresenta un <i>componente Kontact</i>.
-Comment[km]=កា​រកំណត់​រចនាសម្ព័ន្ធ​របស់​កម្មវិធី​ជំនួយ​ប្រតិទិន​របស់ Kontact <b>KOrganizer</b>រួម​មាន <i>ធាតុទិដ្ឋភាព​សង្ខេប</i> និង​បង្ហាញ <i>សមាសភាគ​ Kontact​</i>.
Comment[nds]=Kontact sien Kalenner-Moduul <b>KOrganizer</b> instellen. Stellt en <i>Översicht-Indrag</i> praat un is en <i>Kontact-Komponent</i>.
Comment[nl]=Instellingen voor Kontacts agendaplugin <b>KOrganizer</b>. Bevat een <i>Overzichtsweergaveplugin</i> en een <i>Kontact-component</i>.
Comment[pl]=Konfiguracja wtyczki kalendarza Kontaktu <b>KOrganizer</b>, zawiera <i>element Podsumowanie</i> i jest <i>Składnikiem Kontaktu</i>.
-Comment[ru]=Настройка модуля календаря <b>KOrganizer</b> для показа в виде сводки.
Comment[sr]=Подешавање Kontact-овог прикључка за календар преко <b>KOrganizer-а</b>, укључујући <i>приказ сажетка</i>, и дат као <i>компонента Kontact-а</i>.
Comment[sr@Latn]=Podešavanje Kontact-ovog priključka za kalendar preko <b>KOrganizer-a</b>, uključujući <i>prikaz sažetka</i>, i dat kao <i>komponenta Kontact-a</i>.
Comment[sv]=Inställning av Kontacts kalenderinsticksprogram <b>Korganizer</b>, omfattar ett objekt för <i>översiktsvyn</i> och representerar en <i>Kontactkomponent</i>.
@@ -395,7 +356,6 @@ Name[hi]=समाचार
Name[hu]=Hírek
Name[is]=Fréttir
Name[ja]=ニュース
-Name[ka]=სიახლეები
Name[kk]=Жаңалықтар
Name[km]=ព័ត៌មាន
Name[lt]=Naujienos
@@ -423,8 +383,7 @@ Name[tg]=Ахборот
Name[th]=ข่าว
Name[tr]=Haberler
Name[uk]=Новини
-Name[uz]=Yangiliklar
-Name[uz@cyrillic]=Янгиликлар
+Name[uz]=Янгиликлар
Name[zh_CN]=新闻
Name[zh_TW]=新聞
Comment=Configuration of Kontact's News Plugin <b>KNode</b> which represents a <i>Kontact Component</i>.
@@ -433,16 +392,11 @@ Comment[ca]=Configuració de l'endollable de notícies <b>KNode</b> del Kontact,
Comment[da]=Konfiguration af Kontacts nyheds-plugin <b>KNode</b> som repræsenterer en <i>Kontact-komponent</i>.
Comment[de]=Einrichtung des News-Moduls <b>KNode</b> für Kontact; repräsentiert eine <i>Kontact-Komponente</i>
Comment[el]=Ρύθμιση του πρόσθετου νέων <b>KNode</b> του Kontact που αντιπροσωπεύει ένα <i>Συστατικό του Kontact</i>.
-Comment[es]=Configuración del complemento de noticias de Kontact <b>KNode</b> , el cual representa un <i>Componente de Kontact</i>.
Comment[et]=Kontacti uudisteplugina <b>KNode</b> seadistamine.
-Comment[fr]=Configuration du Module de Nouvelles de Kontact <b>KNode</b> qui correspond à un <i>Composant de Kontact</i>.
-Comment[is]=Stillingar fyrir fréttastraumsíforrit Kontact <b>KNode</b>, inniheldur <i>yfirlitssýnarhlut</i> sem stendur fyrir <i>Kontact einingu</i>.
Comment[it]=Configurazione del plugin notizie <b>KNode</b> di Kontact, che rappresenta un <i>componente Kontact</i>.
-Comment[km]=កា​រកំណត់​រចនាសម្ព័ន្ធ​របស់​កម្មវិធី​ជំនួយ​ព័ត៌មាន​របស់ Kontact <b>KNode</b> ដែល​បង្ហាញ <i>សមាភាគ​​របស់ Kontact​</i>​ ។
Comment[nds]=Kontact sien Narichten-Moduul <b>KNode</b> instellen, dat en <i>Kontact-Komponent</i> is.
Comment[nl]=Instellingen voor Kontacts nieuwsplugin <b>KNode</b>. Bevat een <i>Kontact-component</i>.
-Comment[pl]=Konfiguracja wtyczki wiadomości Kontaktu <b>KNode</b>, która jest <i>składnikiem Kontaktu</i>.
-Comment[ru]=Настройка модуля новостей <b>KNode</b> для показа в виде сводки.
+Comment[pl]=Konfiguracja wtyczki niusów Kontaktu <b>KNode</b>, która jest <i>Składnikiem Kontaktu</i>.
Comment[sr]=Подешавање Kontact-овог прикључка за вести преко <b>KNode-а</b> у облику <i>компненте Kontact-а</i>.
Comment[sr@Latn]=Podešavanje Kontact-ovog priključka za vesti preko <b>KNode-a</b> u obliku <i>kompnente Kontact-a</i>.
Comment[sv]=Inställning av Kontacts nyhetsinsticksprogram <b>Knode</b>, som representerar en <i>Kontactkomponent</i>.
@@ -481,7 +435,6 @@ Name[hu]=Időjárás
Name[is]=Veður
Name[it]=Tempo meteorologico
Name[ja]=気象情報
-Name[ka]=ამინდი
Name[kk]=Ауа райы
Name[km]=អាកាសធាតុ
Name[lt]=Orų pranešėjas
@@ -508,8 +461,7 @@ Name[tg]=Пешгӯии ҳаво
Name[th]=รายงานอากาศ
Name[tr]=Hava Durumu
Name[uk]=Погода
-Name[uz]=Ob-havo
-Name[uz@cyrillic]=Об-ҳаво
+Name[uz]=Об-ҳаво
Name[zh_CN]=天气
Name[zh_TW]=天氣
Comment=Weather Information Component
@@ -518,22 +470,15 @@ Comment[ca]=Component d'informació del temps
Comment[da]=Komponent til vejrinformation
Comment[de]=Komponente für Wetterinformationen
Comment[el]=Συστατικό πληροφοριών καιρού
-Comment[es]=Componente de información meteorológica
Comment[et]=Ilmateate komponent
-Comment[fr]=Composant d'Informations météorologiques
-Comment[is]=Eining fyrir veðurupplýsingar
Comment[it]=Informazioni meteorologiche
Comment[ja]=気象情報コンポーネント
-Comment[km]=សមាសភាគ​ព័ត៌មាន​អាកាសធាតុ
Comment[nds]=Wederinformatschonen-Komponent
Comment[nl]=Weerinformatiecomponent
Comment[pl]=Składnik informacji o pogodzie
-Comment[ru]=Информация о погоде
-Comment[sk]=Informácie o počasí
Comment[sr]=Компонента информација о времену
Comment[sr@Latn]=Komponenta informacija o vremenu
Comment[sv]=Komponent med väderrapport
-Comment[tr]=Hava Durumu Bilgisi Bileşeni
Comment[zh_CN]=天气信息组件
Comment[zh_TW]=天氣資訊組件
Weight=1000
@@ -566,7 +511,6 @@ Name[id]=Ticker Berita
Name[is]=Fréttastrimill
Name[it]=Ticker notizie
Name[ja]=ニュースティッカー
-Name[ka]=სიახლეთა ტიკერი
Name[kk]=Жаңалық таспасы
Name[km]=កម្មវិធី​ទទួល​ព័ត៌មាន
Name[lt]=News pranešėjas
@@ -618,7 +562,6 @@ Comment[hu]=Hírmegjelenítő komponens
Comment[is]=Fréttastrimilshluti
Comment[it]=Ticker notizie
Comment[ja]=ニュースティッカーコンポーネント
-Comment[ka]=სიახლეთა ტიკერის კომპონენტი
Comment[kk]=Жаңалық таспасының компоненті
Comment[km]=សមាសភាគ​កម្មវិធី​ទទួល​ព័ត៌មាន
Comment[lt]=Naujienų pranešėjo komponentas
diff --git a/kontact/src/kontactui.rc b/kontact/src/kontactui.rc
index 8c68f0607..bd846c78c 100644
--- a/kontact/src/kontactui.rc
+++ b/kontact/src/kontactui.rc
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<!DOCTYPE gui SYSTEM "kpartgui.dtd">
-<gui version="22" name="kontact" >
+<gui version="23" name="kontact" >
<MenuBar>
<Menu name="file" noMerge="1">
<text>&amp;File</text>
@@ -31,15 +31,12 @@
<Menu name="help"><text>&amp;Help</text>
<Action name="help_introduction"/>
<Action name="help_tipofday"/>
- <Separator/>
- <Action name="help_requestfeature"/>
</Menu>
</MenuBar>
<ToolBar position="Top" noMerge="1" name="mainToolBar"><text>Main Toolbar</text>
<Action name="action_new"/>
<Action name="action_sync"/>
<Merge/>
- <Action name="help_whats_this"/>
</ToolBar>
<ToolBar position="Top" hidden="true" name="navigatorToolBar"><text>Navigator</text>
<Action name="navigator_spacer_item"/>
diff --git a/kontact/src/main.cpp b/kontact/src/main.cpp
index c19872357..ee098180e 100644
--- a/kontact/src/main.cpp
+++ b/kontact/src/main.cpp
@@ -40,17 +40,21 @@
#include "alarmclient.h"
#include "mainwindow.h"
#include <uniqueapphandler.h> // in ../interfaces
+#include "profilemanager.h"
using namespace std;
static const char description[] =
I18N_NOOP( "KDE personal information manager" );
-static const char version[] = "1.2.9";
+static const char version[] = "1.2.9 (enterprise35 0.20100827.1168748)";
class KontactApp : public KUniqueApplication {
public:
- KontactApp() : mMainWindow( 0 ), mSessionRestored( false ) {}
+ KontactApp() : mMainWindow( 0 ), mSessionRestored( false )
+ {
+ KGlobal::iconLoader()->addAppDir( "kdepim" );
+ }
~KontactApp() {}
int newInstance();
@@ -84,6 +88,14 @@ static void listPlugins()
}
}
+static void listProfiles()
+{
+ TQValueList<Kontact::Profile> profiles = Kontact::ProfileManager::self()->profiles();
+ for( TQValueListIterator<Kontact::Profile> it = profiles.begin() ; it != profiles.end(); ++it ) {
+ cout << (*it).name().latin1() << endl;
+ }
+}
+
int KontactApp::newInstance()
{
KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
@@ -112,6 +124,16 @@ int KontactApp::newInstance()
}
}
+ if ( args->isSet( "profile" ) ) {
+ TQValueList<Kontact::Profile> profiles = Kontact::ProfileManager::self()->profiles();
+ for( TQValueListIterator<Kontact::Profile> it = profiles.begin(); it != profiles.end(); ++it ){
+ if( args->getOption("profile") == (*it).name().latin1() ) {
+ Kontact::ProfileManager::self()->loadProfile( (*it).id() );
+ break;
+ }
+ }
+ }
+
AlarmClient alarmclient;
alarmclient.startDaemon();
@@ -143,6 +165,11 @@ int main( int argc, char **argv )
return 0;
}
+ if ( args->isSet( "listprofiles" ) ) {
+ listProfiles();
+ return 0;
+ }
+
if ( !KontactApp::start() ) {
// Already running, brought to the foreground.
return 0;
diff --git a/kontact/src/mainwindow.cpp b/kontact/src/mainwindow.cpp
index 541742bba..247bb6654 100644
--- a/kontact/src/mainwindow.cpp
+++ b/kontact/src/mainwindow.cpp
@@ -20,6 +20,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include <tqaction.h>
#include <tqcombobox.h>
#include <tqdockarea.h>
#include <tqguardedptr.h>
@@ -122,6 +123,27 @@ void MainWindow::initGUI()
connect( helpMenu, TQT_SIGNAL( showAboutApplication() ),
TQT_SLOT( showAboutDialog() ) );
+ KTrader::OfferList offers = KTrader::self()->query(
+ TQString::fromLatin1( "Kontact/Plugin" ),
+ TQString( "[X-KDE-KontactPluginVersion] == %1" ).arg( KONTACT_PLUGIN_VERSION ) );
+ mPluginInfos = KPluginInfo::fromServices( offers, Prefs::self()->config(), "Plugins" );
+
+ KPluginInfo::List::Iterator it;
+ for ( it = mPluginInfos.begin(); it != mPluginInfos.end(); ++it ) {
+ (*it)->load();
+
+ KAction *action = new KAction( (*it)->name(), (*it)->icon(), KShortcut(),
+ this, TQT_SLOT(slotActionTriggered()),
+ actionCollection(), (*it)->pluginName().latin1() );
+ action->setName( (*it)->pluginName().latin1() );
+ action->setWhatsThis( i18n( "Switch to plugin %1" ).arg( (*it)->name() ) );
+
+ TQVariant hasPartProp = (*it)->property( "X-KDE-KontactPluginHasPart" );
+ if ( !hasPartProp.isValid() || hasPartProp.toBool() ) {
+ mActionPlugins.append( action );
+ }
+ }
+
KStdAction::keyBindings( this, TQT_SLOT( configureShortcuts() ), actionCollection() );
KStdAction::configureToolbars( this, TQT_SLOT( configureToolbars() ), actionCollection() );
setXMLFile( "kontactui.rc" );
@@ -130,38 +152,27 @@ void MainWindow::initGUI()
createGUI( 0 );
+ loadPlugins();
+
resize( 700, 520 ); // initial size to prevent a scrollbar in sidepane
setAutoSaveSettings();
- connect( Kontact::ProfileManager::self(), TQT_SIGNAL( profileLoaded( const TQString& ) ),
+ connect( Kontact::ProfileManager::self(), TQT_SIGNAL( profileLoaded( const TQString& ) ),
this, TQT_SLOT( slotLoadProfile( const TQString& ) ) );
- connect( Kontact::ProfileManager::self(), TQT_SIGNAL( saveToProfileRequested( const TQString& ) ),
+ connect( Kontact::ProfileManager::self(), TQT_SIGNAL( saveToProfileRequested( const TQString& ) ),
this, TQT_SLOT( slotSaveToProfile( const TQString& ) ) );
}
void MainWindow::initObject()
{
- KTrader::OfferList offers = KTrader::self()->query(
- TQString::fromLatin1( "Kontact/Plugin" ),
- TQString( "[X-KDE-KontactPluginVersion] == %1" ).arg( KONTACT_PLUGIN_VERSION ) );
- mPluginInfos = KPluginInfo::fromServices( offers, Prefs::self()->config(), "Plugins" );
-
- KPluginInfo::List::Iterator it;
- for ( it = mPluginInfos.begin(); it != mPluginInfos.end(); ++it ) {
- ( *it )->load();
- }
-
// prepare the part manager
mPartManager = new KParts::PartManager( this );
connect( mPartManager, TQT_SIGNAL( activePartChanged( KParts::Part* ) ),
this, TQT_SLOT( slotActivePartChanged( KParts::Part* ) ) );
- loadPlugins();
-
if ( mSidePane ) {
mSidePane->updatePlugins();
- plugActionList( "navigator_actionlist", mSidePane->actions() );
}
KSettings::Dispatcher::self()->registerInstance( instance(), this,
@@ -240,8 +251,6 @@ void MainWindow::initWidgets()
sizes << 0;
mSplitter->setSizes(sizes);
- mSidePane->setActionCollection( actionCollection() );
-
connect( mSidePane, TQT_SIGNAL( pluginSelected( Kontact::Plugin * ) ),
TQT_SLOT( selectPlugin( Kontact::Plugin * ) ) );
@@ -348,9 +357,7 @@ void MainWindow::setupActions()
actionCollection(), "help_introduction" );
new KAction( i18n( "&Tip of the Day" ), 0, this, TQT_SLOT( slotShowTip() ),
actionCollection(), "help_tipofday" );
- new KAction( i18n( "&Request Feature..." ), 0, this, TQT_SLOT( slotRequestFeature() ),
- actionCollection(), "help_requestfeature" );
-
+
KWidgetAction* spacerAction = new KWidgetAction( new TQWidget( this ), "SpacerAction", "", 0, 0, actionCollection(), "navigator_spacer_item" );
spacerAction->setAutoSized( true );
}
@@ -387,7 +394,7 @@ void MainWindow::slotSaveToProfile( const TQString& id )
::copyConfigEntry( cfg, &profile, "MainWindow Toolbar navigatorToolBar", "Hidden", "true" );
::copyConfigEntry( cfg, &profile, "View", "SidePaneSplitter" );
::copyConfigEntry( cfg, &profile, "Icons", "Theme" );
-
+
for ( PluginList::Iterator it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
if ( !(*it)->isRunningStandalone() ) {
(*it)->part();
@@ -461,6 +468,61 @@ Plugin *MainWindow::pluginFromInfo( const KPluginInfo *info )
return 0;
}
+Plugin *MainWindow::pluginFromAction( const KAction *action )
+{
+ PluginList::ConstIterator end = mPlugins.end();
+ for ( PluginList::ConstIterator it = mPlugins.begin(); it != end; ++it ) {
+ if ( (*it)->identifier() == action->name() ) {
+ return *it;
+ }
+ }
+ return 0;
+}
+
+bool MainWindow::isPluginLoadedByAction( const KAction *action )
+{
+ KPluginInfo::List::ConstIterator it;
+ for ( it = mPluginInfos.begin(); it != mPluginInfos.end(); ++it ) {
+ if ( !(*it)->isPluginEnabled() )
+ continue;
+ if ( isPluginLoaded( *it ) ) {
+ Plugin *plugin = pluginFromInfo( *it );
+ if ( plugin ) {
+ if ( plugin->identifier() == action->name() ) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+void MainWindow::sortActionsByWeight()
+{
+ TQPtrList<KAction> sorted;
+
+ TQPtrListIterator<KAction> eit( mActionPlugins );
+ KAction *action;
+ while ( ( action = eit.current() ) != 0 ) {
+ ++eit;
+ TQPtrListIterator<KAction> sortIt( sorted );
+ uint at = 0;
+ KAction *saction;
+ Plugin *p1 = pluginFromAction( action );
+ while ( ( saction = sortIt.current() ) != 0 ) {
+ Plugin *p2 = pluginFromAction( saction );
+ if ( p1 && p2 && p1->weight() >= p2->weight() ) {
+ ++sortIt;
+ ++at;
+ } else {
+ break;
+ }
+ }
+ sorted.insert( at, action );
+ }
+ mActionPlugins = sorted;
+}
+
void MainWindow::loadPlugins()
{
TQPtrList<Plugin> plugins;
@@ -523,6 +585,9 @@ void MainWindow::loadPlugins()
for ( action = actionList->first(); action; action = actionList->next() ) {
kdDebug(5600) << "Plugging " << action->name() << endl;
action->plug( mNewActions->popupMenu() );
+ if ( action->name() == plugin->identifier() ) {
+ mPluginAction.insert( plugin, action );
+ }
}
if ( mSyncActionsEnabled ) {
@@ -534,6 +599,7 @@ void MainWindow::loadPlugins()
}
addPlugin( plugin );
}
+ updateShortcuts();
mNewActions->setEnabled( mPlugins.size() != 0 );
if ( mSyncActionsEnabled )
@@ -542,24 +608,47 @@ void MainWindow::loadPlugins()
void MainWindow::unloadPlugins()
{
- KPluginInfo::List::ConstIterator end = mPluginInfos.end();
+ KPluginInfo::List::ConstIterator end = mPluginInfos.constEnd();
KPluginInfo::List::ConstIterator it;
- for ( it = mPluginInfos.begin(); it != end; ++it ) {
+ for ( it = mPluginInfos.constBegin(); it != end; ++it ) {
if ( !(*it)->isPluginEnabled() )
removePlugin( *it );
}
}
+void MainWindow::updateShortcuts()
+{
+ TQPtrList<KAction> loadedActions;
+
+ sortActionsByWeight();
+
+ TQPtrListIterator<KAction> it( mActionPlugins );
+ int i = 1;
+ KAction *action;
+ while ( ( action = it.current() ) != 0 ) {
+ ++it;
+ if ( isPluginLoadedByAction( action ) ) {
+ loadedActions.append( action );
+ TQString shortcut = TQString( "CTRL+%1" ).arg( i );
+ action->setShortcut( KShortcut( shortcut ) );
+ i++;
+ } else {
+ action->setShortcut( KShortcut() );
+ }
+ }
+ unplugActionList( "navigator_actionlist" );
+ factory()->plugActionList( this, TQString( "navigator_actionlist" ), loadedActions );
+}
+
bool MainWindow::removePlugin( const KPluginInfo *info )
{
PluginList::Iterator end = mPlugins.end();
- for ( PluginList::Iterator it = mPlugins.begin(); it != end; ++it )
+ for ( PluginList::Iterator it = mPlugins.begin(); it != end; ++it ) {
if ( ( *it )->identifier() == info->pluginName() ) {
Plugin *plugin = *it;
KAction *action;
TQPtrList<KAction> *actionList = plugin->newActions();
-
for ( action = actionList->first(); action; action = actionList->next() ) {
kdDebug(5600) << "Unplugging " << action->name() << endl;
action->unplug( mNewActions->popupMenu() );
@@ -577,9 +666,13 @@ bool MainWindow::removePlugin( const KPluginInfo *info )
if ( mCurrentPlugin == plugin )
mCurrentPlugin = 0;
- delete plugin; // removes the part automatically
+ plugin->deleteLater(); // removes the part automatically
mPlugins.remove( it );
+ if ( plugin->showInSideBar() ) {
+ mPluginAction.remove( plugin );
+ }
+
if ( mCurrentPlugin == 0 ) {
PluginList::Iterator it;
for ( it = mPlugins.begin(); it != mPlugins.end(); ++it ) {
@@ -589,10 +682,9 @@ bool MainWindow::removePlugin( const KPluginInfo *info )
}
}
}
-
return true;
}
-
+ }
return false;
}
@@ -674,6 +766,15 @@ KToolBar* Kontact::MainWindow::findToolBar(const char* name)
return static_cast<KToolBar *>(child(name, "KToolBar"));
}
+void MainWindow::slotActionTriggered()
+{
+ const KAction *actionSender = static_cast<const KAction*>( sender() );
+ TQString identifier = actionSender->name();
+ if ( !identifier.isEmpty() ) {
+ selectPlugin( identifier );
+ }
+}
+
void MainWindow::selectPlugin( Kontact::Plugin *plugin )
{
if ( !plugin )
@@ -713,8 +814,9 @@ void MainWindow::selectPlugin( Kontact::Plugin *plugin )
}
}
- if ( mSidePane )
- mSidePane->selectPlugin( plugin );
+ if ( mSidePane ) {
+ mSidePane->selectPlugin( plugin->identifier() );
+ }
plugin->select();
@@ -832,12 +934,6 @@ void MainWindow::slotShowTip()
showTip( true );
}
-void MainWindow::slotRequestFeature()
-{
- if ( kapp )
- kapp->invokeBrowser( "http://kontact.org/shopping" );
-}
-
void MainWindow::slotShowIntroduction()
{
mPartsStack->raiseWidget( 0 ); // ###
@@ -915,11 +1011,10 @@ int MainWindow::startServiceFor( const TQString& serviceType,
void MainWindow::pluginsChanged()
{
- unplugActionList( "navigator_actionlist" );
unloadPlugins();
loadPlugins();
mSidePane->updatePlugins();
- plugActionList( "navigator_actionlist", mSidePane->actions() );
+ updateShortcuts();
}
void MainWindow::updateConfig()
@@ -965,9 +1060,13 @@ void MainWindow::configureToolbars()
void MainWindow::slotNewToolbarConfig()
{
- if ( mCurrentPlugin && mCurrentPlugin->part() )
+ if ( mCurrentPlugin && mCurrentPlugin->part() ) {
createGUI( mCurrentPlugin->part() );
- applyMainWindowSettings( KGlobal::config(), "MainWindow" );
+ }
+ if ( mCurrentPlugin ) {
+ applyMainWindowSettings( KGlobal::config(), "MainWindow" );
+ }
+ updateShortcuts(); // for the plugActionList call
}
void MainWindow::slotOpenUrl( const KURL &url )
@@ -980,8 +1079,16 @@ void MainWindow::slotOpenUrl( const KURL &url )
KRun::runCommand( "groupwarewizard" );
slotQuit();
}
- } else
+ if ( url.path().startsWith( "/help" ) ) {
+ TQString app( "kontact" );
+ if ( !url.query().isEmpty() ) {
+ app = url.query().mid( 1 );
+ }
+ kapp->invokeHelp( TQString::null, app );
+ }
+ } else {
new KRun( url, this );
+ }
}
void MainWindow::readProperties( KConfig *config )
@@ -1073,11 +1180,11 @@ TQString MainWindow::introductionString()
"<p style=\"margin-bottom: 0px\"> <a href=\"%1\">Skip this introduction</a></p>" )
.arg( kapp->aboutData()->version() )
.arg( i18n( "Kontact handles your e-mail, addressbook, calendar, to-do list and more." ) )
- .arg( "help:/kontact" )
+ .arg( "exec:/help?kontact" )
.arg( iconSize )
.arg( iconSize )
.arg( handbook_icon_path )
- .arg( "help:/kontact" )
+ .arg( "exec:/help?kontact" )
.arg( i18n( "Read Manual" ) )
.arg( i18n( "Learn more about Kontact and its components" ) )
.arg( "http://kontact.org" )
diff --git a/kontact/src/mainwindow.h b/kontact/src/mainwindow.h
index 892fce64e..5d5945b6b 100644
--- a/kontact/src/mainwindow.h
+++ b/kontact/src/mainwindow.h
@@ -36,6 +36,7 @@
#include "core.h"
#include "kontactiface.h"
+class TQAction;
class TQHBox;
class TQSplitter;
class TQVBox;
@@ -56,11 +57,12 @@ namespace KPIM
namespace Kontact
{
-class Plugin;
-class SidePaneBase;
class AboutDialog;
+class IconSidePane;
+class Plugin;
typedef TQValueList<Kontact::Plugin*> PluginList;
+typedef TQPtrList<KAction> ActionPluginList;
class MainWindow : public Kontact::Core, public KDCOPServiceStarter, public KontactIface
{
@@ -83,6 +85,7 @@ class MainWindow : public Kontact::Core, public KDCOPServiceStarter, public Kont
public slots:
virtual void selectPlugin( Kontact::Plugin *plugin );
virtual void selectPlugin( const TQString &pluginName );
+ void slotActionTriggered();
void updateConfig();
@@ -95,7 +98,6 @@ class MainWindow : public Kontact::Core, public KDCOPServiceStarter, public Kont
void slotSyncClicked();
void slotQuit();
void slotShowTip();
- void slotRequestFeature();
void slotConfigureProfiles();
void slotLoadProfile( const TQString& id );
void slotSaveToProfile( const TQString& id );
@@ -112,10 +114,14 @@ class MainWindow : public Kontact::Core, public KDCOPServiceStarter, public Kont
void loadSettings();
void saveSettings();
+ void sortActionsByWeight();
bool isPluginLoaded( const KPluginInfo * );
+ bool isPluginLoadedByAction( const KAction *action );
Kontact::Plugin *pluginFromInfo( const KPluginInfo * );
+ Kontact::Plugin *pluginFromAction( const KAction * );
void loadPlugins();
void unloadPlugins();
+ void updateShortcuts();
bool removePlugin( const KPluginInfo * );
void addPlugin( Kontact::Plugin *plugin );
void partLoaded( Kontact::Plugin *plugin, KParts::ReadOnlyPart *part );
@@ -141,12 +147,13 @@ class MainWindow : public Kontact::Core, public KDCOPServiceStarter, public Kont
KToolBarPopupAction *mNewActions;
KToolBarPopupAction *mSyncActions;
- SidePaneBase *mSidePane;
+ IconSidePane *mSidePane;
TQWidgetStack *mPartsStack;
Plugin *mCurrentPlugin;
KParts::PartManager *mPartManager;
PluginList mPlugins;
PluginList mDelayedPreload;
+ ActionPluginList mActionPlugins;
TQValueList<KPluginInfo*> mPluginInfos;
KHTMLPart *mIntroPart;
@@ -156,6 +163,7 @@ class MainWindow : public Kontact::Core, public KDCOPServiceStarter, public Kont
TQString mActiveModule;
TQMap<TQString, TQGuardedPtr<TQWidget> > mFocusWidgets;
+ TQMap<Kontact::Plugin *, KAction *> mPluginAction;
AboutDialog *mAboutDialog;
bool mReallyClose;
diff --git a/kontact/src/sidepanebase.cpp b/kontact/src/sidepanebase.cpp
index 28bae2999..92a3ce510 100644
--- a/kontact/src/sidepanebase.cpp
+++ b/kontact/src/sidepanebase.cpp
@@ -39,14 +39,4 @@ Core* SidePaneBase::core() const
return mCore;
}
-void SidePaneBase::setActionCollection( KActionCollection *actionCollection )
-{
- mActionCollection = actionCollection;
-}
-
-KActionCollection *SidePaneBase::actionCollection() const
-{
- return mActionCollection;
-}
-
#include "sidepanebase.moc"
diff --git a/kontact/src/sidepanebase.h b/kontact/src/sidepanebase.h
index 407d98de6..0b4a7a542 100644
--- a/kontact/src/sidepanebase.h
+++ b/kontact/src/sidepanebase.h
@@ -38,11 +38,6 @@ class SidePaneBase : public QVBox
SidePaneBase( Core *core, TQWidget *parent, const char *name = 0 );
virtual ~SidePaneBase();
- void setActionCollection( KActionCollection *actionCollection );
- KActionCollection *actionCollection() const;
-
- virtual const TQPtrList<KAction> & actions() = 0;
-
signals:
void pluginSelected( Kontact::Plugin* );
@@ -53,17 +48,6 @@ class SidePaneBase : public QVBox
*/
virtual void updatePlugins() = 0;
- /**
- Select the current plugin without emmiting a signal.
- This is used to sync with the core.
- */
- virtual void selectPlugin( Kontact::Plugin* ) = 0;
-
- /**
- This is an overloaded member function. It behaves essentially like the
- above function.
- */
- virtual void selectPlugin( const TQString &name ) = 0;
virtual void indicateForegrunding( Kontact::Plugin* ) = 0;
protected:
diff --git a/korganizer/Makefile.am b/korganizer/Makefile.am
index 8b6e4d91e..6b434ab8a 100644
--- a/korganizer/Makefile.am
+++ b/korganizer/Makefile.am
@@ -90,7 +90,7 @@ libkorganizer_la_SOURCES = komessagebox.cpp \
koeventview.cpp \
korganizeriface.skel kcalendariface.skel \
filtereditdialog.cpp filteredit_base.ui \
- kowhatsnextview.cpp kocounterdialog.cpp \
+ kowhatsnextview.cpp \
kojournalview.cpp journalentry.cpp \
kocore.cpp mailscheduler.cpp \
kodaymatrix.cpp docprefs.cpp statusdialog.cpp\
@@ -101,6 +101,7 @@ libkorganizer_la_SOURCES = komessagebox.cpp \
koprefs_base.kcfgc \
koincidencetooltip.cpp aboutdata.cpp \
importdialog.cpp \
+ previewdialog.cpp \
korganizerifaceimpl.cpp \
freebusymanager.cpp freebusyurldialog.cpp \
eventarchiver.cpp koidentitymanager.cpp \
@@ -174,10 +175,10 @@ KDE_ICON = AUTO
META_INCLUDES = $(srcdir)/interfaces/korganizer
messages: rc.cpp
- $(PREPARETIPS) > tips.txt
+ $(PREPARETIPS) > tips.cpp
$(EXTRACTRC) `find . -name "*.rc" -o -name "*.ui" -o -name "*.kcfg"` >> rc.cpp
- $(XGETTEXT) `find . -name "*.cpp" -o -name "*.h" -o -name "*.txt"` -o $(podir)/korganizer.pot
- rm -f tips.txt
+ $(XGETTEXT) `find . -name "*.cpp" -o -name "*.h"` -o $(podir)/korganizer.pot
+ rm -f tips.cpp
xdg_apps_DATA = korganizer.desktop
diff --git a/korganizer/Todo-info.text b/korganizer/Todo-info.text
new file mode 100644
index 000000000..19d911163
--- /dev/null
+++ b/korganizer/Todo-info.text
@@ -0,0 +1,18 @@
+
+ TODO's behavior in agenda and month views
+
+
+Here are the rules for how/when/where should to-dos be displayed in agenda/month view:
+
+* startDt doesn't influence to-do behavior, it's irrelevant
+* To-dos without dueDt aren't shown
+* The time component doesn't influence the behavior in month view, only agenda
+* Overdue to-dos appear today, and not at dtDue, so we don't forget them
+* In agenda, if the to-do is overdue and has time, it should appear in the all
+ day area because, since it's overdue, you must do it ASAP and not wait for the
+ original time.
+
+* In agenda, a not-overdue to-do, with time, is drawn with the rectangle ending
+ at dtDue, and not starting at dtDue. If dtDue is at 00h00, then it should be
+ displayed in the previous day, ending at 23:59:59
+
diff --git a/korganizer/aboutdata.cpp b/korganizer/aboutdata.cpp
index f372d11fc..b5fb98c31 100644
--- a/korganizer/aboutdata.cpp
+++ b/korganizer/aboutdata.cpp
@@ -34,10 +34,11 @@ AboutData::AboutData()
KAboutData::License_GPL,
"(c) 1997-1999 Preston Brown\n"
"(c) 2000-2004 Cornelius Schumacher\n"
- "(c) 2004-2005 Reinhold Kainhofer", 0,
+ "(c) 2004-2005 Reinhold Kainhofer\n"
+ "(c) 2009-2010 Timothy Pearson", 0,
"http://korganizer.kde.org" )
{
- addAuthor("Timothy Pearson",I18N_NOOP("Current Maintainer"),
+ addAuthor("Timothy Pearson",I18N_NOOP("Current Developer/Maintainer"),
"kb9vqf@pearsoncomputing.net");
addAuthor("Reinhold Kainhofer",I18N_NOOP("Previous maintainer"),
"reinhold@kainhofer.com");
diff --git a/korganizer/actionmanager.cpp b/korganizer/actionmanager.cpp
index 99939ef1c..b9df9e869 100644
--- a/korganizer/actionmanager.cpp
+++ b/korganizer/actionmanager.cpp
@@ -26,7 +26,7 @@
*/
#include "actionmanager.h"
-
+#include "previewdialog.h"
#include "alarmclient.h"
#include "calendarview.h"
#include "kocore.h"
@@ -34,13 +34,15 @@
#include "koglobals.h"
#include "koprefs.h"
#include "koviewmanager.h"
+#include "koagendaview.h"
+#include "multiagendaview.h"
#include "kowindowlist.h"
#include "kprocess.h"
#include "konewstuff.h"
#include "history.h"
#include "kogroupware.h"
#include "resourceview.h"
-#include "importdialog.h"
+#include "previewdialog.h"
#include "eventarchiver.h"
#include "stdcalendar.h"
#include "freebusymanager.h"
@@ -68,13 +70,13 @@
#include <kstdguiitem.h>
#include <kdeversion.h>
#include <kactionclasses.h>
+#include <kcmdlineargs.h>
#include <tqapplication.h>
#include <tqcursor.h>
#include <tqtimer.h>
#include <tqlabel.h>
-
// FIXME: Several places in the file don't use KConfigXT yet!
KOWindowList *ActionManager::mWindowList = 0;
@@ -153,12 +155,12 @@ void ActionManager::init()
connect( mCalendarView, TQT_SIGNAL( modifiedChanged( bool ) ), TQT_SLOT( setTitle() ) );
connect( mCalendarView, TQT_SIGNAL( configChanged() ), TQT_SLOT( updateConfig() ) );
- connect( mCalendarView, TQT_SIGNAL( incidenceSelected( Incidence * ) ),
- this, TQT_SLOT( processIncidenceSelection( Incidence * ) ) );
+ connect( mCalendarView, TQT_SIGNAL( incidenceSelected( Incidence *,const TQDate & ) ),
+ this, TQT_SLOT( processIncidenceSelection( Incidence *,const TQDate & ) ) );
connect( mCalendarView, TQT_SIGNAL( exportHTML( HTMLExportSettings * ) ),
this, TQT_SLOT( exportHTML( HTMLExportSettings * ) ) );
- processIncidenceSelection( 0 );
+ processIncidenceSelection( 0, TQDate() );
// Update state of paste action
mCalendarView->checkClipboard();
@@ -197,7 +199,7 @@ void ActionManager::createCalendarResources()
mResourceView = factory.resourceView();
connect( mCalendarResources, TQT_SIGNAL( calendarChanged() ),
- mCalendarView, TQT_SLOT(resourcesChanged() ) );
+ mCalendarView, TQT_SLOT( resourcesChanged() ) );
connect( mCalendarResources, TQT_SIGNAL( signalErrorMessage( const TQString & ) ),
mCalendarView, TQT_SLOT( showErrorMessage( const TQString & ) ) );
@@ -250,9 +252,9 @@ void ActionManager::initActions()
//~~~~~~~~~~~~~~~~~~~~~~~~ IMPORT / EXPORT ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- new KAction( i18n("Import &Calendar..."), 0, this, TQT_SLOT( file_merge() ),
+ new KAction( i18n("Import &Event/Calendar (ICS-/VCS-File)..."), 0, this, TQT_SLOT( file_merge() ),
mACollection, "import_icalendar" );
- new KAction( i18n("&Import From UNIX Ical tool"), 0, this, TQT_SLOT( file_icalimport() ),
+ new KAction( i18n("&Import From UNIX Ical tool (.calendar-File)"), 0, this, TQT_SLOT( file_icalimport() ),
mACollection, "import_ical" );
new KAction( i18n("Get &Hot New Stuff..."), 0, this,
TQT_SLOT( downloadNewStuff() ), mACollection,
@@ -312,10 +314,10 @@ void ActionManager::initActions()
mACollection, "edit_delete" );
if ( mIsPart ) {
KStdAction::find( mCalendarView->dialogManager(), TQT_SLOT( showSearchDialog() ),
- mACollection, "korganizer_find" );
+ mACollection, "korganizer_find" );
} else {
KStdAction::find( mCalendarView->dialogManager(), TQT_SLOT( showSearchDialog() ),
- mACollection );
+ mACollection );
}
pasteAction->setEnabled( false );
mUndoAction->setEnabled( false );
@@ -447,11 +449,11 @@ void ActionManager::initActions()
//************************** Actions MENU *********************************
new KAction( i18n("New E&vent..."),
KOGlobals::self()->smallIcon( "newappointment" ), 0,
- mCalendarView, TQT_SLOT( newEvent() ),
+ mCalendarView, TQT_SLOT(newEvent()),
mACollection, "new_event" );
new KAction( i18n("New &To-do..."),
KOGlobals::self()->smallIcon( "newtodo" ), 0,
- mCalendarView, TQT_SLOT( newTodo() ),
+ mCalendarView, TQT_SLOT(newTodo()),
mACollection, "new_todo" );
action = new KAction( i18n("New Su&b-to-do..."), 0,
mCalendarView,TQT_SLOT( newSubTodo() ),
@@ -461,7 +463,7 @@ void ActionManager::initActions()
action,TQT_SLOT( setEnabled( bool ) ) );
new KAction( i18n("New &Journal..."),
KOGlobals::self()->smallIcon( "newjournal" ), 0,
- mCalendarView, TQT_SLOT( newJournal() ),
+ mCalendarView, TQT_SLOT(newJournal()),
mACollection, "new_journal" );
mShowIncidenceAction = new KAction( i18n("&Show"), 0,
@@ -498,40 +500,42 @@ void ActionManager::initActions()
mACollection, "schedule_publish" );
mPublishEvent->setEnabled( false );
- action = new KAction( i18n("Send &Invitation to Attendees"),"mail_generic",0,
- mCalendarView,TQT_SLOT( schedule_request() ),
- mACollection,"schedule_request" );
- action->setEnabled( false );
- connect( mCalendarView, TQT_SIGNAL( organizerEventsSelected( bool ) ),
- action, TQT_SLOT( setEnabled( bool ) ) );
-
- action = new KAction( i18n("Re&quest Update"), 0,
- mCalendarView, TQT_SLOT( schedule_refresh() ),
- mACollection, "schedule_refresh" );
- action->setEnabled( false );
- connect( mCalendarView,TQT_SIGNAL( groupEventsSelected( bool ) ),
- action,TQT_SLOT( setEnabled( bool ) ) );
-
- action = new KAction( i18n("Send &Cancelation to Attendees"), 0,
- mCalendarView, TQT_SLOT( schedule_cancel() ),
- mACollection, "schedule_cancel" );
- action->setEnabled( false );
- connect( mCalendarView,TQT_SIGNAL( organizerEventsSelected( bool ) ),
- action,TQT_SLOT( setEnabled( bool ) ) );
-
- action = new KAction( i18n("Send Status &Update"),"mail_reply",0,
- mCalendarView,TQT_SLOT( schedule_reply() ),
- mACollection,"schedule_reply" );
- action->setEnabled( false );
- connect( mCalendarView,TQT_SIGNAL( groupEventsSelected( bool ) ),
- action,TQT_SLOT( setEnabled( bool ) ) );
-
- action = new KAction( i18n("counter proposal","Request Chan&ge"),0,
- mCalendarView,TQT_SLOT( schedule_counter() ),
- mACollection, "schedule_counter" );
- action->setEnabled( false );
- connect( mCalendarView,TQT_SIGNAL( groupEventsSelected( bool ) ),
- action,TQT_SLOT( setEnabled( bool ) ) );
+ mSendInvitation = new KAction( i18n( "Send &Invitation to Attendees" ),
+ "mail_generic", 0,
+ mCalendarView, TQT_SLOT(schedule_request()),
+ mACollection, "schedule_request" );
+ mSendInvitation->setEnabled( false );
+ connect( mCalendarView, TQT_SIGNAL(organizerEventsSelected(bool)),
+ mSendInvitation, TQT_SLOT(setEnabled(bool)) );
+
+ mRequestUpdate = new KAction( i18n( "Re&quest Update" ), 0,
+ mCalendarView, TQT_SLOT(schedule_refresh()),
+ mACollection, "schedule_refresh" );
+ mRequestUpdate->setEnabled( false );
+ connect( mCalendarView, TQT_SIGNAL(groupEventsSelected(bool)),
+ mRequestUpdate, TQT_SLOT(setEnabled(bool)) );
+
+ mSendCancel = new KAction( i18n( "Send &Cancelation to Attendees" ), 0,
+ mCalendarView, TQT_SLOT(schedule_cancel()),
+ mACollection, "schedule_cancel" );
+ mSendCancel->setEnabled( false );
+ connect( mCalendarView, TQT_SIGNAL(organizerEventsSelected(bool)),
+ mSendCancel, TQT_SLOT(setEnabled(bool)) );
+
+ mSendStatusUpdate = new KAction( i18n( "Send Status &Update" ),
+ "mail_reply", 0,
+ mCalendarView,TQT_SLOT(schedule_reply()),
+ mACollection, "schedule_reply" );
+ mSendStatusUpdate->setEnabled( false );
+ connect( mCalendarView, TQT_SIGNAL(groupEventsSelected(bool)),
+ mSendStatusUpdate, TQT_SLOT(setEnabled(bool)) );
+
+ mRequestChange = new KAction( i18n( "counter proposal", "Request Chan&ge" ), 0,
+ mCalendarView, TQT_SLOT(schedule_counter()),
+ mACollection, "schedule_counter" );
+ mRequestChange->setEnabled( false );
+ connect( mCalendarView, TQT_SIGNAL(groupEventsSelected(bool)),
+ mRequestChange, TQT_SLOT(setEnabled(bool)) );
mForwardEvent = new KAction( i18n("&Send as iCalendar..."), "mail_forward", 0,
mCalendarView, TQT_SLOT(schedule_forward()),
@@ -719,7 +723,7 @@ void ActionManager::file_open( const KURL &url )
// is that URL already opened somewhere else? Activate that window
KOrg::MainWindow *korg=ActionManager::findInstance( url );
if ( ( 0 != korg )&&( korg != mMainWindow ) ) {
- KWin::setActiveWindow( korg->topLevelWidget()->winId() );
+ KWin::activateWindow( korg->topLevelWidget()->winId() );
return;
}
@@ -745,7 +749,7 @@ void ActionManager::file_icalimport()
if ( !TQFile::exists( homeDir ) ) {
KMessageBox::error( dialogParent(),
- i18n( "You have no ical file in your home directory.\n"
+ i18n( "You have no .calendar file in your home directory.\n"
"Import cannot proceed.\n" ) );
return;
}
@@ -1055,6 +1059,11 @@ void ActionManager::exportHTML( HTMLExportSettings *settings )
{
if ( !settings || settings->outputFile().isEmpty() )
return;
+ kdDebug()<<" settings->outputFile() :"<<settings->outputFile()<<endl;
+ if ( TQFileInfo( settings->outputFile() ).exists() ) {
+ if(KMessageBox::questionYesNo( dialogParent(), i18n("Do you want to overwrite file \"%1\"").arg( settings->outputFile()) ) == KMessageBox::No)
+ return;
+ }
settings->setEMail( KOPrefs::instance()->email() );
settings->setName( KOPrefs::instance()->fullName() );
@@ -1376,11 +1385,16 @@ TQString ActionManager::getCurrentURLasString() const
return mURL.url();
}
-bool ActionManager::editIncidence( const TQString& uid )
+bool ActionManager::editIncidence( const TQString &uid )
{
return mCalendarView->editIncidence( uid );
}
+bool ActionManager::editIncidence( const TQString &uid, const TQDate &date )
+{
+ return mCalendarView->editIncidence( uid, date );
+}
+
bool ActionManager::deleteIncidence( const TQString& uid, bool force )
{
return mCalendarView->deleteIncidence( uid, force );
@@ -1454,7 +1468,7 @@ class ActionManager::ActionStringsVisitor : public IncidenceBase::Visitor
KAction *mDelete;
};
-void ActionManager::processIncidenceSelection( Incidence *incidence )
+void ActionManager::processIncidenceSelection( Incidence *incidence, const TQDate & )
{
// kdDebug(5850) << "ActionManager::processIncidenceSelection()" << endl;
@@ -1490,6 +1504,11 @@ void ActionManager::enableIncidenceActions( bool enabled )
mDeleteAction->setEnabled( enabled );
mPublishEvent->setEnabled( enabled );
mForwardEvent->setEnabled( enabled );
+ mSendInvitation->setEnabled( enabled );
+ mSendCancel->setEnabled( enabled );
+ mSendStatusUpdate->setEnabled( enabled );
+ mRequestChange->setEnabled( enabled );
+ mRequestUpdate->setEnabled( enabled );
}
void ActionManager::keyBindings()
@@ -1525,16 +1544,108 @@ KCalendarIface::ResourceRequestReply ActionManager::resourceRequest( const TQVal
return reply;
}
+QPair<ResourceCalendar *, TQString> ActionManager::viewSubResourceCalendar()
+{
+ QPair<ResourceCalendar *, TQString> p( 0, TQString() );
+
+ // return now if we are running as a part and we aren't the currently active part
+ if ( mIsPart && !mMainWindow->isCurrentlyActivePart() ) {
+ return p;
+ }
+
+ KOrg::BaseView *cV = mCalendarView->viewManager()->currentView();
+ if ( cV && cV == mCalendarView->viewManager()->multiAgendaView() ) {
+ cV = mCalendarView->viewManager()->multiAgendaView()->selectedAgendaView();
+ }
+ if ( cV ) {
+ p = qMakePair( cV->resourceCalendar(), cV->subResourceCalendar() );
+ }
+ return p;
+}
+
+bool ActionManager::isWritable( ResourceCalendar *res, const TQString &subRes,
+ const TQString &contentsType )
+{
+
+ if ( res && res->isActive() ) {
+ // Check specified resource for writability.
+ if ( res->readOnly() || !res->subresourceWritable( subRes ) ) {
+ TQString resName = res->resourceName();
+ if ( res->canHaveSubresources() ) {
+ resName = res->labelForSubresource( subRes );
+ }
+ KMessageBox::sorry(
+ dialogParent(),
+ i18n( "\"%1\" is read-only. "
+ "Please select a writable calendar before attempting to create a new item." ).
+ arg( resName ),
+ i18n( "Read-only calendar" ) );
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ // No specific resource so let's check all possible calendars for writability.
+ CalendarResourceManager *m = mCalendarResources->resourceManager();
+ CalendarResourceManager::ActiveIterator it;
+ for ( it = m->activeBegin(); it != m->activeEnd(); ++it ) {
+ ResourceCalendar *res = (*it);
+ if ( res->canHaveSubresources() ) {
+ TQStringList subResources = res->subresources();
+ for ( TQStringList::ConstIterator subit = subResources.constBegin();
+ subit != subResources.constEnd(); ++subit ) {
+ if ( res->subresourceWritable( (*subit) ) && res->subresourceActive( (*subit) ) ) {
+ if ( res->subresourceType( *subit ).isEmpty() ||
+ res->subresourceType( *subit ) == contentsType ) {
+ return true;
+ }
+ }
+ }
+ } else if ( !res->readOnly() ) {
+ return true;
+ }
+ }
+ // we don't have any writable calendars
+ TQString errorText;
+ if ( contentsType == "event" ) {
+ errorText =
+ i18n( "You have no active, writable event folder so saving will not be possible.\n"
+ "Please create or activate at least one writable event folder and try again." );
+ } else if ( contentsType == "todo" ) {
+ errorText =
+ i18n( "You have no active, writable to-do (task) folders so saving will not be possible.\n"
+ "Please create or activate at least one writable to-do folder and try again." );
+ } else if ( contentsType == "journal" ) {
+ errorText =
+ i18n( "You have no active, writable journal folder so saving will not be possible.\n"
+ "Please create or activate at least one writable journal folder and try again." );
+ } else {
+ errorText =
+ i18n( "You have no active, writable calendar folder so saving will not be possible.\n"
+ "Please create or activate at least one writable calendar folder and try again." );
+ }
+ KMessageBox::sorry(
+ dialogParent(),
+ errorText,
+ i18n( "No writable calendar" ) );
+ return false;
+ }
+}
+
void ActionManager::openEventEditor( const TQString& text )
{
- mCalendarView->newEvent( text );
+ QPair<ResourceCalendar *, TQString>p = viewSubResourceCalendar();
+ if ( isWritable( p.first, p.second, "event" ) ) {
+ mCalendarView->newEvent( p.first, p.second, text );
+ }
}
void ActionManager::openEventEditor( const TQString& summary,
const TQString& description,
const TQString& attachment )
{
- mCalendarView->newEvent( summary, description, attachment );
+ QPair<ResourceCalendar *, TQString>p = viewSubResourceCalendar();
+ mCalendarView->newEvent( p.first, p.second, summary, description, attachment );
}
void ActionManager::openEventEditor( const TQString& summary,
@@ -1542,7 +1653,7 @@ void ActionManager::openEventEditor( const TQString& summary,
const TQString& attachment,
const TQStringList& attendees )
{
- mCalendarView->newEvent( summary, description, attachment, attendees );
+ mCalendarView->newEvent( 0, TQString(), summary, description, attachment, attendees );
}
void ActionManager::openEventEditor( const TQString & summary,
@@ -1637,19 +1748,25 @@ void ActionManager::openEventEditor( const TQString & summary,
return;
}
- mCalendarView->newEvent( summary, description, attData, attendees, attachmentMimetype, action != KOPrefs::Link );
+ QPair<ResourceCalendar *, TQString>p = viewSubResourceCalendar();
+ mCalendarView->newEvent( p.first, p.second, summary, description, attData,
+ attendees, attachmentMimetype, action != KOPrefs::Link );
}
void ActionManager::openTodoEditor( const TQString& text )
{
- mCalendarView->newTodo( text );
+ QPair<ResourceCalendar *, TQString>p = viewSubResourceCalendar();
+ if ( isWritable( p.first, p.second, "todo" ) ) {
+ mCalendarView->newTodo( p.first, p.second, text );
+ }
}
void ActionManager::openTodoEditor( const TQString& summary,
const TQString& description,
const TQString& attachment )
{
- mCalendarView->newTodo( summary, description, attachment );
+ QPair<ResourceCalendar *, TQString>p = viewSubResourceCalendar();
+ mCalendarView->newTodo( p.first, p.second, summary, description, attachment );
}
void ActionManager::openTodoEditor( const TQString& summary,
@@ -1657,7 +1774,8 @@ void ActionManager::openTodoEditor( const TQString& summary,
const TQString& attachment,
const TQStringList& attendees )
{
- mCalendarView->newTodo( summary, description, attachment, attendees );
+ QPair<ResourceCalendar *, TQString>p = viewSubResourceCalendar();
+ mCalendarView->newTodo( p.first, p.second, summary, description, attachment, attendees );
}
void ActionManager::openTodoEditor(const TQString & summary,
@@ -1665,7 +1783,8 @@ void ActionManager::openTodoEditor(const TQString & summary,
const TQString & uri,
const TQString & file,
const TQStringList & attendees,
- const TQString & attachmentMimetype)
+ const TQString & attachmentMimetype,
+ bool isTask )
{
int action = KOPrefs::instance()->defaultTodoAttachMethod();
if ( attachmentMimetype != "message/rfc822" ) {
@@ -1680,37 +1799,48 @@ void ActionManager::openTodoEditor(const TQString & summary,
delete menu;
}
- TQString attData;
+ TQStringList attData;
switch ( action ) {
case KOPrefs::TodoAttachAsk:
return;
case KOPrefs::TodoAttachLink:
- attData = uri;
+ attData << uri;
break;
- case KOPrefs::TodoAttachInlineFull:
- attData = file;
+ case KOPrefs::TodoAttachInlineFull:
+ attData << file;
break;
default:
// menu could have been closed by cancel, if so, do nothing
return;
}
- mCalendarView->newTodo( summary, description, attData, attendees, attachmentMimetype, action != KOPrefs::Link );
+ QPair<ResourceCalendar *, TQString>p = viewSubResourceCalendar();
+ mCalendarView->newTodo( p.first, p.second,
+ summary, description,
+ attData, attendees,
+ TQStringList( attachmentMimetype ),
+ action != KOPrefs::TodoAttachLink,
+ isTask );
}
void ActionManager::openJournalEditor( const TQDate& date )
{
- mCalendarView->newJournal( date );
+ QPair<ResourceCalendar *, TQString>p = viewSubResourceCalendar();
+ mCalendarView->newJournal( p.first, p.second, date );
}
void ActionManager::openJournalEditor( const TQString& text, const TQDate& date )
{
- mCalendarView->newJournal( text, date );
+ QPair<ResourceCalendar *, TQString>p = viewSubResourceCalendar();
+ mCalendarView->newJournal( p.first, p.second, text, date );
}
void ActionManager::openJournalEditor( const TQString& text )
{
- mCalendarView->newJournal( text );
+ QPair<ResourceCalendar *, TQString>p = viewSubResourceCalendar();
+ if ( isWritable( p.first, p.second, "journal" ) ) {
+ mCalendarView->newJournal( p.first, p.second, text );
+ }
}
//TODO:
@@ -1718,7 +1848,8 @@ void ActionManager::openJournalEditor( const TQString& text )
// const TQString& description,
// const TQString& attachment )
// {
-// mCalendarView->newJournal( summary, description, attachment );
+// QPair<ResourceCalendar *, TQString>p = viewSubResourceCalendar();
+// mCalendarView->newJournal( p.first, p.second, summary, description, attachment );
// }
@@ -1879,21 +2010,23 @@ void ActionManager::importCalendar( const KURL &url )
return;
}
- ImportDialog *dialog;
- dialog = new ImportDialog( url, mMainWindow->topLevelWidget() );
- connect( dialog, TQT_SIGNAL( dialogFinished( ImportDialog * ) ),
- TQT_SLOT( slotImportDialogFinished( ImportDialog * ) ) );
+ PreviewDialog *dialog;
+ dialog = new PreviewDialog( url, mMainWindow->topLevelWidget() );
+ connect( dialog, TQT_SIGNAL( dialogFinished( PreviewDialog * ) ),
+ TQT_SLOT( slotPreviewDialogFinished( PreviewDialog * ) ) );
connect( dialog, TQT_SIGNAL( openURL( const KURL &, bool ) ),
TQT_SLOT( openURL( const KURL &, bool ) ) );
- connect( dialog, TQT_SIGNAL( newWindow( const KURL & ) ),
- TQT_SIGNAL( actionNew( const KURL & ) ) );
connect( dialog, TQT_SIGNAL( addResource( const KURL & ) ),
TQT_SLOT( addResource( const KURL & ) ) );
- dialog->show();
+ if ( dialog->loadCalendar() ) {
+ dialog->show();
+ } else {
+ KMessageBox::error( dialogParent(), i18n("Unable to open the calendar") );
+ }
}
-void ActionManager::slotImportDialogFinished( ImportDialog *dlg )
+void ActionManager::slotPreviewDialogFinished( PreviewDialog *dlg )
{
dlg->deleteLater();
mCalendarView->updateView();
@@ -1959,6 +2092,42 @@ void ActionManager::saveToProfile( const TQString & path ) const
::copyConfigEntry( cfg, &profile, "Views", "Agenda View Calendar Display" );
}
+bool ActionManager::handleCommandLine()
+{
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ KOrg::MainWindow *mainWindow = ActionManager::findInstance( KURL() );
+
+ bool ret = true;
+
+ if ( !mainWindow ) {
+ kdError() << "Unable to find default calendar resources view." << endl;
+ ret = false;
+ } else if ( args->count() <= 0 ) {
+ // No filenames given => all other args are meaningless, show main Window
+ mainWindow->topLevelWidget()->show();
+ } else if ( !args->isSet( "open" ) ) {
+ // Import, merge, or ask => we need the resource calendar window anyway.
+ mainWindow->topLevelWidget()->show();
+
+ // Check for import, merge or ask
+ if ( args->isSet( "import" ) ) {
+ for( int i = 0; i < args->count(); ++i ) {
+ mainWindow->actionManager()->addResource( args->url( i ) );
+ }
+ } else if ( args->isSet( "merge" ) ) {
+ for( int i = 0; i < args->count(); ++i ) {
+ mainWindow->actionManager()->mergeURL( args->url( i ).url() );
+ }
+ } else {
+ for( int i = 0; i < args->count(); ++i ) {
+ mainWindow->actionManager()->importCalendar( args->url( i ) );
+ }
+ }
+ }
+
+ return ret;
+}
+
TQWidget *ActionManager::dialogParent()
{
return mCalendarView->topLevelWidget();
diff --git a/korganizer/actionmanager.h b/korganizer/actionmanager.h
index 25fd6fabb..555d4e7db 100644
--- a/korganizer/actionmanager.h
+++ b/korganizer/actionmanager.h
@@ -41,8 +41,7 @@ namespace KCal
class Incidence;
class ResourceCalendar;
}
-namespace KOrg
-{
+namespace KOrg {
class MainWindow;
}
@@ -59,7 +58,7 @@ class CalendarView;
class KOrganizer;
class KONewStuff;
class KOWindowList;
-class ImportDialog;
+class PreviewDialog;
class ResourceView;
class HTMLExportSettings;
@@ -152,7 +151,8 @@ class KDE_EXPORT ActionManager : public TQObject, public KCalendarIface
*/
virtual bool deleteIncidence( const TQString& uid, bool force = false );
- bool editIncidence( const TQString& uid );
+ bool editIncidence( const TQString &uid );
+ bool editIncidence( const TQString &uid, const TQDate &date );
/**
Add an incidence to the active calendar.
@@ -194,7 +194,8 @@ class KDE_EXPORT ActionManager : public TQObject, public KCalendarIface
const TQString& uri,
const TQString& file,
const TQStringList& attendees,
- const TQString& attachmentMimetype );
+ const TQString& attachmentMimetype,
+ bool isTask );
void openJournalEditor( const TQDate& date );
void openJournalEditor( const TQString& text, const TQDate& date );
@@ -220,6 +221,8 @@ class KDE_EXPORT ActionManager : public TQObject, public KCalendarIface
void saveToProfile( const TQString & path ) const;
+ bool handleCommandLine();
+
signals:
/**
Emitted when the "New" action is activated.
@@ -251,7 +254,7 @@ class KDE_EXPORT ActionManager : public TQObject, public KCalendarIface
void setDestinationPolicy();
- void processIncidenceSelection( Incidence * );
+ void processIncidenceSelection( Incidence *incidence, const TQDate &date );
void keyBindings();
/**
@@ -342,7 +345,7 @@ class KDE_EXPORT ActionManager : public TQObject, public KCalendarIface
void updateRedoAction( const TQString & );
- void slotImportDialogFinished( ImportDialog * );
+ void slotPreviewDialogFinished( PreviewDialog * );
protected:
/** Get URL for saving. Opens FileDialog. */
@@ -367,6 +370,9 @@ class KDE_EXPORT ActionManager : public TQObject, public KCalendarIface
void initActions();
void enableIncidenceActions( bool enable );
+ QPair<ResourceCalendar *, TQString> viewSubResourceCalendar();
+ bool isWritable( ResourceCalendar *res, const TQString &subRes, const TQString &contentsType );
+
KOrg::Part::List mParts; // List of parts loaded
KURL mURL; // URL of calendar file
TQString mFile; // Local name of calendar file
@@ -401,6 +407,13 @@ class KDE_EXPORT ActionManager : public TQObject, public KCalendarIface
KAction *mPublishEvent;
KAction *mForwardEvent;
+ KAction *mSendInvitation;
+ KAction *mSendCancel;
+ KAction *mSendStatusUpdate;
+
+ KAction *mRequestChange;
+ KAction *mRequestUpdate;
+
KAction *mUndoAction;
KAction *mRedoAction;
diff --git a/korganizer/archivedialog.cpp b/korganizer/archivedialog.cpp
index 88d20fded..48c299e0a 100644
--- a/korganizer/archivedialog.cpp
+++ b/korganizer/archivedialog.cpp
@@ -130,11 +130,11 @@ ArchiveDialog::ArchiveDialog(Calendar *cal,TQWidget *parent, const char *name)
l->setBuddy(mArchiveFile->lineEdit());
fileLayout->addWidget(mArchiveFile);
topLayout->addLayout(fileLayout);
-
- TQHGroupBox *typeBox = new TQHGroupBox( i18n("Type of Items to Archive"),
+
+ TQHGroupBox *typeBox = new TQHGroupBox( i18n("Type of Items to Archive"),
topFrame);
mEvents = new TQCheckBox( i18n("&Events"), typeBox );
- mTodos = new TQCheckBox( i18n("&To-dos"), typeBox );
+ mTodos = new TQCheckBox( i18n("Completed &To-dos"), typeBox );
topLayout->addWidget( typeBox );
TQWhatsThis::add( typeBox, i18n("Here you can select which items "
"should be archived. Events are archived if they "
diff --git a/korganizer/calendarview.cpp b/korganizer/calendarview.cpp
index eb294fe74..ba1bbe6e3 100644
--- a/korganizer/calendarview.cpp
+++ b/korganizer/calendarview.cpp
@@ -65,6 +65,7 @@
#include "komailclient.h"
#include "multiagendaview.h"
+#include <libkcal/calhelper.h>
#include <libkcal/vcaldrag.h>
#include <libkcal/icaldrag.h>
#include <libkcal/icalformat.h>
@@ -130,7 +131,7 @@ CalendarView::CalendarView( TQWidget *parent, const char *name )
mExtensions.setAutoDelete( true );
- mNavigator = new DateNavigator( this );
+ mDateNavigator = new DateNavigator( this );
mDateChecker = new DateChecker( this );
TQBoxLayout *topLayout = new TQVBoxLayout( this );
@@ -145,14 +146,14 @@ CalendarView::CalendarView( TQWidget *parent, const char *name )
"CalendarView::LeftFrame" );
// mPanner->setResizeMode( mLeftSplitter, TQSplitter::Stretch );
- mDateNavigator = new DateNavigatorContainer( mLeftSplitter,
+ mDateNavigatorContainer = new DateNavigatorContainer( mLeftSplitter,
"CalendarView::DateNavigator" );
-// mLeftSplitter->setResizeMode( mDateNavigator, TQSplitter::Stretch );
- mLeftSplitter->setCollapsible( mDateNavigator, true );
+// mLeftSplitter->setResizeMode( mDateNavigatorContainer, TQSplitter::Stretch );
+ mLeftSplitter->setCollapsible( mDateNavigatorContainer, true );
mTodoList = new KOTodoView( CalendarNull::self(), mLeftSplitter, "todolist" );
- mEventViewer = new KOEventViewer( mLeftSplitter,"EventViewer" );
+ mEventViewer = new KOEventViewer( CalendarNull::self(), mLeftSplitter,"EventViewer" );
TQVBox *rightBox = new TQVBox( mPanner );
mNavigatorBar = new NavigatorBar( rightBox );
@@ -174,12 +175,12 @@ CalendarView::CalendarView( TQWidget *parent, const char *name )
topLayout->addWidget( mainBox );
- mDateNavigator = new KDateNavigator( leftFrame, true,
+ mDateNavigatorContainer = new KDateNavigator( leftFrame, true,
"CalendarView::DateNavigator",
TQDate::currentDate() );
mTodoList = new KOTodoView( CalendarNull::self(), leftFrame, "todolist" );
- mEventViewer = new KOEventViewer ( leftFrame, "EventViewer" );
+ mEventViewer = new KOEventViewer ( CalendarNull::self(), leftFrame, "EventViewer" );
TQWidget *rightBox = new TQWidget( mainBox );
TQBoxLayout *rightLayout = new TQVBoxLayout( rightBox );
@@ -193,55 +194,56 @@ CalendarView::CalendarView( TQWidget *parent, const char *name )
mLeftFrame = leftFrame;
if ( KOPrefs::instance()->mVerticalScreen ) {
-// mTodoList->setFixedHeight( 60 );
- mTodoList->setFixedHeight( mDateNavigator->sizeHint().height() );
+ // mTodoList->setFixedHeight( 60 );
+ mTodoList->setFixedHeight( mDateNavigatorContainer->sizeHint().height() );
}
#endif
- connect( mNavigator, TQT_SIGNAL( datesSelected( const KCal::DateList & ) ),
- TQT_SLOT( showDates( const KCal::DateList & ) ) );
- connect( mNavigator, TQT_SIGNAL( datesSelected( const KCal::DateList & ) ),
+ // Signals emited by mDateNavigator
+ connect( mDateNavigator, TQT_SIGNAL( datesSelected( const KCal::DateList &, const TQDate & ) ),
+ TQT_SLOT( showDates( const KCal::DateList &, const TQDate & ) ) );
+
+ // Signals emited by mNavigatorBar
+ connect( mNavigatorBar, TQT_SIGNAL( prevYearClicked() ),
+ mDateNavigator, TQT_SLOT( selectPreviousYear() ) );
+ connect( mNavigatorBar, TQT_SIGNAL( nextYearClicked() ),
+ mDateNavigator, TQT_SLOT( selectNextYear() ) );
+ connect( mNavigatorBar, TQT_SIGNAL( prevMonthClicked() ),
+ mDateNavigator, TQT_SLOT( selectPreviousMonth() ) );
+ connect( mNavigatorBar, TQT_SIGNAL( nextMonthClicked() ),
+ mDateNavigator, TQT_SLOT( selectNextMonth() ) );
+ connect( mNavigatorBar, TQT_SIGNAL( monthSelected(int) ),
+ mDateNavigator, TQT_SLOT( selectMonth(int) ) );
+ connect( mNavigatorBar, TQT_SIGNAL( yearSelected(int)),
+ mDateNavigator, TQT_SLOT(selectYear(int)) );
+
+
+ // Signals emited by mDateNavigatorContainer
+ connect( mDateNavigatorContainer, TQT_SIGNAL( weekClicked( const TQDate & ) ),
+ this, TQT_SLOT( selectWeek( const TQDate & ) ) );
+ connect( mDateNavigatorContainer, TQT_SIGNAL( prevMonthClicked(const TQDate &, const TQDate &, const TQDate &) ),
+ mDateNavigator, TQT_SLOT( selectPreviousMonth(const TQDate &, const TQDate &, const TQDate &) ) );
+ connect( mDateNavigatorContainer, TQT_SIGNAL( nextMonthClicked(const TQDate &, const TQDate &, const TQDate &) ),
+ mDateNavigator, TQT_SLOT( selectNextMonth(const TQDate &, const TQDate &, const TQDate &) ) );
+ connect( mDateNavigatorContainer, TQT_SIGNAL( prevYearClicked() ),
+ mDateNavigator, TQT_SLOT( selectPreviousYear() ) );
+ connect( mDateNavigatorContainer, TQT_SIGNAL( nextYearClicked() ),
+ mDateNavigator, TQT_SLOT( selectNextYear() ) );
+ connect( mDateNavigatorContainer, TQT_SIGNAL( monthSelected(int) ),
+ mDateNavigator, TQT_SLOT( selectMonth(int) ) );
+ connect( mDateNavigatorContainer, TQT_SIGNAL(yearSelected(int)),
+ mDateNavigator, TQT_SLOT(selectYear(int)) );
+ connect( mDateNavigatorContainer, TQT_SIGNAL( goPrevious() ),
+ mDateNavigator, TQT_SLOT( selectPrevious() ) );
+ connect( mDateNavigatorContainer, TQT_SIGNAL( goNext() ),
+ mDateNavigator, TQT_SLOT( selectNext() ) );
+
+ connect( mDateNavigatorContainer, TQT_SIGNAL( datesSelected( const KCal::DateList & ) ),
mDateNavigator, TQT_SLOT( selectDates( const KCal::DateList & ) ) );
- connect( mNavigatorBar, TQT_SIGNAL( goPrevYear() ),
- mNavigator, TQT_SLOT( selectPreviousYear() ) );
- connect( mNavigatorBar, TQT_SIGNAL( goNextYear() ),
- mNavigator, TQT_SLOT( selectNextYear() ) );
- connect( mNavigatorBar, TQT_SIGNAL( goPrevMonth() ),
- mNavigator, TQT_SLOT( selectPreviousMonth() ) );
- connect( mNavigatorBar, TQT_SIGNAL( goNextMonth() ),
- mNavigator, TQT_SLOT( selectNextMonth() ) );
- connect( mNavigatorBar, TQT_SIGNAL( goMonth(int) ),
- mNavigator, TQT_SLOT( selectMonth(int) ) );
-
- connect( mNavigator, TQT_SIGNAL( datesSelected( const KCal::DateList & ) ),
- mNavigatorBar, TQT_SLOT( selectDates( const KCal::DateList & ) ) );
-
- connect( mDateNavigator, TQT_SIGNAL( weekClicked( const TQDate & ) ),
- mNavigator, TQT_SLOT( selectWeek( const TQDate & ) ) );
-
- connect( mDateNavigator, TQT_SIGNAL( goPrevYear() ),
- mNavigator, TQT_SLOT( selectPreviousYear() ) );
- connect( mDateNavigator, TQT_SIGNAL( goNextYear() ),
- mNavigator, TQT_SLOT( selectNextYear() ) );
- connect( mDateNavigator, TQT_SIGNAL( goPrevMonth() ),
- mNavigator, TQT_SLOT( selectPreviousMonth() ) );
- connect( mDateNavigator, TQT_SIGNAL( goNextMonth() ),
- mNavigator, TQT_SLOT( selectNextMonth() ) );
- connect( mDateNavigator, TQT_SIGNAL( goMonth(int) ),
- mNavigator, TQT_SLOT( selectMonth(int) ) );
-
- connect( mDateNavigator, TQT_SIGNAL( goPrevious() ),
- mNavigator, TQT_SLOT( selectPrevious() ) );
- connect( mDateNavigator, TQT_SIGNAL( goNext() ),
- mNavigator, TQT_SLOT( selectNext() ) );
-
- connect( mDateNavigator, TQT_SIGNAL( datesSelected( const KCal::DateList & ) ),
- mNavigator, TQT_SLOT( selectDates( const KCal::DateList & ) ) );
-
- connect( mDateNavigator, TQT_SIGNAL(incidenceDropped(Incidence*, const TQDate&)),
+ connect( mDateNavigatorContainer, TQT_SIGNAL(incidenceDropped(Incidence*, const TQDate&)),
TQT_SLOT( addIncidenceOn( Incidence *, const TQDate & ) ) );
- connect( mDateNavigator, TQT_SIGNAL(incidenceDroppedMove(Incidence*,const TQDate&)),
+ connect( mDateNavigatorContainer, TQT_SIGNAL(incidenceDroppedMove(Incidence*,const TQDate&)),
TQT_SLOT( moveIncidenceTo( Incidence *, const TQDate & ) ) );
connect( mDateChecker, TQT_SIGNAL( dayPassed( const TQDate & ) ),
@@ -249,13 +251,13 @@ CalendarView::CalendarView( TQWidget *parent, const char *name )
connect( mDateChecker, TQT_SIGNAL( dayPassed( const TQDate & ) ),
TQT_SIGNAL( dayPassed( const TQDate & ) ) );
connect( mDateChecker, TQT_SIGNAL( dayPassed( const TQDate & ) ),
- mDateNavigator, TQT_SLOT( updateToday() ) );
+ mDateNavigatorContainer, TQT_SLOT( updateToday() ) );
connect( this, TQT_SIGNAL( configChanged() ),
- mDateNavigator, TQT_SLOT( updateConfig() ) );
+ mDateNavigatorContainer, TQT_SLOT( updateConfig() ) );
- connect( this, TQT_SIGNAL( incidenceSelected(Incidence *) ),
- mEventViewer, TQT_SLOT ( setIncidence (Incidence *) ) );
+ connect( this, TQT_SIGNAL( incidenceSelected(Incidence *, const TQDate &) ),
+ mEventViewer, TQT_SLOT ( setIncidence (Incidence *, const TQDate &) ) );
//TODO: do a pretty Summary,
TQString s;
@@ -267,7 +269,7 @@ CalendarView::CalendarView( TQWidget *parent, const char *name )
TQWhatsThis::add( mEventViewer,
i18n( "View the details of events, journal entries or to-dos "
"selected in KOrganizer's main view here." ) );
- mEventViewer->setIncidence( 0 );
+ mEventViewer->setIncidence( 0, TQDate() );
mViewManager->connectTodoView( mTodoList );
mViewManager->connectView( mTodoList );
@@ -278,10 +280,10 @@ CalendarView::CalendarView( TQWidget *parent, const char *name )
connect( TQApplication::clipboard(), TQT_SIGNAL( dataChanged() ),
TQT_SLOT( checkClipboard() ) );
- connect( mTodoList, TQT_SIGNAL( incidenceSelected( Incidence * ) ),
- TQT_SLOT( processTodoListSelection( Incidence * ) ) );
- disconnect( mTodoList, TQT_SIGNAL( incidenceSelected( Incidence * ) ),
- this, TQT_SLOT( processMainViewSelection( Incidence * ) ) );
+ connect( mTodoList, TQT_SIGNAL( incidenceSelected( Incidence *,const TQDate & ) ),
+ TQT_SLOT( processTodoListSelection( Incidence *,const TQDate & ) ) );
+ disconnect( mTodoList, TQT_SIGNAL( incidenceSelected( Incidence *,const TQDate & ) ),
+ this, TQT_SLOT( processMainViewSelection( Incidence *,const TQDate & ) ) );
kdDebug(5850) << "CalendarView::CalendarView() done" << endl;
}
@@ -313,9 +315,11 @@ void CalendarView::setCalendar( Calendar *cal )
mCalendar->registerObserver( this );
- mDateNavigator->setCalendar( mCalendar );
+ mDateNavigatorContainer->setCalendar( mCalendar );
mTodoList->setCalendar( mCalendar );
+
+ mEventViewer->setCalendar( mCalendar );
}
void CalendarView::setIncidenceChanger( IncidenceChangerBase *changer )
@@ -324,10 +328,8 @@ void CalendarView::setIncidenceChanger( IncidenceChangerBase *changer )
emit newIncidenceChanger( mChanger );
connect( mChanger, TQT_SIGNAL( incidenceAdded( Incidence* ) ),
this, TQT_SLOT( incidenceAdded( Incidence* ) ) );
- connect( mChanger, TQT_SIGNAL( incidenceChanged( Incidence*, Incidence*, int ) ),
- this, TQT_SLOT( incidenceChanged( Incidence*, Incidence*, int ) ) );
- connect( mChanger, TQT_SIGNAL( incidenceChanged( Incidence*, Incidence* ) ),
- this, TQT_SLOT( incidenceChanged( Incidence*, Incidence* ) ) );
+ connect( mChanger, TQT_SIGNAL( incidenceChanged( Incidence*, Incidence*, KOGlobals::WhatChanged ) ),
+ this, TQT_SLOT( incidenceChanged( Incidence*, Incidence*, KOGlobals::WhatChanged ) ) );
connect( mChanger, TQT_SIGNAL( incidenceToBeDeleted( Incidence * ) ),
this, TQT_SLOT( incidenceToBeDeleted( Incidence * ) ) );
connect( mChanger, TQT_SIGNAL( incidenceDeleted( Incidence * ) ),
@@ -347,6 +349,19 @@ Calendar *CalendarView::calendar()
else return CalendarNull::self();
}
+QPair<ResourceCalendar *, TQString> CalendarView::viewSubResourceCalendar()
+{
+ QPair<ResourceCalendar *, TQString> p( 0, TQString() );
+ KOrg::BaseView *cV = mViewManager->currentView();
+ if ( cV && cV == mViewManager->multiAgendaView() ) {
+ cV = mViewManager->multiAgendaView()->selectedAgendaView();
+ }
+ if ( cV ) {
+ p = qMakePair( cV->resourceCalendar(), cV->subResourceCalendar() );
+ }
+ return p;
+}
+
KOIncidenceEditor *CalendarView::editorDialog( Incidence *incidence ) const
{
if (mDialogList.find(incidence) != mDialogList.end ())
@@ -354,16 +369,53 @@ KOIncidenceEditor *CalendarView::editorDialog( Incidence *incidence ) const
else return 0;
}
+TQDate CalendarView::activeDate( bool fallbackToToday )
+{
+ KOrg::BaseView *curView = mViewManager->currentView();
+ if ( curView ) {
+ if ( curView->selectionStart().isValid() ) {
+ return curView->selectionStart().date();
+ }
+
+ // Try the view's selectedDates()
+ if ( !curView->selectedIncidenceDates().isEmpty() ) {
+ if ( curView->selectedIncidenceDates().first().isValid() ) {
+ return curView->selectedIncidenceDates().first();
+ }
+ }
+ }
+
+ // When all else fails, use the navigator start date, or today.
+ if ( fallbackToToday ) {
+ return TQDate::currentDate();
+ } else {
+ return mDateNavigator->selectedDates().first();
+ }
+}
+
+TQDate CalendarView::activeIncidenceDate()
+{
+ KOrg::BaseView *curView = mViewManager->currentView();
+ if ( curView ) {
+ DateList dates = curView->selectedIncidenceDates();
+ if ( !dates.isEmpty() ) {
+ return dates.first();
+ }
+ }
+
+ return TQDate();
+}
+
TQDate CalendarView::startDate()
{
- DateList dates = mNavigator->selectedDates();
+ DateList dates = mDateNavigator->selectedDates();
return dates.first();
}
TQDate CalendarView::endDate()
{
- DateList dates = mNavigator->selectedDates();
+ DateList dates = mDateNavigator->selectedDates();
return dates.last();
}
@@ -397,6 +449,23 @@ bool CalendarView::openCalendar(const TQString& filename, bool merge)
}
} else {
// merge in a file
+ CalendarResources *cl = dynamic_cast<CalendarResources *>( mCalendar );
+ if ( cl && !cl->hasCalendarResources() ) {
+ KMessageBox::sorry(
+ this,
+ i18n( "No calendars found, unable to merge the file into your calendar." ) );
+ return false;
+ }
+ // FIXME: This is a nasty hack, since we need to set a parent for the
+ // resource selection dialog. However, we don't have any UI methods
+ // in the calendar, only in the CalendarResources::DestinationPolicy
+ // So we need to type-cast it and extract it from the CalendarResources
+ TQWidget *tmpparent = 0;
+ if ( cl ) {
+ tmpparent = cl->dialogParentWidget();
+ cl->setDialogParentWidget( this );
+ }
+
FileStorage storage( mCalendar );
storage.setFileName( filename );
loadedSuccesfully = storage.load();
@@ -478,7 +547,7 @@ void CalendarView::readSettings()
TQValueList<int> sizes = config->readIntListEntry( "Separator1" );
if ( sizes.count() != 2 ) {
- sizes << mDateNavigator->minimumSizeHint().width();
+ sizes << mDateNavigatorContainer->minimumSizeHint().width();
sizes << 300;
}
mPanner->setSizes( sizes );
@@ -495,9 +564,12 @@ void CalendarView::readSettings()
readFilterSettings( config );
config->setGroup( "Views" );
- int dateCount = config->readNumEntry( "ShownDatesCount", 7 );
- if ( dateCount == 7 ) mNavigator->selectWeek();
- else mNavigator->selectDates( mNavigator->selectedDates().first(), dateCount );
+ const int dateCount = config->readNumEntry( "ShownDatesCount", 7 );
+ if ( dateCount == 7 ) {
+ mDateNavigator->selectWeek();
+ } else {
+ mDateNavigator->selectDates( mDateNavigator->selectedDates().first(), dateCount );
+ }
}
@@ -525,7 +597,7 @@ void CalendarView::writeSettings()
writeFilterSettings( config );
config->setGroup( "Views" );
- config->writeEntry( "ShownDatesCount", mNavigator->selectedDates().count() );
+ config->writeEntry( "ShownDatesCount", mDateNavigator->selectedDates().count() );
config->sync();
}
@@ -593,39 +665,42 @@ void CalendarView::writeFilterSettings( KConfig *config )
}
-void CalendarView::goDate( const TQDate& date )
+void CalendarView::goDate( const TQDate &date )
{
- mNavigator->selectDate( date );
+ mDateNavigator->selectDate( date );
}
-void CalendarView::showDate(const TQDate & date)
+void CalendarView::showDate( const TQDate &date )
{
- int dateCount = mNavigator->datesCount();
- if ( dateCount == 7 )
- mNavigator->selectWeek( date );
- else
- mNavigator->selectDates( date, dateCount );
+ int dateCount = mDateNavigator->datesCount();
+ if ( dateCount == 7 ) {
+ mDateNavigator->selectWeek( date );
+ } else {
+ mDateNavigator->selectDates( date, dateCount );
+ }
}
void CalendarView::goToday()
{
- mNavigator->selectToday();
+ mDateNavigator->selectToday();
}
void CalendarView::goNext()
{
- if ( dynamic_cast<KOMonthView*>( mViewManager->currentView() ) )
- mNavigator->selectNextMonth();
- else
- mNavigator->selectNext();
+ if ( dynamic_cast<KOMonthView*>( mViewManager->currentView() ) ) {
+ mDateNavigator->selectNextMonth();
+ } else {
+ mDateNavigator->selectNext();
+ }
}
void CalendarView::goPrevious()
{
- if ( dynamic_cast<KOMonthView*>( mViewManager->currentView() ) )
- mNavigator->selectPreviousMonth();
- else
- mNavigator->selectPrevious();
+ if ( dynamic_cast<KOMonthView*>( mViewManager->currentView() ) ) {
+ mDateNavigator->selectPreviousMonth();
+ } else {
+ mDateNavigator->selectPrevious();
+ }
}
void CalendarView::updateConfig( const TQCString& receiver)
@@ -660,16 +735,8 @@ void CalendarView::updateConfig( const TQCString& receiver)
}
emit configChanged();
- // force reload and handle agenda view type switch
- const bool showMerged = KOPrefs::instance()->agendaViewCalendarDisplay() == KOPrefs::CalendarsMerged;
- const bool showSideBySide = KOPrefs::instance()->agendaViewCalendarDisplay() == KOPrefs::CalendarsSideBySide;
- KOrg::BaseView *view = mViewManager->currentView();
- mViewManager->showAgendaView();
- if ( view == mViewManager->agendaView() && showSideBySide )
- view = mViewManager->multiAgendaView();
- else if ( view == mViewManager->multiAgendaView() && showMerged )
- view = mViewManager->agendaView();
- mViewManager->showView( view );
+ //switch beetween merged, side by side and tabbed agenda if needed
+ mViewManager->updateMultiCalendarDisplay();
// To make the "fill window" configurations work
mViewManager->raiseCurrentView();
@@ -686,19 +753,13 @@ void CalendarView::incidenceAdded( Incidence *incidence )
}
void CalendarView::incidenceChanged( Incidence *oldIncidence,
- Incidence *newIncidence )
-{
- incidenceChanged( oldIncidence, newIncidence, KOGlobals::UNKNOWN_MODIFIED );
-}
-
-void CalendarView::incidenceChanged( Incidence *oldIncidence,
- Incidence *newIncidence, int what )
+ Incidence *newIncidence,
+ KOGlobals::WhatChanged modification )
{
- // FIXME: Make use of the what flag, which indicates which parts of the incidence have changed!
KOIncidenceEditor *tmp = editorDialog( newIncidence );
if ( tmp ) {
kdDebug(5850) << "Incidence modified and open" << endl;
- tmp->modified( what );
+ tmp->modified();
}
setModified( true );
history()->recordEdit( oldIncidence, newIncidence );
@@ -706,14 +767,14 @@ void CalendarView::incidenceChanged( Incidence *oldIncidence,
// Record completed todos in journals, if enabled. we should to this here in
// favour of the todolist. users can mark a task as completed in an editor
// as well.
- if ( newIncidence->type() == "Todo"
- && KOPrefs::instance()->recordTodosInJournals()
- && ( what == KOGlobals::COMPLETION_MODIFIED
- || what == KOGlobals::COMPLETION_MODIFIED_WITH_RECURRENCE ) ) {
+ if ( newIncidence->type() == "Todo" &&
+ KOPrefs::instance()->recordTodosInJournals() &&
+ ( modification == KOGlobals::COMPLETION_MODIFIED ||
+ modification == KOGlobals::COMPLETION_MODIFIED_WITH_RECURRENCE ) ) {
Todo *todo = static_cast<Todo *>(newIncidence);
- if ( todo->isCompleted()
- || what == KOGlobals::COMPLETION_MODIFIED_WITH_RECURRENCE ) {
+ if ( todo->isCompleted() ||
+ modification == KOGlobals::COMPLETION_MODIFIED_WITH_RECURRENCE ) {
TQString timeStr = KGlobal::locale()->formatTime( TQTime::currentTime() );
TQString description = i18n( "To-do completed: %1 (%2)" ).arg(
newIncidence->summary() ).arg( timeStr );
@@ -729,7 +790,8 @@ void CalendarView::incidenceChanged( Incidence *oldIncidence,
journal->setSummary( i18n("Journal of %1").arg( dateStr ) );
journal->setDescription( description );
- if ( !mChanger->addIncidence( journal, this ) ) {
+ //TODO: recorded to-dos should save into the standard resource always
+ if ( !mChanger->addIncidence( journal, 0, TQString(), this ) ) {
KODialogManager::errorSaveIncidence( this, journal );
delete journal;
return;
@@ -740,7 +802,8 @@ void CalendarView::incidenceChanged( Incidence *oldIncidence,
Journal *oldJournal = journal->clone();
journal->setDescription( journal->description().append( "\n" + description ) );
- if ( !mChanger->changeIncidence( oldJournal, journal ) ) {
+ if ( !mChanger->changeIncidence( oldJournal, journal,
+ KOGlobals::DESCRIPTION_MODIFIED, this ) ) {
KODialogManager::errorSaveIncidence( this, journal );
delete journal;
return;
@@ -799,14 +862,14 @@ void CalendarView::endMultiModify()
void CalendarView::changeIncidenceDisplay( Incidence *incidence, int action )
{
- mDateNavigator->updateView();
+ mDateNavigatorContainer->updateView();
mDialogManager->updateSearchDialog();
if ( incidence ) {
// If there is an event view visible update the display
mViewManager->currentView()->changeIncidenceDisplay( incidence, action );
if ( mTodoList ) mTodoList->changeIncidenceDisplay( incidence, action );
- mEventViewer->changeIncidenceDisplay( incidence, action );
+ mEventViewer->changeIncidenceDisplay( incidence, activeDate( true ), action );
} else {
mViewManager->currentView()->updateView();
if ( mTodoList ) mTodoList->updateView();
@@ -818,12 +881,12 @@ void CalendarView::updateView(const TQDate &start, const TQDate &end)
{
mTodoList->updateView();
mViewManager->updateView(start, end);
- mDateNavigator->updateView();
+ mDateNavigatorContainer->updateView();
}
void CalendarView::updateView()
{
- DateList tmpList = mNavigator->selectedDates();
+ DateList tmpList = mDateNavigator->selectedDates();
// We assume that the navigator only selects consecutive days.
updateView( tmpList.first(), tmpList.last() );
@@ -831,7 +894,7 @@ void CalendarView::updateView()
void CalendarView::updateUnmanagedViews()
{
- mDateNavigator->updateDayMatrix();
+ mDateNavigatorContainer->updateDayMatrix();
updateView();
}
@@ -845,83 +908,205 @@ int CalendarView::msgItemDelete( Incidence *incidence )
void CalendarView::edit_cut()
{
- Incidence *incidence = selectedIncidence();
+ Incidence *incidence = incToSendToClipboard( true );
if ( !incidence || !mChanger ) {
KNotifyClient::beep();
return;
}
- mChanger->cutIncidence( incidence );
+
+ Incidence::List incidences;
+ int km = KMessageBox::Yes;
+
+ if ( !incidence->relations().isEmpty() &&
+ incidence->type() == "Todo" ) { // Only todos (yet?)
+ km = KMessageBox::questionYesNoCancel( this,
+ i18n("The item \"%1\" has sub-to-dos. "
+ "Do you want to cut just this item and "
+ "make all its sub-to-dos independent, or "
+ "cut the to-do with all its sub-to-dos?"
+ ).arg( incidence->summary() ),
+ i18n("KOrganizer Confirmation"),
+ i18n("Cut Only This"),
+ i18n("Cut All"));
+ }
+
+ if ( km == KMessageBox::Yes ) { // only one
+ incidences.append( incidence );
+ makeChildrenIndependent( incidence );
+ } else if ( km == KMessageBox::No ) { // all
+ // load incidence + children + grandchildren...
+ getIncidenceHierarchy( incidence, incidences );
+ }
+
+ if ( km != KMessageBox::Cancel ) {
+ mChanger->cutIncidences( incidences, this );
+ }
}
void CalendarView::edit_copy()
{
- Incidence *incidence = selectedIncidence();
+ Incidence *incidence = incToSendToClipboard( false );
- if (!incidence) {
+ if ( !incidence ) {
KNotifyClient::beep();
return;
}
- DndFactory factory( mCalendar );
- if ( !factory.copyIncidence( incidence ) ) {
- KNotifyClient::beep();
+
+ Incidence::List incidences;
+ int km = KMessageBox::Yes;
+
+ if ( !incidence->relations().isEmpty() &&
+ incidence->type() == "Todo" ) { // only todos.
+ km = KMessageBox::questionYesNoCancel( this,
+ i18n("The item \"%1\" has sub-to-dos. "
+ "Do you want to copy just this item or "
+ "copy the to-do with all its sub-to-dos?"
+ ).arg( incidence->summary() ),
+ i18n("KOrganizer Confirmation"),
+ i18n("Copy Only This"),
+ i18n("Copy All"));
+ }
+
+ if ( km == KMessageBox::Yes ) { // only one
+ incidences.append( incidence );
+ } else if ( km == KMessageBox::No ) { // all
+ // load incidence + children + grandchildren...
+ getIncidenceHierarchy( incidence, incidences );
+ }
+
+ if ( km != KMessageBox::Cancel ) {
+ DndFactory factory( mCalendar );
+ if ( !factory.copyIncidences( incidences ) ) {
+ KNotifyClient::beep();
+ }
+ }
+}
+
+Incidence* CalendarView::incToSendToClipboard( bool cut )
+{
+ Incidence *originalInc = selectedIncidence();
+
+ if ( originalInc && originalInc->doesRecur() &&
+ originalInc->type() == "Event" ) { // temporary, until recurring to-dos are fixed
+
+ Incidence *inc;
+ KOGlobals::WhichOccurrences chosenOption;
+ if ( cut ) {
+ inc = singleOccurrenceOrAll( originalInc, KOGlobals::CUT, chosenOption, TQDate(), true );
+ } else {
+ // The user is copying, the original incidence can't be changed
+ // we can only dissociate a copy
+ Incidence *originalIncSaved = originalInc->clone();
+ inc = singleOccurrenceOrAll( originalIncSaved, KOGlobals::COPY, chosenOption, TQDate(), false );
+
+ // no dissociation, no need to leak our clone
+ if ( chosenOption == KOGlobals::ALL ) {
+ inc = originalInc;
+ delete originalIncSaved;
+ }
+
+ // no need to leak our clone
+ if ( chosenOption == KOGlobals::NONE ) {
+ delete originalIncSaved;
+ }
+ }
+
+ return inc;
+ } else {
+ return originalInc;
}
}
void CalendarView::edit_paste()
{
-// If in agenda view, use the selected time and date from there.
-// In all other cases, paste the event on the first day of the
-// selection in the day matrix on the left
+// If in agenda and month view, use the selected time and date from there.
+// In all other cases, use the navigator's selected date.
- TQDate date;
- // create an invalid time to check if we got a new time for the eevent
- TQTime time(-1,-1);
- TQDateTime startDT, endDT;
+ TQDate date; // null dates are invalid, that's what we want
+ bool timeSet = false;// flag denoting if the time has been set.
+ TQTime time; // null dates are valid, so rely on the timeSet flag
+ TQDateTime endDT; // null datetimes are invalid, that's what we want
bool useEndTime = false;
+ KOrg::BaseView *curView = mViewManager->currentView();
+
KOAgendaView *aView = mViewManager->agendaView();
- if (aView && aView->selectionStart().isValid()) {
- date = aView->selectionStart().date();
- startDT = aView->selectionStart();
+ KOMonthView *mView = mViewManager->monthView();
+ if ( curView == mViewManager->multiAgendaView() ) {
+ aView = mViewManager->multiAgendaView()->selectedAgendaView();
+ curView = aView;
+ }
+
+ if ( !curView ) {
+ return;
+ }
+
+ if ( curView == aView && aView->selectionStart().isValid() ) {
+ date = aView->selectionStart().date();
endDT = aView->selectionEnd();
useEndTime = !aView->selectedIsSingleCell();
- if (!aView->selectedIsAllDay()) {
- time = aView->selectionStart().time();
+ if ( !aView->selectedIsAllDay() ) {
+ time = aView->selectionStart().time();
+ timeSet = true;
}
+ } else if ( curView == mView && mView->selectionStart().isValid() ) {
+ date = mView->selectionStart().date();
+ } else if ( !mDateNavigator->selectedDates().isEmpty() &&
+ curView->supportsDateNavigation() ) {
+ // default to the selected date from the navigator
+ date = mDateNavigator->selectedDates().first();
+ }
+
+ if ( !date.isValid() && curView->supportsDateNavigation() ) {
+ KMessageBox::sorry(
+ this,
+ i18n( "Paste failed: unable to determine a valid target date." ) );
+ return;
+ }
+ DndFactory factory( mCalendar );
+ Incidence::List pastedIncidences;
+ if ( timeSet && time.isValid() ) {
+ pastedIncidences = factory.pasteIncidences( date, &time );
} else {
- date = mNavigator->selectedDates().first();
+ pastedIncidences = factory.pasteIncidences( date );
}
- DndFactory factory( mCalendar );
- Incidence *pastedIncidence;
- if (time.isValid())
- pastedIncidence = factory.pasteIncidence( date, &time );
- else
- pastedIncidence = factory.pasteIncidence( date );
- if ( !pastedIncidence ) return;
-
- // FIXME: use a visitor here
- if (pastedIncidence->type() == "Event" ) {
-
- Event* pastedEvent = static_cast<Event*>(pastedIncidence);
- // only use selected area if event is of the same type (all-day or non-all-day
- // as the current selection is
- if ( aView && endDT.isValid() && useEndTime ) {
- if ( (pastedEvent->doesFloat() && aView->selectedIsAllDay()) ||
- (!pastedEvent->doesFloat() && ! aView->selectedIsAllDay()) ) {
- pastedEvent->setDtEnd(endDT);
+ Incidence::List::Iterator it;
+ for ( it = pastedIncidences.begin(); it != pastedIncidences.end(); ++it ) {
+ QPair<ResourceCalendar *, TQString>p = viewSubResourceCalendar();
+
+ // FIXME: use a visitor here
+ if ( ( *it )->type() == "Event" ) {
+ Event *pastedEvent = static_cast<Event*>( *it );
+ // only use selected area if event is of the same type
+ // (all-day or non-all-day) as the current selection is
+ if ( aView && endDT.isValid() && useEndTime ) {
+ if ( ( pastedEvent->doesFloat() && aView->selectedIsAllDay() ) ||
+ ( !pastedEvent->doesFloat() && !aView->selectedIsAllDay() ) ) {
+ pastedEvent->setDtEnd( endDT );
+ }
}
- }
- mChanger->addIncidence( pastedEvent, this );
- } else if ( pastedIncidence->type() == "Todo" ) {
- Todo* pastedTodo = static_cast<Todo*>(pastedIncidence);
- Todo* _selectedTodo = selectedTodo();
- if ( _selectedTodo )
- pastedTodo->setRelatedTo( _selectedTodo );
- mChanger->addIncidence( pastedTodo, this );
+ // KCal supports events with relations, but korganizer doesn't
+ // so unset it. It can even come from other application.
+ pastedEvent->setRelatedTo( 0 );
+ pastedEvent->setRelatedToUid( TQString() );
+
+ mChanger->addIncidence( pastedEvent, p.first, p.second, this );
+
+ } else if ( ( *it )->type() == "Todo" ) {
+ Todo *pastedTodo = static_cast<Todo*>( *it );
+ Todo *_selectedTodo = selectedTodo();
+
+ // if we are cutting a hierarchy only the root
+ // should be son of _selectedTodo
+ if ( _selectedTodo && !pastedTodo->relatedTo() ) {
+ pastedTodo->setRelatedTo( _selectedTodo );
+ }
+ mChanger->addIncidence( pastedTodo, p.first, p.second, this );
+ }
}
}
@@ -932,26 +1117,22 @@ void CalendarView::edit_options()
void CalendarView::dateTimesForNewEvent( TQDateTime &startDt, TQDateTime &endDt, bool &allDay )
{
- if ( !startDt.isValid() ) {
- // Default start is the first selected date with the preferred time as set
- // in the config dlg.
- if ( !startDt.date().isValid() ) {
- startDt.setDate( mNavigator->selectedDates().first() );
- }
- if ( !startDt.time().isValid() ) {
- startDt.setTime( KOPrefs::instance()->mStartTime.time() );
- }
- }
- if ( !endDt.isValid() ) {
- int addSecs = ( KOPrefs::instance()->mDefaultDuration.time().hour()*3600 ) +
- ( KOPrefs::instance()->mDefaultDuration.time().minute()*60 );
+ mViewManager->currentView()->eventDurationHint( startDt, endDt, allDay );
+
+ if ( !startDt.isValid() || !endDt.isValid() ) {
+ startDt.setDate( activeDate( true ) );
+ startDt.setTime( KOPrefs::instance()->mStartTime.time() );
+
+ int addSecs = ( KOPrefs::instance()->mDefaultDuration.time().hour() * 3600 ) +
+ ( KOPrefs::instance()->mDefaultDuration.time().minute() * 60 );
+
endDt = startDt.addSecs( addSecs );
}
- mViewManager->currentView()->eventDurationHint( startDt, endDt, allDay );
}
-KOEventEditor *CalendarView::newEventEditor( const TQDateTime &startDtParam,
- const TQDateTime &endDtParam, bool allDayParam)
+KOEventEditor *CalendarView::newEventEditor( ResourceCalendar *res, const TQString &subRes,
+ const TQDateTime &startDtParam,
+ const TQDateTime &endDtParam, bool allDayParam )
{
// let the current view change the default start/end datetime
bool allDay = allDayParam;
@@ -963,111 +1144,164 @@ KOEventEditor *CalendarView::newEventEditor( const TQDateTime &startDtParam,
KOEventEditor *eventEditor = mDialogManager->getEventEditor();
eventEditor->newEvent();
connectIncidenceEditor( eventEditor );
+ eventEditor->setResource( res, subRes );
eventEditor->setDates( startDt, endDt, allDay );
mDialogManager->connectTypeAhead( eventEditor, dynamic_cast<KOrg::AgendaView*>(viewManager()->currentView()) );
return eventEditor;
}
+void CalendarView::newEvent()
+{
+ KOrg::BaseView *currentView = mViewManager->currentView();
+ if ( currentView == mViewManager->multiAgendaView() ) {
+ currentView = mViewManager->multiAgendaView()->selectedAgendaView();
+ }
+ if ( currentView ) {
+ newEvent( currentView->resourceCalendar(),
+ currentView->subResourceCalendar() );
+ }
+}
-void CalendarView::newEvent()
+void CalendarView::newEvent( ResourceCalendar *res, const TQString &subRes )
{
kdDebug(5850) << "CalendarView::newEvent()" << endl;
- newEvent( TQDateTime(), TQDateTime() );
+ newEvent( res, subRes, TQDateTime(), TQDateTime() );
}
-void CalendarView::newEvent( const TQDate &dt )
+void CalendarView::newEvent( ResourceCalendar *res, const TQString &subRes,
+ const TQDate &dt )
{
TQDateTime startDt( dt, KOPrefs::instance()->mStartTime.time() );
- return newEvent( TQDateTime( dt ), TQDateTime() );
+ newEvent( res, subRes, TQDateTime( dt ), TQDateTime() );
}
-void CalendarView::newEvent( const TQDateTime &startDt )
+void CalendarView::newEvent( ResourceCalendar *res, const TQString &subRes,
+ const TQDateTime &startDt )
{
- return newEvent( startDt, TQDateTime() );
+ newEvent( res, subRes, startDt, TQDateTime() );
}
-void CalendarView::newEvent( const TQDateTime &startDt, const TQDateTime &endDt,
+void CalendarView::newEvent( ResourceCalendar *res, const TQString &subRes,
+ const TQDateTime &startDt, const TQDateTime &endDt,
bool allDay )
{
- KOEventEditor *eventEditor = newEventEditor( startDt, endDt, allDay );
+ KOEventEditor *eventEditor = newEventEditor( res, subRes,
+ startDt, endDt, allDay );
eventEditor->show();
}
-void CalendarView::newEvent( const TQString &summary, const TQString &description,
+void CalendarView::newEvent( ResourceCalendar *res, const TQString &subRes,
+ const TQString &summary, const TQString &description,
const TQStringList &attachments, const TQStringList &attendees,
const TQStringList &attachmentMimetypes, bool inlineAttachment )
{
- KOEventEditor *eventEditor = newEventEditor();
+ KOEventEditor *eventEditor = newEventEditor( res, subRes );
eventEditor->setTexts( summary, description );
// if attach or attendee list is empty, these methods don't do anything, so
- // it's save to call them in every case
+ // it's safe to call them in every case
eventEditor->addAttachments( attachments, attachmentMimetypes, inlineAttachment );
eventEditor->addAttendees( attendees );
eventEditor->show();
}
-void CalendarView::newTodo( const TQString &summary, const TQString &description,
+void CalendarView::newTodo( ResourceCalendar *res, const TQString &subRes,
+ const TQString &summary, const TQString &description,
const TQStringList &attachments, const TQStringList &attendees,
- const TQStringList &attachmentMimetypes, bool inlineAttachment )
+ const TQStringList &attachmentMimetypes,
+ bool inlineAttachment, bool isTask )
{
kdDebug(5850) << k_funcinfo << endl;
KOTodoEditor *todoEditor = mDialogManager->getTodoEditor();
connectIncidenceEditor( todoEditor );
todoEditor->newTodo();
+ todoEditor->setResource( res, subRes );
todoEditor->setTexts( summary, description );
todoEditor->addAttachments( attachments, attachmentMimetypes, inlineAttachment );
todoEditor->addAttendees( attendees );
+ todoEditor->selectCreateTask( isTask );
todoEditor->show();
}
void CalendarView::newTodo()
{
+ KOrg::BaseView *currentView = mViewManager->currentView();
+
+ if ( currentView == mViewManager->multiAgendaView() ) {
+ currentView = mViewManager->multiAgendaView()->selectedAgendaView();
+ }
+ if ( currentView ) {
+ newTodo( currentView->resourceCalendar(),
+ currentView->subResourceCalendar() );
+ }
+}
+
+void CalendarView::newTodo( ResourceCalendar *res, const TQString &subRes )
+{
kdDebug(5850) << k_funcinfo << endl;
TQDateTime dtDue;
bool allday = true;
KOTodoEditor *todoEditor = mDialogManager->getTodoEditor();
connectIncidenceEditor( todoEditor );
todoEditor->newTodo();
+ todoEditor->setResource( res, subRes );
if ( mViewManager->currentView()->isEventView() ) {
- dtDue.setDate( mNavigator->selectedDates().first() );
+ dtDue.setDate( mDateNavigator->selectedDates().first() );
TQDateTime dtDummy = TQDateTime::currentDateTime();
- mViewManager->currentView()->
- eventDurationHint( dtDue, dtDummy, allday );
+ mViewManager->currentView()->eventDurationHint( dtDue, dtDummy, allday );
todoEditor->setDates( dtDue, allday );
}
todoEditor->show();
}
-void CalendarView::newTodo( const TQDate &date )
+void CalendarView::newTodo( ResourceCalendar *res, const TQString &subRes,
+ const TQDate &date )
{
KOTodoEditor *todoEditor = mDialogManager->getTodoEditor();
connectIncidenceEditor( todoEditor );
todoEditor->newTodo();
+ todoEditor->setResource( res, subRes );
todoEditor->setDates( TQDateTime( date, TQTime::currentTime() ), true );
todoEditor->show();
}
void CalendarView::newJournal()
{
+ KOrg::BaseView *currentView = mViewManager->currentView();
+
+ if ( currentView == mViewManager->multiAgendaView() ) {
+ currentView = mViewManager->multiAgendaView()->selectedAgendaView();
+ }
+
+ if ( currentView ) {
+ newJournal( currentView->resourceCalendar(),
+ currentView->subResourceCalendar() );
+ }
+}
+
+void CalendarView::newJournal( ResourceCalendar *res, const TQString &subRes )
+{
kdDebug(5850) << "CalendarView::newJournal()" << endl;
- newJournal( TQString::null, TQDate() );
+ newJournal( res, subRes, TQString::null, TQDate() );
}
-void CalendarView::newJournal( const TQDate &date)
+void CalendarView::newJournal( ResourceCalendar *res, const TQString &subRes,
+ const TQDate &date)
{
- newJournal( TQString::null, date );
+ newJournal( res, subRes, TQString::null, date );
}
-void CalendarView::newJournal( const TQString &text, const TQDate &date )
+void CalendarView::newJournal( ResourceCalendar *res, const TQString &subRes,
+ const TQString &text, const TQDate &date )
{
KOJournalEditor *journalEditor = mDialogManager->getJournalEditor();
connectIncidenceEditor( journalEditor );
journalEditor->newJournal();
+ journalEditor->setResource( res, subRes );
journalEditor->setTexts( text );
if ( !date.isValid() ) {
- journalEditor->setDate( mNavigator->selectedDates().first() );
+ journalEditor->setDate( mDateNavigator->selectedDates().first() );
} else {
journalEditor->setDate( date );
}
@@ -1089,15 +1323,6 @@ void CalendarView::newSubTodo(Todo *parentEvent)
todoEditor->show();
}
-void CalendarView::newFloatingEvent()
-{
- DateList tmpList = mNavigator->selectedDates();
- TQDate date = tmpList.first();
-
- newEvent( TQDateTime( date, TQTime( 12, 0, 0 ) ),
- TQDateTime( date, TQTime( 12, 0, 0 ) ), true );
-}
-
bool CalendarView::addIncidence( const TQString &ical )
{
kdDebug(5850) << "CalendarView::addIncidence:\n" << ical << endl;
@@ -1105,7 +1330,7 @@ bool CalendarView::addIncidence( const TQString &ical )
format.setTimeZone( mCalendar->timeZoneId(), true );
Incidence *incidence = format.fromString( ical );
if ( !incidence ) return false;
- if ( !mChanger->addIncidence( incidence, this ) ) {
+ if ( !mChanger->addIncidence( incidence, 0, TQString(), this ) ) {
delete incidence;
return false;
}
@@ -1115,19 +1340,21 @@ bool CalendarView::addIncidence( const TQString &ical )
void CalendarView::appointment_show()
{
Incidence *incidence = selectedIncidence();
- if (incidence)
- showIncidence( incidence );
- else
+ if ( incidence ) {
+ showIncidence( incidence, activeIncidenceDate() );
+ } else {
KNotifyClient::beep();
+ }
}
void CalendarView::appointment_edit()
{
Incidence *incidence = selectedIncidence();
- if (incidence)
- editIncidence( incidence );
- else
+ if ( incidence ) {
+ editIncidence( incidence, activeIncidenceDate() );
+ } else {
KNotifyClient::beep();
+ }
}
void CalendarView::appointment_delete()
@@ -1142,22 +1369,24 @@ void CalendarView::appointment_delete()
void CalendarView::todo_unsub()
{
Todo *anTodo = selectedTodo();
- if( todo_unsub (anTodo ) ) {
+ if( incidence_unsub ( anTodo ) ) {
updateView();
}
}
-bool CalendarView::todo_unsub( Todo *todo )
+bool CalendarView::incidence_unsub( Incidence *inc )
{
- bool status= false;
- if ( !todo || !todo->relatedTo() ) return false;
+ bool status = false;
+ if ( !inc || !inc->relatedTo() ) {
+ return false;
+ }
- if ( mChanger->beginChange( todo ) ) {
- Todo *oldTodo = todo->clone();
- todo->setRelatedTo(0);
- mChanger->changeIncidence( oldTodo, todo, KOGlobals::RELATION_MODIFIED );
- mChanger->endChange( todo );
- delete oldTodo;
+ if ( mChanger->beginChange( inc, 0, TQString() ) ) {
+ Incidence *oldInc = inc->clone();
+ inc->setRelatedTo( 0 );
+ mChanger->changeIncidence( oldInc, inc, KOGlobals::RELATION_MODIFIED, this );
+ mChanger->endChange( inc, 0, TQString() );
+ delete oldInc;
setModified(true);
status = true;
}
@@ -1169,34 +1398,30 @@ bool CalendarView::todo_unsub( Todo *todo )
return status;
}
-bool CalendarView::makeSubTodosIndependents ( )
+bool CalendarView::makeSubTodosIndependent ( )
{
bool status = false;
- Todo *anTodo = selectedTodo();
+ Todo *aTodo = selectedTodo();
- if( makeSubTodosIndependents( anTodo ) ) {
+ if ( makeChildrenIndependent( aTodo ) ) {
updateView();
status = true;
}
return status;
}
-bool CalendarView::makeSubTodosIndependents ( Todo *todo )
+bool CalendarView::makeChildrenIndependent ( Incidence *inc )
{
- if( !todo || todo->relations().isEmpty() ) return false;
+ if ( !inc || inc->relations().isEmpty() ) {
+ return false;
+ }
startMultiModify ( i18n( "Make sub-to-dos independent" ) );
- Incidence::List subTodos( todo->relations() );
+ Incidence::List subIncs( inc->relations() );
Incidence::List::Iterator it;
- Incidence *aIncidence;
- Todo *aTodo;
- for ( it= subTodos.begin(); it != subTodos.end(); ++it ) {
- aIncidence = *it;
- if( aIncidence && aIncidence->type() == "Todo" ) {
- aTodo = static_cast<Todo*>( aIncidence );
- todo_unsub ( aTodo );
- }
+ for ( it= subIncs.begin(); it != subIncs.end(); ++it ) {
+ incidence_unsub ( *it );
}
endMultiModify();
return true;
@@ -1220,7 +1445,7 @@ void CalendarView::toggleAlarm( Incidence *incidence )
return;
}
Incidence*oldincidence = incidence->clone();
- if ( !mChanger->beginChange( incidence ) ) {
+ if ( !mChanger->beginChange( incidence, 0, TQString() ) ) {
kdDebug(5850) << "Unable to lock incidence " << endl;
delete oldincidence;
return;
@@ -1228,15 +1453,35 @@ void CalendarView::toggleAlarm( Incidence *incidence )
Alarm::List alarms = incidence->alarms();
Alarm::List::ConstIterator it;
- for( it = alarms.begin(); it != alarms.end(); ++it )
+ for ( it = alarms.begin(); it != alarms.end(); ++it ) {
(*it)->toggleAlarm();
- if (alarms.isEmpty()) {
+ }
+ if ( alarms.isEmpty() ) {
// Add an alarm if it didn't have one
- Alarm*alm = incidence->newAlarm();
- alm->setEnabled(true);
+ Alarm *alm = incidence->newAlarm();
+ alm->setType( Alarm::Display );
+ alm->setEnabled( true );
+ int duration; // in secs
+ switch( KOPrefs::instance()->mReminderTimeUnits ) {
+ default:
+ case 0: // mins
+ duration = KOPrefs::instance()->mReminderTime * 60;
+ break;
+ case 1: // hours
+ duration = KOPrefs::instance()->mReminderTime * 60 * 60;
+ break;
+ case 2: // days
+ duration = KOPrefs::instance()->mReminderTime * 60 * 60 * 24;
+ break;
+ }
+ if ( incidence->type() == "Event" ) {
+ alm->setStartOffset( KCal::Duration( -duration ) );
+ } else {
+ alm->setEndOffset( KCal::Duration( -duration ) );
+ }
}
- mChanger->changeIncidence( oldincidence, incidence, KOGlobals::ALARM_MODIFIED );
- mChanger->endChange( incidence );
+ mChanger->changeIncidence( oldincidence, incidence, KOGlobals::ALARM_MODIFIED, this );
+ mChanger->endChange( incidence, 0, TQString() );
delete oldincidence;
// mClickedItem->updateIcons();
@@ -1248,7 +1493,11 @@ void CalendarView::dissociateOccurrence( Incidence *incidence, const TQDate &dat
kdDebug(5850) << "CalendarView::toggleAlarm() called without having a clicked item" << endl;
return;
}
- if ( !mChanger->beginChange( incidence ) ) {
+
+ QPair<ResourceCalendar *, TQString>p =
+ CalHelper::incSubResourceCalendar( calendar(), incidence );
+
+ if ( !mChanger->beginChange( incidence, p.first, p.second ) ) {
kdDebug(5850) << "Unable to lock incidence " << endl;
return;
}
@@ -1260,14 +1509,14 @@ void CalendarView::dissociateOccurrence( Incidence *incidence, const TQDate &dat
if ( newInc ) {
// TODO [FIXME]: Use the same resource instead of asking again!
// See also koagenda.cpp: endItemAction()
- bool success = mChanger->addIncidence( newInc, this );
+ bool success = mChanger->addIncidence( newInc, p.first, p.second, this );
if ( success )
- mChanger->changeIncidence( oldincidence, incidence );
+ mChanger->changeIncidence( oldincidence, incidence, KOGlobals::NOTHING_MODIFIED, this );
} else {
KMessageBox::sorry( this, i18n("Dissociating the occurrence failed."),
i18n("Dissociating Failed") );
}
- mChanger->endChange( incidence );
+ mChanger->endChange( incidence, p.first, p.second );
endMultiModify();
delete oldincidence;
}
@@ -1278,7 +1527,11 @@ void CalendarView::dissociateFutureOccurrence( Incidence *incidence, const TQDat
kdDebug(5850) << "CalendarView::toggleAlarm() called without having a clicked item" << endl;
return;
}
- if ( !mChanger->beginChange( incidence ) ) {
+
+ QPair<ResourceCalendar *, TQString>p =
+ CalHelper::incSubResourceCalendar( calendar(), incidence );
+
+ if ( !mChanger->beginChange( incidence, p.first, p.second ) ) {
kdDebug(5850) << "Unable to lock incidence " << endl;
return;
}
@@ -1287,15 +1540,14 @@ void CalendarView::dissociateFutureOccurrence( Incidence *incidence, const TQDat
Incidence* newInc = mCalendar->dissociateOccurrence( incidence, date, true );
if ( newInc ) {
- // TODO: Use the same resource instead of asking again!
- mChanger->changeIncidence( oldincidence, incidence );
- mChanger->addIncidence( newInc, this );
+ mChanger->changeIncidence( oldincidence, incidence, KOGlobals::NOTHING_MODIFIED, this );
+ mChanger->addIncidence( newInc, p.first, p.second, this );
} else {
KMessageBox::sorry( this, i18n("Dissociating the future occurrences failed."),
i18n("Dissociating Failed") );
}
endMultiModify();
- mChanger->endChange( incidence );
+ mChanger->endChange( incidence, p.first, p.second );
delete oldincidence;
}
@@ -1374,29 +1626,43 @@ void CalendarView::schedule_declinecounter(Incidence *incidence)
schedule(Scheduler::Declinecounter,incidence);
}
-void CalendarView::schedule_forward(Incidence * incidence)
+void CalendarView::schedule_forward( Incidence *incidence )
{
- if (incidence == 0)
+ if ( !incidence ) {
incidence = selectedIncidence();
+ }
- if (!incidence) {
- KMessageBox::information( this, i18n("No item selected."),
- "ForwardNoEventSelected" );
+ if ( !incidence ) {
+ KMessageBox::information(
+ this,
+ i18n( "No item selected." ),
+ i18n( "Forwarding" ),
+ "ForwardNoEventSelected" );
return;
}
PublishDialog publishdlg;
if ( publishdlg.exec() == TQDialog::Accepted ) {
TQString recipients = publishdlg.addresses();
+ if ( incidence->organizer().isEmpty() ) {
+ incidence->setOrganizer( Person( KOPrefs::instance()->fullName(),
+ KOPrefs::instance()->email() ) );
+ }
+
ICalFormat format;
TQString messageText = format.createScheduleMessage( incidence, Scheduler::Request );
KOMailClient mailer;
if ( mailer.mailTo( incidence, recipients, messageText ) ) {
-
- KMessageBox::information( this, i18n("The item information was successfully sent."),
- i18n("Forwarding"), "IncidenceForwardSuccess" );
+ KMessageBox::information(
+ this,
+ i18n( "The item information was successfully sent." ),
+ i18n( "Forwarding" ),
+ "IncidenceForwardSuccess" );
} else {
- KMessageBox::error( this, i18n("Unable to forward the item '%1'").arg( incidence->summary() ) );
+ KMessageBox::error(
+ this,
+ i18n( "Unable to forward the item '%1'" ).arg( incidence->summary() ),
+ i18n( "Forwarding Error" ) );
}
}
}
@@ -1458,7 +1724,7 @@ void CalendarView::schedule(Scheduler::Method method, Incidence *incidence)
// Send the mail
KCal::MailScheduler scheduler( mCalendar );
- if ( !scheduler.performTransaction( incidence, method ) ) {
+ if ( scheduler.performTransaction( incidence, method ) ) {
KMessageBox::information( this, i18n("The groupware message for item '%1'"
"was successfully sent.\nMethod: %2")
.arg( incidence->summary() )
@@ -1515,9 +1781,11 @@ void CalendarView::print()
KOrg::BaseView *currentView = mViewManager->currentView();
CalPrinterBase::PrintType printType = CalPrinterBase::Month;
- if ( currentView ) printType = currentView->printType();
+ if ( currentView ) {
+ printType = currentView->printType();
+ }
- DateList tmpDateList = mNavigator->selectedDates();
+ DateList tmpDateList = mDateNavigator->selectedDates();
Incidence::List selectedIncidences;
if ( mViewManager->currentView() ) {
selectedIncidences = mViewManager->currentView()->selectedIncidences();
@@ -1542,12 +1810,20 @@ void CalendarView::exportWeb()
void CalendarView::exportICalendar()
{
TQString filename = KFileDialog::getSaveFileName("icalout.ics",i18n("*.ics|ICalendars"),this);
-
- // Force correct extension
- if (filename.right(4) != ".ics") filename += ".ics";
-
- FileStorage storage( mCalendar, filename, new ICalFormat );
- storage.save();
+ if ( !filename.isEmpty() )
+ {
+ // Force correct extension
+ if (filename.right(4) != ".ics") filename += ".ics";
+ if ( TQFile( filename ).exists() ) {
+ if ( KMessageBox::No == KMessageBox::warningYesNo(
+ this,
+ i18n( "Do you want to overwrite %1?").arg(filename) ) ) {
+ return;
+ }
+ }
+ FileStorage storage( mCalendar, filename, new ICalFormat );
+ storage.save();
+ }
}
void CalendarView::exportVCalendar()
@@ -1561,13 +1837,21 @@ void CalendarView::exportVCalendar()
}
TQString filename = KFileDialog::getSaveFileName("vcalout.vcs",i18n("*.vcs|vCalendars"),this);
-
- // TODO: I don't like forcing extensions:
- // Force correct extension
- if (filename.right(4) != ".vcs") filename += ".vcs";
-
- FileStorage storage( mCalendar, filename, new VCalFormat );
- storage.save();
+ if ( !filename.isEmpty() )
+ {
+ // TODO: I don't like forcing extensions:
+ // Force correct extension
+ if (filename.right(4) != ".vcs") filename += ".vcs";
+ if ( TQFile( filename ).exists() ) {
+ if ( KMessageBox::No == KMessageBox::warningYesNo(
+ this,
+ i18n( "Do you want to overwrite %1?").arg(filename ) ) ) {
+ return;
+ }
+ }
+ FileStorage storage( mCalendar, filename, new VCalFormat );
+ storage.save();
+ }
}
void CalendarView::eventUpdated(Incidence *)
@@ -1592,41 +1876,54 @@ void CalendarView::adaptNavigationUnits()
}
}
-void CalendarView::processMainViewSelection( Incidence *incidence )
+void CalendarView::processMainViewSelection( Incidence *incidence, const TQDate &date )
{
if ( incidence ) mTodoList->clearSelection();
- processIncidenceSelection( incidence );
+ processIncidenceSelection( incidence, date );
}
-void CalendarView::processTodoListSelection( Incidence *incidence )
+void CalendarView::processTodoListSelection( Incidence *incidence, const TQDate &date )
{
if ( incidence && mViewManager->currentView() ) {
mViewManager->currentView()->clearSelection();
}
- processIncidenceSelection( incidence );
+ processIncidenceSelection( incidence, date );
}
-void CalendarView::processIncidenceSelection( Incidence *incidence )
+void CalendarView::processIncidenceSelection( Incidence *incidence, const TQDate &date )
{
- if ( incidence == mSelectedIncidence ) return;
+ if ( incidence != mSelectedIncidence ) {
+ // This signal also must be emitted if incidence is 0
+ emit incidenceSelected( incidence, date );
+ }
+
+ if ( !incidence ) {
+ mSelectedIncidence = incidence;
+ return;
+ }
+ if ( incidence == mSelectedIncidence ) {
+ if ( !incidence->doesRecur() || mSaveDate == date ) {
+ return;
+ }
+ }
mSelectedIncidence = incidence;
+ mSaveDate = date;
- emit incidenceSelected( mSelectedIncidence );
+ emit incidenceSelected( mSelectedIncidence, date );
bool organizerEvents = false;
bool groupEvents = false;
bool todo = false;
bool subtodo = false;
- if ( incidence ) {
- organizerEvents = KOPrefs::instance()->thatIsMe( incidence->organizer().email() );
- groupEvents = incidence->attendeeByMails( KOPrefs::instance()->allEmails() );
+ organizerEvents = KOPrefs::instance()->thatIsMe( incidence->organizer().email() );
+ groupEvents = incidence->attendeeByMails( KOPrefs::instance()->allEmails() );
- if ( incidence && incidence->type() == "Todo" ) {
- todo = true;
- subtodo = ( incidence->relatedTo() != 0 );
- }
+ if ( incidence->type() == "Todo" ) {
+ todo = true;
+ subtodo = ( incidence->relatedTo() != 0 );
}
+
emit todoSelected( todo );
emit subtodoSelected( subtodo );
emit organizerEventsSelected( organizerEvents );
@@ -1647,9 +1944,10 @@ void CalendarView::checkClipboard()
#endif
}
-void CalendarView::showDates(const DateList &selectedDates)
+void CalendarView::showDates( const DateList &selectedDates, const TQDate &preferredMonth )
{
-// kdDebug(5850) << "CalendarView::selectDates()" << endl;
+ mDateNavigatorContainer->selectDates( selectedDates, preferredMonth );
+ mNavigatorBar->selectDates( selectedDates );
if ( mViewManager->currentView() ) {
updateView( selectedDates.first(), selectedDates.last() );
@@ -1663,7 +1961,7 @@ void CalendarView::editFilters()
kdDebug(5850) << "CalendarView::editFilters()" << endl;
CalFilter *filter = mFilters.first();
- while(filter) {
+ while( filter ) {
kdDebug(5850) << " Filter: " << filter->name() << endl;
filter = mFilters.next();
}
@@ -1755,9 +2053,9 @@ void CalendarView::showIntro()
void CalendarView::showDateNavigator( bool show )
{
if( show )
- mDateNavigator->show();
+ mDateNavigatorContainer->show();
else
- mDateNavigator->hide();
+ mDateNavigatorContainer->hide();
}
void CalendarView::showTodoView( bool show )
@@ -1835,7 +2133,7 @@ Todo *CalendarView::selectedTodo()
void CalendarView::dialogClosing( Incidence *in )
{
// FIXME: this doesn't work, because if it's a new incidence, it's not locked!
- mChanger->endChange( in );
+ mChanger->endChange( in, 0, TQString() );
mDialogList.remove( in );
}
@@ -1857,18 +2155,22 @@ Incidence* CalendarView::selectedIncidence()
void CalendarView::showIncidence()
{
- showIncidence( selectedIncidence() );
+ showIncidence( selectedIncidence(), activeIncidenceDate() );
}
void CalendarView::editIncidence()
{
- editIncidence( selectedIncidence() );
+ editIncidence( selectedIncidence(), activeIncidenceDate() );
}
-bool CalendarView::editIncidence( const TQString& uid )
+bool CalendarView::editIncidence( const TQString &uid )
{
- kdDebug(5850) << "CalendarView::editIncidence()" << endl;
- return editIncidence( mCalendar->incidence( uid ) );
+ return editIncidence( mCalendar->incidence( uid ), TQDate() );
+}
+
+bool CalendarView::editIncidence( const TQString &uid, const TQDate &date )
+{
+ return editIncidence( mCalendar->incidence( uid ), date );
}
void CalendarView::deleteIncidence()
@@ -1891,21 +2193,51 @@ void CalendarView::pasteIncidence()
edit_paste();
}
-void CalendarView::showIncidence( Incidence *incidence )
+void CalendarView::showIncidence( Incidence *incidence, const TQDate &date )
{
- KOEventViewerDialog *eventViewer = new KOEventViewerDialog( this );
- eventViewer->setIncidence( incidence );
+ if ( !incidence ) {
+ return;
+ }
+
+ KOEventViewerDialog *eventViewer = new KOEventViewerDialog( calendar(), this );
+ eventViewer->setIncidence( incidence, date );
eventViewer->show();
}
-bool CalendarView::editIncidence( Incidence *incidence, bool isCounter )
+bool CalendarView::editIncidence( Incidence *incidence, const TQDate &date, bool isCounter )
{
kdDebug(5850) << "CalendarView::editEvent()" << endl;
- if ( !incidence || !mChanger ) {
+ CalendarResources *stdcal = dynamic_cast<CalendarResources *>( mCalendar );
+ if( stdcal && !stdcal->hasCalendarResources() ) {
+ KMessageBox::sorry(
+ this,
+ i18n( "No resources found. We can not edit the item." ) );
+ return false;
+ }
+
+ // FIXME: This is a nasty hack, since we need to set a parent for the
+ // resource selection dialog. However, we don't have any UI methods
+ // in the calendar, only in the CalendarResources::DestinationPolicy
+ // So we need to type-cast it and extract it from the CalendarResources
+ TQWidget *tmpparent = 0;
+ if ( stdcal ) {
+ tmpparent = stdcal->dialogParentWidget();
+ stdcal->setDialogParentWidget( this );
+ }
+
+ if ( !incidence ) {
+ kdDebug(5850) << "Empty Incidence" << endl;
KNotifyClient::beep();
return false;
}
+
+ if ( !mChanger ) {
+ kdDebug(5850) << "Empty Changer" << endl;
+ KNotifyClient::beep();
+ return false;
+ }
+
KOIncidenceEditor *tmp = editorDialog( incidence );
if ( tmp ) {
kdDebug(5850) << "CalendarView::editIncidence() in List" << endl;
@@ -1916,24 +2248,47 @@ bool CalendarView::editIncidence( Incidence *incidence, bool isCounter )
}
if ( incidence->isReadOnly() ) {
- showIncidence( incidence );
+ showIncidence( incidence, date );
return true;
}
- if ( !isCounter && !mChanger->beginChange( incidence ) ) {
- warningChangeFailed( incidence );
- showIncidence( incidence );
- return false;
+ QPair<ResourceCalendar *, TQString>p =
+ CalHelper::incSubResourceCalendar( calendar(), incidence );
+
+ Incidence *savedIncidence = incidence->clone();
+ Incidence *incToChange;
+
+ if ( incidence->doesRecur() ) {
+ KOGlobals::WhichOccurrences chosenOption;
+ incToChange = singleOccurrenceOrAll( incidence, KOGlobals::EDIT, chosenOption, date );
+ } else {
+ incToChange = incidence;
}
- kdDebug(5850) << "CalendarView::editIncidence() new IncidenceEditor" << endl;
- KOIncidenceEditor *incidenceEditor = mDialogManager->getEditor( incidence );
- connectIncidenceEditor( incidenceEditor );
+ // If the user pressed cancel incToChange is 0
+ if ( incToChange ) {
+ if ( !isCounter && !mChanger->beginChange( incToChange, p.first, p.second ) ) {
+ warningChangeFailed( incToChange );
+ showIncidence( incToChange, date );
- mDialogList.insert( incidence, incidenceEditor );
- incidenceEditor->editIncidence( incidence, mCalendar );
- incidenceEditor->show();
- return true;
+ return false;
+ }
+
+ kdDebug(5850) << "CalendarView::editIncidence() new IncidenceEditor" << endl;
+ KOIncidenceEditor *incidenceEditor = mDialogManager->getEditor( incToChange );
+ connectIncidenceEditor( incidenceEditor );
+
+ mDialogList.insert( incToChange, incidenceEditor );
+ if ( incidence != incToChange ) {
+ incidenceEditor->setRecurringIncidence( savedIncidence, incidence );
+ }
+ incidenceEditor->setResource( p.first, p.second );
+ incidenceEditor->editIncidence( incToChange, date, mCalendar );
+ incidenceEditor->show();
+ return true;
+ } else {
+ return false;
+ }
}
void CalendarView::deleteSubTodosIncidence ( Todo *todo )
@@ -1952,7 +2307,7 @@ void CalendarView::deleteSubTodosIncidence ( Todo *todo )
deleteSubTodosIncidence ( aTodo );
}
}
- mChanger->deleteIncidence ( todo );
+ mChanger->deleteIncidence ( todo, this );
}
void CalendarView::deleteTodoIncidence ( Todo *todo, bool force )
@@ -1966,29 +2321,31 @@ void CalendarView::deleteTodoIncidence ( Todo *todo, bool force )
doDelete = ( msgItemDelete( todo ) == KMessageBox::Continue );
}
if ( doDelete )
- mChanger->deleteIncidence( todo );
+ mChanger->deleteIncidence( todo, this );
return;
}
/* Ok, this to-do has sub-to-dos, ask what to do */
int km = KMessageBox::No;
if ( !force ) {
- km=KMessageBox::questionYesNoCancel( this,
- i18n("The item \"%1\" has sub-to-dos. "
- "Do you want to delete just this item and "
- "make all its sub-to-dos independent, or "
- "delete the to-do with all its sub-to-dos?"
- ).arg( todo->summary() ),
- i18n("KOrganizer Confirmation"),
- i18n("Delete Only This"),
- i18n("Delete All"));
+ km = KMessageBox::questionYesNoCancel(
+ this,
+ i18n("The item \"%1\" has sub-to-dos. "
+ "Do you want to delete just this item and "
+ "make all its sub-to-dos independent, or "
+ "delete the to-do with all its sub-to-dos?"
+ ).arg( todo->summary() ),
+ i18n("KOrganizer Confirmation"),
+ i18n("Delete Only This"),
+ i18n("Delete All"));
}
startMultiModify( i18n("Deleting sub-to-dos" ) );
// Delete only the father
if( km == KMessageBox::Yes ) {
-
- makeSubTodosIndependents ( todo );
- mChanger->deleteIncidence( todo );
+ // Instead of making a subto-do independent, why not relate
+ // it to it's dead father's parent?
+ makeChildrenIndependent ( todo );
+ mChanger->deleteIncidence( todo, this );
} else if ( km == KMessageBox::No ) {
// Delete all
// we have to hide the delete confirmation for each itemDate
@@ -2054,14 +2411,18 @@ void CalendarView::deleteIncidence(Incidence *incidence, bool force)
i18n("Delete &All"));
}
}
+
+ QPair<ResourceCalendar *, TQString>p =
+ CalHelper::incSubResourceCalendar( calendar(), incidence );
+
switch(km) {
case KMessageBox::Ok: // Continue // all
case KMessageBox::Continue:
- mChanger->deleteIncidence( incidence );
+ mChanger->deleteIncidence( incidence, this );
break;
case KMessageBox::Yes: // just this one
- if ( mChanger->beginChange( incidence ) ) {
+ if ( mChanger->beginChange( incidence, p.first, p.second ) ) {
Incidence *oldIncidence = incidence->clone();
if (incidence->recurrence()->startDate() == itemDate) {
// Moving the first in a series...don't bother with the nonstandard exclusion list
@@ -2079,18 +2440,18 @@ void CalendarView::deleteIncidence(Incidence *incidence, bool force)
// No choice but to use the exclusion list
incidence->recurrence()->addExDate( itemDate );
}
- mChanger->changeIncidence( oldIncidence, incidence );
- mChanger->endChange( incidence );
+ mChanger->changeIncidence( oldIncidence, incidence, KOGlobals::RECURRENCE_MODIFIED_ONE_ONLY, this );
+ mChanger->endChange( incidence, p.first, p.second );
delete oldIncidence;
}
break;
case KMessageBox::No: // all future items
- if ( mChanger->beginChange( incidence ) ) {
+ if ( mChanger->beginChange( incidence, p.first, p.second ) ) {
Incidence *oldIncidence = incidence->clone();
Recurrence *recur = incidence->recurrence();
recur->setEndDate( itemDate.addDays(-1) );
- mChanger->changeIncidence( oldIncidence, incidence );
- mChanger->endChange( incidence );
+ mChanger->changeIncidence( oldIncidence, incidence, KOGlobals::RECURRENCE_MODIFIED_ONE_ONLY, this );
+ mChanger->endChange( incidence, p.first, p.second );
delete oldIncidence;
}
break;
@@ -2101,8 +2462,8 @@ void CalendarView::deleteIncidence(Incidence *incidence, bool force)
doDelete = ( msgItemDelete( incidence ) == KMessageBox::Continue );
}
if ( doDelete ) {
- mChanger->deleteIncidence( incidence );
- processIncidenceSelection( 0 );
+ mChanger->deleteIncidence( incidence, this );
+ processIncidenceSelection( 0, TQDate() );
}
}
@@ -2134,7 +2495,7 @@ bool CalendarView::purgeCompletedSubTodos( Todo* todo, bool &allPurged )
if ( deleteThisTodo ) {
if ( todo->isCompleted() ) {
- if ( !mChanger->deleteIncidence( todo ) )
+ if ( !mChanger->deleteIncidence( todo, this ) )
allPurged = false;
} else {
deleteThisTodo = false;
@@ -2176,20 +2537,19 @@ void CalendarView::purgeCompleted()
}
}
-void CalendarView::slotCalendarChanged()
+void CalendarView::warningChangeFailed( Incidence *incidence )
{
- kdDebug(5850) << "CalendarView::slotCalendarChanged()" << endl;
-}
-
-void CalendarView::warningChangeFailed( Incidence * )
-{
- KMessageBox::sorry( this, i18n("Unable to edit item: "
- "it is locked by another process.") );
+ if ( incidence ) {
+ KMessageBox::sorry(
+ this,
+ i18n( "Unable to edit \"%1\" because it is locked by another process." ).
+ arg( incidence->summary() ) );
+ }
}
-void CalendarView::editCanceled( Incidence *i )
+void CalendarView::editCanceled( Incidence *incidence )
{
- mCalendar->endChange( i );
+ mCalendar->endChange( incidence );
}
void CalendarView::showErrorMessage( const TQString &msg )
@@ -2249,7 +2609,9 @@ void CalendarView::addIncidenceOn( Incidence *incadd, const TQDate &dt )
todo->setHasDueDate( true );
}
- if ( !mChanger->addIncidence( incidence, this ) ) {
+ QPair<ResourceCalendar *, TQString>p = viewSubResourceCalendar();
+
+ if ( !mChanger->addIncidence( incidence, p.first, p.second, this ) ) {
KODialogManager::errorSaveIncidence( this, incidence );
delete incidence;
}
@@ -2267,8 +2629,11 @@ void CalendarView::moveIncidenceTo( Incidence *incmove, const TQDate &dt )
addIncidenceOn( incidence, dt );
return;
}
+
Incidence *oldIncidence = incidence->clone();
- if ( !mChanger->beginChange( incidence ) ) {
+ QPair<ResourceCalendar *, TQString>p = viewSubResourceCalendar();
+
+ if ( !mChanger->beginChange( incidence, p.first, p.second ) ) {
delete oldIncidence;
return;
}
@@ -2295,15 +2660,151 @@ void CalendarView::moveIncidenceTo( Incidence *incmove, const TQDate &dt )
todo->setDtDue( due );
todo->setHasDueDate( true );
}
- mChanger->changeIncidence( oldIncidence, incidence );
- mChanger->endChange( incidence );
+ mChanger->changeIncidence( oldIncidence, incidence, KOGlobals::DATE_MODIFIED,this );
+ mChanger->endChange( incidence, p.first, p.second );
delete oldIncidence;
}
void CalendarView::resourcesChanged()
{
mViewManager->resourcesChanged();
+ mDateNavigatorContainer->setUpdateNeeded();
updateView();
}
+Incidence* CalendarView::singleOccurrenceOrAll( Incidence *inc,
+ KOGlobals::OccurrenceAction userAction,
+ KOGlobals::WhichOccurrences &chosenOption,
+ const TQDate &itemDate,
+ const bool commitToCalendar )
+{
+
+ // temporary, until recurring to-dos are fixed
+ if ( inc->type() != "Event" ) {
+ chosenOption = KOGlobals::ALL;
+ return inc;
+ }
+
+ Incidence *incToReturn = 0;
+ Incidence *incSaved = 0;
+ KOGlobals::WhatChanged whatChanged;
+
+ bool dissociationOccurred = false;
+ const TQDate &dt = itemDate.isValid() ? itemDate : activeIncidenceDate();
+
+ TQString dialogTitle;
+ TQString dialogText;
+
+ if ( userAction == KOGlobals::CUT ) {
+ dialogTitle = i18n( "Cutting Recurring Item" );
+
+ dialogText = i18n("The item you try to cut is a recurring item. Do you want to cut "
+ "only this single occurrence, only future items, "
+ "or all items in the recurrence?");
+
+ } else if ( userAction == KOGlobals::COPY ) {
+ dialogTitle = i18n( "Copying Recurring Item" );
+
+ dialogText = i18n("The item you try to copy is a recurring item. Do you want to copy "
+ "only this single occurrence, only future items, "
+ "or all items in the recurrence?");
+ } else {
+ dialogTitle = i18n( "Changing Recurring Item" );
+
+ dialogText = i18n( "The item you try to change is a recurring item. Shall the changes "
+ "be applied only to this single occurrence, only to the future items, "
+ "or to all items in the recurrence?" );
+ }
+
+ int res = KOMessageBox::fourBtnMsgBox( this, TQMessageBox::Question,
+ dialogText,
+ dialogTitle,
+ i18n("Only &This Item"), i18n("Only &Future Items"), i18n("&All Occurrences") );
+ switch ( res ) {
+ case KMessageBox::Ok: // All occurrences
+ incToReturn = inc;
+ chosenOption = KOGlobals::ALL;
+ break;
+ case KMessageBox::Yes: { // Just this occurrence
+ // Dissociate this occurrence:
+ // create clone of event, set relation to old event, set cloned event
+ // for mActionItem, add exception date to old event, changeIncidence
+ // for the old event, remove the recurrence from the new copy and then just
+ // go on with the newly adjusted mActionItem and let the usual code take
+ // care of the new time!
+
+ chosenOption = KOGlobals::ONLY_THIS_ONE;
+ whatChanged = KOGlobals::RECURRENCE_MODIFIED_ONE_ONLY;
+ startMultiModify( i18n("Dissociate event from recurrence") );
+ incSaved = inc->clone();
+ incToReturn = mCalendar->dissociateOccurrence( inc, dt );
+ if ( incToReturn ) {
+ dissociationOccurred = true;
+ } else {
+ KMessageBox::sorry( this, i18n("Unable to add the exception item to the "
+ "calendar. No change will be done."), i18n("Error Occurred") );
+ incToReturn = 0;
+ }
+
+ break; }
+ case KMessageBox::No/*Future*/: { // All future occurrences
+ // Dissociate this occurrence:
+ // create clone of event, set relation to old event, set cloned event
+ // for mActionItem, add recurrence end date to old event, changeIncidence
+ // for the old event, adjust the recurrence for the new copy and then just
+ // go on with the newly adjusted mActionItem and let the usual code take
+ // care of the new time!
+ chosenOption = KOGlobals::ONLY_FUTURE;
+ whatChanged = KOGlobals::RECURRENCE_MODIFIED_ALL_FUTURE;
+ startMultiModify( i18n("Split future recurrences") );
+ incSaved = inc->clone();
+ incToReturn = mCalendar->dissociateOccurrence( inc, dt, false );
+ if ( incToReturn ) {
+ dissociationOccurred = true;
+ } else {
+ KMessageBox::sorry( this, i18n("Unable to add the future items to the "
+ "calendar. No change will be done."), i18n("Error Occurred") );
+
+ incToReturn = 0;
+ }
+
+ break; }
+ default:
+ chosenOption = KOGlobals::NONE;
+ }
+
+ if ( dissociationOccurred && commitToCalendar ) {
+ QPair<ResourceCalendar *, TQString>p = viewSubResourceCalendar();
+ mChanger->addIncidence( incToReturn, p.first, p.second, this );
+ mChanger->changeIncidence( incSaved, inc, whatChanged, this );
+ }
+
+ return incToReturn;
+}
+
+void CalendarView::selectWeek( const TQDate &date )
+{
+ if ( KOPrefs::instance()->mWeekNumbersShowWork &&
+ mViewManager->agendaIsSelected() &&
+ mViewManager->agendaMode() == KOViewManager::AGENDA_WORK_WEEK ) {
+ mDateNavigator->selectWorkWeek( date );
+ } else {
+ mDateNavigator->selectWeek( date );
+ }
+}
+
+void CalendarView::getIncidenceHierarchy( Incidence *inc,
+ Incidence::List &children )
+{
+ // protecion against looping hierarchies
+ if ( inc && !children.contains( inc ) ) {
+ Incidence::List::ConstIterator it;
+ Incidence::List immediateChildren = inc->relations();
+ for ( it = immediateChildren.constBegin(); it != immediateChildren.constEnd(); ++it ) {
+ getIncidenceHierarchy( *it, children );
+ }
+ children.append( inc );
+ }
+}
+
#include "calendarview.moc"
diff --git a/korganizer/calendarview.h b/korganizer/calendarview.h
index dfcc75ef3..5922e8f2d 100644
--- a/korganizer/calendarview.h
+++ b/korganizer/calendarview.h
@@ -33,7 +33,8 @@
#include <libkcal/scheduler.h>
#include <kdepimmacros.h>
-#include <korganizer/calendarviewbase.h>
+#include "koglobals.h"
+#include "interfaces/korganizer/calendarviewbase.h"
class TQWidgetStack;
class TQSplitter;
@@ -90,7 +91,6 @@ class KDE_EXPORT CalendarView : public KOrg::CalendarViewBase, public Calendar::
CalendarView( TQWidget *parent = 0, const char *name = 0 );
virtual ~CalendarView();
-
class CalendarViewVisitor : public IncidenceBase::Visitor
{
public:
@@ -112,10 +112,11 @@ class KDE_EXPORT CalendarView : public KOrg::CalendarViewBase, public Calendar::
bool visit( Journal *journal ) { return mView->deleteJournal( journal ); }
};
-
void setCalendar( Calendar * );
Calendar *calendar();
+ QPair<ResourceCalendar *, TQString> viewSubResourceCalendar();
+
KOrg::History *history() const { return mHistory; }
KOViewManager *viewManager() const { return mViewManager; }
@@ -124,7 +125,7 @@ class KDE_EXPORT CalendarView : public KOrg::CalendarViewBase, public Calendar::
TQWidgetStack *viewStack() const { return mRightFrame; }
TQWidget *leftFrame() const { return mLeftFrame; }
NavigatorBar *navigatorBar() const { return mNavigatorBar; }
- DateNavigator *dateNavigator() const { return mNavigator; }
+ DateNavigator *dateNavigator() const { return mDateNavigator; }
KOIncidenceEditor *editorDialog( Incidence* ) const;
IncidenceChangerBase *incidenceChanger() const { return mChanger; }
@@ -182,7 +183,7 @@ class KDE_EXPORT CalendarView : public KOrg::CalendarViewBase, public Calendar::
Emitted when an incidence gets selected. If the selection is cleared the
signal is emitted with 0 as argument.
*/
- void incidenceSelected( Incidence * );
+ void incidenceSelected( Incidence *incidence, const TQDate &date );
/** Emitted, when a todoitem is selected or deselected.
the connected slots enables/disables the corresponding menu items */
void todoSelected( bool );
@@ -252,7 +253,8 @@ class KDE_EXPORT CalendarView : public KOrg::CalendarViewBase, public Calendar::
void showIncidence();
void editIncidence();
- bool editIncidence( const TQString& uid );
+ bool editIncidence( const TQString &uid );
+ bool editIncidence( const TQString &uid, const TQDate &date );
void deleteIncidence();
/**
@@ -265,29 +267,37 @@ class KDE_EXPORT CalendarView : public KOrg::CalendarViewBase, public Calendar::
*/
bool addIncidence( const TQString &ical );
- void connectIncidenceEditor( KOIncidenceEditor * );
+ void connectIncidenceEditor( KOIncidenceEditor *editor );
/** create new event without having a date hint. Takes current date as
default hint. */
void newEvent();
+ void newEvent( ResourceCalendar *res, const TQString &subRes );
/** create an editeventwin with supplied date/time, and if bool is true,
* make the event take all day. */
- void newEvent( const TQDate &startDt );
- void newEvent( const TQDateTime &startDt );
- void newEvent( const TQDateTime &startDt, const TQDateTime &EndDt, bool allDay = false );
+ void newEvent( ResourceCalendar *res, const TQString &subRes,
+ const TQDate &startDt );
+ void newEvent( ResourceCalendar *res, const TQString &subRes,
+ const TQDateTime &startDt );
+ void newEvent( ResourceCalendar *res, const TQString &subRes,
+ const TQDateTime &startDt, const TQDateTime &EndDt,
+ bool allDay = false );
/**
Create new Event from given summary, description, attachment list and
attendees list
*/
- void newEvent( const TQString &summary, const TQString &description = TQString::null,
- const TQStringList &attachment = TQStringList(), const TQStringList &attendees = TQStringList(),
- const TQStringList &attachmentMimetypes = TQStringList(), bool inlineAttachment = false );
- void newFloatingEvent();
+ void newEvent( ResourceCalendar *res, const TQString &subRes,
+ const TQString &summary,
+ const TQString &description = TQString::null,
+ const TQStringList &attachment = TQStringList(),
+ const TQStringList &attendees = TQStringList(),
+ const TQStringList &attachmentMimetypes = TQStringList(),
+ bool inlineAttachment = false );
/** Create a read-only viewer dialog for the supplied incidence. It calls the correct showXXX method*/
- void showIncidence( Incidence * );
+ void showIncidence( Incidence *, const TQDate & );
/** Create an editor for the supplied incidence. It calls the correct editXXX method*/
- bool editIncidence( Incidence *incidence, bool isCounter = false );
+ bool editIncidence( Incidence *incidence, const TQDate &date, bool isCounter = false );
/**
Delete the supplied incidence. It calls the correct deleteXXX method
@param force If true, all recurrences and sub-todos (if applicable) will be
@@ -331,20 +341,29 @@ class KDE_EXPORT CalendarView : public KOrg::CalendarViewBase, public Calendar::
/** create new todo */
void newTodo();
+ void newTodo( ResourceCalendar *res, const TQString &subRes );
/** create new todo, due on date */
- void newTodo( const TQDate &date );
+ void newTodo( ResourceCalendar *res, const TQString &subRes,
+ const TQDate &date );
/** create new todo with a parent todo */
void newSubTodo();
/** create new todo with a parent todo */
void newSubTodo( Todo * );
- void newTodo( const TQString &summary, const TQString &description = TQString::null,
- const TQStringList &attachments = TQStringList(), const TQStringList &attendees = TQStringList(),
- const TQStringList &attachmentMimetypes = TQStringList(), bool inlineAttachment = false );
+ void newTodo( ResourceCalendar *res, const TQString &subRes,
+ const TQString &summary,
+ const TQString &description = TQString::null,
+ const TQStringList &attachments = TQStringList(),
+ const TQStringList &attendees = TQStringList(),
+ const TQStringList &attachmentMimetypes = TQStringList(),
+ bool inlineAttachment = false, bool createTask = false );
void newJournal();
- void newJournal( const TQDate &date );
- void newJournal( const TQString &text, const TQDate &date = TQDate() );
+ void newJournal( ResourceCalendar *res, const TQString &subRes );
+ void newJournal( ResourceCalendar *res, const TQString &subRes,
+ const TQDate &date );
+ void newJournal( ResourceCalendar *res, const TQString &subRes,
+ const TQString &text, const TQDate &date = TQDate() );
void toggleAlarm( Incidence * );
void dissociateOccurrence( Incidence *, const TQDate & );
@@ -379,8 +398,8 @@ class KDE_EXPORT CalendarView : public KOrg::CalendarViewBase, public Calendar::
void changeIncidenceDisplay( Incidence *, int );
void incidenceAdded( Incidence * );
- void incidenceChanged( Incidence *oldEvent, Incidence *newEvent );
- void incidenceChanged( Incidence *oldEvent, Incidence *newEvent, int what );
+ void incidenceChanged( Incidence *oldEvent, Incidence *newEvent,
+ KOGlobals::WhatChanged modification );
void incidenceToBeDeleted( Incidence *incidence );
void incidenceDeleted( Incidence * );
void startMultiModify( const TQString &text );
@@ -434,14 +453,21 @@ class KDE_EXPORT CalendarView : public KOrg::CalendarViewBase, public Calendar::
*/
void appointment_delete();
- /* frees a subtodo from it's relation, update the view */
+ /* frees the selected to-do's children from it's relation, update the view */
void todo_unsub();
- /* Free a subtodo from it's relation, without update the view */
- bool todo_unsub( Todo *todo );
- /** Make all sub-to-dos of todo independents, update the view*/
- bool makeSubTodosIndependents ( );
- /** Make all sub-to-dos of todo independents, not update the view*/
- bool makeSubTodosIndependents ( Todo *todo );
+
+ /* frees an incidence's children from it's relation, without update the view
+ Works with any incidence type, although currently we only pass to-dos
+ */
+ bool incidence_unsub( Incidence *inc );
+
+ /** Make all sub-to-dos of the selected todo independent, update the view */
+ bool makeSubTodosIndependent ( );
+
+ /** Make all children of incidence independent, not update the view
+ Works with any incidence type, although currently we only pass to-dos
+ */
+ bool makeChildrenIndependent( Incidence *inc );
/** Take ownership of selected event. */
void takeOverEvent();
@@ -506,15 +532,13 @@ class KDE_EXPORT CalendarView : public KOrg::CalendarViewBase, public Calendar::
void dialogClosing( Incidence * );
- void processMainViewSelection( Incidence * );
- void processTodoListSelection( Incidence * );
+ void processMainViewSelection( Incidence *incidence, const TQDate &date );
+ void processTodoListSelection( Incidence *incidence, const TQDate &date );
- void processIncidenceSelection( Incidence * );
+ void processIncidenceSelection( Incidence *incidence, const TQDate &date );
void purgeCompleted();
- void slotCalendarChanged();
-
void slotAutoArchivingSettingsModified() { emit autoArchivingSettingsModified(); }
void showErrorMessage( const TQString & );
@@ -525,9 +549,20 @@ class KDE_EXPORT CalendarView : public KOrg::CalendarViewBase, public Calendar::
void resourcesChanged();
+ /**
+ The user clicked on a week number in the date navigator
+
+ Lets select a week or a work week depending on the user's
+ config option.
+ */
+ void selectWeek( const TQDate & );
+
protected slots:
- /** Select a view or adapt the current view to display the specified dates. */
- void showDates( const KCal::DateList & );
+ /** Select a view or adapt the current view to display the specified dates.
+ preferredMonth is useful when the datelist crosses months, if valid,
+ any month-like component should honour this
+ */
+ void showDates( const KCal::DateList &, const TQDate &preferredMonth = TQDate() );
public:
// show a standard warning
@@ -539,7 +574,52 @@ class KDE_EXPORT CalendarView : public KOrg::CalendarViewBase, public Calendar::
*/
void adaptNavigationUnits();
- //Attendee* getYourAttendee( Event *event );
+ /**
+ Returns the date of the selected incidence.
+
+ If the selected incidence is recurring, it will return
+ the date of the selected occurrence
+ */
+ TQDate activeIncidenceDate();
+
+ /**
+ Returns the best guess at the current active date in the view.
+ This has nothing to do with selected incidences, use activeIncidenceDate()
+ for that, for example, agenda supports time selection and incidence selection
+ and they can have diferent dates.
+
+ @param fallbackToToday If guessing doesn't work, some views will prefer
+ today to be returned instead of the first select date in the day matrix,
+ Journal view for example.
+ */
+ TQDate activeDate( bool fallbackToToday = false );
+
+ /**
+ Asks the user if he wants to edit only this occurrence, all
+ occurrences or only future occurrences, and then dissociates
+ the incidence if needed.
+
+ @param inc The recurring incidence that's about to be edited.
+ @param userAction Specifies what the user is doing with the occurrence,
+ like cutting, pasting or editing, it only influences the strings
+ in the message box.
+ @param chosenOption After calling this function, it will hold the user's
+ chosen option.
+ @param itemDate The date of the selected view item
+ @param commitToCalendar If true, mChanger is called and the dissociation
+ is saved to the calendar. If false, it's up to the caller to do that.
+
+ @return A pointer to the incidence that should be edited which is
+ 0 if the user pressed cancel, inc if the user pressed
+ "All Occurrences", or points to a newly created incidence
+ when dissociation is involved in which case the caller
+ is responsible to add it to the calendar and freeing it.
+ **/
+ Incidence* singleOccurrenceOrAll( Incidence *inc,
+ KOGlobals::OccurrenceAction userAction,
+ KOGlobals::WhichOccurrences &chosenOption,
+ const TQDate &itemDate = TQDate(),
+ const bool commitToCalendar = false );
protected:
void setIncidenceChanger( IncidenceChangerBase *changer );
@@ -555,18 +635,33 @@ class KDE_EXPORT CalendarView : public KOrg::CalendarViewBase, public Calendar::
defaults, if invalid values are given) and allow the view to adjust the
type. */
void dateTimesForNewEvent( TQDateTime &startDt, TQDateTime &endDt, bool &allDay );
- KOEventEditor *newEventEditor( const TQDateTime &startDtParam = TQDateTime(),
- const TQDateTime &endDtParam = TQDateTime() , bool allDayParam = false );
+ KOEventEditor *newEventEditor( ResourceCalendar *res, const TQString &subRes,
+ const TQDateTime &startDtParam = TQDateTime(),
+ const TQDateTime &endDtParam = TQDateTime() ,
+ bool allDayParam = false );
private:
void init();
+ /**
+ Returns the incidence that should be sent to clipboard.
+ Usually it's just returns the selected incidence, but, if
+ the incidence is recurring, it will ask the user what he wants to
+ cut/paste and dissociate the incidence if necesssary.
+ **/
+ Incidence *incToSendToClipboard( bool cut );
+
void calendarModified( bool, Calendar * );
// Helper function for purgeCompleted that recursively purges a todo and
// its subitems. If it cannot delete a completed todo (because it has
// uncompleted subitems), notAllPurged is set to true.
bool purgeCompletedSubTodos( Todo* todo, bool &notAllPurged );
+ /** Returns all incidences having inc has their parent (or grand parent, etc.)
+ inc is included in the list too.
+ */
+ void getIncidenceHierarchy( Incidence *inc, Incidence::List &incidences );
+
KOrg::History *mHistory;
TQSplitter *mPanner;
@@ -574,16 +669,18 @@ class KDE_EXPORT CalendarView : public KOrg::CalendarViewBase, public Calendar::
TQWidget *mLeftFrame;
TQWidgetStack *mRightFrame;
+ // This navigator bar is used when in full window month view
+ // It has nothing to do with the date navigator
NavigatorBar *mNavigatorBar;
- DateNavigatorContainer *mDateNavigator;
+ DateNavigatorContainer *mDateNavigatorContainer;
TQPtrList<CalendarViewExtension> mExtensions;
Calendar *mCalendar;
- DateNavigator *mNavigator;
+ DateNavigator *mDateNavigator;
DateChecker *mDateChecker;
KOEventViewer *mEventViewer;
@@ -597,9 +694,9 @@ class KDE_EXPORT CalendarView : public KOrg::CalendarViewBase, public Calendar::
// various housekeeping variables.
bool mModified; // flag indicating if calendar is modified
bool mReadOnly; // flag indicating if calendar is read-only
- TQDate mSaveSingleDate;
Incidence *mSelectedIncidence;
+ TQDate mSaveDate;
KOTodoView *mTodoList;
TQMap<Incidence*,KOIncidenceEditor*> mDialogList;
diff --git a/korganizer/datenavigator.cpp b/korganizer/datenavigator.cpp
index 6f5570a10..edc036ce4 100644
--- a/korganizer/datenavigator.cpp
+++ b/korganizer/datenavigator.cpp
@@ -54,11 +54,11 @@ int DateNavigator::datesCount() const
return mSelectedDates.count();
}
-void DateNavigator::selectDates( const DateList& dateList )
+void DateNavigator::selectDates( const DateList &dateList )
{
- if (dateList.count() > 0) {
+ if ( dateList.count() > 0 ) {
mSelectedDates = dateList;
-
+
emitSelected();
}
}
@@ -83,26 +83,33 @@ void DateNavigator::selectDates( int count )
selectDates( mSelectedDates.first(), count );
}
-void DateNavigator::selectDates( const TQDate &d, int count )
+void DateNavigator::selectDates( const TQDate &d, int count, const TQDate &preferredMonth )
{
+ if ( count > MAX_SELECTABLE_DAYS ) {
+ count = MAX_SELECTABLE_DAYS;
+ }
+
DateList dates;
int i;
for( i = 0; i < count; ++i ) {
dates.append( d.addDays( i ) );
}
-
+
mSelectedDates = dates;
-
- emitSelected();
+
+ emitSelected( preferredMonth );
}
-void DateNavigator::selectWeekByDay( int weekDay, const TQDate &d )
+void DateNavigator::selectWeekByDay( int weekDay, const TQDate &d, const TQDate &preferredMonth )
{
int dateCount = mSelectedDates.count();
bool weekStart = ( weekDay == KGlobal::locale()->weekStartDay() );
- if ( weekStart && dateCount == 7 ) selectWeek( d );
- else selectDates( d, dateCount );
+ if ( weekStart && dateCount == 7 ) {
+ selectWeek( d, preferredMonth );
+ } else {
+ selectDates( d, dateCount, preferredMonth );
+ }
}
void DateNavigator::selectWeek()
@@ -110,7 +117,7 @@ void DateNavigator::selectWeek()
selectWeek( mSelectedDates.first() );
}
-void DateNavigator::selectWeek( const TQDate &d )
+void DateNavigator::selectWeek( const TQDate &d, const TQDate &preferredMonth )
{
int dayOfWeek = KOGlobals::self()->calendarSystem()->dayOfWeek( d );
@@ -122,7 +129,7 @@ void DateNavigator::selectWeek( const TQDate &d )
firstDate = firstDate.addDays( -7 );
}
- selectDates( firstDate, 7 );
+ selectDates( firstDate, 7, preferredMonth );
}
void DateNavigator::selectWorkWeek()
@@ -133,7 +140,7 @@ void DateNavigator::selectWorkWeek()
void DateNavigator::selectWorkWeek( const TQDate &d )
{
int weekStart = KGlobal::locale()->weekStartDay();
-
+
int dayOfWeek = KOGlobals::self()->calendarSystem()->dayOfWeek( d );
TQDate currentDate = d.addDays( weekStart - dayOfWeek );
@@ -147,10 +154,10 @@ void DateNavigator::selectWorkWeek( const TQDate &d )
for ( int i = 0; i < 7; ++i ) {
if( (1<< ((i + weekStart + 6) % 7)) & (mask) ) {
- mSelectedDates.append(currentDate.addDays(i));
+ mSelectedDates.append( currentDate.addDays(i) );
}
}
-
+
emitSelected();
}
@@ -160,8 +167,13 @@ void DateNavigator::selectToday()
int dateCount = mSelectedDates.count();
- if ( dateCount == 7 ) selectWeek( d );
- else selectDates( d, dateCount );
+ if ( dateCount == 7 ) {
+ selectWeek( d );
+ } else if ( dateCount == 5 ) {
+ selectWorkWeek( d );
+ } else {
+ selectDates( d, dateCount );
+ }
}
void DateNavigator::selectPreviousYear()
@@ -173,13 +185,14 @@ void DateNavigator::selectPreviousYear()
selectWeekByDay( weekDay, firstSelected );
}
-void DateNavigator::selectPreviousMonth()
+void DateNavigator::selectPreviousMonth( const TQDate &currentMonth,
+ const TQDate &selectionLowerLimit,
+ const TQDate &selectionUpperLimit )
{
- TQDate firstSelected = mSelectedDates.first();
- int weekDay = firstSelected.dayOfWeek();
- firstSelected = KOGlobals::self()->calendarSystem()->addMonths( firstSelected, -1 );
-
- selectWeekByDay( weekDay, firstSelected );
+ shiftMonth( currentMonth,
+ selectionLowerLimit,
+ selectionUpperLimit,
+ -1 );
}
void DateNavigator::selectPreviousWeek()
@@ -201,14 +214,46 @@ void DateNavigator::selectNextWeek()
selectWeekByDay( weekDay, firstSelected );
}
-void DateNavigator::selectNextMonth()
+void DateNavigator::shiftMonth( const TQDate &currentMonth,
+ const TQDate &selectionLowerLimit,
+ const TQDate &selectionUpperLimit,
+ int offset )
{
+ const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem();
+
TQDate firstSelected = mSelectedDates.first();
int weekDay = firstSelected.dayOfWeek();
+ firstSelected = calSys->addMonths( firstSelected, offset );
+
+ /* Don't trust firstSelected to calculate the nextMonth. firstSelected
+ can belong to a month other than currentMonth because KDateNavigator
+ displays 7*6 days. firstSelected should only be used for selection
+ purposes */
+ const TQDate nextMonth = currentMonth.isValid() ?
+ calSys->addMonths( currentMonth, offset ) : firstSelected;
+
+ /* When firstSelected doesn't belong to currentMonth it can happen
+ that the new selection won't be visible on our KDateNavigators
+ so we must adjust it */
+ if ( selectionLowerLimit.isValid() &&
+ firstSelected < selectionLowerLimit ) {
+ firstSelected = selectionLowerLimit;
+ } else if ( selectionUpperLimit.isValid() &&
+ firstSelected > selectionUpperLimit ) {
+ firstSelected = selectionUpperLimit.addDays( -6 );
+ }
- firstSelected = KOGlobals::self()->calendarSystem()->addMonths( firstSelected, 1 );
+ selectWeekByDay( weekDay, firstSelected, nextMonth );
+}
- selectWeekByDay( weekDay, firstSelected );
+void DateNavigator::selectNextMonth( const TQDate &currentMonth,
+ const TQDate &selectionLowerLimit,
+ const TQDate &selectionUpperLimit )
+{
+ shiftMonth( currentMonth,
+ selectionLowerLimit,
+ selectionUpperLimit,
+ 1 );
}
void DateNavigator::selectNextYear()
@@ -240,26 +285,41 @@ void DateNavigator::selectNext()
selectDates( mSelectedDates.first().addDays( offset ), datesCount() );
}
-void DateNavigator::selectMonth(int month)
+void DateNavigator::selectMonth( int month )
{
+ const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem();
+
TQDate firstSelected = mSelectedDates.first();
int weekDay = firstSelected.dayOfWeek();
- const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem();
int day = calSys->day( firstSelected );
- calSys->setYMD( firstSelected, calSys->year(firstSelected), month, 1 );
+ calSys->setYMD( firstSelected, calSys->year( firstSelected ), month, 1 );
int days = calSys->daysInMonth( firstSelected );
// As day we use either the selected date, or if the month has less days
// than that, we use the max day of that month
- if ( day > days ) day = days;
+ if ( day > days ) {
+ day = days;
+ }
+ TQDate requestedMonth;
calSys->setYMD( firstSelected, calSys->year( firstSelected ), month, day );
+ calSys->setYMD( requestedMonth, calSys->year( firstSelected ), month, 1 );
+
+ selectWeekByDay( weekDay, firstSelected, requestedMonth );
+}
+void DateNavigator::selectYear( int year )
+{
+ TQDate firstSelected = mSelectedDates.first();
+ int deltaYear = year - KOGlobals::self()->calendarSystem()->year( firstSelected );
+ firstSelected = KOGlobals::self()->calendarSystem()->addYears( firstSelected, deltaYear );
+
+ int weekDay = firstSelected.dayOfWeek();
selectWeekByDay( weekDay, firstSelected );
}
-void DateNavigator::emitSelected()
+void DateNavigator::emitSelected( const TQDate &preferredMonth )
{
- emit datesSelected( mSelectedDates );
+ emit datesSelected( mSelectedDates, preferredMonth );
}
#include "datenavigator.moc"
diff --git a/korganizer/datenavigator.h b/korganizer/datenavigator.h
index d91bad318..ddb6cf2c8 100644
--- a/korganizer/datenavigator.h
+++ b/korganizer/datenavigator.h
@@ -49,38 +49,61 @@ class DateNavigator : public QObject
void selectDate( const TQDate & );
void selectDates( int count );
- void selectDates( const TQDate &, int count );
+ void selectDates( const TQDate &, int count, const TQDate &preferredMonth = TQDate() );
void selectWeek();
- void selectWeek( const TQDate & );
+ void selectWeek( const TQDate &, const TQDate &preferredMonth = TQDate() );
void selectWorkWeek();
void selectWorkWeek( const TQDate & );
- void selectWeekByDay( int weekDay, const TQDate & );
-
+ void selectWeekByDay( int weekDay, const TQDate &, const TQDate &preferredMonth = TQDate() );
+
void selectToday();
-
+
void selectPreviousYear();
- void selectPreviousMonth();
+ void selectPreviousMonth( const TQDate &currentMonth = TQDate(),
+ const TQDate &selectionLowerLimit = TQDate(),
+ const TQDate &selectionUpperLimit = TQDate() );
void selectPreviousWeek();
void selectNextWeek();
- void selectNextMonth();
+ void selectNextMonth( const TQDate &currentMonth = TQDate(),
+ const TQDate &selectionLowerLimit = TQDate(),
+ const TQDate &selectionUpperLimit = TQDate() );
void selectNextYear();
-
+
void selectPrevious();
void selectNext();
- void selectMonth(int month);
-
+ void selectMonth( int month );
+ void selectYear( int year );
+
signals:
- void datesSelected( const KCal::DateList & );
+ /* preferredMonth is useful when the datelist crosses months,
+ if valid, any month-like component should honour it
+ */
+ void datesSelected( const KCal::DateList &, const TQDate &preferredMonth );
protected:
- void emitSelected();
+ void emitSelected( const TQDate &preferredMonth = TQDate() );
private:
+
+ /*
+ Selects next month if offset equals 1, or previous month
+ if offset equals -1.
+ Bigger offsets are accepted.
+ */
+ void shiftMonth( const TQDate &date,
+ const TQDate &selectionLowerLimit,
+ const TQDate &selectionUpperLimit,
+ int offset );
+
KCal::DateList mSelectedDates;
+
+ enum {
+ MAX_SELECTABLE_DAYS = 50
+ };
};
#endif
diff --git a/korganizer/datenavigatorcontainer.cpp b/korganizer/datenavigatorcontainer.cpp
index e3c092fc0..ac0892947 100644
--- a/korganizer/datenavigatorcontainer.cpp
+++ b/korganizer/datenavigatorcontainer.cpp
@@ -29,6 +29,7 @@
#include "koglobals.h"
#include "navigatorbar.h"
#include "kdatenavigator.h"
+#include "kodaymatrix.h"
#include <kcalendarsystem.h>
#include <kdialog.h>
@@ -79,12 +80,14 @@ void DateNavigatorContainer::connectNavigatorView( KDateNavigator *v )
connect( v, TQT_SIGNAL( goPrevious() ), TQT_SIGNAL( goPrevious() ) );
connect( v, TQT_SIGNAL( goNext() ), TQT_SIGNAL( goNext() ) );
- connect( v, TQT_SIGNAL( goNextMonth() ), TQT_SIGNAL( goNextMonth() ) );
- connect( v, TQT_SIGNAL( goPrevMonth() ), TQT_SIGNAL( goPrevMonth() ) );
- connect( v, TQT_SIGNAL( goNextYear() ), TQT_SIGNAL( goNextYear() ) );
- connect( v, TQT_SIGNAL( goPrevYear() ), TQT_SIGNAL( goPrevYear() ) );
+ connect( v, TQT_SIGNAL( nextYearClicked() ), TQT_SIGNAL( nextYearClicked() ) );
+ connect( v, TQT_SIGNAL( prevYearClicked() ), TQT_SIGNAL( prevYearClicked() ) );
- connect( v, TQT_SIGNAL( goMonth( int ) ), TQT_SIGNAL( goMonth( int ) ) );
+ connect( v, TQT_SIGNAL( prevMonthClicked() ), this, TQT_SLOT( goPrevMonth() ) );
+ connect( v, TQT_SIGNAL( nextMonthClicked() ), this, TQT_SLOT( goNextMonth() ) );
+
+ connect( v, TQT_SIGNAL( monthSelected( int ) ), TQT_SIGNAL( monthSelected( int ) ) );
+ connect( v, TQT_SIGNAL( yearSelected( int ) ), TQT_SIGNAL( yearSelected( int ) ) );
}
void DateNavigatorContainer::setCalendar( Calendar *cal )
@@ -118,12 +121,21 @@ void DateNavigatorContainer::updateToday()
}
}
+void DateNavigatorContainer::setUpdateNeeded()
+{
+ mNavigatorView->setUpdateNeeded();
+ KDateNavigator *n;
+ for ( n = mExtraViews.first(); n; n = mExtraViews.next() ) {
+ n->setUpdateNeeded();
+ }
+}
+
void DateNavigatorContainer::updateView()
{
mNavigatorView->updateView();
KDateNavigator *n;
- for( n = mExtraViews.first(); n; n = mExtraViews.next() ) {
- n->updateView();
+ for ( n = mExtraViews.first(); n; n = mExtraViews.next() ) {
+ n->setUpdateNeeded();
}
}
@@ -136,7 +148,7 @@ void DateNavigatorContainer::updateConfig()
}
}
-void DateNavigatorContainer::selectDates( const DateList &dateList )
+void DateNavigatorContainer::selectDates( const DateList &dateList, const TQDate &preferredMonth )
{
if ( !dateList.isEmpty() ) {
TQDate start( dateList.first() );
@@ -151,11 +163,24 @@ void DateNavigatorContainer::selectDates( const DateList &dateList )
navlast = mNavigatorView->endDate();
navsecond = navfirst;
}
+
+ const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem();
+
+ // If the datelist crosses months we won't know which month to show
+ // so we read what's in preferredMonth
+ const bool changingMonth = ( preferredMonth.isValid() &&
+ calSys->month( mNavigatorView->month() ) != calSys->month( preferredMonth ) );
+
if ( start < navfirst // <- start should always be visible
// end is not visible and we have a spare month at the beginning:
- || ( end > navlast && start >= navsecond ) ) {
- // Change the shown months so that the beginning of the date list is visible
- setBaseDates( start );
+ || ( end > navlast && start >= navsecond )
+ || changingMonth ) {
+
+ if ( preferredMonth.isValid() ) {
+ setBaseDates( preferredMonth );
+ } else {
+ setBaseDates( start );
+ }
}
mNavigatorView->selectDates( dateList );
@@ -202,7 +227,9 @@ void DateNavigatorContainer::resizeAllContents()
if ( horizontalCount != mHorizontalCount ||
verticalCount != mVerticalCount ) {
uint count = horizontalCount * verticalCount;
- if ( count == 0 ) return;
+ if ( count == 0 ) {
+ return;
+ }
while ( count > ( mExtraViews.count() + 1 ) ) {
KDateNavigator *n = new KDateNavigator( this );
@@ -228,22 +255,30 @@ void DateNavigatorContainer::resizeAllContents()
int width = (size().width() - margin*2) / horizontalCount;
NavigatorBar *bar = mNavigatorView->navigatorBar();
- if ( horizontalCount > 1 ) bar->showButtons( true, false );
- else bar->showButtons( true, true );
+ if ( horizontalCount > 1 ) {
+ bar->showButtons( true, false );
+ } else {
+ bar->showButtons( true, true );
+ }
mNavigatorView->setGeometry(
( ( (KOGlobals::self()->reverseLayout())?(horizontalCount-1):0) * width ) + margin,
margin, width, height );
+
for( uint i = 0; i < mExtraViews.count(); ++i ) {
int x = ( i + 1 ) % horizontalCount;
int y = ( i + 1 ) / horizontalCount;
KDateNavigator *view = mExtraViews.at( i );
bar = view->navigatorBar();
- if ( y > 0 ) bar->showButtons( false, false );
- else {
- if ( x + 1 == horizontalCount ) bar->showButtons( false, true );
- else bar->showButtons( false, false );
+ if ( y > 0 ) {
+ bar->showButtons( false, false );
+ } else {
+ if ( x + 1 == horizontalCount ) {
+ bar->showButtons( false, true );
+ } else {
+ bar->showButtons( false, false );
+ }
}
view->setGeometry(
( ( (KOGlobals::self()->reverseLayout())?(horizontalCount-1-x):x) * width ) + margin,
@@ -263,4 +298,41 @@ TQSize DateNavigatorContainer::sizeHint() const
return mNavigatorView->sizeHint() + TQSize( margin, margin );
}
+void DateNavigatorContainer::goNextMonth()
+{
+ const QPair<TQDate,TQDate> p = dateLimits( 1 );
+
+ emit nextMonthClicked( mNavigatorView->month(),
+ p.first,
+ p.second);
+}
+
+void DateNavigatorContainer::goPrevMonth()
+{
+ const QPair<TQDate,TQDate> p = dateLimits( -1 );
+
+ emit prevMonthClicked( mNavigatorView->month(),
+ p.first,
+ p.second );
+}
+
+QPair<TQDate,TQDate> DateNavigatorContainer::dateLimits( int offset )
+{
+ const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem();
+ TQDate firstMonth, lastMonth;
+ if ( mExtraViews.isEmpty() ) {
+ lastMonth = mNavigatorView->month();
+ } else {
+ lastMonth = mExtraViews.last()->month();
+ }
+
+ firstMonth = calSys->addMonths( mNavigatorView->month(), offset );
+ lastMonth = calSys->addMonths( lastMonth, offset );
+
+ QPair<TQDate,TQDate> firstMonthBoundary = KODayMatrix::matrixLimits( firstMonth );
+ QPair<TQDate,TQDate> lastMonthBoundary = KODayMatrix::matrixLimits( lastMonth );
+
+ return qMakePair( firstMonthBoundary.first, lastMonthBoundary.second );
+}
+
#include "datenavigatorcontainer.moc"
diff --git a/korganizer/datenavigatorcontainer.h b/korganizer/datenavigatorcontainer.h
index 2facad303..e30f19b42 100644
--- a/korganizer/datenavigatorcontainer.h
+++ b/korganizer/datenavigatorcontainer.h
@@ -43,29 +43,53 @@ class DateNavigatorContainer: public QFrame
TQSize minimumSizeHint() const;
TQSize sizeHint() const;
-
+ void setUpdateNeeded();
public slots:
- void selectDates( const KCal::DateList & );
+ /**
+ preferredMonth is useful when the datelist crosses months, if different
+ from -1, it has the month that the kdatenavigator should show in case
+ of ambiguity
+ */
+ void selectDates( const KCal::DateList &, const TQDate &preferredMonth = TQDate() );
void updateView();
void updateConfig();
void updateDayMatrix();
void updateToday();
+ void goPrevMonth();
+ void goNextMonth();
+
signals:
void datesSelected( const KCal::DateList & );
void incidenceDropped( Incidence *, const TQDate & );
void incidenceDroppedMove( Incidence *, const TQDate & );
- void weekClicked( const TQDate &);
+ void weekClicked( const TQDate & );
void goPrevious();
void goNext();
- void goNextMonth();
- void goPrevMonth();
- void goNextYear();
- void goPrevYear();
+ void nextYearClicked();
+ void prevYearClicked();
- void goMonth( int month );
+ /** Signals that the previous month button has been clicked.
+
+ @param currentMonth The month displayed on the first KDateNavigator.
+ DateNavigator doesn't know anything abouts months, it just has
+ a list of selected dates, so we must send this.
+ @param selectionLowerLimit The first date of the first KDateNavigator.
+ @param selectionUpperLimit The last date of the last KDateNavigator.
+ */
+ void prevMonthClicked( const TQDate &currentMonth,
+ const TQDate &selectionLowerLimit,
+ const TQDate &selectionUpperLimit );
+
+ void nextMonthClicked( const TQDate &currentMonth,
+ const TQDate &selectionLowerLimit,
+ const TQDate &selectionUpperLimit );
+
+ void monthSelected( int month );
+
+ void yearSelected( int year );
protected:
void resizeEvent( TQResizeEvent * );
@@ -79,6 +103,15 @@ class DateNavigatorContainer: public QFrame
void resizeAllContents();
private:
+ /* Returns the first day of the first KDateNavigator, and the last day
+ of the last KDateNavigator.
+
+ @param monthOffset If you have two KDateNavigators displaying January and February
+ and want to know the boundaries of, for e.g. displaying February and March,
+ use monthOffset = 1.
+ */
+ QPair<TQDate,TQDate> dateLimits( int monthOffset = 0 );
+
KDateNavigator *mNavigatorView;
KCal::Calendar *mCalendar;
diff --git a/korganizer/dcopcalendar.desktop b/korganizer/dcopcalendar.desktop
index df5c098a8..ac1ccf4ee 100644
--- a/korganizer/dcopcalendar.desktop
+++ b/korganizer/dcopcalendar.desktop
@@ -29,7 +29,6 @@ Comment[hu]=Határidőnapló DCOP-felülettel
Comment[is]=Skipuleggjari með DCOP viðmóti
Comment[it]=Organizer con un'interfaccia DCOP
Comment[ja]=DCOP インターフェースを持つオーガナイザ
-Comment[ka]=ორგანიზატორი DCOP ინტერფეისით
Comment[kk]=DCOP интерфейсті Ұйымдастырғыш
Comment[km]=កម្មវិធី​រៀបចំ​ដែល​មាន​ចំណុច​ប្រទាក់ DCOP
Comment[lt]=Tvarkyklė su DCOP sąsaja
diff --git a/korganizer/eventarchiver.cpp b/korganizer/eventarchiver.cpp
index b5a9c0c98..c4adbf820 100644
--- a/korganizer/eventarchiver.cpp
+++ b/korganizer/eventarchiver.cpp
@@ -70,14 +70,15 @@ void EventArchiver::runAuto( Calendar* calendar, TQWidget* widget, bool withGUI
run( calendar, limitDate, widget, withGUI, false );
}
-void EventArchiver::run( Calendar* calendar, const TQDate& limitDate, TQWidget* widget, bool withGUI, bool errorIfNone )
+void EventArchiver::run( Calendar* calendar, const TQDate& limitDate, TQWidget* widget, bool withGUI,
+ bool errorIfNone )
{
// We need to use rawEvents, otherwise events hidden by filters will not be archived.
Incidence::List incidences;
Event::List events;
Todo::List todos;
Journal::List journals;
-
+
if ( KOPrefs::instance()->mArchiveEvents ) {
events = calendar->rawEvents(
TQDate( 1769, 12, 1 ),
@@ -89,21 +90,37 @@ void EventArchiver::run( Calendar* calendar, const TQDate& limitDate, TQWidget*
Todo::List t = calendar->rawTodos();
Todo::List::ConstIterator it;
for( it = t.begin(); it != t.end(); ++it ) {
- if ( (*it) && ( (*it)->isCompleted() ) && ( (*it)->completed().date() < limitDate ) ) {
+ const bool todoComplete = (*it) &&
+ (*it)->isCompleted() &&
+ ( (*it)->completed().date() < limitDate );
+
+ if ( todoComplete && !isSubTreeComplete( *it, limitDate ) ) {
+ // The to-do is complete but some sub-todos are not.
+ KMessageBox::information(
+ widget,
+ i18n( "Unable to archive to-do \"%1\" because at least one of its "
+ "sub-to-dos does not meet the archival requirements." ).arg( (*it)->summary() ),
+ i18n( "Archive To-do" ),
+ "UncompletedChildrenArchiveTodos" );
+ } else if ( todoComplete ) {
todos.append( *it );
}
}
}
-
+
incidences = Calendar::mergeIncidenceList( events, todos, journals );
-
- kdDebug(5850) << "EventArchiver: archiving incidences before " << limitDate << " -> " << incidences.count() << " incidences found." << endl;
+
+ kdDebug(5850) << "EventArchiver: archiving incidences before " << limitDate << " -> "
+ << incidences.count() << " incidences found." << endl;
if ( incidences.isEmpty() ) {
- if ( withGUI && errorIfNone )
- KMessageBox::information( widget, i18n("There are no items before %1")
- .arg(KGlobal::locale()->formatDate(limitDate)),
- "ArchiverNoIncidences" );
+ if ( withGUI && errorIfNone ) {
+ KMessageBox::information(
+ widget,
+ i18n( "There are no incidences available to archive before the specified cut-off date %1. "
+ "Archiving will not be performed." ).arg( KGlobal::locale()->formatDate( limitDate ) ),
+ "ArchiverNoIncidences" );
+ }
return;
}
@@ -222,4 +239,35 @@ void EventArchiver::archiveIncidences( Calendar* calendar, const TQDate& /*limit
emit eventsDeleted();
}
+bool EventArchiver::isSubTreeComplete( const Todo *todo, const TQDate &limitDate,
+ TQStringList checkedUids ) const
+{
+ if ( !todo || !todo->isCompleted() || todo->completed().date() >= limitDate ) {
+ return false;
+ }
+
+ // This QList is only to prevent infinit recursion
+ if ( checkedUids.contains( todo->uid() ) ) {
+ // Probably will never happen, calendar.cpp checks for this
+ kdWarning() << "To-do hierarchy loop detected!";
+ return false;
+ }
+
+ checkedUids.append( todo->uid() );
+
+ Incidence::List::ConstIterator it;
+ const Incidence::List relations = todo->relations();
+
+ for( it = relations.begin(); it != relations.end(); ++it ) {
+ if ( (*it)->type() == "Todo" ) {
+ const Todo *t = static_cast<const Todo*>( *it );
+ if ( !isSubTreeComplete( t, limitDate, checkedUids ) ) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
#include "eventarchiver.moc"
diff --git a/korganizer/eventarchiver.h b/korganizer/eventarchiver.h
index 4d5a8544d..01897b7ec 100644
--- a/korganizer/eventarchiver.h
+++ b/korganizer/eventarchiver.h
@@ -77,8 +77,20 @@ class EventArchiver : public QObject
private:
void run( Calendar* calendar, const TQDate& limitDate, TQWidget* widget, bool withGUI, bool errorIfNone );
- void deleteIncidences( Calendar* calendar, const TQDate& limitDate, TQWidget* widget, const Incidence::List& incidences, bool withGUI );
- void archiveIncidences( Calendar* calendar, const TQDate& limitDate, TQWidget* widget, const Incidence::List& incidences, bool withGUI );
+ void deleteIncidences( Calendar* calendar, const TQDate& limitDate, TQWidget* widget,
+ const Incidence::List& incidences, bool withGUI );
+ void archiveIncidences( Calendar* calendar, const TQDate& limitDate, TQWidget* widget,
+ const Incidence::List& incidences, bool withGUI );
+
+ /**
+ * Checks if all to-dos under @p todo and including @p todo were completed before @p limitDate.
+ * If not, we can't archive this to-do.
+ * @param todo root of the sub-tree we are checking
+ * @param limitDate
+ * @param checkedUids used internaly to prevent infinit recursion due to invalid calendar files
+ */
+ bool isSubTreeComplete( const Todo *todo, const TQDate &limitDate,
+ TQStringList checkedUids = TQStringList() ) const;
};
#endif /* EVENTARCHIVER_H */
diff --git a/korganizer/exportwebdialog.cpp b/korganizer/exportwebdialog.cpp
index c926ad053..869c5b963 100644
--- a/korganizer/exportwebdialog.cpp
+++ b/korganizer/exportwebdialog.cpp
@@ -85,6 +85,7 @@ ExportWebDialog::ExportWebDialog( HTMLExportSettings *settings, TQWidget *parent
connect( this, TQT_SIGNAL( cancelClicked() ), TQT_SLOT( reject() ) );
readConfig();
+ updateState();
}
ExportWebDialog::~ExportWebDialog()
@@ -139,16 +140,18 @@ void ExportWebDialog::setupGeneralPage()
mGeneralPage = addPage( i18n("General") );
TQVBoxLayout *topLayout = new TQVBoxLayout(mGeneralPage, 10);
- TQGroupBox *rangeGroup = new TQHGroupBox( i18n("Date Range"), mGeneralPage );
- topLayout->addWidget( rangeGroup );
- addWidDate( mSettings->dateStartItem(), rangeGroup );
- addWidDate( mSettings->dateEndItem(), rangeGroup );
+ mDateRangeBox = new TQHGroupBox( i18n("Date Range"), mGeneralPage );
+ topLayout->addWidget( mDateRangeBox );
+ addWidDate( mSettings->dateStartItem(), mDateRangeBox );
+ addWidDate( mSettings->dateEndItem(), mDateRangeBox );
TQButtonGroup *typeGroup = new TQVButtonGroup( i18n("View Type"), mGeneralPage );
topLayout->addWidget( typeGroup );
// addWidBool( mSettings->weekViewItem(), typeGroup );
- addWidBool( mSettings->monthViewItem(), typeGroup );
- addWidBool( mSettings->eventViewItem(), typeGroup );
+ mMonthViewCheckBox = addWidBool( mSettings->monthViewItem(), typeGroup )->checkBox();
+ connect( mMonthViewCheckBox, TQT_SIGNAL(toggled(bool)), TQT_SLOT(updateState()) );
+ mEventListCheckBox = addWidBool( mSettings->eventViewItem(), typeGroup )->checkBox();
+ connect( mEventListCheckBox, TQT_SIGNAL(toggled(bool)), TQT_SLOT(updateState()) );
addWidBool( mSettings->todoViewItem(), typeGroup );
// addWidBool( mSettings->journalViewItem(), typeGroup );
// addWidBool( mSettings->freeBusyViewItem(), typeGroup );
@@ -255,3 +258,11 @@ void ExportWebDialog::setupAdvancedPage()
topLayout->addStretch(1);
}
*/
+
+void ExportWebDialog::updateState()
+{
+ const bool exportEvents = mMonthViewCheckBox->isChecked() || mEventListCheckBox->isChecked();
+ mDateRangeBox->setEnabled( exportEvents );
+ mEventPage->setEnabled( exportEvents );
+}
+
diff --git a/korganizer/exportwebdialog.h b/korganizer/exportwebdialog.h
index 4d2dcd39c..27a0a9860 100644
--- a/korganizer/exportwebdialog.h
+++ b/korganizer/exportwebdialog.h
@@ -27,6 +27,7 @@
#include <libkdepim/kprefsdialog.h>
class HTMLExportSettings;
+class TQGroupBox;
using namespace KCal;
@@ -70,6 +71,9 @@ class ExportWebDialog : public KDialogBase, public KPrefsWidManager
protected:
virtual void usrReadConfig() {}
virtual void usrWriteConfig() {}
+
+ private slots:
+ void updateState();
private:
HTMLExportSettings* mSettings;
@@ -79,6 +83,10 @@ class ExportWebDialog : public KDialogBase, public KPrefsWidManager
// TQFrame *mJournalPage;
// TQFrame *mFreeBusyPage;
// TQFrame *mAdvancedPage;
+
+ TQCheckBox *mMonthViewCheckBox;
+ TQCheckBox *mEventListCheckBox;
+ TQGroupBox *mDateRangeBox;
};
#endif // _EXPORTWEBDIALOG_H
diff --git a/korganizer/freebusymanager.cpp b/korganizer/freebusymanager.cpp
index 81b65a3b7..65f945bad 100644
--- a/korganizer/freebusymanager.cpp
+++ b/korganizer/freebusymanager.cpp
@@ -39,6 +39,8 @@
#include "koprefs.h"
#include "mailscheduler.h"
+#include "actionmanager.h"
+#include "korganizer.h"
#include <libkcal/incidencebase.h>
#include <libkcal/attendee.h>
@@ -76,6 +78,10 @@ FreeBusyDownloadJob::FreeBusyDownloadJob( const TQString &email, const KURL &url
: TQObject( manager, name ), mManager( manager ), mEmail( email )
{
KIO::TransferJob *job = KIO::get( url, false, false );
+ //pass the mainwindow to the job so any prompts are active
+ KOrg::MainWindow *korg = ActionManager::findInstance( KURL() );
+ job->setWindow( korg->topLevelWidget() );
+
connect( job, TQT_SIGNAL( result( KIO::Job * ) ),
TQT_SLOT( slotResult( KIO::Job * ) ) );
connect( job, TQT_SIGNAL( data( KIO::Job *, const TQByteArray & ) ),
@@ -224,7 +230,7 @@ void FreeBusyManager::publishFreeBusy()
// Already uploading? Skip this one then.
if ( mUploadingFreeBusy )
return;
- KURL targetURL ( KOPrefs::instance()->freeBusyPublishUrl() );
+ KURL targetURL( KOPrefs::instance()->freeBusyPublishUrl() );
if ( targetURL.isEmpty() ) {
KMessageBox::sorry( 0,
i18n( "<qt>No URL configured for uploading your free/busy list. Please "
@@ -329,6 +335,10 @@ void FreeBusyManager::publishFreeBusy()
true /*overwrite*/,
false /*don't resume*/,
false /*don't show progress info*/ );
+ //pass the mainwindow to the job so any prompts are active
+ KOrg::MainWindow *korg = ActionManager::findInstance( KURL() );
+ job->setWindow( korg->topLevelWidget() );
+
connect( job, TQT_SIGNAL( result( KIO::Job * ) ),
TQT_SLOT( slotUploadFreeBusyResult( KIO::Job * ) ) );
}
@@ -386,11 +396,10 @@ bool FreeBusyManager::processRetrieveQueue()
KURL sourceURL = freeBusyUrl( email );
- DEBUG_5850 << "FreeBusyManager::processRetrieveQueue(): url: " << sourceURL
- << endl;
+ kdDebug(5850) << "FreeBusyManager::processRetrieveQueue(): url: " << sourceURL << endl;
if ( !sourceURL.isValid() ) {
- DEBUG_5850 << "Invalid FB URL\n";
+ kdDebug(5850) << "Invalid FB URL\n";
slotFreeBusyDownloadError( email );
return false;
}
@@ -429,6 +438,43 @@ void FreeBusyManager::cancelRetrieval()
mRetrieveQueue.clear();
}
+KURL replaceVariablesURL( const KURL &url, const TQString &email )
+{
+ TQString emailName, emailHost;
+ int emailpos = email.find( '@' );
+ if( emailpos >= 0 ) {
+ emailName = email.left( emailpos );
+ emailHost = email.mid( emailpos + 1 );
+ }
+
+ TQString saveStr = url.path();
+ saveStr.replace( TQRegExp( "%[Ee][Mm][Aa][Ii][Ll]%" ), email );
+ saveStr.replace( TQRegExp( "%[Nn][Aa][Mm][Ee]%" ), emailName );
+ saveStr.replace( TQRegExp( "%[Ss][Ee][Rr][Vv][Ee][Rr]%" ), emailHost );
+
+ KURL retUrl( url );
+ retUrl.setPath( saveStr );
+ return retUrl;
+}
+
+bool fbExists( const KURL &url )
+{
+ // We need this function because using KIO::NetAccess::exists()
+ // is useless for the http and https protocols. And getting back
+ // arbitrary data is also useless because a server can respond back
+ // with a "no such document" page. So we need smart checking.
+
+ KIO::Job *job = KIO::get( url, false, false );
+ TQByteArray data;
+ if ( KIO::NetAccess::synchronousRun( job, 0, &data ) ) {
+ TQString dataStr ( data );
+ if ( dataStr.contains( "BEGIN:VCALENDAR" ) ) {
+ return true;
+ }
+ }
+ return false;
+}
+
KURL FreeBusyManager::freeBusyUrl( const TQString &email )
{
DEBUG_5850 << "FreeBusyManager::freeBusyUrl(): " << email << endl;
@@ -440,9 +486,15 @@ KURL FreeBusyManager::freeBusyUrl( const TQString &email )
cfg.setGroup( email );
TQString url = cfg.readEntry( "url" );
if ( !url.isEmpty() ) {
- DEBUG_5850 << "found cached url: " << url << endl;
- return KURL( url );
+ kdDebug(5850) << "found cached url: " << url << endl;
+ KURL cachedURL( url );
+ if ( KOPrefs::instance()->thatIsMe( email ) ) {
+ cachedURL.setUser( KOPrefs::instance()->mFreeBusyRetrieveUser );
+ cachedURL.setPass( KOPrefs::instance()->mFreeBusyRetrievePassword );
+ }
+ return replaceVariablesURL( cachedURL, email );
}
+
// Try with the url configurated by preferred email in kaddressbook
KABC::Addressee::List list= KABC::StdAddressBook::self( true )->findByEmail( email );
KABC::Addressee::List::Iterator it;
@@ -450,14 +502,14 @@ KURL FreeBusyManager::freeBusyUrl( const TQString &email )
for ( it = list.begin(); it != list.end(); ++it ) {
pref = (*it).preferredEmail();
if ( !pref.isEmpty() && pref != email ) {
- kdDebug( 5850 ) << "FreeBusyManager::freeBusyUrl():" <<
- "Preferred email of " << email << " is " << pref << endl;
+ kdDebug(5850) << "FreeBusyManager::freeBusyUrl():"
+ << "Preferred email of " << email << " is " << pref << endl;
cfg.setGroup( pref );
url = cfg.readEntry ( "url" );
if ( !url.isEmpty() ) {
- kdDebug( 5850 ) << "FreeBusyManager::freeBusyUrl():" <<
- "Taken url from preferred email:" << url << endl;
- return KURL( url );
+ kdDebug(5850) << "FreeBusyManager::freeBusyUrl():"
+ << "Taken url from preferred email:" << url << endl;
+ return replaceVariablesURL( KURL( url ), email );
}
}
}
@@ -487,54 +539,81 @@ KURL FreeBusyManager::freeBusyUrl( const TQString &email )
// Don't try to fetch free/busy data for users not on the specified servers
// This tests if the hostnames match, or one is a subset of the other
const TQString hostDomain = sourceURL.host();
- if ( hostDomain != emailHost && !hostDomain.endsWith( '.' + emailHost )
- && !emailHost.endsWith( '.' + hostDomain ) ) {
+ if ( hostDomain != emailHost &&
+ !hostDomain.endsWith( '.' + emailHost ) &&
+ !emailHost.endsWith( '.' + hostDomain ) ) {
// Host names do not match
- DEBUG_5850 << "Host '" << sourceURL.host() << "' doesn't match email '"
- << email << '\'' << endl;
+ kdDebug(5850) << "Host '" << sourceURL.host() << "' doesn't match email '" << email << endl;
return KURL();
}
}
- // This should work with anything thrown at it, not just Kolab
- // Notice that Kolab URLs are just entered as the base address, e.g. http://server.com/mykolab/
- // This means that if the trailing slash is not entered, we can treat this as a custom, non-Kolab URL!
- // In that case, just pass it on through with substitution for %u and %d
- // TODO: May want an explicit configuration option in kogroupwareprefspage.ui for this
- if ((sourceURL.url().endsWith("/", true) == false) || (sourceURL.url().contains("%25u", true)) || (sourceURL.url().contains("%25d", true))) {
- // A generic URL, substitute %u and %d
- sourceURL = sourceURL.url().replace("%25u", emailName, true);
- sourceURL = sourceURL.url().replace("%25d", emailHost, true);
- sourceURL.setUser( KOPrefs::instance()->mFreeBusyRetrieveUser );
- sourceURL.setPass( KOPrefs::instance()->mFreeBusyRetrievePassword );
- return sourceURL;
+ if ( sourceURL.url().contains( TQRegExp( "\\.[xiv]fb$" ) ) ) { // user specified a fullpath
+ // do variable string replacements to the URL (MS Outlook style)
+ KURL fullpathURL = replaceVariablesURL( sourceURL, email );
+
+ // This should work with anything thrown at it, not just Kolab
+ // Notice that Kolab URLs are just entered as the base address, e.g. http://server.com/mykolab/
+ // This means that if the trailing slash is not entered, we can treat this as a custom, non-Kolab URL!
+ // In that case, just pass it on through with substitution for %u and %d
+ // TODO: May want an explicit configuration option in kogroupwareprefspage.ui for this
+ if ((fullpathURL.url().endsWith("/", true) == false) || (fullpathURL.url().contains("%25u", true)) || (fullpathURL.url().contains("%25d", true))) {
+ // A generic URL, substitute %u and %d
+ fullpathURL = fullpathURL.url().replace("%25u", emailName, true);
+ fullpathURL = fullpathURL.url().replace("%25d", emailHost, true);
+ }
+ else {
+ // This is (probably) a Kolab URL!
+ }
+
+ // set the User and Password part of the URL
+ fullpathURL.setUser( KOPrefs::instance()->mFreeBusyRetrieveUser );
+ fullpathURL.setPass( KOPrefs::instance()->mFreeBusyRetrievePassword );
+
+ // no need to cache this URL as this is pretty fast to get from the config value.
+
+ // return the fullpath URL
+ return fullpathURL;
}
- else {
- // This is (probably) a Kolab URL!
- DEBUG_5850 << "Server FreeBusy url: " << sourceURL << endl;
- if ( KOPrefs::instance()->mFreeBusyFullDomainRetrieval )
- sourceURL.setFileName( email + ".ifb" );
- else
- sourceURL.setFileName( emailName + ".ifb" );
- sourceURL.setUser( KOPrefs::instance()->mFreeBusyRetrieveUser );
- sourceURL.setPass( KOPrefs::instance()->mFreeBusyRetrievePassword );
-
- DEBUG_5850 << "Results in generated: " << sourceURL << endl;
- return sourceURL;
+
+ // else we search for a fb file in the specified URL with known possible extensions
+
+ TQStringList extensions;
+ extensions << "xfb" << "ifb" << "vfb";
+ TQStringList::ConstIterator ext;
+ for ( ext = extensions.constBegin(); ext != extensions.constEnd(); ++ext ) {
+ // build a url for this extension
+ sourceURL = KOPrefs::instance()->mFreeBusyRetrieveUrl;
+ KURL dirURL = replaceVariablesURL( sourceURL, email );
+ if ( KOPrefs::instance()->mFreeBusyFullDomainRetrieval ) {
+ dirURL.addPath( email + '.' + (*ext) );
+ } else {
+ dirURL.addPath( emailName + '.' + (*ext ) );
+ }
+ dirURL.setUser( KOPrefs::instance()->mFreeBusyRetrieveUser );
+ dirURL.setPass( KOPrefs::instance()->mFreeBusyRetrievePassword );
+ if ( fbExists( dirURL ) ) {
+ // write the URL to the cache
+ cfg.setGroup( email );
+ cfg.writeEntry( "url", dirURL.prettyURL() ); // prettyURL() does not write user nor password
+ return dirURL;
+ }
}
+
+ return KURL();
}
KCal::FreeBusy *FreeBusyManager::iCalToFreeBusy( const TQCString &data )
{
- DEBUG_5850 << "FreeBusyManager::iCalToFreeBusy()" << endl;
- DEBUG_5850 << data << endl;
+ kdDebug(5850) << "FreeBusyManager::iCalToFreeBusy()" << endl;
+ kdDebug(5850) << data << endl;
TQString freeBusyVCal = TQString::fromUtf8( data );
KCal::FreeBusy *fb = mFormat.parseFreeBusy( freeBusyVCal );
if ( !fb ) {
- DEBUG_5850 << "FreeBusyManager::iCalToFreeBusy(): Error parsing free/busy"
+ kdDebug(5850) << "FreeBusyManager::iCalToFreeBusy(): Error parsing free/busy"
<< endl;
- DEBUG_5850 << freeBusyVCal << endl;
+ kdDebug(5850) << freeBusyVCal << endl;
}
return fb;
}
@@ -553,7 +632,7 @@ FreeBusy *FreeBusyManager::loadFreeBusy( const TQString &email )
TQFile f( fbd + "/" + email + ".ifb" );
if ( !f.exists() ) {
DEBUG_5850 << "FreeBusyManager::loadFreeBusy() " << f.name()
- << " doesn't exist." << endl;
+ << " doesn't exist." << endl;
return 0;
}
diff --git a/korganizer/freebusymanager.h b/korganizer/freebusymanager.h
index a91d9f36d..a6f4f6cec 100644
--- a/korganizer/freebusymanager.h
+++ b/korganizer/freebusymanager.h
@@ -117,7 +117,7 @@ class FreeBusyManager : public TQObject, public KCal::FreeBusyCache
KURL freeBusyUrl( const TQString &email );
/**
- Return directory used for stroing free/busy information.
+ Return directory used for storing free/busy information.
*/
TQString freeBusyDir();
@@ -173,7 +173,6 @@ class FreeBusyManager : public TQObject, public KCal::FreeBusyCache
int mTimerID;
bool mUploadingFreeBusy;
bool mBrokenUrl;
-
};
#endif
diff --git a/korganizer/importdialog.cpp b/korganizer/importdialog.cpp
index f1181225d..5f4dce6a5 100644
--- a/korganizer/importdialog.cpp
+++ b/korganizer/importdialog.cpp
@@ -37,15 +37,15 @@
using namespace KCal;
-ImportDialog::ImportDialog( const KURL &url, TQWidget *parent )
- : KDialogBase( Plain, i18n("Import Calendar"), Ok | Cancel, Ok, parent,
+ImportDialog::ImportDialog( const KURL &url, TQWidget *parent, bool isPart )
+ : KDialogBase( Plain, i18n("Import Calendar/Event"), Ok | Cancel, Ok, parent,
0, true, true ),
mUrl( url )
{
TQFrame *topFrame = plainPage();
TQVBoxLayout *topLayout = new TQVBoxLayout( topFrame, 0, spacingHint() );
- TQString txt = i18n("Import calendar at '%1' into KOrganizer.")
+ TQString txt = i18n("Import calendar/event at '%1' into KOrganizer.")
.arg( mUrl.prettyURL() );
topLayout->addWidget( new TQLabel( txt, topFrame ) );
@@ -59,7 +59,7 @@ ImportDialog::ImportDialog( const KURL &url, TQWidget *parent )
mMergeButton = new TQRadioButton( i18n("Merge into existing calendar"),
radioBox );
- mOpenButton = new TQRadioButton( i18n("Open in separate window"), radioBox );
+ mOpenButton = isPart ? 0 : new TQRadioButton( i18n("Open in separate window"), radioBox );
mAddButton->setChecked( true );
}
@@ -77,7 +77,7 @@ void ImportDialog::slotOk()
} else if ( mMergeButton->isChecked() ) {
// emit a signal to action manager to merge mUrl into the current calendar
emit openURL( mUrl, true );
- } else if ( mOpenButton->isChecked() ) {
+ } else if ( mOpenButton && mOpenButton->isChecked() ) {
// emit a signal to the action manager to open mUrl in a separate window
emit newWindow( mUrl );
} else {
diff --git a/korganizer/importdialog.h b/korganizer/importdialog.h
index ae92ae0b6..75d5cb1a7 100644
--- a/korganizer/importdialog.h
+++ b/korganizer/importdialog.h
@@ -36,7 +36,7 @@ class ImportDialog : public KDialogBase
{
Q_OBJECT
public:
- ImportDialog( const KURL &url, TQWidget *parent );
+ ImportDialog( const KURL &url, TQWidget *parent, bool isPart );
~ImportDialog();
public slots:
diff --git a/korganizer/incidencechanger.cpp b/korganizer/incidencechanger.cpp
index 46be25ba7..1c41c5cd9 100644
--- a/korganizer/incidencechanger.cpp
+++ b/korganizer/incidencechanger.cpp
@@ -23,6 +23,7 @@
*/
#include "incidencechanger.h"
+#include "koglobals.h"
#include "koprefs.h"
#include "kogroupware.h"
#include "mailscheduler.h"
@@ -33,24 +34,36 @@
#include <kmessagebox.h>
#include <klocale.h>
+bool IncidenceChanger::beginChange( Incidence *incidence,
+ ResourceCalendar *res, const TQString &subRes )
+{
+ if ( !incidence ) {
+ return false;
+ }
+ kdDebug(5850) << "IncidenceChanger::beginChange for incidence \""
+ << incidence->summary() << "\"" << endl;
-bool IncidenceChanger::beginChange( Incidence * incidence )
-{
- if ( !incidence ) return false;
-kdDebug(5850)<<"IncidenceChanger::beginChange for incidence \""<<incidence->summary()<<"\""<<endl;
- return mCalendar->beginChange( incidence );
+ CalendarResources *calRes = dynamic_cast<CalendarResources*>( mCalendar );
+ if ( !calRes ) {
+ return false;
+ }
+
+ return calRes->beginChange( incidence, res, subRes );
}
-bool IncidenceChanger::sendGroupwareMessage( Incidence *incidence, KCal::Scheduler::Method method, bool deleting )
+bool IncidenceChanger::sendGroupwareMessage( Incidence *incidence,
+ KCal::Scheduler::Method method,
+ KOGlobals::HowChanged action,
+ TQWidget *parent )
{
if ( KOPrefs::instance()->thatIsMe( incidence->organizer().email() ) && incidence->attendeeCount()>0
&& !KOPrefs::instance()->mUseGroupwareCommunication ) {
emit schedule( method, incidence );
return true;
} else if( KOPrefs::instance()->mUseGroupwareCommunication ) {
- // FIXME: Find a widget to use as parent, instead of 0
- return KOGroupware::instance()->sendICalMessage( 0, method, incidence, deleting );
+ return
+ KOGroupware::instance()->sendICalMessage( parent, method, incidence, action, false );
}
return true;
}
@@ -66,7 +79,7 @@ void IncidenceChanger::cancelAttendees( Incidence *incidence )
// them?", which isn't helpful at all in this situation. Afterwards, it
// would only call the MailScheduler::performTransaction, so do this
// manually.
- // FIXME: Groupware schedulling should be factored out to it's own class
+ // FIXME: Groupware scheduling should be factored out to it's own class
// anyway
KCal::MailScheduler scheduler( mCalendar );
scheduler.performTransaction( incidence, Scheduler::Cancel );
@@ -74,23 +87,36 @@ void IncidenceChanger::cancelAttendees( Incidence *incidence )
}
}
-bool IncidenceChanger::endChange( Incidence *incidence )
+bool IncidenceChanger::endChange( Incidence *incidence,
+ ResourceCalendar *res, const TQString &subRes )
{
// FIXME: if that's a groupware incidence, and I'm not the organizer,
// send out a mail to the organizer with a counterproposal instead
// of actually changing the incidence. Then no locking is needed.
// FIXME: if that's a groupware incidence, and the incidence was
// never locked, we can't unlock it with endChange().
- if ( !incidence ) return false;
- // kdDebug(5850)<<"IncidenceChanger::endChange for incidence \""<<incidence->summary()<<"\""<<endl;
- return mCalendar->endChange( incidence );
+
+ if ( !incidence ) {
+ return false;
+ }
+
+ kdDebug(5850) << "IncidenceChanger::endChange for incidence \""
+ << incidence->summary() << "\"" << endl;
+
+ CalendarResources *calRes = dynamic_cast<CalendarResources*>( mCalendar );
+ if ( !calRes ) {
+ return false;
+ }
+
+ return calRes->endChange( incidence, res, subRes );
}
-bool IncidenceChanger::deleteIncidence( Incidence *incidence )
+bool IncidenceChanger::deleteIncidence( Incidence *incidence, TQWidget *parent )
{
if ( !incidence ) return true;
kdDebug(5850)<<"IncidenceChanger::deleteIncidence for incidence \""<<incidence->summary()<<"\""<<endl;
- bool doDelete = sendGroupwareMessage( incidence, KCal::Scheduler::Cancel );
+ bool doDelete = sendGroupwareMessage( incidence, KCal::Scheduler::Cancel,
+ KOGlobals::INCIDENCEDELETED, parent );
if( doDelete ) {
// @TODO: let Calendar::deleteIncidence do the locking...
Incidence* tmp = incidence->clone();
@@ -113,29 +139,52 @@ kdDebug(5850)<<"IncidenceChanger::deleteIncidence for incidence \""<<incidence->
}
}
- if ( notifyOrganizer ) {
+ if ( !KOGroupware::instance()->doNotNotify() && notifyOrganizer ) {
KCal::MailScheduler scheduler( mCalendar );
scheduler.performTransaction( tmp, Scheduler::Reply );
}
+ //reset the doNotNotify flag
+ KOGroupware::instance()->setDoNotNotify( false );
}
+ emit incidenceDeleted( incidence );
}
- emit incidenceDeleted( incidence );
return doDelete;
}
-bool IncidenceChanger::cutIncidence( Incidence *incidence )
+bool IncidenceChanger::cutIncidences( const Incidence::List &incidences,
+ TQWidget *parent )
{
- if ( !incidence ) return true;
-kdDebug(5850)<<"IncidenceChanger::deleteIncidence for incidence \""<<incidence->summary()<<"\""<<endl;
- bool doDelete = sendGroupwareMessage( incidence, KCal::Scheduler::Cancel );
- if( doDelete ) {
- // @TODO: the factory needs to do the locking!
- DndFactory factory( mCalendar );
- emit incidenceToBeDeleted( incidence );
- factory.cutIncidence( incidence );
- emit incidenceDeleted( incidence );
+ Incidence::List::ConstIterator it;
+ bool doDelete = true;
+ Incidence::List incsToCut;
+ for ( it = incidences.constBegin(); it != incidences.constEnd(); ++it ) {
+ if ( *it ) {
+ doDelete = sendGroupwareMessage( *it, KCal::Scheduler::Cancel,
+ KOGlobals::INCIDENCEDELETED, parent );
+ if ( doDelete ) {
+ emit incidenceToBeDeleted( *it );
+ incsToCut.append( *it );
+ }
+ }
+ }
+
+ DndFactory factory( mCalendar );
+
+ if ( factory.cutIncidences( incsToCut ) ) {
+ for ( it = incsToCut.constBegin(); it != incsToCut.constEnd(); ++it ) {
+ emit incidenceDeleted( *it );
+ }
+ return !incsToCut.isEmpty();
+ } else {
+ return false;
}
- return doDelete;
+}
+
+bool IncidenceChanger::cutIncidence( Incidence *incidence, TQWidget *parent )
+{
+ Incidence::List incidences;
+ incidences.append( incidence );
+ return cutIncidences( incidences, parent );
}
class IncidenceChanger::ComparisonVisitor : public IncidenceBase::Visitor
@@ -277,37 +326,35 @@ bool IncidenceChanger::myAttendeeStatusChanged( Incidence *oldInc, Incidence *ne
}
bool IncidenceChanger::changeIncidence( Incidence *oldinc, Incidence *newinc,
- int action )
+ KOGlobals::WhatChanged action,
+ TQWidget *parent )
{
kdDebug(5850)<<"IncidenceChanger::changeIncidence for incidence \""<<newinc->summary()<<"\" ( old one was \""<<oldinc->summary()<<"\")"<<endl;
- if( incidencesEqual( newinc, oldinc ) ) {
+ if ( incidencesEqual( newinc, oldinc ) ) {
// Don't do anything
kdDebug(5850) << "Incidence not changed\n";
} else {
kdDebug(5850) << "Incidence changed\n";
- bool statusChanged = myAttendeeStatusChanged( oldinc, newinc );
+ bool attendeeStatusChanged = myAttendeeStatusChanged( oldinc, newinc );
int revision = newinc->revision();
newinc->setRevision( revision + 1 );
// FIXME: Use a generic method for this! Ideally, have an interface class
// for group scheduling. Each implementation could then just do what
// it wants with the event. If no groupware is used,use the null
// pattern...
- bool revert = KOPrefs::instance()->mUseGroupwareCommunication;
- if ( revert &&
- KOGroupware::instance()->sendICalMessage( 0,
- KCal::Scheduler::Request,
- newinc, false, statusChanged ) ) {
- // Accept the event changes
- revert = false;
+ bool success = true;
+ if ( KOPrefs::instance()->mUseGroupwareCommunication ) {
+ success = KOGroupware::instance()->sendICalMessage(
+ parent,
+ KCal::Scheduler::Request,
+ newinc, KOGlobals::INCIDENCEEDITED, attendeeStatusChanged );
}
- if ( action<0 ) {
- emit incidenceChanged( oldinc, newinc );
- } else {
+ if ( success ) {
+ // Accept the event changes
emit incidenceChanged( oldinc, newinc, action );
- }
-
- if ( revert ) {
+ } else {
+ // revert changes
assignIncidence( newinc, oldinc );
return false;
}
@@ -315,41 +362,97 @@ kdDebug(5850)<<"IncidenceChanger::changeIncidence for incidence \""<<newinc->sum
return true;
}
-bool IncidenceChanger::addIncidence( Incidence *incidence, TQWidget *parent )
+bool IncidenceChanger::addIncidence( Incidence *incidence,
+ ResourceCalendar *res, const TQString &subRes,
+ TQWidget *parent )
{
-kdDebug(5850)<<"IncidenceChanger::addIncidence for incidence \""<<incidence->summary()<<"\""<<endl;
- if ( KOPrefs::instance()->mUseGroupwareCommunication ) {
- if ( !KOGroupware::instance()->sendICalMessage( parent,
- KCal::Scheduler::Request,
- incidence ) ) {
- kdError() << "sendIcalMessage failed." << endl;
- }
+ CalendarResources *stdcal = dynamic_cast<CalendarResources *>( mCalendar );
+ if( stdcal && !stdcal->hasCalendarResources() ) {
+ KMessageBox::sorry(
+ parent,
+ i18n( "No calendars found, unable to save %1 \"%2\"." ).
+ arg( i18n( incidence->type() ) ).
+ arg( incidence->summary() ) );
+ kdDebug(5850) << "IncidenceChanger: No calendars found" << endl;
+ return false;
}
+
// FIXME: This is a nasty hack, since we need to set a parent for the
// resource selection dialog. However, we don't have any UI methods
// in the calendar, only in the CalendarResources::DestinationPolicy
// So we need to type-cast it and extract it from the CalendarResources
- CalendarResources *stdcal = dynamic_cast<CalendarResources*>(mCalendar);
TQWidget *tmpparent = 0;
if ( stdcal ) {
tmpparent = stdcal->dialogParentWidget();
stdcal->setDialogParentWidget( parent );
}
- bool success = mCalendar->addIncidence( incidence );
- if ( stdcal ) {
- // Reset the parent widget, otherwise we'll end up with pointers to deleted
- // widgets sooner or later
- stdcal->setDialogParentWidget( tmpparent );
+
+ // If a ResourceCalendar isn't provided, then try to compute one
+ // along with any subResource from the incidence.
+ ResourceCalendar *pRes = res;
+ TQString pSubRes = subRes;
+ TQString pResName;
+ if ( !pRes ) {
+ if ( stdcal ) {
+ pRes = stdcal->resource( incidence );
+ if ( pRes ) {
+ pResName = pRes->resourceName();
+ if ( pRes->canHaveSubresources() ) {
+ pSubRes = pRes->subresourceIdentifier( incidence );
+ pResName = pRes->labelForSubresource( pSubRes );
+ }
+ }
+ }
+ }
+
+ bool success = false;
+ if ( stdcal && pRes && !pRes->readOnly() && pRes->subresourceWritable( pSubRes ) ) {
+ success = stdcal->addIncidence( incidence, pRes, pSubRes );
+ } else {
+ success = mCalendar->addIncidence( incidence );
}
+
if ( !success ) {
- KMessageBox::sorry( parent, i18n("Unable to save %1 \"%2\".")
- .arg( i18n( incidence->type() ) )
- .arg( incidence->summary() ) );
+ // We can have a failure if the user pressed [cancel] in the resource
+ // selectdialog, so check the exception.
+ ErrorFormat *e = stdcal ? stdcal->exception() : 0;
+ if ( !e ||
+ ( e && ( e->errorCode() != KCal::ErrorFormat::UserCancel &&
+ e->errorCode() != KCal::ErrorFormat::NoWritableFound ) ) ) {
+ TQString errMessage;
+ if ( pResName.isEmpty() ) {
+ errMessage = i18n( "Unable to save %1 \"%2\"." ).
+ arg( i18n( incidence->type() ) ).
+ arg( incidence->summary() );
+ } else {
+ errMessage = i18n( "Unable to save %1 \"%2\" to calendar %3." ).
+ arg( i18n( incidence->type() ) ).
+ arg( incidence->summary() ).
+ arg( pResName );
+ }
+ KMessageBox::sorry( parent, errMessage );
+ }
+ kdDebug(5850) << "IncidenceChanger: Can't add incidence" << endl;
return false;
}
+
+ if ( KOPrefs::instance()->mUseGroupwareCommunication ) {
+ if ( !KOGroupware::instance()->sendICalMessage(
+ parent,
+ KCal::Scheduler::Request,
+ incidence, KOGlobals::INCIDENCEADDED, false ) ) {
+ KMessageBox::sorry(
+ parent,
+ i18n( "Attempt to send the scheduling message failed. "
+ "Please check your Group Scheduling settings. "
+ "Contact your system administrator for more help.") );
+ }
+ }
+
emit incidenceAdded( incidence );
return true;
}
+
#include "incidencechanger.moc"
#include "incidencechangerbase.moc"
diff --git a/korganizer/incidencechanger.h b/korganizer/incidencechanger.h
index 1423b4888..afa550646 100644
--- a/korganizer/incidencechanger.h
+++ b/korganizer/incidencechanger.h
@@ -26,33 +26,53 @@
#include "korganizer/incidencechangerbase.h"
+namespace KCal {
+ class ResourceCalendar;
+}
+
class IncidenceChanger : public KOrg::IncidenceChangerBase
{
-Q_OBJECT
-public:
- IncidenceChanger( Calendar*cal, TQObject *parent ) : IncidenceChangerBase( cal, parent ) {}
- ~IncidenceChanger() {}
-
- bool beginChange( Incidence * incidence );
- bool sendGroupwareMessage( Incidence *incidence, KCal::Scheduler::Method method, bool deleting = false );
- bool endChange( Incidence *incidence );
-
- bool addIncidence( Incidence *incidence, TQWidget *parent = 0 );
- bool changeIncidence( Incidence *oldinc, Incidence *newinc, int action = -1 );
- bool deleteIncidence( Incidence *incidence );
-
- bool cutIncidence( Incidence *incidence );
- static bool incidencesEqual( Incidence *inc1, Incidence *inc2 );
- static bool assignIncidence( Incidence *inc1, Incidence *inc2 );
-public slots:
- void cancelAttendees( Incidence *incidence );
-
-protected:
- bool myAttendeeStatusChanged( Incidence *oldInc, Incidence *newInc );
-
-private:
- class ComparisonVisitor;
- class AssignmentVisitor;
+ Q_OBJECT
+ public:
+ IncidenceChanger( Calendar *cal, TQObject *parent )
+ : IncidenceChangerBase( cal, parent ) {}
+ ~IncidenceChanger() {}
+
+ bool beginChange( Incidence *incidence,
+ ResourceCalendar *res, const TQString &subRes );
+
+ bool sendGroupwareMessage( Incidence *incidence,
+ KCal::Scheduler::Method method,
+ KOGlobals::HowChanged action,
+ TQWidget *parent );
+
+ bool endChange( Incidence *incidence,
+ ResourceCalendar *res, const TQString &subRes );
+
+ bool addIncidence( Incidence *incidence,
+ ResourceCalendar *res, const TQString &subRes,
+ TQWidget *parent );
+
+ bool changeIncidence( Incidence *oldinc, Incidence *newinc,
+ KOGlobals::WhatChanged, TQWidget *parent );
+
+ bool deleteIncidence( Incidence *incidence, TQWidget *parent );
+
+ bool cutIncidences( const Incidence::List &incidences, TQWidget *parent );
+ bool cutIncidence( Incidence *incidence, TQWidget *parent );
+
+ static bool incidencesEqual( Incidence *inc1, Incidence *inc2 );
+ static bool assignIncidence( Incidence *inc1, Incidence *inc2 );
+
+ public slots:
+ void cancelAttendees( Incidence *incidence );
+
+ protected:
+ bool myAttendeeStatusChanged( Incidence *oldInc, Incidence *newInc );
+
+ private:
+ class ComparisonVisitor;
+ class AssignmentVisitor;
};
#endif
diff --git a/korganizer/interfaces/calendar/calendardecoration.desktop b/korganizer/interfaces/calendar/calendardecoration.desktop
index e9763878e..b44db80ad 100644
--- a/korganizer/interfaces/calendar/calendardecoration.desktop
+++ b/korganizer/interfaces/calendar/calendardecoration.desktop
@@ -28,7 +28,6 @@ Comment[hu]=Naptármegjelenési bővítőmodul
Comment[is]=Íforrit til að skreyta texta dagatals
Comment[it]=Plugin di decorazione del calendario
Comment[ja]=カレンダー装飾プラグイン
-Comment[ka]=კალენდრის გაფორმების მოდული
Comment[kk]=Күнтізбені безендіру модулі
Comment[km]=កម្មវិធី​ជំនួយ​សម្រាប់​តុបតែង​ប្រតិទិន
Comment[lt]=vCalendar dekoracijų priedas
diff --git a/korganizer/interfaces/calendar/calendarplugin.desktop b/korganizer/interfaces/calendar/calendarplugin.desktop
index 765fced76..d5c0ab560 100644
--- a/korganizer/interfaces/calendar/calendarplugin.desktop
+++ b/korganizer/interfaces/calendar/calendarplugin.desktop
@@ -30,7 +30,6 @@ Comment[hu]=Naptárkezelő bővítőmodul
Comment[is]=Dagatals íforrit
Comment[it]=Plugin calendario
Comment[ja]=カレンダープラグイン
-Comment[ka]=კალენდრის მოდული
Comment[kk]=Күнтізбе модулі
Comment[km]=កម្មវិធី​ជំនួយ​ប្រតិទិន
Comment[ko]=달력 플러그인
@@ -61,8 +60,7 @@ Comment[tg]=Модул барои тақвимот
Comment[th]=โปรแกรมเสริมบันทึกประจำวัน
Comment[tr]=Takvim Eklentisi
Comment[uk]=Втулок календаря
-Comment[uz]=Kalendar plagini
-Comment[uz@cyrillic]=Календар плагини
+Comment[uz]=Календар плагини
Comment[ven]=U pulaga ha khalenda
Comment[vi]=Plugin lịch
Comment[xh]=Ikhalenda ye Plugin
diff --git a/korganizer/interfaces/korganizer/baseview.h b/korganizer/interfaces/korganizer/baseview.h
index 64fbd72b5..6d60a0a5f 100644
--- a/korganizer/interfaces/korganizer/baseview.h
+++ b/korganizer/interfaces/korganizer/baseview.h
@@ -2,7 +2,7 @@
This file is part of the KOrganizer interfaces.
Copyright (c) 1999,2001,2003 Cornelius Schumacher <schumacher@kde.org>
- Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
+ Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -38,17 +38,19 @@
using namespace KCal;
-namespace KCal { class Calendar; }
+namespace KCal {
+ class Calendar;
+ class ResourceCalendar;
+}
namespace KOrg {
-
/**
- This class provides an interface for all views being displayed within the main
- calendar view. It has functions to update the view, to specify date range and
- other display parameter and to return selected objects. An important class,
- which inherits KOBaseView is KOEventView, which provides the interface for all
- views of event data like the agenda or the month view.
+ This class provides an interface for all views being displayed within the
+ main calendar view. It has functions to update the view, to specify date
+ range and other display parameter and to return selected objects. An
+ important class, which inherits KOBaseView is KOEventView, which provides
+ the interface for all views of event data like the agenda or the month view.
@short Base class for calendar views
@author Preston Brown, Cornelius Schumacher
@@ -56,7 +58,7 @@ namespace KOrg {
*/
class KDE_EXPORT BaseView : public QWidget
{
- Q_OBJECT
+ Q_OBJECT
public:
/**
Constructs a view.
@@ -66,21 +68,41 @@ class KDE_EXPORT BaseView : public QWidget
@param parent parent widget.
@param name name of this widget.
*/
- BaseView( Calendar *cal, TQWidget *parent = 0,
- const char *name = 0 )
- : TQWidget( parent, name ), mCalendar( cal ), mChanger( 0 ) {}
+ BaseView( Calendar *cal, TQWidget *parent = 0, const char *name = 0 )
+ : TQWidget( parent, name ),
+ mReadOnly( false ), mCalendar( cal ), mResource( 0 ), mChanger( 0 ) {}
/**
Destructor. Views will do view-specific cleanups here.
*/
virtual ~BaseView() {}
+ /** Flag indicating if the view is read-only */
+ void setReadOnly( bool readonly ) { mReadOnly = readonly; }
+ bool readOnly() { return mReadOnly; }
+
virtual void setCalendar( Calendar *cal ) { mCalendar = cal; }
/**
Return calendar object of this view.
*/
virtual Calendar *calendar() { return mCalendar; }
+ virtual void setResource( ResourceCalendar *res, const TQString &subResource )
+ {
+ mResource = res;
+ mSubResource = subResource;
+ }
+
+ /**
+ Return resourceCalendar of this view.
+ */
+ ResourceCalendar *resourceCalendar() { return mResource; }
+
+ /**
+ Return subResourceCalendar of this view.
+ */
+ TQString subResourceCalendar() const { return mSubResource; }
+
/**
@return a list of selected events. Most views can probably only
select a single event at a time, but some may be able to select
@@ -93,7 +115,19 @@ class KDE_EXPORT BaseView : public QWidget
select a single event at a time, but some may be able to select
more than one.
*/
- virtual DateList selectedDates() = 0;
+ virtual DateList selectedIncidenceDates() = 0;
+
+ /**
+ Returns the start of the selection, or an invalid TQDateTime if there is no selection
+ or the view doesn't support selecting cells.
+ */
+ virtual TQDateTime selectionStart() { return TQDateTime(); }
+
+ /**
+ Returns the end of the selection, or an invalid TQDateTime if there is no selection
+ or the view doesn't support selecting cells.
+ */
+ virtual TQDateTime selectionEnd() { return TQDateTime(); }
virtual CalPrinterBase::PrintType printType()
{
@@ -108,6 +142,11 @@ class KDE_EXPORT BaseView : public QWidget
/** Return if this view is a view for displaying events. */
virtual bool isEventView() { return false; }
+ /** Returns true if the view supports navigation through the date navigator
+ ( selecting a date range, changing month, changing year, etc. )
+ */
+ virtual bool supportsDateNavigation() const { return false; }
+
public slots:
/**
Show incidences for the given date range. The date range actually shown may be
@@ -124,8 +163,9 @@ class KDE_EXPORT BaseView : public QWidget
show all given events.
@param incidenceList a list of incidences to show.
+ @param date is the TQDate on which the incidences are being shown.
*/
- virtual void showIncidences( const Incidence::List &incidenceList ) = 0;
+ virtual void showIncidences( const Incidence::List &incidenceList, const TQDate &date ) = 0;
/**
Updates the current display to reflect changes that may have happened
@@ -166,19 +206,19 @@ class KDE_EXPORT BaseView : public QWidget
virtual bool eventDurationHint(TQDateTime &/*startDt*/, TQDateTime &/*endDt*/, bool &/*allDay*/) { return false; }
signals:
- void incidenceSelected( Incidence * );
+ void incidenceSelected( Incidence *, const TQDate & );
/**
* instructs the receiver to show the incidence in read-only mode.
*/
- void showIncidenceSignal(Incidence *);
+ void showIncidenceSignal( Incidence *, const TQDate & );
/**
* instructs the receiver to begin editing the incidence specified in
* some manner. Doesn't make sense to connect to more than one
* receiver.
*/
- void editIncidenceSignal(Incidence *);
+ void editIncidenceSignal( Incidence *, const TQDate & );
/**
* instructs the receiver to delete the Incidence in some manner; some
@@ -220,31 +260,40 @@ class KDE_EXPORT BaseView : public QWidget
* instructs the receiver to create a new event. Doesn't make
* sense to connect to more than one receiver.
*/
- void newEventSignal();
+ void newEventSignal( ResourceCalendar *res, const TQString &subResource );
/**
* instructs the receiver to create a new event with the specified beginning
* time. Doesn't make sense to connect to more than one receiver.
*/
- void newEventSignal( const TQDate & );
+ void newEventSignal( ResourceCalendar *res, const TQString &subResource,
+ const TQDate & );
/**
* instructs the receiver to create a new event with the specified beginning
* time. Doesn't make sense to connect to more than one receiver.
*/
- void newEventSignal( const TQDateTime & );
+ void newEventSignal( ResourceCalendar *res, const TQString &subResource,
+ const TQDateTime & );
/**
* instructs the receiver to create a new event, with the specified
* beginning end ending times. Doesn't make sense to connect to more
* than one receiver.
*/
- void newEventSignal( const TQDateTime &, const TQDateTime & );
+ void newEventSignal( ResourceCalendar *res, const TQString &subResource,
+ const TQDateTime &, const TQDateTime & );
- void newTodoSignal( const TQDate & );
+ void newTodoSignal( ResourceCalendar *res,const TQString &subResource,
+ const TQDate & );
void newSubTodoSignal( Todo * );
- void newJournalSignal( const TQDate & );
+ void newJournalSignal( ResourceCalendar *res,const TQString &subResource,
+ const TQDate & );
private:
+ bool mReadOnly;
Calendar *mCalendar;
+ ResourceCalendar *mResource;
+ TQString mSubResource;
+
protected:
IncidenceChangerBase *mChanger;
};
diff --git a/korganizer/interfaces/korganizer/corehelper.h b/korganizer/interfaces/korganizer/corehelper.h
index 53b5d9fb2..8c69a1adc 100644
--- a/korganizer/interfaces/korganizer/corehelper.h
+++ b/korganizer/interfaces/korganizer/corehelper.h
@@ -37,8 +37,7 @@ class CoreHelper
public:
CoreHelper() {}
virtual ~CoreHelper() {}
-
- virtual TQColor defaultEventColor() = 0;
+
virtual TQColor textColor( const TQColor &bgColor ) = 0;
virtual TQColor categoryColor( const TQStringList &cats ) = 0;
virtual TQString holidayString( const TQDate &dt ) = 0;
diff --git a/korganizer/interfaces/korganizer/incidencechangerbase.h b/korganizer/interfaces/korganizer/incidencechangerbase.h
index f482388c5..e7c133056 100644
--- a/korganizer/interfaces/korganizer/incidencechangerbase.h
+++ b/korganizer/interfaces/korganizer/incidencechangerbase.h
@@ -21,13 +21,16 @@
#ifndef KORG_INCIDENCECHANGERBASE_H
#define KORG_INCIDENCECHANGERBASE_H
+#include "korganizer/koglobals.h"
#include <libkcal/scheduler.h>
+#include <libkcal/incidence.h>
#include <tqobject.h>
class TQWidget;
namespace KCal {
-class Calendar;
-class Incidence;
+ class Calendar;
+ class Incidence;
+ class ResourceCalendar;
}
using namespace KCal;
@@ -42,25 +45,29 @@ public:
virtual ~IncidenceChangerBase() {}
virtual bool sendGroupwareMessage( Incidence *incidence,
- KCal::Scheduler::Method method, bool deleting = false ) = 0;
+ KCal::Scheduler::Method method,
+ KOGlobals::HowChanged action,
+ TQWidget *parent ) = 0;
- virtual bool beginChange( Incidence * incidence ) = 0;
- virtual bool endChange( Incidence *incidence ) = 0;
+ virtual bool beginChange( Incidence *incidence,
+ ResourceCalendar *res, const TQString &subRes ) = 0;
+ virtual bool endChange( Incidence *incidence,
+ ResourceCalendar *res, const TQString &subRes ) = 0;
- virtual bool addIncidence( Incidence *incidence, TQWidget *parent = 0 ) = 0;
- virtual bool changeIncidence( Incidence *newinc, Incidence *oldinc,
- int action = -1 ) = 0;
- virtual bool deleteIncidence( Incidence *incidence ) = 0;
- virtual bool cutIncidence( Incidence *incidence ) = 0;
+ virtual bool addIncidence( Incidence *incidence,
+ ResourceCalendar *res, const TQString &subRes,
+ TQWidget *parent ) = 0;
+
+ virtual bool changeIncidence( Incidence *oldinc, Incidence *newinc,
+ KOGlobals::WhatChanged, TQWidget *parent ) = 0;
+ virtual bool deleteIncidence( Incidence *incidence, TQWidget *parent ) = 0;
+
+ virtual bool cutIncidences( const Incidence::List &incidences, TQWidget *parent ) = 0;
+ virtual bool cutIncidence( Incidence *incidence, TQWidget *parent ) = 0;
-/*
- static bool incidencesEqual( Incidence *inc1, Incidence *inc2 );
- static bool assignIncidence( Incidence *inc1, Incidence *inc2 );
-*/
signals:
void incidenceAdded( Incidence * );
- void incidenceChanged( Incidence *oldInc, Incidence *newInc, int );
- void incidenceChanged( Incidence *oldInc, Incidence *newInc );
+ void incidenceChanged( Incidence *oldInc, Incidence *newInc, KOGlobals::WhatChanged );
void incidenceToBeDeleted( Incidence * );
void incidenceDeleted( Incidence * );
diff --git a/korganizer/interfaces/korganizer/korganizerpart.desktop b/korganizer/interfaces/korganizer/korganizerpart.desktop
index 7cb419dea..c1b84659d 100644
--- a/korganizer/interfaces/korganizer/korganizerpart.desktop
+++ b/korganizer/interfaces/korganizer/korganizerpart.desktop
@@ -25,7 +25,6 @@ Comment[hu]=KOrganizer objektum
Comment[is]=KOrganizer hluti
Comment[it]=Parte di KOrganizer
Comment[ja]=KOrganizer パート
-Comment[ka]=KOrganizer კომპონენტი
Comment[kk]=KOrganizer бөлшегі
Comment[km]=ផ្នែក​របស់ KOrganizer
Comment[lt]=KOrganizer dalis
diff --git a/korganizer/interfaces/korganizer/korgprintplugin.desktop b/korganizer/interfaces/korganizer/korgprintplugin.desktop
index ffa520d36..05cbd1b91 100644
--- a/korganizer/interfaces/korganizer/korgprintplugin.desktop
+++ b/korganizer/interfaces/korganizer/korgprintplugin.desktop
@@ -25,7 +25,6 @@ Comment[hu]=KOrganizer objektum
Comment[is]=KOrganizer hluti
Comment[it]=Parte di KOrganizer
Comment[ja]=KOrganizer パート
-Comment[ka]=KOrganizer კომპონენტი
Comment[kk]=KOrganizer бөлшегі
Comment[km]=ផ្នែក​របស់ KOrganizer
Comment[lt]=KOrganizer dalis
diff --git a/korganizer/interfaces/korganizer/mainwindow.h b/korganizer/interfaces/korganizer/mainwindow.h
index 3343470aa..dcda1bee5 100644
--- a/korganizer/interfaces/korganizer/mainwindow.h
+++ b/korganizer/interfaces/korganizer/mainwindow.h
@@ -87,9 +87,11 @@ class MainWindow
*/
virtual void setTitle() = 0;
- void setHasDocument( bool d ) { mDocument = d; }
+ void setHasDocument( bool d ) { mDocument = d; }
bool hasDocument() const { return mDocument; }
+ virtual bool isCurrentlyActivePart() = 0;
+
private:
bool mDocument;
};
diff --git a/korganizer/journalentry.cpp b/korganizer/journalentry.cpp
index ae80a8d6f..c107d6189 100644
--- a/korganizer/journalentry.cpp
+++ b/korganizer/journalentry.cpp
@@ -128,8 +128,8 @@ void JournalDateEntry::addJournal( Journal *j )
entry, TQT_SLOT( flushEntry() ) );
connect( entry, TQT_SIGNAL( deleteIncidence( Incidence* ) ),
this, TQT_SIGNAL( deleteIncidence( Incidence* ) ) );
- connect( entry, TQT_SIGNAL( editIncidence( Incidence* ) ),
- this, TQT_SIGNAL( editIncidence( Incidence* ) ) );
+ connect( entry, TQT_SIGNAL( editIncidence( Incidence*, const TQDate& ) ),
+ this, TQT_SIGNAL( editIncidence( Incidence*, const TQDate& ) ) );
}
Journal::List JournalDateEntry::journals() const
@@ -151,7 +151,7 @@ void JournalDateEntry::setIncidenceChanger( IncidenceChangerBase *changer )
void JournalDateEntry::emitNewJournal()
{
- emit newJournal( mDate );
+ emit newJournal( 0/*ResourceCalendar*/, TQString()/*subResource*/, mDate );
}
void JournalDateEntry::journalEdited( Journal *journal )
@@ -271,8 +271,9 @@ void JournalEntry::deleteItem()
void JournalEntry::editItem()
{
writeJournal();
- if ( mJournal )
- emit editIncidence( mJournal );
+ if ( mJournal ) {
+ emit editIncidence( mJournal, mJournal->dtStart().date() );
+ }
}
void JournalEntry::printItem()
@@ -381,17 +382,17 @@ void JournalEntry::writeJournal()
newJournal = true;
mJournal = new Journal;
writeJournalPrivate( mJournal );
- if ( !mChanger->addIncidence( mJournal, this ) ) {
+ if ( !mChanger->addIncidence( mJournal, 0, TQString(), this ) ) {
KODialogManager::errorSaveIncidence( this, mJournal );
delete mJournal;
mJournal = 0;
}
} else {
oldJournal = mJournal->clone();
- if ( mChanger->beginChange( mJournal ) ) {
+ if ( mChanger->beginChange( mJournal, 0, TQString() ) ) {
writeJournalPrivate( mJournal );
- mChanger->changeIncidence( oldJournal, mJournal, KOGlobals::DESCRIPTION_MODIFIED );
- mChanger->endChange( mJournal );
+ mChanger->changeIncidence( oldJournal, mJournal, KOGlobals::DESCRIPTION_MODIFIED, this );
+ mChanger->endChange( mJournal, 0, TQString() );
}
delete oldJournal;
}
diff --git a/korganizer/journalentry.h b/korganizer/journalentry.h
index 090909f39..9350d5ead 100644
--- a/korganizer/journalentry.h
+++ b/korganizer/journalentry.h
@@ -26,6 +26,7 @@
//
// Widget showing one Journal entry
+#include <libkcal/resourcecalendar.h>
#include <tqvbox.h>
class TQLabel;
@@ -78,7 +79,7 @@ class JournalEntry : public TQWidget {
signals:
void deleteIncidence( Incidence * );
- void editIncidence( Incidence * );
+ void editIncidence( Incidence *, const TQDate& );
protected:
void clearFields();
@@ -131,9 +132,9 @@ class JournalDateEntry : public TQVBox {
void setIncidenceChangerSignal( IncidenceChangerBase *changer );
void setDateSignal( const TQDate & );
void flushEntries();
- void editIncidence( Incidence * );
+ void editIncidence( Incidence *, const TQDate& );
void deleteIncidence( Incidence * );
- void newJournal( const TQDate & );
+ void newJournal( ResourceCalendar *, const TQString &, const TQDate & );
public slots:
void emitNewJournal();
diff --git a/korganizer/kcalendariface.h b/korganizer/kcalendariface.h
index a63f3f1c7..f4a20d7ad 100644
--- a/korganizer/kcalendariface.h
+++ b/korganizer/kcalendariface.h
@@ -86,7 +86,8 @@ class KCalendarIface : public DCOPObject
const TQString& uri,
const TQString& file,
const TQStringList& attendees,
- const TQString& attachmentMimetype ) = 0;
+ const TQString& attachmentMimetype,
+ bool isTask ) = 0;
virtual void openJournalEditor( const TQDate& date ) = 0;
virtual void openJournalEditor( const TQString& text,
diff --git a/korganizer/kdatenavigator.cpp b/korganizer/kdatenavigator.cpp
index 1dea017a2..6fe794592 100644
--- a/korganizer/kdatenavigator.cpp
+++ b/korganizer/kdatenavigator.cpp
@@ -53,11 +53,12 @@ KDateNavigator::KDateNavigator( TQWidget *parent, const char *name )
mNavigatorBar = new NavigatorBar( this );
topLayout->addMultiCellWidget( mNavigatorBar, 0, 0, 0, 7 );
- connect( mNavigatorBar, TQT_SIGNAL( goPrevYear() ), TQT_SIGNAL( goPrevYear() ) );
- connect( mNavigatorBar, TQT_SIGNAL( goPrevMonth() ), TQT_SIGNAL( goPrevMonth() ) );
- connect( mNavigatorBar, TQT_SIGNAL( goNextMonth() ), TQT_SIGNAL( goNextMonth() ) );
- connect( mNavigatorBar, TQT_SIGNAL( goNextYear() ), TQT_SIGNAL( goNextYear() ) );
- connect( mNavigatorBar, TQT_SIGNAL( goMonth( int ) ), TQT_SIGNAL( goMonth( int ) ) );
+ connect( mNavigatorBar, TQT_SIGNAL( prevYearClicked() ), TQT_SIGNAL( prevYearClicked() ) );
+ connect( mNavigatorBar, TQT_SIGNAL( prevMonthClicked() ), TQT_SIGNAL( prevMonthClicked() ) );
+ connect( mNavigatorBar, TQT_SIGNAL( nextMonthClicked() ), TQT_SIGNAL( nextMonthClicked() ) );
+ connect( mNavigatorBar, TQT_SIGNAL( nextYearClicked() ), TQT_SIGNAL( nextYearClicked() ) );
+ connect( mNavigatorBar, TQT_SIGNAL( monthSelected( int ) ), TQT_SIGNAL( monthSelected( int ) ) );
+ connect( mNavigatorBar, TQT_SIGNAL( yearSelected( int ) ), TQT_SIGNAL( yearSelected( int ) ) );
int i;
TQString generalFont = KGlobalSettings::generalFont().family();
@@ -136,6 +137,7 @@ void KDateNavigator::updateToday()
mDayMatrix->recalculateToday();
mDayMatrix->repaint();
}
+
TQDate KDateNavigator::startDate() const
{
// Find the first day of the week of the current month.
@@ -160,6 +162,7 @@ TQDate KDateNavigator::startDate() const
return dayone;
}
+
TQDate KDateNavigator::endDate() const
{
return startDate().addDays( 6*7 );
@@ -202,6 +205,23 @@ void KDateNavigator::updateDayMatrix()
mDayMatrix->repaint();
}
+void KDateNavigator::setUpdateNeeded()
+{
+ mDayMatrix->setUpdateNeeded();
+}
+
+TQDate KDateNavigator::month() const
+{
+ TQDate firstCell = startDate();
+ const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem();
+
+ if ( calSys->day( firstCell ) == 1 ) {
+ return firstCell;
+ } else {
+ calSys->setYMD( firstCell, calSys->year( firstCell ), calSys->month( firstCell ), 1 );
+ return calSys->addMonths( firstCell, 1 );
+ }
+}
void KDateNavigator::updateView()
{
@@ -230,10 +250,11 @@ void KDateNavigator::updateConfig()
void KDateNavigator::setShowWeekNums( bool enabled )
{
for( int i = 0; i < 6; i++ ) {
- if( enabled )
+ if ( enabled ) {
mWeeknos[i]->show();
- else
+ } else {
mWeeknos[i]->hide();
+ }
}
}
@@ -251,15 +272,18 @@ void KDateNavigator::selectDates( const DateList &dateList )
}
}
-void KDateNavigator::wheelEvent ( TQWheelEvent *e )
+void KDateNavigator::wheelEvent( TQWheelEvent *e )
{
- if( e->delta() > 0 ) emit goPrevious();
- else emit goNext();
+ if ( e->delta() > 0 ) {
+ emit goPrevious();
+ } else {
+ emit goNext();
+ }
e->accept();
}
-bool KDateNavigator::eventFilter ( TQObject *o, TQEvent *e )
+bool KDateNavigator::eventFilter( TQObject *o, TQEvent *e )
{
if ( e->type() == TQEvent::MouseButtonPress ) {
int i;
diff --git a/korganizer/kdatenavigator.h b/korganizer/kdatenavigator.h
index 047925895..682a93588 100644
--- a/korganizer/kdatenavigator.h
+++ b/korganizer/kdatenavigator.h
@@ -63,6 +63,14 @@ class KDateNavigator: public QFrame
NavigatorBar *navigatorBar() const { return mNavigatorBar; }
TQDate startDate() const;
TQDate endDate() const;
+ void setUpdateNeeded();
+
+ /**
+ Returns the current displayed month.
+ It's a TQDate instead of uint so it can be easily feed to KCalendarSystem's
+ functions.
+ */
+ TQDate month() const;
public slots:
void selectDates( const KCal::DateList & );
@@ -75,24 +83,24 @@ class KDateNavigator: public QFrame
void datesSelected( const KCal::DateList & );
void incidenceDropped( Incidence *, const TQDate & );
void incidenceDroppedMove( Incidence *, const TQDate & );
- void weekClicked( const TQDate &);
+ void weekClicked( const TQDate & );
void goPrevious();
void goNext();
+ void nextMonthClicked();
+ void prevMonthClicked();
+ void nextYearClicked();
+ void prevYearClicked();
- void goNextMonth();
- void goPrevMonth();
- void goNextYear();
- void goPrevYear();
-
- void goMonth( int month );
+ void monthSelected( int month );
+ void yearSelected( int year );
protected:
void updateDates();
void wheelEvent( TQWheelEvent * );
- bool eventFilter( TQObject *,TQEvent * );
+ bool eventFilter( TQObject *, TQEvent * );
void setShowWeekNums( bool enabled );
diff --git a/korganizer/koagenda.cpp b/korganizer/koagenda.cpp
index 589c13285..8329d161c 100644
--- a/korganizer/koagenda.cpp
+++ b/korganizer/koagenda.cpp
@@ -58,11 +58,12 @@
#include <libkcal/vcaldrag.h>
#include <libkcal/calendar.h>
#include <libkcal/calendarresources.h>
+#include <libkcal/calhelper.h>
#include <math.h>
////////////////////////////////////////////////////////////////////////////
-MarcusBains::MarcusBains(KOAgenda *_agenda,const char *name)
- : TQFrame(_agenda->viewport(),name), agenda(_agenda)
+MarcusBains::MarcusBains(KOAgenda *_agenda,const char *name )
+ : TQFrame(_agenda->viewport(), name), agenda(_agenda)
{
setLineWidth(0);
setMargin(0);
@@ -80,7 +81,8 @@ MarcusBains::MarcusBains(KOAgenda *_agenda,const char *name)
agenda->addChild(mTimeBox);
- oldToday = -1;
+ mOldTime = TQTime( 0, 0 );
+ mOldToday = -1;
}
MarcusBains::~MarcusBains()
@@ -99,33 +101,41 @@ int MarcusBains::todayColumn()
if((*it) == currentDate)
return KOGlobals::self()->reverseLayout() ?
agenda->columns() - 1 - col : col;
- ++col;
+ ++col;
}
return -1;
}
-void MarcusBains::updateLocation(bool recalculate)
+void MarcusBains::updateLocation()
+{
+ updateLocationRecalc();
+}
+
+void MarcusBains::updateLocationRecalc( bool recalculate )
{
TQTime tim = TQTime::currentTime();
- if((tim.hour() == 0) && (oldTime.hour()==23))
+ if((tim.hour() == 0) && (mOldTime.hour()==23))
recalculate = true;
int mins = tim.hour()*60 + tim.minute();
int minutesPerCell = 24 * 60 / agenda->rows();
int y = int( mins * agenda->gridSpacingY() / minutesPerCell );
- int today = recalculate ? todayColumn() : oldToday;
+ int today = recalculate ? todayColumn() : mOldToday;
int x = int( agenda->gridSpacingX() * today );
- bool disabled = !(KOPrefs::instance()->mMarcusBainsEnabled);
- oldTime = tim;
- oldToday = today;
+ mOldTime = tim;
+ mOldToday = today;
- if(disabled || (today<0)) {
+ bool hideIt = !( KOPrefs::instance()->mMarcusBainsEnabled );
+
+ if ( !isHidden() && ( hideIt || ( today < 0 ) ) ) {
hide();
mTimeBox->hide();
return;
- } else {
+ }
+
+ if ( isHidden() && !hideIt ) {
show();
mTimeBox->show();
}
@@ -137,8 +147,12 @@ void MarcusBains::updateLocation(bool recalculate)
if(recalculate)
mTimeBox->setFont(KOPrefs::instance()->mMarcusBainsFont);
- mTimeBox->setText(KGlobal::locale()->formatTime(tim, KOPrefs::instance()->mMarcusBainsShowSeconds));
- mTimeBox->adjustSize();
+ TQString timeStr = KGlobal::locale()->formatTime(tim, KOPrefs::instance()->mMarcusBainsShowSeconds);
+ TQFontMetrics fm = fontMetrics();
+ mTimeBox->setText( timeStr );
+ TQSize sz( fm.width( timeStr + ' ' ), fm.height() );
+ mTimeBox->setFixedSize( sz );
+
if (y-mTimeBox->height()>=0) y-=mTimeBox->height(); else y++;
if (x-mTimeBox->width()+agenda->gridSpacingX() > 0)
x += int( agenda->gridSpacingX() - mTimeBox->width() - 1 );
@@ -157,13 +171,19 @@ void MarcusBains::updateLocation(bool recalculate)
/*
Create an agenda widget with rows rows and columns columns.
*/
-KOAgenda::KOAgenda( int columns, int rows, int rowSize, TQWidget *parent,
- const char *name, WFlags f )
+KOAgenda::KOAgenda( int columns, int rows, int rowSize, CalendarView *calendarView,
+ TQWidget *parent, const char *name, WFlags f )
: TQScrollView( parent, name, f ), mChanger( 0 )
{
mColumns = columns;
mRows = rows;
mGridSpacingY = rowSize;
+ if ( mGridSpacingY < 4 || mGridSpacingY > 30 ) {
+ mGridSpacingY = 10;
+ }
+
+ mCalendarView = calendarView;
+
mAllDayMode = false;
init();
@@ -175,13 +195,14 @@ KOAgenda::KOAgenda( int columns, int rows, int rowSize, TQWidget *parent,
Create an agenda widget with columns columns and one row. This is used for
all-day events.
*/
-KOAgenda::KOAgenda( int columns, TQWidget *parent, const char *name, WFlags f )
- : TQScrollView( parent, name, f )
+KOAgenda::KOAgenda( int columns, CalendarView *calendarView, TQWidget *parent,
+ const char *name, WFlags f ) : TQScrollView( parent, name, f )
{
mColumns = columns;
mRows = 1;
mGridSpacingY = 24;
mAllDayMode = true;
+ mCalendarView = calendarView;
setVScrollBarMode( AlwaysOff );
init();
@@ -214,6 +235,16 @@ const TQString KOAgenda::lastSelectedUid() const
void KOAgenda::init()
{
mGridSpacingX = 100;
+ mDesiredGridSpacingY = KOPrefs::instance()->mHourSize;
+ if ( mDesiredGridSpacingY < 4 || mDesiredGridSpacingY > 30 ) {
+ mDesiredGridSpacingY = 10;
+ }
+
+ // make sure that there are not more than 24 per day
+ mGridSpacingY = (double)height() / (double)mRows;
+ if ( mGridSpacingY < mDesiredGridSpacingY ) {
+ mGridSpacingY = mDesiredGridSpacingY;
+ }
mResizeBorderWidth = 8;
mScrollBorderWidth = 8;
@@ -243,6 +274,7 @@ void KOAgenda::init()
mClickedItem = 0;
mActionItem = 0;
+ mResPair = qMakePair( static_cast<ResourceCalendar *>( 0 ), TQString() );
mActionType = NOP;
mItemMoved = false;
@@ -317,7 +349,7 @@ void KOAgenda::clearSelection()
void KOAgenda::marcus_bains()
{
- if(mMarcusBains) mMarcusBains->updateLocation(true);
+ if(mMarcusBains) mMarcusBains->updateLocationRecalc( true );
}
@@ -510,7 +542,8 @@ bool KOAgenda::eventFilter_key( TQObject *, TQKeyEvent *ke )
void KOAgenda::emitNewEventForSelection()
{
- emit newEventSignal();
+ QPair<ResourceCalendar *, TQString>p = mCalendarView->viewSubResourceCalendar();
+ emit newEventSignal( p.first, p.second );
}
void KOAgenda::finishTypeAhead()
@@ -572,14 +605,17 @@ bool KOAgenda::eventFilter_mouse(TQObject *object, TQMouseEvent *me)
switch (me->type()) {
case TQEvent::MouseButtonPress:
-// kdDebug(5850) << "koagenda: filtered button press" << endl;
+// kdDebug(5850) << "koagenda: filtered button press" << endl;
if (object != viewport()) {
if (me->button() == RightButton) {
mClickedItem = dynamic_cast<KOAgendaItem *>(object);
if (mClickedItem) {
selectItem(mClickedItem);
- emit showIncidencePopupSignal( mClickedItem->incidence(),
+ emit showIncidencePopupSignal( mCalendar,
+ mClickedItem->incidence(),
mClickedItem->itemDate() );
+ } else {
+ return TQScrollView::eventFilter( object, me ); // pass through for use by multiagenda
}
} else {
KOAgendaItem* item = dynamic_cast<KOAgendaItem *>(object);
@@ -587,8 +623,10 @@ bool KOAgenda::eventFilter_mouse(TQObject *object, TQMouseEvent *me)
Incidence *incidence = item->incidence();
if ( incidence->isReadOnly() ) {
mActionItem = 0;
+ mResPair = qMakePair( static_cast<ResourceCalendar *>( 0 ), TQString() );
} else {
mActionItem = item;
+ mResPair = CalHelper::incSubResourceCalendar( mCalendar, incidence );
startItemAction(viewportPos);
}
// Warning: do selectItem() as late as possible, since all
@@ -596,11 +634,12 @@ bool KOAgenda::eventFilter_mouse(TQObject *object, TQMouseEvent *me)
// this filter being run again and mActionItem being set to
// null.
selectItem( item );
+ } else {
+ return TQScrollView::eventFilter( object, me ); // pass through for use by multiagenda
}
}
} else {
- if (me->button() == RightButton)
- {
+ if ( me->button() == RightButton ) {
// if mouse pointer is not in selection, select the cell below the cursor
TQPoint gpos = contentsToGrid( viewportToContents( viewportPos ) );
if ( !ptInSelection( gpos ) ) {
@@ -612,18 +651,18 @@ bool KOAgenda::eventFilter_mouse(TQObject *object, TQMouseEvent *me)
updateContents();
}
showNewEventPopupSignal();
- }
- else
- {
+ } else {
// if mouse pointer is in selection, don't change selection
TQPoint gpos = contentsToGrid( viewportToContents( viewportPos ) );
if ( !ptInSelection( gpos ) ) {
selectItem(0);
mActionItem = 0;
+ mResPair = qMakePair( static_cast<ResourceCalendar *>( 0 ), TQString() );
setCursor(arrowCursor);
startSelectAction(viewportPos);
}
}
+ return TQScrollView::eventFilter( object, me ); // pass through for use by multiagenda
}
break;
@@ -668,29 +707,30 @@ bool KOAgenda::eventFilter_mouse(TQObject *object, TQMouseEvent *me)
} // If we have an action item
} // If move item && !read only
} else {
- if ( mActionType == SELECT ) {
- performSelectAction( viewportPos );
-
- // show cursor at end of timespan
- if ( ((mStartCell.y() < mEndCell.y()) && (mEndCell.x() >= mStartCell.x())) ||
- (mEndCell.x() > mStartCell.x()) )
- indicatorPos = gridToContents( TQPoint(mEndCell.x(), mEndCell.y()+1) );
- else
- indicatorPos = gridToContents( mEndCell );
- }
+ if ( mActionType == SELECT ) {
+ performSelectAction( viewportPos );
+
+ // show cursor at end of timespan
+ if ( ((mStartCell.y() < mEndCell.y()) && (mEndCell.x() >= mStartCell.x())) ||
+ (mEndCell.x() > mStartCell.x()) )
+ indicatorPos = gridToContents( TQPoint(mEndCell.x(), mEndCell.y()+1) );
+ else
+ indicatorPos = gridToContents( mEndCell );
}
+ }
emit mousePosSignal( indicatorPos );
break; }
case TQEvent::MouseButtonDblClick:
if (object == viewport()) {
selectItem(0);
- emit newEventSignal();
+ QPair<ResourceCalendar *, TQString>p = mCalendarView->viewSubResourceCalendar();
+ emit newEventSignal( p.first, p.second );
} else {
- KOAgendaItem *doubleClickedItem = dynamic_cast<KOAgendaItem *>(object);
- if (doubleClickedItem) {
- selectItem(doubleClickedItem);
- emit editIncidenceSignal(doubleClickedItem->incidence());
+ KOAgendaItem *doubleClickedItem = dynamic_cast<KOAgendaItem *>( object );
+ if ( doubleClickedItem ) {
+ selectItem( doubleClickedItem );
+ emit editIncidenceSignal( doubleClickedItem->incidence(), doubleClickedItem->itemDate() );
}
}
break;
@@ -878,10 +918,9 @@ void KOAgenda::performItemAction(const TQPoint& viewportPos)
emit startDragSignal( mActionItem->incidence() );
setCursor( arrowCursor );
mActionItem = 0;
+ mResPair = qMakePair( static_cast<ResourceCalendar *>( 0 ), TQString() );
mActionType = NOP;
mItemMoved = false;
- if ( mItemMoved && mChanger )
- mChanger->endChange( mActionItem->incidence() );
return;
}
} else {
@@ -902,7 +941,8 @@ void KOAgenda::performItemAction(const TQPoint& viewportPos)
// Move or resize item if necessary
if ( mEndCell != gpos ) {
if ( !mItemMoved ) {
- if ( !mChanger || !mChanger->beginChange( mActionItem->incidence() ) ) {
+ if ( !mChanger ||
+ !mChanger->beginChange( mActionItem->incidence(), mResPair.first, mResPair.second ) ) {
KMessageBox::information( this, i18n("Unable to lock item for "
"modification. You cannot make any changes."),
i18n("Locking Failed"), "AgendaLockingFailed" );
@@ -912,6 +952,7 @@ void KOAgenda::performItemAction(const TQPoint& viewportPos)
placeSubCells( mActionItem );
setCursor( arrowCursor );
mActionItem = 0;
+ mResPair = qMakePair( static_cast<ResourceCalendar *>( 0 ), TQString() );
mActionType = NOP;
mItemMoved = false;
return;
@@ -951,7 +992,7 @@ void KOAgenda::performItemAction(const TQPoint& viewportPos)
addChild( newFirst, cpos.x(), cpos.y() );
} else {
newFirst = insertItem( moveItem->incidence(), moveItem->itemDate(),
- moveItem->cellXLeft()-1, rows()+newY, rows()-1 ) ;
+ moveItem->cellXLeft()-1, rows()+newY, rows()-1, moveItem->itemPos(), moveItem->itemCount() ) ;
}
if (newFirst) newFirst->show();
moveItem->prependMoveItem(newFirst);
@@ -996,7 +1037,7 @@ void KOAgenda::performItemAction(const TQPoint& viewportPos)
addChild( newLast, cpos.x(), cpos.y() );
} else {
newLast = insertItem( moveItem->incidence(), moveItem->itemDate(),
- moveItem->cellXLeft()+1, 0, newY-rows()-1 ) ;
+ moveItem->cellXLeft()+1, 0, newY-rows()-1, moveItem->itemPos(), moveItem->itemCount() ) ;
}
moveItem->appendMoveItem( newLast );
newLast->show();
@@ -1046,98 +1087,45 @@ void KOAgenda::endItemAction()
bool multiModify = false;
// FIXME: do the cloning here...
Incidence* inc = mActionItem->incidence();
- // Store modification information in case it is needed to recreate the changes with a new actionitem...
- int mai_xl = mActionItem->cellXLeft();
- int mai_xr = mActionItem->cellXRight();
- int mai_yt = mActionItem->cellYTop();
- int mai_yb = mActionItem->cellYBottom();
- Incidence* newInc;
+
+ if ( mStartCell.x() == mEndCell.x() && mStartCell.y() == mEndCell.y() ) {
+ // not really moved, so stop any change
+ if ( mItemMoved ) {
+ mItemMoved = false;
+ mChanger->endChange( inc, mResPair.first, mResPair.second );
+ }
+ }
if ( mItemMoved ) {
- bool modify = true;
+ Incidence *incToChange = inc;
if ( mActionItem->incidence()->doesRecur() ) {
- int res = KOMessageBox::fourBtnMsgBox( this, TQMessageBox::Question,
- i18n("The item you try to change is a recurring item. Shall the changes "
- "be applied only to this single occurrence, only to the future items, "
- "or to all items in the recurrence?"),
- i18n("Changing Recurring Item"),
- i18n("Only &This Item"), i18n("Only &Future Items"), i18n("&All Occurrences") );
- switch ( res ) {
- case KMessageBox::Ok: // All occurrences
- // Moving the whole sequene of events is handled by the itemModified below.
- modify = true;
- break;
- // FIXME: The following two cases do the following bad things:
- // 1. Pop up a message box asking which resource to save the disassociated event to (!)
- // 2. Crash at mActionItem->endMove(); below.
- case KMessageBox::Yes: { // Just this occurrence
- // Dissociate this occurrence:
- // create clone of event, set relation to old event, set cloned event
- // for mActionItem, add exception date to old event, changeIncidence
- // for the old event, remove the recurrence from the new copy and then just
- // go on with the newly adjusted mActionItem and let the usual code take
- // care of the new time!
- modify = true;
- multiModify = true;
- emit startMultiModify( i18n("Dissociate event from recurrence") );
- Incidence* oldInc = mActionItem->incidence();
- Incidence* oldIncSaved = mActionItem->incidence()->clone();
- newInc = mCalendar->dissociateOccurrence(
- oldInc, mActionItem->itemDate() );
- if ( newInc ) {
- // don't recreate items, they already have the correct position
- emit enableAgendaUpdate( false );
- mActionItem->dissociateFromMultiItem();
- mActionItem->setIncidence( newInc );
- bool success = mChanger->addIncidence( newInc, this );
- emit enableAgendaUpdate( true );
- if ( success ) {
- mChanger->changeIncidence( oldIncSaved, oldInc );
- }
- } else {
- KMessageBox::sorry( this, i18n("Unable to add the exception item to the "
- "calendar. No change will be done."), i18n("Error Occurred") );
- }
- delete oldIncSaved;
- break; }
- case KMessageBox::No/*Future*/: { // All future occurrences
- // Dissociate this occurrence:
- // create clone of event, set relation to old event, set cloned event
- // for mActionItem, add recurrence end date to old event, changeIncidence
- // for the old event, adjust the recurrence for the new copy and then just
- // go on with the newly adjusted mActionItem and let the usual code take
- // care of the new time!
- modify = true;
- multiModify = true;
- emit startMultiModify( i18n("Split future recurrences") );
- Incidence* oldInc = mActionItem->incidence();
- Incidence* oldIncSaved = mActionItem->incidence()->clone();
- newInc = mCalendar->dissociateOccurrence(
- oldInc, mActionItem->itemDate(), false );
- if ( newInc ) {
- emit enableAgendaUpdate( false );
- mActionItem->dissociateFromMultiItem();
- mActionItem->setIncidence( newInc );
- bool success = mChanger->addIncidence( newInc, this );
- emit enableAgendaUpdate( true );
- if ( success ) {
- mChanger->changeIncidence( oldIncSaved, oldInc );
- }
- } else {
- KMessageBox::sorry( this, i18n("Unable to add the future items to the "
- "calendar. No change will be done."), i18n("Error Occurred") );
- }
- delete oldIncSaved;
- break; }
- default:
- modify = false;
- mActionItem->resetMove();
- placeSubCells( mActionItem );
- }
- }
+ Incidence* oldIncSaved = inc->clone();
+ KOGlobals::WhichOccurrences chosenOption;
+ incToChange = mCalendarView->singleOccurrenceOrAll( inc,
+ KOGlobals::EDIT,
+ chosenOption,
+ mActionItem->itemDate() );
+
+ if ( chosenOption == KOGlobals::ONLY_THIS_ONE ||
+ chosenOption == KOGlobals::ONLY_FUTURE ) {
+
+ // Store modification information in case it is needed to recreate the changes with a new actionitem...
+ int mai_xl = mActionItem->cellXLeft();
+ int mai_xr = mActionItem->cellXRight();
+ int mai_yt = mActionItem->cellYTop();
+ int mai_yb = mActionItem->cellYBottom();
+
+ multiModify = true;
+ enableAgendaUpdate( false );
+
+ mChanger->addIncidence( incToChange, mResPair.first, mResPair.second, this );
+ enableAgendaUpdate( true );
+ KOGlobals::WhatChanged wc = chosenOption == KOGlobals::ONLY_THIS_ONE ?
+ KOGlobals::RECURRENCE_MODIFIED_ONE_ONLY :
+ KOGlobals::RECURRENCE_MODIFIED_ALL_FUTURE;
+
+ mChanger->changeIncidence( oldIncSaved, inc, wc, this );
- if ( modify ) {
- if ( multiModify ) {
// mActionItem does not exist any more, seeing as we just got done deleting it
// (by deleting/replacing the original incidence it was created from through
// user modification of said incidence) above!
@@ -1146,7 +1134,7 @@ void KOAgenda::endItemAction()
KOAgendaItem *koai_insertedItem;
for ( koai_insertedItem = mItems.first(); koai_insertedItem; koai_insertedItem = mItems.next() ) {
- if (koai_insertedItem->incidence() == newInc) {
+ if (koai_insertedItem->incidence() == incToChange) {
selectItem( koai_insertedItem );
mSelectedItem->startMove();
mSelectedItem->setCellY(mai_yt, mai_yb);
@@ -1157,15 +1145,12 @@ void KOAgenda::endItemAction()
}
}
-// mActionItem->startMove();
-// mActionItem->setCellY(mai_yt, mai_yb);
-// mActionItem->setCellX(mai_xl, mai_xr);
-// mActionItem->endMove();
+ mActionItem->dissociateFromMultiItem();
+ mActionItem->setIncidence( incToChange );
}
}
- if ( modify ) {
-// if ( !multiModify ) {
+ if ( incToChange ) {
mActionItem->endMove();
KOAgendaItem *placeItem = mActionItem->firstMultiItem();
if ( !placeItem ) {
@@ -1187,17 +1172,27 @@ void KOAgenda::endItemAction()
// Notify about change
// the agenda view will apply the changes to the actual Incidence*!
+ mChanger->endChange( inc, mResPair.first, mResPair.second );
emit itemModified( modif );
-// }
+ } else {
+
+ mActionItem->resetMove();
+ placeSubCells( mActionItem );
+
+ // the item was moved, but not further modified, since it's not recurring
+ // make sure the view updates anyhow, with the right item
+ mChanger->endChange( inc, mResPair.first, mResPair.second );
+ emit itemModified( mActionItem );
}
- // FIXME: If the change failed, we need to update the view!
- mChanger->endChange( inc );
}
mActionItem = 0;
+ mResPair = qMakePair( static_cast<ResourceCalendar *>( 0 ), TQString() );
mItemMoved = false;
- if ( multiModify ) emit endMultiModify();
+ if ( multiModify ) {
+ emit endMultiModify();
+ }
kdDebug(5850) << "KOAgenda::endItemAction() done" << endl;
}
@@ -1280,7 +1275,7 @@ void KOAgenda::placeAgendaItem( KOAgendaItem *item, double subCellWidth )
TQPoint pt = gridToContents( TQPoint( item->cellXLeft(), item->cellYTop() ) );
// right lower corner
TQPoint pt1 = gridToContents( TQPoint( item->cellXLeft() + item->cellWidth(),
- item->cellYBottom()+1 ) );
+ item->cellYBottom()+1 ) );
double subCellPos = item->subCell() * subCellWidth;
@@ -1594,23 +1589,16 @@ void KOAgenda::setStartTime( const TQTime &startHour )
Insert KOAgendaItem into agenda.
*/
KOAgendaItem *KOAgenda::insertItem( Incidence *incidence, const TQDate &qd, int X,
- int YTop, int YBottom )
+ int YTop, int YBottom, int itemPos, int itemCount )
{
-#if 0
- kdDebug(5850) << "KOAgenda::insertItem:" << incidence->summary() << "-"
- << qd.toString() << " ;top, bottom:" << YTop << "," << YBottom
- << endl;
-#endif
-
if ( mAllDayMode ) {
kdDebug(5850) << "KOAgenda: calling insertItem in all-day mode is illegal." << endl;
return 0;
}
-
mActionType = NOP;
- KOAgendaItem *agendaItem = new KOAgendaItem( incidence, qd, viewport() );
+ KOAgendaItem *agendaItem = new KOAgendaItem( mCalendar, incidence, qd, viewport(), itemPos, itemCount );
connect( agendaItem, TQT_SIGNAL( removeAgendaItem( KOAgendaItem * ) ),
TQT_SLOT( removeAgendaItem( KOAgendaItem * ) ) );
connect( agendaItem, TQT_SIGNAL( showAgendaItem( KOAgendaItem * ) ),
@@ -1655,7 +1643,7 @@ KOAgendaItem *KOAgenda::insertAllDayItem( Incidence *event, const TQDate &qd,
mActionType = NOP;
- KOAgendaItem *agendaItem = new KOAgendaItem( event, qd, viewport() );
+ KOAgendaItem *agendaItem = new KOAgendaItem( mCalendar, event, qd, viewport(), 1, 1 );
connect( agendaItem, TQT_SIGNAL( removeAgendaItem( KOAgendaItem* ) ),
TQT_SLOT( removeAgendaItem( KOAgendaItem* ) ) );
connect( agendaItem, TQT_SIGNAL( showAgendaItem( KOAgendaItem* ) ),
@@ -1683,10 +1671,10 @@ KOAgendaItem *KOAgenda::insertAllDayItem( Incidence *event, const TQDate &qd,
}
-void KOAgenda::insertMultiItem (Event *event,const TQDate &qd,int XBegin,int XEnd,
- int YTop,int YBottom)
+void KOAgenda::insertMultiItem( Event *event, const TQDate &qd, int XBegin, int XEnd,
+ int YTop, int YBottom )
{
- if (mAllDayMode) {
+ if ( mAllDayMode ) {
kdDebug(5850) << "KOAgenda: calling insertMultiItem in all-day mode is illegal." << endl;
return;
}
@@ -1698,40 +1686,50 @@ void KOAgenda::insertMultiItem (Event *event,const TQDate &qd,int XBegin,int XEn
int count = 0;
KOAgendaItem *current = 0;
TQPtrList<KOAgendaItem> multiItems;
- int visibleCount = mSelectedDates.first().daysTo(mSelectedDates.last());
+ const int visibleCount = mSelectedDates.first().daysTo( mSelectedDates.last() );
for ( cellX = XBegin; cellX <= XEnd; ++cellX ) {
++count;
//Only add the items that are visible.
- if( cellX >=0 && cellX <= visibleCount ) {
- if ( cellX == XBegin ) cellYTop = YTop;
- else cellYTop = 0;
- if ( cellX == XEnd ) cellYBottom = YBottom;
- else cellYBottom = rows() - 1;
+ if( cellX >= 0 && cellX <= visibleCount ) {
+ if ( cellX == XBegin ) {
+ cellYTop = YTop;
+ } else {
+ cellYTop = 0;
+ }
+
+ if ( cellX == XEnd ) {
+ cellYBottom = YBottom;
+ } else {
+ cellYBottom = rows() - 1;
+ }
+
newtext = TQString("(%1/%2): ").arg( count ).arg( width );
newtext.append( event->summary() );
- current = insertItem( event, qd, cellX, cellYTop, cellYBottom );
+ current = insertItem( event, qd, cellX, cellYTop, cellYBottom, count, width );
current->setText( newtext );
multiItems.append( current );
}
}
-
- KOAgendaItem *next = 0;
- KOAgendaItem *prev = 0;
- KOAgendaItem *last = multiItems.last();
- KOAgendaItem *first = multiItems.first();
- KOAgendaItem *setFirst,*setLast;
- current = first;
- while (current) {
- next = multiItems.next();
- if (current == first) setFirst = 0;
- else setFirst = first;
- if (current == last) setLast = 0;
- else setLast = last;
-
- current->setMultiItem(setFirst, prev, next, setLast);
- prev=current;
- current = next;
+ TQPtrList<KOAgendaItem>::iterator it = multiItems.begin();
+ TQPtrList<KOAgendaItem>::iterator e = multiItems.end();
+
+ if ( it != e ) { // .first asserts if the list is empty
+ KOAgendaItem *first = multiItems.first();
+ KOAgendaItem *last = multiItems.last();
+ KOAgendaItem *prev = 0, *next = 0;
+
+ while ( it != e ) {
+ KOAgendaItem *item = *it;
+ ++it;
+ next = ( it == e ) ? 0 : (*it);
+ if ( item ) {
+ item->setMultiItem( ( item == first ) ? 0 : first,
+ prev, next,
+ ( item == last ) ? 0 : last );
+ }
+ prev = item;
+ }
}
marcus_bains();
@@ -1760,11 +1758,15 @@ void KOAgenda::removeIncidence( Incidence *incidence )
void KOAgenda::showAgendaItem( KOAgendaItem *agendaItem )
{
- if ( !agendaItem ) return;
+ if ( !agendaItem ) {
+ return;
+ }
+
agendaItem->hide();
addChild( agendaItem );
- if ( !mItems.containsRef( agendaItem ) )
+ if ( !mItems.containsRef( agendaItem ) ) {
mItems.append( agendaItem );
+ }
placeSubCells( agendaItem );
agendaItem->show();
@@ -1777,8 +1779,9 @@ bool KOAgenda::removeAgendaItem( KOAgendaItem *item )
KOAgendaItem *thisItem = item;
TQPtrList<KOAgendaItem> conflictItems = thisItem->conflictItems();
removeChild( thisItem );
+
int pos = mItems.find( thisItem );
- if ( pos>=0 ) {
+ if ( pos >= 0 ) {
mItems.take( pos );
taken = true;
}
@@ -1843,23 +1846,24 @@ void KOAgenda::resizeEvent ( TQResizeEvent *ev )
void KOAgenda::resizeAllContents()
{
double subCellWidth;
- KOAgendaItem *item;
- if (mAllDayMode) {
- for ( item=mItems.first(); item != 0; item=mItems.next() ) {
- subCellWidth = calcSubCellWidth( item );
- placeAgendaItem( item, subCellWidth );
- }
- } else {
- for ( item=mItems.first(); item != 0; item=mItems.next() ) {
- subCellWidth = calcSubCellWidth( item );
- placeAgendaItem( item, subCellWidth );
+ if ( mItems.count() > 0 ) {
+ KOAgendaItem *item;
+ if (mAllDayMode) {
+ for ( item=mItems.first(); item != 0; item=mItems.next() ) {
+ subCellWidth = calcSubCellWidth( item );
+ placeAgendaItem( item, subCellWidth );
+ }
+ } else {
+ for ( item=mItems.first(); item != 0; item=mItems.next() ) {
+ subCellWidth = calcSubCellWidth( item );
+ placeAgendaItem( item, subCellWidth );
+ }
}
}
checkScrollBoundaries();
marcus_bains();
}
-
void KOAgenda::scrollUp()
{
scrollBy(0,-mScrollOffset);
@@ -1886,15 +1890,23 @@ int KOAgenda::minimumWidth() const
void KOAgenda::updateConfig()
{
double oldGridSpacingY = mGridSpacingY;
+
mDesiredGridSpacingY = KOPrefs::instance()->mHourSize;
- // make sure that there are not more than 24 per day
- mGridSpacingY = (double)height()/(double)mRows;
- if (mGridSpacingY<mDesiredGridSpacingY) mGridSpacingY=mDesiredGridSpacingY;
+ if ( mDesiredGridSpacingY < 4 || mDesiredGridSpacingY > 30 ) {
+ mDesiredGridSpacingY = 10;
+ }
+
+ // make sure that there are not more than 24 per day
+ mGridSpacingY = (double)height() / (double)mRows;
+ if ( mGridSpacingY < mDesiredGridSpacingY ) {
+ mGridSpacingY = mDesiredGridSpacingY;
+ }
//can be two doubles equal?, it's better to compare them with an epsilon
- if ( fabs( oldGridSpacingY - mGridSpacingY ) > 0.1 )
+ if ( fabs( oldGridSpacingY - mGridSpacingY ) > 0.1 ) {
resizeContents( int( mGridSpacingX * mColumns ),
- int( mGridSpacingY * mRows ) );
+ int( mGridSpacingY * mRows ) );
+ }
calculateWorkingHours();
@@ -1941,7 +1953,9 @@ int KOAgenda::visibleContentsYMax()
void KOAgenda::deselectItem()
{
- if (mSelectedItem.isNull()) return;
+ if ( mSelectedItem.isNull() ) {
+ return;
+ }
mSelectedItem->select(false);
mSelectedItem = 0;
}
@@ -1951,15 +1965,14 @@ void KOAgenda::selectItem(KOAgendaItem *item)
if ((KOAgendaItem *)mSelectedItem == item) return;
deselectItem();
if (item == 0) {
- emit incidenceSelected( 0 );
+ emit incidenceSelected( 0, TQDate() );
return;
}
mSelectedItem = item;
mSelectedItem->select();
- Incidence *incidence = mSelectedItem->incidence();
- assert( incidence );
- mSelectedUid = incidence->uid();
- emit incidenceSelected( incidence );
+ assert( mSelectedItem->incidence() );
+ mSelectedUid = mSelectedItem->incidence()->uid();
+ emit incidenceSelected( mSelectedItem->incidence(), mSelectedItem->itemDate() );
}
void KOAgenda::selectItemByUID( const TQString& uid )
diff --git a/korganizer/koagenda.h b/korganizer/koagenda.h
index a6d06d006..223ea1aa3 100644
--- a/korganizer/koagenda.h
+++ b/korganizer/koagenda.h
@@ -29,6 +29,7 @@
#include <tqguardedptr.h>
#include <libkcal/incidencebase.h>
+#include "calendarview.h"
class TQPopupMenu;
class TQTime;
@@ -37,44 +38,46 @@ class KConfig;
class KOAgenda;
class KOAgendaItem;
-using namespace KOrg;
namespace KOrg {
-class IncidenceChangerBase;
+ class IncidenceChangerBase;
}
+using namespace KOrg;
-using namespace KCal;
namespace KCal {
-class Event;
-class Todo;
-class Calendar;
+ class Event;
+ class Todo;
+ class Calendar;
}
+using namespace KCal;
-class MarcusBains : public TQFrame {
- Q_OBJECT
+class MarcusBains : public TQFrame
+{
+ Q_OBJECT
public:
MarcusBains( KOAgenda *agenda = 0, const char *name = 0 );
+ void updateLocationRecalc( bool recalculate = false );
virtual ~MarcusBains();
public slots:
- void updateLocation( bool recalculate = false );
+ void updateLocation();
private:
int todayColumn();
TQTimer *minutes;
TQLabel *mTimeBox;
KOAgenda *agenda;
- TQTime oldTime;
- int oldToday;
+ TQTime mOldTime;
+ int mOldToday;
};
-
-class KOAgenda : public QScrollView
+class KOAgenda : public TQScrollView
{
- Q_OBJECT
+ Q_OBJECT
public:
- KOAgenda ( int columns, int rows, int columnSize, TQWidget *parent=0,
- const char *name = 0, WFlags f = 0 );
- KOAgenda ( int columns, TQWidget *parent = 0,
+ KOAgenda ( int columns, int rows, int columnSize, CalendarView *calendarView,
+ TQWidget *parent=0, const char *name = 0, WFlags f = 0 );
+
+ KOAgenda ( int columns, CalendarView *calendarView, TQWidget *parent = 0,
const char *name = 0, WFlags f = 0 );
virtual ~KOAgenda();
@@ -103,7 +106,7 @@ class KOAgenda : public QScrollView
void setStartTime( const TQTime &startHour );
KOAgendaItem *insertItem ( Incidence *incidence, const TQDate &qd, int X, int YTop,
- int YBottom );
+ int YBottom, int itemPos, int itemCount );
KOAgendaItem *insertAllDayItem ( Incidence *event, const TQDate &qd, int XBegin,
int XEnd );
void insertMultiItem ( Event *event, const TQDate &qd, int XBegin, int XEnd,
@@ -171,18 +174,18 @@ class KOAgenda : public QScrollView
void showAgendaItem( KOAgendaItem *item );
signals:
- void newEventSignal();
+ void newEventSignal( ResourceCalendar *res, const TQString &subResource );
void newTimeSpanSignal( const TQPoint &, const TQPoint & );
void newStartSelectSignal();
- void showIncidenceSignal( Incidence * );
- void editIncidenceSignal( Incidence * );
+ void showIncidenceSignal( Incidence *, const TQDate & );
+ void editIncidenceSignal( Incidence *, const TQDate & );
void deleteIncidenceSignal( Incidence * );
- void showIncidencePopupSignal( Incidence *, const TQDate &);
+ void showIncidencePopupSignal( Calendar *, Incidence *, const TQDate &);
void showNewEventPopupSignal();
void itemModified( KOAgendaItem *item );
- void incidenceSelected( Incidence * );
+ void incidenceSelected( Incidence *, const TQDate & );
void startMultiModify( const TQString & );
void endMultiModify();
@@ -343,6 +346,7 @@ class KOAgenda : public QScrollView
// The KOAgendaItem, which is being moved/resized
TQGuardedPtr<KOAgendaItem> mActionItem;
+ QPair<ResourceCalendar *, TQString> mResPair;
// Currently selected item
TQGuardedPtr<KOAgendaItem> mSelectedItem;
@@ -373,6 +377,8 @@ class KOAgenda : public QScrollView
bool mReturnPressed;
KOrg::IncidenceChangerBase *mChanger;
+
+ CalendarView *mCalendarView;
};
#endif // KOAGENDA_H
diff --git a/korganizer/koagendaitem.cpp b/korganizer/koagendaitem.cpp
index 629f59c31..de1f4ef87 100644
--- a/korganizer/koagendaitem.cpp
+++ b/korganizer/koagendaitem.cpp
@@ -63,12 +63,16 @@ TQPixmap *KOAgendaItem::organizerPxmp = 0;
//--------------------------------------------------------------------------
-KOAgendaItem::KOAgendaItem( Incidence *incidence, const TQDate &qd, TQWidget *parent,
+KOAgendaItem::KOAgendaItem( Calendar *calendar, Incidence *incidence,
+ const TQDate &qd, TQWidget *parent,
+ int itemPos, int itemCount,
const char *name, WFlags f ) :
- TQWidget( parent, name, f ), mIncidence( incidence ), mDate( qd ),
+ TQWidget( parent, name, f ), mCalendar( calendar ), mIncidence( incidence ), mDate( qd ),
mLabelText( mIncidence->summary() ), mIconAlarm( false ),
mIconRecur( false ), mIconReadonly( false ), mIconReply( false ),
mIconGroup( false ), mIconGroupTentative( false ), mIconOrganizer( false ),
+ mSpecialEvent( false ),
+ mItemPos( itemPos ), mItemCount( itemCount ),
mMultiItemInfo( 0 ), mStartMoveInfo( 0 )
{
setBackgroundMode( Qt::NoBackground );
@@ -83,7 +87,7 @@ KOAgendaItem::KOAgendaItem( Incidence *incidence, const TQDate &qd, TQWidget *pa
mSelected = true;
select( false );
- KOIncidenceToolTip::add( this, incidence, toolTipGroup() );
+ KOIncidenceToolTip::add( this, mCalendar, incidence, mDate, toolTipGroup() );
setAcceptDrops( true );
}
@@ -93,7 +97,7 @@ void KOAgendaItem::updateIcons()
mIconReadonly = mIncidence->isReadOnly();
mIconRecur = mIncidence->doesRecur();
mIconAlarm = mIncidence->isAlarmEnabled();
- if ( mIncidence->attendeeCount() > 0 ) {
+ if ( mIncidence->attendeeCount() > 1 ) {
if ( KOPrefs::instance()->thatIsMe( mIncidence->organizer().email() ) ) {
mIconReply = false;
mIconGroup = false;
@@ -171,7 +175,6 @@ bool KOAgendaItem::setIncidence( Incidence *i )
return true;
}
-
/*
Return height of item in units of agenda cells
*/
@@ -217,10 +220,12 @@ void KOAgendaItem::setCellY( int YTop, int YBottom )
mCellYBottom = YBottom;
}
-void KOAgendaItem::setMultiItem(KOAgendaItem *first, KOAgendaItem *prev,
- KOAgendaItem *next, KOAgendaItem *last)
+void KOAgendaItem::setMultiItem( KOAgendaItem *first, KOAgendaItem *prev,
+ KOAgendaItem *next, KOAgendaItem *last )
{
- if (!mMultiItemInfo) mMultiItemInfo=new MultiItemInfo;
+ if ( !mMultiItemInfo ) {
+ mMultiItemInfo = new MultiItemInfo;
+ }
mMultiItemInfo->mFirstMultiItem = first;
mMultiItemInfo->mPrevMultiItem = prev;
mMultiItemInfo->mNextMultiItem = next;
@@ -575,18 +580,16 @@ void KOAgendaItem::dropEvent( TQDropEvent *e )
}
#ifndef KORG_NOKABC
- TQString vcards;
- KABC::VCardConverter converter;
-
- KVCardDrag::decode( e, vcards );
- KABC::Addressee::List list = converter.parseVCards( vcards );
- KABC::Addressee::List::Iterator it;
- for ( it = list.begin(); it != list.end(); ++it ) {
- TQString em( (*it).fullEmail() );
- if (em.isEmpty()) {
- em=(*it).realName();
+ KABC::Addressee::List list;
+ if ( KVCardDrag::decode( e, list ) ) {
+ KABC::Addressee::List::Iterator it;
+ for ( it = list.begin(); it != list.end(); ++it ) {
+ TQString em( (*it).fullEmail() );
+ if ( em.isEmpty() ) {
+ em = (*it).realName();
+ }
+ addAttendee( em );
}
- addAttendee( em );
}
#else
if( decoded ) {
@@ -665,11 +668,21 @@ static void conditionalPaint( TQPainter *p, bool cond, int &x, int ft,
void KOAgendaItem::paintEventIcon( TQPainter *p, int &x, int ft )
{
if ( !mIncidence ) return;
- static const TQPixmap eventPxmp =
- KOGlobals::self()->smallIcon( "appointment" );
- if ( mIncidence->type() != "Event" )
- return;
- conditionalPaint( p, true, x, ft, eventPxmp );
+
+ if ( mIncidence->type() == "Event" ) {
+ TQPixmap eventPxmp;
+ if ( mIncidence->customProperty( "KABC", "BIRTHDAY" ) == "YES" ) {
+ mSpecialEvent = true;
+ if ( mIncidence->customProperty( "KABC", "ANNIVERSARY" ) == "YES" ) {
+ eventPxmp = KOGlobals::self()->smallIcon( "calendaranniversary" );
+ } else {
+ eventPxmp = KOGlobals::self()->smallIcon( "calendarbirthday" );
+ }
+ conditionalPaint( p, true, x, ft, eventPxmp );
+ }
+ // per kolab/issue4349 we don't draw a regular appointment icon (to save space)
+ }
+
}
void KOAgendaItem::paintTodoIcon( TQPainter *p, int &x, int ft )
@@ -702,9 +715,11 @@ void KOAgendaItem::paintIcons( TQPainter *p, int &x, int ft )
{
paintEventIcon( p, x, ft );
paintTodoIcon( p, x, ft );
- paintAlarmIcon( p, x, ft );
- conditionalPaint( p, mIconRecur, x, ft, *recurPxmp );
- conditionalPaint( p, mIconReadonly, x, ft, *readonlyPxmp );
+ if ( !mSpecialEvent ) {
+ paintAlarmIcon( p, x, ft );
+ }
+ conditionalPaint( p, mIconRecur && !mSpecialEvent, x, ft, *recurPxmp );
+ conditionalPaint( p, mIconReadonly && !mSpecialEvent, x, ft, *readonlyPxmp );
conditionalPaint( p, mIconReply, x, ft, *replyPxmp );
conditionalPaint( p, mIconGroup, x, ft, *groupPxmp );
conditionalPaint( p, mIconGroupTentative, x, ft, *groupPxmpTentative );
@@ -762,7 +777,7 @@ void KOAgendaItem::paintEvent( TQPaintEvent *ev )
TQStringList categories = mIncidence->categories();
TQString cat = categories.first();
if (cat.isEmpty())
- categoryColor = KOPrefs::instance()->mEventColor;
+ categoryColor = KOPrefs::instance()->unsetCategoryColor();
else
categoryColor = *(KOPrefs::instance()->categoryColor(cat));
@@ -770,9 +785,6 @@ void KOAgendaItem::paintEvent( TQPaintEvent *ev )
if ( !resourceColor.isValid() )
resourceColor = categoryColor;
- if (!KOPrefs::instance()->hasCategoryColor(cat))
- categoryColor = resourceColor;
-
TQColor frameColor;
if ( KOPrefs::instance()->agendaViewColors() == KOPrefs::ResourceOnly ||
KOPrefs::instance()->agendaViewColors() == KOPrefs::CategoryInsideResourceOutside ) {
@@ -790,6 +802,16 @@ void KOAgendaItem::paintEvent( TQPaintEvent *ev )
}
}
+ if ( cat.isEmpty() &&
+ KOPrefs::instance()->agendaViewColors() == KOPrefs::ResourceInsideCategoryOutside ) {
+ frameColor = bgColor;
+ }
+
+ if ( cat.isEmpty() &&
+ KOPrefs::instance()->agendaViewColors() == KOPrefs::CategoryInsideResourceOutside ) {
+ bgColor = frameColor;
+ }
+
if ( mSelected ) {
frameColor = TQColor( 85 + frameColor.red() * 2/3,
85 + frameColor.green() * 2/3,
diff --git a/korganizer/koagendaitem.h b/korganizer/koagendaitem.h
index fc774dd1f..f15594428 100644
--- a/korganizer/koagendaitem.h
+++ b/korganizer/koagendaitem.h
@@ -34,6 +34,7 @@ class TQDragEnterEvent;
class TQDropEvent;
namespace KCal {
+class Calendar;
class Incidence;
}
using namespace KCal;
@@ -75,8 +76,10 @@ class KOAgendaItem : public TQWidget, public KOrg::CellItem
{
Q_OBJECT
public:
- KOAgendaItem(Incidence *incidence, const TQDate &qd, TQWidget *parent, const char *name=0,
- WFlags f=0 );
+ KOAgendaItem( Calendar *calendar, Incidence *incidence, const TQDate &qd,
+ TQWidget *parent,
+ int itemPos, int itemCount,
+ const char *name = 0, WFlags f = 0 );
int cellXLeft() const { return mCellXLeft; }
int cellXRight() const { return mCellXRight; }
@@ -85,6 +88,9 @@ class KOAgendaItem : public TQWidget, public KOrg::CellItem
int cellHeight() const;
int cellWidth() const;
+ int itemPos() const { return mItemPos; }
+ int itemCount() const { return mItemCount; }
+
void setCellXY(int X, int YTop, int YBottom);
void setCellY(int YTop, int YBottom);
void setCellX(int XLeft, int XRight);
@@ -173,15 +179,19 @@ class KOAgendaItem : public TQWidget, public KOrg::CellItem
private:
int mCellXLeft, mCellXRight;
int mCellYTop, mCellYBottom;
- int mSubCell; // subcell number of this item
- int mSubCells; // Total number of subcells in cell of this item
+ Calendar *mCalendar;
Incidence *mIncidence; // corresponding event or todo
TQDate mDate; //date this events occurs (for recurrence)
TQString mLabelText;
bool mIconAlarm, mIconRecur, mIconReadonly;
bool mIconReply, mIconGroup, mIconGroupTentative;
- bool mIconOrganizer;
+ bool mIconOrganizer, mSpecialEvent;
+
+ // For incidences that expand through more than 1 day
+ // Will be 1 for single day incidences
+ int mItemPos;
+ int mItemCount;
// Multi item pointers
MultiItemInfo* mMultiItemInfo;
diff --git a/korganizer/koagendaview.cpp b/korganizer/koagendaview.cpp
index e45493ab2..c60546f7b 100644
--- a/korganizer/koagendaview.cpp
+++ b/korganizer/koagendaview.cpp
@@ -152,6 +152,7 @@ void KOAlternateLabel::useShortText()
TQLabel::setText( mShortText );
TQToolTip::remove( this );
TQToolTip::add( this, mExtensiveText );
+ update(); // for kolab/issue4350
}
void KOAlternateLabel::useLongText()
@@ -160,6 +161,7 @@ void KOAlternateLabel::useLongText()
TQLabel::setText( mLongText );
TQToolTip::remove( this );
TQToolTip::add( this, mExtensiveText );
+ update(); // for kolab/issue4350
}
void KOAlternateLabel::useExtensiveText()
@@ -167,7 +169,8 @@ void KOAlternateLabel::useExtensiveText()
mTextTypeFixed = true;
TQLabel::setText( mExtensiveText );
TQToolTip::remove( this );
- TQToolTip::hide();
+ TQToolTip::add( this, "" );
+ update(); // for kolab/issue4350
}
void KOAlternateLabel::useDefaultText()
@@ -176,27 +179,55 @@ void KOAlternateLabel::useDefaultText()
squeezeTextToLabel();
}
+KOAlternateLabel::TextType KOAlternateLabel::largestFittingTextType() const
+{
+ TQFontMetrics fm( fontMetrics() );
+ const int labelWidth = size().width();
+ const int longTextWidth = fm.width( mLongText );
+ const int extensiveTextWidth = fm.width( mExtensiveText );
+ if ( extensiveTextWidth <= labelWidth )
+ return Extensive;
+ else if ( longTextWidth <= labelWidth )
+ return Long;
+ else
+ return Short;
+}
+
+void KOAlternateLabel::setFixedType( TextType type )
+{
+ switch ( type )
+ {
+ case Extensive: useExtensiveText(); break;
+ case Long: useLongText(); break;
+ case Short: useShortText(); break;
+ }
+}
+
void KOAlternateLabel::squeezeTextToLabel()
{
- if (mTextTypeFixed) return;
-
- TQFontMetrics fm(fontMetrics());
- int labelWidth = size().width();
- int textWidth = fm.width(mLongText);
- int longTextWidth = fm.width(mExtensiveText);
- if (longTextWidth <= labelWidth) {
- TQLabel::setText( mExtensiveText );
- TQToolTip::remove( this );
- TQToolTip::hide();
- } else if (textWidth <= labelWidth) {
- TQLabel::setText( mLongText );
- TQToolTip::remove( this );
- TQToolTip::add( this, mExtensiveText );
- } else {
- TQLabel::setText( mShortText );
- TQToolTip::remove( this );
- TQToolTip::add( this, mExtensiveText );
+ if ( mTextTypeFixed )
+ return;
+
+ const TextType type = largestFittingTextType();
+ switch ( type )
+ {
+ case Extensive:
+ TQLabel::setText( mExtensiveText );
+ TQToolTip::remove( this );
+ TQToolTip::add( this, "" );
+ break;
+ case Long:
+ TQLabel::setText( mLongText );
+ TQToolTip::remove( this );
+ TQToolTip::add( this, mExtensiveText );
+ break;
+ case Short:
+ TQLabel::setText( mShortText );
+ TQToolTip::remove( this );
+ TQToolTip::add( this, mExtensiveText );
+ break;
}
+ update(); // for kolab/issue4350
}
void KOAlternateLabel::resizeEvent( TQResizeEvent * )
@@ -211,22 +242,21 @@ TQSize KOAlternateLabel::minimumSizeHint() const
return sh;
}
-void KOAlternateLabel::setText( const TQString &text ) {
- mLongText = text;
- squeezeTextToLabel();
-}
-
-
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
-KOAgendaView::KOAgendaView(Calendar *cal,TQWidget *parent,const char *name, bool isSideBySide ) :
- KOrg::AgendaView (cal,parent,name), mExpandButton( 0 ), mAllowAgendaUpdate( true ),
+KOAgendaView::KOAgendaView( Calendar *cal,
+ CalendarView *calendarView,
+ TQWidget *parent,
+ const char *name,
+ bool isSideBySide ) :
+ KOrg::AgendaView (cal, parent,name), mExpandButton( 0 ),
+ mAllowAgendaUpdate( true ),
mUpdateItem( 0 ),
- mResource( 0 ),
mIsSideBySide( isSideBySide ),
- mPendingChanges( true )
+ mPendingChanges( true ),
+ mAreDatesInitialized( false )
{
mSelectedDates.append(TQDate::currentDate());
@@ -291,7 +321,8 @@ KOAgendaView::KOAgendaView(Calendar *cal,TQWidget *parent,const char *name, bool
label->setAlignment( Qt::AlignRight | Qt::AlignVCenter | Qt::WordBreak );
}
- mAllDayAgenda = new KOAgenda(1,mAllDayFrame);
+ mAllDayAgenda = new KOAgenda( 1, calendarView, mAllDayFrame );
+ mAllDayAgenda->setCalendar( calendar() );
TQWidget *dummyAllDayRight = new TQWidget(mAllDayFrame);
// Create agenda frame
@@ -312,7 +343,8 @@ KOAgendaView::KOAgendaView(Calendar *cal,TQWidget *parent,const char *name, bool
agendaLayout->addWidget(mTimeLabels,1,0);
// Create agenda
- mAgenda = new KOAgenda(1,96,KOPrefs::instance()->mHourSize,agendaFrame);
+ mAgenda = new KOAgenda( 1, 96, KOPrefs::instance()->mHourSize, calendarView, agendaFrame );
+ mAgenda->setCalendar( calendar() );
agendaLayout->addMultiCellWidget(mAgenda,1,1,1,2);
agendaLayout->setColStretch(1,1);
@@ -330,7 +362,7 @@ KOAgendaView::KOAgendaView(Calendar *cal,TQWidget *parent,const char *name, bool
// Update widgets to reflect user preferences
// updateConfig();
- createDayLabels();
+ createDayLabels( true );
if ( !isSideBySide ) {
// these blank widgets make the All Day Event box line up with the agenda
@@ -363,17 +395,13 @@ KOAgendaView::KOAgendaView(Calendar *cal,TQWidget *parent,const char *name, bool
connect( mAgenda, TQT_SIGNAL(upperYChanged(int)),
TQT_SLOT(updateEventIndicatorBottom(int)));
- connectAgenda( mAgenda, mAgendaPopup, mAllDayAgenda );
- connectAgenda( mAllDayAgenda, mAllDayAgendaPopup, mAgenda);
+ if ( !readOnly() ) {
+ connectAgenda( mAgenda, mAgendaPopup, mAllDayAgenda );
+ connectAgenda( mAllDayAgenda, mAllDayAgendaPopup, mAgenda);
+ }
- if ( cal )
+ if ( cal ) {
cal->registerObserver( this );
-
- CalendarResources *calres = dynamic_cast<CalendarResources*>( cal );
- if ( calres ) {
- connect( calres, TQT_SIGNAL(signalResourceAdded(ResourceCalendar *)), TQT_SLOT(resourcesChanged()) );
- connect( calres, TQT_SIGNAL(signalResourceModified( ResourceCalendar *)), TQT_SLOT(resourcesChanged()) );
- connect( calres, TQT_SIGNAL(signalResourceDeleted(ResourceCalendar *)), TQT_SLOT(resourcesChanged()) );
}
}
@@ -389,52 +417,53 @@ KOAgendaView::~KOAgendaView()
void KOAgendaView::connectAgenda( KOAgenda *agenda, TQPopupMenu *popup,
KOAgenda *otherAgenda )
{
- connect( agenda, TQT_SIGNAL( showIncidencePopupSignal( Incidence *, const TQDate & ) ),
- popup, TQT_SLOT( showIncidencePopup( Incidence *, const TQDate & ) ) );
+ connect( agenda, TQT_SIGNAL(showIncidencePopupSignal(Calendar *,Incidence *,const TQDate &)),
+ popup, TQT_SLOT(showIncidencePopup(Calendar *,Incidence *,const TQDate &)) );
- connect( agenda, TQT_SIGNAL( showNewEventPopupSignal() ),
- TQT_SLOT( showNewEventPopup() ) );
+ connect( agenda, TQT_SIGNAL(showNewEventPopupSignal()),
+ TQT_SLOT(showNewEventPopup()) );
- agenda->setCalendar( calendar() );
// Create/Show/Edit/Delete Event
- connect( agenda, TQT_SIGNAL( newEventSignal() ), TQT_SIGNAL( newEventSignal() ) );
-
- connect( agenda, TQT_SIGNAL( newStartSelectSignal() ),
- otherAgenda, TQT_SLOT( clearSelection() ) );
- connect( agenda, TQT_SIGNAL( newStartSelectSignal() ),
- TQT_SIGNAL( timeSpanSelectionChanged()) );
-
- connect( agenda, TQT_SIGNAL( editIncidenceSignal( Incidence * ) ),
- TQT_SIGNAL( editIncidenceSignal( Incidence * ) ) );
- connect( agenda, TQT_SIGNAL( showIncidenceSignal( Incidence * ) ),
- TQT_SIGNAL( showIncidenceSignal( Incidence * ) ) );
- connect( agenda, TQT_SIGNAL( deleteIncidenceSignal( Incidence * ) ),
- TQT_SIGNAL( deleteIncidenceSignal( Incidence * ) ) );
-
- connect( agenda, TQT_SIGNAL( startMultiModify( const TQString & ) ),
- TQT_SIGNAL( startMultiModify( const TQString & ) ) );
- connect( agenda, TQT_SIGNAL( endMultiModify() ),
- TQT_SIGNAL( endMultiModify() ) );
-
- connect( agenda, TQT_SIGNAL( itemModified( KOAgendaItem * ) ),
- TQT_SLOT( updateEventDates( KOAgendaItem * ) ) );
- connect( agenda, TQT_SIGNAL( enableAgendaUpdate( bool ) ),
- TQT_SLOT( enableAgendaUpdate( bool ) ) );
+ connect( agenda, TQT_SIGNAL(newEventSignal(ResourceCalendar *,const TQString &)),
+ TQT_SIGNAL(newEventSignal(ResourceCalendar *,const TQString &)) );
+
+ connect( agenda, TQT_SIGNAL(newStartSelectSignal()),
+ otherAgenda, TQT_SLOT(clearSelection()) );
+ connect( agenda, TQT_SIGNAL(newStartSelectSignal()),
+ TQT_SIGNAL(timeSpanSelectionChanged()) );
+
+ connect( agenda, TQT_SIGNAL(editIncidenceSignal(Incidence *,const TQDate &)),
+ TQT_SIGNAL(editIncidenceSignal(Incidence *,const TQDate &)) );
+ connect( agenda, TQT_SIGNAL(showIncidenceSignal(Incidence *,const TQDate &)),
+ TQT_SIGNAL(showIncidenceSignal(Incidence *,const TQDate &)) );
+ connect( agenda, TQT_SIGNAL(deleteIncidenceSignal(Incidence *)),
+ TQT_SIGNAL(deleteIncidenceSignal(Incidence *)) );
+
+ connect( agenda, TQT_SIGNAL(startMultiModify(const TQString &)),
+ TQT_SIGNAL(startMultiModify(const TQString &)) );
+ connect( agenda, TQT_SIGNAL(endMultiModify()),
+ TQT_SIGNAL(endMultiModify()) );
+
+ connect( agenda, TQT_SIGNAL(itemModified(KOAgendaItem *)),
+ TQT_SLOT(updateEventDates(KOAgendaItem *)) );
+
+ connect( agenda, TQT_SIGNAL(enableAgendaUpdate(bool)),
+ TQT_SLOT(enableAgendaUpdate(bool)) );
// drag signals
- connect( agenda, TQT_SIGNAL( startDragSignal( Incidence * ) ),
- TQT_SLOT( startDrag( Incidence * ) ) );
+ connect( agenda, TQT_SIGNAL(startDragSignal(Incidence *)),
+ TQT_SLOT(startDrag(Incidence *)) );
// synchronize selections
- connect( agenda, TQT_SIGNAL( incidenceSelected( Incidence * ) ),
- otherAgenda, TQT_SLOT( deselectItem() ) );
- connect( agenda, TQT_SIGNAL( incidenceSelected( Incidence * ) ),
- TQT_SIGNAL( incidenceSelected( Incidence * ) ) );
+ connect( agenda, TQT_SIGNAL(incidenceSelected(Incidence *,const TQDate &)),
+ otherAgenda, TQT_SLOT(deselectItem()) );
+ connect( agenda, TQT_SIGNAL(incidenceSelected(Incidence *,const TQDate &)),
+ TQT_SIGNAL(incidenceSelected(Incidence *,const TQDate &)) );
// rescheduling of todos by d'n'd
- connect( agenda, TQT_SIGNAL( droppedToDo( Todo *, const TQPoint &, bool ) ),
- TQT_SLOT( slotTodoDropped( Todo *, const TQPoint &, bool ) ) );
+ connect( agenda, TQT_SIGNAL(droppedToDo(Todo *,const TQPoint &,bool)),
+ TQT_SLOT(slotTodoDropped(Todo *,const TQPoint &,bool)) );
}
@@ -567,14 +596,19 @@ void KOAgendaView::zoomView( const int delta, const TQPoint &pos,
}
}
-void KOAgendaView::createDayLabels()
+void KOAgendaView::createDayLabels( bool force )
{
// kdDebug(5850) << "KOAgendaView::createDayLabels()" << endl;
- // ### Before deleting and recreating we could check if mSelectedDates changed...
- // It would remove some flickering and gain speed (since this is called by
- // each updateView() call)
+ // Check if mSelectedDates has changed, if not just return
+ // Removes some flickering and gains speed (since this is called by each updateView())
+ if ( !force && mSaveSelectedDates == mSelectedDates ) {
+ return;
+ }
+ mSaveSelectedDates = mSelectedDates;
+
delete mDayLabels;
+ mDateDayLabels.clear();
mDayLabels = new TQFrame (mDayLabelsFrame);
mLayoutDayLabels = new TQHBoxLayout(mDayLabels);
@@ -598,7 +632,8 @@ void KOAgendaView::createDayLabels()
TQString shortstr = TQString::number(calsys->day(date));
KOAlternateLabel *dayLabel = new KOAlternateLabel(shortstr,
- longstr, veryLongStr, mDayLabels);
+ longstr, veryLongStr, mDayLabels);
+ dayLabel->useShortText(); // will be recalculated in updateDayLabelSizes() anyway
dayLabel->setMinimumWidth(1);
dayLabel->setAlignment(TQLabel::AlignHCenter);
if (date == TQDate::currentDate()) {
@@ -607,6 +642,7 @@ void KOAgendaView::createDayLabels()
dayLabel->setFont(font);
}
dayLayout->addWidget(dayLabel);
+ mDateDayLabels.append( dayLabel );
// if a holiday region is selected, show the holiday name
TQStringList texts = KOGlobals::self()->holiday( date );
@@ -646,6 +682,7 @@ void KOAgendaView::createDayLabels()
if ( !mIsSideBySide )
mLayoutDayLabels->addSpacing(mAgenda->verticalScrollBar()->width());
mDayLabels->show();
+ TQTimer::singleShot( 0, this, TQT_SLOT( updateDayLabelSizes() ) );
}
void KOAgendaView::enableAgendaUpdate( bool enable )
@@ -678,7 +715,7 @@ Incidence::List KOAgendaView::selectedIncidences()
return selected;
}
-DateList KOAgendaView::selectedDates()
+DateList KOAgendaView::selectedIncidenceDates()
{
DateList selected;
TQDate qd;
@@ -766,7 +803,7 @@ void KOAgendaView::updateConfig()
setHolidayMasks();
- createDayLabels();
+ createDayLabels( true );
updateView();
}
@@ -782,12 +819,41 @@ void KOAgendaView::updateTimeBarWidth()
mTimeLabels->setFixedWidth( width );
}
+void KOAgendaView::updateDayLabelSizes()
+{
+ // First, calculate the maximum text type that fits for all labels
+ KOAlternateLabel::TextType overallType = KOAlternateLabel::Extensive;
+ TQPtrList<KOAlternateLabel>::const_iterator it = mDateDayLabels.constBegin();
+ for( ; it != mDateDayLabels.constEnd(); it++ ) {
+ KOAlternateLabel::TextType type = (*it)->largestFittingTextType();
+ if ( type < overallType )
+ overallType = type;
+ }
+
+ // Then, set that maximum text type to all the labels
+ it = mDateDayLabels.constBegin();
+ for( ; it != mDateDayLabels.constEnd(); it++ ) {
+ (*it)->setFixedType( overallType );
+ }
+}
+
+void KOAgendaView::resizeEvent( TQResizeEvent *resizeEvent )
+{
+ updateDayLabelSizes();
+ KOrg::AgendaView::resizeEvent( resizeEvent );
+}
void KOAgendaView::updateEventDates( KOAgendaItem *item )
{
- kdDebug(5850) << "KOAgendaView::updateEventDates(): " << item->text() << endl;
+ kdDebug(5850) << "KOAgendaView::updateEventDates(): " << item->text()
+ << "; item->cellXLeft(): " << item->cellXLeft()
+ << "; item->cellYTop(): " << item->cellYTop()
+ << "; item->lastMultiItem(): " << item->lastMultiItem()
+ << "; item->itemPos(): " << item->itemPos()
+ << "; item->itemCount(): " << item->itemCount()
+ << endl;
- TQDateTime startDt,endDt;
+ TQDateTime startDt, endDt;
// Start date of this incidence, calculate the offset from it (so recurring and
// non-recurring items can be treated exactly the same, we never need to check
@@ -800,17 +866,22 @@ void KOAgendaView::updateEventDates( KOAgendaItem *item )
thisDate = mSelectedDates[ item->cellXLeft() ];
}
TQDate oldThisDate( item->itemDate() );
- int daysOffset = oldThisDate.daysTo( thisDate );
+ const int daysOffset = oldThisDate.daysTo( thisDate );
int daysLength = 0;
-// startDt.setDate( startDate );
+ // startDt.setDate( startDate );
Incidence *incidence = item->incidence();
- if ( !incidence ) return;
- if ( !mChanger || !mChanger->beginChange(incidence) ) return;
+ if ( !incidence ) {
+ return;
+ }
+ if ( !mChanger ||
+ !mChanger->beginChange( incidence, resourceCalendar(), subResourceCalendar() ) ) {
+ return;
+ }
Incidence *oldIncidence = incidence->clone();
- TQTime startTime(0,0,0), endTime(0,0,0);
+ TQTime startTime( 0, 0, 0 ), endTime( 0, 0, 0 );
if ( incidence->doesFloat() ) {
daysLength = item->cellWidth() - 1;
} else {
@@ -818,12 +889,35 @@ void KOAgendaView::updateEventDates( KOAgendaItem *item )
if ( item->lastMultiItem() ) {
endTime = mAgenda->gyToTime( item->lastMultiItem()->cellYBottom() + 1 );
daysLength = item->lastMultiItem()->cellXLeft() - item->cellXLeft();
+ kdDebug(5850) << "item->lastMultiItem()->cellXLeft(): " << item->lastMultiItem()->cellXLeft()
+ << endl;
+ } else if ( item->itemPos() == item->itemCount() && item->itemCount() > 1 ) {
+ /* multiitem handling in agenda assumes two things:
+ - The start (first KOAgendaItem) is always visible.
+ - The first KOAgendaItem of the incidence has a non-null item->lastMultiItem()
+ pointing to the last KOagendaItem.
+
+ But those aren't always met, for example when in day-view.
+ kolab/issue4417
+ */
+
+ // Cornercase 1: - Resizing the end of the event but the start isn't visible
+ endTime = mAgenda->gyToTime( item->cellYBottom() + 1 );
+ daysLength = item->itemCount() - 1;
+ startTime = incidence->dtStart().time();
+ } else if ( item->itemPos() == 1 && item->itemCount() > 1 ) {
+ // Cornercase 2: - Resizing the start of the event but the end isn't visible
+ endTime = incidence->dtEnd().time();
+ daysLength = item->itemCount() - 1;
} else {
endTime = mAgenda->gyToTime( item->cellYBottom() + 1 );
}
}
-// kdDebug(5850) << "KOAgendaView::updateEventDates(): now setting dates" << endl;
+ kdDebug(5850) << "daysLength: " << daysLength << "; startTime: " << startTime
+ << "; endTime: " << endTime << "; thisDate: " << thisDate
+ << "; incidence->dtStart(): " << incidence->dtStart() << endl;
+
// FIXME: use a visitor here
if ( incidence->type() == "Event" ) {
startDt = incidence->dtStart();
@@ -831,8 +925,8 @@ void KOAgendaView::updateEventDates( KOAgendaItem *item )
startDt.setTime( startTime );
endDt = startDt.addDays( daysLength );
endDt.setTime( endTime );
- Event*ev = static_cast<Event*>(incidence);
- if( incidence->dtStart() == startDt && ev->dtEnd() == endDt ) {
+ Event* ev = static_cast<Event*>( incidence );
+ if ( incidence->dtStart() == startDt && ev->dtEnd() == endDt ) {
// No change
delete oldIncidence;
return;
@@ -840,7 +934,7 @@ void KOAgendaView::updateEventDates( KOAgendaItem *item )
incidence->setDtStart( startDt );
ev->setDtEnd( endDt );
} else if ( incidence->type() == "Todo" ) {
- Todo *td = static_cast<Todo*>(incidence);
+ Todo *td = static_cast<Todo*>( incidence );
startDt = td->hasStartDate() ? td->dtStart() : td->dtDue();
startDt = thisDate.addDays( td->dtDue().daysTo( startDt ) );
startDt.setTime( startTime );
@@ -857,8 +951,9 @@ void KOAgendaView::updateEventDates( KOAgendaItem *item )
// functionality will also be available in other views!
// TODO_Recurrence: This does not belong here, and I'm not really sure
// how it's supposed to work anyway.
- Recurrence *recur = incidence->recurrence();
-/* if ( recur->doesRecur() && daysOffset != 0 ) {
+/*
+ Recurrence *recur = incidence->recurrence();
+ if ( recur->doesRecur() && daysOffset != 0 ) {
switch ( recur->recurrenceType() ) {
case Recurrence::rYearlyPos: {
int freq = recur->frequency();
@@ -1001,23 +1096,31 @@ void KOAgendaView::updateEventDates( KOAgendaItem *item )
// FIXME: use a visitor here
if ( incidence->type() == "Event" ) {
incidence->setDtStart( startDt );
- (static_cast<Event*>( incidence ) )->setDtEnd( endDt );
+ static_cast<Event*>( incidence )->setDtEnd( endDt );
} else if ( incidence->type() == "Todo" ) {
Todo *td = static_cast<Todo*>( incidence );
- if ( td->hasStartDate() )
+ if ( td->hasStartDate() ) {
td->setDtStart( startDt );
+ }
td->setDtDue( endDt );
}
item->setItemDate( startDt.date() );
KOIncidenceToolTip::remove( item );
- KOIncidenceToolTip::add( item, incidence, KOAgendaItem::toolTipGroup() );
+ KOIncidenceToolTip::add( item, calendar(), incidence, thisDate, KOAgendaItem::toolTipGroup() );
- mChanger->changeIncidence( oldIncidence, incidence );
- mChanger->endChange(incidence);
+ const bool result = mChanger->changeIncidence( oldIncidence, incidence,
+ KOGlobals::DATE_MODIFIED, this );
+ mChanger->endChange( incidence, resourceCalendar(), subResourceCalendar() );
delete oldIncidence;
+ if ( !result ) {
+ mPendingChanges = true;
+ TQTimer::singleShot( 0, this, TQT_SLOT(updateView()) );
+ return;
+ }
+
// don't update the agenda as the item already has the correct coordinates.
// an update would delete the current item and recreate it, but we are still
// using a pointer to that item! => CRASH
@@ -1056,99 +1159,141 @@ void KOAgendaView::showDates( const TQDate &start, const TQDate &end )
mSelectedDates.clear();
TQDate d = start;
- while (d <= end) {
- mSelectedDates.append(d);
+ while ( d <= end ) {
+ mSelectedDates.append( d );
d = d.addDays( 1 );
}
+ mAreDatesInitialized = true;
+
// and update the view
fillAgenda();
}
-void KOAgendaView::showIncidences( const Incidence::List & )
+void KOAgendaView::showIncidences( const Incidence::List &, const TQDate & )
{
kdDebug(5850) << "KOAgendaView::showIncidences( const Incidence::List & ) is not yet implemented" << endl;
}
-void KOAgendaView::insertIncidence( Incidence *incidence, const TQDate &curDate,
- int curCol )
+void KOAgendaView::insertIncidence( Incidence *incidence, const TQDate &curDate )
{
- if ( !filterByResource( incidence ) )
+ if ( !filterByResource( incidence ) ) {
return;
+ }
// FIXME: Use a visitor here, or some other method to get rid of the dynamic_cast's
Event *event = dynamic_cast<Event *>( incidence );
Todo *todo = dynamic_cast<Todo *>( incidence );
+ int curCol = mSelectedDates.first().daysTo( curDate );
+
+ // In case incidence->dtStart() isn't visible (crosses bounderies)
if ( curCol < 0 ) {
- curCol = mSelectedDates.findIndex( curDate );
+ curCol = 0;
}
+
// The date for the event is not displayed, just ignore it
- if ( curCol < 0 || curCol > int( mSelectedDates.size() ) )
+ if ( curCol >= int( mSelectedDates.count() ) ) {
return;
+ }
+
+ // Default values, which can never be reached
+ mMinY[curCol] = mAgenda->timeToY( TQTime( 23, 59 ) ) + 1;
+ mMaxY[curCol] = mAgenda->timeToY( TQTime( 0, 0 ) ) - 1;
int beginX;
int endX;
+ TQDate columnDate;
if ( event ) {
- beginX = curDate.daysTo( incidence->dtStart().date() ) + curCol;
- endX = curDate.daysTo( event->dateEnd() ) + curCol;
+ TQDate firstVisibleDate = mSelectedDates.first();
+ // its crossing bounderies, lets calculate beginX and endX
+ if ( curDate < firstVisibleDate ) {
+ beginX = curCol + firstVisibleDate.daysTo( curDate );
+ endX = beginX + event->dtStart().daysTo( event->dtEnd() );
+ columnDate = firstVisibleDate;
+ } else {
+ beginX = curCol;
+ endX = beginX + event->dtStart().daysTo( event->dtEnd() );
+ columnDate = curDate;
+ }
} else if ( todo ) {
- if ( ! todo->hasDueDate() ) return; // todo shall not be displayed if it has no date
- beginX = curDate.daysTo( todo->dtDue().date() ) + curCol;
- endX = beginX;
+ if ( !todo->hasDueDate() ) {
+ return; // todo shall not be displayed if it has no date
+ }
+ columnDate = curDate;
+ beginX = endX = curCol;
+
} else {
return;
}
-
if ( todo && todo->isOverdue() ) {
- mAllDayAgenda->insertAllDayItem( incidence, curDate, curCol, curCol );
- } else if ( incidence->doesFloat() ) {
-// FIXME: This breaks with recurring multi-day events!
- if ( incidence->recurrence()->doesRecur() ) {
- mAllDayAgenda->insertAllDayItem( incidence, curDate, curCol, curCol );
- } else {
- // Insert multi-day events only on the first day, otherwise it will
- // appear multiple times
- if ( ( beginX <= 0 && curCol == 0 ) || beginX == curCol ) {
- mAllDayAgenda->insertAllDayItem( incidence, curDate, beginX, endX );
- }
- }
+ mAllDayAgenda->insertAllDayItem( incidence, columnDate, curCol, curCol );
+ } else if ( incidence->doesFloat() ||
+ ( todo &&
+ !todo->dtDue().isValid() ) ) {
+ mAllDayAgenda->insertAllDayItem( incidence, columnDate, beginX, endX );
} else if ( event && event->isMultiDay() ) {
int startY = mAgenda->timeToY( event->dtStart().time() );
- TQTime endtime( event->dtEnd().time() );
- if ( endtime == TQTime( 0, 0, 0 ) ) endtime = TQTime( 23, 59, 59 );
+ TQTime endtime = event->dtEnd().time();
+ if ( endtime == TQTime( 0, 0, 0 ) ) {
+ endtime = TQTime( 23, 59, 59 );
+ }
int endY = mAgenda->timeToY( endtime ) - 1;
- if ( (beginX <= 0 && curCol == 0) || beginX == curCol ) {
- mAgenda->insertMultiItem( event, curDate, beginX, endX, startY, endY );
+ if ( ( beginX <= 0 && curCol == 0 ) || beginX == curCol ) {
+ mAgenda->insertMultiItem( event, columnDate, beginX, endX, startY, endY );
+
}
if ( beginX == curCol ) {
- mMaxY[curCol] = mAgenda->timeToY( TQTime(23,59) );
- if ( startY < mMinY[curCol] ) mMinY[curCol] = startY;
+ mMaxY[curCol] = mAgenda->timeToY( TQTime( 23, 59 ) );
+ if ( startY < mMinY[curCol] ) {
+ mMinY[curCol] = startY;
+ }
} else if ( endX == curCol ) {
- mMinY[curCol] = mAgenda->timeToY( TQTime(0,0) );
- if ( endY > mMaxY[curCol] ) mMaxY[curCol] = endY;
+ mMinY[curCol] = mAgenda->timeToY( TQTime( 0, 0 ) );
+ if ( endY > mMaxY[curCol] ) {
+ mMaxY[curCol] = endY;
+ }
} else {
- mMinY[curCol] = mAgenda->timeToY( TQTime(0,0) );
- mMaxY[curCol] = mAgenda->timeToY( TQTime(23,59) );
+ mMinY[curCol] = mAgenda->timeToY( TQTime( 0, 0 ) );
+ mMaxY[curCol] = mAgenda->timeToY( TQTime( 23, 59 ) );
}
} else {
int startY = 0, endY = 0;
if ( event ) {
startY = mAgenda->timeToY( incidence->dtStart().time() );
- TQTime endtime( event->dtEnd().time() );
- if ( endtime == TQTime( 0, 0, 0 ) ) endtime = TQTime( 23, 59, 59 );
+ TQTime endtime = event->dtEnd().time();
+ if ( endtime == TQTime( 0, 0, 0 ) ) {
+ endtime = TQTime( 23, 59, 59 );
+ }
endY = mAgenda->timeToY( endtime ) - 1;
}
if ( todo ) {
TQTime t = todo->dtDue().time();
- endY = mAgenda->timeToY( t ) - 1;
- startY = mAgenda->timeToY( t.addSecs( -1800 ) );
+
+ if ( t == TQTime( 0, 0 ) ) {
+ t = TQTime( 23, 59 );
+ }
+
+ int halfHour = 1800;
+ if ( t.addSecs( -halfHour ) < t ) {
+ startY = mAgenda->timeToY( t.addSecs( -halfHour ) );
+ endY = mAgenda->timeToY( t ) - 1;
+ } else {
+ startY = 0;
+ endY = mAgenda->timeToY( t.addSecs( halfHour ) ) - 1;
+ }
+ }
+ if ( endY < startY ) {
+ endY = startY;
+ }
+ mAgenda->insertItem( incidence, columnDate, curCol, startY, endY, 1, 1 );
+ if ( startY < mMinY[curCol] ) {
+ mMinY[curCol] = startY;
+ }
+ if ( endY > mMaxY[curCol] ) {
+ mMaxY[curCol] = endY;
}
- if ( endY < startY ) endY = startY;
- mAgenda->insertItem( incidence, curDate, curCol, startY, endY );
- if ( startY < mMinY[curCol] ) mMinY[curCol] = startY;
- if ( endY > mMaxY[curCol] ) mMaxY[curCol] = endY;
}
}
@@ -1156,75 +1301,53 @@ void KOAgendaView::changeIncidenceDisplayAdded( Incidence *incidence )
{
Todo *todo = dynamic_cast<Todo *>(incidence);
CalFilter *filter = calendar()->filter();
- if ( filter && !filter->filterIncidence( incidence ) ||
- ( todo && !KOPrefs::instance()->showAllDayTodo() ) )
- return;
-
- TQDate f = mSelectedDates.first();
- TQDate l = mSelectedDates.last();
- TQDate startDt = incidence->dtStart().date();
-
- if ( incidence->doesRecur() ) {
- DateList::ConstIterator dit;
- TQDate curDate;
- for( dit = mSelectedDates.begin(); dit != mSelectedDates.end(); ++dit ) {
- curDate = *dit;
-// FIXME: This breaks with recurring multi-day events!
- if ( incidence->recursOn( curDate, calendar() ) ) {
- insertIncidence( incidence, curDate );
- }
- }
+ if ( ( filter && !filter->filterIncidence( incidence ) ) ||
+ ( ( todo && !KOPrefs::instance()->showAllDayTodo() ) ) ) {
return;
}
- TQDate endDt;
- if ( incidence->type() == "Event" )
- endDt = (static_cast<Event *>(incidence))->dateEnd();
- if ( todo ) {
- endDt = todo->isOverdue() ? TQDate::currentDate()
- : todo->dtDue().date();
-
- if ( endDt >= f && endDt <= l ) {
- insertIncidence( incidence, endDt );
- return;
- }
- }
-
- if ( startDt >= f && startDt <= l ) {
- insertIncidence( incidence, startDt );
- }
+ displayIncidence( incidence );
}
void KOAgendaView::changeIncidenceDisplay( Incidence *incidence, int mode )
{
switch ( mode ) {
- case KOGlobals::INCIDENCEADDED: {
- // Add an event. No need to recreate the whole view!
- // recreating everything even causes troubles: dropping to the day matrix
- // recreates the agenda items, but the evaluation is still in an agendaItems' code,
- // which was deleted in the mean time. Thus KOrg crashes...
- if ( mAllowAgendaUpdate )
- changeIncidenceDisplayAdded( incidence );
+ case KOGlobals::INCIDENCEADDED:
+ {
+ // Add an event. No need to recreate the whole view!
+ // recreating everything even causes troubles: dropping to the
+ // day matrix recreates the agenda items, but the evaluation is
+ // still in an agendaItems' code, which was deleted in the mean time.
+ // Thus KOrg crashes...
+ changeIncidenceDisplayAdded( incidence );
+ updateEventIndicators();
break;
}
- case KOGlobals::INCIDENCEEDITED: {
- if ( !mAllowAgendaUpdate ) {
- updateEventIndicators();
- } else {
+ case KOGlobals::INCIDENCEEDITED:
+ {
+ if ( mAllowAgendaUpdate ) {
removeIncidence( incidence );
- updateEventIndicators();
changeIncidenceDisplayAdded( incidence );
}
+ updateEventIndicators();
break;
}
- case KOGlobals::INCIDENCEDELETED: {
- mAgenda->removeIncidence( incidence );
- mAllDayAgenda->removeIncidence( incidence );
+ case KOGlobals::INCIDENCEDELETED:
+ {
+ removeIncidence( incidence );
updateEventIndicators();
break;
}
default:
- updateView();
+ return;
+ }
+
+ // HACK: Update the view if the all-day agenda has been modified.
+ // Do this because there are some layout problems in the
+ // all-day agenda that are not easily solved, but clearing
+ // and redrawing works ok.
+ if ( incidence->doesFloat() ) {
+ updateView();
}
}
@@ -1235,6 +1358,10 @@ void KOAgendaView::fillAgenda( const TQDate & )
void KOAgendaView::fillAgenda()
{
+ if ( !mAreDatesInitialized ) {
+ return;
+ }
+
mPendingChanges = false;
/* Remember the uids of the selected items. In case one of the
@@ -1245,115 +1372,146 @@ void KOAgendaView::fillAgenda()
enableAgendaUpdate( true );
clearView();
- mAllDayAgenda->changeColumns(mSelectedDates.count());
- mAgenda->changeColumns(mSelectedDates.count());
- mEventIndicatorTop->changeColumns(mSelectedDates.count());
- mEventIndicatorBottom->changeColumns(mSelectedDates.count());
+ mAllDayAgenda->changeColumns( mSelectedDates.count() );
+ mAgenda->changeColumns( mSelectedDates.count() );
+ mEventIndicatorTop->changeColumns( mSelectedDates.count() );
+ mEventIndicatorBottom->changeColumns( mSelectedDates.count() );
- createDayLabels();
+ createDayLabels( false );
setHolidayMasks();
- mMinY.resize(mSelectedDates.count());
- mMaxY.resize(mSelectedDates.count());
+ mMinY.resize( mSelectedDates.count() );
+ mMaxY.resize( mSelectedDates.count() );
- Event::List dayEvents;
+ mAgenda->setDateList( mSelectedDates );
- // ToDo items shall be displayed for the day they are due, but only shown today if they are already overdue.
- // Therefore, get all of them.
- Todo::List todos = calendar()->todos();
-
- mAgenda->setDateList(mSelectedDates);
+ bool somethingReselected = false;
+ Incidence::List incidences = calendar()->incidences();
- TQDate today = TQDate::currentDate();
+ for ( Incidence::List::ConstIterator it = incidences.begin(); it!=incidences.constEnd(); ++it ) {
+ Incidence *incidence = (*it);
+ displayIncidence( incidence );
- bool somethingReselected = false;
- DateList::ConstIterator dit;
- int curCol = 0;
- for( dit = mSelectedDates.begin(); dit != mSelectedDates.end(); ++dit ) {
- TQDate currentDate = *dit;
-// kdDebug(5850) << "KOAgendaView::fillAgenda(): " << currentDate.toString()
-// << endl;
-
- dayEvents = calendar()->events(currentDate,
- EventSortStartDate,
- SortDirectionAscending);
-
- // Default values, which can never be reached
- mMinY[curCol] = mAgenda->timeToY(TQTime(23,59)) + 1;
- mMaxY[curCol] = mAgenda->timeToY(TQTime(0,0)) - 1;
-
- unsigned int numEvent;
- for(numEvent=0;numEvent<dayEvents.count();++numEvent) {
- Event *event = *dayEvents.at(numEvent);
-// kdDebug(5850) << " Event: " << event->summary() << endl;
- insertIncidence( event, currentDate, curCol );
- if( event->uid() == selectedAgendaUid && !selectedAgendaUid.isNull() ) {
- mAgenda->selectItemByUID( event->uid() );
- somethingReselected = true;
- }
- if( event->uid() == selectedAllDayAgendaUid && !selectedAllDayAgendaUid.isNull() ) {
- mAllDayAgenda->selectItemByUID( event->uid() );
- somethingReselected = true;
- }
+ if( incidence->uid() == selectedAgendaUid && !selectedAgendaUid.isNull() ) {
+ mAgenda->selectItemByUID( incidence->uid() );
+ somethingReselected = true;
+ }
+ if( incidence->uid() == selectedAllDayAgendaUid && !selectedAllDayAgendaUid.isNull() ) {
+ mAllDayAgenda->selectItemByUID( incidence->uid() );
+ somethingReselected = true;
}
-// if (numEvent == 0) kdDebug(5850) << " No events" << endl;
+ }
+
+ mAgenda->checkScrollBoundaries();
+ updateEventIndicators();
+
+ // mAgenda->viewport()->update();
+ // mAllDayAgenda->viewport()->update();
- // ---------- [display Todos --------------
- if ( KOPrefs::instance()->showAllDayTodo() ) {
- unsigned int numTodo;
- for (numTodo = 0; numTodo < todos.count(); ++numTodo) {
- Todo *todo = *todos.at(numTodo);
+ // make invalid
+ deleteSelectedDateTime();
- if ( ! todo->hasDueDate() ) continue; // todo shall not be displayed if it has no date
+ if( !somethingReselected ) {
+ emit incidenceSelected( 0, TQDate() );
+ }
+}
- if ( !filterByResource( todo ) ) continue;
+void KOAgendaView::displayIncidence( Incidence *incidence )
+{
+ TQDate today = TQDate::currentDate();
+ DateTimeList::iterator t;
- // ToDo items shall be displayed for the day they are due, but only showed today if they are already overdue.
- // Already completed items can be displayed on their original due date
- bool overdue = todo->isOverdue();
+ // FIXME: use a visitor here
+ Todo *todo = dynamic_cast<Todo *>( incidence );
+ Event *event = dynamic_cast<Event *>( incidence );
- if ( (( todo->dtDue().date() == currentDate) && !overdue) ||
- (( currentDate == today) && overdue) ||
- ( todo->recursOn( currentDate ) ) ) {
- if ( todo->doesFloat() || overdue ) { // Todo has no due-time set or is already overdue
- //kdDebug(5850) << "todo without time:" << todo->dtDueDateStr() << ";" << todo->summary() << endl;
+ TQDateTime firstVisibleDateTime = mSelectedDates.first();
+ TQDateTime lastVisibleDateTime = mSelectedDates.last();
- mAllDayAgenda->insertAllDayItem(todo, currentDate, curCol, curCol);
- } else {
- //kdDebug(5850) << "todo with time:" << todo->dtDueStr() << ";" << todo->summary() << endl;
+ lastVisibleDateTime.setTime( TQTime( 23, 59, 59, 59 ) );
+ firstVisibleDateTime.setTime( TQTime( 0, 0 ) );
+ DateTimeList dateTimeList;
- int endY = mAgenda->timeToY(todo->dtDue().time()) - 1;
- int startY = endY - 1;
+ TQDateTime incDtStart = incidence->dtStart();
+ TQDateTime incDtEnd = incidence->dtEnd();
- mAgenda->insertItem(todo,currentDate,curCol,startY,endY);
+ if ( todo &&
+ ( !KOPrefs::instance()->showAllDayTodo() || !todo->hasDueDate() ) ) {
+ return;
+ }
- if (startY < mMinY[curCol]) mMinY[curCol] = startY;
- if (endY > mMaxY[curCol]) mMaxY[curCol] = endY;
- }
- }
+ if ( incidence->doesRecur() ) {
+ int eventDuration = event ? incDtStart.daysTo( incDtEnd ) : 0;
+
+ // if there's a multiday event that starts before firstVisibleDateTime but ends after
+ // lets include it. timesInInterval() ignores incidences that aren't totaly inside
+ // the range
+ TQDateTime startDateTimeWithOffset = firstVisibleDateTime.addDays( -eventDuration );
+ dateTimeList =
+ incidence->recurrence()->timesInInterval( startDateTimeWithOffset,
+ lastVisibleDateTime );
+ } else {
+ TQDateTime dateToAdd; // date to add to our date list
+ TQDateTime incidenceStart;
+ TQDateTime incidenceEnd;
+
+ if ( todo && todo->hasDueDate() && !todo->isOverdue() ) {
+ // If it's not overdue it will be shown at the original date (not today)
+ dateToAdd = todo->dtDue();
+
+ // To-dos are drawn with the bottom of the rectangle at dtDue
+ // if dtDue is at 00:00, then it should be displayed in the previous day, at 23:59
+ if ( !todo->doesFloat() && dateToAdd.time() == TQTime( 0, 0 ) ) {
+ dateToAdd = dateToAdd.addSecs( -1 );
}
- }
- // ---------- display Todos] --------------
- ++curCol;
- }
+ incidenceEnd = dateToAdd;
+ } else if ( event ) {
+ dateToAdd = incDtStart;
+ incidenceEnd = incDtEnd;
+ }
- mAgenda->checkScrollBoundaries();
- updateEventIndicators();
+ if ( incidence->doesFloat() ) {
+ // so comparisons with < > actually work
+ dateToAdd.setTime( TQTime( 0, 0 ) );
+ incidenceEnd.setTime( TQTime( 23, 59, 59, 59 ) );
+ }
-// mAgenda->viewport()->update();
-// mAllDayAgenda->viewport()->update();
+ if ( dateToAdd <= lastVisibleDateTime && incidenceEnd > firstVisibleDateTime ) {
+ dateTimeList += dateToAdd;
+ }
+ }
-// make invalid
- deleteSelectedDateTime();
+ // ToDo items shall be displayed today if they are already overdude
+ TQDateTime dateTimeToday = today;
+ if ( todo &&
+ todo->isOverdue() &&
+ dateTimeToday >= firstVisibleDateTime &&
+ dateTimeToday <= lastVisibleDateTime ) {
+
+ bool doAdd = true;
+
+ if ( todo->doesRecur() ) {
+ /* If there's a recurring instance showing up today don't add "today" again
+ * we don't want the event to appear duplicated */
+ for ( t = dateTimeList.begin(); t != dateTimeList.end(); ++t ) {
+ if ( (*t).date() == today ) {
+ doAdd = false;
+ break;
+ }
+ }
+ }
- if( !somethingReselected ) {
- emit incidenceSelected( 0 );
+ if ( doAdd ) {
+ dateTimeList += dateTimeToday;
+ }
}
-// kdDebug(5850) << "Fill Agenda done" << endl;
+ for ( t = dateTimeList.begin(); t != dateTimeList.end(); ++t ) {
+ insertIncidence( incidence, (*t).date() );
+ }
}
void KOAgendaView::clearView()
@@ -1373,7 +1531,7 @@ void KOAgendaView::updateEventIndicatorTop( int newY )
{
uint i;
for( i = 0; i < mMinY.size(); ++i ) {
- mEventIndicatorTop->enableColumn( i, newY >= mMinY[i] );
+ mEventIndicatorTop->enableColumn( i, newY > mMinY[i] );
}
mEventIndicatorTop->update();
}
@@ -1399,12 +1557,14 @@ void KOAgendaView::slotTodoDropped( Todo *todo, const TQPoint &gpos, bool allDay
if ( existingTodo ) {
kdDebug(5850) << "Drop existing Todo" << endl;
Todo *oldTodo = existingTodo->clone();
- if ( mChanger && mChanger->beginChange( existingTodo ) ) {
+ if ( mChanger &&
+ mChanger->beginChange( existingTodo, resourceCalendar(), subResourceCalendar() ) ) {
existingTodo->setDtDue( newTime );
existingTodo->setFloats( allDay );
existingTodo->setHasDueDate( true );
- mChanger->changeIncidence( oldTodo, existingTodo );
- mChanger->endChange( existingTodo );
+ mChanger->changeIncidence( oldTodo, existingTodo,
+ KOGlobals::DATE_MODIFIED, this );
+ mChanger->endChange( existingTodo, resourceCalendar(), subResourceCalendar() );
} else {
KMessageBox::sorry( this, i18n("Unable to modify this to-do, "
"because it cannot be locked.") );
@@ -1415,7 +1575,7 @@ void KOAgendaView::slotTodoDropped( Todo *todo, const TQPoint &gpos, bool allDay
todo->setDtDue( newTime );
todo->setFloats( allDay );
todo->setHasDueDate( true );
- if ( !mChanger->addIncidence( todo, this ) ) {
+ if ( !mChanger->addIncidence( todo, 0, TQString(), this ) ) {
KODialogManager::errorSaveIncidence( this, todo );
}
}
@@ -1468,6 +1628,10 @@ void KOAgendaView::writeSettings(KConfig *config)
void KOAgendaView::setHolidayMasks()
{
+ if ( mSelectedDates.isEmpty() || !mSelectedDates[0].isValid() ) {
+ return;
+ }
+
mHolidayMask.resize( mSelectedDates.count() + 1 );
for( uint i = 0; i < mSelectedDates.count(); ++i ) {
@@ -1579,23 +1743,34 @@ void KOAgendaView::clearTimeSpanSelection()
deleteSelectedDateTime();
}
-void KOAgendaView::setResource(KCal::ResourceCalendar * res, const TQString & subResource)
-{
- mResource = res;
- mSubResource = subResource;
-}
+bool KOAgendaView::filterByResource( Incidence *incidence )
+{
+ // Special handling for groupware to-dos that are in Task folders.
+ // Put them in the top-level "Calendar" folder for lack of a better
+ // place since we never show Task type folders even in the
+ // multiagenda view.
+ if ( resourceCalendar() && incidence->type() == "Todo" ) {
+ TQString subRes = resourceCalendar()->subresourceIdentifier( incidence );
+ if ( resourceCalendar()->subresourceType( subRes ) == "todo" ) {
+ TQString calmatch = "/.INBOX.directory/Calendar";
+ TQString i18nmatch = "/.INBOX.directory/" + i18n( "Calendar" );
+ if ( subResourceCalendar().contains( calmatch ) ||
+ subResourceCalendar().contains( i18nmatch ) ) {
+ return true;
+ }
+ }
+ }
-bool KOAgendaView::filterByResource(Incidence * incidence)
-{
- if ( !mResource )
+ // Normal handling
+ if ( !resourceCalendar() )
return true;
CalendarResources *calRes = dynamic_cast<CalendarResources*>( calendar() );
if ( !calRes )
return true;
- if ( calRes->resource( incidence ) != mResource )
+ if ( calRes->resource( incidence ) != resourceCalendar() )
return false;
- if ( !mSubResource.isEmpty() ) {
- if ( mResource->subresourceIdentifier( incidence ) != mSubResource )
+ if ( !subResourceCalendar().isEmpty() ) {
+ if ( resourceCalendar()->subresourceIdentifier( incidence ) != subResourceCalendar() )
return false;
}
return true;
@@ -1618,7 +1793,7 @@ void KOAgendaView::calendarIncidenceChanged(Incidence * incidence)
mPendingChanges = true;
}
-void KOAgendaView::calendarIncidenceRemoved(Incidence * incidence)
+void KOAgendaView::calendarIncidenceDeleted(Incidence * incidence)
{
Q_UNUSED( incidence );
mPendingChanges = true;
diff --git a/korganizer/koagendaview.h b/korganizer/koagendaview.h
index 1a16b2bb7..a31581a01 100644
--- a/korganizer/koagendaview.h
+++ b/korganizer/koagendaview.h
@@ -31,6 +31,7 @@
#include <libkcal/calendar.h>
#include "calprinter.h"
+#include "calendarview.h"
#include "agendaview.h"
@@ -43,10 +44,6 @@ class KOAgendaItem;
class TimeLabels;
class KConfig;
-namespace KCal {
- class ResourceCalendar;
-}
-
namespace KOrg {
class IncidenceChangerBase;
}
@@ -85,8 +82,11 @@ class KOAlternateLabel : public QLabel
virtual TQSize minimumSizeHint() const;
+ enum TextType { Short = 0, Long = 1, Extensive = 2 };
+ TextType largestFittingTextType() const;
+ void setFixedType( TextType type );
+
public slots:
- void setText( const TQString & );
void useShortText();
void useLongText();
void useExtensiveText();
@@ -107,11 +107,13 @@ class KOAgendaView : public KOrg::AgendaView, public KCal::Calendar::Observer
{
Q_OBJECT
public:
- KOAgendaView( Calendar *cal, TQWidget *parent = 0, const char *name = 0, bool isSideBySide = false );
+ KOAgendaView( Calendar *cal,
+ CalendarView *calendarView,
+ TQWidget *parent = 0,
+ const char *name = 0,
+ bool isSideBySide = false );
virtual ~KOAgendaView();
-
-
/** Returns maximum number of days supported by the koagendaview */
virtual int maxDatesHint();
@@ -122,7 +124,7 @@ class KOAgendaView : public KOrg::AgendaView, public KCal::Calendar::Observer
virtual Incidence::List selectedIncidences();
/** returns the currently selected events */
- virtual DateList selectedDates();
+ virtual DateList selectedIncidenceDates();
/** return the default start/end date/time for new events */
virtual bool eventDurationHint(TQDateTime &startDt, TQDateTime &endDt, bool &allDay);
@@ -145,24 +147,22 @@ class KOAgendaView : public KOrg::AgendaView, public KCal::Calendar::Observer
void setTypeAheadReceiver( TQObject * );
- /** Show only incidences from the given resource. */
- void setResource( KCal::ResourceCalendar *res, const TQString &subResource = TQString::null );
-
KOAgenda* agenda() const { return mAgenda; }
TQSplitter* splitter() const { return mSplitterAgenda; }
+ TQFrame *dayLabels() const { return mDayLabels; }
/* reimplmented from KCal::Calendar::Observer */
void calendarIncidenceAdded( Incidence *incidence );
void calendarIncidenceChanged( Incidence *incidence );
- void calendarIncidenceRemoved( Incidence *incidence );
+ void calendarIncidenceDeleted( Incidence *incidence );
public slots:
virtual void updateView();
virtual void updateConfig();
virtual void showDates( const TQDate &start, const TQDate &end );
- virtual void showIncidences( const Incidence::List &incidenceList );
+ virtual void showIncidences( const Incidence::List &incidenceList, const TQDate &date );
- void insertIncidence( Incidence *incidence, const TQDate &curDate, int curCol = -1 );
+ void insertIncidence( Incidence *incidence, const TQDate &curDate );
void changeIncidenceDisplayAdded( Incidence *incidence );
void changeIncidenceDisplay( Incidence *incidence, int mode );
@@ -215,7 +215,7 @@ class KOAgendaView : public KOrg::AgendaView, public KCal::Calendar::Observer
void connectAgenda( KOAgenda*agenda, TQPopupMenu*popup, KOAgenda* otherAgenda );
/** Create labels for the selected dates. */
- void createDayLabels();
+ void createDayLabels( bool force );
/**
Set the masks on the agenda widgets indicating, which days are holidays.
@@ -231,6 +231,8 @@ class KOAgendaView : public KOrg::AgendaView, public KCal::Calendar::Observer
void updateTimeBarWidth();
+ virtual void resizeEvent( TQResizeEvent *resizeEvent );
+
protected slots:
/** Update event belonging to agenda item */
void updateEventDates( KOAgendaItem *item );
@@ -245,14 +247,18 @@ class KOAgendaView : public KOrg::AgendaView, public KCal::Calendar::Observer
/** Updates data for selected timespan for all day event*/
void newTimeSpanSelectedAllDay( const TQPoint &start, const TQPoint &end );
+ void updateDayLabelSizes();
+
private:
bool filterByResource( Incidence *incidence );
+ void displayIncidence( Incidence *incidence );
private:
// view widgets
TQFrame *mDayLabels;
TQHBox *mDayLabelsFrame;
TQBoxLayout *mLayoutDayLabels;
+ TQPtrList<KOAlternateLabel> mDateDayLabels;
TQFrame *mAllDayFrame;
KOAgenda *mAllDayAgenda;
KOAgenda *mAgenda;
@@ -262,6 +268,7 @@ class KOAgendaView : public KOrg::AgendaView, public KCal::Calendar::Observer
TQPushButton *mExpandButton;
DateList mSelectedDates; // List of dates to be displayed
+ DateList mSaveSelectedDates; // Save the list of dates between updateViews
int mViewType;
KOEventPopupMenu *mAgendaPopup;
@@ -285,11 +292,16 @@ class KOAgendaView : public KOrg::AgendaView, public KCal::Calendar::Observer
Incidence *mUpdateItem;
- KCal::ResourceCalendar *mResource;
- TQString mSubResource;
-
bool mIsSideBySide;
bool mPendingChanges;
+
+ // the current date is inserted into mSelectedDates in the constructor
+ // however whe should only show events when setDates is called, otherwise
+ // we see day view with current date for a few milisecs, then we see something else
+ // because someone called setDates with the real dates that should be displayed.
+ // Other solution would be not initializing mSelectedDates in the ctor, but that requires
+ // lots of changes in koagenda.cpp and koagendaview.cpp
+ bool mAreDatesInitialized;
};
#endif
diff --git a/korganizer/koattendeeeditor.cpp b/korganizer/koattendeeeditor.cpp
index 370ac3b32..8766a3338 100644
--- a/korganizer/koattendeeeditor.cpp
+++ b/korganizer/koattendeeeditor.cpp
@@ -18,6 +18,8 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include <config.h> // for KDEPIM_NEW_DISTRLISTS
+
#include "koattendeeeditor.h"
#include "koprefs.h"
#include "koglobals.h"
@@ -32,8 +34,16 @@
#include <libemailfunctions/email.h>
+#ifdef KDEPIM_NEW_DISTRLISTS
+#include "distributionlist.h"
+#else
+#include <kabc/distributionlist.h>
+#endif
+#include <kabc/stdaddressbook.h>
+
#include <kiconloader.h>
#include <klocale.h>
+#include <kmessagebox.h>
#include <tqcheckbox.h>
#include <tqcombobox.h>
@@ -101,6 +111,7 @@ void KOAttendeeEditor::initEditWidgets(TQWidget * parent, TQBoxLayout * layout)
mNameEdit->installEventFilter( this );
connect( mNameEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
TQT_SLOT( updateAttendee() ) );
+ connect( mNameEdit, TQT_SIGNAL(returnPressed()), TQT_SLOT(expandAttendee()) );
topLayout->addMultiCellWidget( mNameEdit, 0, 0, 1, 2 );
whatsThis = i18n("Edits the role of the attendee selected "
@@ -206,20 +217,6 @@ void KOAttendeeEditor::openAddressBook()
}
delete dia;
return;
-#if 0
- // old code
- KABC::Addressee a = KABC::AddresseeDialog::getAddressee(this);
- if (!a.isEmpty()) {
- // If this is myself, I don't want to get a response but instead
- // assume I will be available
- bool myself = KOPrefs::instance()->thatIsMe( a.preferredEmail() );
- KCal::Attendee::PartStat partStat =
- myself ? KCal::Attendee::Accepted : KCal::Attendee::NeedsAction;
- insertAttendee( new Attendee( a.realName(), a.preferredEmail(),
- !myself, partStat,
- KCal::Attendee::ReqParticipant, a.uid() ) );
- }
-#endif
#endif
}
@@ -236,12 +233,13 @@ void KOAttendeeEditor::insertAttendeeFromAddressee(const KABC::Addressee &a, con
rsvp = false;
}
Attendee *newAt = new Attendee( a.realName(),
- a.preferredEmail(),
- !myself, partStat,
- at ? at->role() : Attendee::ReqParticipant,
- a.uid() );
+ a.preferredEmail(),
+ !myself, partStat,
+ at ? at->role() : Attendee::ReqParticipant,
+ a.uid() );
newAt->setRSVP( rsvp );
insertAttendee( newAt, true );
+ mnewAttendees.append( newAt );
}
void KOAttendeeEditor::fillOrganizerCombo()
@@ -260,10 +258,21 @@ void KOAttendeeEditor::fillOrganizerCombo()
void KOAttendeeEditor::addNewAttendee()
{
+ // check if there's still an unchanged example entry, and if so
+ // suggest to edit that first
+ if ( TQListViewItem* item = hasExampleAttendee() ) {
+ KMessageBox::information( this,
+ i18n( "Please edit the example attendee, before adding more." ), TQString::null,
+ "EditExistingExampleAttendeeFirst" );
+ // make sure the example attendee is selected
+ item->setSelected( true );
+ item->listView()->setCurrentItem( item );
+ return;
+ }
Attendee *a = new Attendee( i18n("Firstname Lastname"),
i18n("name") + "@example.net", true );
insertAttendee( a, false );
- mnewAttendees.append(a);
+ mnewAttendees.append( a );
updateAttendeeInput();
// We don't want the hint again
mNameEdit->setClickMessage( "" );
@@ -275,7 +284,7 @@ void KOAttendeeEditor::readEvent(KCal::Incidence * incidence)
{
mdelAttendees.clear();
mnewAttendees.clear();
- if ( KOPrefs::instance()->thatIsMe( incidence->organizer().email() ) ) {
+ if ( KOPrefs::instance()->thatIsMe( incidence->organizer().email() ) || incidence->organizer().isEmpty() ) {
if ( !mOrganizerCombo ) {
mOrganizerCombo = new TQComboBox( mOrganizerHBox );
fillOrganizerCombo();
@@ -305,8 +314,36 @@ void KOAttendeeEditor::readEvent(KCal::Incidence * incidence)
Attendee::List al = incidence->attendees();
Attendee::List::ConstIterator it;
- for( it = al.begin(); it != al.end(); ++it )
- insertAttendee( new Attendee( **it ), true );
+ Attendee *first = 0;
+ for( it = al.begin(); it != al.end(); ++it ) {
+ Attendee *a = new Attendee( **it );
+ if ( !first ) {
+ first = a;
+ }
+ insertAttendee( a, true );
+ }
+
+ // Set the initial editing values to the first attendee in the list.
+ if ( first ) {
+ // Don't update the item here, the user didn't edit it, so it's not needed.
+ // Also, AttendeeEditor's subclasses didn't set the current Item at this point
+ // so if updateAttendee is called now what will happen is that a random item
+ // will get the text of "first".
+ mDisableItemUpdate = true;
+
+ setSelected( 0 );
+ mNameEdit->setText( first->fullName() );
+ mUid = first->uid();
+ mRoleCombo->setCurrentItem( first->role() );
+ if ( first->status() != KCal::Attendee::None ) {
+ mStatusCombo->setCurrentItem( first->status() );
+ } else {
+ mStatusCombo->setCurrentItem( KCal::Attendee::NeedsAction );
+ }
+ mRsvpButton->setChecked( first->RSVP() );
+ mRsvpButton->setEnabled( true );
+ mDisableItemUpdate = false;
+ }
}
void KOAttendeeEditor::writeEvent(KCal::Incidence * incidence)
@@ -338,15 +375,39 @@ void KOAttendeeEditor::clearAttendeeInput()
mDelegateLabel->setText( TQString() );
}
+void KOAttendeeEditor::expandAttendee()
+{
+ KABC::Addressee::List aList = expandDistList( mNameEdit->text() );
+ if ( !aList.isEmpty() ) {
+ int index = selectedIndex();
+ for ( KABC::Addressee::List::iterator itr = aList.begin(); itr != aList.end(); ++itr ) {
+ insertAttendeeFromAddressee( (*itr) );
+ }
+ setSelected( index );
+ removeAttendee( currentAttendee() );
+ }
+}
+
void KOAttendeeEditor::updateAttendee()
{
Attendee *a = currentAttendee();
if ( !a || mDisableItemUpdate )
return;
- TQString name;
- TQString email;
- KPIM::getNameAndMail(mNameEdit->text(), name, email);
+ TQString text = mNameEdit->text();
+ if ( !mNameEdit->text().startsWith( "\"" ) ) {
+ // Quote the text as it might contain commas and other quotable chars.
+ text = KPIM::quoteNameIfNecessary( text );
+ }
+
+ TQString name, email;
+ if ( KPIM::getNameAndMail( text, name, email ) ) {
+ name.remove( '"' );
+ email.remove( '"' ).remove( '>' );
+ } else {
+ name = TQString();
+ email = mNameEdit->text();
+ }
bool iAmTheOrganizer = mOrganizerCombo &&
KOPrefs::instance()->thatIsMe( mOrganizerCombo->currentText() );
@@ -356,7 +417,6 @@ void KOAttendeeEditor::updateAttendee()
bool wasMyself =
KPIM::compareEmail( a->email(), mOrganizerCombo->currentText(), false );
if ( myself ) {
- mStatusCombo->setCurrentItem( KCal::Attendee::Accepted );
mRsvpButton->setChecked( false );
mRsvpButton->setEnabled( false );
} else if ( wasMyself ) {
@@ -380,16 +440,37 @@ void KOAttendeeEditor::fillAttendeeInput( KCal::Attendee *a )
{
mDisableItemUpdate = true;
- TQString name = a->name();
- if (!a->email().isEmpty()) {
- name = KPIM::quoteNameIfNecessary( name );
- name += " <" + a->email() + ">";
+ TQString tname, temail;
+ TQString username = a->name();
+ if ( !a->email().isEmpty() ) {
+ username = KPIM::quoteNameIfNecessary( username );
+
+ KPIM::getNameAndMail( username, tname, temail ); // ignore return value
+ // which is always false
+ tname += " <" + a->email() + '>';
+ }
+
+ bool myself = KOPrefs::instance()->thatIsMe( a->email() );
+ bool sameAsOrganizer = mOrganizerCombo &&
+ KPIM::compareEmail( a->email(),
+ mOrganizerCombo->currentText(), false );
+ KCal::Attendee::PartStat partStat = a->status();
+ bool rsvp = a->RSVP();
+
+ if ( myself && sameAsOrganizer && a->status() == KCal::Attendee::None ) {
+ partStat = KCal::Attendee::Accepted;
+ rsvp = false;
}
- mNameEdit->setText(name);
+
+ mNameEdit->setText(tname);
mUid = a->uid();
mRoleCombo->setCurrentItem(a->role());
- mStatusCombo->setCurrentItem(a->status());
- mRsvpButton->setChecked(a->RSVP());
+ if ( partStat != KCal::Attendee::None ) {
+ mStatusCombo->setCurrentItem( partStat );
+ } else {
+ mStatusCombo->setCurrentItem( KCal::Attendee::NeedsAction );
+ }
+ mRsvpButton->setChecked( rsvp );
mDisableItemUpdate = false;
setEnableAttendeeInput( true );
@@ -402,6 +483,9 @@ void KOAttendeeEditor::fillAttendeeInput( KCal::Attendee *a )
else
mDelegateLabel->setText( i18n( "Not delegated" ) );
}
+ if( myself )
+ mRsvpButton->setEnabled( false );
+
}
void KOAttendeeEditor::updateAttendeeInput()
@@ -418,17 +502,24 @@ void KOAttendeeEditor::updateAttendeeInput()
void KOAttendeeEditor::cancelAttendeeEvent( KCal::Incidence *incidence )
{
incidence->clearAttendees();
- Attendee * att;
- for (att=mdelAttendees.first();att;att=mdelAttendees.next()) {
+
+ if ( mdelAttendees.isEmpty() ) {
+ return;
+ }
+
+ Attendee *att;
+ for ( att = mdelAttendees.first(); att; att = mdelAttendees.next() ) {
bool isNewAttendee = false;
- for (Attendee *newAtt=mnewAttendees.first();newAtt;newAtt=mnewAttendees.next()) {
- if (*att==*newAtt) {
- isNewAttendee = true;
- break;
+ if ( !mnewAttendees.isEmpty() ) {
+ for ( Attendee *newAtt = mnewAttendees.first(); newAtt; newAtt = mnewAttendees.next() ) {
+ if ( *att == *newAtt ) {
+ isNewAttendee = true;
+ break;
+ }
}
}
- if (!isNewAttendee) {
- incidence->addAttendee(new Attendee(*att));
+ if ( !isNewAttendee ) {
+ incidence->addAttendee( new Attendee( *att ) );
}
}
mdelAttendees.clear();
@@ -454,4 +545,51 @@ bool KOAttendeeEditor::eventFilter(TQObject *watched, TQEvent *ev)
return TQWidget::eventFilter( watched, ev );
}
+bool KOAttendeeEditor::isExampleAttendee( const KCal::Attendee* attendee ) const
+{
+ if ( !attendee ) return false;
+ if ( attendee->name() == i18n( "Firstname Lastname" )
+ && attendee->email().endsWith( "example.net" ) ) {
+ return true;
+ }
+ return false;
+}
+
+KABC::Addressee::List KOAttendeeEditor::expandDistList( const TQString &text ) const
+{
+ KABC::Addressee::List aList;
+ KABC::AddressBook *abook = KABC::StdAddressBook::self( true );
+
+#ifdef KDEPIM_NEW_DISTRLISTS
+ const TQValueList<KPIM::DistributionList::Entry> eList =
+ KPIM::DistributionList::findByName( abook, text ).entries( abook );
+ TQValueList<KPIM::DistributionList::Entry>::ConstIterator eit;
+ for ( eit = eList.begin(); eit != eList.end(); ++eit ) {
+ KABC::Addressee a = (*eit).addressee;
+ if ( !a.preferredEmail().isEmpty() && aList.find( a ) == aList.end() ) {
+ aList.append( a ) ;
+ }
+ }
+
+#else
+ KABC::DistributionListManager manager( abook );
+ manager.load();
+ const TQStringList dList = manager.listNames();
+ for ( TQStringList::ConstIterator it = dList.begin(); it != dList.end(); ++it ) {
+ if ( (*it) == text ) {
+ const TQValueList<KABC::DistributionList::Entry> eList = manager.list( *it )->entries();
+ TQValueList<KABC::DistributionList::Entry>::ConstIterator eit;
+ for ( eit = eList.begin(); eit != eList.end(); ++eit ) {
+ KABC::Addressee a = (*eit).addressee;
+ if ( !a.preferredEmail().isEmpty() && aList.find( a ) == aList.end() ) {
+ aList.append( a ) ;
+ }
+ }
+ }
+ }
+#endif
+ return aList;
+}
+
+
#include "koattendeeeditor.moc"
diff --git a/korganizer/koattendeeeditor.h b/korganizer/koattendeeeditor.h
index 5f1dfb977..e75d994e5 100644
--- a/korganizer/koattendeeeditor.h
+++ b/korganizer/koattendeeeditor.h
@@ -23,6 +23,7 @@
#include <tqwidget.h>
#include <libkcal/attendee.h>
+#include <kabc/addressee.h>
class TQBoxLayout;
class TQComboBox;
@@ -30,15 +31,12 @@ class TQCheckBox;
class TQLabel;
class TQPushButton;
class TQHBox;
+class TQListViewItem;
namespace KPIM {
class AddresseeLineEdit;
}
-namespace KABC {
- class Addressee;
-}
-
namespace KCal {
class Incidence;
}
@@ -52,7 +50,8 @@ class KOAttendeeEditor : public QWidget
public:
KOAttendeeEditor( TQWidget *parent, const char *name = 0 );
- virtual void insertAttendee( KCal::Attendee* attendee, bool fetchFB = true ) = 0;
+ virtual void insertAttendee( KCal::Attendee *attendee, bool fetchFB = true ) = 0;
+ virtual void removeAttendee( KCal::Attendee *attendee ) = 0;
virtual void readEvent( KCal::Incidence *incidence );
virtual void writeEvent( KCal::Incidence *incidence );
@@ -79,10 +78,13 @@ class KOAttendeeEditor : public QWidget
void insertAttendeeFromAddressee( const KABC::Addressee &a, const KCal::Attendee* at=0 );
void fillOrganizerCombo();
-
+ virtual TQListViewItem* hasExampleAttendee() const = 0;
+ bool isExampleAttendee( const KCal::Attendee* ) const;
virtual KCal::Attendee* currentAttendee() const = 0;
virtual void updateCurrentItem() = 0;
+ virtual void setSelected ( int index ) = 0;
+ virtual int selectedIndex() = 0;
virtual void changeStatusForMe( KCal::Attendee::PartStat status ) = 0;
virtual bool eventFilter( TQObject *, TQEvent *);
@@ -95,6 +97,7 @@ class KOAttendeeEditor : public QWidget
void updateAttendeeInput();
void clearAttendeeInput();
void fillAttendeeInput( KCal::Attendee *a );
+ void expandAttendee();
void updateAttendee();
protected:
@@ -118,6 +121,7 @@ class KOAttendeeEditor : public QWidget
TQPtrList<KCal::Attendee> mnewAttendees;
private:
+ KABC::Addressee::List expandDistList( const TQString &text ) const;
bool mDisableItemUpdate;
};
diff --git a/korganizer/kocorehelper.cpp b/korganizer/kocorehelper.cpp
index 374c7107b..5538d9c33 100644
--- a/korganizer/kocorehelper.cpp
+++ b/korganizer/kocorehelper.cpp
@@ -26,13 +26,17 @@
#include "koglobals.h"
-TQColor KOCoreHelper::categoryColor( const TQStringList &categories )
+TQColor KOCoreHelper::categoryColor( const TQStringList &categories )
{
+ if ( categories.isEmpty() ) {
+ return KOPrefs::instance()->unsetCategoryColor();
+ }
+
// FIXME: Correctly treat events with multiple categories
TQString cat = categories.first();
TQColor bgColor;
if (cat.isEmpty())
- bgColor = defaultEventColor();
+ bgColor = KOPrefs::instance()->unsetCategoryColor();
else
bgColor = *( KOPrefs::instance()->categoryColor( cat ) );
return bgColor;
diff --git a/korganizer/kocorehelper.h b/korganizer/kocorehelper.h
index 609278563..ff3c55a35 100644
--- a/korganizer/kocorehelper.h
+++ b/korganizer/kocorehelper.h
@@ -40,7 +40,6 @@ class KOCoreHelper : public KOrg::CoreHelper
KOCoreHelper() {}
virtual ~KOCoreHelper() {}
- virtual TQColor defaultEventColor() { return KOPrefs::instance()->mEventColor; }
virtual TQColor textColor( const TQColor &bgColor ) { return getTextColor( bgColor ); }
virtual TQColor categoryColor( const TQStringList &cats );
virtual TQString holidayString( const TQDate &dt );
diff --git a/korganizer/kocounterdialog.cpp b/korganizer/kocounterdialog.cpp
index bf3f736ff..a8a581d06 100644
--- a/korganizer/kocounterdialog.cpp
+++ b/korganizer/kocounterdialog.cpp
@@ -32,11 +32,11 @@
#include "kocounterdialog.h"
#include "kocounterdialog.moc"
-KOCounterDialog::KOCounterDialog( TQWidget *parent, const char *name )
+KOCounterDialog::KOCounterDialog( Calendar *calendar, TQWidget *parent, const char *name )
: KDialogBase( parent, name, false, i18n("Counter-Event Viewer"),
User1 | User2, User1, false, i18n("Decline"), i18n("Accept") )
{
- mEventViewer = new KOEventViewer( this );
+ mEventViewer = new KOEventViewer( calendar, this );
setMainWidget( mEventViewer );
connect( this, TQT_SIGNAL( user1Clicked() ), TQT_SLOT( slotCancel() ) );
diff --git a/korganizer/kocounterdialog.h b/korganizer/kocounterdialog.h
index cedb9dabb..64757e987 100644
--- a/korganizer/kocounterdialog.h
+++ b/korganizer/kocounterdialog.h
@@ -27,8 +27,7 @@
#include <kdialogbase.h>
namespace KCal {
-class Event;
-class Todo;
+class Calendar;
}
using namespace KCal;
@@ -41,7 +40,7 @@ class KOCounterDialog : public KDialogBase
{
Q_OBJECT
public:
- KOCounterDialog(TQWidget *parent = 0, const char *name = 0 );
+ KOCounterDialog(Calendar *calendar, TQWidget *parent = 0, const char *name = 0 );
virtual ~KOCounterDialog();
void setIncidence( Incidence *incidence );
diff --git a/korganizer/kodaymatrix.cpp b/korganizer/kodaymatrix.cpp
index ff82ada9c..065e44e7c 100644
--- a/korganizer/kodaymatrix.cpp
+++ b/korganizer/kodaymatrix.cpp
@@ -228,11 +228,15 @@ void KODayMatrix::recalculateToday()
updateView( mStartDate );
}
+void KODayMatrix::setUpdateNeeded()
+{
+ mPendingChanges = true;
+}
+
void KODayMatrix::updateView( const TQDate &actdate )
{
kdDebug(5850) << "KODayMatrix::updateView() " << actdate << ", day start="<<mStartDate<< endl;
if ( !actdate.isValid() ) return;
-
//flag to indicate if the starting day of the matrix has changed by this call
bool daychanged = false;
@@ -340,16 +344,19 @@ int KODayMatrix::getDayIndexFrom( int x, int y )
void KODayMatrix::calendarIncidenceAdded(Incidence * incidence)
{
+ Q_UNUSED( incidence );
mPendingChanges = true;
}
void KODayMatrix::calendarIncidenceChanged(Incidence * incidence)
{
+ Q_UNUSED( incidence );
mPendingChanges = true;
}
-void KODayMatrix::calendarIncidenceRemoved(Incidence * incidence)
+void KODayMatrix::calendarIncidenceDeleted(Incidence * incidence)
{
+ Q_UNUSED( incidence );
mPendingChanges = true;
}
@@ -406,7 +413,7 @@ void KODayMatrix::mouseMoveEvent( TQMouseEvent *e )
if (mSelInit > tmp) {
mSelEnd = mSelInit;
- if (tmp != mSelStart) {
+ if ( tmp != mSelStart ) {
mSelStart = tmp;
repaint();
}
@@ -414,7 +421,7 @@ void KODayMatrix::mouseMoveEvent( TQMouseEvent *e )
mSelStart = mSelInit;
//repaint only if selection has changed
- if (tmp != mSelEnd) {
+ if ( tmp != mSelEnd ) {
mSelEnd = tmp;
repaint();
}
@@ -669,8 +676,7 @@ void KODayMatrix::paintEvent( TQPaintEvent * )
}
// draw selected days with special color
- // DO NOT specially highlight holidays in selection !
- if (i >= mSelStart && i <= mSelEnd) {
+ if ( i >= mSelStart && i <= mSelEnd && !holiday ) {
p.setPen( TQColor( "white" ) );
}
@@ -678,7 +684,7 @@ void KODayMatrix::paintEvent( TQPaintEvent * )
Qt::AlignHCenter | Qt::AlignVCenter, mDayLabels[i]);
// reset color to actual color
- if (holiday) {
+ if ( holiday ) {
p.setPen(actcol);
}
// reset bold font to plain font
@@ -689,7 +695,7 @@ void KODayMatrix::paintEvent( TQPaintEvent * )
}
}
p.end();
- bitBlt( this, 0, 0, &pm );
+ bitBlt( this, 0, 0, &pm );
}
// ----------------------------------------------------------------------------
@@ -702,3 +708,22 @@ void KODayMatrix::resizeEvent( TQResizeEvent * )
mDaySize.setHeight( sz.height() * 7 / NUMDAYS );
mDaySize.setWidth( sz.width() / 7 );
}
+
+/* static */
+QPair<TQDate,TQDate> KODayMatrix::matrixLimits( const TQDate &month )
+{
+ const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem();
+ TQDate d = month;
+ calSys->setYMD( d, calSys->year( month ), calSys->month( month ), 1 );
+
+ const int dayOfWeek = calSys->dayOfWeek( d );
+ const int weekstart = KGlobal::locale()->weekStartDay();
+
+ d = d.addDays( weekstart - dayOfWeek );
+
+ if ( dayOfWeek == weekstart ) {
+ d = d.addDays( -7 ); // Start on the second line
+ }
+
+ return qMakePair( d, d.addDays( NUMDAYS-1 ) );
+}
diff --git a/korganizer/kodaymatrix.h b/korganizer/kodaymatrix.h
index 7dcf830e1..b8354f799 100644
--- a/korganizer/kodaymatrix.h
+++ b/korganizer/kodaymatrix.h
@@ -118,6 +118,11 @@ class KODayMatrix: public TQFrame, public KCal::Calendar::Observer
*/
~KODayMatrix();
+ /** returns the first and last date of the 6*7 matrix that displays @p month
+ * @param month The month we want to get matrix boundaries
+ */
+ static QPair<TQDate,TQDate> matrixLimits( const TQDate &month );
+
/**
Associate a calendar with this day matrix. If there is a calendar, the day
matrix will accept drops and days with events will be highlighted.
@@ -182,7 +187,9 @@ class KODayMatrix: public TQFrame, public KCal::Calendar::Observer
/* reimplmented from KCal::Calendar::Observer */
void calendarIncidenceAdded( Incidence *incidence );
void calendarIncidenceChanged( Incidence *incidence );
- void calendarIncidenceRemoved( Incidence *incidence );
+ void calendarIncidenceDeleted( Incidence *incidence );
+
+ void setUpdateNeeded();
public slots:
/** Recalculates all the flags of the days in the matrix like holidays or events
diff --git a/korganizer/kodialogmanager.cpp b/korganizer/kodialogmanager.cpp
index e17f03409..11f01aa58 100644
--- a/korganizer/kodialogmanager.cpp
+++ b/korganizer/kodialogmanager.cpp
@@ -170,15 +170,15 @@ void KODialogManager::showCategoryEditDialog()
void KODialogManager::showSearchDialog()
{
- if (!mSearchDialog) {
- mSearchDialog = new SearchDialog(mMainView->calendar(),mMainView);
- connect(mSearchDialog,TQT_SIGNAL(showIncidenceSignal(Incidence *)),
- mMainView,TQT_SLOT(showIncidence(Incidence *)));
- connect(mSearchDialog,TQT_SIGNAL(editIncidenceSignal(Incidence *)),
- mMainView,TQT_SLOT(editIncidence(Incidence *)));
- connect(mSearchDialog,TQT_SIGNAL(deleteIncidenceSignal(Incidence *)),
- mMainView, TQT_SLOT(deleteIncidence(Incidence *)));
- connect(mMainView,TQT_SIGNAL(closingDown()),mSearchDialog,TQT_SLOT(reject()));
+ if ( !mSearchDialog ) {
+ mSearchDialog = new SearchDialog( mMainView->calendar(), mMainView );
+ connect( mSearchDialog, TQT_SIGNAL(showIncidenceSignal(Incidence *,const TQDate &)),
+ mMainView, TQT_SLOT(showIncidence(Incidence *,const TQDate &)) );
+ connect( mSearchDialog, TQT_SIGNAL(editIncidenceSignal(Incidence *,const TQDate &)),
+ mMainView, TQT_SLOT(editIncidence(Incidence *,const TQDate &)) );
+ connect( mSearchDialog, TQT_SIGNAL(deleteIncidenceSignal(Incidence *)),
+ mMainView, TQT_SLOT(deleteIncidence(Incidence *)) );
+ connect( mMainView, TQT_SIGNAL(closingDown()),mSearchDialog,TQT_SLOT(reject()) );
}
// make sure the widget is on top again
mSearchDialog->show();
diff --git a/korganizer/koeditoralarms.cpp b/korganizer/koeditoralarms.cpp
index 0a2c7399a..8f3cb4648 100644
--- a/korganizer/koeditoralarms.cpp
+++ b/korganizer/koeditoralarms.cpp
@@ -25,6 +25,9 @@
#include "koeditoralarms_base.h"
#include "koeditoralarms.h"
+#include "koprefs.h"
+
+#include <libkcal/duration.h>
#include <tqlayout.h>
#include <tqlistview.h>
@@ -35,6 +38,9 @@
#include <tqbuttongroup.h>
#include <tqtextedit.h>
#include <tqwidgetstack.h>
+#include <tqradiobutton.h>
+#include <tqtooltip.h>
+#include <tqwhatsthis.h>
#include <kurlrequester.h>
#include <klocale.h>
@@ -48,22 +54,46 @@
class AlarmListViewItem : public QListViewItem
{
public:
- AlarmListViewItem( TQListView *parent, KCal::Alarm *alarm );
+ AlarmListViewItem( TQListView *parent, KCal::Alarm *alarm, const TQCString &inctype );
virtual ~AlarmListViewItem();
KCal::Alarm *alarm() const { return mAlarm; }
void construct();
enum AlarmViewColumns { ColAlarmType=0, ColAlarmOffset, ColAlarmRepeat };
+
protected:
KCal::Alarm *mAlarm;
+
+ private:
+ TQCString mIncType;
};
-AlarmListViewItem::AlarmListViewItem( TQListView *parent, KCal::Alarm *alarm )
- : TQListViewItem( parent )
+AlarmListViewItem::AlarmListViewItem( TQListView *parent, KCal::Alarm *alarm,
+ const TQCString &inctype )
+ : TQListViewItem( parent ), mIncType( inctype )
{
if ( alarm ) {
mAlarm = new KCal::Alarm( *alarm );
} else {
mAlarm = new KCal::Alarm( 0 );
+ mAlarm->setType( KCal::Alarm::Display );
+ int duration; // in secs
+ switch( KOPrefs::instance()->mReminderTimeUnits ) {
+ default:
+ case 0: // mins
+ duration = KOPrefs::instance()->mReminderTime * 60;
+ break;
+ case 1: // hours
+ duration = KOPrefs::instance()->mReminderTime * 60 * 60;
+ break;
+ case 2: // days
+ duration = KOPrefs::instance()->mReminderTime * 60 * 60 * 24;
+ break;
+ }
+ if ( mIncType == "Event" ) {
+ mAlarm->setStartOffset( KCal::Duration( -duration ) );
+ } else {
+ mAlarm->setEndOffset( KCal::Duration( -duration ) );
+ }
}
construct();
}
@@ -102,19 +132,33 @@ void AlarmListViewItem::construct()
int offset = 0;
if ( mAlarm->hasStartOffset() ) {
offset = mAlarm->startOffset().asSeconds();
- if ( offset < 0 ) {
- offsetstr = i18n("N days/hours/minutes before/after the start/end", "%1 before the start");
+ if ( offset <= 0 ) {
+ offsetstr = i18n( "N days/hours/minutes before/after the start/end",
+ "%1 before the start" );
offset = -offset;
} else {
- offsetstr = i18n("N days/hours/minutes before/after the start/end", "%1 after the start");
+ offsetstr = i18n( "N days/hours/minutes before/after the start/end",
+ "%1 after the start" );
}
} else if ( mAlarm->hasEndOffset() ) {
offset = mAlarm->endOffset().asSeconds();
- if ( offset < 0 ) {
- offsetstr = i18n("N days/hours/minutes before/after the start/end", "%1 before the end");
+ if ( offset <= 0 ) {
+ if ( mIncType == "Todo" ) {
+ offsetstr = i18n( "N days/hours/minutes before/after the due date",
+ "%1 before the to-do is due" );
+ } else {
+ offsetstr = i18n( "N days/hours/minutes before/after the start/end",
+ "%1 before the end" );
+ }
offset = -offset;
} else {
- offsetstr = i18n("N days/hours/minutes before/after the start/end", "%1 after the end");
+ if ( mIncType == "Todo" ) {
+ offsetstr = i18n( "N days/hours/minutes before/after the due date",
+ "%1 after the to-do is due" );
+ } else {
+ offsetstr = i18n( "N days/hours/minutes before/after the start/end",
+ "%1 after the end" );
+ }
}
}
@@ -143,11 +187,23 @@ void AlarmListViewItem::construct()
}
-KOEditorAlarms::KOEditorAlarms( KCal::Alarm::List *alarms, TQWidget *parent,
+KOEditorAlarms::KOEditorAlarms( const TQCString &type,
+ KCal::Alarm::List *alarms, TQWidget *parent,
const char *name )
- : KDialogBase( parent, name, true, i18n("Edit Reminders"), Ok | Cancel ), mAlarms( alarms ),mCurrentItem(0L)
+ : KDialogBase( parent, name, true, i18n("Advanced Reminders"), Ok | Cancel ),
+ mType( type ), mAlarms( alarms ),mCurrentItem( 0 )
{
+ if ( mType != "Todo" ) {
+ // only Todos and Events can have reminders
+ mType = "Event";
+ }
setMainWidget( mWidget = new KOEditorAlarms_base( this ) );
+
+ // The text is set here, and not in the UI file, because the i18n context is not
+ // properly extracted from the UI file.
+ mWidget->mAddButton->setText( i18n( "Add a new alarm to the alarm list.", "&Add" ) );
+
+ mWidget->mAlarmList->setResizeMode( TQListView::LastColumn );
mWidget->mAlarmList->setColumnWidthMode( 0, TQListView::Maximum );
mWidget->mAlarmList->setColumnWidthMode( 1, TQListView::Maximum );
connect( mWidget->mAlarmList, TQT_SIGNAL( selectionChanged( TQListViewItem * ) ),
@@ -171,6 +227,11 @@ KOEditorAlarms::KOEditorAlarms( KCal::Alarm::List *alarms, TQWidget *parent,
connect( mWidget->mEmailText, TQT_SIGNAL( textChanged() ), TQT_SLOT( changed() ) );
init();
+
+ //TODO: backport email reminders from trunk
+ mWidget->mTypeEmailRadio->hide(); //email reminders not implemented yet
+
+ mWidget->setMinimumSize( 500, 500 );
}
KOEditorAlarms::~KOEditorAlarms()
@@ -180,7 +241,16 @@ KOEditorAlarms::~KOEditorAlarms()
void KOEditorAlarms::changed()
{
if ( !mInitializing && mCurrentItem ) {
- writeAlarm( mCurrentItem->alarm() );
+ KCal::Alarm *alarm = mCurrentItem->alarm();
+
+ // Based on settings, provide default sound file for audio alarms
+ if ( alarm->audioFile().isEmpty() &&
+ KOPrefs::instance()->defaultAudioFileReminders() ) {
+ alarm->setAudioFile( KOPrefs::instance()->audioFilePath() );
+ mWidget->mSoundFile->setURL( KOPrefs::instance()->audioFilePath() );
+ }
+
+ writeAlarm( alarm );
mCurrentItem->construct();
}
}
@@ -194,6 +264,11 @@ void KOEditorAlarms::readAlarm( KCal::Alarm *alarm )
// Offsets
int offset;
int beforeafterpos = 0;
+ if ( mType == "Todo" ) {
+ if ( !alarm->hasStartOffset() ) {
+ beforeafterpos = 2;
+ }
+ }
if ( alarm->hasEndOffset() ) {
beforeafterpos = 2;
offset = alarm->endOffset().asSeconds();
@@ -202,7 +277,7 @@ void KOEditorAlarms::readAlarm( KCal::Alarm *alarm )
offset = alarm->startOffset().asSeconds();
}
// Negative offset means before the start/end...
- if ( offset < 0 ) {
+ if ( offset <= 0 ) {
offset = -offset;
} else {
++beforeafterpos;
@@ -229,7 +304,7 @@ void KOEditorAlarms::readAlarm( KCal::Alarm *alarm )
mWidget->mRepeats->setChecked( alarm->repeatCount()>0 );
if ( alarm->repeatCount()>0 ) {
mWidget->mRepeatCount->setValue( alarm->repeatCount() );
- mWidget->mRepeatInterval->setValue( alarm->snoozeTime() );
+ mWidget->mRepeatInterval->setValue( alarm->snoozeTime().asSeconds() / 60 ); // show as minutes
}
switch ( alarm->type() ) {
@@ -290,7 +365,7 @@ void KOEditorAlarms::writeAlarm( KCal::Alarm *alarm )
// Repeating
if ( mWidget->mRepeats->isChecked() ) {
alarm->setRepeatCount( mWidget->mRepeatCount->value() );
- alarm->setSnoozeTime( mWidget->mRepeatInterval->value() );
+ alarm->setSnoozeTime( KCal::Duration( mWidget->mRepeatInterval->value() * 60 ) ); // convert back to seconds
} else {
alarm->setRepeatCount( 0 );
}
@@ -333,6 +408,9 @@ void KOEditorAlarms::selectionChanged( TQListViewItem *listviewitem )
void KOEditorAlarms::slotOk()
{
+ // save the current item settings, if any
+ changed();
+
// copy the mAlarms list
if ( mAlarms ) {
mAlarms->clear();
@@ -350,17 +428,15 @@ void KOEditorAlarms::slotOk()
void KOEditorAlarms::slotAdd()
{
- mCurrentItem = new AlarmListViewItem( mWidget->mAlarmList, 0 );
+ mCurrentItem = new AlarmListViewItem( mWidget->mAlarmList, 0, mType );
mWidget->mAlarmList->setCurrentItem( mCurrentItem );
-// selectionChanged( mCurrentItem );
}
void KOEditorAlarms::slotDuplicate()
{
if ( mCurrentItem ) {
- mCurrentItem = new AlarmListViewItem( mWidget->mAlarmList, mCurrentItem->alarm() );
+ mCurrentItem = new AlarmListViewItem( mWidget->mAlarmList, mCurrentItem->alarm(), mType );
mWidget->mAlarmList->setCurrentItem( mCurrentItem );
-// selectionChanged( mCurrentItem );
}
}
@@ -370,16 +446,36 @@ void KOEditorAlarms::slotRemove()
delete mCurrentItem;
mCurrentItem = dynamic_cast<AlarmListViewItem*>( mWidget->mAlarmList->currentItem() );
mWidget->mAlarmList->setSelected( mCurrentItem, true );
-
}
}
void KOEditorAlarms::init()
{
mInitializing = true;
+
+ // Tweak some UI stuff depending on the Incidence type
+ if ( mType == "Todo" ) {
+ // Replace before/after end datetime with before/after due datetime
+ mWidget->mBeforeAfter->clear();
+ mWidget->mBeforeAfter->insertItem( i18n( "before the to-do starts" ), 0 );
+ mWidget->mBeforeAfter->insertItem( i18n( "after the to-do starts" ), 1 );
+ mWidget->mBeforeAfter->insertItem( i18n( "before the to-do is due" ), 2 );
+ mWidget->mBeforeAfter->insertItem( i18n( "after the to-do is due" ), 3 );
+ TQToolTip::add(
+ mWidget->mBeforeAfter,
+ i18n( "Select the reminder trigger relative to the start or due time" ) );
+ TQWhatsThis::add(
+ mWidget->mBeforeAfter,
+ i18n( "Use this combobox to specify if you want the reminder to "
+ "trigger before or after the start or due time." ) );
+
+ mWidget->mBeforeAfter->setCurrentItem( 2 ); // default is before due start
+ }
+
+ // Fill-in existing alarms
KCal::Alarm::List::ConstIterator it;
for ( it = mAlarms->begin(); it != mAlarms->end(); ++it ) {
- new AlarmListViewItem( mWidget->mAlarmList, *it );
+ new AlarmListViewItem( mWidget->mAlarmList, *it, mType );
}
mWidget->mAlarmList->setSelected( mWidget->mAlarmList->firstChild(), true );
mInitializing = false;
diff --git a/korganizer/koeditoralarms.h b/korganizer/koeditoralarms.h
index ed01d656b..971df799b 100644
--- a/korganizer/koeditoralarms.h
+++ b/korganizer/koeditoralarms.h
@@ -35,7 +35,8 @@ class KOEditorAlarms : public KDialogBase
{
Q_OBJECT
public:
- KOEditorAlarms( KCal::Alarm::List *alarms, TQWidget *parent = 0,
+ KOEditorAlarms( const TQCString &type,
+ KCal::Alarm::List *alarms, TQWidget *parent = 0,
const char *name = 0 );
~KOEditorAlarms();
@@ -46,11 +47,14 @@ class KOEditorAlarms : public KDialogBase
void slotRemove();
void changed();
void selectionChanged( TQListViewItem *listviewitem );
+
protected:
void init();
void readAlarm( KCal::Alarm *alarm );
void writeAlarm( KCal::Alarm *alarm );
+
private:
+ TQCString mType; // as in the Incidence::type
KCal::Alarm::List *mAlarms;
KOEditorAlarms_base *mWidget;
bool mInitializing;
diff --git a/korganizer/koeditoralarms_base.ui b/korganizer/koeditoralarms_base.ui
index 68e8d5bc9..1da104404 100644
--- a/korganizer/koeditoralarms_base.ui
+++ b/korganizer/koeditoralarms_base.ui
@@ -45,6 +45,12 @@
<property name="name">
<cstring>mAlarmOffset</cstring>
</property>
+ <property name="maxValue">
+ <number>99999</number>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
<property name="sizePolicy">
<sizepolicy>
<hsizetype>4</hsizetype>
@@ -381,7 +387,7 @@
<cstring>mSoundFile</cstring>
</property>
<property name="filter">
- <string>audio/x-wav audio/x-mp3 application/ogg</string>
+ <string>audio/x-wav audio/x-mp3 application/ogg</string>
</property>
</widget>
<spacer>
@@ -535,7 +541,7 @@
<cstring>mRemoveButton</cstring>
</property>
<property name="text">
- <string>&amp;Remove...</string>
+ <string>&amp;Remove</string>
</property>
</widget>
<widget class="QPushButton" row="0" column="1">
@@ -543,7 +549,7 @@
<cstring>mAddButton</cstring>
</property>
<property name="text">
- <string>&amp;Add</string>
+ <string></string>
</property>
</widget>
<widget class="QPushButton" row="1" column="1">
diff --git a/korganizer/koeditorattachments.cpp b/korganizer/koeditorattachments.cpp
index adcd871e6..99d775e69 100644
--- a/korganizer/koeditorattachments.cpp
+++ b/korganizer/koeditorattachments.cpp
@@ -25,15 +25,19 @@
#include "koeditorattachments.h"
+#include <libkcal/attachmenthandler.h>
#include <libkcal/incidence.h>
#include <libkdepim/kpimurlrequesterdlg.h>
#include <libkdepim/kfileio.h>
+#include <libkdepim/kdepimprotocols.h>
+#include <libkdepim/maillistdrag.h>
+#include <libkdepim/kvcarddrag.h>
+#include <libkdepim/kdepimprotocols.h>
#include <klocale.h>
#include <kdebug.h>
#include <kmdcodec.h>
#include <kmessagebox.h>
-#include <kiconview.h>
#include <krun.h>
#include <kurldrag.h>
#include <ktempfile.h>
@@ -45,7 +49,13 @@
#include <kstdaction.h>
#include <kactioncollection.h>
#include <kpopupmenu.h>
+#include <kprotocolinfo.h>
+#include <klineedit.h>
+#include <kseparator.h>
+#include <kurlrequester.h>
+#include <libkmime/kmime_message.h>
+#include <tqcheckbox.h>
#include <tqfile.h>
#include <tqlabel.h>
#include <tqlayout.h>
@@ -58,7 +68,7 @@
#include <tqclipboard.h>
#include <cassert>
-#include <set>
+#include <cstdlib>
class AttachmentListItem : public KIconViewItem
{
@@ -69,7 +79,8 @@ class AttachmentListItem : public KIconViewItem
if ( att ) {
mAttachment = new KCal::Attachment( *att );
} else {
- mAttachment = new KCal::Attachment( TQString::null );
+ mAttachment = new KCal::Attachment( '\0' ); //use the non-uri constructor
+ //as we want inline by default
}
readAttachment();
setDragEnabled( true );
@@ -77,112 +88,364 @@ class AttachmentListItem : public KIconViewItem
~AttachmentListItem() { delete mAttachment; }
KCal::Attachment *attachment() const { return mAttachment; }
+ const TQString uri() const
+ {
+ return mAttachment->uri();
+ }
void setUri( const TQString &uri )
{
mAttachment->setUri( uri );
readAttachment();
}
- void setData( const char *base64 )
+ void setData( const TQByteArray data )
{
- mAttachment->setData( base64 );
+ mAttachment->setDecodedData( data );
readAttachment();
}
+ const TQString mimeType() const
+ {
+ return mAttachment->mimeType();
+ }
void setMimeType( const TQString &mime )
{
mAttachment->setMimeType( mime );
readAttachment();
}
+ const TQString label() const
+ {
+ return mAttachment->label();
+ }
void setLabel( const TQString &label )
{
mAttachment->setLabel( label );
readAttachment();
}
-
+ bool isBinary() const
+ {
+ return mAttachment->isBinary();
+ }
+ TQPixmap icon() const
+ {
+ return icon( KMimeType::mimeType( mAttachment->mimeType() ),
+ mAttachment->uri() );
+ }
+ static TQPixmap icon( KMimeType::Ptr mimeType, const TQString &uri )
+ {
+ TQString iconStr = mimeType->icon( uri, false );
+ return KGlobal::iconLoader()->loadIcon( iconStr, KIcon::Small );
+ }
void readAttachment()
{
- if ( mAttachment->isUri() )
- setText( mAttachment->uri() );
- else {
- if ( mAttachment->label().isEmpty() )
- setText( i18n("[Binary data]") );
- else
- setText( mAttachment->label() );
+ if ( mAttachment->label().isEmpty() ) {
+ if ( mAttachment->isUri() ) {
+ setText( mAttachment->uri() );
+ } else {
+ setText( i18n( "[Binary data]" ) );
+ }
+ } else {
+ setText( mAttachment->label() );
}
- KMimeType::Ptr mt = KMimeType::mimeType( mAttachment->mimeType() );
- if ( mt ) {
- const TQString iconName( mt->icon( TQString(), false ) );
- TQPixmap pix = KGlobal::iconLoader( )->loadIcon( iconName, KIcon::Small );
- if ( pix.isNull() )
- pix = KGlobal::iconLoader( )->loadIcon( "unknown", KIcon::Small );
- if ( !pix.isNull() )
- setPixmap( pix );
+ if ( mAttachment->mimeType().isEmpty() ||
+ !( KMimeType::mimeType( mAttachment->mimeType() ) ) ) {
+ KMimeType::Ptr mimeType;
+ if ( mAttachment->isUri() ) {
+ mimeType = KMimeType::findByURL( mAttachment->uri() );
+ } else {
+ mimeType = KMimeType::findByContent( mAttachment->decodedData() );
+ }
+ mAttachment->setMimeType( mimeType->name() );
}
+
+ setPixmap( icon() );
}
private:
KCal::Attachment *mAttachment;
};
-class AttachmentIconView : public KIconView
-{
- friend class KOEditorAttachments;
- public:
- AttachmentIconView( KOEditorAttachments* parent=0 )
- :KIconView( parent ),
- mParent( parent )
- {
- setAcceptDrops( true );
- setSelectionMode( TQIconView::Extended );
- setMode( KIconView::Select );
- setItemTextPos( TQIconView::Right );
- setArrangement( TQIconView::LeftToRight );
- setMaxItemWidth( QMAX(maxItemWidth(), 250) );
- setMinimumHeight( QMAX(fontMetrics().height(), 16) + 12 );
- }
- ~AttachmentIconView()
- {
- for ( std::set<KTempDir*>::iterator it = mTempDirs.begin() ; it != mTempDirs.end() ; ++it ) {
- delete *it;
- }
- }
- protected:
- TQDragObject * dragObject()
- {
- KURL::List urls;
- for ( TQIconViewItem *it = firstItem( ); it; it = it->nextItem( ) ) {
- if ( !it->isSelected() ) continue;
- AttachmentListItem * item = dynamic_cast<AttachmentListItem*>( it );
- if ( !item ) return 0;
- KCal::Attachment * att = item->attachment();
- assert( att );
- KURL url;
- if ( att->isUri() ) {
- url.setPath( att->uri() );
- } else {
- KTempDir * tempDir = new KTempDir(); // will be deleted on editor close
- tempDir->setAutoDelete( true );
- mTempDirs.insert( tempDir );
- TQByteArray encoded;
- encoded.duplicate( att->data(), strlen(att->data()) );
- TQByteArray decoded;
- KCodecs::base64Decode( encoded, decoded );
- const TQString fileName = tempDir->name( ) + "/" + att->label();
- KPIM::kByteArrayToFile( decoded, fileName, false, false, false );
- url.setPath( fileName );
- }
- urls << url;
- }
- KURLDrag *drag = new KURLDrag( urls, this );
- return drag;
- }
- void contentsDropEvent( TQDropEvent* event )
- {
- mParent->handlePasteOrDrop( event );
+AttachmentEditDialog::AttachmentEditDialog( AttachmentListItem *item,
+ TQWidget *parent )
+ : KDialogBase ( Plain, i18n( "Add Attachment" ), Ok|Cancel, Ok, parent, 0, false, false ),
+ mItem( item ), mURLRequester( 0 )
+{
+ TQFrame *topFrame = plainPage();
+ TQVBoxLayout *vbl = new TQVBoxLayout( topFrame, 0, spacingHint() );
+
+ TQGridLayout *grid = new TQGridLayout();
+ grid->setColStretch( 0, 0 );
+ grid->setColStretch( 1, 0 );
+ grid->setColStretch( 2, 1 );
+ vbl->addLayout( grid );
+
+ mIcon = new TQLabel( topFrame );
+ mIcon->setPixmap( item->icon() );
+ grid->addWidget( mIcon, 0, 0 );
+
+ mLabelEdit = new KLineEdit( topFrame );
+ mLabelEdit->setText( item->label().isEmpty() ? item->uri() : item->label() );
+ mLabelEdit->setClickMessage( i18n( "Attachment name" ) );
+ TQToolTip::add( mLabelEdit, i18n( "Give the attachment a name" ) );
+ TQWhatsThis::add( mLabelEdit,
+ i18n( "Type any string you desire here for the name of the attachment" ) );
+ grid->addMultiCellWidget( mLabelEdit, 0, 0, 1, 2 );
+
+ KSeparator *sep = new KSeparator( TQt::Horizontal, topFrame );
+ grid->addMultiCellWidget( sep, 1, 1, 0, 2 );
+
+ TQLabel *label = new TQLabel( i18n( "Type:" ), topFrame );
+ grid->addWidget( label, 2, 0 );
+ TQString typecomment = item->mimeType().isEmpty() ?
+ i18n( "Unknown" ) :
+ KMimeType::mimeType( item->mimeType() )->comment();
+ mTypeLabel = new TQLabel( typecomment, topFrame );
+ grid->addWidget( mTypeLabel, 2, 1 );
+ mMimeType = KMimeType::mimeType( item->mimeType() );
+
+ mInline = new TQCheckBox( i18n( "Store attachment inline" ), topFrame );
+ grid->addMultiCellWidget( mInline, 3, 3, 0, 2 );
+ mInline->setChecked( item->isBinary() );
+ TQToolTip::add( mInline, i18n( "Store the attachment file inside the calendar" ) );
+ TQWhatsThis::add(
+ mInline,
+ i18n( "Checking this option will cause the attachment to be stored inside "
+ "your calendar, which can take a lot of space depending on the size "
+ "of the attachment. If this option is not checked, then only a link "
+ "pointing to the attachment will be stored. Do not use a link for "
+ "attachments that change often or may be moved (or removed) from "
+ "their current location." ) );
+
+ if ( item->attachment()->isUri() || !item->attachment()->data() ) {
+ label = new TQLabel( i18n( "Location:" ), topFrame );
+ grid->addWidget( label, 4, 0 );
+ mURLRequester = new KURLRequester( item->uri(), topFrame );
+ TQToolTip::add( mURLRequester, i18n( "Provide a location for the attachment file" ) );
+ TQWhatsThis::add(
+ mURLRequester,
+ i18n( "Enter the path to the attachment file or use the "
+ "file browser by pressing the adjacent button" ) );
+ grid->addMultiCellWidget( mURLRequester, 4, 4, 1, 2 );
+ connect( mURLRequester, TQT_SIGNAL(urlSelected(const TQString &)),
+ TQT_SLOT(urlSelected(const TQString &)) );
+ connect( mURLRequester, TQT_SIGNAL( textChanged( const TQString& ) ),
+ TQT_SLOT( urlChanged( const TQString& ) ) );
+ urlChanged( item->uri() );
+ } else {
+ uint size = item->attachment()->size();
+ grid->addWidget( new TQLabel( i18n( "Size:" ), topFrame ), 4, 0 );
+ grid->addWidget( new TQLabel( TQString::fromLatin1( "%1 (%2)" ).
+ arg( KIO::convertSize( size ) ).
+ arg( KGlobal::locale()->formatNumber(
+ size, 0 ) ), topFrame ), 4, 2 );
+ }
+ vbl->addStretch( 10 );
+}
+
+void AttachmentEditDialog::slotApply()
+{
+ if ( !mLabelEdit->text().isEmpty() ) {
+ mItem->setLabel( mLabelEdit->text() );
+ } else {
+ if ( mURLRequester ) {
+ KURL url( mURLRequester->url() );
+ if ( url.isLocalFile() ) {
+ mItem->setLabel( url.fileName() );
+ } else {
+ mItem->setLabel( url.url() );
+ }
+ }
+ }
+ if ( mItem->label().isEmpty() ) {
+ mItem->setLabel( i18n( "New attachment" ) );
+ }
+ mItem->setMimeType( mMimeType->name() );
+ if ( mURLRequester ) {
+ KURL url( mURLRequester->url() );
+
+ TQString correctedUrl = mURLRequester->url();
+ if ( !url.isValid() ) {
+ // If the user used KURLRequester's KURLCompletion
+ // (used the line edit instead of the file dialog)
+ // the returned url is not absolute and is always relative
+ // to the home directory (not pwd), so we must prepend home
+
+ correctedUrl = TQDir::home().filePath( mURLRequester->url() );
+ url = KURL( correctedUrl );
+ if ( url.isValid() ) {
+ urlSelected( correctedUrl );
+ mItem->setMimeType( mMimeType->name() );
+ }
+ }
+
+ if ( mInline->isChecked() ) {
+ TQString tmpFile;
+ if ( KIO::NetAccess::download( correctedUrl, tmpFile, this ) ) {
+ TQFile f( tmpFile );
+ if ( !f.open( IO_ReadOnly ) ) {
+ return;
}
- private:
- std::set<KTempDir*> mTempDirs;
- KOEditorAttachments* mParent;
-};
+ TQByteArray data = f.readAll();
+ f.close();
+ mItem->setData( data );
+ }
+ KIO::NetAccess::removeTempFile( tmpFile );
+ } else {
+ mItem->setUri( url.url() );
+ }
+ }
+}
+
+void AttachmentEditDialog::accept()
+{
+ slotApply();
+ KDialog::accept();
+}
+
+void AttachmentEditDialog::urlChanged( const TQString &url )
+{
+ enableButton( Ok, !url.isEmpty() );
+}
+
+void AttachmentEditDialog::urlSelected( const TQString &url )
+{
+ KURL kurl( url );
+ mMimeType = KMimeType::findByURL( kurl );
+ mTypeLabel->setText( mMimeType->comment() );
+ mIcon->setPixmap( AttachmentListItem::icon( mMimeType, kurl.path() ) );
+}
+
+AttachmentIconView::AttachmentIconView( KOEditorAttachments* parent )
+ : KIconView( parent ),
+ mParent( parent )
+{
+ setSelectionMode( TQIconView::Extended );
+ setMode( KIconView::Select );
+ setItemTextPos( TQIconView::Right );
+ setArrangement( TQIconView::LeftToRight );
+ setMaxItemWidth( QMAX(maxItemWidth(), 250) );
+ setMinimumHeight( QMAX(fontMetrics().height(), 16) + 12 );
+
+ connect( this, TQT_SIGNAL( dropped ( TQDropEvent *, const TQValueList<TQIconDragItem> & ) ),
+ this, TQT_SLOT( handleDrop( TQDropEvent *, const TQValueList<TQIconDragItem> & ) ) );
+}
+
+KURL AttachmentIconView::tempFileForAttachment( KCal::Attachment *attachment )
+{
+ if ( mTempFiles.contains( attachment ) ) {
+ return mTempFiles[attachment];
+ }
+ TQStringList patterns = KMimeType::mimeType( attachment->mimeType() )->patterns();
+
+ KTempFile *file;
+ if ( !patterns.empty() ) {
+ file = new KTempFile( TQString::null,
+ TQString( patterns.first() ).remove( '*' ),0600 );
+ } else {
+ file = new KTempFile( TQString::null, TQString::null, 0600 );
+ }
+ file->setAutoDelete( true );
+ file->file()->open( IO_WriteOnly );
+ TQTextStream stream( file->file() );
+ stream.writeRawBytes( attachment->decodedData().data(), attachment->size() );
+ KURL url( file->name() );
+ mTempFiles.insert( attachment, url );
+ file->close();
+ return mTempFiles[attachment];
+}
+
+TQDragObject *AttachmentIconView::mimeData()
+{
+ // create a list of the URL:s that we want to drag
+ KURL::List urls;
+ TQStringList labels;
+ for ( TQIconViewItem *it = firstItem(); it; it = it->nextItem() ) {
+ if ( it->isSelected() ) {
+ AttachmentListItem *item = static_cast<AttachmentListItem *>( it );
+ if ( item->isBinary() ) {
+ urls.append( tempFileForAttachment( item->attachment() ) );
+ } else {
+ urls.append( item->uri() );
+ }
+ labels.append( KURL::encode_string( item->label() ) );
+ }
+ }
+ if ( selectionMode() == TQIconView::NoSelection ) {
+ AttachmentListItem *item = static_cast<AttachmentListItem *>( currentItem() );
+ if ( item ) {
+ urls.append( item->uri() );
+ labels.append( KURL::encode_string( item->label() ) );
+ }
+ }
+
+ TQMap<TQString, TQString> metadata;
+ metadata["labels"] = labels.join( ":" );
+
+ KURLDrag *drag = new KURLDrag( urls, metadata );
+ return drag;
+}
+
+AttachmentIconView::~AttachmentIconView()
+{
+ for ( std::set<KTempDir*>::iterator it = mTempDirs.begin() ; it != mTempDirs.end() ; ++it ) {
+ delete *it;
+ }
+}
+
+TQDragObject * AttachmentIconView::dragObject()
+{
+ KURL::List urls;
+ for ( TQIconViewItem *it = firstItem( ); it; it = it->nextItem( ) ) {
+ if ( !it->isSelected() ) continue;
+ AttachmentListItem * item = dynamic_cast<AttachmentListItem*>( it );
+ if ( !item ) return 0;
+ KCal::Attachment * att = item->attachment();
+ assert( att );
+ KURL url;
+ if ( att->isUri() ) {
+ url.setPath( att->uri() );
+ } else {
+ KTempDir *tempDir = new KTempDir(); // will be deleted on editor close
+ tempDir->setAutoDelete( true );
+ mTempDirs.insert( tempDir );
+ TQByteArray encoded;
+ encoded.duplicate( att->data(), strlen( att->data() ) );
+ TQByteArray decoded;
+ KCodecs::base64Decode( encoded, decoded );
+ const TQString fileName = tempDir->name( ) + '/' + att->label();
+ KPIM::kByteArrayToFile( decoded, fileName, false, false, false );
+ url.setPath( fileName );
+ }
+ urls << url;
+ }
+ KURLDrag *drag = new KURLDrag( urls, this );
+ return drag;
+}
+
+void AttachmentIconView::handleDrop( TQDropEvent *event, const TQValueList<TQIconDragItem> & list )
+{
+ Q_UNUSED( list );
+ mParent->handlePasteOrDrop( event );
+}
+
+
+void AttachmentIconView::dragMoveEvent( TQDragMoveEvent *event )
+{
+ mParent->dragMoveEvent( event );
+}
+
+void AttachmentIconView::contentsDragMoveEvent( TQDragMoveEvent *event )
+{
+ mParent->dragMoveEvent( event );
+}
+
+void AttachmentIconView::contentsDragEnterEvent( TQDragEnterEvent *event )
+{
+ mParent->dragMoveEvent( event );
+}
+
+void AttachmentIconView::dragEnterEvent( TQDragEnterEvent *event )
+{
+ mParent->dragEnterEvent( event );
+}
KOEditorAttachments::KOEditorAttachments( int spacing, TQWidget *parent,
const char *name )
@@ -206,44 +469,51 @@ KOEditorAttachments::KOEditorAttachments( int spacing, TQWidget *parent,
connect( mAttachments, TQT_SIGNAL(contextMenuRequested(TQIconViewItem*,const TQPoint&)),
TQT_SLOT(contextMenu(TQIconViewItem*,const TQPoint&)) );
- mAddMenu = new KPopupMenu( this );
+ TQPushButton *addButton = new TQPushButton( this );
+ addButton->setIconSet( SmallIconSet( "add" ) );
+ TQToolTip::add( addButton, i18n( "Add an attachment" ) );
+ TQWhatsThis::add( addButton,
+ i18n( "Shows a dialog used to select an attachment "
+ "to add to this event or to-do as link or as "
+ "inline data." ) );
+ topLayout->addWidget( addButton );
+ connect( addButton, TQT_SIGNAL(clicked()), TQT_SLOT(slotAdd()) );
+
+ mRemoveBtn = new TQPushButton( this );
+ mRemoveBtn->setIconSet( SmallIconSet( "remove" ) );
+ TQToolTip::add( mRemoveBtn, i18n("&Remove") );
+ TQWhatsThis::add( mRemoveBtn,
+ i18n("Removes the attachment selected in the list above "
+ "from this event or to-do.") );
+ topLayout->addWidget( mRemoveBtn );
+ connect( mRemoveBtn, TQT_SIGNAL(clicked()), TQT_SLOT(slotRemove()) );
+
mContextMenu = new KPopupMenu( this );
KActionCollection* ac = new KActionCollection( this, this );
- mOpenAction = new KAction( i18n("View"), 0, this, TQT_SLOT(slotShow()), ac );
+ mOpenAction = new KAction( i18n("Open"), 0, this, TQT_SLOT(slotShow()), ac );
mOpenAction->plug( mContextMenu );
+
+ mSaveAsAction = new KAction( i18n( "Save As..." ), 0, this, TQT_SLOT(slotSaveAs()), ac );
+ mSaveAsAction->plug( mContextMenu );
mContextMenu->insertSeparator();
- mCopyAction = KStdAction::copy(this, TQT_SLOT(slotCopy( ) ), ac );
+ mCopyAction = KStdAction::copy(this, TQT_SLOT(slotCopy()), ac );
mCopyAction->plug( mContextMenu );
- mCutAction = KStdAction::cut(this, TQT_SLOT(slotCut( ) ), ac );
+ mCutAction = KStdAction::cut(this, TQT_SLOT(slotCut()), ac );
mCutAction->plug( mContextMenu );
- KAction *action = KStdAction::paste(this, TQT_SLOT(slotPaste( ) ), ac );
+ KAction *action = KStdAction::paste(this, TQT_SLOT(slotPaste()), ac );
action->plug( mContextMenu );
+ mContextMenu->insertSeparator();
- action = new KAction( i18n("&Attach File..."), 0, this, TQT_SLOT(slotAddData()), ac );
- action->setWhatsThis( i18n("Shows a dialog used to select an attachment "
- "to add to this event or to-do as link as inline data.") );
- action->plug( mAddMenu );
- action = new KAction( i18n("Attach &Link..."), 0, this, TQT_SLOT(slotAdd()), ac );
- action->setWhatsThis( i18n("Shows a dialog used to select an attachment "
- "to add to this event or to-do as link.") );
- action->plug( mAddMenu );
+ mDeleteAction = new KAction( i18n( "&Remove" ), 0, this, TQT_SLOT(slotRemove()), ac );
+ mDeleteAction->plug( mContextMenu );
+ mDeleteAction->setShortcut( Key_Delete );
+ mContextMenu->insertSeparator();
- TQPushButton *addButton = new TQPushButton( this );
- addButton->setIconSet( SmallIconSet( "add" ) );
- addButton->setPopup( mAddMenu );
- topLayout->addWidget( addButton );
-
- mRemoveBtn = new TQPushButton( this );
- mRemoveBtn->setIconSet( SmallIconSet( "remove" ) );
- TQToolTip::add( mRemoveBtn, i18n("&Remove") );
- TQWhatsThis::add( mRemoveBtn,
- i18n("Removes the attachment selected in the list above "
- "from this event or to-do.") );
- topLayout->addWidget( mRemoveBtn );
- connect( mRemoveBtn, TQT_SIGNAL( clicked() ), TQT_SLOT( slotRemove() ) );
+ mEditAction = new KAction( i18n( "&Properties..." ), 0, this, TQT_SLOT(slotEdit()), ac );
+ mEditAction->plug( mContextMenu );
selectionChanged();
setAcceptDrops( true );
@@ -258,26 +528,106 @@ bool KOEditorAttachments::hasAttachments()
return mAttachments->count() != 0;
}
+void KOEditorAttachments::dragMoveEvent( TQDragMoveEvent *event )
+{
+ event->accept( KURLDrag::canDecode( event ) ||
+ TQTextDrag::canDecode( event ) ||
+ KPIM::MailListDrag::canDecode( event ) ||
+ KVCardDrag::canDecode( event ) );
+}
+
void KOEditorAttachments::dragEnterEvent( TQDragEnterEvent* event )
{
- event->accept( KURLDrag::canDecode( event ) | TQTextDrag::canDecode( event ) );
+ dragMoveEvent( event );
}
void KOEditorAttachments::handlePasteOrDrop( TQMimeSource* source )
{
KURL::List urls;
- TQString text;
- if ( KURLDrag::decode( source, urls ) ) {
- const bool asUri = KMessageBox::questionYesNo( this,
- i18n("Do you want to link to the attachments, or include them in the event?"),
- i18n("Attach as link?"), i18n("As Link"), i18n("As File") ) == KMessageBox::Yes;
- for ( KURL::List::ConstIterator it = urls.begin(); it != urls.end(); ++it ) {
- addAttachment( (*it).url(), TQString::null, asUri );
- }
- } else if ( TQTextDrag::decode( source, text ) ) {
- TQStringList lst = TQStringList::split( '\n', text );
- for ( TQStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it ) {
- addAttachment( (*it) );
+ bool probablyWeHaveUris = false;
+ bool weCanCopy = true;
+ TQStringList labels;
+
+ if ( KVCardDrag::canDecode( source ) ) {
+ KABC::Addressee::List addressees;
+ KVCardDrag::decode( source, addressees );
+ for ( KABC::Addressee::List::ConstIterator it = addressees.constBegin();
+ it != addressees.constEnd(); ++it ) {
+ urls.append( KDEPIMPROTOCOL_CONTACT + ( *it ).uid() );
+ // there is some weirdness about realName(), hence fromUtf8
+ labels.append( TQString::fromUtf8( ( *it ).realName().latin1() ) );
+ }
+ probablyWeHaveUris = true;
+ } else if ( KURLDrag::canDecode( source ) ) {
+ TQMap<TQString,TQString> metadata;
+ if ( KURLDrag::decode( source, urls, metadata ) ) {
+ probablyWeHaveUris = true;
+ labels = TQStringList::split( ':', metadata["labels"], FALSE );
+ for ( TQStringList::Iterator it = labels.begin(); it != labels.end(); ++it ) {
+ *it = KURL::decode_string( (*it).latin1() );
+ }
+
+ }
+ } else if ( TQTextDrag::canDecode( source ) ) {
+ TQString text;
+ TQTextDrag::decode( source, text );
+ TQStringList lst = TQStringList::split( '\n', text, FALSE );
+ for ( TQStringList::ConstIterator it = lst.constBegin(); it != lst.constEnd(); ++it ) {
+ urls.append( *it );
+ labels.append( TQString::null );
+ }
+ probablyWeHaveUris = true;
+ }
+
+ KPopupMenu menu;
+ int items=0;
+ if ( probablyWeHaveUris ) {
+ menu.insertItem( i18n( "&Link here" ), DRAG_LINK, items++ );
+ // we need to check if we can reasonably expect to copy the objects
+ for ( KURL::List::ConstIterator it = urls.constBegin(); it != urls.constEnd(); ++it ) {
+ if ( !( weCanCopy = KProtocolInfo::supportsReading( *it ) ) ) {
+ break; // either we can copy them all, or no copying at all
+ }
+ }
+ if ( weCanCopy ) {
+ menu.insertItem( SmallIcon( "editcopy" ), i18n( "&Copy Here" ), DRAG_COPY, items++ );
+ }
+ } else {
+ menu.insertItem( SmallIcon( "editcopy" ), i18n( "&Copy Here" ), DRAG_COPY, items++ );
+ }
+
+ menu.insertSeparator();
+ items++;
+ menu.insertItem( SmallIcon( "cancel" ), i18n( "C&ancel" ), DRAG_CANCEL, items );
+ int action = menu.exec( TQCursor::pos(), 0 );
+
+ if ( action == DRAG_LINK ) {
+ TQStringList::ConstIterator jt = labels.constBegin();
+ for ( KURL::List::ConstIterator it = urls.constBegin();
+ it != urls.constEnd(); ++it ) {
+ TQString label = (*jt++);
+ if ( mAttachments->findItem( label ) ) {
+ label += '~' + randomString( 3 );
+ }
+ addUriAttachment( (*it).url(), TQString::null, label, true );
+ }
+ } else if ( action != DRAG_CANCEL ) {
+ if ( probablyWeHaveUris ) {
+ for ( KURL::List::ConstIterator it = urls.constBegin();
+ it != urls.constEnd(); ++it ) {
+ TQString label = (*it).fileName();
+ if ( label.isEmpty() ) {
+ label = (*it).prettyURL();
+ }
+ if ( mAttachments->findItem( label ) ) {
+ label += '~' + randomString( 3 );
+ }
+ addUriAttachment( (*it).url(), TQString::null, label, true );
+ }
+ } else { // we take anything
+ addDataAttachment( source->encodedData( source->format() ),
+ source->format(),
+ KMimeType::mimeType( source->format() )->name() );
}
}
}
@@ -293,95 +643,98 @@ void KOEditorAttachments::showAttachment( TQIconViewItem *item )
if ( !attitem || !attitem->attachment() ) return;
KCal::Attachment *att = attitem->attachment();
- if ( att->isUri() ) {
- emit openURL( att->uri() );
- } else {
- KTempFile f;
- if ( !f.file() )
- return;
- TQByteArray encoded;
- encoded.duplicate( att->data(), strlen(att->data()) );
- TQByteArray decoded;
- KCodecs::base64Decode( encoded, decoded );
- f.file()->writeBlock( decoded );
- f.file()->close();
- KRun::runURL( f.name(), att->mimeType(), true, false );
- }
+ KCal::AttachmentHandler::view( this, att );
+}
+
+void KOEditorAttachments::saveAttachment( TQIconViewItem *item )
+{
+ AttachmentListItem *attitem = static_cast<AttachmentListItem*>(item);
+ if ( !attitem || !attitem->attachment() ) return;
+
+ KCal::Attachment *att = attitem->attachment();
+ KCal::AttachmentHandler::saveAs( this, att );
}
void KOEditorAttachments::slotAdd()
{
- KURL uri = KPimURLRequesterDlg::getURL( TQString::null, i18n(
- "URL (e.g. a web page) or file to be attached (only "
- "the link will be attached, not the file itself):"), this,
- i18n("Add Attachment") );
- if ( !uri.isEmpty() ) {
- addAttachment( uri );
+ AttachmentListItem *item = new AttachmentListItem( 0, mAttachments );
+
+ AttachmentEditDialog *dlg = new AttachmentEditDialog( item, mAttachments )
+;
+ if ( dlg->exec() == KDialog::Rejected ) {
+ delete item;
}
+ delete dlg;
}
void KOEditorAttachments::slotAddData()
{
KURL uri = KFileDialog::getOpenFileName( TQString(), TQString(), this, i18n("Add Attachment") );
if ( !uri.isEmpty() ) {
- addAttachment( uri, TQString::null, false );
+ TQString label = uri.fileName();
+ if ( label.isEmpty() ) {
+ label = uri.prettyURL();
+ }
+ addUriAttachment( uri.url(), TQString::null, label, true );
}
}
void KOEditorAttachments::slotEdit()
{
- TQIconViewItem *item = mAttachments->currentItem();
- AttachmentListItem *attitem = static_cast<AttachmentListItem*>(item);
- if ( !attitem || !attitem->attachment() ) return;
-
- KCal::Attachment *att = attitem->attachment();
- if ( att->isUri() ) {
- KURL uri = KPimURLRequesterDlg::getURL( att->uri(), i18n(
- "URL (e.g. a web page) or file to be attached (only "
- "the link will be attached, not the file itself):"), this,
- i18n("Edit Attachment") );
-
- if ( !uri.isEmpty() )
- attitem->setUri( uri.url() );
- } else {
- KURL uri = KPimURLRequesterDlg::getURL( TQString::null, i18n(
- "File to be attached:"), this, i18n("Add Attachment") );
- if ( !uri.isEmpty() ) {
- TQString tmpFile;
- if ( KIO::NetAccess::download( uri, tmpFile, this ) ) {
- TQFile f( tmpFile );
- if ( !f.open( IO_ReadOnly ) )
- return;
- TQByteArray data = f.readAll();
- f.close();
- attitem->setData( KCodecs::base64Encode( data ) );
- attitem->setMimeType( KIO::NetAccess::mimetype( uri, this ) );
- TQString label = uri.fileName();
- if ( label.isEmpty() )
- label = uri.prettyURL();
- attitem->setLabel( label );
- KIO::NetAccess::removeTempFile( tmpFile );
+ for ( TQIconViewItem *item = mAttachments->firstItem(); item; item = item->nextItem() ) {
+ if ( item->isSelected() ) {
+ AttachmentListItem *attitem = static_cast<AttachmentListItem*>( item );
+ if ( !attitem || !attitem->attachment() ) {
+ return;
}
+
+ AttachmentEditDialog *dialog = new AttachmentEditDialog( attitem, mAttachments );
+ dialog->mInline->setEnabled( false );
+ dialog->setModal( false );
+ connect( dialog, TQT_SIGNAL(hidden()), dialog, TQT_SLOT(delayedDestruct()) );
+ dialog->show();
}
}
}
void KOEditorAttachments::slotRemove()
{
- TQValueList<TQIconViewItem*> selected;
- for ( TQIconViewItem *it = mAttachments->firstItem( ); it; it = it->nextItem( ) ) {
- if ( !it->isSelected() ) continue;
- selected << it;
- }
- if ( selected.isEmpty() || KMessageBox::warningContinueCancel(this,
- selected.count() == 1?i18n("This item will be permanently deleted."):
- i18n("The selected items will be permanently deleted."),
- i18n("KOrganizer Confirmation"),KStdGuiItem::del()) != KMessageBox::Continue )
- return;
+ TQValueList<TQIconViewItem*> selected;
+ TQStringList labels;
+ for ( TQIconViewItem *it = mAttachments->firstItem( ); it; it = it->nextItem( ) ) {
+ if ( !it->isSelected() ) continue;
+ selected << it;
+
+ AttachmentListItem *attitem = static_cast<AttachmentListItem*>(it);
+ KCal::Attachment *att = attitem->attachment();
+ labels << att->label();
+ }
- for ( TQValueList<TQIconViewItem*>::iterator it( selected.begin() ), end( selected.end() ); it != end ; ++it ) {
- delete *it;
+ if ( selected.isEmpty() ) {
+ return;
+ }
+
+ TQString labelsStr = labels.join( "<br>" );
+
+ if ( KMessageBox::questionYesNo(
+ this,
+ i18n( "<qt>Do you really want to remove these attachments?<p>%1</qt>" ).arg( labelsStr ),
+ i18n( "Remove Attachment?" ),
+ KStdGuiItem::yes(), KStdGuiItem::no(),
+ "calendarRemoveAttachments" ) != KMessageBox::Yes ) {
+ return;
+ }
+
+ for ( TQValueList<TQIconViewItem*>::iterator it( selected.begin() ), end( selected.end() );
+ it != end ; ++it ) {
+ if ( (*it)->nextItem() ) {
+ (*it)->nextItem()->setSelected( true );
+ } else if ( (*it)->prevItem() ) {
+ (*it)->prevItem()->setSelected( true );
}
+ delete *it;
+ }
+ mAttachments->slotUpdate();
}
void KOEditorAttachments::slotShow()
@@ -393,40 +746,98 @@ void KOEditorAttachments::slotShow()
}
}
+void KOEditorAttachments::slotSaveAs()
+{
+ for ( TQIconViewItem *it = mAttachments->firstItem(); it; it = it->nextItem() ) {
+ if ( !it->isSelected() )
+ continue;
+ saveAttachment( it );
+ }
+}
+
void KOEditorAttachments::setDefaults()
{
mAttachments->clear();
}
-void KOEditorAttachments::addAttachment( const KURL &uri,
- const TQString &mimeType, bool asUri )
+TQString KOEditorAttachments::randomString(int length) const
{
- AttachmentListItem *item = new AttachmentListItem( 0, mAttachments );
- if ( asUri ) {
- item->setUri( uri.url() );
- if ( !mimeType.isEmpty() ) item->setMimeType( mimeType );
+ if (length <=0 ) return TQString();
+
+ TQString str; str.setLength( length );
+ int i = 0;
+ while (length--)
+ {
+ int r=random() % 62;
+ r+=48;
+ if (r>57) r+=7;
+ if (r>90) r+=6;
+ str[i++] = char(r);
+ // so what if I work backwards?
+ }
+ return str;
+}
+
+void KOEditorAttachments::addUriAttachment( const TQString &uri,
+ const TQString &mimeType,
+ const TQString &label,
+ bool inLine )
+{
+ if ( !inLine ) {
+ AttachmentListItem *item = new AttachmentListItem( 0, mAttachments );
+ item->setUri( uri );
+ item->setLabel( label );
+ if ( mimeType.isEmpty() ) {
+ if ( uri.startsWith( KDEPIMPROTOCOL_CONTACT ) ) {
+ item->setMimeType( "text/directory" );
+ } else if ( uri.startsWith( KDEPIMPROTOCOL_EMAIL ) ) {
+ item->setMimeType( "message/rfc822" );
+ } else if ( uri.startsWith( KDEPIMPROTOCOL_INCIDENCE ) ) {
+ item->setMimeType( "text/calendar" );
+ } else if ( uri.startsWith( KDEPIMPROTOCOL_NEWSARTICLE ) ) {
+ item->setMimeType( "message/news" );
+ } else {
+ item->setMimeType( KMimeType::findByURL( uri )->name() );
+ }
+ }
} else {
TQString tmpFile;
if ( KIO::NetAccess::download( uri, tmpFile, this ) ) {
TQFile f( tmpFile );
- if ( !f.open( IO_ReadOnly ) )
+ if ( !f.open( IO_ReadOnly ) ) {
return;
- TQByteArray data = f.readAll();
+ }
+ const TQByteArray data = f.readAll();
f.close();
- item->setData( KCodecs::base64Encode( data ) );
- if ( !mimeType.isEmpty() )
- item->setMimeType( mimeType );
- else
- item->setMimeType( KIO::NetAccess::mimetype( uri, this ) );
- TQString label = uri.fileName();
- if ( label.isEmpty() )
- label = uri.prettyURL();
- item->setLabel( label );
- KIO::NetAccess::removeTempFile( tmpFile );
+ addDataAttachment( data, mimeType, label );
}
+ KIO::NetAccess::removeTempFile( tmpFile );
}
}
+void KOEditorAttachments::addDataAttachment( const TQByteArray &data,
+ const TQString &mimeType,
+ const TQString &label )
+{
+ AttachmentListItem *item = new AttachmentListItem( 0, mAttachments );
+
+ TQString nlabel = label;
+ if ( mimeType == "message/rfc822" ) {
+ // mail message. try to set the label from the mail Subject:
+ KMime::Message msg;
+ msg.setContent( data.data() );
+ msg.parse();
+ nlabel = msg.subject()->asUnicodeString();
+ }
+
+ item->setData( data );
+ item->setLabel( nlabel );
+ if ( mimeType.isEmpty() ) {
+ item->setMimeType( KMimeType::findByContent( data )->name() );
+ } else {
+ item->setMimeType( mimeType );
+ }
+}
void KOEditorAttachments::addAttachment( KCal::Attachment *attachment )
{
@@ -463,7 +874,7 @@ void KOEditorAttachments::writeIncidence( KCal::Incidence *i )
void KOEditorAttachments::slotCopy()
{
- TQApplication::clipboard()->setData( mAttachments->dragObject(), QClipboard::Clipboard );
+ TQApplication::clipboard()->setData( mAttachments->mimeData(), QClipboard::Clipboard );
}
void KOEditorAttachments::slotCut()
@@ -492,9 +903,21 @@ void KOEditorAttachments::selectionChanged()
void KOEditorAttachments::contextMenu(TQIconViewItem * item, const TQPoint & pos)
{
const bool enable = item != 0;
+
+ int numSelected = 0;
+ for ( TQIconViewItem *item = mAttachments->firstItem(); item; item = item->nextItem() ) {
+ if ( item->isSelected() ) {
+ numSelected++;
+ }
+ }
+
mOpenAction->setEnabled( enable );
- mCopyAction->setEnabled( enable );
- mCutAction->setEnabled( enable );
+ //TODO: support saving multiple attachments into a directory
+ mSaveAsAction->setEnabled( enable && numSelected == 1 );
+ mCopyAction->setEnabled( enable && numSelected == 1 );
+ mCutAction->setEnabled( enable && numSelected == 1 );
+ mDeleteAction->setEnabled( enable );
+ mEditAction->setEnabled( enable );
mContextMenu->exec( pos );
}
diff --git a/korganizer/koeditorattachments.h b/korganizer/koeditorattachments.h
index 09b2c48ea..dfcdb2b5f 100644
--- a/korganizer/koeditorattachments.h
+++ b/korganizer/koeditorattachments.h
@@ -26,19 +26,56 @@
#define KOEDITORATTACHMENTS_H
#include <tqwidget.h>
+#include <tqmap.h>
+#include <kdialogbase.h>
+#include <kmimetype.h>
#include <kurl.h>
+#include <kiconview.h>
+
+#include <set>
+
+class AttachmentListItem;
+class AttachmentIconView;
namespace KCal {
class Incidence;
class Attachment;
}
+class TQCheckBox;
class TQIconViewItem;
-class AttachmentIconView;
+class TQLabel;
class TQMimeSource;
class TQPushButton;
class TQPopupMenu;
+
class KAction;
+class KLineEdit;
+class KURLRequester;
+class KTempDir;
+
+class AttachmentEditDialog : public KDialogBase
+{
+ Q_OBJECT
+ public:
+ AttachmentEditDialog( AttachmentListItem *item, TQWidget *parent=0 );
+
+ void accept();
+
+ protected slots:
+ void urlSelected( const TQString &url );
+ void urlChanged( const TQString & url );
+ virtual void slotApply();
+
+ private:
+ friend class KOEditorAttachments;
+ KMimeType::Ptr mMimeType;
+ AttachmentListItem *mItem;
+ TQLabel *mTypeLabel, *mIcon;
+ TQCheckBox *mInline;
+ KLineEdit *mLabelEdit;
+ KURLRequester *mURLRequester;
+};
class KOEditorAttachments : public QWidget
{
@@ -48,9 +85,14 @@ class KOEditorAttachments : public QWidget
const char *name = 0 );
~KOEditorAttachments();
- void addAttachment( const KURL &uri,
- const TQString &mimeType = TQString::null, bool asUri = true );
+ void addUriAttachment( const TQString &uri,
+ const TQString &mimeType = TQString(),
+ const TQString &label = TQString(),
+ bool inLine = false );
void addAttachment( KCal::Attachment *attachment );
+ void addDataAttachment( const TQByteArray &data,
+ const TQString &mimeType = TQString(),
+ const TQString &label = TQString() );
/** Set widgets to default values */
void setDefaults();
@@ -63,29 +105,75 @@ class KOEditorAttachments : public QWidget
protected slots:
void showAttachment( TQIconViewItem *item );
+ void saveAttachment( TQIconViewItem *item );
void slotAdd();
void slotAddData();
void slotEdit();
void slotRemove();
void slotShow();
+ void slotSaveAs();
void dragEnterEvent( TQDragEnterEvent *event );
+ void dragMoveEvent( TQDragMoveEvent *event );
void dropEvent( TQDropEvent *event );
void slotCopy();
void slotCut();
void slotPaste();
void selectionChanged();
void contextMenu( TQIconViewItem* item, const TQPoint &pos );
+
signals:
void openURL( const KURL &url );
+ protected:
+ enum {
+ DRAG_COPY = 0,
+ DRAG_LINK = 1,
+ DRAG_CANCEL = 2
+ };
+
private:
friend class AttachmentIconView;
void handlePasteOrDrop( TQMimeSource* source );
-
+ TQString randomString( int length ) const;
AttachmentIconView *mAttachments;
TQPushButton *mRemoveBtn;
TQPopupMenu *mContextMenu, *mAddMenu;
- KAction *mOpenAction, *mCopyAction, *mCutAction;
+ KAction *mOpenAction;
+ KAction *mSaveAsAction;
+ KAction *mCopyAction;
+ KAction *mCutAction;
+ KAction *mDeleteAction;
+ KAction *mEditAction;
+};
+
+
+class AttachmentIconView : public KIconView
+{
+ Q_OBJECT
+
+ friend class KOEditorAttachments;
+ public:
+ AttachmentIconView( KOEditorAttachments* parent=0 );
+ KURL tempFileForAttachment( KCal::Attachment *attachment );
+ TQDragObject *mimeData();
+ ~AttachmentIconView();
+
+ protected:
+ TQDragObject * dragObject();
+
+ void dragMoveEvent( TQDragMoveEvent *event );
+ void contentsDragMoveEvent( TQDragMoveEvent *event );
+ void contentsDragEnterEvent( TQDragEnterEvent *event );
+ void dragEnterEvent( TQDragEnterEvent *event );
+
+ protected slots:
+
+ void handleDrop( TQDropEvent *event, const TQValueList<TQIconDragItem> & list );
+
+ private:
+ std::set<KTempDir*> mTempDirs;
+ TQMap<KCal::Attachment *, KURL> mTempFiles;
+ KOEditorAttachments* mParent;
};
#endif
diff --git a/korganizer/koeditordetails.cpp b/korganizer/koeditordetails.cpp
index 0b8c6159f..a882363da 100644
--- a/korganizer/koeditordetails.cpp
+++ b/korganizer/koeditordetails.cpp
@@ -72,7 +72,8 @@
template <>
CustomListViewItem<KCal::Attendee *>::~CustomListViewItem()
{
- delete mData;
+ // do not delete mData here
+// delete mData;
}
template <>
@@ -152,18 +153,15 @@ void KOAttendeeListView::dropEvent( TQDropEvent *e )
{
#ifndef KORG_NODND
TQString text;
- TQString vcards;
#ifndef KORG_NOKABC
- if ( KVCardDrag::decode( e, vcards ) ) {
- KABC::VCardConverter converter;
-
- KABC::Addressee::List list = converter.parseVCards( vcards );
+ KABC::Addressee::List list;
+ if ( KVCardDrag::decode( e, list ) ) {
KABC::Addressee::List::Iterator it;
for ( it = list.begin(); it != list.end(); ++it ) {
TQString em( (*it).fullEmail() );
- if (em.isEmpty()) {
- em=(*it).realName();
+ if ( em.isEmpty() ) {
+ em = (*it).realName();
}
addAttendee( em );
}
@@ -240,13 +238,22 @@ void KOEditorDetails::removeAttendee()
static_cast<AttendeeListItem *>( mListView->selectedItem() );
if ( !aItem ) return;
- Attendee *delA = new Attendee( aItem->data()->name(), aItem->data()->email(),
- aItem->data()->RSVP(), aItem->data()->status(),
- aItem->data()->role(), aItem->data()->uid() );
- mdelAttendees.append( delA );
+ AttendeeListItem *nextSelectedItem = static_cast<AttendeeListItem*>( aItem->nextSibling() );
+ if( mListView->childCount() == 1 )
+ nextSelectedItem = 0;
+ if( mListView->childCount() > 1 && aItem == mListView->lastItem() )
+ nextSelectedItem = static_cast<AttendeeListItem*>( mListView->firstChild() );
+ Attendee *attendee = aItem->data();
+ Attendee *delA = new Attendee( attendee->name(), attendee->email(),
+ attendee->RSVP(), attendee->status(),
+ attendee->role(), attendee->uid() );
+ mdelAttendees.append( delA );
delete aItem;
+ if( nextSelectedItem ) {
+ mListView->setSelected( nextSelectedItem, true );
+ }
updateAttendeeInput();
emit updateAttendeeSummary( mListView->childCount() );
}
@@ -257,12 +264,25 @@ void KOEditorDetails::insertAttendee( Attendee *a, bool goodEmailAddress )
Q_UNUSED( goodEmailAddress );
// lastItem() is O(n), but for n very small that should be fine
- AttendeeListItem *item = new AttendeeListItem( a, mListView,
- static_cast<KListViewItem*>( mListView->lastItem() ) );
+ AttendeeListItem *item = new AttendeeListItem(
+ a, mListView, static_cast<KListViewItem*>( mListView->lastItem() ) );
mListView->setSelected( item, true );
emit updateAttendeeSummary( mListView->childCount() );
}
+void KOEditorDetails::removeAttendee( Attendee *attendee )
+{
+ TQListViewItem *item;
+ for ( item = mListView->firstChild(); item; item = item->nextSibling() ) {
+ AttendeeListItem *anItem = static_cast<AttendeeListItem *>( item );
+ Attendee *att = anItem->data();
+ if ( att == attendee ) {
+ delete anItem;
+ break;
+ }
+ }
+}
+
void KOEditorDetails::setDefaults()
{
mRsvpButton->setChecked( true );
@@ -350,9 +370,34 @@ void KOEditorDetails::updateCurrentItem()
item->updateItem();
}
-void KOEditorDetails::slotInsertAttendee(Attendee * a)
+void KOEditorDetails::slotInsertAttendee( Attendee *a )
{
insertAttendee( a );
+ mnewAttendees.append( a );
+}
+
+void KOEditorDetails::setSelected( int index )
+{
+ int count = 0;
+ for ( TQListViewItemIterator it( mListView ); it.current(); ++it ) {
+ if ( count == index ) {
+ mListView->setSelected( *it, true );
+ return;
+ }
+ count++;
+ }
+}
+
+int KOEditorDetails::selectedIndex()
+{
+ int index = 0;
+ for ( TQListViewItemIterator it( mListView ); it.current(); ++it ) {
+ if ( mListView->isSelected( *it ) ) {
+ break;
+ }
+ index++;
+ }
+ return index;
}
void KOEditorDetails::changeStatusForMe(Attendee::PartStat status)
@@ -369,4 +414,16 @@ void KOEditorDetails::changeStatusForMe(Attendee::PartStat status)
}
}
+TQListViewItem* KOEditorDetails::hasExampleAttendee() const
+{
+ for ( TQListViewItemIterator it( mListView ); it.current(); ++it ) {
+ AttendeeListItem *item = static_cast<AttendeeListItem*>( it.current() );
+ Attendee *attendee = item->data();
+ Q_ASSERT( attendee );
+ if ( isExampleAttendee( attendee ) )
+ return item;
+ }
+ return 0;
+}
+
#include "koeditordetails.moc"
diff --git a/korganizer/koeditordetails.h b/korganizer/koeditordetails.h
index 92a271644..890841f6e 100644
--- a/korganizer/koeditordetails.h
+++ b/korganizer/koeditordetails.h
@@ -95,16 +95,21 @@ class KOEditorDetails : public KOAttendeeEditor
/** Returns whether at least one attendee was added */
bool hasAttendees();
- void insertAttendee( Attendee*, bool goodEmailAddress = true );
+ void insertAttendee( Attendee *a, bool goodEmailAddress = true );
+ void removeAttendee( Attendee *a );
protected slots:
void removeAttendee();
void slotInsertAttendee( Attendee *a );
protected:
+ void setSelected ( int index );
+ int selectedIndex();
void changeStatusForMe( Attendee::PartStat status );
KCal::Attendee* currentAttendee() const;
+ /* reimpl */
+ TQListViewItem* hasExampleAttendee() const;
void updateCurrentItem();
private:
diff --git a/korganizer/koeditorfreebusy.cpp b/korganizer/koeditorfreebusy.cpp
index 19691e807..c56ff033f 100644
--- a/korganizer/koeditorfreebusy.cpp
+++ b/korganizer/koeditorfreebusy.cpp
@@ -130,7 +130,8 @@ class FreeBusyItem : public KDGanttViewTaskItem
void FreeBusyItem::updateItem()
{
- setListViewText( 0, mAttendee->fullName() );
+ TQString text = mAttendee->name() + " <" + mAttendee->email() + '>';
+ setListViewText( 0, text );
switch ( mAttendee->status() ) {
case Attendee::Accepted:
setPixmap( 0, KOGlobals::self()->smallIcon( "ok" ) );
@@ -166,17 +167,34 @@ void FreeBusyItem::setFreeBusyPeriods( FreeBusy* fb )
TQValueList<KCal::Period> busyPeriods = fb->busyPeriods();
for( TQValueList<KCal::Period>::Iterator it = busyPeriods.begin();
it != busyPeriods.end(); ++it ) {
- KDGanttViewTaskItem* newSubItem = new KDGanttViewTaskItem( this );
- newSubItem->setStartTime( (*it).start() );
- newSubItem->setEndTime( (*it).end() );
+ Period per = *it;
+
+ KDGanttViewTaskItem *newSubItem = new KDGanttViewTaskItem( this );
+ newSubItem->setStartTime( per.start() );
+ newSubItem->setEndTime( per.end() );
newSubItem->setColors( Qt::red, Qt::red, Qt::red );
- TQString toolTip;
- if ( !(*it).summary().isEmpty() )
- toolTip += "<b>" + (*it).summary() + "</b><br/>";
- if ( !(*it).location().isEmpty() )
- toolTip += i18n( "Location: %1" ).arg( (*it).location() );
- if ( !toolTip.isEmpty() )
- newSubItem->setTooltipText( toolTip );
+
+ TQString toolTip = "<qt>";
+ toolTip += "<b>" + i18n( "Freebusy Period" ) + "</b>";
+ toolTip += "<br>----------------------<br>";
+ if ( !per.summary().isEmpty() ) {
+ toolTip += "<i>" + i18n( "Summary:" ) + "</i>" + "&nbsp;";
+ toolTip += per.summary();
+ toolTip += "<br>";
+ }
+ if ( !per.location().isEmpty() ) {
+ toolTip += "<i>" + i18n( "Location:" ) + "</i>" + "&nbsp;";
+ toolTip += per.location();
+ toolTip += "<br>";
+ }
+ toolTip += "<i>" + i18n( "Start:" ) + "</i>" + "&nbsp;";
+ toolTip += KGlobal::locale()->formatDateTime( per.start() );
+ toolTip += "<br>";
+ toolTip += "<i>" + i18n( "End:" ) + "</i>" + "&nbsp;";
+ toolTip += KGlobal::locale()->formatDateTime( per.end() );
+ toolTip += "<br>";
+ toolTip += "</qt>";
+ newSubItem->setTooltipText( toolTip );
}
setFreeBusy( fb );
setShowNoInformation( false );
@@ -529,12 +547,18 @@ void KOEditorFreeBusy::slotPickDate()
i18n( "The meeting already has suitable start/end times." ), TQString::null,
"MeetingTimeOKFreeBusy" );
} else {
- emit dateTimesChanged( start, end );
- slotUpdateGanttView( start, end );
- KMessageBox::information( this,
- i18n( "The meeting has been moved to\nStart: %1\nEnd: %2." )
- .arg( start.toString() ).arg( end.toString() ), TQString::null,
- "MeetingMovedFreeBusy" );
+ if ( KMessageBox::questionYesNo(
+ this,
+ i18n( "<qt>The next available time slot for the meeting is:<br>"
+ "Start: %1<br>End: %2<br>"
+ "Would you like to move the meeting to this time slot?</qt>" ).
+ arg( start.toString(), end.toString() ),
+ TQString::null,
+ KStdGuiItem::yes(), KStdGuiItem::no(),
+ "MeetingMovedFreeBusy" ) == KMessageBox::Yes ) {
+ emit dateTimesChanged( start, end );
+ slotUpdateGanttView( start, end );
+ }
}
} else
KMessageBox::sorry( this, i18n( "No suitable date found." ) );
@@ -664,6 +688,7 @@ void KOEditorFreeBusy::updateStatusSummary()
case Attendee::Delegated:
case Attendee::Completed:
case Attendee::InProcess:
+ case Attendee::None:
/* just to shut up the compiler */
break;
}
@@ -803,6 +828,12 @@ void KOEditorFreeBusy::removeAttendee()
if ( !item )
return;
+ FreeBusyItem *nextSelectedItem = static_cast<FreeBusyItem*>( item->nextSibling() );
+ if( mGanttView->childCount() == 1 )
+ nextSelectedItem = 0;
+ if( mGanttView->childCount() > 1 && item == mGanttView->lastItem() )
+ nextSelectedItem = static_cast<FreeBusyItem*>( mGanttView->firstChild() );
+
Attendee *delA = new Attendee( item->attendee()->name(), item->attendee()->email(),
item->attendee()->RSVP(), item->attendee()->status(),
item->attendee()->role(), item->attendee()->uid() );
@@ -810,6 +841,8 @@ void KOEditorFreeBusy::removeAttendee()
delete item;
updateStatusSummary();
+ if( nextSelectedItem )
+ mGanttView->setSelected( nextSelectedItem, true );
updateAttendeeInput();
emit updateAttendeeSummary( mGanttView->childCount() );
}
@@ -823,6 +856,32 @@ void KOEditorFreeBusy::clearSelection() const
item->repaint();
}
+void KOEditorFreeBusy::setSelected( int index )
+{
+ int count = 0;
+ for( KDGanttViewItem *it = mGanttView->firstChild(); it; it = it->nextSibling() ) {
+ FreeBusyItem *item = static_cast<FreeBusyItem*>( it );
+ if ( count == index ) {
+ mGanttView->setSelected( item, true );
+ return;
+ }
+ count++;
+ }
+}
+
+int KOEditorFreeBusy::selectedIndex()
+{
+ int index = 0;
+ for ( KDGanttViewItem *it = mGanttView->firstChild(); it; it = it->nextSibling() ) {
+ FreeBusyItem *item = static_cast<FreeBusyItem*>( it );
+ if ( item->isSelected() ) {
+ break;
+ }
+ index++;
+ }
+ return index;
+}
+
void KOEditorFreeBusy::changeStatusForMe(KCal::Attendee::PartStat status)
{
const TQStringList myEmails = KOPrefs::instance()->allEmails();
@@ -911,6 +970,7 @@ void KOEditorFreeBusy::slotOrganizerChanged(const TQString & newOrganizer)
if (!newOrganizerAttendee) {
Attendee *a = new Attendee( name, email, true );
insertAttendee( a, false );
+ mnewAttendees.append( a );
updateAttendee();
}
}
@@ -928,4 +988,16 @@ bool KOEditorFreeBusy::eventFilter( TQObject *watched, TQEvent *event )
}
}
+TQListViewItem* KOEditorFreeBusy::hasExampleAttendee() const
+{
+ for ( FreeBusyItem *item = static_cast<FreeBusyItem *>( mGanttView->firstChild() ); item;
+ item = static_cast<FreeBusyItem*>( item->nextSibling() ) ) {
+ Attendee *attendee = item->attendee();
+ Q_ASSERT( attendee );
+ if ( isExampleAttendee( attendee ) )
+ return item;
+ }
+ return 0;
+}
+
#include "koeditorfreebusy.moc"
diff --git a/korganizer/koeditorfreebusy.h b/korganizer/koeditorfreebusy.h
index 4e561cfa2..72ce6e7d4 100644
--- a/korganizer/koeditorfreebusy.h
+++ b/korganizer/koeditorfreebusy.h
@@ -93,8 +93,12 @@ class KOEditorFreeBusy : public KOAttendeeEditor
protected:
void timerEvent( TQTimerEvent* );
KCal::Attendee* currentAttendee() const;
+ /* reimpl */
+ TQListViewItem* hasExampleAttendee() const;
void updateCurrentItem();
void clearSelection() const;
+ void setSelected ( int index );
+ int selectedIndex();
void changeStatusForMe( KCal::Attendee::PartStat status );
virtual bool eventFilter( TQObject *watched, TQEvent *event );
diff --git a/korganizer/koeditorgeneral.cpp b/korganizer/koeditorgeneral.cpp
index 816806e3a..e1d8db245 100644
--- a/korganizer/koeditorgeneral.cpp
+++ b/korganizer/koeditorgeneral.cpp
@@ -30,7 +30,6 @@
#include <tqhbox.h>
#include <tqbuttongroup.h>
#include <tqvgroupbox.h>
-#include <tqwidgetstack.h>
#include <tqdatetime.h>
#include <tqlineedit.h>
#include <tqlabel.h>
@@ -54,6 +53,7 @@
#include <libkcal/todo.h>
#include <libkcal/event.h>
+#include <libkcal/incidenceformatter.h>
#include <libkcal/resourcecached.h>
#include <libkdepim/kdateedit.h>
@@ -68,9 +68,10 @@
#include "koeditorgeneral.moc"
#include "kohelper.h"
-KOEditorGeneral::KOEditorGeneral(TQObject* parent, const char* name) :
+KOEditorGeneral::KOEditorGeneral( TQObject *parent, const char* name) :
TQObject( parent, name ), mAttachments(0)
{
+ mType = "Event";
ResourceCached::setEditorWindowOpen(true);
mAlarmList.setAutoDelete( true );
}
@@ -103,11 +104,6 @@ void KOEditorGeneral::initHeader( TQWidget *parent,TQBoxLayout *topLayout)
headerLayout->setSpacing( topLayout->spacing() );
topLayout->addLayout( headerLayout );
-#if 0
- mOwnerLabel = new TQLabel(i18n("Owner:"),parent);
- headerLayout->addMultiCellWidget(mOwnerLabel,0,0,0,1);
-#endif
-
TQString whatsThis = i18n("Sets the Title of this event or to-do.");
TQLabel *summaryLabel = new TQLabel( i18n("T&itle:"), parent );
TQWhatsThis::add( summaryLabel, whatsThis );
@@ -198,52 +194,63 @@ void KOEditorGeneral::initDescription(TQWidget *parent,TQBoxLayout *topLayout)
topLayout->addWidget(mDescriptionEdit, 4);
}
-void KOEditorGeneral::initAlarm(TQWidget *parent,TQBoxLayout *topLayout)
+void KOEditorGeneral::initAlarm( TQWidget *parent, TQBoxLayout *topLayout )
{
- TQBoxLayout *alarmLayout = new TQHBoxLayout(topLayout);
-
- mAlarmBell = new TQLabel(parent);
- mAlarmBell->setPixmap(KOGlobals::self()->smallIcon("bell"));
- alarmLayout->addWidget( mAlarmBell );
-
-
- mAlarmStack = new TQWidgetStack( parent );
- alarmLayout->addWidget( mAlarmStack );
-
- mAlarmInfoLabel = new TQLabel( i18n("No reminders configured"), mAlarmStack );
- mAlarmStack->addWidget( mAlarmInfoLabel, AdvancedAlarmLabel );
-
- TQHBox *simpleAlarmBox = new TQHBox( mAlarmStack );
- mAlarmStack->addWidget( simpleAlarmBox, SimpleAlarmPage );
-
- mAlarmButton = new TQCheckBox(i18n("&Reminder:"), simpleAlarmBox );
- TQWhatsThis::add( mAlarmButton,
- i18n("Activates a reminder for this event or to-do.") );
-
- TQString whatsThis = i18n("Sets how long before the event occurs "
- "the reminder will be triggered.");
- mAlarmTimeEdit = new TQSpinBox( 0, 99999, 1, simpleAlarmBox, "alarmTimeEdit" );
+ TQBoxLayout *alarmLayout = new TQHBoxLayout( topLayout );
+
+ mAlarmButton = new TQCheckBox( parent );
+ TQWhatsThis::add( mAlarmButton, i18n( "Enable reminders for this event or to-do." ) );
+ TQToolTip::add( mAlarmButton, i18n( "Enable reminders" ) );
+ alarmLayout->addWidget( mAlarmButton );
+
+ mAlarmAdvancedButton = new TQPushButton( parent );
+ mAlarmAdvancedButton->setIconSet( KOGlobals::self()->smallIconSet( "bell", 16 ) );
+ TQWhatsThis::add( mAlarmAdvancedButton,
+ i18n( "Push this button to create an advanced set of reminders "
+ "for this event or to-do." ) );
+ TQToolTip::add( mAlarmAdvancedButton, i18n( "Set an advanced reminder" ) );
+ connect( mAlarmAdvancedButton, TQT_SIGNAL(clicked()), TQT_SLOT(editAlarms()) );
+ alarmLayout->addWidget( mAlarmAdvancedButton );
+
+ mSimpleAlarmBox = new TQHBox( parent );
+ alarmLayout->addWidget( mSimpleAlarmBox );
+
+ TQString whatsThis, toolTip;
+ if ( mType == "Event" ) {
+ whatsThis = i18n( "Set the time before the event starts when the reminder will be triggered." );
+ toolTip = i18n( "Set the start time trigger offset" );
+ } else {
+ whatsThis = i18n( "Set the time before the to-do is due when the reminder will be triggered." );
+ toolTip = i18n( "Set the due time trigger offset" );
+ }
+ mAlarmTimeEdit = new TQSpinBox( 0, 99999, 1, mSimpleAlarmBox, "alarmTimeEdit" );
mAlarmTimeEdit->setValue( 0 );
TQWhatsThis::add( mAlarmTimeEdit, whatsThis );
+ TQToolTip::add( mAlarmTimeEdit, toolTip );
- mAlarmIncrCombo = new TQComboBox( false, simpleAlarmBox );
- TQWhatsThis::add( mAlarmIncrCombo, whatsThis );
+ mAlarmIncrCombo = new TQComboBox( false, mSimpleAlarmBox );
mAlarmIncrCombo->insertItem( i18n("minute(s)") );
mAlarmIncrCombo->insertItem( i18n("hour(s)") );
mAlarmIncrCombo->insertItem( i18n("day(s)") );
-// mAlarmIncrCombo->setMinimumHeight(20);
- connect(mAlarmButton, TQT_SIGNAL(toggled(bool)), mAlarmTimeEdit, TQT_SLOT(setEnabled(bool)));
- connect(mAlarmButton, TQT_SIGNAL(toggled(bool)), mAlarmIncrCombo, TQT_SLOT(setEnabled(bool)));
- mAlarmTimeEdit->setEnabled( false );
- mAlarmIncrCombo->setEnabled( false );
+ TQWhatsThis::add( mAlarmIncrCombo, whatsThis );
+ TQToolTip::add( mAlarmIncrCombo, toolTip );
- mAlarmEditButton = new TQPushButton( i18n("Advanced"), parent );
- mAlarmEditButton->setEnabled( false );
- alarmLayout->addWidget( mAlarmEditButton );
- connect( mAlarmButton, TQT_SIGNAL(toggled(bool)), mAlarmEditButton, TQT_SLOT(setEnabled( bool)));
- connect( mAlarmEditButton, TQT_SIGNAL( clicked() ),
- TQT_SLOT( editAlarms() ) );
+ mAlarmInfoLabel = new TQLabel( parent );
+ if ( mType == "Event" ) {
+ mAlarmInfoLabel->setText( i18n( "before the start" ) );
+ } else {
+ mAlarmInfoLabel->setText( i18n( "before the due time" ) );
+ }
+ alarmLayout->addWidget( mAlarmInfoLabel );
+ mAlarmAdvancedButton->setEnabled( false );
+ mAlarmTimeEdit->setEnabled( false );
+ mAlarmIncrCombo->setEnabled( false );
+ mAlarmInfoLabel->setEnabled( false );
+ connect( mAlarmButton, TQT_SIGNAL(toggled(bool)), mAlarmAdvancedButton, TQT_SLOT(setEnabled(bool)) );
+ connect( mAlarmButton, TQT_SIGNAL(toggled(bool)), mAlarmTimeEdit, TQT_SLOT(setEnabled(bool)) );
+ connect( mAlarmButton, TQT_SIGNAL(toggled(bool)), mAlarmIncrCombo, TQT_SLOT(setEnabled(bool)) );
+ connect( mAlarmButton, TQT_SIGNAL(toggled(bool)), mAlarmInfoLabel, TQT_SLOT(setEnabled(bool)) );
}
void KOEditorGeneral::initAttachments(TQWidget *parent,TQBoxLayout *topLayout)
@@ -254,6 +261,12 @@ void KOEditorGeneral::initAttachments(TQWidget *parent,TQBoxLayout *topLayout)
topLayout->addWidget( mAttachments, 1 );
}
+void KOEditorGeneral::setType( const TQCString &type )
+{
+ // must be "Event", "Todo", "Journal", etc.
+ mType = type;
+}
+
void KOEditorGeneral::addAttachments( const TQStringList &attachments,
const TQStringList &mimeTypes,
bool inlineAttachments )
@@ -261,10 +274,13 @@ void KOEditorGeneral::addAttachments( const TQStringList &attachments,
TQStringList::ConstIterator it;
uint i = 0;
for ( it = attachments.begin(); it != attachments.end(); ++it, ++i ) {
- TQString mimeType;
- if ( mimeTypes.count() > i )
- mimeType = mimeTypes[ i ];
- mAttachments->addAttachment( *it, mimeType, !inlineAttachments );
+ if ( !(*it).isEmpty() ) {
+ TQString mimeType;
+ if ( mimeTypes.count() > i ) {
+ mimeType = mimeTypes[ i ];
+ }
+ mAttachments->addUriAttachment( *it, mimeType, TQString(), inlineAttachments );
+ }
}
}
@@ -286,31 +302,48 @@ void KOEditorGeneral::selectCategories()
void KOEditorGeneral::editAlarms()
{
- if ( mAlarmStack->id( mAlarmStack->visibleWidget() ) == SimpleAlarmPage ) {
+ if ( mAlarmIsSimple ) {
mAlarmList.clear();
- Alarm *al = alarmFromSimplePage();
+ Alarm *al = alarmFromSimplePage( 0 );
if ( al ) {
mAlarmList.append( al );
}
}
- KOEditorAlarms *dlg = new KOEditorAlarms( &mAlarmList, mAlarmEditButton );
+ KOEditorAlarms *dlg = new KOEditorAlarms( mType, &mAlarmList, mAlarmAdvancedButton );
if ( dlg->exec() != KDialogBase::Cancel ) {
- updateAlarmWidgets();
+ if ( mType == "Event" ) {
+ Event *e = new Event;
+ Alarm::List::ConstIterator it;
+ for( it = mAlarmList.begin(); it != mAlarmList.end(); ++it ) {
+ Alarm *a = (*it)->clone();
+ a->setParent( e );
+ e->addAlarm( a );
+ }
+ updateAlarmWidgets( e );
+ delete e;
+ } else {
+ Todo *t = new Todo;
+ Alarm::List::ConstIterator it;
+ for( it = mAlarmList.begin(); it != mAlarmList.end(); ++it ) {
+ Alarm *a = (*it)->clone();
+ a->setParent( t );
+ t->addAlarm( a );
+ }
+ updateAlarmWidgets( t );
+ delete t;
+ }
}
}
-
void KOEditorGeneral::enableAlarm( bool enable )
{
- mAlarmStack->setEnabled( enable );
- mAlarmEditButton->setEnabled( enable );
+ mAlarmAdvancedButton->setEnabled( enable );
}
-
void KOEditorGeneral::toggleAlarm( bool on )
{
- mAlarmButton->setChecked( on );
+ mAlarmButton->setChecked( on );
}
void KOEditorGeneral::setCategories( const TQStringList &categories )
@@ -321,65 +354,104 @@ void KOEditorGeneral::setCategories( const TQStringList &categories )
void KOEditorGeneral::setDefaults(bool /*allDay*/)
{
-#if 0
- mOwnerLabel->setText(i18n("Owner: ") + KOPrefs::instance()->fullName());
-#endif
-
mAlarmList.clear();
updateDefaultAlarmTime();
- updateAlarmWidgets();
+ updateAlarmWidgets( 0 );
- mSecrecyCombo->setCurrentItem(Incidence::SecrecyPublic);
+ mSecrecyCombo->setCurrentItem( Incidence::SecrecyPublic );
mAttachments->setDefaults();
}
void KOEditorGeneral::updateDefaultAlarmTime()
{
- // FIXME: Implement a KPrefsComboItem to solve this in a clean way.
-// FIXME: Use an int value for minutes instead of 5 hardcoded values
- int alarmTime;
- int a[] = { 1,5,10,15,30 };
- int index = KOPrefs::instance()->mAlarmTime;
- if (index < 0 || index > 4) {
- alarmTime = 0;
- } else {
- alarmTime = a[index];
+ int reminderTime = KOPrefs::instance()->mReminderTime;
+ int index = KOPrefs::instance()->mReminderTimeUnits;
+ if ( index < 0 || index > 2 ) {
+ index = 0;
}
- mAlarmTimeEdit->setValue(alarmTime);
+ mAlarmTimeEdit->setValue( reminderTime );
+ mAlarmIncrCombo->setCurrentItem( index );
}
-void KOEditorGeneral::updateAlarmWidgets()
+bool KOEditorGeneral::isSimpleAlarm( Alarm *alarm ) const
{
- if ( mAlarmList.isEmpty() ) {
- mAlarmStack->raiseWidget( SimpleAlarmPage );
- if (KOPrefs::instance()->mAlarmsEnabledByDefault == true) {
- mAlarmButton->setChecked( true );
+ // Check if its the trivial type of alarm, which can be
+ // configured with a simply spin box...
+
+ bool simple = false;
+ if ( alarm->type() == Alarm::Display && alarm->text().isEmpty() &&
+ alarm->repeatCount() == 0 && !alarm->hasTime() ) {
+ if ( mType == "Event" &&
+ alarm->hasStartOffset() && alarm->startOffset().asSeconds() <= 0 ) {
+ simple = true;
}
- else {
- mAlarmButton->setChecked( false );
+ if ( mType == "Todo" &&
+ alarm->hasEndOffset() && alarm->endOffset().asSeconds() <= 0 ) {
+ simple = true;
}
- mAlarmEditButton->setEnabled( false );
- } else if ( mAlarmList.count() > 1 ) {
- mAlarmStack->raiseWidget( AdvancedAlarmLabel );
- mAlarmInfoLabel->setText( i18n("1 advanced reminder configured",
- "%n advanced reminders configured",
- mAlarmList.count() ) );
- mAlarmEditButton->setEnabled( true );
- } else {
- Alarm *alarm = mAlarmList.first();
- // Check if its the trivial type of alarm, which can be
- // configured with a simply spin box...
+ }
+ return simple;
+}
- if ( alarm->type() == Alarm::Display && alarm->text().isEmpty()
- && alarm->repeatCount() == 0 && !alarm->hasTime()
- && alarm->hasStartOffset() && alarm->startOffset().asSeconds() < 0 ) {
- mAlarmStack->raiseWidget( SimpleAlarmPage );
- mAlarmButton->setChecked( true );
- int offset = alarm->startOffset().asSeconds();
+static TQString etc = i18n( "elipsis", "..." );
+void KOEditorGeneral::updateAlarmWidgets( Incidence *incidence )
+{
+ uint maxLen = 75; //TODO: compute from the font and dialog width
+
+ if ( incidence ) {
+ mAlarmButton->setChecked( incidence->isAlarmEnabled() );
+ }
+ if ( mAlarmList.isEmpty() ) {
+ mAlarmIsSimple = true;
+ mSimpleAlarmBox->show();
+ bool on;
+ if ( mType == "Event" ) {
+ on = KOPrefs::instance()->defaultEventReminders();
+ } else if ( mType == "Todo" ) {
+ on = KOPrefs::instance()->defaultTodoReminders();
+ } else {
+ on = false;
+ }
+ mAlarmButton->setChecked( on );
+ mAlarmAdvancedButton->setEnabled( on );
+ } else if ( mAlarmList.count() > 1 ) {
+ mAlarmIsSimple = false;
+ mAlarmAdvancedButton->setEnabled( true );
+ mSimpleAlarmBox->hide();
+ if ( incidence ) {
+ TQString remStr = IncidenceFormatter::reminderStringList( incidence ).join( ", " );
+ if ( remStr.length() > maxLen ) {
+ maxLen -= etc.length();
+ remStr = remStr.left( maxLen );
+ remStr += etc;
+ }
+ mAlarmInfoLabel->setText( i18n( "Triggers %1" ).arg( remStr ) );
+ }
+ } else { // alarm count is 1
+ Alarm *alarm = mAlarmList.first();
+ if ( isSimpleAlarm( alarm ) ) {
+ mAlarmIsSimple = true;
+ mSimpleAlarmBox->show();
+ int offset;
+ if ( mType == "Event" ) {
+ offset = alarm->startOffset().asSeconds();
+ mAlarmInfoLabel->setText( i18n( "before the start" ) );
+ }
+ if ( mType == "Todo" ) {
+ if ( alarm->hasStartOffset() ) {
+ offset = alarm->startOffset().asSeconds();
+ mAlarmInfoLabel->setText( i18n( "before the start" ) );
+ } else {
+ offset = alarm->endOffset().asSeconds();
+ mAlarmInfoLabel->setText( i18n( "before the due time" ) );
+ }
+ }
offset = offset / -60; // make minutes
int useoffset = offset;
- if (offset % (24*60) == 0) { // divides evenly into days?
+ if ( offset == 0 ) {
+ mAlarmIncrCombo->setCurrentItem( 0 ); // use minute units for 0 offset
+ } else if (offset % (24*60) == 0) { // divides evenly into days?
useoffset = offset / (24*60);
mAlarmIncrCombo->setCurrentItem(2);
} else if (offset % 60 == 0) { // divides evenly into hours?
@@ -388,97 +460,105 @@ void KOEditorGeneral::updateAlarmWidgets()
}
mAlarmTimeEdit->setValue( useoffset );
} else {
- mAlarmStack->raiseWidget( AdvancedAlarmLabel );
- mAlarmInfoLabel->setText( i18n("1 advanced reminder configured") );
- mAlarmEditButton->setEnabled( true );
+ mAlarmIsSimple = false;
+ mAlarmAdvancedButton->setEnabled( true );
+ mSimpleAlarmBox->hide();
+ if ( incidence ) {
+ TQString remStr = IncidenceFormatter::reminderStringList( incidence ).first();
+ mAlarmInfoLabel->setText( i18n( "Triggers %1" ).arg( remStr ) );
+ }
}
}
}
-void KOEditorGeneral::readIncidence(Incidence *event, Calendar *calendar)
+void KOEditorGeneral::readIncidence( Incidence *incidence, Calendar *calendar )
{
- mSummaryEdit->setText(event->summary());
- mLocationEdit->setText(event->location());
+ mSummaryEdit->setText( incidence->summary() );
+ mLocationEdit->setText( incidence->location() );
+ mDescriptionEdit->setText( incidence->description() );
- mDescriptionEdit->setText(event->description());
-
-#if 0
- // organizer information
- mOwnerLabel->setText(i18n("Owner: ") + event->organizer().fullName() );
-#endif
-
- mSecrecyCombo->setCurrentItem(event->secrecy());
+ mSecrecyCombo->setCurrentItem( incidence->secrecy() );
// set up alarm stuff
mAlarmList.clear();
Alarm::List::ConstIterator it;
- Alarm::List alarms = event->alarms();
+ Alarm::List alarms = incidence->alarms();
for( it = alarms.begin(); it != alarms.end(); ++it ) {
Alarm *al = new Alarm( *(*it) );
al->setParent( 0 );
mAlarmList.append( al );
}
updateDefaultAlarmTime();
- updateAlarmWidgets();
+ updateAlarmWidgets( incidence );
- setCategories(event->categories());
+ setCategories( incidence->categories() );
- mAttachments->readIncidence( event );
+ mAttachments->readIncidence( incidence );
- TQString resLabel = KOHelper::resourceLabel( calendar, event );
+ TQString resLabel = IncidenceFormatter::resourceString( calendar, incidence );
if ( !resLabel.isEmpty() ) {
mResourceLabel->setText( i18n( "Calendar: %1" ).arg( resLabel ) );
mResourceLabel->show();
}
}
-Alarm *KOEditorGeneral::alarmFromSimplePage() const
+Alarm *KOEditorGeneral::alarmFromSimplePage( Incidence *incidence ) const
{
if ( mAlarmButton->isChecked() ) {
Alarm *alarm = new Alarm( 0 );
- alarm->setDisplayAlarm("");
+ alarm->setDisplayAlarm( "" );
alarm->setEnabled(true);
TQString tmpStr = mAlarmTimeEdit->text();
int j = mAlarmTimeEdit->value() * -60;
- if (mAlarmIncrCombo->currentItem() == 1)
+ if ( mAlarmIncrCombo->currentItem() == 1 ) {
j = j * 60;
- else if (mAlarmIncrCombo->currentItem() == 2)
+ } else if ( mAlarmIncrCombo->currentItem() == 2 ) {
j = j * (60 * 24);
- alarm->setStartOffset( j );
+ }
+ if ( mType == "Event" ) {
+ alarm->setStartOffset( j );
+ }
+ if ( mType == "Todo" ) {
+ Todo *todo = static_cast<Todo *>( incidence );
+ if ( todo && todo->hasStartDate() && !todo->hasDueDate() ) {
+ alarm->setStartOffset( j );
+ } else {
+ alarm->setEndOffset( j );
+ }
+ }
return alarm;
} else {
return 0;
}
}
-void KOEditorGeneral::writeIncidence(Incidence *event)
+void KOEditorGeneral::writeIncidence( Incidence *incidence )
{
-// kdDebug(5850) << "KOEditorGeneral::writeEvent()" << endl;
-
- event->setSummary(mSummaryEdit->text());
- event->setLocation(mLocationEdit->text());
- event->setDescription(mDescriptionEdit->text());
- event->setCategories(mCategories);
- event->setSecrecy(mSecrecyCombo->currentItem());
+ incidence->setSummary(mSummaryEdit->text());
+ incidence->setLocation(mLocationEdit->text());
+ incidence->setDescription(mDescriptionEdit->text());
+ incidence->setCategories(mCategories);
+ incidence->setSecrecy(mSecrecyCombo->currentItem());
// alarm stuff
- event->clearAlarms();
- if ( mAlarmStack->id( mAlarmStack->visibleWidget() ) == SimpleAlarmPage ) {
- Alarm *al = alarmFromSimplePage();
+ incidence->clearAlarms();
+ if ( mAlarmIsSimple ) {
+ Alarm *al = alarmFromSimplePage( incidence );
if ( al ) {
- al->setParent( event );
- event->addAlarm( al );
+ al->setParent( incidence );
+ al->setEnabled( mAlarmButton->isChecked() );
+ incidence->addAlarm( al );
}
} else {
// simply assign the list of alarms
Alarm::List::ConstIterator it;
for( it = mAlarmList.begin(); it != mAlarmList.end(); ++it ) {
Alarm *al = new Alarm( *(*it) );
- al->setParent( event );
- al->setEnabled( true );
- event->addAlarm( al );
+ al->setParent( incidence );
+ al->setEnabled( mAlarmButton->isChecked() );
+ incidence->addAlarm( al );
}
}
- mAttachments->writeIncidence( event );
+ mAttachments->writeIncidence( incidence );
}
void KOEditorGeneral::setSummary( const TQString &text )
@@ -499,7 +579,7 @@ TQObject *KOEditorGeneral::typeAheadReceiver() const
void KOEditorGeneral::updateAttendeeSummary(int count)
{
if ( count <= 0 )
- mAttendeeSummaryLabel->setText( "No attendees" );
+ mAttendeeSummaryLabel->setText( i18n("No attendees") );
else
mAttendeeSummaryLabel->setText( i18n( "One attendee", "%n attendees", count ) );
}
diff --git a/korganizer/koeditorgeneral.h b/korganizer/koeditorgeneral.h
index b1fffc26c..1a9d6017c 100644
--- a/korganizer/koeditorgeneral.h
+++ b/korganizer/koeditorgeneral.h
@@ -28,10 +28,10 @@
class TQWidget;
class TQBoxLayout;
+class TQHBox;
class TQLineEdit;
class TQLabel;
class TQCheckBox;
-class TQWidgetStack;
class TQSpinBox;
class TQPushButton;
class TQComboBox;
@@ -41,8 +41,8 @@ class KURL;
class KOEditorAttachments;
namespace KCal {
-class Incidence;
-class Calendar;
+ class Incidence;
+ class Calendar;
}
using namespace KCal;
@@ -77,10 +77,10 @@ class KOEditorGeneral : public QObject
/** Set widgets to default values */
void setDefaults(bool allDay);
- /** Read event object and setup widgets accordingly */
- void readIncidence(Incidence *event, Calendar *calendar);
- /** Write event settings to event object */
- void writeIncidence(Incidence *);
+ /** Read incidence object and setup widgets accordingly */
+ void readIncidence( Incidence *incidence, Calendar *calendar );
+ /** Write incidence settings to incidence object */
+ void writeIncidence( Incidence *incidence );
/** Check if the input is valid. */
bool validateInput() { return true; }
@@ -96,14 +96,14 @@ class KOEditorGeneral : public QObject
public slots:
void setCategories(const TQStringList &categories);
void selectCategories();
+ void setType( const TQCString &type );
void addAttachments( const TQStringList &attachments,
const TQStringList& mimeTypes = TQStringList(),
bool inlineAttachment = false );
-
protected slots:
void editAlarms();
- void updateAlarmWidgets();
+ void updateAlarmWidgets( Incidence *incidence );
void updateDefaultAlarmTime();
void updateAttendeeSummary( int count );
@@ -112,19 +112,19 @@ class KOEditorGeneral : public QObject
void updateCategoryConfig();
void focusReceivedSignal();
void openURL( const KURL & );
- protected:
- Alarm *alarmFromSimplePage() const;
+ protected:
TQLineEdit *mSummaryEdit;
TQLineEdit *mLocationEdit;
TQLabel *mAttendeeSummaryLabel;
+ TQLabel *mRecEditLabel;
+ TQPushButton *mRecEditButton;
TQLabel *mAlarmBell;
- TQWidgetStack *mAlarmStack;
TQLabel *mAlarmInfoLabel;
TQCheckBox *mAlarmButton;
TQSpinBox *mAlarmTimeEdit;
TQComboBox *mAlarmIncrCombo;
- TQPushButton *mAlarmEditButton;
+ TQPushButton *mAlarmAdvancedButton;
KTextEdit *mDescriptionEdit;
TQLabel *mOwnerLabel;
TQComboBox *mSecrecyCombo;
@@ -133,10 +133,14 @@ class KOEditorGeneral : public QObject
KOEditorAttachments *mAttachments;
TQLabel *mResourceLabel;
- enum AlarmStackPages { SimpleAlarmPage, AdvancedAlarmLabel };
-
private:
+ Alarm *alarmFromSimplePage( Incidence *incidence ) const;
+ bool isSimpleAlarm( Alarm *alarm ) const;
+
+ bool mAlarmIsSimple;
+ TQHBox *mSimpleAlarmBox;
TQStringList mCategories;
+ TQCString mType; // as in Incidence::type()
KCal::Alarm::List mAlarmList;
};
diff --git a/korganizer/koeditorgeneralevent.cpp b/korganizer/koeditorgeneralevent.cpp
index 24e8b4ca2..0411c2f8e 100644
--- a/korganizer/koeditorgeneralevent.cpp
+++ b/korganizer/koeditorgeneralevent.cpp
@@ -39,7 +39,6 @@
#include <kdebug.h>
#include <kglobal.h>
#include <klocale.h>
-#include <kiconloader.h>
#include <kmessagebox.h>
#include <kfiledialog.h>
#include <kstandarddirs.h>
@@ -52,6 +51,7 @@
#include <libkdepim/kdateedit.h>
#include "koprefs.h"
+#include "koglobals.h"
#include "koeditorgeneralevent.h"
#include "koeditorgeneralevent.moc"
@@ -78,18 +78,15 @@ void KOEditorGeneralEvent::finishSetup()
TQWidget::setTabOrder( mStartTimeEdit, mEndDateEdit );
TQWidget::setTabOrder( mEndDateEdit, mEndTimeEdit );
TQWidget::setTabOrder( mEndTimeEdit, mAlldayEventCheckbox );
- TQWidget::setTabOrder( mAlldayEventCheckbox, mAlarmButton );
+ TQWidget::setTabOrder( mAlldayEventCheckbox, mRecEditButton );
+ TQWidget::setTabOrder( mRecEditButton, mAlarmButton );
TQWidget::setTabOrder( mAlarmButton, mAlarmTimeEdit );
TQWidget::setTabOrder( mAlarmTimeEdit, mAlarmIncrCombo );
-// TQWidget::setTabOrder( mAlarmIncrCombo, mAlarmSoundButton );
- TQWidget::setTabOrder( mAlarmIncrCombo, mAlarmEditButton );
-// TQWidget::setTabOrder( mAlarmSoundButton, mAlarmProgramButton );
-// TQWidget::setTabOrder( mAlarmProgramButton, mFreeTimeCombo );
- TQWidget::setTabOrder( mAlarmEditButton, mFreeTimeCombo );
+ TQWidget::setTabOrder( mAlarmIncrCombo, mAlarmAdvancedButton );
+ TQWidget::setTabOrder( mAlarmAdvancedButton, mFreeTimeCombo );
TQWidget::setTabOrder( mFreeTimeCombo, mDescriptionEdit );
TQWidget::setTabOrder( mDescriptionEdit, mCategoriesButton );
TQWidget::setTabOrder( mCategoriesButton, mSecrecyCombo );
-// TQWidget::setTabOrder( mSecrecyCombo, mDescriptionEdit );
mSummaryEdit->setFocus();
}
@@ -121,7 +118,6 @@ void KOEditorGeneralEvent::initTime(TQWidget *parent,TQBoxLayout *topLayout)
mStartTimeEdit = new KTimeEdit(timeBoxFrame);
layoutTimeBox->addWidget(mStartTimeEdit,0,2);
-
mEndDateLabel = new TQLabel(i18n("&End:"),timeBoxFrame);
layoutTimeBox->addWidget(mEndDateLabel,1,0);
@@ -151,16 +147,19 @@ void KOEditorGeneralEvent::initTime(TQWidget *parent,TQBoxLayout *topLayout)
connect(mEndDateEdit, TQT_SIGNAL(dateChanged(const TQDate&)),
this, TQT_SLOT(endDateChanged(const TQDate&)));
+ TQLabel *label = new TQLabel( i18n( "Recurrence:" ), timeBoxFrame );
+ layoutTimeBox->addWidget( label, 2, 0 );
TQBoxLayout *recLayout = new TQHBoxLayout();
layoutTimeBox->addMultiCellLayout( recLayout, 2, 2, 1, 4 );
- mRecurrenceSummary = new TQLabel( TQString(), timeBoxFrame );
- recLayout->addWidget( mRecurrenceSummary );
- TQPushButton *recEditButton = new TQPushButton( i18n("Edit..."), timeBoxFrame );
- recLayout->addWidget( recEditButton );
- connect( recEditButton, TQT_SIGNAL(clicked()), TQT_SIGNAL(editRecurrence()) );
+ mRecEditButton = new TQPushButton( timeBoxFrame );
+ mRecEditButton->setIconSet( KOGlobals::self()->smallIconSet( "recur", 16 ) );
+ recLayout->addWidget( mRecEditButton );
+ connect( mRecEditButton, TQT_SIGNAL(clicked()), TQT_SIGNAL(editRecurrence()) );
+ mRecEditLabel = new TQLabel( TQString(), timeBoxFrame );
+ recLayout->addWidget( mRecEditLabel );
recLayout->addStretch( 1 );
- TQLabel *label = new TQLabel( i18n("Reminder:"), timeBoxFrame );
+ label = new TQLabel( i18n("Reminder:"), timeBoxFrame );
layoutTimeBox->addWidget( label, 3, 0 );
TQBoxLayout *alarmLineLayout = new TQHBoxLayout();
layoutTimeBox->addMultiCellLayout( alarmLineLayout, 3, 3, 1, 4 );
@@ -230,7 +229,6 @@ void KOEditorGeneralEvent::timeStuffDisable(bool disable)
void KOEditorGeneralEvent::associateTime(bool time)
{
timeStuffDisable(time);
- //if(alarmButton->isChecked()) alarmStuffDisable(noTime);
allDayChanged(time);
}
@@ -317,7 +315,7 @@ void KOEditorGeneralEvent::setDefaults( const TQDateTime &from,
setDateTimes(from,to);
}
-void KOEditorGeneralEvent::readEvent( Event *event, Calendar *calendar, bool tmpl )
+void KOEditorGeneralEvent::readEvent( Event *event, Calendar *calendar, const TQDate &date, bool tmpl )
{
TQString tmpStr;
@@ -325,8 +323,26 @@ void KOEditorGeneralEvent::readEvent( Event *event, Calendar *calendar, bool tmp
timeStuffDisable(event->doesFloat());
if ( !tmpl ) {
+ TQDateTime startDT = event->dtStart();
+ TQDateTime endDT = event->dtEnd();
+ if ( event->doesRecur() && date.isValid() ) {
+ // Consider the active date when editing recurring Events.
+ TQDateTime kdt( date, TQTime( 0, 0, 0 ) );
+ const int eventLength = startDT.daysTo( endDT );
+ kdt = kdt.addSecs( -1 );
+ startDT.setDate( event->recurrence()->getNextDateTime( kdt ).date() );
+ if ( event->hasEndDate() ) {
+ endDT.setDate( startDT.addDays( eventLength ).date() );
+ } else {
+ if ( event->hasDuration() ) {
+ endDT = startDT.addSecs( event->duration() );
+ } else {
+ endDT = startDT;
+ }
+ }
+ }
// the rest is for the events only
- setDateTimes(event->dtStart(),event->dtEnd());
+ setDateTimes( startDT, endDT );
}
switch( event->transparency() ) {
@@ -338,11 +354,13 @@ void KOEditorGeneralEvent::readEvent( Event *event, Calendar *calendar, bool tmp
break;
}
- mRecurrenceSummary->setText( IncidenceFormatter::recurrenceString( event ) );
+ updateRecurrenceSummary( event );
Attendee *me = event->attendeeByMails( KOPrefs::instance()->allEmails() );
- if ( me && (me->status() == Attendee::NeedsAction || me->status() == Attendee::Tentative ||
- me->status() == Attendee::InProcess) ) {
+ if ( event->attendeeCount() > 1 &&
+ me && ( me->status() == Attendee::NeedsAction ||
+ me->status() == Attendee::Tentative ||
+ me->status() == Attendee::InProcess ) ) {
mInvitationBar->show();
} else {
mInvitationBar->hide();
@@ -509,16 +527,22 @@ bool KOEditorGeneralEvent::validateInput()
endDt.setTime(mEndTimeEdit->getTime());
}
- if (startDt > endDt) {
- KMessageBox::sorry(0,i18n("The event ends before it starts.\n"
- "Please correct dates and times."));
+ if ( startDt > endDt ) {
+ KMessageBox::sorry(
+ 0,
+ i18n( "The event ends before it starts.\n"
+ "Please correct dates and times." ) );
return false;
}
return KOEditorGeneral::validateInput();
}
-void KOEditorGeneralEvent::updateRecurrenceSummary(const TQString & summary)
+void KOEditorGeneralEvent::updateRecurrenceSummary( Event *event )
{
- mRecurrenceSummary->setText( summary );
+ if ( event->doesRecur() ) {
+ mRecEditLabel->setText( IncidenceFormatter::recurrenceString( event ) );
+ } else {
+ mRecEditLabel->setText( TQString() );
+ }
}
diff --git a/korganizer/koeditorgeneralevent.h b/korganizer/koeditorgeneralevent.h
index a13fa47c6..57ffba8df 100644
--- a/korganizer/koeditorgeneralevent.h
+++ b/korganizer/koeditorgeneralevent.h
@@ -58,14 +58,14 @@ class KOEditorGeneralEvent : public KOEditorGeneral
Read event object and setup widgets accordingly. If templ is true, the
event is read as template, i.e. the time and date information isn't set.
*/
- void readEvent( Event *event, Calendar *calendar, bool tmpl = false );
+ void readEvent( Event *event, Calendar *calendar, const TQDate &date, bool tmpl = false );
/** Write event settings to event object */
void writeEvent( Event * );
/** Check if the input is valid. */
bool validateInput();
- void updateRecurrenceSummary( const TQString &summary );
+ void updateRecurrenceSummary( Event *event );
TQFrame* invitationBar() const { return mInvitationBar; }
@@ -102,7 +102,6 @@ class KOEditorGeneralEvent : public KOEditorGeneral
TQLabel *mDurationLabel;
TQCheckBox *mAlldayEventCheckbox;
TQComboBox *mFreeTimeCombo;
- TQLabel *mRecurrenceSummary;
TQFrame *mInvitationBar;
// current start and end date and time
diff --git a/korganizer/koeditorgeneraljournal.cpp b/korganizer/koeditorgeneraljournal.cpp
index 620417194..0a4e5ec36 100644
--- a/korganizer/koeditorgeneraljournal.cpp
+++ b/korganizer/koeditorgeneraljournal.cpp
@@ -45,10 +45,11 @@
#include <tqwhatsthis.h>
-KOEditorGeneralJournal::KOEditorGeneralJournal( TQObject *parent,
+KOEditorGeneralJournal::KOEditorGeneralJournal( TQWidget *parent,
const char *name )
- : TQObject( parent, name )
+ : KOEditorGeneral( parent, name )
{
+ setType( "Journal" );
}
KOEditorGeneralJournal::~KOEditorGeneralJournal()
@@ -58,7 +59,7 @@ KOEditorGeneralJournal::~KOEditorGeneralJournal()
void KOEditorGeneralJournal::initTitle( TQWidget *parent, TQBoxLayout *topLayout )
{
TQHBoxLayout *hbox = new TQHBoxLayout( topLayout );
-
+
TQString whatsThis = i18n("Sets the title of this journal.");
TQLabel *summaryLabel = new TQLabel( i18n("T&itle:"), parent );
TQWhatsThis::add( summaryLabel, whatsThis );
@@ -78,19 +79,19 @@ void KOEditorGeneralJournal::initDate( TQWidget *parent, TQBoxLayout *topLayout
{
// TQBoxLayout *dateLayout = new TQVBoxLayout(topLayout);
TQBoxLayout *dateLayout = new TQHBoxLayout( topLayout );
-
+
mDateLabel = new TQLabel( i18n("&Date:"), parent);
dateLayout->addWidget( mDateLabel );
mDateEdit = new KDateEdit( parent );
dateLayout->addWidget( mDateEdit );
mDateLabel->setBuddy( mDateEdit );
-
+
dateLayout->addStretch();
-
+
mTimeCheckBox = new TQCheckBox( i18n("&Time: "), parent );
dateLayout->addWidget( mTimeCheckBox );
-
+
mTimeEdit = new KTimeEdit( parent );
dateLayout->addWidget( mTimeEdit );
connect( mTimeCheckBox, TQT_SIGNAL(toggled(bool)),
@@ -135,7 +136,7 @@ void KOEditorGeneralJournal::setDefaults( const TQDate &date )
setDate( date );
}
-void KOEditorGeneralJournal::readJournal( Journal *journal, bool tmpl )
+void KOEditorGeneralJournal::readJournal( Journal *journal, const TQDate &, bool tmpl )
{
setSummary( journal->summary() );
if ( !tmpl ) {
@@ -143,10 +144,10 @@ void KOEditorGeneralJournal::readJournal( Journal *journal, bool tmpl )
if ( !journal->doesFloat() ) {
kdDebug()<<"KOEditorGeneralJournal::readJournal, does not float, time="<<(journal->dtStart().time().toString())<<endl;
setTime( journal->dtStart().time() );
- } else {
+ } else {
kdDebug()<<"KOEditorGeneralJournal::readJournal, does float"<<endl;
setTime( TQTime( -1, -1, -1 ) );
- }
+ }
}
setDescription( journal->description() );
}
@@ -156,7 +157,7 @@ void KOEditorGeneralJournal::writeJournal( Journal *journal )
// kdDebug(5850) << "KOEditorGeneralJournal::writeIncidence()" << endl;
journal->setSummary( mSummaryEdit->text() );
journal->setDescription( mDescriptionEdit->text() );
-
+
TQDateTime tmpDT( mDateEdit->date(), TQTime(0,0,0) );
bool hasTime = mTimeCheckBox->isChecked();
journal->setFloats( !hasTime );
diff --git a/korganizer/koeditorgeneraljournal.h b/korganizer/koeditorgeneraljournal.h
index 28827c8c8..649a6d345 100644
--- a/korganizer/koeditorgeneraljournal.h
+++ b/korganizer/koeditorgeneraljournal.h
@@ -25,6 +25,8 @@
#ifndef KOEDITORGENERALJOURNAL_H
#define KOEDITORGENERALJOURNAL_H
+#include "koeditorgeneral.h"
+
#include <tqobject.h>
#include <tqdatetime.h>
@@ -43,11 +45,11 @@ class Journal;
}
using namespace KCal;
-class KOEditorGeneralJournal : public QObject
+class KOEditorGeneralJournal : public KOEditorGeneral
{
- Q_OBJECT
+ Q_OBJECT
public:
- KOEditorGeneralJournal ( TQObject* parent=0, const char* name=0 );
+ KOEditorGeneralJournal ( TQWidget *parent=0, const char* name=0 );
virtual ~KOEditorGeneralJournal();
void initDate( TQWidget *, TQBoxLayout * );
@@ -59,7 +61,7 @@ class KOEditorGeneralJournal : public QObject
void setDate( const TQDate &date );
void setTime( const TQTime &time );
/** Read journal object and setup widgets accordingly */
- void readJournal( Journal *, bool tmpl = false );
+ void readJournal( Journal *, const TQDate &, bool tmpl = false );
/** Write journal settings to event object */
void writeJournal( Journal * );
diff --git a/korganizer/koeditorgeneraltodo.cpp b/korganizer/koeditorgeneraltodo.cpp
index dd2a77b5c..d659e8e95 100644
--- a/korganizer/koeditorgeneraltodo.cpp
+++ b/korganizer/koeditorgeneraltodo.cpp
@@ -38,13 +38,13 @@
#include <kglobal.h>
#include <klocale.h>
-#include <kiconloader.h>
#include <kmessagebox.h>
#include <kdebug.h>
#include <kstandarddirs.h>
#include <kfiledialog.h>
#include <ktextedit.h>
+#include <libkcal/incidenceformatter.h>
#include <libkcal/todo.h>
#include <libkdepim/kdateedit.h>
@@ -56,10 +56,10 @@
#include "koeditorgeneraltodo.h"
#include "koeditorgeneraltodo.moc"
-KOEditorGeneralTodo::KOEditorGeneralTodo(TQObject* parent,
- const char* name)
- : KOEditorGeneral( parent, name)
+KOEditorGeneralTodo::KOEditorGeneralTodo( TQObject *parent, const char *name )
+ : KOEditorGeneral( parent, name )
{
+ setType( "Todo" );
}
KOEditorGeneralTodo::~KOEditorGeneralTodo()
@@ -76,19 +76,17 @@ void KOEditorGeneralTodo::finishSetup()
TQWidget::setTabOrder( mDueCheck, mDueDateEdit );
TQWidget::setTabOrder( mDueDateEdit, mDueTimeEdit );
TQWidget::setTabOrder( mDueTimeEdit, mTimeButton );
- TQWidget::setTabOrder( mTimeButton, mCompletedCombo );
+ TQWidget::setTabOrder( mTimeButton, mRecEditButton );
+ TQWidget::setTabOrder( mRecEditButton, mCompletedToggle );
+ TQWidget::setTabOrder( mCompletedToggle, mCompletedCombo );
TQWidget::setTabOrder( mCompletedCombo, mPriorityCombo );
TQWidget::setTabOrder( mPriorityCombo, mAlarmButton );
TQWidget::setTabOrder( mAlarmButton, mAlarmTimeEdit );
TQWidget::setTabOrder( mAlarmTimeEdit, mAlarmIncrCombo );
-// TQWidget::setTabOrder( mAlarmIncrCombo, mAlarmSoundButton );
- TQWidget::setTabOrder( mAlarmIncrCombo, mAlarmEditButton );
-// TQWidget::setTabOrder( mAlarmSoundButton, mAlarmProgramButton );
-// TQWidget::setTabOrder( mAlarmProgramButton, mDescriptionEdit );
- TQWidget::setTabOrder( mAlarmEditButton, mDescriptionEdit );
+ TQWidget::setTabOrder( mAlarmIncrCombo, mAlarmAdvancedButton );
+ TQWidget::setTabOrder( mAlarmAdvancedButton, mDescriptionEdit );
TQWidget::setTabOrder( mDescriptionEdit, mCategoriesButton );
TQWidget::setTabOrder( mCategoriesButton, mSecrecyCombo );
-// TQWidget::setTabOrder( mSecrecyCombo, mDescriptionEdit );
mSummaryEdit->setFocus();
}
@@ -134,7 +132,6 @@ void KOEditorGeneralTodo::initTime(TQWidget *parent,TQBoxLayout *topLayout)
TQWhatsThis::add( mDueCheck, whatsThis );
layoutTimeBox->addWidget(mDueCheck,1,0);
connect(mDueCheck,TQT_SIGNAL(toggled(bool)),TQT_SLOT(enableDueEdit(bool)));
- connect(mDueCheck,TQT_SIGNAL(toggled(bool)),TQT_SLOT(showAlarm()));
connect(mDueCheck,TQT_SIGNAL(toggled(bool)),TQT_SIGNAL(dueDateEditToggle(bool)));
connect(mDueCheck,TQT_SIGNAL(toggled(bool)),TQT_SLOT(dateChanged()));
@@ -153,13 +150,31 @@ void KOEditorGeneralTodo::initTime(TQWidget *parent,TQBoxLayout *topLayout)
TQWhatsThis::add( mTimeButton,
i18n("Sets whether or not this to-do's start and due dates "
"have times associated with them.") );
- layoutTimeBox->addMultiCellWidget(mTimeButton,2,2,0,2);
-
+ layoutTimeBox->addWidget( mTimeButton, 0, 3 );
connect(mTimeButton,TQT_SIGNAL(toggled(bool)),TQT_SLOT(enableTimeEdits(bool)));
connect(mTimeButton,TQT_SIGNAL(toggled(bool)),TQT_SLOT(dateChanged()));
+ TQLabel *label = new TQLabel( i18n( "Recurrence:" ), timeBoxFrame );
+ layoutTimeBox->addWidget( label, 3, 0 );
+ TQBoxLayout *recLayout = new TQHBoxLayout();
+ layoutTimeBox->addMultiCellLayout( recLayout, 3, 3, 1, 4 );
+ mRecEditButton = new TQPushButton( timeBoxFrame );
+ mRecEditButton->setIconSet( KOGlobals::self()->smallIconSet( "recur", 16 ) );
+ recLayout->addWidget( mRecEditButton );
+ connect( mRecEditButton, TQT_SIGNAL(clicked()), TQT_SIGNAL(editRecurrence()) );
+ mRecEditLabel = new TQLabel( TQString(), timeBoxFrame );
+ recLayout->addWidget( mRecEditLabel );
+ recLayout->addStretch( 1 );
+
+ label = new TQLabel( i18n("Reminder:"), timeBoxFrame );
+ layoutTimeBox->addWidget( label, 4, 0 );
+ TQBoxLayout *alarmLineLayout = new TQHBoxLayout();
+ layoutTimeBox->addMultiCellLayout( alarmLineLayout, 4, 4, 1, 4 );
+ initAlarm( timeBoxFrame, alarmLineLayout );
+ alarmLineLayout->addStretch( 1 );
+
// some more layouting
- layoutTimeBox->setColStretch(3,1);
+ layoutTimeBox->setColStretch( 3, 1 );
TQBoxLayout *secLayout = new TQHBoxLayout();
layoutTimeBox->addLayout( secLayout, 0, 4 );
@@ -167,54 +182,73 @@ void KOEditorGeneralTodo::initTime(TQWidget *parent,TQBoxLayout *topLayout)
}
-void KOEditorGeneralTodo::initCompletion(TQWidget *parent, TQBoxLayout *topLayout)
+void KOEditorGeneralTodo::initCompletion( TQWidget *parent, TQBoxLayout *topLayout )
{
- TQString whatsThis = i18n("Sets the current completion status of this to-do "
- "as a percentage.");
- mCompletedCombo = new TQComboBox(parent);
- TQWhatsThis::add( mCompletedCombo, whatsThis );
- for (int i = 0; i <= 100; i+=10) {
+ TQHBoxLayout *completionLayout = new TQHBoxLayout( topLayout );
+
+ TQLabel *label = new TQLabel( i18n( "&Completed:" ), parent );
+ completionLayout->addWidget( label );
+
+ mCompletedToggle = new TQCheckBox( parent );
+ TQToolTip::add( mCompletedToggle,
+ i18n( "Toggle between 0% and 100% complete" ) );
+ TQWhatsThis::add( mCompletedToggle,
+ i18n( "Click this checkbox to toggle the completed percentage of the to-do "
+ "between 0% or 100%" ) );
+ connect( mCompletedToggle, TQT_SIGNAL(clicked()), TQT_SLOT(completedChanged()) );
+ completionLayout->addWidget( mCompletedToggle );
+ label->setBuddy( mCompletedToggle );
+
+ mCompletedCombo = new TQComboBox( parent );
+ TQToolTip::add( mCompletedCombo,
+ i18n( "Select the completed percentage" ) );
+ TQWhatsThis::add( mCompletedCombo,
+ i18n( "Use this combobox to set the completion percentage of the to-do." ) );
+ for ( int i = 0; i <= 100; i+=10 ) {
// xgettext:no-c-format
- TQString label = i18n("Percent complete", "%1 %").arg (i);
- mCompletedCombo->insertItem(label);
+ TQString label = i18n( "Percent complete", "%1 %" ).arg( i );
+ mCompletedCombo->insertItem( label );
}
- connect(mCompletedCombo,TQT_SIGNAL(activated(int)),TQT_SLOT(completedChanged(int)));
- topLayout->addWidget(mCompletedCombo);
+ connect( mCompletedCombo, TQT_SIGNAL(activated(int)), TQT_SLOT(completedChanged(int)) );
+ completionLayout->addWidget( mCompletedCombo );
+
+ mCompletedLabel = new TQLabel( i18n( "completed on", "on" ), parent );
+ mCompletedLabel->hide();
+ completionLayout->addWidget( mCompletedLabel );
- mCompletedLabel = new TQLabel(i18n("co&mpleted"),parent);
- topLayout->addWidget(mCompletedLabel);
- mCompletedLabel->setBuddy( mCompletedCombo );
mCompletionDateEdit = new KDateEdit( parent );
mCompletionDateEdit->hide();
- topLayout->addWidget( mCompletionDateEdit );
+ completionLayout->addWidget( mCompletionDateEdit );
+
mCompletionTimeEdit = new KTimeEdit( parent, TQTime() );
mCompletionTimeEdit->hide();
- topLayout->addWidget( mCompletionTimeEdit );
+ completionLayout->addWidget( mCompletionTimeEdit );
}
void KOEditorGeneralTodo::initPriority(TQWidget *parent, TQBoxLayout *topLayout)
{
- TQString whatsThis = i18n("Sets the priority of this to-do on a scale "
- "from one to nine, with one being the highest "
- "priority, five being a medium priority, and "
- "nine being the lowest. In programs that have a "
- "different scale, the numbers will be adjusted "
- "to match the appropriate scale.");
- TQLabel *priorityLabel = new TQLabel(i18n("&Priority:"),parent);
- topLayout->addWidget(priorityLabel);
-
- mPriorityCombo = new TQComboBox(parent);
- mPriorityCombo->insertItem(i18n("unspecified"));
- mPriorityCombo->insertItem(i18n("1 (highest)"));
- mPriorityCombo->insertItem(i18n("2"));
- mPriorityCombo->insertItem(i18n("3"));
- mPriorityCombo->insertItem(i18n("4"));
- mPriorityCombo->insertItem(i18n("5 (medium)"));
- mPriorityCombo->insertItem(i18n("6"));
- mPriorityCombo->insertItem(i18n("7"));
- mPriorityCombo->insertItem(i18n("8"));
- mPriorityCombo->insertItem(i18n("9 (lowest)"));
- topLayout->addWidget(mPriorityCombo);
+ TQLabel *priorityLabel = new TQLabel( i18n( "&Priority:" ), parent );
+ topLayout->addWidget( priorityLabel );
+
+ mPriorityCombo = new TQComboBox( parent );
+ TQToolTip::add( mPriorityCombo,
+ i18n( "Set the priority of the to-do" ) );
+ TQWhatsThis::add( mPriorityCombo,
+ i18n( "Sets the priority of this to-do on a scale from one to nine, "
+ "with one being the highest priority, five being a medium priority, "
+ "and nine being the lowest. In programs that have a different scale, "
+ "the numbers will be adjusted to match the appropriate scale." ) );
+ mPriorityCombo->insertItem( i18n( "unspecified" ) );
+ mPriorityCombo->insertItem( i18n( "1 (highest)" ) );
+ mPriorityCombo->insertItem( i18n( "2" ) );
+ mPriorityCombo->insertItem( i18n( "3" ) );
+ mPriorityCombo->insertItem( i18n( "4" ) );
+ mPriorityCombo->insertItem( i18n( "5 (medium)" ) );
+ mPriorityCombo->insertItem( i18n( "6" ) );
+ mPriorityCombo->insertItem( i18n( "7" ) );
+ mPriorityCombo->insertItem( i18n( "8" ) );
+ mPriorityCombo->insertItem( i18n( "9 (lowest)" ) );
+ topLayout->addWidget( mPriorityCombo );
priorityLabel->setBuddy( mPriorityCombo );
}
@@ -263,25 +297,29 @@ void KOEditorGeneralTodo::setDefaults( const TQDateTime &due, bool allDay )
}
mStartDateModified = false;
- mPriorityCombo->setCurrentItem(5);
+ mPriorityCombo->setCurrentItem( 5 );
- mCompletedCombo->setCurrentItem(0);
+ mCompletedToggle->setChecked( false );
+ mCompletedCombo->setCurrentItem( 0 );
}
-void KOEditorGeneralTodo::readTodo(Todo *todo, Calendar *calendar)
+void KOEditorGeneralTodo::readTodo(Todo *todo, Calendar *calendar, const TQDate &date )
{
KOEditorGeneral::readIncidence(todo, calendar);
TQDateTime dueDT;
if (todo->hasDueDate()) {
- enableAlarm( true );
dueDT = todo->dtDue();
- mDueDateEdit->setDate(todo->dtDue().date());
- mDueTimeEdit->setTime(todo->dtDue().time());
+ if ( todo->doesRecur() && date.isValid() ) {
+ TQDateTime dt( date, TQTime( 0, 0, 0 ) );
+ dt = dt.addSecs( -1 );
+ dueDT.setDate( todo->recurrence()->getNextDateTime( dt ).date() );
+ }
+ mDueDateEdit->setDate(dueDT.date());
+ mDueTimeEdit->setTime(dueDT.time());
mDueCheck->setChecked(true);
} else {
- enableAlarm( false );
mDueDateEdit->setEnabled(false);
mDueTimeEdit->setEnabled(false);
mDueDateEdit->setDate(TQDate::currentDate());
@@ -290,8 +328,13 @@ void KOEditorGeneralTodo::readTodo(Todo *todo, Calendar *calendar)
}
if (todo->hasStartDate()) {
- mStartDateEdit->setDate(todo->dtStart().date());
- mStartTimeEdit->setTime(todo->dtStart().time());
+ TQDateTime startDT = todo->dtStart();
+ if ( todo->doesRecur() && date.isValid() && todo->hasDueDate() ) {
+ int days = todo->dtStart( true ).daysTo( todo->dtDue( true ) );
+ startDT.setDate( date.addDays( -days ) );
+ }
+ mStartDateEdit->setDate(startDT.date());
+ mStartTimeEdit->setTime(startDT.time());
mStartCheck->setChecked(true);
} else {
mStartDateEdit->setEnabled(false);
@@ -303,10 +346,13 @@ void KOEditorGeneralTodo::readTodo(Todo *todo, Calendar *calendar)
mTimeButton->setChecked( !todo->doesFloat() );
+ updateRecurrenceSummary( todo );
+
mAlreadyComplete = false;
- mCompletedCombo->setCurrentItem(todo->percentComplete() / 10);
- if (todo->isCompleted() && todo->hasCompletedDate()) {
- mCompleted = todo->completed();
+ mCompletedCombo->setCurrentItem( todo->percentComplete() / 10 );
+ if ( todo->isCompleted() && todo->hasCompletedDate() ) {
+ mCompletedDateTime = todo->completed();
+ mCompletedToggle->setChecked( true );
mAlreadyComplete = true;
}
setCompletedDate();
@@ -369,25 +415,25 @@ void KOEditorGeneralTodo::writeTodo(Todo *todo)
if ( todo->doesRecur() && !mStartDateModified ) {
todo->setDtDue( tmpDueDT );
} else {
- todo->setDtDue( tmpDueDT, true );
- todo->setDtStart( tmpStartDT );
- todo->setDtRecurrence( tmpDueDT );
+ todo->setDtDue( tmpDueDT, true );
+ todo->setDtStart( tmpStartDT );
+ todo->setDtRecurrence( tmpDueDT );
}
todo->setPriority( mPriorityCombo->currentItem() );
// set completion state
- todo->setPercentComplete(mCompletedCombo->currentItem() * 10);
+ todo->setPercentComplete( mCompletedCombo->currentItem() * 10 );
- if (mCompletedCombo->currentItem() == 10 && mCompleted.isValid()) {
+ if (mCompletedCombo->currentItem() == 10 && mCompletedDateTime.isValid()) {
TQDateTime completed( mCompletionDateEdit->date(),
mCompletionTimeEdit->getTime() );
- int difference = mCompleted.secsTo( completed );
+ int difference = mCompletedDateTime.secsTo( completed );
if ( (difference < 60) && (difference > -60) &&
- (completed.time().minute() == mCompleted.time().minute() ) ) {
+ (completed.time().minute() == mCompletedDateTime.time().minute() ) ) {
// completion time wasn't changed substantially (only the seconds
// truncated, but that's an effect done by KTimeEdit automatically).
- completed = mCompleted;
+ completed = mCompletedDateTime;
}
todo->setCompleted( completed );
}
@@ -439,11 +485,6 @@ void KOEditorGeneralTodo::enableTimeEdits(bool enable)
}
}
-void KOEditorGeneralTodo::showAlarm()
-{
- enableAlarm( mDueCheck->isChecked() );
-}
-
bool KOEditorGeneralTodo::validateInput()
{
if (mDueCheck->isChecked()) {
@@ -491,10 +532,33 @@ bool KOEditorGeneralTodo::validateInput()
return KOEditorGeneral::validateInput();
}
-void KOEditorGeneralTodo::completedChanged(int index)
+void KOEditorGeneralTodo::updateRecurrenceSummary( Todo *todo )
+{
+ if ( todo->doesRecur() ) {
+ mRecEditLabel->setText( IncidenceFormatter::recurrenceString( todo ) );
+ } else {
+ mRecEditLabel->setText( TQString() );
+ }
+}
+
+void KOEditorGeneralTodo::completedChanged( int index )
{
- if (index == 10) {
- mCompleted = TQDateTime::currentDateTime();
+ if ( index == 10 ) {
+ mCompletedToggle->setChecked( true );
+ mCompletedDateTime = TQDateTime::currentDateTime();
+ } else {
+ mCompletedToggle->setChecked( false );
+ }
+ setCompletedDate();
+}
+
+void KOEditorGeneralTodo::completedChanged()
+{
+ if ( mCompletedToggle->isChecked() ) {
+ mCompletedCombo->setCurrentItem( 10 );
+ mCompletedDateTime = TQDateTime::currentDateTime();
+ } else {
+ mCompletedCombo->setCurrentItem( 0 );
}
setCompletedDate();
}
@@ -533,21 +597,20 @@ void KOEditorGeneralTodo::startDateModified()
void KOEditorGeneralTodo::setCompletedDate()
{
- if (mCompletedCombo->currentItem() == 10 && mCompleted.isValid()) {
- mCompletedLabel->setText(i18n("co&mpleted on"));
-// .arg(KGlobal::locale()->formatDateTime(mCompleted)));
+ if ( mCompletedCombo->currentItem() == 10 && mCompletedDateTime.isValid() ) {
+ mCompletedLabel->show();
mCompletionDateEdit->show();
mCompletionTimeEdit->show();
- mCompletionDateEdit->setDate( mCompleted.date() );
- mCompletionTimeEdit->setTime( mCompleted.time() );
+ mCompletionDateEdit->setDate( mCompletedDateTime.date() );
+ mCompletionTimeEdit->setTime( mCompletedDateTime.time() );
} else {
- mCompletedLabel->setText(i18n("co&mpleted"));
+ mCompletedLabel->hide();
mCompletionDateEdit->hide();
mCompletionTimeEdit->hide();
}
}
-void KOEditorGeneralTodo::modified (Todo* todo, int modification)
+void KOEditorGeneralTodo::modified (Todo* todo, KOGlobals::HowChanged modification)
{
switch (modification) {
case KOGlobals::PRIORITY_MODIFIED:
@@ -556,7 +619,8 @@ void KOEditorGeneralTodo::modified (Todo* todo, int modification)
case KOGlobals::COMPLETION_MODIFIED:
mCompletedCombo->setCurrentItem(todo->percentComplete() / 10);
if (todo->isCompleted() && todo->hasCompletedDate()) {
- mCompleted = todo->completed();
+ mCompletedDateTime = todo->completed();
+ mCompletedToggle->setChecked( true );
}
setCompletedDate();
break;
@@ -565,7 +629,7 @@ void KOEditorGeneralTodo::modified (Todo* todo, int modification)
break;
case KOGlobals::UNKNOWN_MODIFIED: // fall through
default:
- readTodo( todo, 0 );
+ readTodo( todo, 0, TQDate() );
break;
}
}
diff --git a/korganizer/koeditorgeneraltodo.h b/korganizer/koeditorgeneraltodo.h
index 7ebc1f7ef..2d07cecac 100644
--- a/korganizer/koeditorgeneraltodo.h
+++ b/korganizer/koeditorgeneraltodo.h
@@ -25,6 +25,8 @@
#define _KOEDITORGENERALTODO_H
#include "koeditorgeneral.h"
+#include "koglobals.h"
+
#include <tqdatetime.h>
class KRestrictedLine;
@@ -54,30 +56,33 @@ class KOEditorGeneralTodo : public KOEditorGeneral
/** Set widgets to default values */
void setDefaults( const TQDateTime &due, bool allDay );
/** Read todo object and setup widgets accordingly */
- void readTodo(Todo *todo, Calendar *calendar);
+ void readTodo( Todo *todo, Calendar *calendar, const TQDate &date );
/** Write todo settings to event object */
void writeTodo(Todo *);
/** Check if the input is valid. */
bool validateInput();
+ void updateRecurrenceSummary( Todo *todo );
+
/** The todo has been modified externally */
- void modified (Todo*, int);
+ void modified( Todo *todo, KOGlobals::HowChanged modification );
signals:
void dueDateEditToggle( bool );
void dateTimeStrChanged( const TQString & );
void signalDateTimeChanged( const TQDateTime &, const TQDateTime & );
+ void editRecurrence();
protected slots:
- void completedChanged(int);
+ void completedChanged( int );
+ void completedChanged();
void dateChanged();
void startDateModified();
void enableDueEdit( bool enable );
void enableStartEdit( bool enable );
void enableTimeEdits( bool enable );
- void showAlarm();
protected:
void setCompletedDate();
@@ -92,6 +97,7 @@ class KOEditorGeneralTodo : public KOEditorGeneral
TQCheckBox *mDueCheck;
KDateEdit *mDueDateEdit;
KTimeEdit *mDueTimeEdit;
+ TQCheckBox *mCompletedToggle;
TQComboBox *mCompletedCombo;
TQLabel *mCompletedLabel;
TQLabel *mPriorityLabel;
@@ -102,7 +108,7 @@ class KOEditorGeneralTodo : public KOEditorGeneral
TQCheckBox *mStartCheck;
- TQDateTime mCompleted;
+ TQDateTime mCompletedDateTime;
};
diff --git a/korganizer/koeditorrecurrence.cpp b/korganizer/koeditorrecurrence.cpp
index 6f24446c2..564c39534 100644
--- a/korganizer/koeditorrecurrence.cpp
+++ b/korganizer/koeditorrecurrence.cpp
@@ -593,7 +593,8 @@ ExceptionsWidget::ExceptionsWidget( TQWidget *parent, const char *name ) :
mExceptionDateEdit->setDate( TQDate::currentDate() );
boxLayout->addWidget( mExceptionDateEdit, 0, 0 );
- TQPushButton *addExceptionButton = new TQPushButton( i18n("&Add"), box );
+ TQPushButton *addExceptionButton = new TQPushButton(
+ i18n( "Add a new recurrence to the recurrence list", "&Add" ), box );
TQWhatsThis::add( addExceptionButton,
i18n("Add this date as an exception "
"to the recurrence rules for this event or to-do.") );
@@ -1073,6 +1074,9 @@ KOEditorRecurrence::KOEditorRecurrence( TQWidget* parent, const char *name ) :
mExceptionsButton = 0;
topLayout->addWidget( mExceptionsWidget, 3, 1 );
}
+
+ // set some initial defaults for the saved recurrence
+ mSaveRec.setDuration( -1 ); // never ending
}
KOEditorRecurrence::~KOEditorRecurrence()
@@ -1083,6 +1087,7 @@ void KOEditorRecurrence::setRecurrenceEnabled( bool enabled )
{
// kdDebug(5850) << "KOEditorRecurrence::setRecurrenceEnabled(): " << (enabled ? "on" : "off") << endl;
+ mEnabledCheck->setChecked( enabled );
mTimeGroupBox->setEnabled( enabled );
mRuleBox->setEnabled( enabled );
if ( mRecurrenceRangeWidget ) mRecurrenceRangeWidget->setEnabled( enabled );
@@ -1147,9 +1152,7 @@ void KOEditorRecurrence::setDefaults( const TQDateTime &from, const TQDateTime &
{
setDateTimes( from, to );
- bool enabled = false;
- mEnabledCheck->setChecked( enabled );
- setRecurrenceEnabled( enabled );
+ setRecurrenceEnabled( false );
mRecurrenceRange->setDefaults( from );
@@ -1200,8 +1203,6 @@ void KOEditorRecurrence::readIncidence(Incidence *incidence)
f = r->frequency();
}
-
- mEnabledCheck->setChecked( recurs );
setRecurrenceEnabled( recurs );
int recurrenceType = RecurrenceChooser::Weekly;
@@ -1438,10 +1439,218 @@ bool KOEditorRecurrence::doesRecur()
return mEnabledCheck->isChecked();
}
+void KOEditorRecurrence::saveValues()
+{
+ int duration = mRecurrenceRange->duration();
+ TQDate endDate;
+ if ( duration == 0 ) {
+ endDate = mRecurrenceRange->endDate();
+ }
+
+ int recurrenceType = mRecurrenceChooser->type();
+ if ( recurrenceType == RecurrenceChooser::Daily ) {
+ mSaveRec.setDaily( mDaily->frequency() );
+ } else if ( recurrenceType == RecurrenceChooser::Weekly ) {
+ mSaveRec.setWeekly( mWeekly->frequency(), mWeekly->days() );
+ } else if ( recurrenceType == RecurrenceChooser::Monthly ) {
+ mSaveRec.setMonthly( mMonthly->frequency() );
+
+ if ( mMonthly->byPos() ) {
+ int pos = mMonthly->count();
+
+ TQBitArray days( 7 );
+ days.fill( false );
+ days.setBit( mMonthly->weekday() - 1 );
+ mSaveRec.addMonthlyPos( pos, days );
+ } else {
+ // it's by day
+ mSaveRec.addMonthlyDate( mMonthly->day() );
+ }
+ } else if ( recurrenceType == RecurrenceChooser::Yearly ) {
+ mSaveRec.setYearly( mYearly->frequency() );
+
+ switch ( mYearly->getType() ) {
+ case RecurYearly::byMonth:
+ mSaveRec.addYearlyDate( mYearly->monthDay() );
+ mSaveRec.addYearlyMonth( mYearly->month() );
+ break;
+
+ case RecurYearly::byPos:
+ {
+ mSaveRec.addYearlyMonth( mYearly->posMonth() );
+ TQBitArray days( 7 );
+ days.fill( false );
+ days.setBit( mYearly->posWeekday() - 1 );
+ mSaveRec.addYearlyPos( mYearly->posCount(), days );
+ break;
+ }
+
+ case RecurYearly::byDay:
+ mSaveRec.addYearlyDay( mYearly->day() );
+ break;
+ }
+ }
+
+ if ( duration > 0 ) {
+ mSaveRec.setDuration( duration );
+ } else if ( duration == 0 ) {
+ mSaveRec.setEndDate( endDate );
+ }
+
+ mSaveRec.setExDates( mExceptions->dates() );
+}
-KOEditorRecurrenceDialog::KOEditorRecurrenceDialog(TQWidget * parent) :
- KDialogBase( parent, 0, false, i18n("Recurrence"), Ok )
+void KOEditorRecurrence::restoreValues()
+{
+ TQBitArray rDays( 7 );
+ int day = 0;
+ int count = 0;
+ int month = 0;
+
+ if ( mSaveRec.startDateTime().isValid() && mSaveRec.endDateTime().isValid() ) {
+ setDefaults( mSaveRec.startDateTime(), mSaveRec.endDateTime(), mSaveRec.doesFloat() );
+ }
+
+ int recurrenceType;
+ switch ( mSaveRec.recurrenceType() ) {
+ case Recurrence::rNone:
+ recurrenceType = RecurrenceChooser::Weekly;
+ break;
+
+ case Recurrence::rDaily:
+ recurrenceType = RecurrenceChooser::Daily;
+ mDaily->setFrequency( mSaveRec.frequency() );
+ break;
+
+ case Recurrence::rWeekly:
+ recurrenceType = RecurrenceChooser::Weekly;
+
+ mWeekly->setFrequency( mSaveRec.frequency() );
+ mWeekly->setDays( mSaveRec.days() );
+ break;
+
+ case Recurrence::rMonthlyPos:
+ {
+ // TODO: we only handle one possibility in the list right now,
+ // so I have hardcoded calls with first(). If we make the GUI
+ // more extended, this can be changed.
+ recurrenceType = RecurrenceChooser::Monthly;
+
+ TQValueList<RecurrenceRule::WDayPos> rmp = mSaveRec.monthPositions();
+ if ( !rmp.isEmpty() ) {
+ mMonthly->setByPos( rmp.first().pos(), rmp.first().day() );
+ }
+ mMonthly->setFrequency( mSaveRec.frequency() );
+ break;
+ }
+
+ case Recurrence::rMonthlyDay:
+ {
+ recurrenceType = RecurrenceChooser::Monthly;
+
+ TQValueList<int> rmd = mSaveRec.monthDays();
+ // check if we have any setting for which day (vcs import is broken and
+ // does not set any day, thus we need to check)
+ if ( !rmd.isEmpty() ) {
+ day = rmd.first();
+ }
+ if ( day > 0 ) {
+ mMonthly->setByDay( day );
+ mMonthly->setFrequency( mSaveRec.frequency() );
+ }
+ break;
+ }
+
+ case Recurrence::rYearlyMonth:
+ {
+ recurrenceType = RecurrenceChooser::Yearly;
+
+ TQValueList<int> rmd = mSaveRec.yearDates();
+ if ( !rmd.isEmpty() ) {
+ day = rmd.first();
+ }
+ rmd = mSaveRec.yearMonths();
+ if ( !rmd.isEmpty() ) {
+ month = rmd.first();
+ }
+ if ( day > 0 && month > 0 ) {
+ mYearly->setByMonth( day, month );
+ mYearly->setFrequency( mSaveRec.frequency() );
+ }
+ break;
+ }
+
+ case Recurrence::rYearlyPos:
+ {
+ recurrenceType = RecurrenceChooser::Yearly;
+
+ TQValueList<int> months = mSaveRec.yearMonths();
+ if ( !months.isEmpty() ) {
+ month = months.first();
+ }
+ TQValueList<RecurrenceRule::WDayPos> pos = mSaveRec.yearPositions();
+ if ( !pos.isEmpty() ) {
+ count = pos.first().pos();
+ day = pos.first().day();
+ }
+ if ( count > 0 && day > 0 && month > 0 ) {
+ mYearly->setByPos( count, day, month );
+ mYearly->setFrequency( mSaveRec.frequency() );
+ }
+ break;
+ }
+
+ case Recurrence::rYearlyDay:
+ {
+ recurrenceType = RecurrenceChooser::Yearly;
+
+ TQValueList<int> days = mSaveRec.yearDays();
+ if ( !days.isEmpty() ) {
+ day = days.first();
+ }
+ if ( day > 0 ) {
+ mYearly->setByDay( day );
+ mYearly->setFrequency( mSaveRec.frequency() );
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ mRecurrenceChooser->setType( recurrenceType );
+ showCurrentRule( recurrenceType );
+
+ if ( mSaveRec.startDateTime().isValid() ) {
+ mRecurrenceRange->setDateTimes( mSaveRec.startDateTime() );
+ }
+
+ mRecurrenceRange->setDuration( mSaveRec.duration() );
+ if ( mSaveRec.duration() == 0 && mSaveRec.endDate().isValid() ) {
+ mRecurrenceRange->setEndDate( mSaveRec.endDate() );
+ }
+
+ mExceptions->setDates( mSaveRec.exDates() );
+}
+
+KOEditorRecurrenceDialog::KOEditorRecurrenceDialog(TQWidget * parent)
+ : KDialogBase( parent, 0, false, i18n("Recurrence"), Ok|Cancel ), mRecurEnabled( false )
{
mRecurrence = new KOEditorRecurrence( this );
setMainWidget( mRecurrence );
}
+
+void KOEditorRecurrenceDialog::slotOk()
+{
+ mRecurEnabled = mRecurrence->doesRecur();
+ mRecurrence->saveValues();
+ emit okClicked(); // tell the incidence editor to update the recurrenceString
+ accept();
+}
+
+void KOEditorRecurrenceDialog::slotCancel()
+{
+ mRecurrence->setRecurrenceEnabled( mRecurEnabled );
+ mRecurrence->restoreValues();
+ reject();
+}
diff --git a/korganizer/koeditorrecurrence.h b/korganizer/koeditorrecurrence.h
index 0ce9c6dda..05074cdd9 100644
--- a/korganizer/koeditorrecurrence.h
+++ b/korganizer/koeditorrecurrence.h
@@ -297,6 +297,9 @@ class KOEditorRecurrence : public QWidget
bool doesRecur();
+ void saveValues();
+ void restoreValues();
+
public slots:
void setRecurrenceEnabled( bool );
void setDateTimes( const TQDateTime &start, const TQDateTime &end );
@@ -311,6 +314,7 @@ class KOEditorRecurrence : public QWidget
void showRecurrenceRangeDialog();
private:
+ Recurrence mSaveRec;
TQCheckBox *mEnabledCheck;
TQGroupBox *mTimeGroupBox;
@@ -345,8 +349,13 @@ class KOEditorRecurrenceDialog : public KDialogBase
KOEditorRecurrenceDialog( TQWidget *parent );
KOEditorRecurrence* editor() const { return mRecurrence; }
+ protected slots:
+ void slotOk();
+ void slotCancel();
+
private:
KOEditorRecurrence *mRecurrence;
+ bool mRecurEnabled;
};
#endif
diff --git a/korganizer/koeventeditor.cpp b/korganizer/koeventeditor.cpp
index 5cc7041ee..8a8340fc0 100644
--- a/korganizer/koeventeditor.cpp
+++ b/korganizer/koeventeditor.cpp
@@ -41,7 +41,6 @@
#include "koprefs.h"
#include "koeditorgeneralevent.h"
-#include "koeditoralarms.h"
#include "koeditorrecurrence.h"
#include "koeditordetails.h"
#include "koeditorfreebusy.h"
@@ -66,7 +65,6 @@ KOEventEditor::~KOEventEditor()
void KOEventEditor::init()
{
setupGeneral();
-// setupAlarmsTab();
setupRecurrence();
setupFreeBusy();
setupDesignerTabs( "event" );
@@ -111,7 +109,9 @@ void KOEventEditor::reload()
{
kdDebug(5850) << "KOEventEditor::reload()" << endl;
- if ( mEvent ) readEvent( mEvent, mCalendar );
+ if ( mEvent ) {
+ readEvent( mEvent, mCalendar, TQDate() );
+ }
}
void KOEventEditor::setupGeneral()
@@ -129,9 +129,6 @@ void KOEventEditor::setupGeneral()
mGeneral->initHeader( topFrame, topLayout );
mGeneral->initTime(topFrame,topLayout);
-// TQBoxLayout *alarmLineLayout = new TQHBoxLayout(topLayout);
- mGeneral->initAlarm(topFrame,topLayout);
- mGeneral->enableAlarm( false );
topLayout->addStretch( 1 );
@@ -166,27 +163,15 @@ void KOEventEditor::setupGeneral()
mGeneral->finishSetup();
}
-void KOEventEditor::modified (int /*modification*/)
+void KOEventEditor::modified()
{
- // Play dump, just reload the event. This dialog has become so complicated
+ // Play dumb, just reload the event. This dialog has become so complicated
// that there is no point in trying to be smart here...
reload();
}
void KOEventEditor::setupRecurrence()
{
-#if 0
- TQFrame *topFrame = addPage( i18n("Rec&urrence") );
-
- TQWhatsThis::add( topFrame,
- i18n("The Recurrence tab allows you to set options on "
- "how often this event recurs.") );
-
- TQBoxLayout *topLayout = new TQVBoxLayout( topFrame );
-
- mRecurrence = new KOEditorRecurrence( topFrame );
- topLayout->addWidget( mRecurrence );
-#endif
mRecurrenceDialog = new KOEditorRecurrenceDialog( this );
mRecurrenceDialog->hide();
mRecurrence = mRecurrenceDialog->editor();
@@ -205,7 +190,9 @@ void KOEventEditor::setupFreeBusy()
topLayout->addWidget( mFreeBusy );
}
-void KOEventEditor::editIncidence( Incidence *incidence, Calendar *calendar )
+void KOEventEditor::editIncidence( Incidence *incidence,
+ const TQDate &date,
+ Calendar *calendar )
{
Event*event = dynamic_cast<Event*>(incidence);
if ( event ) {
@@ -213,7 +200,9 @@ void KOEventEditor::editIncidence( Incidence *incidence, Calendar *calendar )
mEvent = event;
mCalendar = calendar;
- readEvent( mEvent, mCalendar );
+
+ const TQDate &dt = mRecurIncidence && date.isValid() ? date : incidence->dtStart().date();
+ readEvent( mEvent, mCalendar, dt );
}
setCaption( i18n("Edit Event") );
@@ -263,9 +252,12 @@ void KOEventEditor::loadDefaults()
bool KOEventEditor::processInput()
{
- kdDebug(5850) << "KOEventEditor::processInput()" << endl;
+ kdDebug(5850) << "KOEventEditor::processInput(); event is " << mEvent << endl;
- if ( !validateInput() || !mChanger ) return false;
+ if ( !validateInput() || !mChanger ) {
+ kdDebug(5850) << " mChanger is " << mChanger << endl;
+ return false;
+ }
TQGuardedPtr<KOEditorFreeBusy> freeBusy( mFreeBusy );
@@ -280,11 +272,12 @@ bool KOEventEditor::processInput()
if( *event == *mEvent ) {
// Don't do anything
- kdDebug(5850) << "Event not changed\n";
- if ( mIsCounter )
+ kdDebug(5850) << "Event not changed" << endl;
+ if ( mIsCounter ) {
KMessageBox::information( this, i18n("You didn't change the event, thus no counter proposal has been sent to the organizer."), i18n("No changes") );
+ }
} else {
- kdDebug(5850) << "Event changed\n";
+ kdDebug(5850) << "Event changed" << endl;
//IncidenceChanger::assignIncidence( mEvent, event );
writeEvent( mEvent );
if ( mIsCounter ) {
@@ -293,9 +286,17 @@ bool KOEventEditor::processInput()
Event *event = mEvent->clone();
event->clearAttendees();
event->setSummary( i18n("My counter proposal for: %1").arg( mEvent->summary() ) );
- mChanger->addIncidence( event );
+ mChanger->addIncidence( event, mResource, mSubResource, this );
} else {
- mChanger->changeIncidence( oldEvent, mEvent );
+ if ( mRecurIncidence && mRecurIncidenceAfterDissoc ) {
+ mChanger->addIncidence( mEvent, mResource, mSubResource, this );
+
+ mChanger->changeIncidence( mRecurIncidence, mRecurIncidenceAfterDissoc,
+ KOGlobals::RECURRENCE_MODIFIED_ALL_FUTURE, this );
+
+ } else {
+ mChanger->changeIncidence( oldEvent, mEvent, KOGlobals::NOTHING_MODIFIED, this );
+ }
}
}
delete event;
@@ -307,14 +308,16 @@ bool KOEventEditor::processInput()
KOPrefs::instance()->email() ) );
writeEvent( mEvent );
// NOTE: triggered by addIncidence, the kolab resource might open a non-modal dialog (parent is not available in the resource) to select a resource folder. Thus the user can close this dialog before addIncidence() returns.
- if ( !mChanger->addIncidence( mEvent, this ) ) {
+ if ( !mChanger->addIncidence( mEvent, mResource, mSubResource, this ) ) {
delete mEvent;
mEvent = 0;
return false;
}
}
// if "this" was deleted, freeBusy is 0 (being a guardedptr)
- if ( freeBusy ) freeBusy->cancelReload();
+ if ( freeBusy ) {
+ freeBusy->cancelReload();
+ }
return true;
}
@@ -324,6 +327,11 @@ void KOEventEditor::processCancel()
kdDebug(5850) << "KOEventEditor::processCancel()" << endl;
if ( mFreeBusy ) mFreeBusy->cancelReload();
+
+ if ( mRecurIncidence && mRecurIncidenceAfterDissoc ) {
+ *mRecurIncidenceAfterDissoc = *mRecurIncidence;
+ }
+
}
void KOEventEditor::deleteEvent()
@@ -336,11 +344,11 @@ void KOEventEditor::deleteEvent()
reject();
}
-void KOEventEditor::readEvent( Event *event, Calendar *calendar, bool tmpl )
+void KOEventEditor::readEvent( Event *event, Calendar *calendar, const TQDate &date, bool tmpl )
{
- mGeneral->readEvent( event, calendar, tmpl );
+ mGeneral->readEvent( event, calendar, date, tmpl );
mRecurrence->readIncidence( event );
-// mAlarms->readIncidence( event );
+
if ( mFreeBusy ) {
mFreeBusy->readEvent( event );
mFreeBusy->triggerReload();
@@ -368,11 +376,14 @@ void KOEventEditor::writeEvent( Event *event )
bool KOEventEditor::validateInput()
{
- if ( !mGeneral->validateInput() ) return false;
- if ( !mDetails->validateInput() ) return false;
- if ( !mRecurrence->validateInput() ) return false;
-
- return true;
+ if ( !mGeneral->validateInput() ||
+ !mDetails->validateInput() ||
+ !mRecurrence->validateInput() ) {
+ kdDebug(5850) << "ValidateInput returns false" << endl;
+ return false;
+ } else {
+ return true;
+ }
}
int KOEventEditor::msgItemDelete()
@@ -390,7 +401,7 @@ void KOEventEditor::loadTemplate( /*const*/ CalendarLocal& cal )
i18n("Template does not contain a valid event.") );
} else {
kdDebug(5850) << "KOEventEditor::slotLoadTemplate(): readTemplate" << endl;
- readEvent( events.first(), 0, true );
+ readEvent( events.first(), 0, TQDate(), true );
}
}
@@ -414,9 +425,9 @@ TQObject *KOEventEditor::typeAheadReceiver() const
void KOEventEditor::updateRecurrenceSummary()
{
- Event *ev = new Event();
+ Event *ev = new Event();
writeEvent( ev );
- mGeneral->updateRecurrenceSummary( IncidenceFormatter::recurrenceString( ev ) );
+ mGeneral->updateRecurrenceSummary( ev );
delete ev;
}
diff --git a/korganizer/koeventeditor.h b/korganizer/koeventeditor.h
index ba0974793..dbcec875f 100644
--- a/korganizer/koeventeditor.h
+++ b/korganizer/koeventeditor.h
@@ -57,7 +57,7 @@ class KOEventEditor : public KOIncidenceEditor
void init();
/** This event has been modified externally */
- void modified (int change=0);
+ void modified();
void reload();
/**
@@ -74,7 +74,7 @@ class KOEventEditor : public KOIncidenceEditor
/**
Edit an existing event.
*/
- void editIncidence( Incidence *incidence, Calendar *calendar );
+ void editIncidence( Incidence *incidence, const TQDate &date, Calendar *calendar );
/**
Set widgets to the given date/time values
@@ -85,7 +85,7 @@ class KOEventEditor : public KOIncidenceEditor
Read event object and setup widgets accordingly. If tmpl is true, the
event is read as template, i.e. the time and date information isn't set.
*/
- void readEvent( Event *event, Calendar *calendar, bool tmpl = false );
+ void readEvent( Event *event, Calendar *calendar, const TQDate &date, bool tmpl = false );
/**
Write event settings to event object
*/
diff --git a/korganizer/koeventpopupmenu.cpp b/korganizer/koeventpopupmenu.cpp
index 75c96d205..b0326ee52 100644
--- a/korganizer/koeventpopupmenu.cpp
+++ b/korganizer/koeventpopupmenu.cpp
@@ -45,6 +45,7 @@
KOEventPopupMenu::KOEventPopupMenu()
{
+ mCalendar = 0;
mCurrentIncidence = 0;
mCurrentDate = TQDate();
mHasAdditionalItems = false;
@@ -89,8 +90,9 @@ KOEventPopupMenu::KOEventPopupMenu()
this, TQT_SLOT(forward()) );
}
-void KOEventPopupMenu::showIncidencePopup( Incidence *incidence, const TQDate &qd )
+void KOEventPopupMenu::showIncidencePopup( Calendar *cal, Incidence *incidence, const TQDate &qd )
{
+ mCalendar = cal;
mCurrentIncidence = incidence;
mCurrentDate = qd;
@@ -123,19 +125,23 @@ void KOEventPopupMenu::addAdditionalItem(const TQIconSet &icon,const TQString &t
void KOEventPopupMenu::popupShow()
{
- if (mCurrentIncidence) emit showIncidenceSignal(mCurrentIncidence);
+ if ( mCurrentIncidence ) {
+ emit showIncidenceSignal( mCurrentIncidence, mCurrentDate );
+ }
}
void KOEventPopupMenu::popupEdit()
{
- if (mCurrentIncidence) emit editIncidenceSignal(mCurrentIncidence);
+ if ( mCurrentIncidence ) {
+ emit editIncidenceSignal( mCurrentIncidence, mCurrentDate );
+ }
}
void KOEventPopupMenu::print()
{
#ifndef KORG_NOPRINTER
KOCoreHelper helper;
- CalPrinter printer( this, 0, &helper );
+ CalPrinter printer( this, mCalendar, &helper );
connect( this, TQT_SIGNAL(configChanged()), &printer, TQT_SLOT(updateConfig()) );
Incidence::List selectedIncidences;
diff --git a/korganizer/koeventpopupmenu.h b/korganizer/koeventpopupmenu.h
index 8d4f2df26..96911b8cb 100644
--- a/korganizer/koeventpopupmenu.h
+++ b/korganizer/koeventpopupmenu.h
@@ -31,6 +31,7 @@
#include <tqdatetime.h>
namespace KCal {
+class Calendar;
class Incidence;
}
using namespace KCal;
@@ -46,7 +47,7 @@ class KOEventPopupMenu : public TQPopupMenu {
public slots:
- void showIncidencePopup( Incidence *, const TQDate & );
+ void showIncidencePopup( Calendar *, Incidence *, const TQDate & );
protected slots:
void popupShow();
@@ -62,17 +63,19 @@ class KOEventPopupMenu : public TQPopupMenu {
void forward();
signals:
- void editIncidenceSignal(Incidence *);
- void showIncidenceSignal(Incidence *);
- void deleteIncidenceSignal(Incidence *);
- void cutIncidenceSignal(Incidence *);
- void copyIncidenceSignal(Incidence *);
+ void configChanged();
+ void editIncidenceSignal( Incidence *, const TQDate & );
+ void showIncidenceSignal( Incidence *, const TQDate & );
+ void deleteIncidenceSignal( Incidence * );
+ void cutIncidenceSignal( Incidence * );
+ void copyIncidenceSignal( Incidence * );
void pasteIncidenceSignal();
- void toggleAlarmSignal(Incidence *);
+ void toggleAlarmSignal( Incidence * );
void dissociateOccurrenceSignal( Incidence *, const TQDate & );
void dissociateFutureOccurrenceSignal( Incidence *, const TQDate & );
private:
+ Calendar *mCalendar;
Incidence *mCurrentIncidence;
TQDate mCurrentDate;
diff --git a/korganizer/koeventview.cpp b/korganizer/koeventview.cpp
index 17708953b..9e01ea4e0 100644
--- a/korganizer/koeventview.cpp
+++ b/korganizer/koeventview.cpp
@@ -60,25 +60,25 @@ KOEventView::~KOEventView()
KOEventPopupMenu *KOEventView::eventPopup()
{
KOEventPopupMenu *eventPopup = new KOEventPopupMenu;
-
- connect(eventPopup,TQT_SIGNAL(editIncidenceSignal(Incidence *)),
- TQT_SIGNAL(editIncidenceSignal(Incidence *)));
- connect(eventPopup,TQT_SIGNAL(showIncidenceSignal(Incidence *)),
- TQT_SIGNAL(showIncidenceSignal(Incidence *)));
- connect(eventPopup,TQT_SIGNAL(deleteIncidenceSignal(Incidence *)),
- TQT_SIGNAL(deleteIncidenceSignal(Incidence *)));
- connect(eventPopup,TQT_SIGNAL(cutIncidenceSignal(Incidence *)),
- TQT_SIGNAL(cutIncidenceSignal(Incidence *)));
- connect(eventPopup,TQT_SIGNAL(copyIncidenceSignal(Incidence *)),
- TQT_SIGNAL(copyIncidenceSignal(Incidence *)));
- connect(eventPopup,TQT_SIGNAL(pasteIncidenceSignal()),
- TQT_SIGNAL(pasteIncidenceSignal()));
- connect(eventPopup,TQT_SIGNAL(toggleAlarmSignal(Incidence *)),
- TQT_SIGNAL(toggleAlarmSignal(Incidence*)));
- connect(eventPopup,TQT_SIGNAL(dissociateOccurrenceSignal( Incidence *, const TQDate & )),
- TQT_SIGNAL(dissociateOccurrenceSignal( Incidence *, const TQDate & )));
- connect(eventPopup,TQT_SIGNAL(dissociateFutureOccurrenceSignal( Incidence *, const TQDate & )),
- TQT_SIGNAL(dissociateFutureOccurrenceSignal( Incidence *, const TQDate & )));
+
+ connect( eventPopup, TQT_SIGNAL(editIncidenceSignal(Incidence *,const TQDate &)),
+ TQT_SIGNAL(editIncidenceSignal(Incidence *,const TQDate &)) );
+ connect( eventPopup, TQT_SIGNAL(showIncidenceSignal(Incidence *,const TQDate &)),
+ TQT_SIGNAL(showIncidenceSignal(Incidence *,const TQDate &)) );
+ connect( eventPopup, TQT_SIGNAL(deleteIncidenceSignal(Incidence *)),
+ TQT_SIGNAL(deleteIncidenceSignal(Incidence *)) );
+ connect( eventPopup, TQT_SIGNAL(cutIncidenceSignal(Incidence *)),
+ TQT_SIGNAL(cutIncidenceSignal(Incidence *)) );
+ connect( eventPopup, TQT_SIGNAL(copyIncidenceSignal(Incidence *)),
+ TQT_SIGNAL(copyIncidenceSignal(Incidence *)) );
+ connect( eventPopup, TQT_SIGNAL(pasteIncidenceSignal()),
+ TQT_SIGNAL(pasteIncidenceSignal()) );
+ connect( eventPopup, TQT_SIGNAL(toggleAlarmSignal(Incidence *)),
+ TQT_SIGNAL(toggleAlarmSignal(Incidence*)) );
+ connect( eventPopup, TQT_SIGNAL(dissociateOccurrenceSignal(Incidence *,const TQDate &)),
+ TQT_SIGNAL(dissociateOccurrenceSignal(Incidence *,const TQDate &)) );
+ connect( eventPopup, TQT_SIGNAL(dissociateFutureOccurrenceSignal(Incidence *,const TQDate &)),
+ TQT_SIGNAL(dissociateFutureOccurrenceSignal(Incidence *,const TQDate &)) );
return eventPopup;
}
@@ -102,14 +102,14 @@ TQPopupMenu *KOEventView::newEventPopup()
void KOEventView::popupShow()
{
- emit showIncidenceSignal(mCurrentIncidence);
+ emit showIncidenceSignal(mCurrentIncidence, TQDate() );
}
//---------------------------------------------------------------------------
void KOEventView::popupEdit()
{
- emit editIncidenceSignal(mCurrentIncidence);
+ emit editIncidenceSignal( mCurrentIncidence, TQDate() );
}
//---------------------------------------------------------------------------
@@ -137,14 +137,16 @@ void KOEventView::popupCopy()
void KOEventView::showNewEventPopup()
{
- TQPopupMenu *popup = newEventPopup();
- if ( !popup ) {
- kdError() << "KOEventView::showNewEventPopup(): popup creation failed"
- << endl;
- return;
+ if ( !readOnly() ) {
+ TQPopupMenu *popup = newEventPopup();
+ if ( !popup ) {
+ kdError() << "KOEventView::showNewEventPopup(): popup creation failed"
+ << endl;
+ return;
+ }
+
+ popup->popup( TQCursor::pos() );
}
-
- popup->popup( TQCursor::pos() );
}
//---------------------------------------------------------------------------
@@ -157,10 +159,11 @@ void KOEventView::defaultAction( Incidence *incidence )
kdDebug(5850) << " type: " << incidence->type() << endl;
- if ( incidence->isReadOnly() )
- emit showIncidenceSignal(incidence);
- else
- emit editIncidenceSignal(incidence);
+ if ( incidence->isReadOnly() ) {
+ emit showIncidenceSignal( incidence, TQDate() );
+ } else {
+ emit editIncidenceSignal( incidence, TQDate() );
+ }
}
//---------------------------------------------------------------------------
diff --git a/korganizer/koeventview.h b/korganizer/koeventview.h
index c33348813..69f6377f9 100644
--- a/korganizer/koeventview.h
+++ b/korganizer/koeventview.h
@@ -90,6 +90,8 @@ class KOEventView : public KOrg::BaseView
/** This view is an view for displaying events. */
bool isEventView() { return true; }
+ bool supportsDateNavigation() const { return true; }
+
public slots:
/**
@@ -126,6 +128,7 @@ class KOEventView : public KOrg::BaseView
protected:
Incidence *mCurrentIncidence; // Incidence selected e.g. for a context menu
+
};
#endif
diff --git a/korganizer/koeventviewer.cpp b/korganizer/koeventviewer.cpp
index 47ac5b7a4..83534d6aa 100644
--- a/korganizer/koeventviewer.cpp
+++ b/korganizer/koeventviewer.cpp
@@ -23,24 +23,62 @@
*/
#include "koeventviewer.h"
-
+#include "koglobals.h"
#include "urihandler.h"
+#include <libkcal/attachmenthandler.h>
+#include <libkcal/calendar.h>
#include <libkcal/incidence.h>
#include <libkcal/incidenceformatter.h>
+
#include <kdebug.h>
-#include <koglobals.h>
+#include <klocale.h>
+#include <kpopupmenu.h>
+
+#include <tqcursor.h>
+#include <tqregexp.h>
+#include <tqtooltip.h>
-KOEventViewer::KOEventViewer( TQWidget *parent, const char *name )
- : TQTextBrowser( parent, name ), mDefaultText("")
+KOEventViewer::KOEventViewer( Calendar *calendar, TQWidget *parent, const char *name )
+ : TQTextBrowser( parent, name ), mCalendar( calendar ), mDefaultText("")
{
mIncidence = 0;
+ connect( this, TQT_SIGNAL(highlighted(const TQString &)), TQT_SLOT(message(const TQString &)) );
}
KOEventViewer::~KOEventViewer()
{
}
+void KOEventViewer::message( const TQString &link )
+{
+ mAttachLink = TQString();
+ if ( link.isEmpty() ) {
+ TQToolTip::remove( this );
+ return;
+ }
+
+ TQString ttStr;
+ if ( link.startsWith( "kmail:" ) ) {
+ ttStr = i18n( "Open the message in KMail" );
+ } else if ( link.startsWith( "mailto:" ) ) {
+ ttStr = i18n( "Send an email message to %1" ).arg( link.mid( 7 ) );
+ } else if ( link.startsWith( "uid:" ) ) {
+ ttStr = i18n( "Lookup the contact in KAddressbook" );
+ } else if ( link.startsWith( "ATTACH:" ) ) {
+ TQString tmp = link;
+ tmp.remove( TQRegExp( "^ATTACH://" ) );
+ TQString uid = tmp.section( ':', 0, 0 );
+ TQString name = tmp.section( ':', -1, -1 );
+ ttStr = i18n( "View attachment \"%1\"" ).arg( name );
+ mAttachLink = link;
+ } else { // no special URI, let KDE handle it
+ ttStr = i18n( "Launch a viewer on the link" );
+ }
+
+ TQToolTip::add( this, ttStr );
+}
+
void KOEventViewer::readSettings( KConfig * config )
{
if ( config ) {
@@ -50,7 +88,7 @@ void KOEventViewer::readSettings( KConfig * config )
config->setGroup( TQString("EventViewer-%1").arg( name() ) );
int zoomFactor = config->readNumEntry("ZoomFactor", pointSize() );
zoomTo( zoomFactor/2 );
- kdDebug(5850) << " KOEventViewer: restoring the pointSize: "<< pointSize()
+ kdDebug(5850) << " KOEventViewer: restoring the pointSize: "<< pointSize()
<< ", zoomFactor: " << zoomFactor << endl;
#endif
}
@@ -67,20 +105,25 @@ void KOEventViewer::writeSettings( KConfig * config )
void KOEventViewer::setSource( const TQString &n )
{
- UriHandler::process( n );
+ UriHandler::process( parentWidget(), n );
}
-bool KOEventViewer::appendIncidence( Incidence *incidence )
+bool KOEventViewer::appendIncidence( Incidence *incidence, const TQDate &date )
{
- addText( IncidenceFormatter::extensiveDisplayString( incidence ) );
+ addText( IncidenceFormatter::extensiveDisplayStr( mCalendar, incidence, date ) );
return true;
}
-void KOEventViewer::setIncidence( Incidence *incidence )
+void KOEventViewer::setCalendar( Calendar *calendar )
+{
+ mCalendar = calendar;
+}
+
+void KOEventViewer::setIncidence( Incidence *incidence, const TQDate &date )
{
clearEvents();
if( incidence ) {
- appendIncidence( incidence );
+ appendIncidence( incidence, date );
mIncidence = incidence;
} else {
clearEvents( true );
@@ -105,20 +148,43 @@ void KOEventViewer::setDefaultText( const TQString &text )
mDefaultText = text;
}
-void KOEventViewer::changeIncidenceDisplay( Incidence *incidence, int action )
+void KOEventViewer::changeIncidenceDisplay( Incidence *incidence, const TQDate &date, int action )
{
if ( mIncidence && ( incidence->uid() == mIncidence->uid() ) ) {
- switch (action ) {
- case KOGlobals::INCIDENCEEDITED:{
- setIncidence( incidence );
- break;
- }
- case KOGlobals::INCIDENCEDELETED: {
- setIncidence( 0 );
- break;
- }
+ switch ( action ) {
+ case KOGlobals::INCIDENCEEDITED:
+ setIncidence( incidence, date );
+ break;
+ case KOGlobals::INCIDENCEDELETED:
+ setIncidence( 0, date );
+ break;
}
}
}
+void KOEventViewer::contentsContextMenuEvent( TQContextMenuEvent *e )
+{
+ TQString name = UriHandler::attachmentNameFromUri( mAttachLink );
+ TQString uid = UriHandler::uidFromUri( mAttachLink );
+ if ( name.isEmpty() || uid.isEmpty() ) {
+ TQTextBrowser::contentsContextMenuEvent( e );
+ return;
+ }
+
+ KPopupMenu *menu = new KPopupMenu();
+ menu->insertItem( i18n( "Open Attachment" ), 0 );
+ menu->insertItem( i18n( "Save Attachment As..." ), 1 );
+
+ switch( menu->exec( TQCursor::pos(), 0 ) ) {
+ case 0: // open
+ AttachmentHandler::view( parentWidget(), name, uid );
+ break;
+ case 1: // save as
+ AttachmentHandler::saveAs( parentWidget(), name, uid );
+ break;
+ default:
+ break;
+ }
+}
+
#include "koeventviewer.moc"
diff --git a/korganizer/koeventviewer.h b/korganizer/koeventviewer.h
index 80b1ef772..c4022d026 100644
--- a/korganizer/koeventviewer.h
+++ b/korganizer/koeventviewer.h
@@ -24,15 +24,13 @@
#ifndef KOEVENTVIEWER_H
#define KOEVENTVIEWER_H
-#include <tqtextbrowser.h>
#include <kdepimmacros.h>
-
#include <kconfig.h>
+#include <tqtextbrowser.h>
+
namespace KCal {
-class Incidence;
-class Todo;
-class Event;
-class Journal;
+ class Calendar;
+ class Incidence;
}
using namespace KCal;
@@ -41,18 +39,23 @@ using namespace KCal;
*/
class KDE_EXPORT KOEventViewer : public QTextBrowser
{
- Q_OBJECT
+ Q_OBJECT
public:
- KOEventViewer( TQWidget *parent = 0, const char *name = 0 );
+ explicit KOEventViewer( Calendar *calendar, TQWidget *parent = 0, const char *name = 0 );
virtual ~KOEventViewer();
/**
Reimplemented from TQTextBrowser to handle links.
*/
void setSource( const TQString & );
-
- virtual bool appendIncidence( Incidence * );
-
+
+ virtual bool appendIncidence( Incidence *incidence, const TQDate &date );
+
+ /**
+ Set the Calendar associated with this viewer.
+ */
+ void setCalendar ( Calendar *calendar );
+
/**
Clear viewer. If \a now is set to true delete view immediately. If set to
false delete it with next call to appendIncidence().
@@ -61,30 +64,35 @@ class KDE_EXPORT KOEventViewer : public QTextBrowser
/**
Add given text to currently shown content.
- */
-
+ */
+
void addText( const TQString &text );
-
+
/**
- Set the default text that is showed when
+ Set the default text that is showed when
there aren't a incidence to show
*/
void setDefaultText( const TQString &text );
-
- void readSettings( KConfig *config);
- void writeSettings ( KConfig *config);
-
+
+ void readSettings( KConfig *config );
+ void writeSettings ( KConfig *config );
+
public slots:
/**
Show given incidence in viewer. Clear all previously shown incidences.
*/
- virtual void setIncidence( Incidence * );
- void changeIncidenceDisplay( Incidence *incidence, int action );
+ void setIncidence( Incidence *incidence, const TQDate &date );
+ void changeIncidenceDisplay( Incidence *incidence, const TQDate &date, int action );
+ void message( const TQString &link );
+ void contentsContextMenuEvent( TQContextMenuEvent * );
+
private:
+ Calendar *mCalendar;
Incidence *mIncidence;
TQTextBrowser *mEventTextView;
TQString mDefaultText;
TQString mText;
+ TQString mAttachLink;
};
#endif
diff --git a/korganizer/koeventviewerdialog.cpp b/korganizer/koeventviewerdialog.cpp
index a51e5bccb..d88aa31c2 100644
--- a/korganizer/koeventviewerdialog.cpp
+++ b/korganizer/koeventviewerdialog.cpp
@@ -28,21 +28,20 @@
#include <klocale.h>
-KOEventViewerDialog::KOEventViewerDialog( TQWidget *parent, const char *name,
- bool compact )
+KOEventViewerDialog::KOEventViewerDialog( Calendar *calendar, TQWidget *parent,
+ const char *name, bool compact )
: KDialogBase( parent, name, false, i18n("Event Viewer"), Ok, Ok, false,
i18n("Edit") )
{
- mEventViewer = new KOEventViewer( this );
+ mEventViewer = new KOEventViewer( calendar, this );
setMainWidget( mEventViewer );
- // FIXME: Set a sensible size (based on the content?).
if ( compact ) {
setFixedSize( 240,284 );
move( 0, 15 );
} else {
- setMinimumSize( 300, 200 );
- resize( 320, 300 );
+ setMinimumSize( 500, 500 );
+ resize( 520, 500 );
}
connect( this, TQT_SIGNAL(finished()), this, TQT_SLOT(delayedDestruct()) );
}
@@ -51,9 +50,14 @@ KOEventViewerDialog::~KOEventViewerDialog()
{
}
+void KOEventViewerDialog::setCalendar( Calendar *calendar )
+{
+ mEventViewer->setCalendar( calendar );
+}
+
void KOEventViewerDialog::addText( const TQString &text )
{
- mEventViewer->addText(text);
+ mEventViewer->addText( text );
}
#include "koeventviewerdialog.moc"
diff --git a/korganizer/koeventviewerdialog.h b/korganizer/koeventviewerdialog.h
index e14c6bafd..dc0ceb7b7 100644
--- a/korganizer/koeventviewerdialog.h
+++ b/korganizer/koeventviewerdialog.h
@@ -42,13 +42,20 @@ class KDE_EXPORT KOEventViewerDialog : public KDialogBase
{
Q_OBJECT
public:
- KOEventViewerDialog( TQWidget *parent = 0, const char *name = 0,
- bool compact = false );
+ explicit KOEventViewerDialog( Calendar *calendar, TQWidget *parent = 0,
+ const char *name = 0, bool compact = false );
virtual ~KOEventViewerDialog();
- void setIncidence( Incidence *incidence ) { mEventViewer->setIncidence( incidence ); }
- void appendIncidence( Incidence *incidence ) { mEventViewer->appendIncidence( incidence ); }
+ void setIncidence( Incidence *incidence, const TQDate &date )
+ {
+ mEventViewer->setIncidence( incidence, date );
+ }
+ void appendIncidence( Incidence *incidence, const TQDate &date )
+ {
+ mEventViewer->appendIncidence( incidence, date );
+ }
+ void setCalendar( Calendar *calendar );
void addText( const TQString &text );
private:
diff --git a/korganizer/koglobals.h b/korganizer/koglobals.h
index 771588101..119eb6c1d 100644
--- a/korganizer/koglobals.h
+++ b/korganizer/koglobals.h
@@ -24,7 +24,9 @@
#define KORG_GLOBALS_H
#include <kdepimmacros.h>
+#include <tqwidget.h>
+class TQDate;
class TQPixmap;
class TQIconSet;
class KCalendarSystem;
@@ -39,11 +41,40 @@ class KDE_EXPORT KOGlobals
public:
static KOGlobals *self();
- enum { INCIDENCEADDED, INCIDENCEEDITED, INCIDENCEDELETED };
- enum { PRIORITY_MODIFIED, COMPLETION_MODIFIED, CATEGORY_MODIFIED,
- DATE_MODIFIED, RELATION_MODIFIED, ALARM_MODIFIED,
- DESCRIPTION_MODIFIED, SUMMARY_MODIFIED,
- COMPLETION_MODIFIED_WITH_RECURRENCE, UNKNOWN_MODIFIED };
+ enum HowChanged {
+ INCIDENCEADDED,
+ INCIDENCEEDITED,
+ INCIDENCEDELETED,
+ NOCHANGE
+ };
+ enum WhatChanged {
+ PRIORITY_MODIFIED,
+ COMPLETION_MODIFIED,
+ CATEGORY_MODIFIED,
+ DATE_MODIFIED,
+ RELATION_MODIFIED,
+ ALARM_MODIFIED,
+ DESCRIPTION_MODIFIED,
+ SUMMARY_MODIFIED,
+ COMPLETION_MODIFIED_WITH_RECURRENCE,
+ RECURRENCE_MODIFIED_ONE_ONLY,
+ RECURRENCE_MODIFIED_ALL_FUTURE,
+ UNKNOWN_MODIFIED,
+ NOTHING_MODIFIED
+ };
+
+ enum WhichOccurrences {
+ NONE,
+ ONLY_THIS_ONE,
+ ONLY_FUTURE,
+ ALL
+ };
+
+ enum OccurrenceAction {
+ CUT,
+ COPY,
+ EDIT
+ };
static void fitDialogToScreen( TQWidget *widget, bool force=false );
KConfig *config() const;
diff --git a/korganizer/kogroupware.cpp b/korganizer/kogroupware.cpp
index 7b017cc4d..0edcdc9c7 100644
--- a/korganizer/kogroupware.cpp
+++ b/korganizer/kogroupware.cpp
@@ -73,8 +73,8 @@ KOGroupware *KOGroupware::instance()
}
- KOGroupware::KOGroupware( CalendarView* view, KCal::CalendarResources* cal )
- : TQObject( 0, "kmgroupware_instance" ), mView( view ), mCalendar( cal )
+KOGroupware::KOGroupware( CalendarView* view, KCal::CalendarResources* cal )
+ : TQObject( 0, "kmgroupware_instance" ), mView( view ), mCalendar( cal ), mDoNotNotify( false )
{
// Set up the dir watch of the three incoming dirs
KDirWatch* watcher = KDirWatch::self();
@@ -105,10 +105,8 @@ void KOGroupware::slotViewNewIncidenceChanger( IncidenceChangerBase* changer )
// Call slot perhapsUploadFB if an incidence was added, changed or removed
connect( changer, TQT_SIGNAL( incidenceAdded( Incidence* ) ),
mFreeBusyManager, TQT_SLOT( slotPerhapsUploadFB() ) );
- connect( changer, TQT_SIGNAL( incidenceChanged( Incidence*, Incidence*, int ) ),
+ connect( changer, TQT_SIGNAL( incidenceChanged( Incidence*, Incidence*, KOGlobals::WhatChanged ) ),
mFreeBusyManager, TQT_SLOT( slotPerhapsUploadFB() ) );
- connect( changer, TQT_SIGNAL( incidenceChanged( Incidence*, Incidence* ) ),
- mFreeBusyManager, TQT_SLOT( slotPerhapsUploadFB() ) ) ;
connect( changer, TQT_SIGNAL( incidenceDeleted( Incidence * ) ),
mFreeBusyManager, TQT_SLOT( slotPerhapsUploadFB() ) );
}
@@ -179,6 +177,10 @@ void KOGroupware::incomingDirChanged( const TQString& path )
KCal::ScheduleMessage::Status status = message->status();
KCal::Incidence* incidence =
dynamic_cast<KCal::Incidence*>( message->event() );
+ if(!incidence) {
+ delete message;
+ return;
+ }
KCal::MailScheduler scheduler( mCalendar );
if ( action.startsWith( "accepted" ) || action.startsWith( "tentative" )
|| action.startsWith( "delegated" ) || action.startsWith( "counter" ) ) {
@@ -200,10 +202,10 @@ void KOGroupware::incomingDirChanged( const TQString& path )
}
}
if ( KOPrefs::instance()->outlookCompatCounterProposals() || !action.startsWith( "counter" ) )
- scheduler.acceptTransaction( incidence, method, status );
+ scheduler.acceptTransaction( incidence, method, status, receiver );
} else if ( action.startsWith( "cancel" ) )
// Delete the old incidence, if one is present
- scheduler.acceptTransaction( incidence, KCal::Scheduler::Cancel, status );
+ scheduler.acceptTransaction( incidence, KCal::Scheduler::Cancel, status, receiver );
else if ( action.startsWith( "reply" ) ) {
if ( method != Scheduler::Counter ) {
scheduler.acceptTransaction( incidence, method, status );
@@ -211,13 +213,13 @@ void KOGroupware::incomingDirChanged( const TQString& path )
// accept counter proposal
scheduler.acceptCounterProposal( incidence );
// send update to all attendees
- sendICalMessage( mView, Scheduler::Request, incidence );
+ sendICalMessage( mView, Scheduler::Request, incidence, KOGlobals::INCIDENCEEDITED, false );
}
} else
kdError(5850) << "Unknown incoming action " << action << endl;
if ( action.startsWith( "counter" ) ) {
- mView->editIncidence( incidence, true );
+ mView->editIncidence( incidence, TQDate(), true );
KOIncidenceEditor *tmp = mView->editorDialog( incidence );
tmp->selectInvitationCounterProposal( true );
}
@@ -238,8 +240,9 @@ class KOInvitationFormatterHelper : public InvitationFormatterHelper
*/
bool KOGroupware::sendICalMessage( TQWidget* parent,
KCal::Scheduler::Method method,
- Incidence* incidence, bool isDeleting,
- bool statusChanged )
+ Incidence* incidence,
+ KOGlobals::HowChanged action,
+ bool attendeeStatusChanged )
{
// If there are no attendees, don't bother
if( incidence->attendees().isEmpty() )
@@ -267,16 +270,48 @@ bool KOGroupware::sendICalMessage( TQWidget* parent,
* mail. */
if ( incidence->attendees().count() > 1
|| incidence->attendees().first()->email() != incidence->organizer().email() ) {
- TQString type;
- if( incidence->type() == "Event") type = i18n("event");
- else if( incidence->type() == "Todo" ) type = i18n("task");
- else if( incidence->type() == "Journal" ) type = i18n("journal entry");
- else type = incidence->type();
- TQString txt = i18n( "This %1 includes other people. "
- "Should email be sent out to the attendees?" )
- .arg( type );
- rc = KMessageBox::questionYesNoCancel( parent, txt,
- i18n("Group Scheduling Email"), i18n("Send Email"), i18n("Do Not Send") );
+
+ TQString txt;
+ switch( action ) {
+ case KOGlobals::INCIDENCEEDITED:
+ txt = i18n( "You changed the invitation \"%1\".\n"
+ "Do you want to email the attendees an update message?" ).
+ arg( incidence->summary() );
+ break;
+ case KOGlobals::INCIDENCEDELETED:
+ Q_ASSERT( incidence->type() == "Event" || incidence->type() == "Todo" );
+ if ( incidence->type() == "Event" ) {
+ txt = i18n( "You removed the invitation \"%1\".\n"
+ "Do you want to email the attendees that the event is canceled?" ).
+ arg( incidence->summary() );
+ } else if ( incidence->type() == "Todo" ) {
+ txt = i18n( "You removed the invitation \"%1\".\n"
+ "Do you want to email the attendees that the todo is canceled?" ).
+ arg( incidence->summary() );
+ }
+ break;
+ case KOGlobals::INCIDENCEADDED:
+ if ( incidence->type() == "Event" ) {
+ txt = i18n( "The event \"%1\" includes other people.\n"
+ "Do you want to email the invitation to the attendees?" ).
+ arg( incidence->summary() );
+ } else if ( incidence->type() == "Todo" ) {
+ txt = i18n( "The todo \"%1\" includes other people.\n"
+ "Do you want to email the invitation to the attendees?" ).
+ arg( incidence->summary() );
+ } else {
+ txt = i18n( "This incidence includes other people. "
+ "Should an email be sent to the attendees?" );
+ }
+ break;
+ default:
+ kdError() << "Unsupported HowChanged action" << int( action ) << endl;
+ break;
+ }
+
+ rc = KMessageBox::questionYesNo(
+ parent, txt, i18n( "Group Scheduling Email" ),
+ KGuiItem( i18n( "Send Email" ) ), KGuiItem( i18n( "Do Not Send" ) ) );
} else {
return true;
}
@@ -291,32 +326,49 @@ bool KOGroupware::sendICalMessage( TQWidget* parent,
rc = KMessageBox::questionYesNo( parent, txt, TQString::null, i18n("Send Update"), i18n("Do Not Send") );
} else if( incidence->type() == "Event" ) {
TQString txt;
- if ( statusChanged && method == Scheduler::Request ) {
- txt = i18n( "Your status as an attendee of this event "
- "changed. Do you want to send a status update to the "
- "organizer of this event?" );
+ if ( attendeeStatusChanged && method == Scheduler::Request ) {
+ txt = i18n( "Your status as an attendee of this event changed. "
+ "Do you want to send a status update to the event organizer?" );
method = Scheduler::Reply;
rc = KMessageBox::questionYesNo( parent, txt, TQString::null, i18n("Send Update"), i18n("Do Not Send") );
} else {
- if( isDeleting )
- txt = i18n( "You are not the organizer of this event. "
- "Deleting it will bring your calendar out of sync "
- "with the organizers calendar. Do you really want "
- "to delete it?" );
- else
- txt = i18n( "You are not the organizer of this event. "
- "Editing it will bring your calendar out of sync "
- "with the organizers calendar. Do you really want "
- "to edit it?" );
- rc = KMessageBox::warningYesNo( parent, txt );
- return ( rc == KMessageBox::Yes );
+ if( action == KOGlobals::INCIDENCEDELETED ) {
+ const TQStringList myEmails = KOPrefs::instance()->allEmails();
+ bool askConfirmation = false;
+ for ( TQStringList::ConstIterator it = myEmails.begin(); it != myEmails.end(); ++it ) {
+ TQString email = *it;
+ Attendee *me = incidence->attendeeByMail(email);
+ if (me && (me->status()==KCal::Attendee::Accepted || me->status()==KCal::Attendee::Delegated)) {
+ askConfirmation = true;
+ break;
+ }
+ }
+
+ if ( !askConfirmation ) {
+ return true;
+ }
+
+ txt = i18n( "You had previously accepted an invitation to this event. "
+ "Do you want to send an updated response to the organizer "
+ "declining the invitation?" );
+ rc = KMessageBox::questionYesNo(
+ parent, txt, i18n( "Group Scheduling Email" ),
+ KGuiItem( i18n( "Send Update" ) ), KGuiItem( i18n( "Do Not Send" ) ) );
+ setDoNotNotify( rc == KMessageBox::No );
+ } else {
+ txt = i18n( "You are not the organizer of this event. Editing it will "
+ "bring your calendar out of sync with the organizer's calendar. "
+ "Do you really want to edit it?" );
+ rc = KMessageBox::warningYesNo( parent, txt );
+ return ( rc == KMessageBox::Yes );
+ }
}
} else {
kdWarning(5850) << "Groupware messages for Journals are not implemented yet!" << endl;
return true;
}
- if( rc == KMessageBox::Yes ) {
+ if ( rc == KMessageBox::Yes ) {
// We will be sending out a message here. Now make sure there is
// some summary
if( incidence->summary().isEmpty() )
@@ -327,10 +379,11 @@ bool KOGroupware::sendICalMessage( TQWidget* parent,
scheduler.performTransaction( incidence, method );
return true;
- } else if( rc == KMessageBox::No )
+ } else if ( rc == KMessageBox::No ) {
return true;
- else
+ } else {
return false;
+ }
}
void KOGroupware::sendCounterProposal(KCal::Calendar *calendar, KCal::Event * oldEvent, KCal::Event * newEvent) const
@@ -341,7 +394,9 @@ void KOGroupware::sendCounterProposal(KCal::Calendar *calendar, KCal::Event * ol
Incidence* tmp = oldEvent->clone();
tmp->setSummary( i18n("Counter proposal: %1").arg( newEvent->summary() ) );
tmp->setDescription( newEvent->description() );
- tmp->addComment( i18n("Proposed new meeting time: %1 - %2").arg( newEvent->dtStartStr(), newEvent->dtEndStr() ) );
+ tmp->addComment( i18n("Proposed new meeting time: %1 - %2").
+ arg( IncidenceFormatter::dateToString( newEvent->dtStart() ),
+ IncidenceFormatter::dateToString( newEvent->dtEnd() ) ) );
KCal::MailScheduler scheduler( calendar );
scheduler.performTransaction( tmp, Scheduler::Reply );
delete tmp;
diff --git a/korganizer/kogroupware.h b/korganizer/kogroupware.h
index 0af6a3c42..f6695de07 100644
--- a/korganizer/kogroupware.h
+++ b/korganizer/kogroupware.h
@@ -37,13 +37,16 @@
#ifndef KOGROUPWARE_H
#define KOGROUPWARE_H
+#include "koglobals.h"
+
#include <libkcal/calendarresources.h>
#include <libkcal/icalformat.h>
#include <libkcal/scheduler.h>
-#include <tqstring.h>
#include <kio/job.h>
+#include <tqstring.h>
+
using namespace KCal;
namespace KCal {
@@ -72,9 +75,10 @@ class KOGroupware : public QObject
Returns false if the user cancels the dialog, and true if the
user presses Yes og or No.
*/
- bool sendICalMessage( TQWidget* parent, KCal::Scheduler::Method method,
- Incidence* incidence, bool isDeleting = false,
- bool statusChanged = false );
+ bool sendICalMessage( TQWidget *parent, KCal::Scheduler::Method method,
+ Incidence* incidence,
+ KOGlobals::HowChanged action,
+ bool attendeeStatusChanged );
/**
Send counter proposal message.
@@ -83,12 +87,14 @@ class KOGroupware : public QObject
*/
void sendCounterProposal( KCal::Calendar* calendar, KCal::Event* oldEvent, KCal::Event *newEvent ) const;
- // THIS IS THE ACTUAL KM/KO API
- enum EventState { Accepted, ConditionallyAccepted, Declined, Request };
-
// convert the TNEF attachment to a vCard or iCalendar part
TQString msTNEFToVPart( const TQByteArray& tnef );
+ // DoNotNotify is a flag indicating that the user does not want
+ // updates sent back to the organizer.
+ void setDoNotNotify( bool notify ) { mDoNotNotify = notify; }
+ bool doNotNotify() { return mDoNotNotify; }
+
private slots:
/** Handle iCals given by KMail. */
void incomingDirChanged( const TQString& path );
@@ -106,6 +112,7 @@ class KOGroupware : public QObject
CalendarView *mView;
KCal::CalendarResources *mCalendar;
static FreeBusyManager *mFreeBusyManager;
+ bool mDoNotNotify;
};
#endif
diff --git a/korganizer/kogroupwareprefspage.ui b/korganizer/kogroupwareprefspage.ui
index d6f14f9ad..a4e558fbf 100644
--- a/korganizer/kogroupwareprefspage.ui
+++ b/korganizer/kogroupwareprefspage.ui
@@ -39,7 +39,7 @@
<cstring>TextLabel1</cstring>
</property>
<property name="text">
- <string>By publishing Free/Busy information, you allow others to take your calendar into account when inviting you for a meeting. Only the times you have already busy are published, not why they are busy.</string>
+ <string>By publishing Free/Busy information, you allow others to take your calendar into account when inviting you for a meeting. Only the times you have already busy are published, not why they are busy. For Kolab2 Server leave this disabled (the information is generated on the server).</string>
</property>
<property name="alignment">
<set>WordBreak|AlignVCenter</set>
@@ -182,8 +182,7 @@ Note: If KOrganizer is acting as a KDE Kolab client, this is not required, as th
</property>
<property name="whatsThis" stdset="0">
<string>Enter the URL for the server on which your Free/Busy information shall be published here.
-Ask the server administrator for this information.
-Here is a Kolab2 server URL example: "webdavs://kolab2.com/freebusy/joe@kolab2.com.ifb"</string>
+Ask the server administrator for this information.</string>
</property>
</widget>
<widget class="QCheckBox" row="7" column="0" rowspan="1" colspan="2">
@@ -278,8 +277,7 @@ A Kolab2 server specificity: Registered your UID (Unique IDentifier). By default
</property>
<property name="whatsThis" stdset="0">
<string>Enter the URL for the server on which your Free/Busy information shall be published here.
-Ask the server administrator for this information.
-Here is a Kolab2 server URL example: "webdavs://kolab2.com/freebusy/joe@kolab2.com.ifb"</string>
+Ask the server administrator for this information.</string>
</property>
</widget>
</grid>
@@ -385,9 +383,11 @@ Here is a Kolab2 server URL example: "webdavs://kolab2.com/freebusy/joe@kolab2.c
<property name="whatsThis" stdset="0">
<string>Enter the URL for the server on which the Free/Busy information is published here.
Ask the server administrator for this information.
-Here is a Kolab2 server URL example: "webdavs://kolab2.com/freebusy/"
+Here is a Kolab2 Server URL example: "https://kolab2.example.com/freebusy/"
Here is a generic server example: "http://myserver.net/%u@%d/?internal.ics"
-%u expands to the username, and %d expands to the domain name.</string>
+%u expands to the username, and %d expands to the domain name.
+Alternatively, you can specify a full path to the Free/Busy file,
+For example: "https://kolab2.example.com/freebusy/user.xfb"</string>
</property>
</widget>
<widget class="QLineEdit">
@@ -400,9 +400,11 @@ Here is a generic server example: "http://myserver.net/%u@%d/?internal.ics"
<property name="whatsThis" stdset="0">
<string>Enter the URL for the server on which the Free/Busy information is published here.
Ask the server administrator for this information.
-Here is a Kolab2 server URL example: "webdavs://kolab2.com/freebusy/"
+Here is a Kolab2 Server URL example: "https://kolab2.example.com/freebusy/"
Here is a generic server example: "http://myserver.net/%u@%d/?internal.ics"
-%u expands to the username, and %d expands to the domain name.</string>
+%u expands to the username, and %d expands to the domain name.
+Alternatively, you can specify a full path to the Free/Busy file,
+For example: "https://kolab2.example.com/freebusy/user.xfb"</string>
</property>
</widget>
</hbox>
diff --git a/korganizer/kohelper.cpp b/korganizer/kohelper.cpp
index 827279fe4..3b7bd8776 100644
--- a/korganizer/kohelper.cpp
+++ b/korganizer/kohelper.cpp
@@ -62,23 +62,3 @@ TQColor KOHelper::resourceColor( KCal::Calendar*calendar, KCal::Incidence*incide
}
return resourceColor;
}
-
-TQString KOHelper::resourceLabel(KCal::Calendar * calendar, KCal::Incidence * incidence)
-{
- KCal::CalendarResources *calendarResource = dynamic_cast<KCal::CalendarResources*>( calendar );
- if ( !calendarResource || ! incidence )
- return TQString();
-
- KCal::ResourceCalendar *resourceCalendar = calendarResource->resource( incidence );
- if( resourceCalendar ) {
- if ( !resourceCalendar->subresources().isEmpty() ) {
- TQString subRes = resourceCalendar->subresourceIdentifier( incidence );
- if ( subRes.isEmpty() )
- return resourceCalendar->resourceName();
- return resourceCalendar->labelForSubresource( subRes );
- }
- return resourceCalendar->resourceName();
- }
-
- return TQString();
-}
diff --git a/korganizer/kohelper.h b/korganizer/kohelper.h
index b7f61b796..07d91058b 100644
--- a/korganizer/kohelper.h
+++ b/korganizer/kohelper.h
@@ -42,12 +42,6 @@ class KDE_EXPORT KOHelper
to a subresource, the color for the subresource is returned (if set).
*/
static TQColor resourceColor( KCal::Calendar*calendar, KCal::Incidence*incidence );
-
- /**
- Returns the resource label the given incidence belongs to.
- */
- static TQString resourceLabel( KCal::Calendar *calendar, KCal::Incidence *incidence );
-
};
#endif
diff --git a/korganizer/koincidenceeditor.cpp b/korganizer/koincidenceeditor.cpp
index 3eb4920f8..240497e19 100644
--- a/korganizer/koincidenceeditor.cpp
+++ b/korganizer/koincidenceeditor.cpp
@@ -45,6 +45,7 @@
#include <libkcal/calendarlocal.h>
#include <libkcal/incidence.h>
#include <libkcal/icalformat.h>
+#include <libkcal/resourcecalendar.h>
#include "koprefs.h"
#include "koglobals.h"
@@ -58,7 +59,8 @@ KOIncidenceEditor::KOIncidenceEditor( const TQString &caption,
Calendar *calendar, TQWidget *parent )
: KDialogBase( Tabbed, caption, Ok | Apply | Cancel | Default, Ok,
parent, 0, false, false ),
- mAttendeeEditor( 0 ), mIsCounter( false )
+ mAttendeeEditor( 0 ), mResource( 0 ), mIsCounter( false ), mIsCreateTask( false ),
+ mRecurIncidence( 0 ), mRecurIncidenceAfterDissoc( 0 )
{
// Set this to be the group leader for all subdialogs - this means
// modal subdialogs will only affect this dialog, not the other windows
@@ -349,14 +351,14 @@ void KOIncidenceEditor::createEmbeddedURLPages( Incidence *i )
void KOIncidenceEditor::openURL( const KURL &url )
{
TQString uri = url.url();
- UriHandler::process( uri );
+ UriHandler::process( this, uri );
}
void KOIncidenceEditor::addAttachments( const TQStringList &attachments,
const TQStringList &mimeTypes,
bool inlineAttachments )
{
- emit signalAddAttachments( attachments, mimeTypes, inlineAttachments );
+ emit signalAddAttachments( attachments, mimeTypes, inlineAttachments );
}
void KOIncidenceEditor::addAttendees( const TQStringList &attendees )
@@ -365,7 +367,33 @@ void KOIncidenceEditor::addAttendees( const TQStringList &attendees )
for ( it = attendees.begin(); it != attendees.end(); ++it ) {
TQString name, email;
KABC::Addressee::parseEmailAddress( *it, name, email );
- mAttendeeEditor->insertAttendee( new Attendee( name, email ) );
+ mAttendeeEditor->insertAttendee( new Attendee( name, email, true, Attendee::NeedsAction ) );
+ }
+}
+
+void KOIncidenceEditor::setResource( ResourceCalendar *res, const TQString &subRes )
+{
+ TQString label;
+ if ( res ) {
+ if ( !res->subresources().isEmpty() && !subRes.isEmpty() ) {
+ label = res->labelForSubresource( subRes );
+ } else {
+ label = res->resourceName();
+ }
+ }
+
+ mResource = res;
+ mSubResource = subRes;
+}
+
+
+void KOIncidenceEditor::selectCreateTask( bool enable )
+{
+ mIsCreateTask = enable;
+ if ( mIsCreateTask ) {
+ setCaption( i18n( "Create to-do" ) );
+ setButtonOK( i18n( "Create to-do" ) );
+ showButtonApply( false );
}
}
@@ -375,9 +403,16 @@ void KOIncidenceEditor::selectInvitationCounterProposal(bool enable)
if ( mIsCounter ) {
setCaption( i18n( "Counter proposal" ) );
setButtonOK( i18n( "Counter proposal" ) );
- enableButtonApply( false );
+ showButtonApply( false );
}
}
+void KOIncidenceEditor::setRecurringIncidence ( Incidence *originalIncidence,
+ Incidence *incAfterDissociation )
+{
+ mRecurIncidence = originalIncidence;
+ mRecurIncidenceAfterDissoc = incAfterDissociation;
+}
+
#include "koincidenceeditor.moc"
diff --git a/korganizer/koincidenceeditor.h b/korganizer/koincidenceeditor.h
index 35c4c45ba..91f22afdd 100644
--- a/korganizer/koincidenceeditor.h
+++ b/korganizer/koincidenceeditor.h
@@ -28,6 +28,7 @@
#include <kdialogbase.h>
#include <kurl.h>
+class TQDate;
class TQDateTime;
namespace KPIM {
@@ -42,9 +43,10 @@ class KOEditorDetails;
class KOAttendeeEditor;
namespace KCal {
-class Calendar;
-class CalendarLocal;
-class Incidence;
+ class Calendar;
+ class CalendarLocal;
+ class Incidence;
+ class ResourceCalendar;
}
using namespace KCal;
using namespace KOrg;
@@ -54,7 +56,7 @@ using namespace KOrg;
*/
class KOIncidenceEditor : public KDialogBase
{
- Q_OBJECT
+ Q_OBJECT
public:
/**
Construct new IncidenceEditor.
@@ -64,15 +66,31 @@ class KOIncidenceEditor : public KDialogBase
virtual ~KOIncidenceEditor();
/** This incidence has been modified externally */
- virtual void modified (int /*change*/=0) {}
+ virtual void modified() {}
virtual void reload() = 0;
+ virtual void setResource( ResourceCalendar *res, const TQString &subRes );
virtual void selectInvitationCounterProposal( bool enable );
+ virtual void selectCreateTask( bool enable );
+
+ /**
+ This should be called when editing only one occurrence of a recurring incidence,
+ before showing the editor.
+
+ It gives the editor a pointer to the original incidence, which contains all occurrences
+ and a pointer to the original incidence already dissociated from the event (mEvent).
+
+ If the user presses ok/apply the changes made to the incAfterDissociation are commited
+ to the callendar through mChanger.
+
+ If the user presses cancel we restore originalIncidence and all dissociations are discarded
+ */
+ void setRecurringIncidence( Incidence *originalIncidence, Incidence *incAfterDissociation );
public slots:
/** Edit an existing todo. */
- virtual void editIncidence(Incidence *, Calendar *) = 0;
+ virtual void editIncidence(Incidence *, const TQDate &, Calendar *) = 0;
virtual void setIncidenceChanger( IncidenceChangerBase *changer ) {
mChanger = changer; }
/** Initialize editor. This function creates the tab widgets. */
@@ -88,7 +106,6 @@ class KOIncidenceEditor : public KDialogBase
*/
void addAttendees( const TQStringList &attendees );
-
signals:
void deleteAttendee( Incidence * );
@@ -153,7 +170,14 @@ class KOIncidenceEditor : public KDialogBase
TQMap<TQWidget*, KPIM::DesignerFields*> mDesignerFieldForWidget;
TQPtrList<TQWidget> mEmbeddedURLPages;
TQPtrList<TQWidget> mAttachedDesignerFields;
+ ResourceCalendar *mResource;
+ TQString mSubResource;
bool mIsCounter;
+ bool mIsCreateTask;
+
+ Incidence *mRecurIncidence;
+ Incidence *mRecurIncidenceAfterDissoc;
+
};
#endif
diff --git a/korganizer/koincidencetooltip.cpp b/korganizer/koincidencetooltip.cpp
index 8b3f11756..2b2a80f29 100644
--- a/korganizer/koincidencetooltip.cpp
+++ b/korganizer/koincidencetooltip.cpp
@@ -33,19 +33,24 @@
some improvements by Mikolaj Machowski
*/
-void KOIncidenceToolTip::add ( TQWidget * widget, Incidence *incidence,
- TQToolTipGroup * group, const TQString & longText )
+void KOIncidenceToolTip::add ( TQWidget *widget, Calendar *calendar,
+ Incidence *incidence, const TQDate &date,
+ TQToolTipGroup *group, const TQString &longText )
{
- if ( !widget || !incidence ) return;
- TQToolTip::add(widget, IncidenceFormatter::toolTipString( incidence ), group, longText);
+ if ( !widget || !incidence ) {
+ return;
+ }
+ TQToolTip::add( widget, IncidenceFormatter::toolTipStr( calendar, incidence, date ), group, longText );
}
-void KOIncidenceToolTip::add(KOAgendaItem * item, Incidence * incidence, TQToolTipGroup * group)
+void KOIncidenceToolTip::add( KOAgendaItem *item, Calendar *calendar,
+ Incidence *incidence, const TQDate &date,
+ TQToolTipGroup *group )
{
Q_UNUSED( incidence );
Q_UNUSED( group );
TQToolTip::remove( item );
- new KOIncidenceToolTip( item );
+ new KOIncidenceToolTip( item, calendar, date );
}
void KOIncidenceToolTip::maybeTip(const TQPoint & pos)
@@ -55,6 +60,6 @@ void KOIncidenceToolTip::maybeTip(const TQPoint & pos)
if ( !item )
return;
if ( !mText )
- mText = IncidenceFormatter::toolTipString( item->incidence() );
+ mText = IncidenceFormatter::toolTipStr( mCalendar, item->incidence(), mDate );
tip( TQRect( TQPoint( 0, 0 ), item->size() ), mText );
}
diff --git a/korganizer/koincidencetooltip.h b/korganizer/koincidencetooltip.h
index 11b5d39a3..348ab890b 100644
--- a/korganizer/koincidencetooltip.h
+++ b/korganizer/koincidencetooltip.h
@@ -27,6 +27,7 @@
namespace KCal
{
+class Calendar;
class Incidence;
}
using namespace KCal;
@@ -39,19 +40,24 @@ class KOAgendaItem;
class KOIncidenceToolTip : public QToolTip
{
public:
- KOIncidenceToolTip(TQWidget * widget, TQToolTipGroup * group = 0 ):TQToolTip (widget, group),mText(0) {}
+ KOIncidenceToolTip( TQWidget *widget, Calendar *calendar, const TQDate &date, TQToolTipGroup *group = 0 )
+ : TQToolTip (widget, group), mCalendar( calendar ), mDate( date ), mText(0) {}
/* ~KOIncidenceToolTip();*/
public:
- static void add ( TQWidget * widget, Incidence *incidence,
- TQToolTipGroup * group = 0, const TQString & longText = "" );
- static void add( KOAgendaItem *item, Incidence *incidence = 0,
+ static void add ( TQWidget *widget, Calendar *calendar,
+ Incidence *incidence, const TQDate &date=TQDate(),
+ TQToolTipGroup *group = 0, const TQString &longText = "" );
+ static void add( KOAgendaItem *item, Calendar *calendar,
+ Incidence *incidence = 0, const TQDate &date=TQDate(),
TQToolTipGroup *group = 0 );
/* reimplmented from TQToolTip */
void maybeTip( const TQPoint &pos );
private:
+ Calendar *mCalendar;
+ TQDate mDate;
TQString mText;
};
diff --git a/korganizer/kojournaleditor.cpp b/korganizer/kojournaleditor.cpp
index a50ba1fe2..b53e071ee 100644
--- a/korganizer/kojournaleditor.cpp
+++ b/korganizer/kojournaleditor.cpp
@@ -62,8 +62,10 @@ void KOJournalEditor::init()
void KOJournalEditor::reload()
{
- kdDebug(5851)<<"reloading Journal"<<endl;
- if ( mJournal ) readJournal( mJournal );
+ kdDebug(5851) << "reloading Journal" << endl;
+ if ( mJournal ) {
+ readJournal( mJournal, TQDate() );
+ }
}
void KOJournalEditor::setupGeneral()
@@ -94,7 +96,7 @@ void KOJournalEditor::setupGeneral()
mGeneral->finishSetup();
}
-void KOJournalEditor::editIncidence( Incidence *incidence, Calendar * )
+void KOJournalEditor::editIncidence( Incidence *incidence, const TQDate &date, Calendar * )
{
Journal *journal=dynamic_cast<Journal*>(incidence);
if (journal)
@@ -102,7 +104,7 @@ void KOJournalEditor::editIncidence( Incidence *incidence, Calendar * )
init();
mJournal = journal;
- readJournal(mJournal);
+ readJournal(mJournal, date);
}
}
@@ -140,7 +142,7 @@ bool KOJournalEditor::processInput()
if ( mJournal ) {
Journal *oldJournal = mJournal->clone();
writeJournal( mJournal );
- mChanger->changeIncidence( oldJournal, mJournal );
+ mChanger->changeIncidence( oldJournal, mJournal, KOGlobals::NOTHING_MODIFIED, this );
delete oldJournal;
} else {
mJournal = new Journal;
@@ -149,8 +151,7 @@ bool KOJournalEditor::processInput()
writeJournal( mJournal );
- if ( !mChanger->addIncidence( mJournal, this ) ) {
- KODialogManager::errorSaveIncidence( this, mJournal );
+ if ( !mChanger->addIncidence( mJournal, mResource, mSubResource, this ) ) {
delete mJournal;
mJournal = 0;
return false;
@@ -176,10 +177,10 @@ void KOJournalEditor::setDate( const TQDate &date )
mDetails->setDefaults();
}
-void KOJournalEditor::readJournal( Journal *journal )
+void KOJournalEditor::readJournal( Journal *journal, const TQDate &date )
{
kdDebug(5851)<<"read Journal"<<endl;
- mGeneral->readJournal( journal );
+ mGeneral->readJournal( journal, date );
mDetails->readEvent( journal );
}
@@ -201,10 +202,10 @@ int KOJournalEditor::msgItemDelete()
i18n("KOrganizer Confirmation"), KGuiItem( i18n("Delete"), "editdelete" ));
}
-void KOJournalEditor::modified( int /*modification*/)
+void KOJournalEditor::modified()
{
- // Play dump, just reload the Journal. This dialog has become so complicated that
- // there is no point in trying to be smart here...
+ // Play dump, just reload the Journal. This dialog has become so complicated
+ // that there is no point in trying to be smart here...
reload();
}
@@ -215,7 +216,7 @@ void KOJournalEditor::loadTemplate( /*const*/ CalendarLocal& cal)
KMessageBox::error( this,
i18n("Template does not contain a valid journal.") );
} else {
- readJournal( journals.first() );
+ readJournal( journals.first(), TQDate() );
}
}
diff --git a/korganizer/kojournaleditor.h b/korganizer/kojournaleditor.h
index 75edb1829..291940cf0 100644
--- a/korganizer/kojournaleditor.h
+++ b/korganizer/kojournaleditor.h
@@ -69,12 +69,12 @@ class KOJournalEditor : public KOIncidenceEditor
*/
void setTexts( const TQString &summary, const TQString &description = TQString::null );
/** Edit an existing Journal. */
- void editIncidence(Incidence *, Calendar *);
+ void editIncidence(Incidence *, const TQDate &date, Calendar *);
/** Set widgets to default values */
void setDate( const TQDate &date );
/** Read event object and setup widgets accordingly */
- void readJournal( Journal * );
+ void readJournal( Journal *, const TQDate &date );
/** Write event settings to event object */
void writeJournal( Journal * );
@@ -86,7 +86,7 @@ class KOJournalEditor : public KOIncidenceEditor
bool processInput();
/** This Journal has been modified externally */
- void modified (int change=0);
+ void modified();
protected slots:
void loadDefaults();
diff --git a/korganizer/kojournalview.cpp b/korganizer/kojournalview.cpp
index e8de3daed..74a0f17cd 100644
--- a/korganizer/kojournalview.cpp
+++ b/korganizer/kojournalview.cpp
@@ -71,20 +71,24 @@ void KOJournalView::appendJournal( Journal*journal, const TQDate &dt)
entry->setDate( dt );
entry->setIncidenceChanger( mChanger );
entry->show();
- connect( this, TQT_SIGNAL(flushEntries()), entry, TQT_SIGNAL(flushEntries()) );
- connect( this, TQT_SIGNAL(setIncidenceChangerSignal( IncidenceChangerBase * ) ),
- entry, TQT_SLOT(setIncidenceChanger( IncidenceChangerBase * ) ) );
- connect( this, TQT_SIGNAL( journalEdited( Journal* ) ),
- entry, TQT_SLOT( journalEdited( Journal* ) ) );
- connect( this, TQT_SIGNAL( journalDeleted( Journal* ) ),
- entry, TQT_SLOT( journalDeleted( Journal* ) ) );
-
- connect( entry, TQT_SIGNAL( editIncidence( Incidence* ) ),
- this, TQT_SIGNAL( editIncidenceSignal( Incidence* ) ) );
- connect( entry, TQT_SIGNAL( deleteIncidence( Incidence* ) ),
- this, TQT_SIGNAL( deleteIncidenceSignal( Incidence* ) ) );
- connect( entry, TQT_SIGNAL( newJournal( const TQDate & ) ),
- this, TQT_SIGNAL( newJournalSignal( const TQDate & ) ) );
+ connect( this, TQT_SIGNAL(flushEntries()),
+ entry, TQT_SIGNAL(flushEntries()) );
+
+ connect( this, TQT_SIGNAL(setIncidenceChangerSignal(IncidenceChangerBase *)),
+ entry, TQT_SLOT(setIncidenceChanger( IncidenceChangerBase *)) );
+
+ connect( this, TQT_SIGNAL(journalEdited(Journal *)),
+ entry, TQT_SLOT(journalEdited(Journal *)) );
+ connect( this, TQT_SIGNAL(journalDeleted(Journal *)),
+ entry, TQT_SLOT(journalDeleted(Journal *)) );
+
+ connect( entry, TQT_SIGNAL(editIncidence(Incidence *,const TQDate &)),
+ this, TQT_SIGNAL(editIncidenceSignal(Incidence *,const TQDate &)) );
+ connect( entry, TQT_SIGNAL(deleteIncidence(Incidence *)),
+ this, TQT_SIGNAL(deleteIncidenceSignal(Incidence *)) );
+
+ connect( entry, TQT_SIGNAL(newJournal(ResourceCalendar *,const TQString &,const TQDate &)),
+ this, TQT_SIGNAL(newJournalSignal(ResourceCalendar *,const TQString &,const TQDate &)) );
mEntries.insert( dt, entry );
}
@@ -134,16 +138,18 @@ void KOJournalView::flushView()
emit flushEntries();
}
-void KOJournalView::showDates(const TQDate &start, const TQDate &end)
+void KOJournalView::showDates( const TQDate &start, const TQDate &end )
{
// kdDebug(5850) << "KOJournalView::showDates(): "<<start.toString().latin1()<<" - "<<end.toString().latin1() << endl;
clearEntries();
- if ( end<start ) return;
+ if ( end < start ) {
+ return;
+ }
Journal::List::ConstIterator it;
Journal::List jnls;
- TQDate d=start;
- for ( TQDate d=start; d<=end; d=d.addDays(1) ) {
+ TQDate d = start;
+ for ( TQDate d = start; d <= end; d = d.addDays( 1 ) ) {
jnls = calendar()->journals( d );
for ( it = jnls.begin(); it != jnls.end(); ++it ) {
appendJournal( *it, d );
@@ -155,15 +161,17 @@ void KOJournalView::showDates(const TQDate &start, const TQDate &end)
}
}
-void KOJournalView::showIncidences( const Incidence::List &incidences )
+void KOJournalView::showIncidences( const Incidence::List &incidences, const TQDate & )
{
// kdDebug(5850) << "KOJournalView::showIncidences(): "<< endl;
clearEntries();
Incidence::List::const_iterator it;
- for ( it=incidences.constBegin(); it!=incidences.constEnd(); ++it) {
- if ((*it) && ( (*it)->type()=="Journal" ) ) {
- Journal*j = static_cast<Journal*>(*it);
- if ( j ) appendJournal( j, j->dtStart().date() );
+ for ( it = incidences.constBegin(); it != incidences.constEnd(); ++it ) {
+ if ( (*it) && ( (*it)->type() == "Journal" ) ) {
+ Journal *j = static_cast<Journal*>(*it);
+ if ( j ) {
+ appendJournal( j, j->dtStart().date() );
+ }
}
}
}
@@ -202,7 +210,8 @@ void KOJournalView::setIncidenceChanger( IncidenceChangerBase *changer )
void KOJournalView::newJournal()
{
- emit newJournalSignal( TQDate::currentDate() );
+ emit newJournalSignal( 0/*ResourceCalendar*/, TQString()/*subResource*/,
+ TQDate::currentDate() );
}
#include "kojournalview.moc"
diff --git a/korganizer/kojournalview.h b/korganizer/kojournalview.h
index 9af95537e..fbc38efb1 100644
--- a/korganizer/kojournalview.h
+++ b/korganizer/kojournalview.h
@@ -25,8 +25,8 @@
#define KOJOURNALVIEW_H
#include <korganizer/baseview.h>
-#include "journalentry.h"
+class JournalDateEntry;
class JournalEntry;
class TQScrollView;
class TQVBox;
@@ -48,7 +48,7 @@ class KOJournalView : public KOrg::BaseView
virtual int currentDateCount();
virtual Incidence::List selectedIncidences();
- DateList selectedDates() { return DateList(); }
+ DateList selectedIncidenceDates() { return DateList(); }
void appendJournal( Journal*journal, const TQDate &dt);
CalPrinterBase::PrintType printType();
@@ -60,7 +60,7 @@ class KOJournalView : public KOrg::BaseView
void flushView();
void showDates( const TQDate &start, const TQDate &end );
- void showIncidences( const Incidence::List &incidenceList );
+ void showIncidences( const Incidence::List &incidenceList, const TQDate &date );
void changeIncidenceDisplay( Incidence *, int );
void setIncidenceChanger( IncidenceChangerBase *changer );
diff --git a/korganizer/kolistview.cpp b/korganizer/kolistview.cpp
index 7ca342e87..59b7f17e1 100644
--- a/korganizer/kolistview.cpp
+++ b/korganizer/kolistview.cpp
@@ -28,6 +28,7 @@
#include <tqlayout.h>
#include <tqpopupmenu.h>
#include <tqcursor.h>
+#include <tqstyle.h>
#include <klocale.h>
#include <kdebug.h>
@@ -45,30 +46,39 @@
#include "kolistview.h"
#include "kolistview.moc"
+enum {
+ Summary_Column = 0,
+ Reminder_Column,
+ Recurs_Column,
+ StartDateTime_Column,
+ EndDateTime_Column,
+ Categories_Column
+};
+
KOListViewToolTip::KOListViewToolTip( TQWidget* parent,
- KListView* lv )
- :TQToolTip(parent)
+ Calendar *calendar,
+ KListView *lv )
+ :TQToolTip( parent ), mCalendar( calendar )
{
- eventlist=lv;
+ eventlist = lv;
}
-void KOListViewToolTip::maybeTip( const TQPoint & pos)
+void KOListViewToolTip::maybeTip( const TQPoint &pos )
{
TQRect r;
- TQListViewItem *it = eventlist->itemAt(pos);
- KOListViewItem *i = static_cast<KOListViewItem*>(it);
+ TQListViewItem *it = eventlist->itemAt( pos );
+ KOListViewItem *i = static_cast<KOListViewItem*>( it );
- if( i && KOPrefs::instance()->mEnableToolTips ) {
+ if ( i && KOPrefs::instance()->mEnableToolTips ) {
/* Calculate the rectangle. */
- r=eventlist->itemRect( it );
+ r = eventlist->itemRect( it );
/* Show the tip */
- TQString tipText( IncidenceFormatter::toolTipString( i->data() ) );
+ TQString tipText( IncidenceFormatter::toolTipStr( mCalendar, i->data() ) );
if ( !tipText.isEmpty() ) {
- tip(r, tipText);
+ tip( r, tipText );
}
}
-
}
/**
@@ -91,132 +101,127 @@ class KOListView::ListItemVisitor : public IncidenceBase::Visitor
bool KOListView::ListItemVisitor::visit( Event *e )
{
- mItem->setText(0,e->summary());
+ mItem->setText( Summary_Column, e->summary() );
if ( e->isAlarmEnabled() ) {
static const TQPixmap alarmPxmp = KOGlobals::self()->smallIcon( "bell" );
- mItem->setPixmap(1,alarmPxmp);
- mItem->setSortKey(1,"1");
+ mItem->setPixmap( Reminder_Column, alarmPxmp );
+ mItem->setSortKey( Reminder_Column, "1" );
+ } else {
+ mItem->setSortKey( Reminder_Column, "0" );
}
- else
- mItem->setSortKey(1,"0");
if ( e->doesRecur() ) {
static const TQPixmap recurPxmp = KOGlobals::self()->smallIcon( "recur" );
- mItem->setPixmap(2,recurPxmp);
- mItem->setSortKey(2,"1");
+ mItem->setPixmap( Recurs_Column, recurPxmp );
+ mItem->setSortKey( Recurs_Column, "1" );
+ } else {
+ mItem->setSortKey( Recurs_Column, "0" );
}
- else
- mItem->setSortKey(2,"0");
-
- static const TQPixmap eventPxmp = KOGlobals::self()->smallIcon( "appointment" );
- mItem->setPixmap(0, eventPxmp);
- mItem->setText( 3,e->dtStartDateStr());
- mItem->setSortKey( 3, e->dtStart().toString(Qt::ISODate));
- if (e->doesFloat()) mItem->setText(4, "---"); else {
- mItem->setText( 4, e->dtStartTimeStr() );
- mItem->setSortKey( 4,e->dtStart().time().toString(Qt::ISODate));
- }
- mItem->setText( 5,e->dtEndDateStr());
- mItem->setSortKey( 5, e->dtEnd().toString(Qt::ISODate));
- if (e->doesFloat()) mItem->setText(6, "---"); else {
- mItem->setText( 6, e->dtEndTimeStr() );
- mItem->setSortKey( 6, e->dtEnd().time().toString(Qt::ISODate));
+ TQPixmap eventPxmp;
+ if ( e->customProperty( "KABC", "BIRTHDAY" ) == "YES" ) {
+ if ( e->customProperty( "KABC", "ANNIVERSARY" ) == "YES" ) {
+ eventPxmp = KOGlobals::self()->smallIcon( "calendaranniversary" );
+ } else {
+ eventPxmp = KOGlobals::self()->smallIcon( "calendarbirthday" );
+ }
+ } else {
+ eventPxmp = KOGlobals::self()->smallIcon( "appointment" );
}
- mItem->setText( 7,e->categoriesStr());
+
+ mItem->setPixmap( Summary_Column, eventPxmp );
+
+ TQString startDateTime;
+ TQString endDateTime;
+
+ mItem->setText( StartDateTime_Column, IncidenceFormatter::dateTimeToString( e->dtStart(), e->doesFloat() ) );
+ mItem->setSortKey( StartDateTime_Column, e->dtStart().toString( Qt::ISODate ) );
+ mItem->setText( EndDateTime_Column, IncidenceFormatter::dateTimeToString( e->dtEnd(), e->doesFloat() ) );
+ mItem->setSortKey( EndDateTime_Column, e->dtEnd().toString( Qt::ISODate ) );
+ mItem->setText( Categories_Column, e->categoriesStr() );
return true;
}
-bool KOListView::ListItemVisitor::visit(Todo *t)
+bool KOListView::ListItemVisitor::visit( Todo *t )
{
static const TQPixmap todoPxmp = KOGlobals::self()->smallIcon( "todo" );
static const TQPixmap todoDonePxmp = KOGlobals::self()->smallIcon( "checkedbox" );
- mItem->setPixmap(0, t->isCompleted() ? todoDonePxmp : todoPxmp );
- mItem->setText(0,t->summary());
+ mItem->setPixmap(Summary_Column, t->isCompleted() ? todoDonePxmp : todoPxmp );
+ mItem->setText(Summary_Column, t->summary());
if ( t->isAlarmEnabled() ) {
static const TQPixmap alarmPxmp = KOGlobals::self()->smallIcon( "bell" );
- mItem->setPixmap(1,alarmPxmp);
- mItem->setSortKey(1, "1");
+ mItem->setPixmap( Reminder_Column, alarmPxmp );
+ mItem->setSortKey( Reminder_Column, "1" );
+ } else {
+ mItem->setSortKey( Reminder_Column, "0" );
}
- else
- mItem->setSortKey(1, "0");
if ( t->doesRecur() ) {
static const TQPixmap recurPxmp = KOGlobals::self()->smallIcon( "recur" );
- mItem->setPixmap(2,recurPxmp);
- mItem->setSortKey(2, "1");
- }
- else
- mItem->setSortKey(2, "0");
-
- if (t->hasStartDate()) {
- mItem->setText(3,t->dtStartDateStr());
- mItem->setSortKey(3,t->dtStart().toString(Qt::ISODate));
- if (t->doesFloat()) {
- mItem->setText(4,"---");
- } else {
- mItem->setText(4,t->dtStartTimeStr());
- mItem->setSortKey( 4, t->dtStart().time().toString(Qt::ISODate) );
- }
+ mItem->setPixmap( Recurs_Column, recurPxmp );
+ mItem->setSortKey( Recurs_Column, "1" );
} else {
- mItem->setText(3,"---");
- mItem->setText(4,"---");
+ mItem->setSortKey( Recurs_Column, "0" );
}
- if (t->hasDueDate()) {
- mItem->setText(5,t->dtDueDateStr());
- mItem->setSortKey( 5, t->dtDue().toString(Qt::ISODate) );
- if (t->doesFloat()) {
- mItem->setText(6,"---");
- } else {
- mItem->setText(6,t->dtDueTimeStr());
- mItem->setSortKey( 6, t->dtDue().time().toString(Qt::ISODate) );
- }
+ if ( t->hasStartDate() ) {
+ mItem->setText( StartDateTime_Column, IncidenceFormatter::dateTimeToString( t->dtStart(), t->doesFloat() ) );
+ mItem->setSortKey( StartDateTime_Column, t->dtStart().toString( Qt::ISODate ) );
} else {
- mItem->setText(5,"---");
- mItem->setText(6,"---");
+ mItem->setText( StartDateTime_Column, "---" );
}
- mItem->setText(7,t->categoriesStr());
+ if ( t->hasDueDate() ) {
+ mItem->setText( EndDateTime_Column, IncidenceFormatter::dateTimeToString( t->dtDue(), t->doesFloat() ) );
+ mItem->setSortKey( EndDateTime_Column, t->dtDue().toString( Qt::ISODate ) );
+ } else {
+ mItem->setText( EndDateTime_Column, "---" );
+ }
+ mItem->setText( Categories_Column, t->categoriesStr() );
return true;
}
-bool KOListView::ListItemVisitor::visit(Journal *t)
+bool KOListView::ListItemVisitor::visit( Journal *j )
{
- static const TQPixmap jrnalPxmp = KOGlobals::self()->smallIcon( "journal" );
- mItem->setPixmap(0,jrnalPxmp);
+ static const TQPixmap jornalPxmp = KOGlobals::self()->smallIcon( "journal" );
+ mItem->setPixmap( Summary_Column, jornalPxmp );
// Just use the first line
- mItem->setText( 0, t->description().section( "\n", 0, 0 ) );
- mItem->setText( 3, t->dtStartDateStr() );
- mItem->setSortKey( 3, t->dtStart().toString(Qt::ISODate) );
+ mItem->setText( Summary_Column, j->description().section( "\n", 0, 0 ) );
+ mItem->setText( StartDateTime_Column, IncidenceFormatter::dateTimeToString( j->dtStart(), j->doesFloat() ) );
+ mItem->setSortKey( StartDateTime_Column, j->dtStart().toString( Qt::ISODate ) );
return true;
}
-KOListView::KOListView( Calendar *calendar, TQWidget *parent,
- const char *name)
- : KOEventView(calendar, parent, name)
+KOListView::KOListView( Calendar *calendar,
+ TQWidget *parent,
+ const char *name,
+ bool nonInteractive )
+ : KOEventView( calendar, parent, name )
{
mActiveItem = 0;
+ mIsNonInteractive = nonInteractive;
- mListView = new KListView(this);
- mListView->addColumn(i18n("Summary"));
- mListView->addColumn(i18n("Reminder")); // alarm set?
- mListView->addColumn(i18n("Recurs")); // recurs?
- mListView->addColumn(i18n("Start Date"));
- mListView->setColumnAlignment(3,AlignHCenter);
- mListView->addColumn(i18n("Start Time"));
- mListView->setColumnAlignment(4,AlignHCenter);
- mListView->addColumn(i18n("End Date"));
- mListView->setColumnAlignment(5,AlignHCenter);
- mListView->addColumn(i18n("End Time"));
- mListView->setColumnAlignment(6,AlignHCenter);
- mListView->addColumn(i18n("Categories"));
-
- TQBoxLayout *layoutTop = new TQVBoxLayout(this);
- layoutTop->addWidget(mListView);
+ mListView = new KListView( this );
+ mListView->addColumn( i18n("Summary") );
+ mListView->addColumn( i18n("Reminder") ); // alarm set?
+ mListView->setColumnAlignment( Reminder_Column, AlignHCenter );
+
+ mListView->addColumn( i18n("Recurs") ); // recurs?
+ mListView->setColumnAlignment( Recurs_Column, AlignHCenter );
+
+ mListView->addColumn( i18n("Start Date/Time") );
+ mListView->setColumnAlignment( StartDateTime_Column, AlignHCenter );
+
+ mListView->addColumn( i18n("End Date/Time") );
+ mListView->setColumnAlignment( EndDateTime_Column, AlignHCenter );
+
+ mListView->addColumn( i18n("Categories") );
+
+ TQBoxLayout *layoutTop = new TQVBoxLayout( this );
+ layoutTop->addWidget( mListView );
mPopupMenu = eventPopup();
/*
@@ -239,9 +244,9 @@ KOListView::KOListView( Calendar *calendar, TQWidget *parent,
TQT_SLOT( processSelectionChange() ) );
// setMinimumSize(100,100);
- mListView->restoreLayout(KOGlobals::self()->config(),"KOListView Layout");
+ mListView->restoreLayout( KOGlobals::self()->config(), "KOListView Layout" );
- new KOListViewToolTip( mListView->viewport(), mListView );
+ new KOListViewToolTip( mListView->viewport(), calendar, mListView );
mSelectedDates.append( TQDate::currentDate() );
}
@@ -266,43 +271,45 @@ Incidence::List KOListView::selectedIncidences()
Incidence::List eventList;
TQListViewItem *item = mListView->selectedItem();
- if (item) eventList.append(((KOListViewItem *)item)->data());
+ if ( item ) {
+ eventList.append( static_cast<KOListViewItem *>( item )->data() );
+ }
return eventList;
}
-DateList KOListView::selectedDates()
+DateList KOListView::selectedIncidenceDates()
{
return mSelectedDates;
}
-void KOListView::showDates(bool show)
+void KOListView::showDates( bool show )
{
// Shouldn't we set it to a value greater 0? When showDates is called with
// show == true at first, then the columnwidths are set to zero.
static int oldColWidth1 = 0;
static int oldColWidth3 = 0;
- if (!show) {
- oldColWidth1 = mListView->columnWidth(1);
- oldColWidth3 = mListView->columnWidth(3);
- mListView->setColumnWidth(1, 0);
- mListView->setColumnWidth(3, 0);
+ if ( !show ) {
+ oldColWidth1 = mListView->columnWidth( 1 );
+ oldColWidth3 = mListView->columnWidth( 3 );
+ mListView->setColumnWidth( 1, 0 );
+ mListView->setColumnWidth( 3, 0 );
} else {
- mListView->setColumnWidth(1, oldColWidth1);
- mListView->setColumnWidth(3, oldColWidth3);
+ mListView->setColumnWidth( 1, oldColWidth1 );
+ mListView->setColumnWidth( 3, oldColWidth3 );
}
mListView->repaint();
}
void KOListView::showDates()
{
- showDates(true);
+ showDates( true );
}
void KOListView::hideDates()
{
- showDates(false);
+ showDates( false );
}
void KOListView::updateView()
@@ -310,82 +317,103 @@ void KOListView::updateView()
kdDebug(5850) << "KOListView::updateView() does nothing" << endl;
}
-void KOListView::showDates(const TQDate &start, const TQDate &end)
+void KOListView::showDates( const TQDate &start, const TQDate &end )
{
clear();
TQDate date = start;
while( date <= end ) {
- addIncidences( calendar()->incidences(date) );
+ addIncidences( calendar()->incidences( date ), date );
mSelectedDates.append( date );
date = date.addDays( 1 );
}
- emit incidenceSelected( 0 );
+ emit incidenceSelected( 0, TQDate() );
}
-void KOListView::addIncidences( const Incidence::List &incidenceList )
+void KOListView::showAll()
+{
+ Incidence::List incidenceList = calendar()->incidences();
+
+ Incidence::List::ConstIterator it;
+ for( it = incidenceList.begin(); it != incidenceList.end(); ++it ) {
+ // we don't need the date, using showAll in non interactive mode for now
+ addIncidence( *it, TQDate() );
+ }
+}
+
+void KOListView::addIncidences( const Incidence::List &incidenceList, const TQDate &date )
{
Incidence::List::ConstIterator it;
for( it = incidenceList.begin(); it != incidenceList.end(); ++it ) {
- addIncidence( *it );
+ addIncidence( *it, date );
}
}
-void KOListView::addIncidence(Incidence *incidence)
+void KOListView::addIncidence( Incidence *incidence, const TQDate &date )
{
- if ( mUidDict.find( incidence->uid() ) ) return;
+ if ( mUidDict.find( incidence->uid() ) ) {
+ return;
+ }
+ mDateList[incidence->uid()] = date;
mUidDict.insert( incidence->uid(), incidence );
KOListViewItem *item = new KOListViewItem( incidence, mListView );
- ListItemVisitor v(item);
- if (incidence->accept(v)) return;
- else delete item;
+ ListItemVisitor v( item );
+ if (incidence->accept( v ) ) {
+ return;
+ } else {
+ delete item;
+ }
}
-void KOListView::showIncidences( const Incidence::List &incidenceList )
+void KOListView::showIncidences( const Incidence::List &incidenceList, const TQDate &date )
{
clear();
- addIncidences( incidenceList );
+ addIncidences( incidenceList, date );
// After new creation of list view no events are selected.
- emit incidenceSelected( 0 );
+ emit incidenceSelected( 0, date );
}
-void KOListView::changeIncidenceDisplay(Incidence *incidence, int action)
+void KOListView::changeIncidenceDisplay( Incidence *incidence, int action )
{
KOListViewItem *item;
TQDate f = mSelectedDates.first();
TQDate l = mSelectedDates.last();
TQDate date;
- if ( incidence->type() == "Todo" )
- date = static_cast<Todo *>(incidence)->dtDue().date();
- else
+ if ( incidence->type() == "Todo" ) {
+ date = static_cast<Todo *>( incidence )->dtDue().date();
+ } else {
date = incidence->dtStart().date();
+ }
- switch(action) {
+ switch( action ) {
case KOGlobals::INCIDENCEADDED: {
if ( date >= f && date <= l )
- addIncidence( incidence );
+ addIncidence( incidence, date );
break;
}
case KOGlobals::INCIDENCEEDITED: {
- item = getItemForIncidence(incidence);
- if (item) {
+ item = getItemForIncidence( incidence );
+ if ( item ) {
delete item;
mUidDict.remove( incidence->uid() );
+ mDateList.remove( incidence->uid() );
+ }
+ if ( date >= f && date <= l ) {
+ addIncidence( incidence, date );
}
- if ( date >= f && date <= l )
- addIncidence( incidence );
}
break;
case KOGlobals::INCIDENCEDELETED: {
- item = getItemForIncidence(incidence);
- if (item)
+ item = getItemForIncidence( incidence );
+ if ( item ) {
delete item;
+ }
break;
}
default:
@@ -393,58 +421,68 @@ void KOListView::changeIncidenceDisplay(Incidence *incidence, int action)
}
}
-KOListViewItem *KOListView::getItemForIncidence(Incidence *incidence)
+KOListViewItem *KOListView::getItemForIncidence( Incidence *incidence )
{
- KOListViewItem *item = (KOListViewItem *)mListView->firstChild();
- while (item) {
+ KOListViewItem *item = static_cast<KOListViewItem *>( mListView->firstChild() );
+ while ( item ) {
// kdDebug(5850) << "Item " << item->text(0) << " found" << endl;
- if (item->data() == incidence) return item;
- item = (KOListViewItem *)item->nextSibling();
+ if ( item->data() == incidence ) {
+ return item;
+ }
+ item = static_cast<KOListViewItem *>( item->nextSibling() );
}
return 0;
}
-void KOListView::defaultItemAction(TQListViewItem *i)
+void KOListView::defaultItemAction( TQListViewItem *i )
{
- KOListViewItem *item = static_cast<KOListViewItem *>( i );
- if ( item ) defaultAction( item->data() );
+ if ( !mIsNonInteractive ) {
+ KOListViewItem *item = static_cast<KOListViewItem *>( i );
+ if ( item ) {
+ defaultAction( item->data() );
+ }
+ }
}
-void KOListView::popupMenu(TQListViewItem *item,const TQPoint &,int)
+void KOListView::popupMenu( TQListViewItem *item,const TQPoint &, int )
{
- mActiveItem = (KOListViewItem *)item;
- if (mActiveItem) {
- Incidence *incidence = mActiveItem->data();
- // FIXME: For recurring incidences we don't know the date of this
- // occurrence, there's no reference to it at all!
- mPopupMenu->showIncidencePopup( incidence, TQDate() );
- }
- else {
- showNewEventPopup();
+ if ( !mIsNonInteractive ) {
+ mActiveItem = static_cast<KOListViewItem *>( item );
+ if ( mActiveItem ) {
+ Incidence *incidence = mActiveItem->data();
+ // FIXME: For recurring incidences we don't know the date of this
+ // occurrence, there's no reference to it at all!
+ mPopupMenu->showIncidencePopup( calendar(), incidence, TQDate() );
+ } else {
+ showNewEventPopup();
+ }
}
}
-void KOListView::readSettings(KConfig *config)
+void KOListView::readSettings( KConfig *config )
{
- mListView->restoreLayout(config,"KOListView Layout");
+ mListView->restoreLayout( config,"KOListView Layout" );
}
-void KOListView::writeSettings(KConfig *config)
+void KOListView::writeSettings( KConfig *config )
{
- mListView->saveLayout(config,"KOListView Layout");
+ mListView->saveLayout( config, "KOListView Layout" );
}
void KOListView::processSelectionChange()
{
- kdDebug(5850) << "KOListView::processSelectionChange()" << endl;
+ if ( !mIsNonInteractive ) {
+ kdDebug(5850) << "KOListView::processSelectionChange()" << endl;
- KOListViewItem *item =
- static_cast<KOListViewItem *>( mListView->selectedItem() );
+ KOListViewItem *item =
+ static_cast<KOListViewItem *>( mListView->selectedItem() );
- if ( !item ) {
- emit incidenceSelected( 0 );
- } else {
- emit incidenceSelected( item->data() );
+ if ( !item ) {
+ emit incidenceSelected( 0, TQDate() );
+ } else {
+ Incidence *incidence = static_cast<Incidence *>( item->data() );
+ emit incidenceSelected( incidence, mDateList[incidence->uid()] );
+ }
}
}
@@ -458,4 +496,12 @@ void KOListView::clear()
mSelectedDates.clear();
mListView->clear();
mUidDict.clear();
+ mDateList.clear();
+}
+
+TQSize KOListView::sizeHint() const
+{
+ const TQSize s = KOEventView::sizeHint();
+ return TQSize( s.width() + style().pixelMetric( TQStyle::PM_ScrollBarExtent ) + 1,
+ s.height() );
}
diff --git a/korganizer/kolistview.h b/korganizer/kolistview.h
index 6da6988a8..5a5c40d8f 100644
--- a/korganizer/kolistview.h
+++ b/korganizer/kolistview.h
@@ -27,6 +27,7 @@
#define _KOLISTVIEW_H
#include <tqdict.h>
+#include <tqmap.h>
#include <tqtooltip.h>
#include <libkcal/incidence.h>
@@ -43,12 +44,13 @@ class KOListView;
class KOListViewToolTip : public QToolTip
{
public:
- KOListViewToolTip (TQWidget* parent, KListView* lv );
+ KOListViewToolTip ( TQWidget* parent, Calendar *calendar, KListView* lv );
protected:
- void maybeTip( const TQPoint & pos);
+ void maybeTip( const TQPoint &pos );
private:
+ Calendar *mCalendar;
KListView* eventlist;
};
@@ -67,26 +69,32 @@ class KOListView : public KOEventView
{
Q_OBJECT
public:
- KOListView(Calendar *calendar, TQWidget *parent = 0,
- const char *name = 0);
+ explicit KOListView( Calendar *calendar,
+ TQWidget *parent = 0,
+ const char *name = 0,
+ bool nonInteractive = false );
~KOListView();
virtual int maxDatesHint();
virtual int currentDateCount();
virtual Incidence::List selectedIncidences();
- virtual DateList selectedDates();
+ virtual DateList selectedIncidenceDates();
- void showDates(bool show);
+ void showDates( bool show );
+
+ // Shows all incidences of the calendar
+ void showAll();
void readSettings(KConfig *config);
void writeSettings(KConfig *config);
void clear();
+ TQSize sizeHint() const;
public slots:
virtual void updateView();
virtual void showDates( const TQDate &start, const TQDate &end );
- virtual void showIncidences( const Incidence::List &incidenceList );
+ virtual void showIncidences( const Incidence::List &incidenceList, const TQDate &date );
void clearSelection();
@@ -102,8 +110,8 @@ class KOListView : public KOEventView
void processSelectionChange();
protected:
- void addIncidences( const Incidence::List & );
- void addIncidence(Incidence *);
+ void addIncidences(const Incidence::List &, const TQDate &date);
+ void addIncidence(Incidence *, const TQDate &date);
KOListViewItem *getItemForIncidence(Incidence *incidence);
private:
@@ -112,7 +120,11 @@ class KOListView : public KOEventView
KOEventPopupMenu *mPopupMenu;
KOListViewItem *mActiveItem;
TQDict<Incidence> mUidDict;
+ TQMap<TQString, TQDate>mDateList;
DateList mSelectedDates;
+
+ // if it's non interactive we disable context menu, and incidence editing
+ bool mIsNonInteractive;
};
#endif
diff --git a/korganizer/komailclient.cpp b/korganizer/komailclient.cpp
index 946331fde..1b3215c09 100644
--- a/korganizer/komailclient.cpp
+++ b/korganizer/komailclient.cpp
@@ -34,12 +34,18 @@
#include <dcopclient.h>
#include <kprocess.h>
+#include <libemailfunctions/email.h>
+
+#include <libkpimidentities/identity.h>
+#include <libkpimidentities/identitymanager.h>
+
#include <libkcal/event.h>
#include <libkcal/todo.h>
#include <libkcal/incidenceformatter.h>
#include "version.h"
#include "koprefs.h"
+#include "kocore.h"
#include "komailclient.h"
@@ -54,23 +60,59 @@ KOMailClient::~KOMailClient()
bool KOMailClient::mailAttendees(IncidenceBase *incidence,const TQString &attachment)
{
Attendee::List attendees = incidence->attendees();
- if (attendees.count() == 0) return false;
+ if ( attendees.count() == 0 ) {
+ return false;
+ }
const TQString from = incidence->organizer().fullName();
const TQString organizerEmail = incidence->organizer().email();
+
TQStringList toList;
- for(uint i=0; i<attendees.count();++i) {
- const TQString email = (*attendees.at(i))->email();
- // In case we (as one of our identities) are the organizer we are sending this
- // mail. We could also have added ourselves as an attendee, in which case we
- // don't want to send ourselves a notification mail.
- if( organizerEmail != email )
- toList << email;
+ TQStringList ccList;
+ for ( uint i=0; i<attendees.count(); ++i ) {
+ Attendee *a = (*attendees.at(i));
+
+ const TQString email = a->email();
+ if ( email.isEmpty() ) {
+ continue;
+ }
+
+ // In case we (as one of our identities) are the organizer we are sending
+ // this mail. We could also have added ourselves as an attendee, in which
+ // case we don't want to send ourselves a notification mail.
+ if ( organizerEmail == email ) {
+ continue;
+ }
+
+ // Build a nice address for this attendee including the CN.
+ TQString tname, temail;
+ const TQString username = KPIM::quoteNameIfNecessary( a->name() );
+ KPIM::getNameAndMail( username, tname, temail ); // ignore return value
+ // which is always false
+ tname += " <" + email + '>';
+
+
+ // Optional Participants and Non-Participants are copied on the email
+ if ( a->role() == Attendee::OptParticipant ||
+ a->role() == Attendee::NonParticipant ) {
+ ccList << tname;
+ } else {
+ toList << tname;
+ }
}
- if( toList.count() == 0 )
+
+ if( toList.count() == 0 && ccList.count() == 0 ) {
// Not really to be called a groupware meeting, eh
return false;
- TQString to = toList.join( ", " );
+ }
+ TQString to;
+ if ( toList.count() > 0 ) {
+ to = toList.join( ", " );
+ }
+ TQString cc;
+ if ( ccList.count() > 0 ) {
+ cc = ccList.join( ", " );
+ }
TQString subject;
if(incidence->type()!="FreeBusy") {
@@ -84,7 +126,7 @@ bool KOMailClient::mailAttendees(IncidenceBase *incidence,const TQString &attach
bool bcc = KOPrefs::instance()->mBcc;
- return send(from,to,subject,body,bcc,attachment);
+ return send(from,to,cc,subject,body,bcc,attachment);
}
bool KOMailClient::mailOrganizer(IncidenceBase *incidence,const TQString &attachment, const TQString &sub)
@@ -106,7 +148,7 @@ bool KOMailClient::mailOrganizer(IncidenceBase *incidence,const TQString &attach
bool bcc = KOPrefs::instance()->mBcc;
- return send(from,to,subject,body,bcc,attachment);
+ return send(from,to,TQString::null,subject,body,bcc,attachment);
}
bool KOMailClient::mailTo(IncidenceBase *incidence,const TQString &recipients,
@@ -123,16 +165,25 @@ bool KOMailClient::mailTo(IncidenceBase *incidence,const TQString &recipients,
TQString body = IncidenceFormatter::mailBodyString(incidence);
bool bcc = KOPrefs::instance()->mBcc;
kdDebug () << "KOMailClient::mailTo " << recipients << endl;
- return send(from,recipients,subject,body,bcc,attachment);
+ return send(from,recipients,TQString::null,subject,body,bcc,attachment);
}
-bool KOMailClient::send(const TQString &from,const TQString &to,
+bool KOMailClient::send(const TQString &from,const TQString &_to,const TQString &cc,
const TQString &subject,const TQString &body,bool bcc,
const TQString &attachment)
{
- kdDebug(5850) << "KOMailClient::sendMail():\nFrom: " << from << "\nTo: " << to
- << "\nSubject: " << subject << "\nBody: \n" << body
- << "\nAttachment:\n" << attachment << endl;
+ // We must have a recipients list for most MUAs. Thus, if the 'to' list
+ // is empty simply use the 'from' address as the recipient.
+ TQString to = _to;
+ if ( to.isEmpty() ) {
+ to = from;
+ }
+
+ kdDebug(5850) << "KOMailClient::sendMail():\nFrom: " << from
+ << "\nTo: " << to
+ << "\nCC: " << cc
+ << "\nSubject: " << subject << "\nBody: \n" << body
+ << "\nAttachment:\n" << attachment << endl;
if (KOPrefs::instance()->mMailClient == KOPrefs::MailClientSendmail) {
bool needHeaders = true;
@@ -152,6 +203,11 @@ bool KOMailClient::send(const TQString &from,const TQString &to,
command.append(KProcess::quote(from));
}
+ if ( !cc.isEmpty() ) {
+ command.append(" -c ");
+ command.append(KProcess::quote(cc));
+ }
+
command.append(" ");
command.append(KProcess::quote(to));
@@ -170,6 +226,9 @@ bool KOMailClient::send(const TQString &from,const TQString &to,
{
textComplete += TQString::fromLatin1("From: ") + from + '\n';
textComplete += TQString::fromLatin1("To: ") + to + '\n';
+ if ( !cc.isEmpty() ) {
+ textComplete += TQString::fromLatin1("Cc: " ) + cc + '\n';
+ }
if (bcc) textComplete += TQString::fromLatin1("Bcc: ") + from + '\n';
textComplete += TQString::fromLatin1("Subject: ") + subject + '\n';
textComplete += TQString::fromLatin1("X-Mailer: KOrganizer") + korgVersion + '\n';
@@ -184,14 +243,14 @@ bool KOMailClient::send(const TQString &from,const TQString &to,
pclose(fd);
} else {
if (!kapp->dcopClient()->isApplicationRegistered("kmail")) {
- if (KApplication::startServiceByDesktopName("kmail")) {
+ if (KApplication::startServiceByDesktopName("kmail")) {
KMessageBox::error(0,i18n("No running instance of KMail found."));
return false;
- }
+ }
}
if (attachment.isEmpty()) {
- if (!kMailOpenComposer(to,"",bcc ? from : "",subject,body,0,KURL())) return false;
+ if (!kMailOpenComposer(to,cc,bcc ? from : "",subject,body,0,KURL())) return false;
} else {
TQString meth;
int idx = attachment.find("METHOD");
@@ -203,9 +262,12 @@ bool KOMailClient::send(const TQString &from,const TQString &to,
} else {
meth = "publish";
}
- if (!kMailOpenComposer(to,"",bcc ? from : "",subject,body,0,"cal.ics","7bit",
+ if (!kMailOpenComposer(to,cc,bcc ? from : "",subject,body,0,"cal.ics","7bit",
attachment.utf8(),"text","calendar","method",meth,
- "attachment","utf-8")) return false;
+ "attachment","utf-8",
+ KOCore::self()->identityManager()->identityForAddress( from ).uoid())) {
+ return false;
+ }
}
}
return true;
@@ -252,7 +314,7 @@ int KOMailClient::kMailOpenComposer( const TQString& arg0, const TQString& arg1,
const TQCString& arg7, const TQCString& arg8,
const TQCString& arg9, const TQCString& arg10,
const TQCString& arg11, const TQString& arg12,
- const TQCString& arg13, const TQCString& arg14 )
+ const TQCString& arg13, const TQCString& arg14, uint identity )
{
//kdDebug(5850) << "KOMailClient::kMailOpenComposer( "
// << arg0 << " , " << arg1 << arg2 << " , " << arg3
@@ -281,11 +343,12 @@ int KOMailClient::kMailOpenComposer( const TQString& arg0, const TQString& arg1,
arg << arg12;
arg << arg13;
arg << arg14;
+ arg << identity;
#if KDE_IS_VERSION( 3, 2, 90 )
kapp->updateRemoteUserTimestamp("kmail");
#endif
if ( kapp->dcopClient()->call("kmail","KMailIface",
- "openComposer(TQString,TQString,TQString,TQString,TQString,int,TQString,TQCString,TQCString,TQCString,TQCString,TQCString,TQString,TQCString,TQCString)", data, replyType, replyData ) ) {
+ "openComposer(TQString,TQString,TQString,TQString,TQString,int,TQString,TQCString,TQCString,TQCString,TQCString,TQCString,TQString,TQCString,TQCString,uint)", data, replyType, replyData ) ) {
if ( replyType == "int" ) {
TQDataStream _reply_stream( replyData, IO_ReadOnly );
_reply_stream >> result;
diff --git a/korganizer/komailclient.h b/korganizer/komailclient.h
index da71ecec1..3051bab7e 100644
--- a/korganizer/komailclient.h
+++ b/korganizer/komailclient.h
@@ -45,8 +45,8 @@ class KOMailClient
protected:
/** 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 */
- bool send(const TQString &from,const TQString &to,const TQString &subject,
- const TQString &body,bool bcc=false,
+ bool send(const TQString &from,const TQString &to,const TQString &cc,
+ const TQString &subject,const TQString &body,bool bcc=false,
const TQString &attachment=TQString::null);
int kMailOpenComposer(const TQString& to, const TQString& cc,
@@ -59,7 +59,8 @@ class KOMailClient
const TQCString& attachParamAttr,
const TQString& attachParamValue,
const TQCString& attachContDisp,
- const TQCString& attachCharset);
+ const TQCString& attachCharset,
+ uint identity);
int kMailOpenComposer(const TQString& arg0,const TQString& arg1,
const TQString& arg2,const TQString& arg3,
const TQString& arg4,int arg5,const KURL& arg6);
diff --git a/korganizer/komonthview.cpp b/korganizer/komonthview.cpp
index 85d9049b6..264525418 100644
--- a/korganizer/komonthview.cpp
+++ b/korganizer/komonthview.cpp
@@ -62,13 +62,15 @@
//--------------------------------------------------------------------------
KOMonthCellToolTip::KOMonthCellToolTip( TQWidget *parent,
+ Calendar *calendar,
+ const TQDate &date,
KNoScrollListBox *lv )
- : TQToolTip( parent )
+ : TQToolTip( parent ), mCalendar( calendar ), mDate( date )
{
eventlist = lv;
}
-void KOMonthCellToolTip::maybeTip( const TQPoint & pos )
+void KOMonthCellToolTip::maybeTip( const TQPoint &pos )
{
TQRect r;
TQListBoxItem *it = eventlist->itemAt( pos );
@@ -78,7 +80,7 @@ void KOMonthCellToolTip::maybeTip( const TQPoint & pos )
/* Calculate the rectangle. */
r=eventlist->itemRect( it );
/* Show the tip */
- TQString tipText( IncidenceFormatter::toolTipString( i->incidence() ) );
+ TQString tipText( IncidenceFormatter::toolTipStr( mCalendar, i->incidence(), mDate ) );
if ( !tipText.isEmpty() ) {
tip( r, tipText );
}
@@ -199,13 +201,14 @@ MonthViewItem::MonthViewItem( Incidence *incidence, const TQDateTime &qd,
mDateTime = qd;
mEventPixmap = KOGlobals::self()->smallIcon( "appointment" );
+ mBirthdayPixmap = KOGlobals::self()->smallIcon( "calendarbirthday" );
+ mAnniversaryPixmap= KOGlobals::self()->smallIcon( "calendaranniversary" );
mTodoPixmap = KOGlobals::self()->smallIcon( "todo" );
mTodoDonePixmap = KOGlobals::self()->smallIcon( "checkedbox" );
mAlarmPixmap = KOGlobals::self()->smallIcon( "bell" );
mRecurPixmap = KOGlobals::self()->smallIcon( "recur" );
mReplyPixmap = KOGlobals::self()->smallIcon( "mail_reply" );
- mResourceColor = TQColor();
mEvent = false;
mTodo = false;
mTodoDone = false;
@@ -214,6 +217,26 @@ MonthViewItem::MonthViewItem( Incidence *incidence, const TQDateTime &qd,
mReply = false;
}
+TQColor MonthViewItem::catColor() const
+{
+ TQColor retColor;
+ if ( !mIncidence ) {
+ return retColor;
+ }
+
+ TQStringList categories = mIncidence->categories();
+ TQString cat;
+ if ( !categories.isEmpty() ) {
+ cat = categories.first();
+ }
+ if ( cat.isEmpty() ) {
+ retColor = KOPrefs::instance()->unsetCategoryColor();
+ } else {
+ retColor = *( KOPrefs::instance()->categoryColor( cat ) );
+ }
+ return retColor;
+}
+
void MonthViewItem::paint( TQPainter *p )
{
#if QT_VERSION >= 0x030000
@@ -222,25 +245,86 @@ void MonthViewItem::paint( TQPainter *p )
bool sel = selected();
#endif
- TQColor bgColor = palette().color( TQPalette::Normal,
- sel ? TQColorGroup::Highlight : TQColorGroup::Background );
- int offset=0;
- if ( KOPrefs::instance()->monthViewUsesResourceColor() &&
- mResourceColor.isValid() ) {
- p->setBackgroundColor( mResourceColor );
- p->eraseRect( 0, 0, listBox()->maxItemWidth(), height( listBox() ) );
- offset=2;
+ TQColor bgColor = TQColor(); // Default invalid color;
+ if ( mIncidence && mTodo ) {
+ if ( static_cast<Todo*>( mIncidence )->isOverdue() ) {
+ bgColor = KOPrefs::instance()->todoOverdueColor();
+ } else if ( static_cast<Todo*>( mIncidence )->dtDue().date() == TQDate::currentDate() ) {
+ bgColor = KOPrefs::instance()->todoDueTodayColor();
+ }
+ }
+
+ if ( !bgColor.isValid() ) {
+ if ( KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemResourceOnly ||
+ KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemResourceInsideCategoryOutside ) {
+ bgColor = resourceColor();
+ } else {
+ bgColor = catColor();
+ }
+
+ if ( !bgColor.isValid() ) {
+ bgColor = palette().color( TQPalette::Normal,
+ sel ? TQColorGroup::Highlight :
+ TQColorGroup::Background );
+ }
+ }
+
+ TQColor frameColor;
+ if ( KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemResourceOnly ||
+ KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemCategoryInsideResourceOutside ) {
+ frameColor = resourceColor();
+ } else {
+ frameColor = catColor();
+ }
+
+ if ( mIncidence ) {
+ if ( mIncidence->categories().isEmpty() &&
+ KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemResourceInsideCategoryOutside ) {
+ frameColor = bgColor;
+ }
+
+ if ( mIncidence->categories().isEmpty() &&
+ KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemCategoryInsideResourceOutside ) {
+ bgColor = frameColor;
+ }
}
- if ( KOPrefs::instance()->monthViewUsesCategoryColor() ) {
- p->setBackgroundColor( bgColor );
- p->eraseRect( offset, offset, listBox()->maxItemWidth()-2*offset, height( listBox() )-2*offset );
+
+ if ( !frameColor.isValid() ) {
+ frameColor = palette().color( TQPalette::Normal,
+ sel ? TQColorGroup::Highlight :
+ TQColorGroup::Foreground );
+ } else {
+ frameColor = frameColor.dark( 115 );
}
+
+ // draw the box for the item
+ p->setBackgroundColor( frameColor );
+ p->eraseRect( 0, 0, listBox()->maxItemWidth(), height( listBox() ) );
+ int offset = 2;
+ p->setBackgroundColor( bgColor );
+ p->eraseRect( offset, offset, listBox()->maxItemWidth()-2*offset, height( listBox() )-2*offset );
+
int x = 3;
-// Do NOT put on the event pixmap because it takes up too much space
-// if ( mEvent ) {
-// p->drawPixmap( x, 0, mEventPixmap );
-// x += mEventPixmap.width() + 2;
-// }
+
+ bool specialEvent = false;
+ if ( mEvent ) {
+ if ( mIncidence->customProperty( "KABC", "BIRTHDAY" ) == "YES" ) {
+ specialEvent = true;
+ if ( mIncidence->customProperty( "KABC", "ANNIVERSARY" ) == "YES" ) {
+ p->drawPixmap( x, 0, mAnniversaryPixmap );
+ x += mAnniversaryPixmap.width() + 2;
+ } else {
+ p->drawPixmap( x, 0, mBirthdayPixmap );
+ x += mBirthdayPixmap.width() + 2;
+ }
+ // Do NOT put on the event pixmap because it takes up too much space
+ //} else {
+ // p->drawPixmap( x, 0, mEventPixmap );
+ // x += mEventPixmap.width() + 2;
+ //
+ }
+ }
+
if ( mTodo ) {
p->drawPixmap( x, 0, mTodoPixmap );
x += mTodoPixmap.width() + 2;
@@ -249,11 +333,11 @@ void MonthViewItem::paint( TQPainter *p )
p->drawPixmap( x, 0, mTodoDonePixmap );
x += mTodoPixmap.width() + 2;
}
- if ( mRecur ) {
+ if ( mRecur && !specialEvent ) {
p->drawPixmap( x, 0, mRecurPixmap );
x += mRecurPixmap.width() + 2;
}
- if ( mAlarm ) {
+ if ( mAlarm && !specialEvent ) {
p->drawPixmap( x, 0, mAlarmPixmap );
x += mAlarmPixmap.width() + 2;
}
@@ -300,7 +384,8 @@ int MonthViewItem::width( const TQListBox *lb ) const
MonthViewCell::MonthViewCell( KOMonthView *parent)
: TQWidget( parent ),
- mMonthView( parent ), mPrimary( false ), mHoliday( false )
+ mMonthView( parent ), mPrimary( false ), mHoliday( false ),
+ isSelected( false )
{
TQVBoxLayout *topLayout = new TQVBoxLayout( this );
@@ -314,9 +399,6 @@ MonthViewCell::MonthViewCell( KOMonthView *parent)
mItemList->setFrameStyle( TQFrame::Panel | TQFrame::Plain );
mItemList->setLineWidth( 1 );
- new KOMonthCellToolTip( mItemList->viewport(),
- static_cast<KNoScrollListBox *>( mItemList ) );
-
topLayout->addWidget( mItemList );
mLabel->raise();
@@ -357,6 +439,11 @@ void MonthViewCell::setDate( const TQDate &date )
}
mLabel->setText( text );
+ new KOMonthCellToolTip( mItemList->viewport(),
+ monthView()->calendar(),
+ mDate,
+ static_cast<KNoScrollListBox *>( mItemList ) );
+
resizeEvent( 0 );
}
@@ -368,10 +455,11 @@ TQDate MonthViewCell::date() const
void MonthViewCell::setFrameWidth()
{
// show current day with a thicker frame
- if ( mDate == TQDate::currentDate() )
+ if ( mDate == TQDate::currentDate() ) {
mItemList->setLineWidth( 3 );
- else
+ } else if ( !isSelected ) {
mItemList->setLineWidth( 1 );
+ }
}
void MonthViewCell::setPrimary( bool primary )
@@ -490,13 +578,16 @@ class MonthViewCell::CreateItemVisitor :
mItem = new MonthViewItem( event, dt, text );
mItem->setEvent( true );
- if (KOPrefs::instance()->monthViewUsesCategoryColor()) {
+ if ( KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemCategoryOnly ||
+ KOPrefs::instance()->monthItemColors() == KOPrefs::MonthItemCategoryInsideResourceOutside ) {
TQStringList categories = event->categories();
TQString cat = categories.first();
if (cat.isEmpty()) {
- mItem->setPalette(TQPalette(KOPrefs::instance()->mEventColor, KOPrefs::instance()->mEventColor));
+ mItem->setPalette(TQPalette(KOPrefs::instance()->unsetCategoryColor(),
+ KOPrefs::instance()->unsetCategoryColor()) );
} else {
- mItem->setPalette(TQPalette(*(KOPrefs::instance()->categoryColor(cat)), *(KOPrefs::instance()->categoryColor(cat))));
+ mItem->setPalette(TQPalette(*(KOPrefs::instance()->categoryColor(cat)),
+ *(KOPrefs::instance()->categoryColor(cat))));
}
} else {
mItem->setPalette( mStandardPalette );
@@ -514,7 +605,8 @@ class MonthViewCell::CreateItemVisitor :
if ( !KOPrefs::instance()->showAllDayTodo() )
return false;
TQDateTime dt( mDate );
- if ( todo->hasDueDate() && !todo->doesFloat() ) {
+ if ( todo->hasDueDate() && !todo->doesFloat() &&
+ todo->dtDue().time() != TQTime( 0,0 ) && todo->dtDue().time().isValid() ) {
text += KGlobal::locale()->formatTime( todo->dtDue().time() );
text += ' ';
dt.setTime( todo->dtDue().time() );
@@ -547,9 +639,9 @@ void MonthViewCell::addIncidence( Incidence *incidence, CreateItemVisitor& v, in
item->setAlarm( incidence->isAlarmEnabled() );
item->setRecur( incidence->recurrenceType() );
- TQColor resourceColor = KOHelper::resourceColor( mCalendar, incidence );
+ TQColor resourceColor = KOHelper::resourceColor( monthView()->calendar(), incidence );
if ( !resourceColor.isValid() )
- resourceColor = KOPrefs::instance()->mEventColor;
+ resourceColor = KOPrefs::instance()->unsetCategoryColor();
item->setResourceColor( resourceColor );
// FIXME: Find the correct position (time-wise) to insert the item.
@@ -661,6 +753,9 @@ TQDate MonthViewCell::selectedIncidenceDate()
void MonthViewCell::select()
{
+
+ isSelected = true;
+
// setSelectedCell will deselect currently selected cells
mMonthView->setSelectedCell( this );
@@ -676,6 +771,8 @@ void MonthViewCell::select()
void MonthViewCell::deselect()
{
+ isSelected = false;
+
mItemList->clearSelection();
mItemList->setFrameStyle( TQFrame::Plain | TQFrame::Panel );
setFrameWidth();
@@ -693,7 +790,7 @@ void MonthViewCell::defaultAction( TQListBoxItem *item )
select();
if ( !item ) {
- emit newEventSignal( date() );
+ emit newEventSignal( 0/*ResourceCalendar*/, TQString()/*subResource*/, date() );
} else {
MonthViewItem *eventItem = static_cast<MonthViewItem *>( item );
Incidence *incidence = eventItem->incidence();
@@ -708,9 +805,10 @@ void MonthViewCell::contextMenu( TQListBoxItem *item )
if ( item ) {
MonthViewItem *eventItem = static_cast<MonthViewItem *>( item );
Incidence *incidence = eventItem->incidence();
- if ( incidence ) mMonthView->showEventContextMenu( incidence, date() );
- }
- else {
+ if ( incidence ) {
+ mMonthView->showEventContextMenu( monthView()->calendar(), incidence, mDate );
+ }
+ } else {
mMonthView->showGeneralContextMenu();
}
}
@@ -764,14 +862,13 @@ KOMonthView::KOMonthView( Calendar *calendar, TQWidget *parent, const char *name
for( row = 0; row < mNumWeeks; ++row ) {
for( col = 0; col < mDaysPerWeek; ++col ) {
MonthViewCell *cell = new MonthViewCell( this );
- cell->setCalendar(calendar);
mCells.insert( row * mDaysPerWeek + col, cell );
dayLayout->addWidget( cell, row + 2, col );
- connect( cell, TQT_SIGNAL( defaultAction( Incidence * ) ),
- TQT_SLOT( defaultAction( Incidence * ) ) );
- connect( cell, TQT_SIGNAL( newEventSignal( const TQDate & ) ),
- TQT_SIGNAL( newEventSignal( const TQDate & ) ) );
+ connect( cell, TQT_SIGNAL(defaultAction(Incidence *)),
+ TQT_SLOT(defaultAction(Incidence *)) );
+ connect( cell, TQT_SIGNAL(newEventSignal(ResourceCalendar *,const TQString &,const TQDate &)),
+ TQT_SIGNAL(newEventSignal(ResourceCalendar *,const TQString &,const TQDate &)) );
}
dayLayout->setRowStretch( row + 2, 1 );
}
@@ -780,7 +877,7 @@ KOMonthView::KOMonthView( Calendar *calendar, TQWidget *parent, const char *name
updateConfig();
- emit incidenceSelected( 0 );
+ emit incidenceSelected( 0, TQDate() );
}
KOMonthView::~KOMonthView()
@@ -810,7 +907,7 @@ Incidence::List KOMonthView::selectedIncidences()
return selected;
}
-DateList KOMonthView::selectedDates()
+DateList KOMonthView::selectedIncidenceDates()
{
DateList selected;
@@ -851,6 +948,8 @@ void KOMonthView::updateConfig()
for ( uint i = 0; i < mCells.count(); ++i ) {
mCells[i]->updateConfig();
}
+
+ showLabel( !KOPrefs::instance()->fullViewMonth() );
}
void KOMonthView::updateDayLabels()
@@ -883,11 +982,8 @@ void KOMonthView::showDates( const TQDate &start, const TQDate & )
mLabel->setText( i18n( "monthname year", "%1 %2" )
.arg( calSys->monthName( start ) )
.arg( calSys->year( start ) ) );
- if ( !KOPrefs::instance()->fullViewMonth() ) {
- mLabel->show();
- } else {
- mLabel->hide();
- }
+
+ showLabel( !KOPrefs::instance()->fullViewMonth() );
bool primary = false;
uint i;
@@ -899,8 +995,9 @@ void KOMonthView::showDates( const TQDate &start, const TQDate & )
mCells[i]->setDate( date );
mDateToCell[ date ] = mCells[ i ];
- if( date == start )
+ if( date == start ) {
mCells[i]->select();
+ }
mCells[i]->setPrimary( primary );
@@ -916,7 +1013,22 @@ void KOMonthView::showDates( const TQDate &start, const TQDate & )
updateView();
}
-void KOMonthView::showIncidences( const Incidence::List & )
+TQDateTime KOMonthView::selectionStart()
+{
+ if ( mSelectedCell) {
+ return TQDateTime( mSelectedCell->date() );
+ } else {
+ return TQDateTime();
+ }
+}
+
+TQDateTime KOMonthView::selectionEnd()
+{
+ // Only one cell can be selected (for now)
+ return selectionStart();
+}
+
+void KOMonthView::showIncidences( const Incidence::List &, const TQDate & )
{
kdDebug(5850) << "KOMonthView::showIncidences( const Incidence::List & ) is not implemented yet." << endl;
}
@@ -941,8 +1053,14 @@ class KOMonthView::GetDateVisitor : public IncidenceBase::Visitor
}
bool visit( Todo *todo ) {
if ( todo->hasDueDate() ) {
- mStartDate = todo->dtDue();
- mEndDate = todo->dtDue();
+ if ( todo->dtDue().time() != TQTime( 0, 0 ) &&
+ todo->dtDue().time().isValid() ) {
+ mStartDate = todo->dtDue();
+ mEndDate = todo->dtDue();
+ } else {
+ mStartDate = TQDateTime( todo->dtDue().date(), TQTime( 23,59 ) );
+ mEndDate = mStartDate;
+ }
}// else
// return false;
return true;
@@ -1048,9 +1166,9 @@ void KOMonthView::resizeEvent( TQResizeEvent * )
}
}
-void KOMonthView::showEventContextMenu( Incidence *incidence, const TQDate &qd )
+void KOMonthView::showEventContextMenu( Calendar *cal, Incidence *incidence, const TQDate &qd )
{
- mEventContextMenu->showIncidencePopup( incidence, qd );
+ mEventContextMenu->showIncidencePopup( cal, incidence, qd );
}
void KOMonthView::showGeneralContextMenu()
@@ -1066,18 +1184,26 @@ void KOMonthView::setSelectedCell( MonthViewCell *cell )
mSelectedCell = cell;
if ( !mSelectedCell )
- emit incidenceSelected( 0 );
+ emit incidenceSelected( 0, TQDate() );
else
- emit incidenceSelected( mSelectedCell->selectedIncidence() );
+ if ( selectedIncidenceDates().isEmpty() ) {
+ emit incidenceSelected( mSelectedCell->selectedIncidence(), TQDate() );
+ } else {
+ emit incidenceSelected( mSelectedCell->selectedIncidence(), selectedIncidenceDates().first() );
+ }
}
void KOMonthView::processSelectionChange()
{
Incidence::List incidences = selectedIncidences();
if (incidences.count() > 0) {
- emit incidenceSelected( incidences.first() );
+ if ( selectedIncidenceDates().isEmpty() ) {
+ emit incidenceSelected( incidences.first(), TQDate() );
+ } else {
+ emit incidenceSelected( incidences.first(), selectedIncidenceDates().first() );
+ }
} else {
- emit incidenceSelected( 0 );
+ emit incidenceSelected( 0, TQDate() );
}
}
@@ -1088,3 +1214,12 @@ void KOMonthView::clearSelection()
mSelectedCell = 0;
}
}
+
+void KOMonthView::showLabel( bool show )
+{
+ if ( show ) {
+ mLabel->show();
+ } else {
+ mLabel->hide();
+ }
+}
diff --git a/korganizer/komonthview.h b/korganizer/komonthview.h
index 9a3015d03..dafce597f 100644
--- a/korganizer/komonthview.h
+++ b/korganizer/komonthview.h
@@ -36,12 +36,14 @@ class KNoScrollListBox;
class KOMonthCellToolTip : public QToolTip
{
public:
- KOMonthCellToolTip (TQWidget* parent, KNoScrollListBox* lv );
+ KOMonthCellToolTip (TQWidget* parent, Calendar *calendar, const TQDate &date, KNoScrollListBox* lv );
protected:
void maybeTip( const TQPoint & pos);
private:
+ Calendar *mCalendar;
+ TQDate mDate;
KNoScrollListBox* eventlist;
};
@@ -107,6 +109,8 @@ class MonthViewItem: public QListBoxItem
bool mReply;
TQPixmap mEventPixmap;
+ TQPixmap mBirthdayPixmap;
+ TQPixmap mAnniversaryPixmap;
TQPixmap mTodoPixmap;
TQPixmap mTodoDonePixmap;
TQPixmap mAlarmPixmap;
@@ -117,6 +121,7 @@ class MonthViewItem: public QListBoxItem
TQDateTime mDateTime;
Incidence *mIncidence;
+ TQColor catColor() const;
};
@@ -138,6 +143,9 @@ class MonthViewCell : public QWidget
/** @return Date of cell */
TQDate date() const;
+ /** @return MonthView parent */
+ KOMonthView *monthView() { return mMonthView; }
+
/**
Set this cell as primary if @p primary is true. A primary cell belongs
to the current month. A non-primary cell belongs to the month before or
@@ -184,7 +192,6 @@ class MonthViewCell : public QWidget
void deselect();
- void setCalendar( Calendar*cal ) { mCalendar = cal; }
signals:
void defaultAction( Incidence * );
/**
@@ -192,7 +199,8 @@ class MonthViewCell : public QWidget
will pop up.
@param date The date of the event we want create.
*/
- void newEventSignal( const TQDate &date );
+ void newEventSignal( ResourceCalendar *res,const TQString &subResource,
+ const TQDate &date );
public slots:
void select();
@@ -207,8 +215,6 @@ class MonthViewCell : public QWidget
private:
KOMonthView *mMonthView;
- // We need the calendar for paint the ResourceColor
- Calendar *mCalendar;
TQDate mDate;
bool mPrimary;
@@ -218,6 +224,8 @@ class MonthViewCell : public QWidget
TQLabel *mLabel;
KNoScrollListBox *mItemList;
+ bool isSelected;
+
TQSize mLabelSize;
// TQPalette mOriginalPalette;
TQPalette mHolidayPalette;
@@ -249,7 +257,11 @@ class KOMonthView: public KOEventView
virtual Incidence::List selectedIncidences();
/** Returns dates of the currently selected events */
- virtual DateList selectedDates();
+ virtual DateList selectedIncidenceDates();
+
+ virtual TQDateTime selectionStart();
+
+ virtual TQDateTime selectionEnd();
virtual bool eventDurationHint(TQDateTime &startDt, TQDateTime &endDt, bool &allDay);
@@ -257,14 +269,14 @@ class KOMonthView: public KOEventView
virtual void updateView();
virtual void updateConfig();
virtual void showDates(const TQDate &start, const TQDate &end);
- virtual void showIncidences( const Incidence::List &incidenceList );
+ virtual void showIncidences( const Incidence::List &incidenceList, const TQDate &date );
void changeIncidenceDisplay(Incidence *, int);
void changeIncidenceDisplayAdded(Incidence *, MonthViewCell::CreateItemVisitor&);
void clearSelection();
- void showEventContextMenu( Incidence *, const TQDate & );
+ void showEventContextMenu( Calendar *, Incidence *, const TQDate & );
void showGeneralContextMenu();
void setSelectedCell( MonthViewCell * );
@@ -279,6 +291,8 @@ class KOMonthView: public KOEventView
void updateDayLabels();
private:
+ void showLabel( bool show );
+
class GetDateVisitor;
int mDaysPerWeek;
int mNumWeeks;
diff --git a/korganizer/koprefs.cpp b/korganizer/koprefs.cpp
index 3532b1cc1..535fe1045 100644
--- a/korganizer/koprefs.cpp
+++ b/korganizer/koprefs.cpp
@@ -88,12 +88,9 @@ KOPrefs::KOPrefs() :
timeBarFontItem()->setDefaultValue( mDefaultTimeBarFont );
monthViewFontItem()->setDefaultValue( mDefaultMonthViewFont );
- eventColorItem()->setDefaultValue( mDefaultCategoryColor );
// Load it now, not deep within some painting code
mMyAddrBookMails = KABC::StdAddressBook::self()->whoAmI().emails();
-
- mAlarmsEnabledByDefault = false;
}
@@ -202,8 +199,8 @@ void KOPrefs::usrReadConfig()
TQMapIterator<TQString, TQString> it3;
for( it3 = map.begin(); it3 != map.end(); ++it3 ) {
- kdDebug(5850)<< "KOPrefs::usrReadConfig: key: " << it3.key() << " value: "
- << it3.data()<<endl;
+ // kdDebug(5850)<< "KOPrefs::usrReadConfig: key: " << it3.key() << " value: "
+ // << it3.data()<<endl;
setResourceColor( it3.key(), config()->readColorEntry( it3.key(),
&mDefaultResourceColor ) );
}
@@ -213,9 +210,6 @@ void KOPrefs::usrReadConfig()
setTimeZoneIdDefault();
}
- config()->setGroup("Event Dialogs");
- mAlarmsEnabledByDefault = config()->readBoolEntry( "Alarm Enabled By Default" );
-
#if 0
config()->setGroup("FreeBusy");
if( mRememberRetrievePw )
@@ -256,9 +250,6 @@ void KOPrefs::usrWriteConfig()
i->writeConfig( config() );
}
- config()->setGroup("Event Dialogs");
- config()->writeEntry( "Alarm Enabled By Default", mAlarmsEnabledByDefault );
-
#if 0
if( mRememberRetrievePw )
config()->writeEntry( "Retrieve Server Password", KStringHandler::obscure( mRetrievePassword ) );
@@ -292,8 +283,8 @@ bool KOPrefs::hasCategoryColor( const TQString& cat ) const
void KOPrefs::setResourceColor ( const TQString &cal, const TQColor &color )
{
- kdDebug(5850)<<"KOPrefs::setResourceColor: " << cal << " color: "<<
- color.name()<<endl;
+ // kdDebug(5850)<<"KOPrefs::setResourceColor: " << cal << " color: "<<
+ // color.name()<<endl;
mResourceColors.replace( cal, new TQColor( color ) );
}
@@ -327,12 +318,21 @@ TQColor* KOPrefs::resourceColor( const TQString &cal )
TQString KOPrefs::fullName()
{
+ TQString tusername;
if ( mEmailControlCenter ) {
KEMailSettings settings;
- return settings.getSetting( KEMailSettings::RealName );
+ tusername = settings.getSetting( KEMailSettings::RealName );
} else {
- return userName();
+ tusername = userName();
}
+
+ // Quote the username as it might contain commas and other quotable chars.
+ tusername = KPIM::quoteNameIfNecessary( tusername );
+
+ TQString tname, temail;
+ KPIM::getNameAndMail( tusername, tname, temail ); // ignore return value
+ // which is always false
+ return tname;
}
TQString KOPrefs::email()
@@ -415,8 +415,11 @@ bool KOPrefs::thatIsMe( const TQString& _email )
for ( KPIM::IdentityManager::ConstIterator it = KOCore::self()->identityManager()->begin();
it != KOCore::self()->identityManager()->end(); ++it ) {
- if ( email == (*it).emailAddr() )
+ if ( email == (*it).primaryEmailAddress() )
return true;
+ const TQStringList & aliases = (*it).emailAliases();
+ if ( aliases.find( email ) != aliases.end() )
+ return true;
}
if ( mAdditionalMails.find( email ) != mAdditionalMails.end() )
diff --git a/korganizer/koprefs.h b/korganizer/koprefs.h
index 48a42cbd5..fcda71437 100644
--- a/korganizer/koprefs.h
+++ b/korganizer/koprefs.h
@@ -91,7 +91,6 @@ class KDE_EXPORT KOPrefs : public KOPrefsBase
TQColor* resourceColor( const TQString & );
TQString mHtmlExportFile;
- bool mAlarmsEnabledByDefault;
// Groupware passwords
TQString mPublishPassword;
diff --git a/korganizer/koprefsdialog.cpp b/korganizer/koprefsdialog.cpp
index 0205b59ea..37f889cfb 100644
--- a/korganizer/koprefsdialog.cpp
+++ b/korganizer/koprefsdialog.cpp
@@ -44,20 +44,24 @@
#include <tqwhatsthis.h>
#include <kcolorbutton.h>
+#include <kcombobox.h>
#include <kdebug.h>
#include <klocale.h>
#include <kglobal.h>
#include <kmessagebox.h>
#include <kiconloader.h>
+#include <knuminput.h>
#include <kemailsettings.h>
#include <kcalendarsystem.h>
#include <ktrader.h>
#include <kpushbutton.h>
#include <kocore.h>
-#include <libkcal/calendarresources.h>
#include <kstandarddirs.h>
#include <ksimpleconfig.h>
#include <kholidays.h>
+#include <kurlrequester.h>
+
+#include <libkcal/calendarresources.h>
#if defined(USE_SOLARIS)
#include <sys/param.h>
@@ -315,21 +319,46 @@ class KOPrefsDialogTime : public KPrefsModule
topLayout->addWidget( defaultDuration->label(), 4, 0 );
topLayout->addWidget( defaultDuration->timeEdit(), 4, 1 );
- TQStringList alarmList;
- alarmList << i18n( "1 minute" ) << i18n( "5 minutes" )
- << i18n( "10 minutes" ) << i18n( "15 minutes" )
- << i18n( "30 minutes" );
- TQLabel *alarmLabel = new TQLabel( i18n( "Default reminder time:" ), topFrame);
- topLayout->addWidget( alarmLabel, 5, 0 );
- TQWhatsThis::add( alarmLabel,
- i18n( "Enter the default reminder time here." ) );
- mAlarmTimeCombo = new TQComboBox( topFrame );
- TQWhatsThis::add( mAlarmTimeCombo,
- i18n( "Enter the default reminder time here." ) );
- connect( mAlarmTimeCombo, TQT_SIGNAL( activated( int ) ),
- TQT_SLOT( slotWidChanged() ) );
- mAlarmTimeCombo->insertStringList( alarmList );
- topLayout->addWidget( mAlarmTimeCombo, 5, 1 );
+ TQGroupBox *remindersGroupBox = new TQGroupBox( 1, Horizontal,
+ i18n( "Reminders" ),
+ topFrame );
+ topLayout->addMultiCellWidget( remindersGroupBox, 5, 5, 0, 1 );
+
+ TQHBox *remindersBox = new TQHBox( remindersGroupBox );
+ new TQLabel( i18n( "Default reminder time:" ), remindersBox );
+
+ mReminderTimeSpin = new KIntSpinBox( remindersBox );
+ connect( mReminderTimeSpin, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(slotWidChanged()) );
+
+ mReminderUnitsCombo = new KComboBox( remindersBox );
+ connect( mReminderUnitsCombo, TQT_SIGNAL(activated(int)), TQT_SLOT(slotWidChanged()) );
+ mReminderUnitsCombo->insertItem( i18n( "minute(s)" ) );
+ mReminderUnitsCombo->insertItem( i18n( "hour(s)" ) );
+ mReminderUnitsCombo->insertItem( i18n( "day(s)" ) );
+
+ TQHBox *audioFileRemindersBox = new TQHBox( remindersGroupBox );
+
+ TQCheckBox *cb = addWidBool( KOPrefs::instance()->defaultAudioFileRemindersItem(),
+ audioFileRemindersBox )->checkBox();
+ cb->setText( TQString::null );
+
+ if ( KOPrefs::instance()->audioFilePathItem()->value().isEmpty() ) {
+ TQString defAudioFile = KGlobal::dirs()->findResourceDir( "sound", "KDE-Sys-Warning.ogg");
+ KOPrefs::instance()->audioFilePathItem()->setValue( defAudioFile + "KDE-Sys-Warning.ogg" );
+ }
+ TQString filter = i18n( "*.ogg *.wav *.mp3 *.wma *.flac *.aiff *.raw *.au *.ra|"
+ "Audio Files (*.ogg *.wav *.mp3 *.wma *.flac *.aiff *.raw *.au *.ra)" );
+ KURLRequester *rq = addWidPath( KOPrefs::instance()->audioFilePathItem(),
+ audioFileRemindersBox, filter )->urlRequester();
+ rq->setEnabled( cb->isChecked() );
+ connect( cb, TQT_SIGNAL(toggled(bool)),
+ rq, TQT_SLOT(setEnabled( bool)) );
+
+ TQHBox *eventRemindersBox = new TQHBox( remindersGroupBox );
+ addWidBool( KOPrefs::instance()->defaultEventRemindersItem(), eventRemindersBox )->checkBox();
+
+ TQHBox *todoRemindersBox = new TQHBox( remindersGroupBox );
+ addWidBool( KOPrefs::instance()->defaultTodoRemindersItem(), todoRemindersBox )->checkBox();
TQLabel *alarmDefaultLabel = new TQLabel( i18n( "Enable reminders by default:" ), topFrame);
topLayout->addWidget( alarmDefaultLabel, 6, 0 );
@@ -386,8 +415,9 @@ class KOPrefsDialogTime : public KPrefsModule
setCombo( mTimeZoneCombo,
i18n( KOPrefs::instance()->mTimeZoneId.utf8() ) );
- mAlarmTimeCombo->setCurrentItem( KOPrefs::instance()->mAlarmTime );
- mAlarmTimeDefaultCheckBox->setChecked ( KOPrefs::instance()->mAlarmsEnabledByDefault );
+ mReminderTimeSpin->setValue( KOPrefs::instance()->mReminderTime );
+ mReminderUnitsCombo->setCurrentItem( KOPrefs::instance()->mReminderTimeUnits );
+
for ( int i = 0; i < 7; ++i ) {
mWorkDays[i]->setChecked( (1<<i) & (KOPrefs::instance()->mWorkWeekMask) );
}
@@ -409,8 +439,9 @@ class KOPrefsDialogTime : public KPrefsModule
TQString::null :
mRegionMap[mHolidayCombo->currentText()];
- KOPrefs::instance()->mAlarmTime = mAlarmTimeCombo->currentItem();
- KOPrefs::instance()->mAlarmsEnabledByDefault = mAlarmTimeDefaultCheckBox->isChecked();
+ KOPrefs::instance()->mReminderTime = mReminderTimeSpin->value();
+ KOPrefs::instance()->mReminderTimeUnits = mReminderUnitsCombo->currentItem();
+
int mask = 0;
for ( int i = 0; i < 7; ++i ) {
if (mWorkDays[i]->isChecked()) mask = mask | (1<<i);
@@ -440,7 +471,8 @@ class KOPrefsDialogTime : public KPrefsModule
TQStringList tzonenames;
TQComboBox *mHolidayCombo;
TQMap<TQString,TQString> mRegionMap;
- TQComboBox *mAlarmTimeCombo;
+ KIntSpinBox *mReminderTimeSpin;
+ KComboBox *mReminderUnitsCombo;
TQCheckBox *mAlarmTimeDefaultCheckBox;
TQCheckBox *mWorkDays[7];
};
@@ -483,6 +515,7 @@ class KOPrefsDialogViews : public KPrefsModule
topFrame );
addWidBool( KOPrefs::instance()->dailyRecurItem(), dateNavGroup );
addWidBool( KOPrefs::instance()->weeklyRecurItem(), dateNavGroup );
+ addWidBool( KOPrefs::instance()->weekNumbersShowWorkItem(), dateNavGroup );
topLayout->addWidget( dateNavGroup );
@@ -520,20 +553,14 @@ class KOPrefsDialogViews : public KPrefsModule
topLayout->addWidget( agendaGroup );
- /*** Month and Todo view groups side by side, to save space. ***/
- TQHBoxLayout *hbox = new TQHBoxLayout();
- topLayout->addLayout( hbox );
-
/*** Month View Group ***/
TQGroupBox *monthGroup = new TQGroupBox( 1, Horizontal,
i18n("Month View"),
topFrame );
addWidBool( KOPrefs::instance()->enableMonthScrollItem(), monthGroup );
addWidBool( KOPrefs::instance()->fullViewMonthItem(), monthGroup );
- addWidBool( KOPrefs::instance()->monthViewUsesCategoryColorItem(),
- monthGroup );
- addWidBool( KOPrefs::instance()->monthViewUsesResourceColorItem(), monthGroup );
- hbox->addWidget( monthGroup );
+ addWidCombo( KOPrefs::instance()->monthItemColorsItem(), monthGroup );
+ topLayout->addWidget( monthGroup );
/*** Todo View Group ***/
@@ -542,7 +569,7 @@ class KOPrefsDialogViews : public KPrefsModule
topFrame );
addWidBool( KOPrefs::instance()->fullViewTodoItem(), todoGroup );
addWidBool( KOPrefs::instance()->recordTodosInJournalsItem(), todoGroup );
- hbox->addWidget( todoGroup );
+ topLayout->addWidget( todoGroup );
topLayout->addStretch( 1 );
@@ -642,40 +669,42 @@ KOPrefsDialogColors::KOPrefsDialogColors( TQWidget *parent, const char *name )
topLayout->addWidget(highlightColor->label(),1,0);
topLayout->addWidget(highlightColor->button(),1,1);
- KPrefsWidColor *eventColor =
- addWidColor( KOPrefs::instance()->eventColorItem(), topFrame );
- topLayout->addWidget(eventColor->label(),2,0);
- topLayout->addWidget(eventColor->button(),2,1);
-
// agenda view background color
KPrefsWidColor *agendaBgColor =
addWidColor( KOPrefs::instance()->agendaBgColorItem(), topFrame );
- topLayout->addWidget(agendaBgColor->label(),3,0);
- topLayout->addWidget(agendaBgColor->button(),3,1);
+ topLayout->addWidget(agendaBgColor->label(),2,0);
+ topLayout->addWidget(agendaBgColor->button(),2,1);
// working hours color
KPrefsWidColor *workingHoursColor =
addWidColor( KOPrefs::instance()->workingHoursColorItem(), topFrame );
- topLayout->addWidget(workingHoursColor->label(),4,0);
- topLayout->addWidget(workingHoursColor->button(),4,1);
+ topLayout->addWidget(workingHoursColor->label(),3,0);
+ topLayout->addWidget(workingHoursColor->button(),3,1);
// Todo due today color
KPrefsWidColor *todoDueTodayColor =
addWidColor( KOPrefs::instance()->todoDueTodayColorItem(), topFrame );
- topLayout->addWidget(todoDueTodayColor->label(),5,0);
- topLayout->addWidget(todoDueTodayColor->button(),5,1);
+ topLayout->addWidget(todoDueTodayColor->label(),4,0);
+ topLayout->addWidget(todoDueTodayColor->button(),4,1);
// Todo overdue color
KPrefsWidColor *todoOverdueColor =
addWidColor( KOPrefs::instance()->todoOverdueColorItem(), topFrame );
- topLayout->addWidget(todoOverdueColor->label(),6,0);
- topLayout->addWidget(todoOverdueColor->button(),6,1);
+ topLayout->addWidget(todoOverdueColor->label(),5,0);
+ topLayout->addWidget(todoOverdueColor->button(),5,1);
+
+ // "No Category" color
+ KPrefsWidColor *unsetCategoryColor =
+ addWidColor( KOPrefs::instance()->unsetCategoryColorItem(), topFrame );
+ topLayout->addWidget( unsetCategoryColor->label(), 6, 0 );
+ topLayout->addWidget( unsetCategoryColor->button(), 6, 1 );
// categories colors
TQGroupBox *categoryGroup = new TQGroupBox(1,Horizontal,i18n("Categories"),
topFrame);
topLayout->addMultiCellWidget(categoryGroup,7,7,0,1);
+
mCategoryCombo = new TQComboBox(categoryGroup);
mCategoryCombo->insertStringList(KOPrefs::instance()->mCustomCategories);
TQWhatsThis::add( mCategoryCombo,
@@ -1031,6 +1060,11 @@ void KOPrefsDialogGroupwareScheduling::usrWriteConfig()
KOPrefs::instance()->mFreeBusyRetrieveUser = mGroupwarePage->retrieveUser->text();
KOPrefs::instance()->mFreeBusyRetrievePassword = mGroupwarePage->retrievePassword->text();
KOPrefs::instance()->mFreeBusyRetrieveSavePassword = mGroupwarePage->retrieveSavePassword->isChecked();
+
+ // clear the url cache for our user
+ TQString configFile = locateLocal( "data", "korganizer/freebusyurls" );
+ KConfig cfg( configFile );
+ cfg.deleteGroup( KOPrefs::instance()->email() );
}
extern "C"
diff --git a/korganizer/korgac/alarmdialog.cpp b/korganizer/korgac/alarmdialog.cpp
index 6c9d62e90..839d463a9 100644
--- a/korganizer/korgac/alarmdialog.cpp
+++ b/korganizer/korgac/alarmdialog.cpp
@@ -2,6 +2,7 @@
This file is part of the KOrganizer alarm daemon.
Copyright (c) 2000,2003 Cornelius Schumacher <schumacher@kde.org>
+ Copyright (c) 2009-2010 Klar�lvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -31,11 +32,14 @@
#include <tqpushbutton.h>
#include <tqcstring.h>
#include <tqdatastream.h>
+#include <tqsplitter.h>
+#include <dcopclient.h>
+#include <dcopref.h>
#include <kapplication.h>
#include <kconfig.h>
+#include <kdcopservicestarter.h>
#include <kiconloader.h>
-#include <dcopclient.h>
#include <klocale.h>
#include <kprocess.h>
#include <kaudioplayer.h>
@@ -48,64 +52,97 @@
#include <klockfile.h>
#include <libkcal/event.h>
+#include <libkcal/incidenceformatter.h>
#include "koeventviewer.h"
#include "alarmdialog.h"
#include "alarmdialog.moc"
+static int defSuspendVal = 5;
+static int defSuspendUnit = 0; // 0=>minutes, 1=>hours, 2=>days, 3=>weeks
+
class AlarmListItem : public KListViewItem
{
public:
- AlarmListItem( Incidence *incidence, TQListView *parent ) :
- KListViewItem( parent ),
- mIncidence( incidence->clone() ),
- mNotified( false )
- {}
+ AlarmListItem( const TQString &uid, TQListView *parent )
+ : KListViewItem( parent ), mUid( uid ), mNotified( false )
+ {
+ }
~AlarmListItem()
{
- delete mIncidence;
}
- Incidence *mIncidence;
+ int compare( TQListViewItem *item, int iCol, bool bAscending ) const;
+
+ TQString mDisplayText;
+
+ TQString mUid;
TQDateTime mRemindAt;
+ TQDateTime mHappening;
bool mNotified;
};
+int AlarmListItem::compare( TQListViewItem *item, int iCol, bool bAscending ) const
+{
+ if ( iCol == 1 ) {
+ AlarmListItem *pItem = static_cast<AlarmListItem *>( item );
+ return pItem->mHappening.secsTo( mHappening );
+ } else {
+ return KListViewItem::compare( item, iCol, bAscending );
+ }
+}
+
typedef TQValueList<AlarmListItem*> ItemList;
-AlarmDialog::AlarmDialog( TQWidget *parent, const char *name )
- : KDialogBase( Plain, WType_TopLevel | WStyle_Customize | WStyle_StaysOnTop |
- WStyle_DialogBorder,
- parent, name, false, i18n("Reminder"), Ok | User1 | User2 | User3, User1/*3*/,
- false, i18n("Dismiss all"), i18n("Edit..."), i18n("Suspend") ),
- mSuspendTimer(this)
+AlarmDialog::AlarmDialog( KCal::CalendarResources *calendar, TQWidget *parent, const char *name )
+ : KDialogBase( Plain,
+ WType_TopLevel | WStyle_Customize | WStyle_StaysOnTop | WStyle_DialogBorder,
+ parent, name, false, i18n("Reminder"),
+ Ok | User1 | User2 | User3, NoDefault,
+ false, i18n("Edit..."), i18n("Dismiss All"), i18n("Dismiss Reminder") ),
+ mCalendar( calendar ), mSuspendTimer(this)
{
+ // User1 => Edit...
+ // User2 => Dismiss All
+ // User3 => Dismiss Selected
+ // Ok => Suspend
+
+ connect( calendar, TQT_SIGNAL(calendarChanged()),
+ this, TQT_SLOT(slotCalendarChanged()) );
+
KGlobal::iconLoader()->addAppDir( "kdepim" );
- setButtonOK( i18n( "Dismiss" ) );
+ setButtonOK( i18n( "Suspend" ) );
TQWidget *topBox = plainPage();
TQBoxLayout *topLayout = new TQVBoxLayout( topBox );
topLayout->setSpacing( spacingHint() );
- TQLabel *label = new TQLabel( i18n("The following events triggered reminders:"),
- topBox );
+ TQLabel *label = new TQLabel( i18n("The following items triggered reminders:"), topBox );
topLayout->addWidget( label );
- mIncidenceListView = new KListView( topBox );
+ mSplitter = new TQSplitter( TQt::Vertical, topBox );
+ mSplitter->setOpaqueResize( KGlobalSettings::opaqueResize() );
+ topLayout->addWidget( mSplitter );
+
+ mIncidenceListView = new KListView( mSplitter );
mIncidenceListView->addColumn( i18n( "Summary" ) );
- mIncidenceListView->addColumn( i18n( "Due" ) );
+ mIncidenceListView->addColumn( i18n( "Date, Time" ) );
+ mIncidenceListView->setSorting( 0, true );
+ mIncidenceListView->setSorting( 1, true );
+ mIncidenceListView->setSortColumn( 1 );
+ mIncidenceListView->setShowSortIndicator( true );
mIncidenceListView->setAllColumnsShowFocus( true );
mIncidenceListView->setSelectionMode( TQListView::Extended );
- topLayout->addWidget( mIncidenceListView );
connect( mIncidenceListView, TQT_SIGNAL(selectionChanged()), TQT_SLOT(updateButtons()) );
- connect( mIncidenceListView, TQT_SIGNAL(doubleClicked(TQListViewItem*)), TQT_SLOT(slotUser2()) );
+ connect( mIncidenceListView, TQT_SIGNAL(doubleClicked(TQListViewItem*)), TQT_SLOT(edit()) );
connect( mIncidenceListView, TQT_SIGNAL(currentChanged(TQListViewItem*)), TQT_SLOT(showDetails()) );
connect( mIncidenceListView, TQT_SIGNAL(selectionChanged()), TQT_SLOT(showDetails()) );
- mDetailView = new KOEventViewer( topBox );
- topLayout->addWidget( mDetailView );
+ mDetailView = new KOEventViewer( mCalendar, mSplitter );
+ mDetailView->setFocus(); // set focus here to start with to make it harder
+ // to hit return by mistake and dismiss a reminder.
TQHBox *suspendBox = new TQHBox( topBox );
suspendBox->setSpacing( spacingHint() );
@@ -113,7 +150,7 @@ AlarmDialog::AlarmDialog( TQWidget *parent, const char *name )
TQLabel *l = new TQLabel( i18n("Suspend &duration:"), suspendBox );
mSuspendSpin = new TQSpinBox( 1, 9999, 1, suspendBox );
- mSuspendSpin->setValue( 5 ); // default suspend duration
+ mSuspendSpin->setValue( defSuspendVal ); // default suspend duration
l->setBuddy( mSuspendSpin );
mSuspendUnit = new KComboBox( suspendBox );
@@ -121,11 +158,14 @@ AlarmDialog::AlarmDialog( TQWidget *parent, const char *name )
mSuspendUnit->insertItem( i18n("hour(s)") );
mSuspendUnit->insertItem( i18n("day(s)") );
mSuspendUnit->insertItem( i18n("week(s)") );
+ mSuspendUnit->setCurrentItem( defSuspendUnit );
+
connect( &mSuspendTimer, TQT_SIGNAL(timeout()), TQT_SLOT(wakeUp()) );
- // showButton( User2/*3*/, false );
+ setMainWidget( mIncidenceListView );
+ mIncidenceListView->setMinimumSize( 500, 50 );
- setMinimumSize( 300, 200 );
+ readLayout();
}
AlarmDialog::~AlarmDialog()
@@ -133,26 +173,82 @@ AlarmDialog::~AlarmDialog()
mIncidenceListView->clear();
}
-void AlarmDialog::addIncidence( Incidence *incidence, const TQDateTime &reminderAt )
+AlarmListItem *AlarmDialog::searchByUid( const TQString &uid )
+{
+ AlarmListItem *found = 0;
+ for ( TQListViewItemIterator it( mIncidenceListView ) ; it.current() ; ) {
+ AlarmListItem *item = static_cast<AlarmListItem*>( it.current() );
+ if ( item->mUid == uid ) {
+ found = item;
+ break;
+ }
+ ++it;
+ }
+ return found;
+}
+
+static TQString etc = i18n( "elipsis", "..." );
+static TQString cleanSummary( const TQString &summary )
{
- AlarmListItem *item = new AlarmListItem( incidence, mIncidenceListView );
- item->setText( 0, incidence->summary() );
+ uint maxLen = 45;
+ TQString retStr = summary;
+ retStr.replace( '\n', ' ' );
+ if ( retStr.length() > maxLen ) {
+ maxLen -= etc.length();
+ retStr = retStr.left( maxLen );
+ retStr += etc;
+ }
+ return retStr;
+}
+
+void AlarmDialog::readLayout()
+{
+ KConfig *config = kapp->config();
+ config->setGroup( "Layout" );
+ TQValueList<int> sizes = config->readIntListEntry( "SplitterSizes" );
+ if ( sizes.count() == 2 ) {
+ mSplitter->setSizes( sizes );
+ }
+ mSplitter->setCollapsible( mIncidenceListView, false );
+ mSplitter->setCollapsible( mDetailView, false );
+}
+
+void AlarmDialog::writeLayout()
+{
+ KConfig *config = kapp->config();
+ config->setGroup( "Layout" );
+ TQValueList<int> list = mSplitter->sizes();
+ config->writeEntry( "SplitterSizes", list );
+}
+
+void AlarmDialog::addIncidence( Incidence *incidence,
+ const TQDateTime &reminderAt,
+ const TQString &displayText )
+{
+ AlarmListItem *item = searchByUid( incidence->uid() );
+ if ( !item ) {
+ item = new AlarmListItem( incidence->uid(), mIncidenceListView );
+ }
+ item->mNotified = false;
+ item->mHappening = TQDateTime();
item->mRemindAt = reminderAt;
- Todo *todo;
- if ( dynamic_cast<Event*>( incidence ) ) {
+ item->mDisplayText = displayText;
+ item->setText( 0, cleanSummary( incidence->summary() ) );
+ item->setText( 1, TQString() );
+
+ TQString displayStr;
+ const TQDateTime dateTime = triggerDateForIncidence( incidence, reminderAt, displayStr );
+
+ item->mHappening = dateTime;
+ item->setText( 1, displayStr );
+
+ if ( incidence->type() == "Event" ) {
item->setPixmap( 0, SmallIcon( "appointment" ) );
- if ( incidence->doesRecur() ) {
- TQDateTime nextStart = incidence->recurrence()->getNextDateTime( reminderAt );
- if ( nextStart.isValid() )
- item->setText( 1, KGlobal::locale()->formatDateTime( nextStart ) );
- }
- if ( item->text( 1 ).isEmpty() )
- item->setText( 1, incidence->dtStartStr() );
- } else if ( (todo = dynamic_cast<Todo*>( incidence )) ) {
+ } else {
item->setPixmap( 0, SmallIcon( "todo" ) );
- item->setText( 1, todo->dtDueStr() );
}
- if ( activeCount() == 1 ) {// previously empty
+
+ if ( activeCount() == 1 ) { // previously empty
mIncidenceListView->clearSelection();
item->setSelected( true );
}
@@ -161,6 +257,26 @@ void AlarmDialog::addIncidence( Incidence *incidence, const TQDateTime &reminder
void AlarmDialog::slotOk()
{
+ suspend();
+}
+
+void AlarmDialog::slotUser1()
+{
+ edit();
+}
+
+void AlarmDialog::slotUser2()
+{
+ dismissAll();
+}
+
+void AlarmDialog::slotUser3()
+{
+ dismissCurrent();
+}
+
+void AlarmDialog::dismissCurrent()
+{
ItemList selection = selectedItems();
for ( ItemList::Iterator it = selection.begin(); it != selection.end(); ++it ) {
if ( (*it)->itemBelow() )
@@ -169,18 +285,96 @@ void AlarmDialog::slotOk()
(*it)->itemAbove()->setSelected( true );
delete *it;
}
- if ( activeCount() == 0 )
+ if ( activeCount() == 0 ) {
+ writeLayout();
accept();
- else {
+ } else {
updateButtons();
showDetails();
}
emit reminderCount( activeCount() );
}
-void AlarmDialog::slotUser1()
+void AlarmDialog::dismissAll()
{
- dismissAll();
+ for ( TQListViewItemIterator it( mIncidenceListView ) ; it.current() ; ) {
+ AlarmListItem *item = static_cast<AlarmListItem*>( it.current() );
+ if ( !item->isVisible() ) {
+ ++it;
+ continue;
+ }
+ mIncidenceListView->takeItem( item );
+ delete item;
+ }
+ setTimer();
+ writeLayout();
+ accept();
+ emit reminderCount( activeCount() );
+}
+
+void AlarmDialog::edit()
+{
+ ItemList selection = selectedItems();
+ if ( selection.count() != 1 ) {
+ return;
+ }
+ Incidence *incidence = mCalendar->incidence( selection.first()->mUid );
+ if ( !incidence ) {
+ return;
+ }
+ TQDate dt = selection.first()->mRemindAt.date();
+
+ if ( incidence->isReadOnly() ) {
+ KMessageBox::sorry(
+ this,
+ i18n( "\"%1\" is a read-only item so modifications are not possible." ).
+ arg( cleanSummary( incidence->summary() ) ) );
+ return;
+ }
+
+ if ( !ensureKorganizerRunning() ) {
+ KMessageBox::error(
+ this,
+ i18n( "Could not start KOrganizer so editing is not possible." ) );
+ return;
+ }
+
+ TQByteArray data;
+ TQDataStream arg( data, IO_WriteOnly );
+ arg << incidence->uid();
+ arg << dt;
+ //kdDebug(5890) << "editing incidence " << incidence->summary() << endl;
+ if ( !kapp->dcopClient()->send( "korganizer", "KOrganizerIface",
+ "editIncidence(TQString,TQDate)",
+ data ) ) {
+ KMessageBox::error(
+ this,
+ i18n( "An internal KOrganizer error occurred attempting to start the incidence editor" ) );
+ return;
+ }
+
+ // get desktop # where korganizer (or kontact) runs
+ TQByteArray replyData;
+ TQCString object, replyType;
+ object = kapp->dcopClient()->isApplicationRegistered( "kontact" ) ?
+ "kontact-mainwindow#1" : "KOrganizer MainWindow";
+ if (!kapp->dcopClient()->call( "korganizer", object,
+ "getWinID()", 0, replyType, replyData, true, -1 ) ) {
+ }
+
+ if ( replyType == "int" ) {
+ int desktop, window;
+ TQDataStream ds( replyData, IO_ReadOnly );
+ ds >> window;
+ desktop = KWin::windowInfo( window ).desktop();
+
+ if ( KWin::currentDesktop() == desktop ) {
+ KWin::iconifyWindow( winId(), false );
+ } else {
+ KWin::setCurrentDesktop( desktop );
+ }
+ KWin::activateWindow( KWin::transientFor( window ) );
+ }
}
void AlarmDialog::suspend()
@@ -202,6 +396,7 @@ void AlarmDialog::suspend()
break;
}
+ AlarmListItem *selitem = 0;
for ( TQListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
AlarmListItem * item = static_cast<AlarmListItem*>( it.current() );
if ( item->isSelected() && item->isVisible() ) {
@@ -209,13 +404,26 @@ void AlarmDialog::suspend()
item->setSelected( false );
item->mRemindAt = TQDateTime::currentDateTime().addSecs( unit * mSuspendSpin->value() );
item->mNotified = false;
+ selitem = item;
}
}
+ if ( selitem ) {
+ if ( selitem->itemBelow() ) {
+ selitem->itemBelow()->setSelected( true );
+ } else if ( selitem->itemAbove() ) {
+ selitem->itemAbove()->setSelected( true );
+ }
+ }
+
+ // save suspended alarms too so they can be restored on restart
+ // kolab/issue4108
+ slotSave();
setTimer();
- if ( activeCount() == 0 )
+ if ( activeCount() == 0 ) {
+ writeLayout();
accept();
- else {
+ } else {
updateButtons();
showDetails();
}
@@ -239,76 +447,37 @@ void AlarmDialog::setTimer()
}
}
-void AlarmDialog::slotUser2()
-{
- ItemList selection = selectedItems();
- if ( selection.count() != 1 )
- return;
- Incidence *incidence = selection.first()->mIncidence;
-
- if ( !kapp->dcopClient()->isApplicationRegistered( "korganizer" ) ) {
- if ( kapp->startServiceByDesktopName( "korganizer", TQString::null ) )
- KMessageBox::error( 0, i18n("Could not start KOrganizer.") );
- }
-
- kapp->dcopClient()->send( "korganizer", "KOrganizerIface",
- "editIncidence(TQString)",
- incidence->uid() );
-
- // get desktop # where korganizer (or kontact) runs
- TQByteArray replyData;
- TQCString object, replyType;
- object = kapp->dcopClient()->isApplicationRegistered( "kontact" ) ?
- "kontact-mainwindow#1" : "KOrganizer MainWindow";
- if (!kapp->dcopClient()->call( "korganizer", object,
- "getWinID()", 0, replyType, replyData, true, -1 ) ) {
- }
-
- if ( replyType == "int" ) {
- int desktop, window;
- TQDataStream ds( replyData, IO_ReadOnly );
- ds >> window;
- desktop = KWin::windowInfo( window ).desktop();
-
- if ( KWin::currentDesktop() == desktop ) {
- KWin::iconifyWindow( winId(), false );
- }
- else
- KWin::setCurrentDesktop( desktop );
-
- KWin::activateWindow( KWin::transientFor( window ) );
- }
-}
-
-void AlarmDialog::slotUser3()
+void AlarmDialog::show()
{
- suspend();
-}
+ mIncidenceListView->sort();
-void AlarmDialog::dismissAll()
-{
- for ( TQListViewItemIterator it( mIncidenceListView ) ; it.current() ; ) {
+ // select the first item that hasn't already been notified
+ mIncidenceListView->clearSelection();
+ for ( TQListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
AlarmListItem *item = static_cast<AlarmListItem*>( it.current() );
- if ( !item->isVisible() ) {
- ++it;
- continue;
+ if ( !item->mNotified ) {
+ (*it)->setSelected( true );
+ break;
}
- delete item;
}
- setTimer();
- accept();
- emit reminderCount( activeCount() );
-}
-void AlarmDialog::show()
-{
- mIncidenceListView->clearSelection();
- if ( mIncidenceListView->firstChild() )
- mIncidenceListView->firstChild()->setSelected( true );
updateButtons();
+ showDetails();
+
+ // reset the default suspend time
+ mSuspendSpin->setValue( defSuspendVal );
+ mSuspendUnit->setCurrentItem( defSuspendUnit );
+
KDialogBase::show();
- KWin::setState( winId(), NET::KeepAbove );
+ KWin::deIconifyWindow( winId(), false );
+ KWin::setState( winId(), NET::KeepAbove | NET::DemandsAttention );
KWin::setOnAllDesktops( winId(), true );
+ KWin::activateWindow( winId() );
+ raise();
+ setActiveWindow();
+ if ( isMinimized() ) {
+ showNormal();
+ }
eventNotification();
}
@@ -319,11 +488,16 @@ void AlarmDialog::eventNotification()
TQValueList<AlarmListItem*> list;
for ( TQListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
AlarmListItem *item = static_cast<AlarmListItem*>( it.current() );
- if ( !item->isVisible() || item->mNotified )
+ if ( !item->isVisible() || item->mNotified ) {
+ continue;
+ }
+ Incidence *incidence = mCalendar->incidence( item->mUid );
+ if ( !incidence ) {
continue;
+ }
found = true;
item->mNotified = true;
- Alarm::List alarms = item->mIncidence->alarms();
+ Alarm::List alarms = incidence->alarms();
Alarm::List::ConstIterator it;
for ( it = alarms.begin(); it != alarms.end(); ++it ) {
Alarm *alarm = *it;
@@ -351,7 +525,13 @@ void AlarmDialog::wakeUp()
{
bool activeReminders = false;
for ( TQListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
- AlarmListItem * item = static_cast<AlarmListItem*>( it.current() );
+ AlarmListItem *item = static_cast<AlarmListItem*>( it.current() );
+ Incidence *incidence = mCalendar->incidence( item->mUid );
+ if ( !incidence ) {
+ delete item;
+ continue;
+ }
+
if ( item->mRemindAt <= TQDateTime::currentDateTime() ) {
if ( !item->isVisible() ) {
item->setVisible( true );
@@ -381,9 +561,13 @@ void AlarmDialog::slotSave()
int numReminders = config->readNumEntry("Reminders", 0);
for ( TQListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
- AlarmListItem * item = static_cast<AlarmListItem*>( it.current() );
- config->setGroup( TQString("Incidence-%1").arg(numReminders) );
- config->writeEntry( "UID", item->mIncidence->uid() );
+ AlarmListItem *item = static_cast<AlarmListItem*>( it.current() );
+ Incidence *incidence = mCalendar->incidence( item->mUid );
+ if ( !incidence ) {
+ continue;
+ }
+ config->setGroup( TQString("Incidence-%1").arg(numReminders + 1) );
+ config->writeEntry( "UID", incidence->uid() );
config->writeEntry( "RemindAt", item->mRemindAt );
++numReminders;
}
@@ -394,12 +578,19 @@ void AlarmDialog::slotSave()
lock.data()->unlock();
}
+void AlarmDialog::closeEvent( TQCloseEvent * )
+{
+ slotSave();
+ writeLayout();
+ accept();
+}
+
void AlarmDialog::updateButtons()
{
ItemList selection = selectedItems();
- enableButton( User2, selection.count() == 1 );
- enableButton( Ok, selection.count() > 0 );
- enableButton( User3, selection.count() > 0 );
+ enableButton( User1, selection.count() == 1 ); // can only edit 1 at a time
+ enableButton( User3, selection.count() > 0 ); // dismiss 1 or more
+ enableButton( Ok, selection.count() > 0 ); // suspend 1 or more
}
TQValueList< AlarmListItem * > AlarmDialog::selectedItems() const
@@ -437,8 +628,113 @@ void AlarmDialog::showDetails()
{
mDetailView->clearEvents( true );
mDetailView->clear();
- AlarmListItem *item = static_cast<AlarmListItem*>( mIncidenceListView->currentItem() );
+ AlarmListItem *item = static_cast<AlarmListItem*>( mIncidenceListView->selectedItems().first() );
if ( !item || !item->isVisible() )
return;
- mDetailView->appendIncidence( item->mIncidence );
+
+ Incidence *incidence = mCalendar->incidence( item->mUid );
+ if ( !incidence ) {
+ return;
+ }
+
+ if ( !item->mDisplayText.isEmpty() ) {
+ TQString txt = "<qt><p><b>" + item->mDisplayText + "</b></p></qt>";
+ mDetailView->addText( txt );
+ }
+ item->setText( 0, cleanSummary( incidence->summary() ) );
+ mDetailView->appendIncidence( incidence, item->mRemindAt.date() );
+}
+
+bool AlarmDialog::ensureKorganizerRunning() const
+{
+ TQString error;
+ TQCString dcopService;
+
+ int result = KDCOPServiceStarter::self()->findServiceFor(
+ "DCOP/Organizer", TQString::null, TQString::null, &error, &dcopService );
+
+ if ( result == 0 ) {
+ // OK, so korganizer (or kontact) is running. Now ensure the object we
+ // want is available [that's not the case when kontact was already running,
+ // but korganizer not loaded into it...]
+ static const char* const dcopObjectId = "KOrganizerIface";
+ TQCString dummy;
+ if ( !kapp->dcopClient()->findObject(
+ dcopService, dcopObjectId, "", TQByteArray(), dummy, dummy ) ) {
+ DCOPRef ref( dcopService, dcopService ); // talk to KUniqueApplication or its kontact wrapper
+ DCOPReply reply = ref.call( "load()" );
+ if ( reply.isValid() && (bool)reply ) {
+ Q_ASSERT( kapp->dcopClient()->findObject(
+ dcopService, dcopObjectId, "", TQByteArray(), dummy, dummy ) );
+ } else {
+ kdWarning() << "Error loading " << dcopService << endl;
+ }
+ }
+
+ // We don't do anything with it we just need it to be running
+ return true;
+
+ } else {
+ kdWarning() << "Couldn't start DCOP/Organizer: " << dcopService
+ << " " << error << endl;
+ }
+ return false;
+}
+
+/** static */
+TQDateTime AlarmDialog::triggerDateForIncidence( Incidence *incidence,
+ const TQDateTime &reminderAt,
+ TQString &displayStr )
+{
+ // Will be simplified in trunk, with roles.
+ TQDateTime result;
+
+ Alarm *alarm = incidence->alarms().first();
+
+ if ( incidence->doesRecur() ) {
+ result = incidence->recurrence()->getNextDateTime( reminderAt );
+ displayStr = KGlobal::locale()->formatDateTime( result );
+ }
+
+ if ( incidence->type() == "Event" ) {
+ if ( !result.isValid() ) {
+ Event *event = static_cast<Event *>( incidence );
+ result = alarm->hasStartOffset() ? event->dtStart() :
+ event->dtEnd();
+ displayStr = IncidenceFormatter::dateTimeToString( result, false, true );
+ }
+ } else if ( incidence->type() == "Todo" ) {
+ if ( !result.isValid() ) {
+ Todo *todo = static_cast<Todo *>( incidence );
+ result = alarm->hasStartOffset() && todo->dtStart().isValid() ? todo->dtStart():
+ todo->dtDue();
+ displayStr = IncidenceFormatter::dateTimeToString( result, false, true );
+ }
+ }
+
+ return result;
+}
+
+void AlarmDialog::slotCalendarChanged()
+{
+ Incidence::List incidences = mCalendar->incidences();
+ for ( Incidence::List::ConstIterator it = incidences.begin();
+ it != incidences.constEnd(); ++it ) {
+ Incidence *incidence = *it;
+ AlarmListItem *item = searchByUid( incidence->uid() );
+
+ if ( item ) {
+ TQString displayStr;
+ const TQDateTime dateTime = triggerDateForIncidence( incidence,
+ item->mRemindAt,
+ displayStr );
+
+ const TQString summary = cleanSummary( incidence->summary() );
+
+ if ( displayStr != item->text( 1 ) || summary != item->text( 0 ) ) {
+ item->setText( 1, displayStr );
+ item->setText( 0, summary );
+ }
+ }
+ }
}
diff --git a/korganizer/korgac/alarmdialog.h b/korganizer/korgac/alarmdialog.h
index 4c2162a54..75208f654 100644
--- a/korganizer/korgac/alarmdialog.h
+++ b/korganizer/korgac/alarmdialog.h
@@ -31,36 +31,48 @@
#include <kdialogbase.h>
#include <libkcal/event.h>
-#include <libkcal/calendarlocal.h>
+#include <libkcal/calendarresources.h>
using namespace KCal;
+class AlarmListItem;
class KOEventViewer;
-class TQSpinBox;
class KComboBox;
class KListView;
-class AlarmListItem;
+class TQSpinBox;
+class TQSplitter;
class AlarmDialog : public KDialogBase {
- Q_OBJECT
+ Q_OBJECT
public:
- AlarmDialog( TQWidget *parent = 0, const char *name = 0 );
- virtual ~AlarmDialog();
+ explicit AlarmDialog( CalendarResources *calendar, TQWidget *parent = 0, const char *name = 0 );
+
+ ~AlarmDialog();
- void addIncidence( Incidence *incidence, const TQDateTime &reminderAt );
+ void addIncidence( Incidence *incidence, const TQDateTime &reminderAt,
+ const TQString &displayText );
void eventNotification();
public slots:
- void slotOk();
- void slotUser1();
- void slotUser2();
- void slotUser3();
+
+ void slotOk(); // suspend
+ void slotUser1(); // edit
+ void slotUser2(); // dismiss all
+ void slotUser3(); // dismiss selected
void slotSave();
void wakeUp();
void show();
+ void edit();
void suspend();
void suspendAll();
void dismissAll();
+ void dismissCurrent();
+
+ /**
+ If an incidence changed, for example in korg, we must update
+ the date and summary shown in the list view.
+ */
+ void slotCalendarChanged();
signals:
void reminderCount( int count );
@@ -69,16 +81,29 @@ class AlarmDialog : public KDialogBase {
void updateButtons();
void showDetails();
+ protected:
+ void closeEvent( TQCloseEvent * );
+
private:
- bool startKOrganizer();
+
+ static TQDateTime triggerDateForIncidence( Incidence *inc,
+ const TQDateTime &reminderAt,
+ TQString &displayStr );
+
+ void readLayout();
+ void writeLayout();
+ AlarmListItem *searchByUid( const TQString &uid );
+ bool ensureKorganizerRunning() const;
void setTimer();
int activeCount();
TQValueList<AlarmListItem*> selectedItems() const;
+ CalendarResources *mCalendar;
KListView *mIncidenceListView;
KOEventViewer *mDetailView;
TQSpinBox *mSuspendSpin;
+ TQSplitter *mSplitter;
KComboBox *mSuspendUnit;
TQTimer mSuspendTimer;
};
diff --git a/korganizer/korgac/koalarmclient.cpp b/korganizer/korgac/koalarmclient.cpp
index a4298d7aa..ec19ce9aa 100644
--- a/korganizer/korgac/koalarmclient.cpp
+++ b/korganizer/korgac/koalarmclient.cpp
@@ -70,14 +70,17 @@ KOAlarmClient::KOAlarmClient( TQObject *parent, const char *name )
// load reminders that were active when quitting
config->setGroup( "General" );
int numReminders = config->readNumEntry( "Reminders", 0 );
- for ( int i=1; i<=numReminders; ++i )
- {
+ for ( int i = 1; i <= numReminders; ++i ) {
TQString group( TQString( "Incidence-%1" ).arg( i ) );
config->setGroup( group );
TQString uid = config->readEntry( "UID" );
TQDateTime dt = config->readDateTimeEntry( "RemindAt" );
- if ( !uid.isEmpty() )
- createReminder( mCalendar->incidence( uid ), dt );
+ if ( !uid.isEmpty() ) {
+ Incidence *i = mCalendar->incidence( uid );
+ if ( i && !i->alarms().isEmpty() ) {
+ createReminder( mCalendar, i, dt, TQString() );
+ }
+ }
config->deleteGroup( group );
}
config->setGroup( "General" );
@@ -115,24 +118,27 @@ void KOAlarmClient::checkAlarms()
for( it = alarms.begin(); it != alarms.end(); ++it ) {
kdDebug(5891) << "REMINDER: " << (*it)->parent()->summary() << endl;
Incidence *incidence = mCalendar->incidence( (*it)->parent()->uid() );
- createReminder( incidence, TQDateTime::currentDateTime() );
+ createReminder( mCalendar, incidence, from, (*it)->text() );
}
}
-void KOAlarmClient::createReminder( KCal::Incidence *incidence, TQDateTime dt )
+void KOAlarmClient::createReminder( KCal::CalendarResources *calendar,
+ KCal::Incidence *incidence,
+ const TQDateTime &dt,
+ const TQString &displayText )
{
if ( !incidence )
return;
if ( !mDialog ) {
- mDialog = new AlarmDialog();
+ mDialog = new AlarmDialog( calendar );
connect( mDialog, TQT_SIGNAL(reminderCount(int)), mDocker, TQT_SLOT(slotUpdate(int)) );
connect( mDocker, TQT_SIGNAL(suspendAllSignal()), mDialog, TQT_SLOT(suspendAll()) );
connect( mDocker, TQT_SIGNAL(dismissAllSignal()), mDialog, TQT_SLOT(dismissAll()) );
connect( this, TQT_SIGNAL( saveAllSignal() ), mDialog, TQT_SLOT( slotSave() ) );
}
- mDialog->addIncidence( incidence, dt );
+ mDialog->addIncidence( incidence, dt, displayText );
mDialog->wakeUp();
saveLastCheckTime();
}
diff --git a/korganizer/korgac/koalarmclient.h b/korganizer/korgac/koalarmclient.h
index 89c122c39..c8eee984e 100644
--- a/korganizer/korgac/koalarmclient.h
+++ b/korganizer/korgac/koalarmclient.h
@@ -69,7 +69,8 @@ class KOAlarmClient : public TQObject, virtual public AlarmClientIface, public K
void saveAllSignal();
private:
- void createReminder( KCal::Incidence *incidence, TQDateTime dt );
+ void createReminder( KCal::CalendarResources *calendar, KCal::Incidence *incidence,
+ const TQDateTime &dt, const TQString &displayText );
void saveLastCheckTime();
AlarmDockWindow *mDocker; // the panel icon
diff --git a/korganizer/korgac/korgac.desktop b/korganizer/korgac/korgac.desktop
index cad7d7e5e..6420a120f 100644
--- a/korganizer/korgac/korgac.desktop
+++ b/korganizer/korgac/korgac.desktop
@@ -22,7 +22,6 @@ Name[hu]=KOrganizer-emlékeztető kliens
Name[is]=Áminningarforrit fyrir KOrganizer
Name[it]=Client degli avvisi di KOrganizer
Name[ja]=KOrganizer リマインダクライアント
-Name[ka]=KOrganizer შემხსენებელის კლიენტი
Name[kk]=KOrganizer-дің еске салу клиенті
Name[km]=កម្មវិធី​រំលឹក​របស់ KOrganizer
Name[lt]=KOrganizer priminimų klientas
@@ -69,7 +68,6 @@ GenericName[hu]=KOrganizer emlékeztető szolgáltatás kliense
GenericName[is]=Áminningarpúki fyrir KOrganizer
GenericName[it]=Client del demone degli avvisi di KOrganizer
GenericName[ja]=KOrganizer リマインダデーモンクライアント
-GenericName[ka]=KOrganizer შემხსენებელის დემონის კლიენტი
GenericName[kk]=Organizer-дің еске салу қызметінің клиенті
GenericName[km]=កម្មវិធី​ដេមិន​អ្នក​រំលឹក​របស់ KOrganizer
GenericName[lt]=KOrganizer priminimų tarnybos klientas
diff --git a/korganizer/korgac/testalarmdlg.cpp b/korganizer/korgac/testalarmdlg.cpp
index 84fa51ed6..5a3ba5a18 100644
--- a/korganizer/korgac/testalarmdlg.cpp
+++ b/korganizer/korgac/testalarmdlg.cpp
@@ -29,6 +29,8 @@
#include <kdebug.h>
#include <klocale.h>
#include <kcmdlineargs.h>
+#include <kconfig.h>
+#include <kstandarddirs.h>
#include "alarmdialog.h"
@@ -39,6 +41,11 @@ int main(int argc,char **argv)
KApplication app;
+ KConfig c( locate( "config", "korganizerrc" ) );
+ c.setGroup( "Time & Date" );
+ TQString tz = c.readEntry( "TimeZoneId" );
+ CalendarResources *mCalendar = new CalendarResources( tz );
+
Event *e1 = new Event;
e1->setSummary( "This is a summary." );
TQDateTime now = TQDateTime::currentDateTime();
@@ -46,24 +53,64 @@ int main(int argc,char **argv)
e1->setDtEnd( now.addDays( 1 ) );
Alarm *a = e1->newAlarm();
// a->setProcedureAlarm( "/usr/X11R6/bin/xeyes" );
- a->setAudioAlarm( "/opt/kde/share/apps/korganizer/sounds/spinout.wav" );
+ a->setAudioAlarm( "/data/kde/share/apps/korganizer/sounds/spinout.wav" );
+ mCalendar->addEvent( e1 );
Todo *t1 = new Todo;
t1->setSummary( "To-do A" );
t1->setDtDue( now );
t1->newAlarm();
+ mCalendar->addTodo( t1 );
Event *e2 = new Event;
e2->setSummary( "This is another summary." );
- e2->setDtStart( now );
- e2->setDtEnd( now.addDays( 1 ) );
+ e2->setDtStart( now.addDays( 1 ) );
+ e2->setDtEnd( now.addDays( 2 ) );
e2->newAlarm();
+ mCalendar->addEvent( e2 );
+
+ Event *e3 = new Event;
+ e3->setSummary( "Meet with Fred" );
+ e3->setDtStart( now.addDays( 2 ) );
+ e3->setDtEnd( now.addDays( 3 ) );
+ e3->newAlarm();
+ mCalendar->addEvent( e3 );
+
+ Todo *t2 = new Todo;
+ t2->setSummary( "Something big is due today" );
+ t2->setDtDue( now );
+ t2->newAlarm();
+ mCalendar->addTodo( t2 );
+
+ Todo *t3 = new Todo;
+ t3->setSummary( "Be lazy" );
+ t3->setDtDue( now );
+ t3->newAlarm();
+ mCalendar->addTodo( t3 );
+
+ Event *e4 = new Event;
+ e4->setSummary( "Watch TV" );
+ e4->setDtStart( now.addSecs( 120 ) );
+ e4->setDtEnd( now.addSecs( 180 ) );
+ e4->newAlarm();
+ mCalendar->addEvent( e4 );
- AlarmDialog dlg;
+ AlarmDialog dlg( mCalendar, 0 );
app.setMainWidget( &dlg );
- dlg.addIncidence( e1, TQDateTime::currentDateTime() );
- dlg.addIncidence( t1, TQDateTime::currentDateTime() );
- dlg.addIncidence( e2, TQDateTime::currentDateTime() );
+ dlg.addIncidence( e2, TQDateTime::currentDateTime().addSecs( 60 ),
+ TQString() );
+ dlg.addIncidence( t1, TQDateTime::currentDateTime().addSecs( 300 ),
+ TQString( "THIS IS DISPLAY TEXT" ) );
+ dlg.addIncidence( e4, TQDateTime::currentDateTime().addSecs( 120 ),
+ TQString( "Fred and Barney get cloned" ) );
+ dlg.addIncidence( e3, TQDateTime::currentDateTime().addSecs( 240 ),
+ TQString() );
+ dlg.addIncidence( e1, TQDateTime::currentDateTime().addSecs( 180 ),
+ TQString() );
+ dlg.addIncidence( t2, TQDateTime::currentDateTime().addSecs( 600 ),
+ TQString( "THIS IS DISPLAY TEXT" ) );
+ dlg.addIncidence( t3, TQDateTime::currentDateTime().addSecs( 360 ),
+ TQString() );
dlg.show();
dlg.eventNotification();
diff --git a/korganizer/korganizer.cpp b/korganizer/korganizer.cpp
index fae21bff1..69ab0f4a3 100644
--- a/korganizer/korganizer.cpp
+++ b/korganizer/korganizer.cpp
@@ -308,3 +308,9 @@ void KOrganizer::setTitle()
setCaption( title, !mCalendarView->isReadOnly() &&
mCalendarView->isModified() );
}
+
+bool KOrganizer::isCurrentlyActivePart()
+{
+ return false;
+}
+
diff --git a/korganizer/korganizer.desktop b/korganizer/korganizer.desktop
index 2f717f7a4..b3337dd0f 100644
--- a/korganizer/korganizer.desktop
+++ b/korganizer/korganizer.desktop
@@ -27,7 +27,6 @@ Comment[hu]=Határidőnapló és eseményszervező
Comment[is]=Dagbók og skipulag
Comment[it]=Programma di calendario e di agenda
Comment[ja]=カレンダーとスケジュール管理プログラム
-Comment[ka]=კალენდრის და მგეგმავის პროგრამა
Comment[kk]=Күнтізбе және Жоспарлау бағдарламасы
Comment[km]=កម្មវិធី​ប្រតិទិន និង​កាលវិភាគ
Comment[lt]=Kalendoriaus ir planavimo programa
@@ -57,8 +56,7 @@ Comment[tg]=Тақвимот ва ҷадвали шахсӣ
Comment[th]=โปรแกรมจัดการบันทึกประจำวันและตารางการนัดหมาย
Comment[tr]=Takvim ve Zamanlama Programı
Comment[uk]=Програма календаря та розкладу
-Comment[uz]=Kalendar va rejalashtirish dasturi
-Comment[uz@cyrillic]=Календар ва режалаштириш дастури
+Comment[uz]=Календар ва режалаштириш дастури
Comment[ven]=Khalenda na mbekanyamushumo ya u shedula
Comment[vi]=Chương trình lịch và kế hoạch
Comment[xh]=Ikhalenda no Dweliso lwenkqubo Yokucwangcisa
@@ -113,7 +111,6 @@ GenericName[hu]=Határidőnapló
GenericName[is]=Persónuleg skipulagsbók
GenericName[it]=Organizzatore personale
GenericName[ja]=個人向けスケジュール管理
-GenericName[ka]=პირადი ორგანიზატორი
GenericName[kk]=Дербес ұйымдастырғышы
GenericName[km]=កម្មវិធី​រៀបចំ​ផ្ទាល់​ខ្លួន
GenericName[lt]=Asmeninės informacijos tvarkyklė
@@ -138,8 +135,7 @@ GenericName[ta]=தனிப்பயன் அமைப்பாளர்
GenericName[tg]=Органайзери инфиродӣ
GenericName[tr]=Kişisel Bilgi Yöneticisi
GenericName[uk]=Персональний тижневик
-GenericName[uz]=Shaxsiy organayzer
-GenericName[uz@cyrillic]=Шахсий органайзер
+GenericName[uz]=Шахсий органайзер
GenericName[zh_CN]=个人日程安排
GenericName[zh_TW]=個人行程組織軟體
ServiceTypes=Browser/View,DCOP/Organizer
diff --git a/korganizer/korganizer.h b/korganizer/korganizer.h
index 3ad0952a1..d088becba 100644
--- a/korganizer/korganizer.h
+++ b/korganizer/korganizer.h
@@ -95,6 +95,8 @@ class KOrganizer : public KPartsMainWindow, public KOrgMainWindow
virtual KXMLGUIClient *mainGuiClient() { return this; }
virtual TQWidget *topLevelWidget() { return this; }
+ virtual bool isCurrentlyActivePart();
+
public slots:
/** show status message */
void showStatusMessage( const TQString & );
diff --git a/korganizer/korganizer.kcfg b/korganizer/korganizer.kcfg
index eaf23fb34..c299aa75c 100644
--- a/korganizer/korganizer.kcfg
+++ b/korganizer/korganizer.kcfg
@@ -148,10 +148,38 @@
<whatsthis>Enter default duration for events here. The default is used if you do not supply an end time.</whatsthis>
<default>QDateTime(QDate(), QTime(2,0))</default>
</entry>
- <entry type="Int" key="Default Alarm Time" name="AlarmTime">
- <label>Default Reminder Time</label>
- <whatsthis>Enter the reminder time here.</whatsthis>
- <default>3</default>
+
+ <entry type="Int" key="Default Reminder Time" name="ReminderTime">
+ <label>Default reminder time</label>
+ <whatsthis>Enter the default reminder time for all newly created items. The time unit is specified in the adjacent combobox.</whatsthis>
+ <tooltip>Default time for reminders</tooltip>
+ <default>15</default>
+ </entry>
+ <entry type="Int" key="Default Reminder Time Units" name="ReminderTimeUnits">
+ <whatsthis>Enter the default reminder time units for all newly created items. The time is specified in the adjacent spinbox.</whatsthis>
+ <tooltip>Default time unit for reminders</tooltip>
+ <default>0</default>
+ </entry>
+ <entry type="Bool" key="Enable Default Audio File" name="defaultAudioFileReminders">
+ <label>Enable a default sound file for audio reminders</label>
+ <whatsthis>Check this box if you want to enable the specified file to be used as the default sound file for new reminders. You can always specify another file in the Advanced Reminder accessible from the Event or To-do editors.</whatsthis>
+ <default>false</default>
+ </entry>
+ <entry type="Path" key="Reminder Audio File" name="audioFilePath">
+ <label>Default audio file</label>
+ <whatsthis>Set a file to be used as the default sound file for new reminders. You can always specify another file in the Advanced Reminder accessible from the Event or To-do editors.</whatsthis>
+ </entry>
+ <entry type="Bool" key="Enable Event Reminders" name="defaultEventReminders">
+ <label>Enable reminders for new Events</label>
+ <whatsthis>Check this box if you want to enable reminders for all newly created Events. You can always turn-off the reminders in the Event editor dialog.</whatsthis>
+ <tooltip>By default, enable reminders for new events</tooltip>
+ <default>false</default>
+ </entry>
+ <entry type="Bool" key="Enable To-do Reminders" name="defaultTodoReminders">
+ <label>Enable reminders for new To-dos</label>
+ <whatsthis>Check this box if you want to enable reminders for all newly created To-dos. You can always turn-off the reminders in the To-do editor dialog.</whatsthis>
+ <tooltip>By default, enable reminders for new to-dos</tooltip>
+ <default>false</default>
</entry>
</group>
@@ -173,6 +201,11 @@
<whatsthis>Check this box to show the days containing weekly recurring events in bold typeface in the Date Navigator, or uncheck it to give more prominence to other (non weekly recurring) events.</whatsthis>
<default>true</default>
</entry>
+ <entry type="Bool" key="Week Numbers Show Work Week" name="weekNumbersShowWork">
+ <label>Week numbers select a work week when in work week view</label>
+ <whatsthis>Check this box to select a work week when clicking on date navigator's week numbers or uncheck it to chose the whole week.</whatsthis>
+ <default>false</default>
+ </entry>
<entry type="Bool" key="Enable ToolTips">
<label>Enable tooltips displaying summary of events</label>
<whatsthis>Check this box to display an event summary tooltip when hovering the mouse over an event.</whatsthis>
@@ -222,7 +255,7 @@
<label>Only calendar</label>
</choice>
</choices>
- <default>CategoryInsideResourceOutside</default>
+ <default>ResourceInsideCategoryOutside</default>
</entry>
<entry type="Enum" name="Agenda View Calendar Display">
@@ -241,8 +274,6 @@
<default>CalendarsMerged</default>
</entry>
-
-
<entry type="DateTime" name="DayBegins">
<label>Day begins at</label>
<whatsthis>Enter the start time for events here. This time should be the earliest time that you use for events, as it will be displayed at the top.</whatsthis>
@@ -268,16 +299,24 @@
<default>true</default>
</entry>
- <entry type="Bool" key="Month View Uses Category Color">
- <label>Month view uses category colors</label>
- <whatsthis>Check this box to make the month view use the category colors of an item.</whatsthis>
- <default>true</default>
- </entry>
-
- <entry type="Bool" key="Month View Uses Resource Color">
- <label>Month view uses resource colors</label>
- <whatsthis>Check this box to make the month view use the resource colors of an item.</whatsthis>
- <default>true</default>
+ <entry type="Enum" key="MonthItemColors">
+ <label>Colors used in month view</label>
+ <whatsthis>Choose the colors of the month view items.</whatsthis>
+ <choices>
+ <choice name="MonthItemCategoryInsideResourceOutside">
+ <label>Category inside, calendar outside</label>
+ </choice>
+ <choice name="MonthItemResourceInsideCategoryOutside">
+ <label>Calendar inside, category outside</label>
+ </choice>
+ <choice name="MonthItemCategoryOnly">
+ <label>Only category</label>
+ </choice>
+ <choice name="MonthItemResourceOnly">
+ <label>Only calendar</label>
+ </choice>
+ </choices>
+ <default>MonthItemResourceInsideCategoryOutside</default>
</entry>
<entry type="Bool" key="Full View Month">
@@ -391,9 +430,9 @@
<whatsthis>Select the to-do overdue color here.</whatsthis>
<default>255, 100, 100</default>
</entry>
- <entry type="Color" key="EventColor">
- <label>Default event color</label>
- <whatsthis>Select the default event color here. The default event color will be used for events categories in your agenda. Note that you can specify a separate color for each event category below.</whatsthis>
+ <entry type="Color" key="Unset Category Color">
+ <label>"No category" color (for "Only category" drawing schemes)</label>
+ <whatsthis>Select a color to use for the "no category" or "unset category" situation, when an item does not belong to any category. This color is used when drawing items in the agenda or month views using the "Only category" scheme.</whatsthis>
<default>151, 235, 121</default>
</entry>
@@ -465,7 +504,7 @@
<entry type="Bool" name="FreeBusyCheckHostname">
<label>Check whether hostname and retrieval email address match</label>
<whatsthis>With this setting you can configure whether the domain part of the free/busy url has to match the domain part of the user id you are looking for. For example if this option is 'true' then looking for the free/busy data of joe@mydomain.com on the server www.yourdomain.com won't work.</whatsthis>
- <default>true</default>
+ <default>false</default>
</entry>
<entry type="Bool" name="FreeBusyFullDomainRetrieval">
diff --git a/korganizer/korganizer_configcolors.desktop b/korganizer/korganizer_configcolors.desktop
index 59582a536..9a2c7f158 100644
--- a/korganizer/korganizer_configcolors.desktop
+++ b/korganizer/korganizer_configcolors.desktop
@@ -43,7 +43,6 @@ Name[id]=Warna
Name[is]=Litir
Name[it]=Colori
Name[ja]=色
-Name[ka]=ფერები
Name[kk]=Түстері
Name[km]=ពណ៌
Name[lt]=Spalvos
@@ -73,8 +72,7 @@ Name[tg]=Рангҳо
Name[th]=สี
Name[tr]=Renkler
Name[uk]=Кольори
-Name[uz]=Ranglar
-Name[uz@cyrillic]=Ранглар
+Name[uz]=Ранглар
Name[ven]=Mivhala
Name[vi]=Màu
Name[xh]=Imibala
@@ -109,7 +107,6 @@ Comment[hu]=KOrganizer színbeállítások
Comment[is]=KOrganizer litastillingar
Comment[it]=Configurazione dei colori di Korganizer
Comment[ja]=KOrganizer 色設定
-Comment[ka]=KDE-ს ორგანიზატორის ფერთა კონფიგურაცია
Comment[kk]=KOrganizer-дің түстер параметрлері
Comment[km]=ការ​កំណត់​រចនាសម្ព័ន្ធ​ពណ៌ KOrganizer
Comment[lt]=KOrganizer spalvų konfigūravimas
@@ -154,7 +151,7 @@ Keywords[et]=korganizer,värvid
Keywords[eu]=korganizer,koloreak
Keywords[fa]=korganizer،رنگها
Keywords[fi]=korganizer,värit
-Keywords[fr]=korganizer,couleurs
+Keywords[fr]=KOrganizer,couleurs
Keywords[fy]=korganizer,colors,kleuren
Keywords[ga]=korganizer,dathanna
Keywords[gl]=korganizer,cores
@@ -164,7 +161,6 @@ Keywords[hu]=korganizer,színek
Keywords[is]=korganizer,litir
Keywords[it]=korganizer,colori
Keywords[ja]=korganizer,色
-Keywords[ka]=korganizer,ფერები
Keywords[km]=korganizer,ពណ៌
Keywords[lt]=korganizer,colors, spalvos
Keywords[mk]=korganizer,colors,корганизатор,бои
@@ -188,6 +184,5 @@ Keywords[ta]=கேஅமைப்பாளர், வண்ணங்கள்
Keywords[tg]=korganizer,colors,органайзер,рангҳо
Keywords[tr]=korganizer,renkler
Keywords[uk]=korganizer,кольори
-Keywords[uz]=korganizer,organayzer,ranglar
-Keywords[uz@cyrillic]=korganizer,органайзер,ранглар
+Keywords[uz]=korganizer,органайзер,ранглар
Keywords[zh_CN]=korganizer,colors,颜色
diff --git a/korganizer/korganizer_configdesignerfields.desktop b/korganizer/korganizer_configdesignerfields.desktop
index 99f9e4b58..5263f22d3 100644
--- a/korganizer/korganizer_configdesignerfields.desktop
+++ b/korganizer/korganizer_configdesignerfields.desktop
@@ -37,7 +37,6 @@ Name[hu]=Egyéni lapok
Name[is]=Sérsniðnar síður
Name[it]=Pagine personalizzate
Name[ja]=カスタムページ
-Name[ka]=სამომხმარებლო გვერდები
Name[kk]=Қосымша парақтар
Name[km]=ទំព័រ​ផ្ទាល់​ខ្លួន
Name[lt]=Pasirinkti puslapiai
@@ -89,7 +88,6 @@ Comment[hu]=Az egyéni lapok beállítása
Comment[is]=Stilla sérsniðnu síðurnar
Comment[it]=Configura le pagine personalizzate
Comment[ja]=カスタムページの設定
-Comment[ka]=სამომხმარებლო გვერდების კონფიგურაცია
Comment[kk]=Қосымша парақтарды баптау
Comment[km]=កំណត់​រចនាសម្ព័ន្ធ​ទំព័រ​ផ្ទាល់​ខ្លួន
Comment[lt]=Konfigūruoti darbastalių skaičių ir pavadinimus
@@ -128,7 +126,7 @@ Keywords[et]=korganizer, seadistamine, seadistused, omaloodud väljad
Keywords[eu]=korganizer, konfiguratu, ezarpenak, eremu pertsonalizatuak
Keywords[fa]=korganizer، پیکربندی، تنظیمات، حوزه‌های سفارشی
Keywords[fi]=kaddressbook, aseta, asetukset,omat kentät
-Keywords[fr]=korganizer, configuration, configurer, champs personnalisés
+Keywords[fr]=KOrganizer, configuration, configurer, champs personnalisés
Keywords[fy]=korganizer, configuratie, instellingen, ynstellings, oanpaste fjilden, aangepaste velden
Keywords[ga]=korganizer, cumraigh, socruithe, réimsí saincheaptha
Keywords[gl]=korganizer, configurar, opcións, campos personalizados
@@ -137,7 +135,6 @@ Keywords[hu]=korganizer,beállítás,beállítások,egyéni mezők
Keywords[is]=korganizer, stillingar, stilla, sérsniðnir reitir
Keywords[it]=korganizer, configura, impostazioni, campi personalizzati
Keywords[ja]=korganizer、設定、設定,カスタムフィールド
-Keywords[ka]=korganizer, კონფიგურაცია,პარამეტრები,სამომხმარებლო ველები
Keywords[km]=korganizer,កំណត់​រចនាសម្ព័ន្ធ,ការ​កំណត់,វាល​ផ្ទាល់​ខ្លួន
Keywords[lt]=korganizer, configure, settings, custom fields, konfigūruoti, nustatymai, pasirinkti laukai
Keywords[mk]=korganizer, configure, settings, custom fields, корганизатор, конфигурација, конфигурирање, поставувања, сопствени полиња
diff --git a/korganizer/korganizer_configfonts.desktop b/korganizer/korganizer_configfonts.desktop
index c1c1a1f25..cacdc75f5 100644
--- a/korganizer/korganizer_configfonts.desktop
+++ b/korganizer/korganizer_configfonts.desktop
@@ -42,7 +42,6 @@ Name[hu]=Betűtípusok
Name[is]=Letur
Name[it]=Tipi di carattere
Name[ja]=フォント
-Name[ka]=შრიფტები
Name[kk]=Қаріптері
Name[km]=ពុម្ពអក្សរ
Name[lt]=Šriftai
@@ -71,8 +70,7 @@ Name[tg]=Ҳарфҳо
Name[th]=รูปแบบตัวอักษร
Name[tr]=Yazı tipleri
Name[uk]=Шрифти
-Name[uz]=Shriftlar
-Name[uz@cyrillic]=Шрифтлар
+Name[uz]=Шрифтлар
Name[ven]=Fontu
Name[vi]=Phông
Name[xh]=Ubungakanani bamagama
@@ -105,7 +103,6 @@ Comment[hu]=KOrganizer betűtípus-beállítások
Comment[is]=KOrganizer leturstillingar
Comment[it]=Configurazione font di KOrganizer
Comment[ja]=KOrganizer フォント設定
-Comment[ka]=KOrganizer შრიფტთა კონფიგურაცია
Comment[kk]=KOrganizer-дің қаріптер параметрлері
Comment[km]=ការ​កំណត់​រចនាសម្ព័ន្ធ​ពុម្ពអក្សរ KOrganizer
Comment[lt]=KOrganizer šriftų konfigūravimas
@@ -151,7 +148,7 @@ Keywords[et]=korganizer,fondid
Keywords[eu]=korganizer,letra-tipoak
Keywords[fa]=korganizer،قلمها
Keywords[fi]=korganizer,kirjasimet
-Keywords[fr]=korganizer,polices
+Keywords[fr]=KOrganizer,polices
Keywords[fy]=korganizer,fonts,lettertypen
Keywords[ga]=korganizer,clónna,clófhoirne
Keywords[gl]=korganizer,fontes
@@ -161,7 +158,6 @@ Keywords[hu]=korganizer,betűtípusok
Keywords[is]=korganizer,letur
Keywords[it]=korganizer,font
Keywords[ja]=korganizer,フォント
-Keywords[ka]=korganizer,შრიფტები
Keywords[km]=korganizer,ពុម្ពអក្សរ
Keywords[lt]=korganizer,fonts, šriftai
Keywords[mk]=korganizer,fonts,корганизатор,фонтови
@@ -185,6 +181,5 @@ Keywords[ta]=கேஅமைப்பாளர்,எழுத்துரு
Keywords[tg]=korganizer,fonts,органайзер,ҳуруфҳо
Keywords[tr]=korganizer,yazıtipleri
Keywords[uk]=korganizer,шрифти
-Keywords[uz]=korganizer,organayzer,shriftlar
-Keywords[uz@cyrillic]=korganizer,органайзер,шрифтлар
+Keywords[uz]=korganizer,органайзер,шрифтлар
Keywords[zh_CN]=korganizer,fonts,字体
diff --git a/korganizer/korganizer_configfreebusy.desktop b/korganizer/korganizer_configfreebusy.desktop
index 84640ab8f..2bae305c8 100644
--- a/korganizer/korganizer_configfreebusy.desktop
+++ b/korganizer/korganizer_configfreebusy.desktop
@@ -35,7 +35,6 @@ Name[hu]=Foglaltság
Name[is]=Tímaráðstöfun
Name[it]=Libero/Occupato
Name[ja]=動静情報
-Name[ka]=თავისუფალი/დაკავებული
Name[kk]=Бос/Істе
Name[km]=ទំនេរ/រវល់
Name[lt]=Užimtumas
@@ -59,8 +58,7 @@ Name[ta]=சுதந்திரமான/வேலையில் இருக
Name[tg]=Озод/машғул аст
Name[tr]=Boş/Meşgul
Name[uk]=Вільний/зайнятий час
-Name[uz]=Boʻsh/Band
-Name[uz@cyrillic]=Бўш/Банд
+Name[uz]=Бўш/Банд
Name[zh_CN]=忙/闲
Name[zh_TW]=行程資訊
Comment=KOrganizer Free/Busy Configuration
@@ -87,7 +85,6 @@ Comment[hu]=KOrganizer foglaltsági beállítások
Comment[is]=KOrganizer stillingar fyrir tímaráðstöfun
Comment[it]=Configurazione Libero/Occupato di KOrganizer
Comment[ja]=KOrganizer 動静情報の設定
-Comment[ka]=KOrganizer-ის თავისუფალი/დაკავებულობის კონფიგურაცია
Comment[kk]=KOrganizer--дің Бос/Істе мәлімет параметрлері
Comment[km]=ការ​កំណត់​រចនាសម្ព័ន្ធ​ទំនេរ/រវល់ របស់ KOrganizer
Comment[lt]=KOrganizer užimtumo konfigūravimas
@@ -128,7 +125,7 @@ Keywords[et]=korganizer,vaba,hõivatud,ajakava
Keywords[eu]=korganizer,libre, lanpetuta,antolaketa
Keywords[fa]=korganizer،آزاد اشغال، زمان‌بندی
Keywords[fi]=korganizer,vapaa,varattu,ajastus
-Keywords[fr]=korganizer,disponibilité, planification
+Keywords[fr]=KOrganizer,disponibilité, planification
Keywords[fy]=korganizer,freebusy,scheduling,plannen,frij,beset,roaster
Keywords[gl]=korganizer,dispoñibilidade,axenda
Keywords[hi]=के-आर्गेनाइज़र,फ्री-बिज़ी,समय-सारणी
@@ -136,7 +133,6 @@ Keywords[hu]=korganizer,foglaltság,szervezés
Keywords[is]=korganizer,tímaráðstöfun,áætlun
Keywords[it]=korganizer,libero/occupato,pianificazione
Keywords[ja]=korganizer,動静,スケジューラ
-Keywords[ka]=korganizer,თავისუფალიდაკავებული,დაგეგმვა
Keywords[km]=korganizer,ទំនេរ,រវល់,កាលវិភាគ
Keywords[mk]=korganizer,freebusy,scheduling,корганизатор,слободно,зафатено,закажување
Keywords[ms]=korganizer,lapang sibuk,penjadualan
diff --git a/korganizer/korganizer_configgroupautomation.desktop b/korganizer/korganizer_configgroupautomation.desktop
index 8e3227bc7..6386deda6 100644
--- a/korganizer/korganizer_configgroupautomation.desktop
+++ b/korganizer/korganizer_configgroupautomation.desktop
@@ -35,7 +35,6 @@ Name[hu]=Csoportmunka
Name[is]=Hópsjálfvirkni
Name[it]=Automazione gruppi
Name[ja]=グループ自動化
-Name[ka]=ჯგუფური ავტომატიზაცია
Name[kk]=Топтың біріккен жұмысы
Name[km]=ស្វ័យប្រតិកម្ម​ក្រុម
Name[lt]=Grupių automatizavimas
@@ -86,7 +85,6 @@ Comment[hu]=KOrganizer csoportmunka-beállítások
Comment[is]=Stillingar KOrganizer hópsjálfvirkni
Comment[it]=Configurazione automazione gruppi di KOrganizer
Comment[ja]=KOrganizer グループ自動化設定
-Comment[ka]=KOrganizer-ის ჯგუფური ავტომატიზაციის კონფიგურაცია
Comment[kk]=KOrganizer топтық жұмысының параметрлері
Comment[km]=ការ​កំណត់​រចនាសម្ព័ន្ធ​ស្វ័យប្រតិកម្ម​ក្រុម​របស់ KOrganizer
Comment[lt]=KOrganizer grupių automatizavimo konfigūravimas
@@ -129,7 +127,7 @@ Keywords[et]=korganizer,grupid,grupitöö
Keywords[eu]=korganizer,taldea,automatizazioa
Keywords[fa]=korganizer،گروه، خودکارسازی
Keywords[fi]=korganizer,ryhmä,automaatio
-Keywords[fr]=korganizer,groupes,automatisation
+Keywords[fr]=KOrganizer,groupes,automatisation
Keywords[fy]=korganizer,groep,automatisearring
Keywords[gl]=korganizer,grupo,automatización
Keywords[hi]=के-आर्गेनाइज़र,समूह,स्वचालन
@@ -137,7 +135,6 @@ Keywords[hu]=korganizer,csoport,csoportmunka
Keywords[is]=korganizer,hópar,sjálfvirkni
Keywords[it]=korganizer,gruppi,automazione
Keywords[ja]=korganizer,グループ,自動化
-Keywords[ka]=korganizer,ჯგუფი,ავტომატიზაცია
Keywords[km]=korganizer,ក្រុម,ស្វ័យប្រតិកម្ម
Keywords[lt]=korganizer,group,automation, grupės,automatizavimas
Keywords[mk]=korganizer,group,automation,корганизатор,група,групи,автоматизација
diff --git a/korganizer/korganizer_configgroupscheduling.desktop b/korganizer/korganizer_configgroupscheduling.desktop
index d5fe9975e..710f6df7b 100644
--- a/korganizer/korganizer_configgroupscheduling.desktop
+++ b/korganizer/korganizer_configgroupscheduling.desktop
@@ -35,7 +35,6 @@ Name[hu]=Szervezés
Name[is]=Hópáætlun
Name[it]=Programmazione gruppi
Name[ja]=グループスケジューリング
-Name[ka]=ჯგუფის დაგეგმვა
Name[kk]=Топтың жұмысын жоспарлау
Name[km]=រៀបចំ​កាលវិភាគ​ក្រុម
Name[lt]=Grupių tvarkaraščių tvarkymas
@@ -87,7 +86,6 @@ Comment[hu]=KOrganizer szervezési beállítások
Comment[is]=Stillingar fyrir KOrganizer hópáætlun
Comment[it]=Configurazione del programmatore gruppi di KOrganizer
Comment[ja]=KOrganizer グループスケジューリング設定
-Comment[ka]=KOrganizer გჯუფის დაგეგმვის კონფიგურაცია
Comment[kk]=KOrganizer топтық жұмысты жоспрлаудың параметрлері
Comment[km]=ការ​កំណត់​រចនាសម្ព័ន្ធ​ការ​រៀបចំ​កាលវិភាគ​ក្រុម​របស់ KOrganizer
Comment[lt]=KOrganizer grupių tvarkaraščių tvarkymo konfigūravimas
@@ -128,14 +126,13 @@ Keywords[et]=korganizer,grupid,grupitöö,ajakavad
Keywords[eu]=korganizer,taldea,antolaketa
Keywords[fa]=korganizer،گروه، زمان‌بندی
Keywords[fi]=korganizer,ryhmä,ajastus
-Keywords[fr]=korganizer,groupes,planification
+Keywords[fr]=KOrganizer,groupes,planification
Keywords[fy]=korganizer,group,scheduling,plannen,groep
Keywords[gl]=korganizer,grupo,programar
Keywords[hu]=korganizer,csoport,szervezés
Keywords[is]=korganizer,hóp,áætlun
Keywords[it]=korganizer,gruppo,programmazione
Keywords[ja]=korganizer,グループ,スケジューリング
-Keywords[ka]=korganizer,გჯუფი,დაგეგმვა
Keywords[km]=korganizer,ក្រុម,កាលវិភាគ
Keywords[lt]=korganizer,group,scheduling,tvarkaraštis, grupė
Keywords[mk]=korganizer,group,scheduling,корганизатор,група,групи,закажување
diff --git a/korganizer/korganizer_configmain.desktop b/korganizer/korganizer_configmain.desktop
index 52e70ee05..1f5c5bde0 100644
--- a/korganizer/korganizer_configmain.desktop
+++ b/korganizer/korganizer_configmain.desktop
@@ -38,7 +38,6 @@ Name[hu]=Alapbeállítások
Name[is]=Persónulegt
Name[it]=Personale
Name[ja]=個人設定
-Name[ka]=პირადი
Name[kk]=Дербес
Name[km]=ផ្ទាល់​ខ្លួន
Name[lt]=Suasmeninimas
@@ -63,8 +62,7 @@ Name[ta]=அந்தரங்கமான
Name[tg]=Танзимотҳои шахсӣ
Name[tr]=Kişisel
Name[uk]=Особисті
-Name[uz]=Shaxsiy
-Name[uz@cyrillic]=Шахсий
+Name[uz]=Шахсий
Name[zh_CN]=个人
Name[zh_TW]=個人
Comment=KOrganizer Main Configuration
@@ -94,7 +92,6 @@ Comment[hu]=A KOrganizer alapbeállításai
Comment[is]=Aðalstillingar KOrganizer
Comment[it]=Configurazione principale di KOrganizer
Comment[ja]=KOrganizer 主要設定
-Comment[ka]=KOrganizer ძირითადი კონფიგურაცია
Comment[kk]=KOrganizer-дің негізгі параметрлері
Comment[km]=ការ​កំណត់​រចនាសម្ព័ន្ធ​សំខាន់ៗ​របស់ KOrganizer
Comment[lt]=KOrganizer bendroji konfigūravimas
@@ -135,7 +132,7 @@ Keywords[et]=korganizer,peamine,isiklik
Keywords[eu]=korganizer,nagusia,pertsonala
Keywords[fa]=korganizer،اصلی، شخصی
Keywords[fi]=korganizer,pää,henkilökohtainen
-Keywords[fr]=korganizer,principal,personnel
+Keywords[fr]=KOrganizer,principal,personnel
Keywords[fy]=korganizer,algemien, persoanlik
Keywords[gl]=korganizer,principal,persoal
Keywords[he]=korganizer,main,personal,ארגונית,תצורה,הגדרה,הגדרות
@@ -144,7 +141,6 @@ Keywords[hu]=korganizer,alapbeállítások,személyes
Keywords[is]=korganizer,aðal,persónulegt
Keywords[it]=korganizer,principale,personale
Keywords[ja]=korganizer,メイン,個人
-Keywords[ka]=korganizer,ძირითადი,პირადი
Keywords[km]=korganizer,សំខាន់,ផ្ទាល់​ខ្លួន
Keywords[lt]=korganizer,main,personal,pagrindinis,asmeninis,bendroji
Keywords[mk]=korganizer,main,personal,корганизатор,главно,лично
@@ -168,6 +164,5 @@ Keywords[ta]=கேஅமைப்பாளர்,முக்கிய, தன
Keywords[tg]=korganizer,main,personal,почта,танзимотҳои шахсӣ,органайзер
Keywords[tr]=korganizer,temel,kişisel
Keywords[uk]=korganizer,особистий,Персональний
-Keywords[uz]=korganizer,organayzer,asosiy,shaxsiy
-Keywords[uz@cyrillic]=korganizer,органайзер,асосий,шахсий
+Keywords[uz]=korganizer,органайзер,асосий,шахсий
Keywords[zh_CN]=korganizer,main,personal,主要,个人
diff --git a/korganizer/korganizer_configplugins.desktop b/korganizer/korganizer_configplugins.desktop
index 7e4c332a2..2488f1ade 100644
--- a/korganizer/korganizer_configplugins.desktop
+++ b/korganizer/korganizer_configplugins.desktop
@@ -37,7 +37,6 @@ Name[hu]=Bővítőmodulok
Name[is]=Íforrit
Name[it]=Plugin
Name[ja]=プラグイン
-Name[ka]=მოდულები
Name[kk]=Плагин модульдері
Name[km]=កម្មវិធី​ជំនួយ
Name[lt]=Priedai
@@ -59,8 +58,7 @@ Name[sv]=Insticksprogram
Name[ta]=சொருகுப்பொருள்கள்
Name[tr]=Eklentiler
Name[uk]=Втулки
-Name[uz]=Plaginlar
-Name[uz@cyrillic]=Плагинлар
+Name[uz]=Плагинлар
Name[zh_CN]=插件
Name[zh_TW]=外掛程式
Comment=KOrganizer Plugin Configuration
@@ -87,7 +85,6 @@ Comment[hu]=A KOrganizer bővítőmodul beállításai
Comment[is]=Stillingar KOrganizer íforrita
Comment[it]=Configurazione plugin KOrganizer
Comment[ja]=KOrganizer プラグイン設定
-Comment[ka]=KOrganizer მოდულების კონფიგურაცია
Comment[kk]=KOrganizer-дің плагин модульдерінің параметрлері
Comment[km]=ការ​កំណត់​រចនាសម្ព័ន្ធ​កម្មវិធី​ជំនួយ KOrganizer
Comment[lt]=KOrganizer priedų konfigūravimas
@@ -125,7 +122,7 @@ Keywords[et]=korganizer,plugin,moodul
Keywords[eu]=korganizer,plugin-a,modulua
Keywords[fa]=korganizer،وصله، پیمانه
Keywords[fi]=korganizer,liitännäinen,moduuli
-Keywords[fr]=korganizer,module
+Keywords[fr]=KOrganizer,module
Keywords[ga]=korganizer,breiseán,modúl
Keywords[gl]=korganizer,extensión,módulo
Keywords[he]=korganizer,plugin,module,מודול,תוסף,ארגונית
@@ -133,7 +130,6 @@ Keywords[hu]=korganizer,bővítőmodul,modul
Keywords[is]=korganizer,íforrit,eining
Keywords[it]=korganizer,plugin,modulo
Keywords[ja]=korganizer,プラグイン,モジュール
-Keywords[ka]=korganizer,მოდული
Keywords[km]=korganizer,កម្មវិធី​ជំនួយ,ម៉ូឌុល
Keywords[lt]=korganizer,plugin,module,modulis,priedas
Keywords[mk]=korganizer,plugin,module,корганизатор,приклучок,приклучоци,модул.модули
diff --git a/korganizer/korganizer_configtime.desktop b/korganizer/korganizer_configtime.desktop
index 72d7629a1..a1eebdbc9 100644
--- a/korganizer/korganizer_configtime.desktop
+++ b/korganizer/korganizer_configtime.desktop
@@ -40,7 +40,6 @@ Name[hu]=Dátum és idő
Name[is]=Tími og dagsetning
Name[it]=Data e ora
Name[ja]=日付と時間
-Name[ka]=დრო და თარიღი
Name[kk]=Уақыт пен Күн
Name[km]=កាលបរិច្ឆេទ & ពេលវេលា
Name[lt]=Laikas ir data
@@ -66,8 +65,7 @@ Name[ta]=நேரம் & தேதி
Name[tg]=Сана ва вақт
Name[tr]=Saat & Tarih
Name[uk]=Час та дата
-Name[uz]=Sana va vaqt
-Name[uz@cyrillic]=Сана ва вақт
+Name[uz]=Сана ва вақт
Name[zh_CN]=时间和日期
Name[zh_TW]=時間與日期
Comment=KOrganizer Time Configuration
@@ -97,7 +95,6 @@ Comment[hu]=KOrganizer dátum- és időbeállítások
Comment[is]=KOrganizer tímastillingar
Comment[it]=Configurazione data di KOrganizer
Comment[ja]=KOrganizer 時間設定
-Comment[ka]=KOrganizer დროის კონფიგურაცია
Comment[kk]=KOrganizer-дің уақыт параметрлері
Comment[km]=ការ​កំណត់​រចនាសម្ព័ន្ធ​ពេលវេលា​របស់ KOrganizer
Comment[lt]=KOrganizer laiko konfigūravimas
@@ -141,7 +138,7 @@ Keywords[et]=korganizer,aeg
Keywords[eu]=korganizer,ordua,data
Keywords[fa]=korganizer،زمان
Keywords[fi]=korganizer,aika
-Keywords[fr]=korganizer,date
+Keywords[fr]=KOrganizer,date
Keywords[fy]=datum,tijd,tiid,korganizer
Keywords[ga]=korganizer,am
Keywords[gl]=korganizer,hora
@@ -151,7 +148,6 @@ Keywords[hu]=korganizer,idő
Keywords[is]=korganizer,tími
Keywords[it]=korganizer,data,ora
Keywords[ja]=korganizer,時間
-Keywords[ka]=korganizer,დრო
Keywords[km]=korganizer,ពេលវេលា
Keywords[lt]=korganizer,time,laikas
Keywords[mk]=korganizer,time,корганизатор,датум,време
@@ -175,6 +171,5 @@ Keywords[ta]=கேஅமைப்பாளர்,நேரம்
Keywords[tg]=korganizer,time,органайзер,вақт
Keywords[tr]=korganizer,zaman
Keywords[uk]=korganizer,час,дата
-Keywords[uz]=korganizer,organayzer,sana,vaqt
-Keywords[uz@cyrillic]=korganizer,органайзер,сана,вақт
+Keywords[uz]=korganizer,органайзер,сана,вақт
Keywords[zh_CN]=korganizer,time,时间
diff --git a/korganizer/korganizer_configviews.desktop b/korganizer/korganizer_configviews.desktop
index dd20819ac..d46f352a7 100644
--- a/korganizer/korganizer_configviews.desktop
+++ b/korganizer/korganizer_configviews.desktop
@@ -37,10 +37,9 @@ Name[gl]=Vistas
Name[he]=תצוגות
Name[hi]=दृश्य
Name[hu]=Nézetek
-Name[is]=Sýnir
+Name[is]=Sýn
Name[it]=Viste
Name[ja]=ビューア
-Name[ka]=ხედები
Name[kk]=Көріністері
Name[km]=ទិដ្ឋភាព
Name[lt]=Žiūrikliai
@@ -66,8 +65,7 @@ Name[ta]=காட்சிகள்
Name[tg]=Намудҳо
Name[tr]=Görünümler
Name[uk]=Перегляди
-Name[uz]=Koʻrinishlar
-Name[uz@cyrillic]=Кўринишлар
+Name[uz]=Кўринишлар
Name[zh_CN]=视图
Name[zh_TW]=檢視
Comment=KOrganizer View Configuration
@@ -95,7 +93,6 @@ Comment[hu]=KOrganizer nézeti beállítások
Comment[is]=Stillingar KOrganizer sýna
Comment[it]=Configurazione viste di KOrganizer
Comment[ja]=KOrganizer ビューア設定
-Comment[ka]=KOrganizer ხედის კონფიგურაცია
Comment[kk]=KOrganizer-дің көрінісінің параметрлері
Comment[km]=ការ​កំណត់​រចនាសម្ព័ន្ធ​ទិដ្ឋភាព​របស់ KOrganizer
Comment[lt]=KOrganizer žiūriklių konfigūravimas
@@ -138,7 +135,7 @@ Keywords[et]=korganizer,vaade
Keywords[eu]=korganizer,ikuspegia
Keywords[fa]=korganizer،نما
Keywords[fi]=korganizer,näkymä
-Keywords[fr]=korganizer,vues
+Keywords[fr]=KOrganizer,vues
Keywords[fy]=korganizer,weergave, werjefte
Keywords[ga]=korganizer,amharc
Keywords[gl]=korganizer,vista
@@ -146,7 +143,6 @@ Keywords[hi]=के-आर्गेनाइज़र,दृश्य
Keywords[hu]=korganizer,nézet
Keywords[is]=korganizer,sýn
Keywords[it]=korganizer,viste
-Keywords[ka]=korganizer,ხედი
Keywords[km]=korganizer,ទិដ្ឋភាព
Keywords[lt]=korganizer,view,žiūrikliai
Keywords[mk]=korganizer,view,корганизатор,приказ
@@ -170,6 +166,5 @@ Keywords[ta]=கேஅமைப்பாளர்,காட்சி
Keywords[tg]=korganizer,view,органайзер,намудҳо
Keywords[tr]=korganizer,görünüm
Keywords[uk]=korganizer,перегляд
-Keywords[uz]=korganizer,organayzer,koʻrinish
-Keywords[uz@cyrillic]=korganizer,органайзер,кўриниш
+Keywords[uz]=korganizer,органайзер,кўриниш
Keywords[zh_CN]=korganizer,view,视图
diff --git a/korganizer/korganizer_part.cpp b/korganizer/korganizer_part.cpp
index 572255494..65511bd18 100644
--- a/korganizer/korganizer_part.cpp
+++ b/korganizer/korganizer_part.cpp
@@ -52,7 +52,7 @@
#include <ktempfile.h>
#include <kstatusbar.h>
#include <kparts/genericfactory.h>
-
+#include <kparts/partmanager.h>
#include <kparts/statusbarextension.h>
#include <sidebarextension.h>
@@ -109,8 +109,8 @@ KOrganizerPart::KOrganizerPart( TQWidget *parentWidget, const char *widgetName,
KParts::InfoExtension *ie = new KParts::InfoExtension( this,
"KOrganizerInfo" );
- connect( mView, TQT_SIGNAL( incidenceSelected( Incidence * ) ),
- TQT_SLOT( slotChangeInfo( Incidence * ) ) );
+ connect( mView, TQT_SIGNAL( incidenceSelected( Incidence *,const TQDate & ) ),
+ TQT_SLOT( slotChangeInfo( Incidence *,const TQDate & ) ) );
connect( this, TQT_SIGNAL( textChanged( const TQString & ) ),
ie, TQT_SIGNAL( textChanged( const TQString & ) ) );
@@ -145,7 +145,7 @@ void KOrganizerPart::startCompleted( KProcess *process )
delete process;
}
-void KOrganizerPart::slotChangeInfo( Incidence *incidence )
+void KOrganizerPart::slotChangeInfo( Incidence *incidence, const TQDate & )
{
if ( incidence ) {
emit textChanged( incidence->summary() + " / " +
@@ -234,4 +234,13 @@ void KOrganizerPart::setTitle()
emit setWindowCaption( title );*/
}
+bool KOrganizerPart::isCurrentlyActivePart()
+{
+ if ( manager() ) {
+ return ( manager()->activePart() == this );
+ } else {
+ return false;
+ }
+}
+
#include "korganizer_part.moc"
diff --git a/korganizer/korganizer_part.h b/korganizer/korganizer_part.h
index 25a4b9c4b..ad6a45081 100644
--- a/korganizer/korganizer_part.h
+++ b/korganizer/korganizer_part.h
@@ -51,6 +51,8 @@ namespace KOrg {
class CalendarViewBase;
}
+class TQDate;
+
class KOrganizerPart: public KParts::ReadOnlyPart,
public KOrg::MainWindow
{
@@ -81,10 +83,12 @@ class KOrganizerPart: public KParts::ReadOnlyPart,
virtual KActionCollection *getActionCollection() const { return actionCollection(); }
virtual void showStatusMessage( const TQString &message );
+ virtual bool isCurrentlyActivePart();
+
void setTitle();
public slots:
- void slotChangeInfo( Incidence * );
+ void slotChangeInfo( Incidence *incidence, const TQDate & );
protected:
virtual bool openFile();
diff --git a/korganizer/korganizeriface.h b/korganizer/korganizeriface.h
index f3d8a15ea..88ab61d50 100644
--- a/korganizer/korganizeriface.h
+++ b/korganizer/korganizeriface.h
@@ -21,7 +21,7 @@
#define KORGANIZERIFACE_H
#include <dcopobject.h>
-
+#include <tqdatetime.h>
class KOrganizerIface : virtual public DCOPObject
{
@@ -35,6 +35,7 @@ class KOrganizerIface : virtual public DCOPObject
virtual bool saveAsURL(const TQString &url) = 0;
virtual TQString getCurrentURLasString() const = 0;
virtual bool editIncidence(const TQString &uid) = 0;
+ virtual bool editIncidence( const TQString &uid, const TQDate &date ) = 0;
virtual bool deleteIncidence(const TQString &uid) = 0;
virtual void syncAllResources() = 0;
/**
@@ -56,6 +57,13 @@ class KOrganizerIface : virtual public DCOPObject
virtual void loadProfile( const TQString& path ) = 0;
virtual void saveToProfile( const TQString& path ) const = 0;
+
+ /**
+ * DCOP-enabled for KOrganizerUniqueAppHandler in the kontact plugin
+ * Returns true if the command line was successfully handled
+ * false otherwise.
+ */
+ virtual bool handleCommandLine() = 0;
};
#endif
diff --git a/korganizer/korganizerifaceimpl.cpp b/korganizer/korganizerifaceimpl.cpp
index 77db1afc7..e482e0f4a 100644
--- a/korganizer/korganizerifaceimpl.cpp
+++ b/korganizer/korganizerifaceimpl.cpp
@@ -91,6 +91,11 @@ bool KOrganizerIfaceImpl::editIncidence( const TQString &uid )
return mActionManager->editIncidence( uid );
}
+bool KOrganizerIfaceImpl::editIncidence( const TQString &uid, const TQDate &date )
+{
+ return mActionManager->editIncidence( uid, date );
+}
+
bool KOrganizerIfaceImpl::addIncidence( const TQString &ical )
{
return mActionManager->addIncidence( ical );
@@ -103,12 +108,14 @@ bool KOrganizerIfaceImpl::canQueryClose()
void KOrganizerIfaceImpl::loadProfile( const TQString& path )
{
- mActionManager->loadProfile( path );
+ mActionManager->loadProfile( path );
}
void KOrganizerIfaceImpl::saveToProfile( const TQString& path ) const
{
- mActionManager->saveToProfile( path );
+ mActionManager->saveToProfile( path );
}
-
+bool KOrganizerIfaceImpl::handleCommandLine() {
+ return mActionManager->handleCommandLine();
+}
diff --git a/korganizer/korganizerifaceimpl.h b/korganizer/korganizerifaceimpl.h
index 03f02a9e8..3efa4b17a 100644
--- a/korganizer/korganizerifaceimpl.h
+++ b/korganizer/korganizerifaceimpl.h
@@ -55,6 +55,8 @@ public:
void syncAllResources();
bool editIncidence( const TQString &uid );
+ bool editIncidence( const TQString &uid, const TQDate &date );
+
/** @reimp from KOrganizerIface::deleteIncidence() */
bool deleteIncidence( const TQString &uid ) { return deleteIncidence( uid, false ); }
/** @reimp from KOrganizerIface::deleteIncidence() */
@@ -69,6 +71,9 @@ public:
/** @reimp from KOrganizerIface::saveToProfile() */
void saveToProfile( const TQString& path ) const;
+ /** @reimp from KOrganizerIface::handleCommandLine() */
+ bool handleCommandLine();
+
private:
ActionManager* mActionManager;
};
diff --git a/korganizer/kotimelineview.cpp b/korganizer/kotimelineview.cpp
index ac40e2a31..1eb1084de 100644
--- a/korganizer/kotimelineview.cpp
+++ b/korganizer/kotimelineview.cpp
@@ -88,7 +88,7 @@ KCal::ListBase<KCal::Incidence> KOTimelineView::selectedIncidences()
}
/*virtual*/
-KCal::DateList KOTimelineView::selectedDates()
+KCal::DateList KOTimelineView::selectedIncidenceDates()
{
return KCal::DateList();
}
@@ -120,7 +120,7 @@ void KOTimelineView::showDates(const TQDate& start, const TQDate& end)
TimelineItem *item = 0;
CalendarResources *calres = dynamic_cast<CalendarResources*>( calendar() );
if ( !calres ) {
- item = new TimelineItem( i18n("Calendar"), mGantt );
+ item = new TimelineItem( i18n("Calendar"), calendar(), mGantt );
mCalendarItemMap[0][TQString()] = item;
} else {
CalendarResourceManager *manager = calres->resourceManager();
@@ -132,7 +132,7 @@ void KOTimelineView::showDates(const TQDate& start, const TQDate& end)
TQString type = (*it)->subresourceType( *subit );
if ( !(*it)->subresourceActive( *subit ) || (!type.isEmpty() && type != "event") )
continue;
- item = new TimelineItem( (*it)->labelForSubresource( *subit ), mGantt );
+ item = new TimelineItem( (*it)->labelForSubresource( *subit ), calendar(), mGantt );
resourceColor = *KOPrefs::instance()->resourceColor( (*it)->identifier() );
TQColor subrescol = *KOPrefs::instance()->resourceColor( *subit );
if ( subrescol.isValid() )
@@ -142,7 +142,7 @@ void KOTimelineView::showDates(const TQDate& start, const TQDate& end)
mCalendarItemMap[*it][*subit] = item;
}
} else {
- item = new TimelineItem( (*it)->resourceName(), mGantt );
+ item = new TimelineItem( (*it)->resourceName(), calendar(), mGantt );
if ( resourceColor.isValid() )
item->setColors( resourceColor, resourceColor, resourceColor );
mCalendarItemMap[*it][TQString()] = item;
@@ -163,7 +163,7 @@ void KOTimelineView::showDates(const TQDate& start, const TQDate& end)
}
/*virtual*/
-void KOTimelineView::showIncidences(const KCal::ListBase<KCal::Incidence>&)
+void KOTimelineView::showIncidences(const KCal::ListBase<KCal::Incidence>&, const TQDate &)
{
}
@@ -198,14 +198,15 @@ void KOTimelineView::itemSelected( KDGanttViewItem *item )
{
TimelineSubItem *tlitem = dynamic_cast<TimelineSubItem*>( item );
if ( tlitem )
- emit incidenceSelected( tlitem->incidence() );
+ emit incidenceSelected( tlitem->incidence(), tlitem->originalStart().date() );
}
void KOTimelineView::itemDoubleClicked( KDGanttViewItem *item )
{
TimelineSubItem *tlitem = dynamic_cast<TimelineSubItem*>( item );
- if ( tlitem )
- emit editIncidenceSignal( tlitem->incidence() );
+ if ( tlitem ) {
+ emit editIncidenceSignal( tlitem->incidence(), TQDate() );
+ }
}
void KOTimelineView::itemRightClicked( KDGanttViewItem *item )
@@ -218,7 +219,7 @@ void KOTimelineView::itemRightClicked( KDGanttViewItem *item )
}
if ( !mEventPopup )
mEventPopup = eventPopup();
- mEventPopup->showIncidencePopup( tlitem->incidence(), TQDate() );
+ mEventPopup->showIncidencePopup( calendar(), tlitem->incidence(), TQDate() );
}
bool KOTimelineView::eventDurationHint(TQDateTime & startDt, TQDateTime & endDt, bool & allDay)
@@ -233,7 +234,7 @@ bool KOTimelineView::eventDurationHint(TQDateTime & startDt, TQDateTime & endDt,
void KOTimelineView::newEventWithHint( const TQDateTime& dt )
{
mHintDate = dt;
- emit newEventSignal( dt );
+ emit newEventSignal( 0/*ResourceCalendar*/, TQString()/*subResource*/, dt );
}
TimelineItem * KOTimelineView::calendarItemForIncidence(KCal::Incidence * incidence)
@@ -323,7 +324,7 @@ void KOTimelineView::itemMoved(KDGanttViewItem * item)
if ( !tlit )
return;
Incidence *i = tlit->incidence();
- mChanger->beginChange( i );
+ mChanger->beginChange( i, 0, TQString() );
TQDateTime newStart = tlit->startTime();
if ( i->doesFloat() )
newStart = TQDateTime( newStart.date() );
@@ -341,7 +342,7 @@ void KOTimelineView::itemMoved(KDGanttViewItem * item)
i->setDuration( duration );
TimelineItem *parent = static_cast<TimelineItem*>( tlit->parent() );
parent->moveItems( i, tlit->originalStart().secsTo( newStart ), duration + allDayOffset );
- mChanger->endChange( i );
+ mChanger->endChange( i, 0, TQString() );
}
void KOTimelineView::overscale(KDGanttView::Scale scale)
diff --git a/korganizer/kotimelineview.h b/korganizer/kotimelineview.h
index 5c3ec6a7c..81e1eef40 100644
--- a/korganizer/kotimelineview.h
+++ b/korganizer/kotimelineview.h
@@ -50,10 +50,10 @@ class KOTimelineView : public KOEventView
~KOTimelineView();
virtual KCal::ListBase<KCal::Incidence> selectedIncidences();
- virtual KCal::DateList selectedDates();
+ virtual KCal::DateList selectedIncidenceDates();
virtual int currentDateCount();
virtual void showDates(const TQDate&, const TQDate&);
- virtual void showIncidences(const KCal::ListBase<KCal::Incidence>&);
+ virtual void showIncidences(const KCal::ListBase<KCal::Incidence>&, const TQDate &date);
virtual void updateView();
virtual void changeIncidenceDisplay(KCal::Incidence* incidence, int mode);
virtual int maxDatesHint() { return 0; }
diff --git a/korganizer/kotodoeditor.cpp b/korganizer/kotodoeditor.cpp
index fe749c9c9..9d273b3a0 100644
--- a/korganizer/kotodoeditor.cpp
+++ b/korganizer/kotodoeditor.cpp
@@ -52,11 +52,9 @@
#include "kocore.h"
KOTodoEditor::KOTodoEditor( Calendar *calendar, TQWidget *parent ) :
- KOIncidenceEditor( TQString::null, calendar, parent )
+ KOIncidenceEditor( TQString::null, calendar, parent ),
+ mTodo( 0 ), mCalendar( 0 ), mRelatedTodo( 0 ), mGeneral( 0 ), mRecurrence( 0 )
{
- mTodo = 0;
- mCalendar = 0;
- mRelatedTodo = 0;
}
KOTodoEditor::~KOTodoEditor()
@@ -66,11 +64,9 @@ KOTodoEditor::~KOTodoEditor()
void KOTodoEditor::init()
{
- kdDebug(5850) << k_funcinfo << endl;
setupGeneral();
setupRecurrence();
setupAttendeesTab();
-// setupAttachmentsTab();
connect( mGeneral, TQT_SIGNAL( dateTimeStrChanged( const TQString & ) ),
mRecurrence, TQT_SLOT( setDateTimeStr( const TQString & ) ) );
@@ -82,11 +78,18 @@ void KOTodoEditor::init()
connect( mDetails, TQT_SIGNAL(updateAttendeeSummary(int)),
mGeneral, TQT_SLOT(updateAttendeeSummary(int)) );
+
+ connect( mGeneral, TQT_SIGNAL(editRecurrence()),
+ mRecurrenceDialog, TQT_SLOT(show()) );
+ connect( mRecurrenceDialog, TQT_SIGNAL(okClicked()),
+ TQT_SLOT(updateRecurrenceSummary()) );
}
void KOTodoEditor::reload()
{
- if ( mTodo ) readTodo( mTodo, mCalendar );
+ if ( mTodo ) {
+ readTodo( mTodo, mCalendar, TQDate() );
+ }
}
void KOTodoEditor::setupGeneral()
@@ -115,8 +118,6 @@ void KOTodoEditor::setupGeneral()
TQHBoxLayout *completionLayout = new TQHBoxLayout( topLayout2 );
mGeneral->initCompletion(topFrame2,completionLayout);
- mGeneral->initAlarm(topFrame,topLayout);
-
mGeneral->initSecrecy( topFrame2, topLayout2 );
mGeneral->initDescription(topFrame2,topLayout2);
} else {
@@ -128,9 +129,6 @@ void KOTodoEditor::setupGeneral()
mGeneral->initHeader( topFrame, topLayout );
mGeneral->initTime(topFrame,topLayout);
mGeneral->initStatus(topFrame,topLayout);
- TQBoxLayout *alarmLineLayout = new TQHBoxLayout(topLayout);
- mGeneral->initAlarm(topFrame,alarmLineLayout);
- alarmLineLayout->addStretch( 1 );
mGeneral->initDescription(topFrame,topLayout);
mGeneral->initAttachments(topFrame,topLayout);
connect( mGeneral, TQT_SIGNAL( openURL( const KURL& ) ),
@@ -138,36 +136,25 @@ void KOTodoEditor::setupGeneral()
connect( this, TQT_SIGNAL( signalAddAttachments( const TQStringList&, const TQStringList&, bool ) ),
mGeneral, TQT_SLOT( addAttachments( const TQStringList&, const TQStringList&, bool ) ) );
}
- mGeneral->enableAlarm( true );
-
mGeneral->finishSetup();
}
void KOTodoEditor::setupRecurrence()
{
- TQFrame *topFrame = addPage( i18n("Rec&urrence") );
-
- TQBoxLayout *topLayout = new TQVBoxLayout( topFrame );
-
- mRecurrence = new KOEditorRecurrence( topFrame );
- topLayout->addWidget( mRecurrence );
-
- mRecurrence->setEnabled( false );
- connect(mGeneral,TQT_SIGNAL(dueDateEditToggle( bool ) ),
- mRecurrence, TQT_SLOT( setEnabled( bool ) ) );
+ mRecurrenceDialog = new KOEditorRecurrenceDialog( this );
+ mRecurrenceDialog->hide();
+ mRecurrence = mRecurrenceDialog->editor();
}
-void KOTodoEditor::editIncidence(Incidence *incidence, Calendar *calendar)
+void KOTodoEditor::editIncidence( Incidence *incidence, const TQDate &date, Calendar *calendar )
{
kdDebug(5850) << k_funcinfo << endl;
- Todo *todo=dynamic_cast<Todo*>(incidence);
- if (todo)
- {
+ Todo *todo = dynamic_cast<Todo*>( incidence );
+ if ( todo ) {
init();
-
mTodo = todo;
mCalendar = calendar;
- readTodo( mTodo, mCalendar );
+ readTodo( mTodo, mCalendar, date );
}
setCaption( i18n("Edit To-do") );
@@ -195,18 +182,18 @@ void KOTodoEditor::setTexts( const TQString &summary, const TQString &descriptio
}
}
-
-
void KOTodoEditor::loadDefaults()
{
kdDebug(5850) << k_funcinfo << endl;
- setDates( TQDateTime::currentDateTime().addDays(7), true, 0 );
- mGeneral->toggleAlarm( true );
+ setDates( TQDateTime::currentDateTime().addDays( 7 ), true, 0 );
+ mGeneral->toggleAlarm( KOPrefs::instance()->defaultTodoReminders() );
}
bool KOTodoEditor::processInput()
{
- if ( !validateInput() ) return false;
+ if ( !validateInput() ) {
+ return false;
+ }
if ( mTodo ) {
bool rc = true;
@@ -217,14 +204,23 @@ bool KOTodoEditor::processInput()
writeTodo( todo );
kdDebug(5850) << "KOTodoEditor::processInput() event written." << endl;
- if( *mTodo == *todo )
+ if ( *mTodo == *todo ) {
// Don't do anything
kdDebug(5850) << "Todo not changed\n";
- else {
+ } else {
kdDebug(5850) << "Todo changed\n";
//IncidenceChanger::assignIncidence( mTodo, todo );
writeTodo( mTodo );
- mChanger->changeIncidence( oldTodo, mTodo );
+
+ KOGlobals::WhatChanged whatChanged;
+
+ if ( !oldTodo->isCompleted() && todo->isCompleted() ) {
+ whatChanged = KOGlobals::COMPLETION_MODIFIED;
+ } else {
+ whatChanged = KOGlobals::NOTHING_MODIFIED;
+ }
+
+ mChanger->changeIncidence( oldTodo, mTodo, whatChanged, this );
}
delete todo;
delete oldTodo;
@@ -237,7 +233,7 @@ bool KOTodoEditor::processInput()
writeTodo( mTodo );
- if ( !mChanger->addIncidence( mTodo, this ) ) {
+ if ( !mChanger->addIncidence( mTodo, mResource, mSubResource, this ) ) {
delete mTodo;
mTodo = 0;
return false;
@@ -250,9 +246,10 @@ bool KOTodoEditor::processInput()
void KOTodoEditor::deleteTodo()
{
- if (mTodo)
+ if ( mTodo ) {
emit deleteIncidenceSignal( mTodo );
- emit dialogClose(mTodo);
+ }
+ emit dialogClose( mTodo );
reject();
}
@@ -271,18 +268,21 @@ void KOTodoEditor::setDates( const TQDateTime &due, bool allDay, Todo *relatedEv
}
mDetails->setDefaults();
- if ( mTodo )
+ if ( mTodo ) {
mRecurrence->setDefaults( mTodo->dtStart(), due, false );
- else
+ } else {
mRecurrence->setDefaults( TQDateTime::currentDateTime(), due, false );
+ }
}
-void KOTodoEditor::readTodo( Todo *todo, Calendar *calendar )
+void KOTodoEditor::readTodo( Todo *todo, Calendar *calendar, const TQDate &date )
{
- if ( !todo ) return;
+ if ( !todo ) {
+ return;
+ }
// mRelatedTodo = todo->relatedTo();
- kdDebug(5850)<<"read todo"<<endl;
- mGeneral->readTodo( todo, calendar );
+
+ mGeneral->readTodo( todo, calendar, date );
mDetails->readEvent( todo );
mRecurrence->readIncidence( todo );
@@ -300,8 +300,9 @@ void KOTodoEditor::writeTodo( Todo *todo )
if ( *(oldIncidence->recurrence()) != *(todo->recurrence() ) ) {
todo->setDtDue( todo->dtDue(), true );
- if ( todo->hasStartDate() )
+ if ( todo->hasStartDate() ) {
todo->setDtStart( todo->dtStart() );
+ }
}
writeDesignerFields( todo );
@@ -328,10 +329,10 @@ int KOTodoEditor::msgItemDelete()
i18n("KOrganizer Confirmation"), KStdGuiItem::del() );
}
-void KOTodoEditor::modified (int /*modification*/)
+void KOTodoEditor::modified()
{
- // Play dump, just reload the todo. This dialog has become so complicated that
- // there is no point in trying to be smart here...
+ // Play dump, just reload the todo. This dialog has become so complicated
+ // that there is no point in trying to be smart here...
reload();
}
@@ -342,7 +343,7 @@ void KOTodoEditor::loadTemplate( /*const*/ CalendarLocal& cal )
KMessageBox::error( this,
i18n("Template does not contain a valid to-do.") );
} else {
- readTodo( todos.first(), 0 );
+ readTodo( todos.first(), 0, TQDate() );
}
}
@@ -358,4 +359,12 @@ TQStringList& KOTodoEditor::templates() const
return KOPrefs::instance()->mTodoTemplates;
}
+void KOTodoEditor::updateRecurrenceSummary()
+{
+ Todo *todo = new Todo();
+ writeTodo( todo );
+ mGeneral->updateRecurrenceSummary( todo );
+ delete todo;
+}
+
#include "kotodoeditor.moc"
diff --git a/korganizer/kotodoeditor.h b/korganizer/kotodoeditor.h
index 3b6df5b38..5ab3e36dd 100644
--- a/korganizer/kotodoeditor.h
+++ b/korganizer/kotodoeditor.h
@@ -60,12 +60,12 @@ class KOTodoEditor : public KOIncidenceEditor
*/
void setTexts( const TQString &summary, const TQString &description = TQString::null );
/** Edit an existing todo. */
- void editIncidence(Incidence *incidence, Calendar* calendar);
+ void editIncidence(Incidence *incidence, const TQDate &date, Calendar* calendar);
/** Set widgets to default values */
void setDates( const TQDateTime &due, bool allDay = true, Todo *relatedTodo = 0 );
/** Read event object and setup widgets accordingly */
- void readTodo(Todo *todo, Calendar *calendar);
+ void readTodo(Todo *todo, Calendar *calendar, const TQDate &date);
/** Write event settings to event object */
void writeTodo(Todo *);
@@ -76,12 +76,14 @@ class KOTodoEditor : public KOIncidenceEditor
bool processInput();
/** This todo has been modified externally */
- void modified (int change=0);
+ void modified();
protected slots:
void loadDefaults();
void deleteTodo();
+
void slotSaveTemplate( const TQString & );
+ void updateRecurrenceSummary();
protected:
void loadTemplate( /*const*/ CalendarLocal& );
@@ -98,6 +100,7 @@ class KOTodoEditor : public KOIncidenceEditor
Todo *mRelatedTodo;
KOEditorGeneralTodo *mGeneral;
+ KOEditorRecurrenceDialog *mRecurrenceDialog;
KOEditorRecurrence *mRecurrence;
};
diff --git a/korganizer/kotodoview.cpp b/korganizer/kotodoview.cpp
index 3736bf29c..5951d8bc4 100644
--- a/korganizer/kotodoview.cpp
+++ b/korganizer/kotodoview.cpp
@@ -35,6 +35,7 @@
#include <kiconloader.h>
#include <kmessagebox.h>
+#include <libkcal/calhelper.h>
#include <libkcal/icaldrag.h>
#include <libkcal/vcaldrag.h>
#include <libkcal/dndfactory.h>
@@ -63,9 +64,10 @@ using namespace KOrg;
#include "calprinter.h"
#endif
-KOTodoListViewToolTip::KOTodoListViewToolTip (TQWidget* parent,
- KOTodoListView* lv )
- :TQToolTip(parent)
+KOTodoListViewToolTip::KOTodoListViewToolTip (TQWidget *parent,
+ Calendar *calendar,
+ KOTodoListView *lv )
+ :TQToolTip(parent), mCalendar( calendar )
{
todolist=lv;
}
@@ -88,7 +90,7 @@ void KOTodoListViewToolTip::maybeTip( const TQPoint & pos)
r.setRight(headerPos + todolist->header()->sectionSize(col));
/* Show the tip */
- TQString tipText( IncidenceFormatter::toolTipString( i->todo() ) );;
+ TQString tipText( IncidenceFormatter::toolTipStr( mCalendar, i->todo(), TQDate(), true ) );;
if ( !tipText.isEmpty() ) {
tip(r, tipText);
}
@@ -103,14 +105,10 @@ KOTodoListView::KOTodoListView( TQWidget *parent, const char *name )
{
mOldCurrent = 0;
mMousePressed = false;
-
- /* Create a Tooltip */
- tooltip = new KOTodoListViewToolTip( viewport(), this );
}
KOTodoListView::~KOTodoListView()
{
- delete tooltip;
}
void KOTodoListView::setCalendar( Calendar *cal )
@@ -222,11 +220,12 @@ void KOTodoListView::contentsDropEvent( TQDropEvent *e )
}
to = to->relatedTo();
}
+
Todo*oldTodo = existingTodo->clone();
- if ( mChanger->beginChange( existingTodo ) ) {
+ if ( mChanger->beginChange( existingTodo, 0, TQString() ) ) {
existingTodo->setRelatedTo( destinationEvent );
- mChanger->changeIncidence( oldTodo, existingTodo, KOGlobals::RELATION_MODIFIED );
- mChanger->endChange( existingTodo );
+ mChanger->changeIncidence( oldTodo, existingTodo, KOGlobals::RELATION_MODIFIED, this );
+ mChanger->endChange( existingTodo, 0, TQString() );
} else {
KMessageBox::sorry( this, i18n("Unable to change to-do's parent, "
"because the to-do cannot be locked.") );
@@ -236,14 +235,13 @@ void KOTodoListView::contentsDropEvent( TQDropEvent *e )
} else {
// kdDebug(5850) << "Drop new Todo" << endl;
todo->setRelatedTo(destinationEvent);
- if ( !mChanger->addIncidence( todo, this ) ) {
+ if ( !mChanger->addIncidence( todo, 0, TQString(), this ) ) {
KODialogManager::errorSaveIncidence( this, todo );
delete todo;
return;
}
}
- }
- else {
+ } else {
TQString text;
KOTodoViewItem *todoi = dynamic_cast<KOTodoViewItem *>(itemAt( contentsToViewport(e->pos()) ));
if ( ! todoi ) {
@@ -256,7 +254,7 @@ void KOTodoListView::contentsDropEvent( TQDropEvent *e )
//TQListViewItem *qlvi = itemAt( contentsToViewport(e->pos()) );
kdDebug(5850) << "Dropped : " << text << endl;
Todo*todo = todoi->todo();
- if( mChanger->beginChange( todo ) ) {
+ if( mChanger->beginChange( todo, 0, TQString() ) ) {
Todo*oldtodo = todo->clone();
if( text.startsWith( "file:" ) ) {
@@ -273,8 +271,9 @@ void KOTodoListView::contentsDropEvent( TQDropEvent *e )
}
}
}
- mChanger->changeIncidence( oldtodo, todo );
- mChanger->endChange( todo );
+ //FIXME: attendees or attachment added, so there is something modified
+ mChanger->changeIncidence( oldtodo, todo, KOGlobals::NOTHING_MODIFIED, this );
+ mChanger->endChange( todo, 0, TQString() );
} else {
KMessageBox::sorry( this, i18n("Unable to add attendees to the to-do, "
"because the to-do cannot be locked.") );
@@ -393,6 +392,7 @@ KOTodoView::KOTodoView( Calendar *calendar, TQWidget *parent, const char* name)
mTodoListView->addColumn( i18n("Due Date/Time") );
mTodoListView->setColumnAlignment( eDueDateColumn, AlignLeft );
mTodoListView->addColumn( i18n("Categories") );
+ mTodoListView->addColumn( i18n( "Calendar" ) );
#if 0
mTodoListView->addColumn( i18n("Sort Id") );
mTodoListView->setColumnAlignment( 4, AlignHCenter );
@@ -408,6 +408,7 @@ KOTodoView::KOTodoView( Calendar *calendar, TQWidget *parent, const char* name)
mTodoListView->setColumnWidthMode( ePercentColumn, TQListView::Manual );
mTodoListView->setColumnWidthMode( eDueDateColumn, TQListView::Manual );
mTodoListView->setColumnWidthMode( eCategoriesColumn, TQListView::Manual );
+ mTodoListView->setColumnWidthMode( eFolderColumn, TQListView::Manual );
#if 0
mTodoListView->setColumnWidthMode( eDescriptionColumn, TQListView::Manual );
#endif
@@ -461,7 +462,7 @@ KOTodoView::KOTodoView( Calendar *calendar, TQWidget *parent, const char* name)
TQT_SLOT (deleteTodo()), 0, ePopupDelete );
mItemPopupMenu->insertSeparator();
mItemPopupMenu->insertItem(KOGlobals::self()->smallIconSet("todo"), i18n("New &To-do..."), this,
- TQT_SLOT (newTodo()));
+ TQT_SLOT (newTodo()) );
mItemPopupMenu->insertItem(i18n("New Su&b-to-do..."), this,
TQT_SLOT (newSubTodo()));
mItemPopupMenu->insertItem( i18n("&Make this To-do Independent"), this,
@@ -482,7 +483,7 @@ KOTodoView::KOTodoView( Calendar *calendar, TQWidget *parent, const char* name)
mPopupMenu = new TQPopupMenu(this);
mPopupMenu->insertItem(KOGlobals::self()->smallIconSet("todo"), i18n("&New To-do..."), this,
- TQT_SLOT (newTodo()));
+ TQT_SLOT(newTodo()) );
mPopupMenu->insertItem(i18n("delete completed to-dos","&Purge Completed"),
this, TQT_SLOT(purgeCompleted()));
@@ -514,6 +515,8 @@ KOTodoView::KOTodoView( Calendar *calendar, TQWidget *parent, const char* name)
TQT_SLOT( processSelectionChange() ) );
connect( mQuickAdd, TQT_SIGNAL( returnPressed () ),
TQT_SLOT( addQuickTodo() ) );
+
+ new KOTodoListViewToolTip( mTodoListView->viewport(), calendar, mTodoListView );
}
KOTodoView::~KOTodoView()
@@ -742,24 +745,21 @@ void KOTodoView::showDates(const TQDate &, const TQDate &)
{
}
-void KOTodoView::showIncidences( const Incidence::List & )
+void KOTodoView::showIncidences( const Incidence::List &, const TQDate & )
{
kdDebug(5850) << "KOTodoView::showIncidences( const Incidence::List & ): not yet implemented" << endl;
}
CalPrinterBase::PrintType KOTodoView::printType()
{
- if ( mTodoListView->selectedItem() ) {
- return CalPrinterBase::Incidence;
- } else {
- return CalPrinterBase::Todolist;
- }
+ return CalPrinterBase::Todolist;
}
void KOTodoView::editItem( TQListViewItem *item )
{
- if (item)
- emit editIncidenceSignal( static_cast<KOTodoViewItem *>( item )->todo() );
+ if ( item ) {
+ emit editIncidenceSignal( static_cast<KOTodoViewItem *>( item )->todo(), TQDate () );
+ }
}
void KOTodoView::editItem( TQListViewItem *item, const TQPoint &, int )
@@ -769,8 +769,9 @@ void KOTodoView::editItem( TQListViewItem *item, const TQPoint &, int )
void KOTodoView::showItem( TQListViewItem *item )
{
- if (item)
- emit showIncidenceSignal( static_cast<KOTodoViewItem *>( item )->todo() );
+ if ( item ) {
+ emit showIncidenceSignal( static_cast<KOTodoViewItem *>( item )->todo(), TQDate() );
+ }
}
void KOTodoView::showItem( TQListViewItem *item, const TQPoint &, int )
@@ -830,7 +831,8 @@ void KOTodoView::popupMenu( TQListViewItem *item, const TQPoint &, int column )
void KOTodoView::newTodo()
{
kdDebug() << k_funcinfo << endl;
- emit newTodoSignal( TQDate::currentDate().addDays(7) );
+ emit newTodoSignal( 0/*ResourceCalendar*/, TQString()/*subResource*/,
+ TQDate::currentDate().addDays(7) );
}
void KOTodoView::newSubTodo()
@@ -860,8 +862,15 @@ void KOTodoView::printTodo()
Incidence::List selectedIncidences;
selectedIncidences.append( mActiveItem->todo() );
+ TQDateTime todoDate;
+ if ( mActiveItem->todo() && mActiveItem->todo()->hasStartDate() ) {
+ todoDate = mActiveItem->todo()->dtStart();
+ } else {
+ todoDate = mActiveItem->todo()->dtDue();
+ }
+
printer.print( KOrg::CalPrinterBase::Incidence,
- TQDate(), TQDate(), selectedIncidences );
+ todoDate.date(), todoDate.date(), selectedIncidences );
#endif
}
@@ -877,13 +886,13 @@ void KOTodoView::setNewPriority(int index)
if ( !mActiveItem || !mChanger ) return;
Todo *todo = mActiveItem->todo();
if ( !todo->isReadOnly () &&
- mChanger->beginChange( todo ) ) {
+ mChanger->beginChange( todo, 0, TQString() ) ) {
Todo *oldTodo = todo->clone();
todo->setPriority(mPriority[index]);
mActiveItem->construct();
- mChanger->changeIncidence( oldTodo, todo, KOGlobals::PRIORITY_MODIFIED );
- mChanger->endChange( todo );
+ mChanger->changeIncidence( oldTodo, todo, KOGlobals::PRIORITY_MODIFIED, this );
+ mChanger->endChange( todo, 0, TQString() );
delete oldTodo;
}
}
@@ -895,7 +904,8 @@ void KOTodoView::setNewPercentage( KOTodoViewItem *item, int percentage )
Todo *todo = item->todo();
if ( !todo ) return;
- if ( !todo->isReadOnly () && mChanger->beginChange( todo ) ) {
+ if ( !todo->isReadOnly () &&
+ mChanger->beginChange( todo, 0, TQString() ) ) {
Todo *oldTodo = todo->clone();
/* Old code to make sub-items's percentage related to this one's:
@@ -910,18 +920,20 @@ void KOTodoView::setNewPercentage( KOTodoViewItem *item, int percentage )
todo->setCompleted( TQDateTime::currentDateTime() );
// If the todo does recur, it doesn't get set as completed. However, the
// item is still checked. Uncheck it again.
- if ( !todo->isCompleted() ) item->setState( TQCheckListItem::Off );
- else todo->setPercentComplete( percentage );
+ if ( !todo->isCompleted() ) {
+ item->setState( TQCheckListItem::Off );
+ }
} else {
- todo->setCompleted( false );
todo->setPercentComplete( percentage );
}
item->construct();
if ( todo->doesRecur() && percentage == 100 )
- mChanger->changeIncidence( oldTodo, todo, KOGlobals::COMPLETION_MODIFIED_WITH_RECURRENCE );
+ mChanger->changeIncidence( oldTodo, todo,
+ KOGlobals::COMPLETION_MODIFIED_WITH_RECURRENCE, this );
else
- mChanger->changeIncidence( oldTodo, todo, KOGlobals::COMPLETION_MODIFIED );
- mChanger->endChange( todo );
+ mChanger->changeIncidence( oldTodo, todo,
+ KOGlobals::COMPLETION_MODIFIED, this );
+ mChanger->endChange( todo, 0, TQString() );
delete oldTodo;
} else {
item->construct();
@@ -940,24 +952,22 @@ void KOTodoView::setNewDate( TQDate date )
Todo *todo = mActiveItem->todo();
if ( !todo ) return;
- if ( !todo->isReadOnly() && mChanger->beginChange( todo ) ) {
+ if ( !todo->isReadOnly() && mChanger->beginChange( todo, 0, TQString() ) ) {
Todo *oldTodo = todo->clone();
TQDateTime dt;
dt.setDate( date );
- if ( !todo->doesFloat() )
+ if ( !todo->doesFloat() ) {
dt.setTime( todo->dtDue().time() );
+ }
- if ( date.isNull() )
- todo->setHasDueDate( false );
- else if ( !todo->hasDueDate() )
- todo->setHasDueDate( true );
+ todo->setHasDueDate( !date.isNull() );
todo->setDtDue( dt );
mActiveItem->construct();
- mChanger->changeIncidence( oldTodo, todo, KOGlobals::COMPLETION_MODIFIED );
- mChanger->endChange( todo );
+ mChanger->changeIncidence( oldTodo, todo, KOGlobals::COMPLETION_MODIFIED, this );
+ mChanger->endChange( todo, 0, TQString() );
delete oldTodo;
} else {
kdDebug(5850) << "No active item, active item is read-only, or locking failed" << endl;
@@ -969,19 +979,24 @@ void KOTodoView::copyTodoToDate( TQDate date )
TQDateTime dt( date );
if ( mActiveItem && mChanger ) {
- Todo *newTodo = mActiveItem->todo()->clone();
+ Todo *oldTodo = mActiveItem->todo();
+ Todo *newTodo = oldTodo->clone();
newTodo->recreate();
- newTodo->setHasDueDate( !date.isNull() );
- newTodo->setDtDue( dt );
- newTodo->setPercentComplete( 0 );
+ newTodo->setHasDueDate( !date.isNull() );
+
+ if ( oldTodo->hasDueDate() && !oldTodo->doesFloat() ) {
+ dt.setTime( oldTodo->dtDue().time() );
+ }
+
+ newTodo->setDtDue( dt );
+ newTodo->setPercentComplete( 0 );
- // avoid forking
- if ( newTodo->doesRecur() )
- newTodo->recurrence()->unsetRecurs();
+ QPair<ResourceCalendar *, TQString>p =
+ CalHelper::incSubResourceCalendar( calendar(), mActiveItem->todo() );
- mChanger->addIncidence( newTodo, this );
- }
+ mChanger->addIncidence( newTodo, p.first, p.second, this );
+ }
}
TQPopupMenu *KOTodoView::getCategoryPopupMenu( KOTodoViewItem *todoItem )
@@ -1011,7 +1026,7 @@ void KOTodoView::changedCategories(int index)
Todo *todo = mActiveItem->todo();
if ( !todo ) return;
- if ( !todo->isReadOnly() && mChanger->beginChange( todo ) ) {
+ if ( !todo->isReadOnly() && mChanger->beginChange( todo, 0, TQString() ) ) {
Todo *oldTodo = todo->clone();
TQStringList categories = todo->categories ();
@@ -1022,8 +1037,8 @@ void KOTodoView::changedCategories(int index)
categories.sort();
todo->setCategories( categories );
mActiveItem->construct();
- mChanger->changeIncidence( oldTodo, todo, KOGlobals::CATEGORY_MODIFIED );
- mChanger->endChange( todo );
+ mChanger->changeIncidence( oldTodo, todo, KOGlobals::CATEGORY_MODIFIED, this );
+ mChanger->endChange( todo, 0, TQString() );
delete oldTodo;
} else {
kdDebug(5850) << "No active item, active item is read-only, or locking failed" << endl;
@@ -1082,9 +1097,13 @@ void KOTodoView::processSelectionChange()
static_cast<KOTodoViewItem *>( mTodoListView->selectedItem() );
if ( !item ) {
- emit incidenceSelected( 0 );
+ emit incidenceSelected( 0, TQDate() );
} else {
- emit incidenceSelected( item->todo() );
+ if ( selectedIncidenceDates().isEmpty() ) {
+ emit incidenceSelected( item->todo(), TQDate() );
+ } else {
+ emit incidenceSelected( item->todo(), selectedIncidenceDates().first() );
+ }
}
}
@@ -1105,8 +1124,7 @@ void KOTodoView::addQuickTodo()
todo->setSummary( mQuickAdd->text() );
todo->setOrganizer( Person( KOPrefs::instance()->fullName(),
KOPrefs::instance()->email() ) );
- if ( !mChanger->addIncidence( todo, this ) ) {
- KODialogManager::errorSaveIncidence( this, todo );
+ if ( !mChanger->addIncidence( todo, 0, TQString(), this ) ) {
delete todo;
return;
}
diff --git a/korganizer/kotodoview.h b/korganizer/kotodoview.h
index 7deaafded..bc7302d34 100644
--- a/korganizer/kotodoview.h
+++ b/korganizer/kotodoview.h
@@ -58,12 +58,13 @@ using namespace KOrg;
class KOTodoListViewToolTip : public QToolTip
{
public:
- KOTodoListViewToolTip( TQWidget *parent, KOTodoListView *lv );
+ KOTodoListViewToolTip( TQWidget *parent, Calendar *calendar, KOTodoListView *lv );
protected:
void maybeTip( const TQPoint &pos );
private:
+ Calendar *mCalendar;
KOTodoListView *todolist;
};
@@ -99,7 +100,6 @@ class KOTodoListView : public KListView
TQPoint mPressPos;
bool mMousePressed;
TQListViewItem *mOldCurrent;
- KOTodoListViewToolTip *tooltip;
};
@@ -121,7 +121,7 @@ class KOTodoView : public KOrg::BaseView
Incidence::List selectedIncidences();
Todo::List selectedTodos();
- DateList selectedDates() { return DateList(); }
+ DateList selectedIncidenceDates() { return DateList(); }
/** Return number of shown dates. TodoView does not show dates, */
int currentDateCount() { return 0; }
@@ -143,7 +143,7 @@ class KOTodoView : public KOrg::BaseView
void changeIncidenceDisplay( Incidence *, int );
void showDates( const TQDate &start, const TQDate &end );
- void showIncidences( const Incidence::List &incidenceList );
+ void showIncidences( const Incidence::List &incidenceList, const TQDate &date );
void clearSelection();
@@ -177,8 +177,8 @@ class KOTodoView : public KOrg::BaseView
signals:
void unSubTodoSignal();
void unAllSubTodoSignal();
-
void purgeCompletedSignal();
+ void configChanged();
protected slots:
void processSelectionChange();
@@ -232,7 +232,7 @@ class KOTodoView : public KOrg::BaseView
ePercentColumn = 3,
eDueDateColumn = 4,
eCategoriesColumn = 5,
- eDescriptionColumn = 6
+ eFolderColumn = 6
};
enum {
ePopupEdit = 1300,
diff --git a/korganizer/kotodoviewitem.cpp b/korganizer/kotodoviewitem.cpp
index 7e5541fa3..f5b0adced 100644
--- a/korganizer/kotodoviewitem.cpp
+++ b/korganizer/kotodoviewitem.cpp
@@ -24,17 +24,19 @@
without including the source code for Qt in the source distribution.
*/
-#include <tqpainter.h>
+#include "kotodoviewitem.h"
+#include "kotodoview.h"
+#include "koprefs.h"
+#include "koglobals.h"
+
+#include <libkcal/incidenceformatter.h>
#include <klocale.h>
#include <kdebug.h>
#include <tqpainter.h>
#include <tqpixmap.h>
-#include "kotodoviewitem.h"
-#include "kotodoview.h"
-#include "koprefs.h"
-#include "koglobals.h"
+#include <tqpainter.h>
KOTodoViewItem::KOTodoViewItem( TQListView *parent, Todo *todo, KOTodoView *kotodo)
: TQCheckListItem( parent , "", CheckBox ), mTodo( todo ), mTodoView( kotodo )
@@ -50,7 +52,7 @@ KOTodoViewItem::KOTodoViewItem( KOTodoViewItem *parent, Todo *todo, KOTodoView *
inline int KOTodoViewItem::compareDueDates( const KOTodoViewItem *b ) const
{
- if ( mEffectiveDueDate.isValid() &&
+ if ( mEffectiveDueDate.isValid() &&
!b->mEffectiveDueDate.isValid() )
return -1;
else if ( !mEffectiveDueDate.isValid() &&
@@ -63,41 +65,57 @@ inline int KOTodoViewItem::compareDueDates( const KOTodoViewItem *b ) const
int KOTodoViewItem::compare( TQListViewItem *it, int col, bool ascending ) const
{
KOTodoViewItem *i = dynamic_cast<KOTodoViewItem *>( it );
- if ( !i )
+ if ( !i ) {
return TQListViewItem::compare( it, col, ascending );
-
+ }
+
// throw completed todos to the bottom
- if ( mTodo->isCompleted() && !i->todo()->isCompleted() )
+ if ( mTodo->isCompleted() && !i->todo()->isCompleted() ) {
return ascending ? 1 : -1;
- else if ( !mTodo->isCompleted() && i->todo()->isCompleted() )
+ } else if ( !mTodo->isCompleted() && i->todo()->isCompleted() ) {
return ascending ? -1 : 1;
-
+ }
+
int c;
switch ( col ) {
- case ( KOTodoView::eSummaryColumn ):
- return mTodo->summary().localeAwareCompare( i->todo()->summary() );
- case ( KOTodoView::eRecurColumn ):
- return ( mTodo->doesRecur() ? 1 : 0 ) - (i->todo()->doesRecur() ? 1 : 0 );
- case ( KOTodoView::ePriorityColumn ):
- c = mTodo->priority() - i->todo()->priority();
- if ( c )
- return c;
+ case KOTodoView::eSummaryColumn:
+ return mTodo->summary().localeAwareCompare( i->todo()->summary() );
+
+ case KOTodoView::eRecurColumn:
+ return ( mTodo->doesRecur() ? 1 : 0 ) - ( i->todo()->doesRecur() ? 1 : 0 );
+
+ case KOTodoView::ePriorityColumn:
+ c = mTodo->priority() - i->todo()->priority();
+ if ( c ) {
+ return c;
+ } else {
return compareDueDates( i );
- case ( KOTodoView::ePercentColumn ):
- return mTodo->percentComplete() - i->todo()->percentComplete();
- case ( KOTodoView::eDueDateColumn ):
- c = compareDueDates( i );
- if ( c )
- return c;
+ }
+
+ case KOTodoView::ePercentColumn:
+ return mTodo->percentComplete() - i->todo()->percentComplete();
+
+ case KOTodoView::eDueDateColumn:
+ c = compareDueDates( i );
+ if ( c ) {
+ return c;
+ } else {
return mTodo->priority() - i->todo()->priority();
- case ( KOTodoView::eCategoriesColumn ):
- return mTodo->categoriesStr().localeAwareCompare(
- i->todo()->categoriesStr() );
- case ( KOTodoView::eDescriptionColumn ):
- return mTodo->description().localeAwareCompare( i->todo()->description() );
- default:
- Q_ASSERT( false && "unknown column to compare" );
- return TQListViewItem::compare( it, col, ascending );
+ }
+ case KOTodoView::eCategoriesColumn:
+ return mTodo->categoriesStr().localeAwareCompare( i->todo()->categoriesStr() );
+
+ case KOTodoView::eFolderColumn:
+ return TQListViewItem::compare( it, col, ascending );
+
+#if 0
+ case KOTodoView::eDescriptionColumn:
+ return mTodo->description().localeAwareCompare( i->todo()->description() );
+#endif
+
+ default:
+ Q_ASSERT( false && "unknown column to compare" );
+ return TQListViewItem::compare( it, col, ascending );
}
}
@@ -120,14 +138,14 @@ void KOTodoViewItem::construct()
static const TQPixmap recurPxmp = KOGlobals::self()->smallIcon("recur");
if ( mTodo->doesRecur() )
setPixmap( KOTodoView::eRecurColumn, recurPxmp );
-
+
if ( mTodo->priority()==0 ) {
setText( KOTodoView::ePriorityColumn, i18n("--") );
} else {
setText( KOTodoView::ePriorityColumn, TQString::number(mTodo->priority()) );
}
setText( KOTodoView::ePercentColumn, TQString::number(mTodo->percentComplete()) );
-
+
if (mTodo->hasDueDate()) {
TQString dtStr = mTodo->dtDueDateStr();
if (!mTodo->doesFloat()) {
@@ -143,9 +161,12 @@ void KOTodoViewItem::construct()
}
} else
setText( KOTodoView::eDueDateColumn, "" );
-
+
setText( KOTodoView::eCategoriesColumn, mTodo->categoriesStr() );
+ setText( KOTodoView::eFolderColumn,
+ IncidenceFormatter::resourceString( mTodoView->calendar(), mTodo ) );
+
#if 0
// Find sort id in description. It's the text behind the last '#' character
// found in the description. White spaces are removed from beginning and end
@@ -173,7 +194,7 @@ void KOTodoViewItem::stateChange( bool state )
setOn( mTodo->isCompleted() );
return;
}
-
+
kdDebug(5850) << "State changed, modified " << state << endl;
mTodoView->setNewPercentageDelayed( this, state ? 100 : 0 );
}
diff --git a/korganizer/koviewmanager.cpp b/korganizer/koviewmanager.cpp
index f086e1924..1906a07ee 100644
--- a/korganizer/koviewmanager.cpp
+++ b/korganizer/koviewmanager.cpp
@@ -26,9 +26,12 @@
#include <tqwidgetstack.h>
#include <tqtabwidget.h>
+#include <libkcal/calendarresources.h>
+#include <kactioncollection.h>
#include <kconfig.h>
#include <kglobal.h>
+#include "actionmanager.h"
#include "calendarview.h"
#include "datenavigator.h"
#include "kotodoview.h"
@@ -42,6 +45,7 @@
#include "koglobals.h"
#include "navigatorbar.h"
#include "multiagendaview.h"
+#include <korganizer/mainwindow.h>
#include "koviewmanager.h"
#include "koviewmanager.moc"
@@ -62,6 +66,8 @@ KOViewManager::KOViewManager( CalendarView *mainView ) :
mJournalView = 0;
mTimelineView = 0;
mAgendaViewTabs = 0;
+ mAgendaViewTabIndex = 0;
+ mAgendaMode = AGENDA_NONE;
}
KOViewManager::~KOViewManager()
@@ -85,7 +91,29 @@ void KOViewManager::readSettings(KConfig *config)
else if (view == "Journal") showJournalView();
else if (view == "Todo") showTodoView();
else if (view == "Timeline") showTimelineView();
- else showAgendaView();
+ else {
+ mAgendaMode = AgendaMode( config->readNumEntry( "Agenda Mode", AGENDA_OTHER ) );
+
+ switch ( mAgendaMode ) {
+ case AGENDA_WORK_WEEK:
+ showWorkWeekView();
+ break;
+ case AGENDA_WEEK:
+ showWeekView();
+ break;
+ case AGENDA_NEXTX:
+ showNextXView();
+ break;
+ case AGENDA_DAY:
+ showDayView();
+ break;
+ case AGENDA_NONE:
+ // Someone has been playing with the config file.
+ default:
+ mAgendaMode = AGENDA_OTHER;
+ showAgendaView();
+ }
+ }
}
void KOViewManager::writeSettings(KConfig *config)
@@ -99,7 +127,10 @@ void KOViewManager::writeSettings(KConfig *config)
else if (mCurrentView == mJournalView) view = "Journal";
else if (mCurrentView == mTodoView) view = "Todo";
else if (mCurrentView == mTimelineView) view = "Timeline";
- else view = "Agenda";
+ else {
+ view = "Agenda";
+ config->writeEntry( "Agenda Mode", mAgendaMode );
+ }
config->writeEntry("Current View",view);
@@ -127,13 +158,37 @@ void KOViewManager::showView(KOrg::BaseView *view)
if ( mAgendaView ) mAgendaView->deleteSelectedDateTime();
raiseCurrentView();
- mMainView->processIncidenceSelection( 0 );
+
+ mMainView->processIncidenceSelection( 0, TQDate() );
mMainView->updateView();
mMainView->adaptNavigationUnits();
}
+void KOViewManager::goMenu( bool enable )
+{
+ KOrg::MainWindow *w = ActionManager::findInstance( KURL() );
+ if ( w ) {
+ KActionCollection *ac = w->getActionCollection();
+ if ( ac ) {
+ KAction *action;
+ action = ac->action( "go_today" );
+ if ( action ) {
+ action->setEnabled( enable );
+ }
+ action = ac->action( "go_previous" );
+ if ( action ) {
+ action->setEnabled( enable );
+ }
+ action = ac->action( "go_next" );
+ if ( action ) {
+ action->setEnabled( enable );
+ }
+ }
+ }
+}
+
void KOViewManager::raiseCurrentView()
{
if ((mMonthView && KOPrefs::instance()->mFullViewMonth && mCurrentView == mMonthView) ||
@@ -170,44 +225,46 @@ void KOViewManager::connectView(KOrg::BaseView *view)
if (!view) return;
// selecting an incidence
- connect( view, TQT_SIGNAL( incidenceSelected( Incidence * ) ),
- mMainView, TQT_SLOT( processMainViewSelection( Incidence * ) ) );
+ connect( view, TQT_SIGNAL( incidenceSelected( Incidence *,const TQDate & ) ),
+ mMainView, TQT_SLOT( processMainViewSelection( Incidence *,const TQDate & ) ) );
// showing/editing/deleting an incidence. The calendar view takes care of the action.
- connect(view, TQT_SIGNAL(showIncidenceSignal(Incidence *)),
- mMainView, TQT_SLOT(showIncidence(Incidence *)));
- connect(view, TQT_SIGNAL(editIncidenceSignal(Incidence *)),
- mMainView, TQT_SLOT(editIncidence(Incidence *)));
- connect(view, TQT_SIGNAL(deleteIncidenceSignal(Incidence *)),
- mMainView, TQT_SLOT(deleteIncidence(Incidence *)));
- connect(view, TQT_SIGNAL(copyIncidenceSignal(Incidence *)),
- mMainView, TQT_SLOT(copyIncidence(Incidence *)));
- connect(view, TQT_SIGNAL(cutIncidenceSignal(Incidence *)),
- mMainView, TQT_SLOT(cutIncidence(Incidence *)));
- connect(view, TQT_SIGNAL(pasteIncidenceSignal()),
- mMainView, TQT_SLOT(pasteIncidence()));
- connect(view, TQT_SIGNAL(toggleAlarmSignal(Incidence *)),
- mMainView, TQT_SLOT(toggleAlarm(Incidence *)));
- connect(view,TQT_SIGNAL(dissociateOccurrenceSignal( Incidence *, const TQDate & )),
- mMainView, TQT_SLOT(dissociateOccurrence( Incidence *, const TQDate & )));
- connect(view,TQT_SIGNAL(dissociateFutureOccurrenceSignal( Incidence *, const TQDate & )),
- mMainView, TQT_SLOT(dissociateFutureOccurrence( Incidence *, const TQDate & )));
+ connect( view, TQT_SIGNAL(showIncidenceSignal(Incidence *,const TQDate &)),
+ mMainView, TQT_SLOT(showIncidence(Incidence *,const TQDate &)) );
+ connect( view, TQT_SIGNAL(editIncidenceSignal(Incidence *,const TQDate &)),
+ mMainView, TQT_SLOT(editIncidence(Incidence *,const TQDate &)) );
+ connect( view, TQT_SIGNAL(deleteIncidenceSignal(Incidence *)),
+ mMainView, TQT_SLOT(deleteIncidence(Incidence *)) );
+ connect( view, TQT_SIGNAL(copyIncidenceSignal(Incidence *)),
+ mMainView, TQT_SLOT(copyIncidence(Incidence *)) );
+ connect( view, TQT_SIGNAL(cutIncidenceSignal(Incidence *)),
+ mMainView, TQT_SLOT(cutIncidence(Incidence *)) );
+ connect( view, TQT_SIGNAL(pasteIncidenceSignal()),
+ mMainView, TQT_SLOT(pasteIncidence()));
+ connect( view, TQT_SIGNAL(toggleAlarmSignal(Incidence *)),
+ mMainView, TQT_SLOT(toggleAlarm(Incidence *)) );
+ connect( view,TQT_SIGNAL(dissociateOccurrenceSignal(Incidence *,const TQDate &)),
+ mMainView, TQT_SLOT(dissociateOccurrence(Incidence *,const TQDate &)) );
+ connect( view,TQT_SIGNAL(dissociateFutureOccurrenceSignal(Incidence *,const TQDate &)),
+ mMainView, TQT_SLOT(dissociateFutureOccurrence(Incidence *,const TQDate &)) );
// signals to create new incidences
- connect( view, TQT_SIGNAL( newEventSignal() ),
- mMainView, TQT_SLOT( newEvent() ) );
- connect( view, TQT_SIGNAL( newEventSignal( const TQDateTime & ) ),
- mMainView, TQT_SLOT( newEvent( const TQDateTime & ) ) );
- connect( view, TQT_SIGNAL( newEventSignal( const TQDateTime &, const TQDateTime & ) ),
- mMainView, TQT_SLOT( newEvent( const TQDateTime &, const TQDateTime & ) ) );
- connect( view, TQT_SIGNAL( newEventSignal( const TQDate & ) ),
- mMainView, TQT_SLOT( newEvent( const TQDate & ) ) );
- connect( view, TQT_SIGNAL( newTodoSignal( const TQDate & ) ),
- mMainView, TQT_SLOT( newTodo( const TQDate & ) ) );
- connect( view, TQT_SIGNAL( newSubTodoSignal( Todo * ) ),
- mMainView, TQT_SLOT( newSubTodo( Todo *) ) );
- connect( view, TQT_SIGNAL( newJournalSignal( const TQDate & ) ),
- mMainView, TQT_SLOT( newJournal( const TQDate & ) ) );
+ connect( view, TQT_SIGNAL(newEventSignal(ResourceCalendar *,const TQString &)),
+ mMainView, TQT_SLOT(newEvent(ResourceCalendar *,const TQString &)) );
+ connect( view, TQT_SIGNAL(newEventSignal(ResourceCalendar *,const TQString &,const TQDate &)),
+ mMainView, TQT_SLOT(newEvent(ResourceCalendar *,const TQString &,const TQDate &)) );
+ connect( view, TQT_SIGNAL(newEventSignal(ResourceCalendar *,const TQString &,const TQDateTime &)),
+ mMainView, TQT_SLOT(newEvent(ResourceCalendar *,const TQString &,const TQDateTime &)) );
+ connect( view, TQT_SIGNAL(newEventSignal(ResourceCalendar *,const TQString &,const TQDateTime &,const TQDateTime &)),
+ mMainView, TQT_SLOT(newEvent(ResourceCalendar *,const TQString &,const TQDateTime &,const TQDateTime &)) );
+
+ connect( view, TQT_SIGNAL(newTodoSignal(ResourceCalendar *,const TQString &,const TQDate &)),
+ mMainView, TQT_SLOT(newTodo(ResourceCalendar *,const TQString &,const TQDate &)) );
+ connect( view, TQT_SIGNAL(newSubTodoSignal(Todo *)),
+ mMainView, TQT_SLOT(newSubTodo(Todo *)) );
+
+ connect( view, TQT_SIGNAL(newJournalSignal(ResourceCalendar *,const TQString &,const TQDate &)),
+ mMainView, TQT_SLOT(newJournal(ResourceCalendar *,const TQString &,const TQDate &)) );
// reload settings
connect(mMainView, TQT_SIGNAL(configChanged()), view, TQT_SLOT(updateConfig()));
@@ -235,7 +292,7 @@ void KOViewManager::connectTodoView( KOTodoView* todoView )
connect( todoView, TQT_SIGNAL( unSubTodoSignal() ),
mMainView, TQT_SLOT( todo_unsub() ) );
connect( todoView, TQT_SIGNAL( unAllSubTodoSignal() ),
- mMainView, TQT_SLOT( makeSubTodosIndependents() ) );
+ mMainView, TQT_SLOT( makeSubTodosIndependent() ) );
}
void KOViewManager::zoomInHorizontally()
@@ -272,6 +329,7 @@ void KOViewManager::showWhatsNextView()
"KOViewManager::WhatsNextView");
addView(mWhatsNextView);
}
+ goMenu( true );
showView(mWhatsNextView);
}
@@ -281,14 +339,24 @@ void KOViewManager::showListView()
mListView = new KOListView(mMainView->calendar(), mMainView->viewStack(), "KOViewManager::ListView");
addView(mListView);
}
+ goMenu( true );
showView(mListView);
}
void KOViewManager::showAgendaView()
{
- const bool showBoth = KOPrefs::instance()->agendaViewCalendarDisplay() == KOPrefs::AllCalendarViews;
- const bool showMerged = showBoth || KOPrefs::instance()->agendaViewCalendarDisplay() == KOPrefs::CalendarsMerged;
- const bool showSideBySide = showBoth || KOPrefs::instance()->agendaViewCalendarDisplay() == KOPrefs::CalendarsSideBySide;
+ // If the user opens a local file, through menu->open ( for example ), then
+ // it doesn't make sense to use multiagenda.
+ CalendarResources *calres = dynamic_cast<CalendarResources*>( mMainView->calendar() );
+ bool isLocalFile = !calres;
+
+ int mode = KOPrefs::instance()->agendaViewCalendarDisplay();
+
+ const bool showBoth = ( mode == KOPrefs::AllCalendarViews && !isLocalFile );
+
+ const bool showMerged = showBoth || mode == KOPrefs::CalendarsMerged || isLocalFile;
+
+ const bool showSideBySide = !isLocalFile && ( showBoth || mode == KOPrefs::CalendarsSideBySide );
TQWidget *parent = mMainView->viewStack();
if ( !mAgendaViewTabs && showBoth ) {
@@ -296,10 +364,17 @@ void KOViewManager::showAgendaView()
connect( mAgendaViewTabs, TQT_SIGNAL( currentChanged( TQWidget* ) ),
this, TQT_SLOT( currentAgendaViewTabChanged( TQWidget* ) ) );
parent = mAgendaViewTabs;
+
+ KConfig *config = KOGlobals::self()->config();
+ config->setGroup( "Views" );
+ mAgendaViewTabIndex = config->readNumEntry( "Agenda View Tab Index", 0 );
}
if ( !mAgendaView && showMerged ) {
- mAgendaView = new KOAgendaView(mMainView->calendar(), parent, "KOViewManager::AgendaView");
+ mAgendaView = new KOAgendaView( mMainView->calendar(),
+ mMainView,
+ parent,
+ "KOViewManager::AgendaView" );
addView(mAgendaView);
@@ -315,7 +390,7 @@ void KOViewManager::showAgendaView()
if ( !mAgendaSideBySideView && showSideBySide ) {
mAgendaSideBySideView =
- new MultiAgendaView( mMainView->calendar(), parent,
+ new MultiAgendaView( mMainView->calendar(), mMainView, parent,
"KOViewManager::AgendaSideBySideView" );
addView(mAgendaSideBySideView);
@@ -332,8 +407,9 @@ void KOViewManager::showAgendaView()
if ( showBoth && mAgendaViewTabs ) {
if ( mAgendaView && mAgendaViewTabs->indexOf( mAgendaView ) < 0 )
mAgendaViewTabs->addTab( mAgendaView, i18n("Merged calendar") );
- if ( mAgendaSideBySideView && mAgendaViewTabs->indexOf( mAgendaSideBySideView ) < 0 )
+ if ( mAgendaSideBySideView && mAgendaViewTabs->indexOf( mAgendaSideBySideView ) < 0 )
mAgendaViewTabs->addTab( mAgendaSideBySideView, i18n("Calendars Side by Side") );
+ mAgendaViewTabs->setCurrentPage( mAgendaViewTabIndex );
} else {
if ( mAgendaView && mMainView->viewStack()->id( mAgendaView ) < 0 )
mMainView->viewStack()->addWidget( mAgendaView );
@@ -341,6 +417,7 @@ void KOViewManager::showAgendaView()
mMainView->viewStack()->addWidget( mAgendaSideBySideView );
}
+ goMenu( true );
if ( mAgendaViewTabs && showBoth )
showView( static_cast<KOrg::BaseView*>( mAgendaViewTabs->currentPage() ) );
else if ( mAgendaView && showMerged )
@@ -351,24 +428,28 @@ void KOViewManager::showAgendaView()
void KOViewManager::showDayView()
{
+ mAgendaMode = AGENDA_DAY;
showAgendaView();
mMainView->dateNavigator()->selectDates( 1 );
}
void KOViewManager::showWorkWeekView()
{
+ mAgendaMode = AGENDA_WORK_WEEK;
showAgendaView();
mMainView->dateNavigator()->selectWorkWeek();
}
void KOViewManager::showWeekView()
{
+ mAgendaMode = AGENDA_WEEK;
showAgendaView();
mMainView->dateNavigator()->selectWeek();
}
void KOViewManager::showNextXView()
{
+ mAgendaMode = AGENDA_NEXTX;
showAgendaView();
mMainView->dateNavigator()->selectDates( TQDate::currentDate(),
KOPrefs::instance()->mNextXDays );
@@ -381,6 +462,7 @@ void KOViewManager::showMonthView()
addView(mMonthView);
}
+ goMenu( true );
showView(mMonthView);
}
@@ -397,6 +479,7 @@ void KOViewManager::showTodoView()
mTodoView->restoreLayout( config, "Todo View" );
}
+ goMenu( false );
showView( mTodoView );
}
@@ -408,6 +491,7 @@ void KOViewManager::showJournalView()
addView(mJournalView);
}
+ goMenu( true );
showView(mJournalView);
}
@@ -419,13 +503,18 @@ void KOViewManager::showTimelineView()
"KOViewManager::TimelineView");
addView(mTimelineView);
}
+ goMenu( true );
showView(mTimelineView);
}
void KOViewManager::showEventView()
{
- if ( mLastEventView ) showView( mLastEventView );
- else showWeekView();
+ if ( mLastEventView ) {
+ goMenu( true );
+ showView( mLastEventView );
+ } else {
+ showWeekView();
+ }
}
Incidence *KOViewManager::currentSelection()
@@ -441,7 +530,7 @@ TQDate KOViewManager::currentSelectionDate()
{
TQDate qd;
if (mCurrentView) {
- DateList qvl = mCurrentView->selectedDates();
+ DateList qvl = mCurrentView->selectedIncidenceDates();
if (!qvl.isEmpty()) qd = qvl.first();
}
return qd;
@@ -465,6 +554,11 @@ TQWidget* KOViewManager::widgetForView( KOrg::BaseView* view ) const
void KOViewManager::currentAgendaViewTabChanged( TQWidget* widget )
{
+ KConfig *config = KOGlobals::self()->config();
+ config->setGroup( "Views" );
+ config->writeEntry( "Agenda View Tab Index", mAgendaViewTabs->currentPageIndex() );
+
+ goMenu( true );
showView( static_cast<KOrg::BaseView*>( widget ) );
}
@@ -475,3 +569,19 @@ void KOViewManager::resourcesChanged()
if ( mAgendaSideBySideView )
mAgendaSideBySideView->resourcesChanged();
}
+
+void KOViewManager::updateMultiCalendarDisplay()
+{
+ if ( agendaIsSelected() ) {
+ showAgendaView();
+ } else {
+ updateView();
+ }
+}
+
+bool KOViewManager::agendaIsSelected() const
+{
+ return mCurrentView == mAgendaView ||
+ mCurrentView == mAgendaSideBySideView ||
+ ( mAgendaViewTabs && mCurrentView == mAgendaViewTabs->currentPage() );
+}
diff --git a/korganizer/koviewmanager.h b/korganizer/koviewmanager.h
index 32c55c3d4..9fe521e4f 100644
--- a/korganizer/koviewmanager.h
+++ b/korganizer/koviewmanager.h
@@ -53,6 +53,16 @@ class KOViewManager : public QObject
{
Q_OBJECT
public:
+
+ enum AgendaMode {
+ AGENDA_NONE,
+ AGENDA_DAY,
+ AGENDA_WORK_WEEK,
+ AGENDA_WEEK,
+ AGENDA_NEXTX,
+ AGENDA_OTHER // for example, showing 8 days
+ };
+
KOViewManager( CalendarView * );
virtual ~KOViewManager();
@@ -74,6 +84,7 @@ class KOViewManager : public QObject
void updateView();
void updateView( const TQDate &start, const TQDate &end );
+ void goMenu( bool enable );
void raiseCurrentView();
void connectView( KOrg::BaseView * );
@@ -84,7 +95,25 @@ class KOViewManager : public QObject
KOAgendaView *agendaView() const { return mAgendaView; }
KOrg::MultiAgendaView *multiAgendaView() const { return mAgendaSideBySideView; }
- KOTodoView *todoView() const { return mTodoView; }
+ KOTodoView *todoView() const { return mTodoView; }
+ KOMonthView *monthView() const { return mMonthView; }
+
+ void updateMultiCalendarDisplay();
+
+ /*
+ * Returns true if the agenda is the current view.
+ *
+ * Never use the pointer returned by agendaView()
+ * to know if agenda is selected, because agenda has other modes
+ * (tabbed, side by side). Use this function instead.
+ */
+ bool agendaIsSelected() const;
+
+ /**
+ If the agenda view is selected it returns the current range mode:
+ week, work week, day or nextX days
+ */
+ AgendaMode agendaMode() const { return mAgendaMode; }
public slots:
void showWhatsNextView();
@@ -129,6 +158,10 @@ class KOViewManager : public QObject
KOrg::BaseView *mLastEventView;
TQTabWidget *mAgendaViewTabs;
+ int mAgendaViewTabIndex;
+
+ AgendaMode mAgendaMode;
+
};
#endif
diff --git a/korganizer/kowhatsnextview.cpp b/korganizer/kowhatsnextview.cpp
index 351972199..884b70b22 100644
--- a/korganizer/kowhatsnextview.cpp
+++ b/korganizer/kowhatsnextview.cpp
@@ -35,6 +35,7 @@
#include <kmessagebox.h>
#include <libkcal/calendar.h>
+#include <libkcal/incidenceformatter.h>
#include "koglobals.h"
#include "koprefs.h"
@@ -244,7 +245,7 @@ void KOWhatsNextView::showDates( const TQDate &start, const TQDate &end )
updateView();
}
-void KOWhatsNextView::showIncidences( const Incidence::List & )
+void KOWhatsNextView::showIncidences( const Incidence::List &, const TQDate & )
{
}
@@ -312,8 +313,8 @@ void KOWhatsNextView::appendTodo( Incidence *ev )
if ( ev->type()=="Todo" ) {
Todo *todo = static_cast<Todo*>(ev);
if ( todo->hasDueDate() ) {
- mText += i18n(" (Due: %1)")
- .arg( (todo->doesFloat())?(todo->dtDueDateStr()):(todo->dtDueStr()) );
+ mText += i18n( " (Due: %1)" ).
+ arg( IncidenceFormatter::dateTimeToString( todo->dtDue(), todo->doesFloat() ) );
}
}
mText += "</li>\n";
@@ -329,7 +330,9 @@ void KOWhatsNextView::showIncidence( const TQString &uid )
} else if ( uid.startsWith( "todo://" ) ) {
incidence = calendar()->incidence( uid.mid( 7 ) );
}
- if ( incidence ) emit showIncidenceSignal( incidence );
+ if ( incidence ) {
+ emit showIncidenceSignal( incidence, TQDate() );
+ }
}
#include "kowhatsnextview.moc"
diff --git a/korganizer/kowhatsnextview.h b/korganizer/kowhatsnextview.h
index 6f49ab2b1..69c6a62eb 100644
--- a/korganizer/kowhatsnextview.h
+++ b/korganizer/kowhatsnextview.h
@@ -57,17 +57,19 @@ class KOWhatsNextView : public KOrg::BaseView
virtual int currentDateCount();
virtual Incidence::List selectedIncidences() { return Incidence::List(); }
- DateList selectedDates() { return DateList(); }
+ DateList selectedIncidenceDates() { return DateList(); }
+
+ bool supportsDateNavigation() const { return true; }
public slots:
virtual void updateView();
virtual void showDates(const TQDate &start, const TQDate &end);
- virtual void showIncidences( const Incidence::List &incidenceList );
+ virtual void showIncidences( const Incidence::List &incidenceList, const TQDate &date );
void changeIncidenceDisplay(Incidence *, int);
protected:
- void appendEvent( Incidence *, const TQDateTime &start = TQDateTime(),
+ void appendEvent( Incidence *, const TQDateTime &start = TQDateTime(),
const TQDateTime &end = TQDateTime() );
void appendTodo( Incidence * );
diff --git a/korganizer/multiagendaview.cpp b/korganizer/multiagendaview.cpp
index fb5cd6255..a6aa51665 100644
--- a/korganizer/multiagendaview.cpp
+++ b/korganizer/multiagendaview.cpp
@@ -30,6 +30,7 @@
#include <tqlayout.h>
#include <tqvbox.h>
#include <tqobjectlist.h>
+#include <tqheader.h>
#define FOREACH_VIEW(av) \
for(TQValueList<KOAgendaView*>::ConstIterator it = mAgendaViews.constBegin(); \
@@ -39,20 +40,23 @@ for(TQValueList<KOAgendaView*>::ConstIterator it = mAgendaViews.constBegin(); \
using namespace KOrg;
-MultiAgendaView::MultiAgendaView(Calendar * cal, TQWidget * parent, const char *name ) :
+MultiAgendaView::MultiAgendaView( Calendar * cal, CalendarView *calendarView,
+ TQWidget * parent, const char *name ) :
AgendaView( cal, parent, name ),
+ mSelectedAgendaView( 0 ),
mLastMovedSplitter( 0 ),
mUpdateOnShow( false ),
- mPendingChanges( true )
+ mPendingChanges( true ),
+ mCalendarView( calendarView )
{
TQBoxLayout *topLevelLayout = new TQHBoxLayout( this );
TQFontMetrics fm( font() );
- int topLabelHeight = 2 * fm.height();
+ int topLabelHeight = 2 * fm.height() + fm.lineSpacing();
TQVBox *topSideBox = new TQVBox( this );
- TQWidget *topSideSpacer = new TQWidget( topSideBox );
- topSideSpacer->setFixedHeight( topLabelHeight );
+ mLeftTopSpacer = new TQWidget( topSideBox );
+ mLeftTopSpacer->setFixedHeight( topLabelHeight );
mLeftSplitter = new TQSplitter( Qt::Vertical, topSideBox );
mLeftSplitter->setOpaqueResize( KGlobalSettings::opaqueResize() );
TQLabel *label = new TQLabel( i18n("All Day"), mLeftSplitter );
@@ -75,8 +79,8 @@ MultiAgendaView::MultiAgendaView(Calendar * cal, TQWidget * parent, const char *
mScrollView->addChild( mTopBox );
topSideBox = new TQVBox( this );
- topSideSpacer = new TQWidget( topSideBox );
- topSideSpacer->setFixedHeight( topLabelHeight );
+ mRightTopSpacer = new TQWidget( topSideBox );
+ mRightTopSpacer->setFixedHeight( topLabelHeight );
mRightSplitter = new TQSplitter( Qt::Vertical, topSideBox );
mRightSplitter->setOpaqueResize( KGlobalSettings::opaqueResize() );
new TQWidget( mRightSplitter );
@@ -96,8 +100,10 @@ MultiAgendaView::MultiAgendaView(Calendar * cal, TQWidget * parent, const char *
void MultiAgendaView::recreateViews()
{
- if ( !mPendingChanges )
+ if ( !mPendingChanges ) {
return;
+ }
+
mPendingChanges = false;
deleteViews();
@@ -105,9 +111,10 @@ void MultiAgendaView::recreateViews()
CalendarResources *calres = dynamic_cast<CalendarResources*>( calendar() );
if ( !calres ) {
// fallback to single-agenda
- KOAgendaView* av = new KOAgendaView( calendar(), mTopBox );
+ KOAgendaView* av = new KOAgendaView( calendar(), mCalendarView, mTopBox );
mAgendaViews.append( av );
mAgendaWidgets.append( av );
+ mSelectedAgendaView = av;
av->show();
} else {
CalendarResourceManager *manager = calres->resourceManager();
@@ -116,8 +123,11 @@ void MultiAgendaView::recreateViews()
TQStringList subResources = (*it)->subresources();
for ( TQStringList::ConstIterator subit = subResources.constBegin(); subit != subResources.constEnd(); ++subit ) {
TQString type = (*it)->subresourceType( *subit );
- if ( !(*it)->subresourceActive( *subit ) || (!type.isEmpty() && type != "event") )
+
+ if ( !(*it)->subresourceActive( *subit ) || (!type.isEmpty() && type != "event") ) {
continue;
+ }
+
addView( (*it)->labelForSubresource( *subit ), *it, *subit );
}
} else {
@@ -127,19 +137,14 @@ void MultiAgendaView::recreateViews()
}
// no resources activated, so stop here to avoid crashing somewhere down the line, TODO: show a nice message instead
- if ( mAgendaViews.isEmpty() )
+ if ( mAgendaViews.isEmpty() ) {
return;
+ }
setupViews();
TQTimer::singleShot( 0, this, TQT_SLOT(slotResizeScrollView()) );
mTimeLabels->updateConfig();
- TQScrollBar *scrollBar = mAgendaViews.first()->agenda()->verticalScrollBar();
- mScrollBar->setMinValue( scrollBar->minValue() );
- mScrollBar->setMaxValue( scrollBar->maxValue() );
- mScrollBar->setLineStep( scrollBar->lineStep() );
- mScrollBar->setPageStep( scrollBar->pageStep() );
- mScrollBar->setValue( scrollBar->value() );
connect( mTimeLabels->verticalScrollBar(), TQT_SIGNAL(valueChanged(int)),
mScrollBar, TQT_SLOT(setValue(int)) );
connect( mScrollBar, TQT_SIGNAL(valueChanged(int)),
@@ -147,7 +152,20 @@ void MultiAgendaView::recreateViews()
installSplitterEventFilter( mLeftSplitter );
installSplitterEventFilter( mRightSplitter );
- resizeSplitters();
+
+ TQValueList<int> sizes = KOGlobals::self()->config()->readIntListEntry( "Separator AgendaView" );
+ if ( sizes.count() != 2 ) {
+ sizes = mLeftSplitter->sizes();
+ }
+ FOREACH_VIEW( agenda ) {
+ agenda->splitter()->setSizes( sizes );
+ }
+ mLeftSplitter->setSizes( sizes );
+ mRightSplitter->setSizes( sizes );
+
+ TQTimer::singleShot( 0, this, TQT_SLOT(setupScrollBar()) );
+
+ mTimeLabels->positionChanged();
}
void MultiAgendaView::deleteViews()
@@ -159,60 +177,88 @@ void MultiAgendaView::deleteViews()
mAgendaViews.clear();
mAgendaWidgets.clear();
mLastMovedSplitter = 0;
+ mSelectedAgendaView = 0;
}
void MultiAgendaView::setupViews()
{
FOREACH_VIEW( agenda ) {
- connect( agenda, TQT_SIGNAL( newEventSignal() ),
- TQT_SIGNAL( newEventSignal() ) );
- connect( agenda, TQT_SIGNAL( editIncidenceSignal( Incidence * ) ),
- TQT_SIGNAL( editIncidenceSignal( Incidence * ) ) );
- connect( agenda, TQT_SIGNAL( showIncidenceSignal( Incidence * ) ),
- TQT_SIGNAL( showIncidenceSignal( Incidence * ) ) );
- connect( agenda, TQT_SIGNAL( deleteIncidenceSignal( Incidence * ) ),
- TQT_SIGNAL( deleteIncidenceSignal( Incidence * ) ) );
- connect( agenda, TQT_SIGNAL( startMultiModify( const TQString & ) ),
- TQT_SIGNAL( startMultiModify( const TQString & ) ) );
- connect( agenda, TQT_SIGNAL( endMultiModify() ),
- TQT_SIGNAL( endMultiModify() ) );
-
- connect( agenda, TQT_SIGNAL( incidenceSelected( Incidence * ) ),
- TQT_SIGNAL( incidenceSelected( Incidence * ) ) );
-
- connect( agenda, TQT_SIGNAL(cutIncidenceSignal(Incidence*)),
- TQT_SIGNAL(cutIncidenceSignal(Incidence*)) );
- connect( agenda, TQT_SIGNAL(copyIncidenceSignal(Incidence*)),
+ if ( !agenda->readOnly() ) {
+ connect( agenda,
+ TQT_SIGNAL(newEventSignal(ResourceCalendar *,const TQString &)),
+ TQT_SIGNAL(newEventSignal(ResourceCalendar *,const TQString &)) );
+ connect( agenda,
+ TQT_SIGNAL(newEventSignal(ResourceCalendar *,const TQString &,const TQDate &)),
+ TQT_SIGNAL(newEventSignal(ResourceCalendar *,const TQString &,const TQDate &)) );
+ connect( agenda,
+ TQT_SIGNAL(newEventSignal(ResourceCalendar *,const TQString &,const TQDateTime &)),
+ TQT_SIGNAL(newEventSignal(ResourceCalendar *,const TQString &,const TQDateTime &)) );
+ connect( agenda,
+ TQT_SIGNAL(newEventSignal(ResourceCalendar *,const TQString &,const TQDateTime &,const TQDateTime &)),
+ TQT_SIGNAL(newEventSignal(ResourceCalendar *,const TQString &,const TQDateTime &,const TQDateTime&)) );
+
+ connect( agenda,
+ TQT_SIGNAL(newTodoSignal(ResourceCalendar *,const TQString &,const TQDate &)),
+ TQT_SIGNAL(newTodoSignal(ResourceCalendar *,const TQString &,const TQDate &)) );
+
+ connect( agenda,
+ TQT_SIGNAL(editIncidenceSignal(Incidence *,const TQDate &)),
+ TQT_SIGNAL(editIncidenceSignal(Incidence *,const TQDate &)) );
+ connect( agenda,
+ TQT_SIGNAL(deleteIncidenceSignal(Incidence *)),
+ TQT_SIGNAL(deleteIncidenceSignal(Incidence *)) );
+ connect( agenda,
+ TQT_SIGNAL(startMultiModify(const TQString &)),
+ TQT_SIGNAL(startMultiModify(const TQString &)) );
+ connect( agenda,
+ TQT_SIGNAL(endMultiModify()),
+ TQT_SIGNAL(endMultiModify()) );
+
+ connect( agenda,
+ TQT_SIGNAL(cutIncidenceSignal(Incidence*)),
+ TQT_SIGNAL(cutIncidenceSignal(Incidence*)) );
+ connect( agenda,
+ TQT_SIGNAL(pasteIncidenceSignal()),
+ TQT_SIGNAL(pasteIncidenceSignal()) );
+ connect( agenda,
+ TQT_SIGNAL(toggleAlarmSignal(Incidence*)),
+ TQT_SIGNAL(toggleAlarmSignal(Incidence*)) );
+ connect( agenda,
+ TQT_SIGNAL(dissociateOccurrenceSignal(Incidence*, const TQDate&)),
+ TQT_SIGNAL(dissociateOccurrenceSignal(Incidence*, const TQDate&)) );
+ connect( agenda,
+ TQT_SIGNAL(dissociateFutureOccurrenceSignal(Incidence*, const TQDate&)),
+ TQT_SIGNAL(dissociateFutureOccurrenceSignal(Incidence*, const TQDate&)) );
+ }
+
+ connect( agenda,
+ TQT_SIGNAL(copyIncidenceSignal(Incidence*)),
TQT_SIGNAL(copyIncidenceSignal(Incidence*)) );
- connect( agenda, TQT_SIGNAL(pasteIncidenceSignal()),
- TQT_SIGNAL(pasteIncidenceSignal()) );
- connect( agenda, TQT_SIGNAL(toggleAlarmSignal(Incidence*)),
- TQT_SIGNAL(toggleAlarmSignal(Incidence*)) );
- connect( agenda, TQT_SIGNAL(dissociateOccurrenceSignal(Incidence*, const TQDate&)),
- TQT_SIGNAL(dissociateOccurrenceSignal(Incidence*, const TQDate&)) );
- connect( agenda, TQT_SIGNAL(dissociateFutureOccurrenceSignal(Incidence*, const TQDate&)),
- TQT_SIGNAL(dissociateFutureOccurrenceSignal(Incidence*, const TQDate&)) );
-
- connect( agenda, TQT_SIGNAL(newEventSignal(const TQDate&)),
- TQT_SIGNAL(newEventSignal(const TQDate&)) );
- connect( agenda, TQT_SIGNAL(newEventSignal(const TQDateTime&)),
- TQT_SIGNAL(newEventSignal(const TQDateTime&)) );
- connect( agenda, TQT_SIGNAL(newEventSignal(const TQDateTime&, const TQDateTime&)),
- TQT_SIGNAL(newEventSignal(const TQDateTime&, const TQDateTime&)) );
- connect( agenda, TQT_SIGNAL(newTodoSignal(const TQDate&)),
- TQT_SIGNAL(newTodoSignal(const TQDate&)) );
-
- connect( agenda, TQT_SIGNAL(incidenceSelected(Incidence*)),
+ connect( agenda,
+ TQT_SIGNAL(showIncidenceSignal(Incidence *,const TQDate &)),
+ TQT_SIGNAL(showIncidenceSignal(Incidence *,const TQDate &)) );
+ connect( agenda,
+ TQT_SIGNAL(incidenceSelected(Incidence *,const TQDate &)),
+ TQT_SIGNAL(incidenceSelected(Incidence *,const TQDate &)) );
+ connect( agenda,
+ TQT_SIGNAL(incidenceSelected(Incidence*,const TQDate &)),
TQT_SLOT(slotSelectionChanged()) );
- connect( agenda, TQT_SIGNAL(timeSpanSelectionChanged()),
+ connect( agenda,
+ TQT_SIGNAL(timeSpanSelectionChanged()),
TQT_SLOT(slotClearTimeSpanSelection()) );
- disconnect( agenda->agenda(), TQT_SIGNAL(zoomView(const int,const TQPoint&,const Qt::Orientation)), agenda, 0 );
- connect( agenda->agenda(), TQT_SIGNAL(zoomView(const int,const TQPoint&,const Qt::Orientation)),
+ disconnect( agenda->agenda(),
+ TQT_SIGNAL(zoomView(const int,const TQPoint&,const Qt::Orientation)),
+ agenda, 0 );
+ connect( agenda->agenda(),
+ TQT_SIGNAL(zoomView(const int,const TQPoint&,const Qt::Orientation)),
TQT_SLOT(zoomView(const int,const TQPoint&,const Qt::Orientation)) );
}
+ KOAgenda *anAgenda = mAgendaViews.first()->agenda();
+ connect( anAgenda, TQT_SIGNAL(lowerYChanged(int) ), TQT_SLOT(resizeSpacers(int)) );
+
FOREACH_VIEW( agenda ) {
agenda->readSettings();
}
@@ -237,11 +283,11 @@ Incidence::List MultiAgendaView::selectedIncidences()
return list;
}
-DateList MultiAgendaView::selectedDates()
+DateList MultiAgendaView::selectedIncidenceDates()
{
DateList list;
FOREACH_VIEW(agendaView) {
- list += agendaView->selectedDates();
+ list += agendaView->selectedIncidenceDates();
}
return list;
}
@@ -262,10 +308,10 @@ void MultiAgendaView::showDates(const TQDate & start, const TQDate & end)
agendaView->showDates( start, end );
}
-void MultiAgendaView::showIncidences(const Incidence::List & incidenceList)
+void MultiAgendaView::showIncidences(const Incidence::List & incidenceList, const TQDate &date)
{
FOREACH_VIEW( agendaView )
- agendaView->showIncidences( incidenceList );
+ agendaView->showIncidences( incidenceList, date );
}
void MultiAgendaView::updateView()
@@ -326,12 +372,35 @@ void MultiAgendaView::finishTypeAhead()
agenda->finishTypeAhead();
}
-void MultiAgendaView::addView( const TQString &label, KCal::ResourceCalendar * res, const TQString & subRes )
+void MultiAgendaView::addView( const TQString &label, ResourceCalendar *res, const TQString &subRes )
{
+ bool readOnlyView = false;
+
TQVBox *box = new TQVBox( mTopBox );
- TQLabel *l = new TQLabel( label, box );
- l->setAlignment( AlignVCenter | AlignHCenter );
- KOAgendaView* av = new KOAgendaView( calendar(), box, 0, true );
+
+ // First, the calendar folder title
+ TQHeader *title = new TQHeader( 1, box );
+ title->setClickEnabled( false );
+ title->setStretchEnabled( true );
+ if ( res->readOnly() || !res->subresourceWritable( subRes ) ) {
+ readOnlyView = true;
+ title->setLabel( 0, TQIconSet( KOGlobals::self()->smallIcon( "readonlyevent" ) ), label );
+ } else {
+ TQColor resColor;
+ if ( subRes.isEmpty() ) {
+ resColor = *KOPrefs::instance()->resourceColor( res->identifier() );
+ } else {
+ resColor = *KOPrefs::instance()->resourceColor( subRes );
+ }
+ TQFontMetrics fm = fontMetrics();
+ TQPixmap px( fm.height(), fm.height() );
+ px.fill( resColor );
+ title->setLabel( 0, TQIconSet( px, TQIconSet::Small ), label );
+ }
+
+ // Now, the sub agenda view
+ KOAgendaView* av = new KOAgendaView( calendar(), mCalendarView, box, 0, true );
+ av->setReadOnly( readOnlyView );
av->setResource( res, subRes );
av->setIncidenceChanger( mChanger );
av->agenda()->setVScrollBarMode( TQScrollView::AlwaysOff );
@@ -345,6 +414,7 @@ void MultiAgendaView::addView( const TQString &label, KCal::ResourceCalendar * r
connect( mTimeLabels->verticalScrollBar(), TQT_SIGNAL(valueChanged(int)),
av, TQT_SLOT(setContentsPos(int)) );
+ av->installEventFilter( this );
installSplitterEventFilter( av->splitter() );
}
@@ -387,10 +457,10 @@ void MultiAgendaView::updateConfig()
agenda->updateConfig();
}
-// KDE4: not needed anymore, TQSplitter has a moved signal there
bool MultiAgendaView::eventFilter(TQObject * obj, TQEvent * event)
{
if ( obj->className() == TQCString("QSplitterHandle") ) {
+ // KDE4: not needed anymore, TQSplitter has a moved signal there
if ( (event->type() == TQEvent::MouseMove && KGlobalSettings::opaqueResize())
|| event->type() == TQEvent::MouseButtonRelease ) {
FOREACH_VIEW( agenda ) {
@@ -404,9 +474,22 @@ bool MultiAgendaView::eventFilter(TQObject * obj, TQEvent * event)
TQTimer::singleShot( 0, this, TQT_SLOT(resizeSplitters()) );
}
}
+
+ if ( obj->className() == TQCString( "KOAgendaView" ) ) {
+ if ( event->type() == TQEvent::MouseButtonRelease ||
+ event->type() == TQEvent::MouseButtonPress ) {
+ mSelectedAgendaView = (KOAgendaView *)obj;
+ }
+ }
+
return AgendaView::eventFilter( obj, event );
}
+KOAgendaView *MultiAgendaView::selectedAgendaView()
+{
+ return mSelectedAgendaView;
+}
+
void MultiAgendaView::resizeSplitters()
{
if ( !mLastMovedSplitter )
@@ -422,6 +505,21 @@ void MultiAgendaView::resizeSplitters()
mRightSplitter->setSizes( mLastMovedSplitter->sizes() );
}
+void MultiAgendaView::resizeSpacers( int newY )
+{
+ // this slot is needed because the Agenda view's day labels frame height
+ // can change depending if holidays are shown. When this happens, all
+ // the widgets move down except the timelabels, so we need to change
+ // the top spacer height accordingly to move the timelabels up/down.
+ // kolab/issue2656
+ Q_UNUSED( newY );
+ TQFontMetrics fm( font() );
+ int topLabelHeight = mAgendaViews.first()->dayLabels()->height() +
+ fm.height() + mLeftSplitter->handleWidth();
+ mLeftTopSpacer->setFixedHeight( topLabelHeight );
+ mRightTopSpacer->setFixedHeight( topLabelHeight );
+}
+
void MultiAgendaView::zoomView( const int delta, const TQPoint & pos, const Qt::Orientation ori )
{
if ( ori == Qt::Vertical ) {
@@ -477,8 +575,45 @@ void MultiAgendaView::show()
void MultiAgendaView::resourcesChanged()
{
mPendingChanges = true;
+
+ kdDebug() << "mAgendaViews.size is " << mAgendaViews.size()
+ << "; mAgendaWidgets.size is " << mAgendaWidgets.size()
+ << "; mSelectedAgendaView is " << mSelectedAgendaView
+ << endl;
+
+ if ( mSelectedAgendaView ) {
+ ResourceCalendar *res = mSelectedAgendaView->resourceCalendar();
+ if ( res ) {
+ if ( res->canHaveSubresources() ) {
+ TQString subRes = mSelectedAgendaView->subResourceCalendar();
+ if ( !res->subresourceWritable( subRes ) ||
+ !res->subresourceActive( subRes ) ) {
+ mSelectedAgendaView = 0;
+ }
+ } else {
+ if ( res->readOnly() || !res->isActive() ) {
+ mSelectedAgendaView = 0;
+ }
+ }
+ } else {
+ mSelectedAgendaView = 0;
+ }
+ }
+
FOREACH_VIEW( agenda )
agenda->resourcesChanged();
}
+void MultiAgendaView::setupScrollBar()
+{
+ if ( !mAgendaViews.isEmpty() && mAgendaViews.first()->agenda() ) {
+ TQScrollBar *scrollBar = mAgendaViews.first()->agenda()->verticalScrollBar();
+ mScrollBar->setMinValue( scrollBar->minValue() );
+ mScrollBar->setMaxValue( scrollBar->maxValue() );
+ mScrollBar->setLineStep( scrollBar->lineStep() );
+ mScrollBar->setPageStep( scrollBar->pageStep() );
+ mScrollBar->setValue( scrollBar->value() );
+ }
+}
+
#include "multiagendaview.moc"
diff --git a/korganizer/multiagendaview.h b/korganizer/multiagendaview.h
index d7316698d..ebdfc9005 100644
--- a/korganizer/multiagendaview.h
+++ b/korganizer/multiagendaview.h
@@ -20,6 +20,7 @@
#define KORG_MULTIAGENDAVIEW_H_H
#include "agendaview.h"
+#include "calendarview.h"
class TQScrollView;
class TQHBox;
@@ -41,11 +42,14 @@ class MultiAgendaView : public AgendaView
{
Q_OBJECT
public:
- explicit MultiAgendaView( Calendar* cal, TQWidget *parent = 0, const char *name = 0 );
+ explicit MultiAgendaView( Calendar* cal, CalendarView *calendarView,
+ TQWidget *parent = 0, const char *name = 0 );
~MultiAgendaView();
+ KOAgendaView *selectedAgendaView();
+ void deSelectAgendaView() { mSelectedAgendaView = 0; }
Incidence::List selectedIncidences();
- DateList selectedDates();
+ DateList selectedIncidenceDates();
int currentDateCount();
int maxDatesHint();
@@ -55,7 +59,7 @@ class MultiAgendaView : public AgendaView
public slots:
void showDates( const TQDate &start, const TQDate &end );
- void showIncidences( const Incidence::List &incidenceList );
+ void showIncidences( const Incidence::List &incidenceList, const TQDate &date );
void updateView();
void changeIncidenceDisplay( Incidence *incidence, int mode );
void updateConfig();
@@ -84,10 +88,13 @@ class MultiAgendaView : public AgendaView
void slotSelectionChanged();
void slotClearTimeSpanSelection();
void resizeSplitters();
+ void resizeSpacers( int );
+ void setupScrollBar();
void zoomView( const int delta, const TQPoint &pos, const Qt::Orientation ori );
void slotResizeScrollView();
private:
+ KOAgendaView *mSelectedAgendaView;
TQValueList<KOAgendaView*> mAgendaViews;
TQValueList<TQWidget*> mAgendaWidgets;
TQHBox *mTopBox;
@@ -96,10 +103,12 @@ class MultiAgendaView : public AgendaView
TQSplitter *mLeftSplitter, *mRightSplitter;
TQSplitter *mLastMovedSplitter;
TQScrollBar *mScrollBar;
+ TQWidget *mLeftTopSpacer, *mRightTopSpacer;
TQWidget *mLeftBottomSpacer, *mRightBottomSpacer;
TQDate mStartDate, mEndDate;
bool mUpdateOnShow;
bool mPendingChanges;
+ CalendarView *mCalendarView;
};
}
diff --git a/korganizer/navigatorbar.cpp b/korganizer/navigatorbar.cpp
index 0ece74c57..f663af815 100644
--- a/korganizer/navigatorbar.cpp
+++ b/korganizer/navigatorbar.cpp
@@ -60,55 +60,70 @@ NavigatorBar::NavigatorBar( TQWidget *parent, const char *name )
tfont.setPointSize( 10 );
tfont.setBold( false );
+ // Create a horizontal spacers
+ TQSpacerItem *frontSpacer = new TQSpacerItem( 50, 1, TQSizePolicy::Expanding );
+ TQSpacerItem *endSpacer = new TQSpacerItem( 50, 1, TQSizePolicy::Expanding );
+
bool isRTL = KOGlobals::self()->reverseLayout();
TQPixmap pix;
// Create backward navigation buttons
- mPrevYear = new TQPushButton( this );
pix = KOGlobals::self()->smallIcon( isRTL ? "2rightarrow" : "2leftarrow" );
+ mPrevYear = new TQPushButton( this );
mPrevYear->setPixmap( pix );
mPrevYear->setSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Fixed );
- TQToolTip::add( mPrevYear, i18n("Previous year") );
+ TQToolTip::add( mPrevYear, i18n( "Previous year" ) );
pix = KOGlobals::self()->smallIcon( isRTL ? "1rightarrow" : "1leftarrow");
mPrevMonth = new TQPushButton( this );
mPrevMonth->setPixmap( pix );
mPrevMonth->setSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Fixed );
- TQToolTip::add( mPrevMonth, i18n("Previous month") );
+ TQToolTip::add( mPrevMonth, i18n( "Previous month" ) );
// Create forward navigation buttons
pix = KOGlobals::self()->smallIcon( isRTL ? "1leftarrow" : "1rightarrow");
mNextMonth = new TQPushButton( this );
mNextMonth->setPixmap( pix );
mNextMonth->setSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Fixed );
- TQToolTip::add( mNextMonth, i18n("Next month") );
+ TQToolTip::add( mNextMonth, i18n( "Next month" ) );
pix = KOGlobals::self()->smallIcon( isRTL ? "2leftarrow" : "2rightarrow");
mNextYear = new TQPushButton( this );
mNextYear->setPixmap( pix );
mNextYear->setSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Fixed );
- TQToolTip::add( mNextYear, i18n("Next year") );
+ TQToolTip::add( mNextYear, i18n( "Next year" ) );
// Create month name button
mMonth = new ActiveLabel( this );
mMonth->setFont( tfont );
mMonth->setAlignment( AlignCenter );
mMonth->setMinimumHeight( mPrevYear->sizeHint().height() );
- TQToolTip::add( mMonth, i18n("Select a month") );
+ TQToolTip::add( mMonth, i18n( "Select a month" ) );
+
+ // Create year button
+ mYear = new ActiveLabel( this );
+ mYear->setFont( tfont );
+ mYear->setAlignment( AlignCenter );
+ mYear->setMinimumHeight( mPrevYear->sizeHint().height() );
+ TQToolTip::add( mYear, i18n( "Select a year" ) );
// set up control frame layout
- TQBoxLayout *ctrlLayout = new TQHBoxLayout( this, 0, 4 );
- ctrlLayout->addWidget( mPrevYear, 3 );
- ctrlLayout->addWidget( mPrevMonth, 3 );
- ctrlLayout->addWidget( mMonth, 3 );
- ctrlLayout->addWidget( mNextMonth, 3 );
- ctrlLayout->addWidget( mNextYear, 3 );
-
- connect( mPrevYear, TQT_SIGNAL( clicked() ), TQT_SIGNAL( goPrevYear() ) );
- connect( mPrevMonth, TQT_SIGNAL( clicked() ), TQT_SIGNAL( goPrevMonth() ) );
- connect( mNextMonth, TQT_SIGNAL( clicked() ), TQT_SIGNAL( goNextMonth() ) );
- connect( mNextYear, TQT_SIGNAL( clicked() ), TQT_SIGNAL( goNextYear() ) );
- connect( mMonth, TQT_SIGNAL( clicked() ), TQT_SLOT( selectMonth() ) );
+ TQHBoxLayout *ctrlLayout = new TQHBoxLayout( this );
+ ctrlLayout->addWidget( mPrevYear );
+ ctrlLayout->addWidget( mPrevMonth );
+ ctrlLayout->addItem( frontSpacer );
+ ctrlLayout->addWidget( mMonth );
+ ctrlLayout->addWidget( mYear );
+ ctrlLayout->addItem( endSpacer );
+ ctrlLayout->addWidget( mNextMonth );
+ ctrlLayout->addWidget( mNextYear );
+
+ connect( mPrevYear, TQT_SIGNAL( clicked() ), TQT_SIGNAL( prevYearClicked() ) );
+ connect( mPrevMonth, TQT_SIGNAL( clicked() ), TQT_SIGNAL( prevMonthClicked() ) );
+ connect( mNextMonth, TQT_SIGNAL( clicked() ), TQT_SIGNAL( nextMonthClicked() ) );
+ connect( mNextYear, TQT_SIGNAL( clicked() ), TQT_SIGNAL( nextYearClicked() ) );
+ connect( mMonth, TQT_SIGNAL( clicked() ), TQT_SLOT( selectMonthFromMenu() ) );
+ connect( mYear, TQT_SIGNAL( clicked() ), TQT_SLOT( selectYearFromMenu() ) );
}
NavigatorBar::~NavigatorBar()
@@ -142,29 +157,29 @@ void NavigatorBar::selectDates( const KCal::DateList &dateList )
const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem();
- if ( !mHasMinWidth ) {
- // Set minimum width to width of widest month name label
- int i;
- int maxwidth = 0;
+ // Set minimum width to width of widest month name label
+ int i;
+ int maxwidth = 0;
- for( i = 1; i <= calSys->monthsInYear( mDate ); ++i ) {
- int w = TQFontMetrics( mMonth->font() ).width( TQString("%1 8888")
- .arg( calSys->monthName( i, calSys->year( mDate ) ) ) );
- if ( w > maxwidth ) maxwidth = w;
+ for( i = 1; i <= calSys->monthsInYear( mDate ); ++i ) {
+ int w = TQFontMetrics( mMonth->font() ).
+ width( TQString( "%1" ).
+ arg( calSys->monthName( i, calSys->year( mDate ) ) ) );
+ if ( w > maxwidth ) {
+ maxwidth = w;
}
- mMonth->setMinimumWidth( maxwidth );
-
- mHasMinWidth = true;
}
+ mMonth->setMinimumWidth( maxwidth );
+
+ mHasMinWidth = true;
- // compute the label at the top of the navigator
- mMonth->setText( i18n( "monthname year", "%1 %2" )
- .arg( calSys->monthName( mDate ) )
- .arg( calSys->year( mDate ) ) );
+ // set the label text at the top of the navigator
+ mMonth->setText( i18n( "monthname", "%1" ).arg( calSys->monthName( mDate ) ) );
+ mYear->setText( i18n( "4 digit year", "%1" ).arg( calSys->yearString( mDate, false ) ) );
}
}
-void NavigatorBar::selectMonth()
+void NavigatorBar::selectMonthFromMenu()
{
// every year can have different month names (in some calendar systems)
const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem();
@@ -185,7 +200,36 @@ void NavigatorBar::selectMonth()
return; // canceled
}
- emit goMonth( month );
+ emit monthSelected( month );
+
+ delete popup;
+}
+
+void NavigatorBar::selectYearFromMenu()
+{
+ const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem();
+
+ int year = calSys->year( mDate );
+ int years = 11; // odd number (show a few years ago -> a few years from now)
+ int minYear = year - ( years / 3 );
+
+ TQPopupMenu *popup = new TQPopupMenu( mYear );
+
+ TQString yearStr;
+ int y = minYear;
+ for ( int i=0; i < years; i++ ) {
+ popup->insertItem( yearStr.setNum( y ), i );
+ y++;
+ }
+ popup->setActiveItem( year - minYear );
+
+ if ( ( year = popup->exec( mYear->mapToGlobal( TQPoint( 0, 0 ) ),
+ year - minYear ) ) == -1 ) {
+ delete popup;
+ return; // canceled
+ }
+
+ emit yearSelected( year + minYear );
delete popup;
}
diff --git a/korganizer/navigatorbar.h b/korganizer/navigatorbar.h
index c6bc41768..05d624a58 100644
--- a/korganizer/navigatorbar.h
+++ b/korganizer/navigatorbar.h
@@ -58,14 +58,16 @@ class NavigatorBar: public QWidget
void selectDates( const KCal::DateList & );
signals:
- void goNextMonth();
- void goPrevMonth();
- void goNextYear();
- void goPrevYear();
- void goMonth(int month);
+ void nextMonthClicked();
+ void prevMonthClicked();
+ void nextYearClicked();
+ void prevYearClicked();
+ void monthSelected( int month );
+ void yearSelected( int year );
private slots:
- void selectMonth();
+ void selectMonthFromMenu();
+ void selectYearFromMenu();
private:
bool mHasMinWidth;
@@ -75,6 +77,7 @@ class NavigatorBar: public QWidget
TQPushButton *mPrevYear;
TQPushButton *mPrevMonth;
ActiveLabel *mMonth;
+ ActiveLabel *mYear;
TQPushButton *mNextMonth;
TQPushButton *mNextYear;
};
diff --git a/korganizer/plugins/datenums/datenums.desktop b/korganizer/plugins/datenums/datenums.desktop
index b5010edc9..b93e3d1de 100644
--- a/korganizer/plugins/datenums/datenums.desktop
+++ b/korganizer/plugins/datenums/datenums.desktop
@@ -24,7 +24,6 @@ Name[hu]=Dátumkezelő bővítőmodul naptárakhoz
Name[is]=Íforrit fyrir númer dags á dagatali
Name[it]=Plugin delle date per i calendari
Name[ja]=日数表示カレンダープラグイン
-Name[ka]=თარიღის რიცხვების მოდული კალენდრებისათვის
Name[kk]=Күнтізбедегі күн нөмірінің модулі
Name[km]=កម្មវិធី​ជំនួយ​លេខ​កាលបរិច្ឆេទ​សម្រាប់​ប្រតិទិន
Name[lt]=Datų numerių priedas kalendoriams
@@ -69,7 +68,6 @@ Comment[hu]=Megjeleníti az év elejétől eltelt napok számát az áttekintő
Comment[is]=Þetta íforrit sýnir efst í fundarskránni númer hvers dags í árinu. T.d. er 1. febrúar 32. dagurinn í árinu.
Comment[it]=Per ciascun giorno, questo plugin mostra la data giuliana (numero progressivo a partire dal primo gennaio dell'anno corrente). Per esempio al primo di febbraio corrisponde il numero 32.
Comment[ja]=このプラグインは予定表ビューの上に、それぞれの日がその年の何日目であるかを表示します。例えば、2 月 1 日はその年の 32 日目です。
-Comment[ka]= გეგმის ზედა ხედში ეს მოდული თვითეული დღისათვის აჩვენებს მის დღის ნომერს ამ წლისათვის . მაგალითად,1 თებერვალი წლის 32-ე დღეა.
Comment[kk]=Бұл модуль күн тәртібі бетінің жоғарында жыл басынан өткен күндер санын көрсетеді. Мысалы, 1-ақпан жылдың 32-күні.
Comment[km]=សម្រាប់​ថ្ងៃ​នីមួយៗ កម្មវិធី​ជំនួយ​នេះ​នឹង​បង្ហាញ​លេខ​ថ្ងៃ​នៃ​ឆ្នាំ នៅ​ផ្នែក​ខាង​លើ​នៃ​ទិដ្ឋភាព​របៀបវារៈ ។ ឧទាហរណ៍ ថ្ងៃ​ទី ១ ខែ កុម្ភៈ នឹង​ត្រូវ​ជា​ថ្ងៃ​ទី ៣២ នៃ​ឆ្នាំ ។
Comment[lt]=Kiekvienai dienai šis priedas rodo metų dienos numerį tvarkyklės viršuje. Pvz., Vasario 1 yra32 metų diena.
diff --git a/korganizer/plugins/exchange/exchange.desktop b/korganizer/plugins/exchange/exchange.desktop
index 121bf9863..95484e3b4 100644
--- a/korganizer/plugins/exchange/exchange.desktop
+++ b/korganizer/plugins/exchange/exchange.desktop
@@ -24,7 +24,6 @@ Name[hu]=Microsoft Exchange 2000-bővítőmodul a KOrganizerhez
Name[is]=Microsoft Exchange 2000 íforrit fyrir KOrganizer
Name[it]=Plugin Microsoft Exchange 2000 per KOrganizer
Name[ja]=KOrganizer の Microsoft Exchange 2000 プラグイン
-Name[ka]=Microsoft Exchange 2000-ის მოდული KOrganizer-სთვის
Name[kk]=KOrganizer-дің Microsoft Exchange 2000 модулі
Name[km]=កម្មវិធី​ជំនួយ​ម៉ៃក្រូសូហ្វ Exchange ២០០០ សម្រាប់ KOrganizer
Name[lt]=Microsoft Exchange 2000 priedas, skirtas KOrganizer
@@ -70,7 +69,6 @@ Comment[hu]=Ez a modul lehetővé teszi KOrganizer-felhasználóknak Microsoft E
Comment[is]=Þetta íforrit gerir KOrganizer kleyft að vinna með Microsoft Exchange 2000 hópvinnuþjónum.
Comment[it]=Questo plugin permette agli utenti di korganizer di lavorare con i server groupware Microsoft Exchange 2000.
Comment[ja]=このプラグインにより、korganizer のユーザが Microsoft Exchange 2000 グループウェアサーバと同期できるようになります。
-Comment[ka]=ეს მოდული korganizer-ის მომხმარებლებს საშუალებას აძლევს იმუშაონ Microsoft Exchange 2000 ჯგუფურ სერვერებთან.
Comment[kk]=Бұл модуль korganizer-мен MS Exchange 2000 біріккен жұмыс сервермен істеуге мүмкіндік береді.
Comment[km]=កម្មវិធី​ជំនួយ​នេះ​អនុញ្ញាត​ឲ្យ​អ្នក​ប្រើ​របស់ korganizer ធ្វើការ​ជាមួយ​ម៉ាស៊ីន​បម្រើ​កម្មវិធី​ពហុ​អ្នកប្រើ​របស់​ម៉ៃក្រូសូហ្វ Exchange ២០០០ ។
Comment[lt]=Šis priedas leidžia korganizer dirbti su Microsoft Exchange 2000 groupware serveriais.
diff --git a/korganizer/plugins/hebrew/hebrew.cpp b/korganizer/plugins/hebrew/hebrew.cpp
index 9fb0f2fbf..8a9f37bd4 100644
--- a/korganizer/plugins/hebrew/hebrew.cpp
+++ b/korganizer/plugins/hebrew/hebrew.cpp
@@ -55,7 +55,7 @@ TQString Hebrew::shortText(const TQDate & date)
Holiday::ParshaP = config.readBoolEntry("Parsha", true);
Holiday::CholP = config.readBoolEntry("Chol_HaMoed", true);
Holiday::OmerP = config.readBoolEntry("Omer", true);
- TQString *label_text = new TQString();
+ TQString label_text;
int day = date.day();
int month = date.month();
@@ -81,7 +81,7 @@ TQString Hebrew::shortText(const TQDate & date)
hebrew_day_number, hebrew_year);
KCalendarSystem *cal = KCalendarSystemFactory::create("hebrew");
- *label_text = TQString("%1 %2").arg(cal->dayString(date, false))
+ label_text = TQString("%1 %2").arg(cal->dayString(date, false))
.arg(cal->monthName(date));
if (holidays.count())
@@ -90,11 +90,11 @@ TQString Hebrew::shortText(const TQDate & date)
for (int h = 0; h <= count; ++h)
{
- *label_text += "\n" + holidays[h];
+ label_text += "\n" + holidays[h];
}
}
- return *label_text;
+ return label_text;
}
TQString Hebrew::info()
diff --git a/korganizer/plugins/hebrew/hebrew.desktop b/korganizer/plugins/hebrew/hebrew.desktop
index 86c88328d..dc67c2eba 100644
--- a/korganizer/plugins/hebrew/hebrew.desktop
+++ b/korganizer/plugins/hebrew/hebrew.desktop
@@ -23,7 +23,6 @@ Name[hu]=Bővítőmodul a zsidó naptár kezeléséhez
Name[is]=Gyðinga dagatalsíforrit
Name[it]=Plugin calendario ebraico
Name[ja]=ユダヤ歴カレンダープラグイン
-Name[ka]=ებრაული კალენდრის მოდული
Name[kk]=Яһуди күнтізбесінің модулі
Name[km]=កម្មវិធី​ជំនួយ​ប្រតិទិន Jewish
Name[lt]=Žydų kalendoriaus priedas
@@ -70,7 +69,6 @@ Comment[hu]=A KOrganizer dátumait kiírja a hagyományos zsidó naptár szerint
Comment[is]=Sýna alla dagsetningar í KOrganizer sem eru einnig í dagatali gyðinga.
Comment[it]=Mostra tutte le date in korganizer secondo il calendario ebraico.
Comment[ja]=korganizer のすべての日付をユダヤ暦でも表示します。
-Comment[ka]=ყველა თარიღს ებრაული კალენდრის მიხედვითაც აჩვენებს
Comment[kk]=Яһуди күнтізбе күндерін korganizer-де көрсететін модулі.
Comment[km]=បង្ហាញ​កាលបរិច្ឆេទ​ទាំងអស់​ក្នុង korganizer នៅ​ក្នុង​ប្រព័ន្ធ​ប្រតិទិន Jewish ។
Comment[lt]=Rodo visas dienas kalendoriuje taip pat ir žydų kalendoriaus sistema.
diff --git a/korganizer/plugins/printing/journal/journalprint.cpp b/korganizer/plugins/printing/journal/journalprint.cpp
index 551f23a9d..93bc51eff 100644
--- a/korganizer/plugins/printing/journal/journalprint.cpp
+++ b/korganizer/plugins/printing/journal/journalprint.cpp
@@ -123,13 +123,19 @@ void CalPrintJournal::print( TQPainter &p, int width, int height )
}
}
- drawHeader( p, i18n("Journal entries"), TQDate(), TQDate(), TQRect( 0, 0, width, headerHeight() ) );
+ TQRect headerBox( 0, 0, width, headerHeight() );
+ TQRect footerBox( 0, height - footerHeight(), width, footerHeight() );
+ height -= footerHeight();
+
+ drawHeader( p, i18n("Journal entries"), TQDate(), TQDate(), headerBox );
y = headerHeight() + 15;
Journal::List::Iterator it = journals.begin();
for ( ; it != journals.end(); ++it ) {
drawJournal( *it, p, x, y, width, height );
}
+
+ drawFooter( p, footerBox );
}
#endif
diff --git a/korganizer/plugins/printing/journal/journalprint.desktop b/korganizer/plugins/printing/journal/journalprint.desktop
index 081f73d6d..6d811fcec 100644
--- a/korganizer/plugins/printing/journal/journalprint.desktop
+++ b/korganizer/plugins/printing/journal/journalprint.desktop
@@ -21,7 +21,6 @@ Name[hu]=Naplónyomtatási stílus
Name[is]=Dagbókarprentstíll
Name[it]=Stile di stampa a diario
Name[ja]=ジャーナル印刷スタイル
-Name[ka]=ჟურნალის ბეჭდვის სტილი
Name[kk]=Күнделікті басу стилі
Name[km]=រចនាប័ទ្ម​បោះពុម្ព​ទិនានុប្បវត្តិ
Name[lt]=Dienyno spausdinimo stilius
@@ -65,7 +64,6 @@ Comment[hu]=Ez a modul naplóbejegyzések kinyomtatását teszi lehetővé.
Comment[is]=Þetta íforrit gerir þér kleyft að prenta út dagbókarfærslur.
Comment[it]=Questo plugin ti permette di stampare le registrazioni del diario.
Comment[ja]=このプラグインにより、ジャーナル (日誌) のエントリを印刷できるようになります。
-Comment[ka]=ეს მოდული საშუალებას გაძლევთ ამობეჭდოთ ჟურნალის შემადგენლობა (დღიურის ელემენტები)
Comment[kk]=Бұл күнделіктің жазуларын басып шығаратын модулі.
Comment[km]=កម្មវិធី​ជំនួយ​នេះ​អនុញ្ញាត​ឲ្យ​អ្នក​បោះពុម្ព​ធាតុ​ទិនានុប្បវត្តិ (ធាតុ​កំណត់ហេតុ​ប្រចាំ​ថ្ងៃ) ។
Comment[lt]=Šis priedas leidžia spausdinti dienyno įrašus.
diff --git a/korganizer/plugins/printing/list/listprint.desktop b/korganizer/plugins/printing/list/listprint.desktop
index 7688a2c52..6be822b85 100644
--- a/korganizer/plugins/printing/list/listprint.desktop
+++ b/korganizer/plugins/printing/list/listprint.desktop
@@ -21,7 +21,6 @@ Name[hu]=Eseménylista kinyomtatása
Name[is]=Listaprentstíll
Name[it]=Stile di stampa ad elenco
Name[ja]=リスト印刷スタイル
-Name[ka]=ბეჭდვის სტილის სია
Name[kk]=Тізімді басу стилі
Name[km]=រចនាប័ទ្ម​បោះពុម្ព​បញ្ជី
Name[lt]=Sąrašo spausdinimo stilius
@@ -65,7 +64,6 @@ Comment[hu]=Ezzel a modullal listaként kinyomtathatók a feladatok és esemény
Comment[is]=Þetta íforrit gerir þér kleyft að prenta út lista með atburðum og verkþáttum.
Comment[it]=Questo plugin ti permette di stampare eventi e cose da fare in modalità elenco.
Comment[ja]=このプラグインにより、リストフォーム内のイベントや To-Do を印刷できるようになります。
-Comment[ka]=ეს მოდული საშუალებას გაძლევთ სიის ფორმით ამობეჭდოთ მოვლენები და დავალებები.
Comment[kk]=Бұл оқиғалар мен жоспарларды тізім түрінде басатын модулі.
Comment[km]=កម្មវិធី​ជំនួយ​នេះ​អនុញ្ញាត​ឲ្យ​អ្នក​បោះពុម្ព​ព្រឹត្តិការណ៍ និង​ការងារ​ត្រូវ​ធ្វើក្នុង​ទម្រង់​ជា​បញ្ជី ។
Comment[lt]=Šis priedas leidžia spausdinti įvykius ir darbus sąrašo forma.
diff --git a/korganizer/plugins/printing/whatsnext/whatsnextprint.desktop b/korganizer/plugins/printing/whatsnext/whatsnextprint.desktop
index 50131734e..59ed74c21 100644
--- a/korganizer/plugins/printing/whatsnext/whatsnextprint.desktop
+++ b/korganizer/plugins/printing/whatsnext/whatsnextprint.desktop
@@ -21,7 +21,6 @@ Name[hu]=A közeljövő eseményeinek kinyomtatása
Name[is]=Hvað er næst prentstíll
Name[it]=Stile di stampa "cosa viene dopo"
Name[ja]=次は何? 印刷スタイル
-Name[ka]=ბეჭდვის სტილი "შემდეგი რა არის?"
Name[kk]="Не істеу?" бетін басу стилі
Name[km]=រចនាប័ទ្ម​បោះពុម្ព​ការងារ​បន្តបន្ទាប់
Name[lt]=Ateinančių įvykių spausdinimo stilius
@@ -34,7 +33,7 @@ Name[nn]=Utskriftsstil for «Kva no»
Name[pl]=Styl drukowania "Do dalej"
Name[pt]=Estilo de Impressão "O Que Se Segue"
Name[pt_BR]=Estilo de impressão "A Seguir"
-Name[ru]=Предстоящие задачи
+Name[ru]=Даджест
Name[sk]=Štýl tlače Čo nasleduje
Name[sl]=Slog tiskanja v obliki »Kaj je naslednje«
Name[sr]=Стил штампе „Шта је следеће“
@@ -65,7 +64,6 @@ Comment[hu]=Ezzel a modullal kinyomtathatók a rövidesen aktuálissá váló fe
Comment[is]=Þetta íforrit gerir þér kleyft að prenta út lista yfir alla væntanlega atburði og verkþætti.
Comment[it]=Questo plugin vi permette di stampare una lista dei prossimi eventi e cose da fare.
Comment[ja]=このプラグインにより、将来のすべてのイベントや To-Do のリストを印刷できるようになります。
-Comment[ka]=ეს მოდული საშუალებას გაძლევთ ამობეჭდოთ მომავალი მოვლენები და დავალებები.
Comment[kk]=Бұл келер оқиғалар мен жоспарлар тізімін басып шығаратын модулі.
Comment[km]=កម្មវិធី​ជំនួយ​នេះ​អនុញ្ញាត​ឲ្យ​អ្នក​បោះពុម្ព​បញ្ជី​នៃ​ព្រឹត្តិការណ៍ និង​ការងារ​ត្រូវ​ធ្វើ​បន្តបន្ទាប់
Comment[lt]=Šis priedas leidžia spausdinti sąrašą visų artėjančių įvykių ir darbų.
diff --git a/korganizer/plugins/printing/year/yearprint.cpp b/korganizer/plugins/printing/year/yearprint.cpp
index 5f3a9dc68..59a43db75 100644
--- a/korganizer/plugins/printing/year/yearprint.cpp
+++ b/korganizer/plugins/printing/year/yearprint.cpp
@@ -137,13 +137,14 @@ void CalPrintYear::setDateRange( const TQDate& from, const TQDate& to )
void CalPrintYear::print( TQPainter &p, int width, int height )
{
-kdDebug()<<"CalPrintYear::print, width: "<<width<<", height: "<<height<<endl;
- TQRect headerBox( 0, 0, width, headerHeight() );
-kdDebug()<<"headerBox: "<<headerBox<<endl;
const KCalendarSystem *calsys = calendarSystem();
KLocale *locale = KGlobal::locale();
if ( !calsys || !locale ) return;
+ TQRect headerBox( 0, 0, width, headerHeight() );
+ TQRect footerBox( 0, height - footerHeight(), width, footerHeight() );
+ height -= footerHeight();
+
TQDate start;
calsys->setYMD( start, mYear, 1, 1 );
@@ -197,6 +198,8 @@ kdDebug()<<"headerBox: "<<headerBox<<endl;
temp = calsys->addMonths( temp, 1 );
}
+
+ drawFooter( p, footerBox );
start = calsys->addMonths( start, monthsPerPage );
}
}
diff --git a/korganizer/plugins/printing/year/yearprint.desktop b/korganizer/plugins/printing/year/yearprint.desktop
index 5edafedc2..40f1de60b 100644
--- a/korganizer/plugins/printing/year/yearprint.desktop
+++ b/korganizer/plugins/printing/year/yearprint.desktop
@@ -16,7 +16,6 @@ Name[fr]=Impression annuelle
Name[fy]=Printstyl foar jierkalinder
Name[gl]=Estilo de impresión anual
Name[hu]=Éves naptár nyomtatási stílus
-Name[is]=Ársyfirlitsprentstíll
Name[it]=Stile di stampa annuale
Name[ja]=年毎印刷スタイル
Name[kk]=Жылдық басу стилі
@@ -54,7 +53,6 @@ Comment[fr]=Ce module vous permet d'imprimer l'ensemble de l'année
Comment[fy]=Dizze plugin makket it mooglik om in jierkalinder út te printsjen.
Comment[gl]=Este engadido permítelle imprimir un calendario anual.
Comment[hu]=Ez a modul egy egész éves naptár kinyomtatását teszi lehetővé.
-Comment[is]=Þetta íforrit gerir þér kleyft að prenta út dagbókarfærslur fyrir allt árið.
Comment[it]=Questo plugin ti permette di stampare un calendario annuale.
Comment[ja]=このプラグインにより、年毎のカレンダーを印刷できるようになります。
Comment[kk]=Бұл жылдық күнтізбені басып шығаратын модулі.
diff --git a/korganizer/plugins/timespanview/timespanview.desktop b/korganizer/plugins/timespanview/timespanview.desktop
index 13654b46a..72e403bb0 100644
--- a/korganizer/plugins/timespanview/timespanview.desktop
+++ b/korganizer/plugins/timespanview/timespanview.desktop
@@ -21,7 +21,6 @@ Name[hu]=Időszakáttekintő bővítőmodul a KOrganizerhez
Name[is]=Tímabilsskoðunar íforrit fyrir KOrganizer
Name[it]=Plugin vista intervalli temporali per KOrganizer
Name[ja]=KOrganizer タイムスパンビュー プラグイン
-Name[ka]=დროის დიაგრამიანი ხედის მოდული KOrganizer-სთვის
Name[kk]=KOrganizer-дің уақыт аралығы көрініс модулі
Name[km]=កម្មវិធី​ជំនួយ​ទិដ្ឋភាព​រយៈពេល​សម្រាប់ KOrganizer
Name[lt]=Laiko tarpsnio vaizdo KOrganizer priedas
@@ -65,7 +64,6 @@ Comment[hu]=Ezzel modullal egy időszakot lehet áttekinteni a KOrganizerben (p
Comment[is]=Þetta íforrit veitir tímabilssýn fyrir KOrganizer (svipað og verkþátta eða mánaðarsýn). Ef þú virkjar þetta íforrit getur þú skipt yfir í tímabilssýn og skoðað atburðina þína eins og á Gantt skýringarmynd.
Comment[it]=Questo plugin fornisce una vista a intervalli temporali. Se abiliti questo plugin, potrai passare alla vista a intervalli temporali e vedere i tuoi eventi come in un diagramma di Gantt.
Comment[ja]=このプラグインは KOrganizer にタイムスパンビューを提供します (To-Do ビューや月ビューなど)。このプラグインを有効にすると、タイムスパンビューに切り替えて、ガントチャートのようにイベントを見ることができます。
-Comment[ka]=ეს მოდული უზრუნველჰყოფს korganizer-ს დროის დიაგრამიანი ხედით (მაგ.:დავალებები ან თვიური მიმოხილვა). თუ ამ მოდულს გაააქტიურებთ,თქვენ შეგიძლიათ გადართოთ დროის დიაგრამიან ხედზე და იხილოთ მოვლენები განტის დიაგრამის სახით.
Comment[kk]=Бұл KOrganizer-нің уақыт аралығы көрінісінің модулі. Модулін орнатсаңыз, осы көрініске ауысып оқиғаларыңызды Гант диаграмма түріне келтре аласыз.
Comment[km]=កម្មវិធី​ជំនួយ​នេះ​ផ្ដល់​នូវ​ទិដ្ឋភាព​រយៈពេល​សម្រាប់ korganizer (ដូចជា ទិដ្ឋភាព​ការងារ​ត្រូវ​ធ្វើ ឬ ទិដ្ឋភាព​ខែ​ជាដើម) ។ បើ​អ្នក​ធ្វើ​ឲ្យ​កម្មវិធី​ជំនួយ​នេះ​ប្រើ​បាន អ្នក​នឹង​អាច​ប្ដូរ​ទិដ្ឋភាព​រយៈពេល ហើយ​មើល​ព្រឹត្តិការណ៍​របស់​អ្នក​ដូចជា​នៅ​ក្នុងដ្យាក្រាម Gantt អញ្ចឹង​ដែរ ។
Comment[lt]=Šis priedas korganizer programoje sudaro galimybę apžvelgti laiko tarpą (pvz., darbų arba mėnesio peržiūra). Įgalinus šį priedą galėsite persijungti į laiko tarpo peržiūrą ir žiūrėti įvykius tarsi Gantt diagramoje.
diff --git a/korganizer/previewdialog.cpp b/korganizer/previewdialog.cpp
new file mode 100644
index 000000000..23671bd92
--- /dev/null
+++ b/korganizer/previewdialog.cpp
@@ -0,0 +1,163 @@
+/*
+ This file is part of KOrganizer.
+
+ Copyright (c) 2003,2004 Cornelius Schumacher <schumacher@kde.org>
+ Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
+
+ Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
+ Author: Sergio Martins, <sergio.martins@kdab.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.
+
+ As a special exception, permission is given to link this program
+ with any edition of TQt, and distribute the resulting executable,
+ without including the source code for TQt in the source distribution.
+*/
+
+#include "previewdialog.h"
+
+#include "kolistview.h"
+#include "koprefs.h"
+#include "stdcalendar.h"
+
+#include <klocale.h>
+
+#include <libkcal/calendarlocal.h>
+
+#include <kstandarddirs.h>
+#include <kfiledialog.h>
+#include <kmessagebox.h>
+#include <kio/netaccess.h>
+
+#include <tqlabel.h>
+#include <tqlayout.h>
+#include <tqradiobutton.h>
+#include <tqpushbutton.h>
+#include <tqdialog.h>
+
+using namespace KCal;
+
+PreviewDialog::PreviewDialog( const KURL &url, TQWidget *parent )
+ : KDialogBase( Plain, i18n("Import Calendar/Event"), User1 | User2 | Cancel, User1, parent,
+ 0, true, true, KGuiItem( i18n("&Merge into existing calendar"), "merge" ) ),
+ mOriginalUrl( url )
+{
+ TQFrame *topFrame = plainPage();
+ TQVBoxLayout *topLayout = new TQVBoxLayout( topFrame, 0, spacingHint() );
+
+ mCalendar = new CalendarLocal( KOPrefs::instance()->mTimeZoneId );
+ mListView = new KOListView( mCalendar, topFrame, "PreviewDialog::ListView", true );
+ topLayout->addWidget( mListView );
+
+ topLayout->setSpacing( spacingHint() );
+ topLayout->setMargin( marginHint() );
+
+ connect( this, TQT_SIGNAL(user1Clicked()), TQT_SLOT(slotMerge()) );
+ connect( this, TQT_SIGNAL(user2Clicked()), TQT_SLOT(slotAdd()) );
+
+ // when someone edits a kmail attachment he's editing a tmp file, check for that
+ // and if it's a tmp file then open a save dialog
+ if ( isTempFile() ) {
+ setButtonGuiItem( User2, KGuiItem( i18n("&Add as new calendar..."), "add" ) );
+ } else {
+ setButtonGuiItem( User2, KGuiItem( i18n("&Add as new calendar"), "add" ) );
+ }
+
+ mLocalUrl = 0;
+}
+
+PreviewDialog::~PreviewDialog()
+{
+ if ( mLocalUrl && !mOriginalUrl.isLocalFile() ) {
+ KIO::NetAccess::removeTempFile( mLocalUrl->path() );
+ delete mLocalUrl;
+ }
+
+ delete mCalendar;
+}
+
+bool PreviewDialog::loadCalendar()
+{
+ // If it's a remote file, download it so we can give it to CalendarLocal
+ if ( !mOriginalUrl.isLocalFile() ) {
+ if ( mLocalUrl ) {
+ // loadCalendar already called.. remove old one.
+ KIO::NetAccess::removeTempFile( mLocalUrl->path() );
+ delete mLocalUrl;
+ }
+
+ TQString tmpFile;
+ if ( KIO::NetAccess::download( mOriginalUrl, tmpFile, 0 ) ) {
+ mLocalUrl = new KURL( tmpFile );
+ } else {
+ mLocalUrl = 0;
+ }
+ } else {
+ mLocalUrl = &mOriginalUrl;
+ }
+
+ if ( mLocalUrl ) {
+ const bool success = mCalendar->load( mLocalUrl->path() );
+
+ if ( !success && !mOriginalUrl.isLocalFile() ) {
+ KIO::NetAccess::removeTempFile( mLocalUrl->path() );
+ } else {
+ mListView->showAll();
+ }
+ return success;
+ } else {
+ return false;
+ }
+}
+
+void PreviewDialog::slotMerge()
+{
+ if ( mLocalUrl ) {
+ emit openURL( *mLocalUrl, true );
+ emit dialogFinished( this );
+ accept();
+ }
+}
+
+void PreviewDialog::slotAdd()
+{
+ KURL finalUrl = mOriginalUrl;
+ if ( isTempFile() ) {
+ const TQString fileName =
+ KFileDialog::getSaveFileName( locateLocal( "data","korganizer/" ),
+ i18n( "*.vcs *.ics|Calendar Files" ),
+ this, i18n( "Select path for new calendar" ) );
+
+ finalUrl = KURL( fileName );
+
+ if ( !KIO::NetAccess::copy( mOriginalUrl, finalUrl, this ) && KIO::NetAccess::lastError() ) {
+ KMessageBox::error( this, KIO::NetAccess::lastErrorString() );
+ return;
+ }
+ }
+
+ if ( finalUrl.isValid() ) {
+ emit addResource( finalUrl );
+ emit dialogFinished( this );
+ accept();
+ }
+}
+
+bool PreviewDialog::isTempFile() const
+{
+ return mOriginalUrl.path().startsWith( locateLocal( "tmp", "" ) );
+}
+
+#include "previewdialog.moc"
diff --git a/korganizer/previewdialog.h b/korganizer/previewdialog.h
new file mode 100644
index 000000000..ed32c5f50
--- /dev/null
+++ b/korganizer/previewdialog.h
@@ -0,0 +1,69 @@
+/*
+ This file is part of KOrganizer.
+
+ Copyright (c) 2003,2004 Cornelius Schumacher <schumacher@kde.org>
+ Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
+
+ Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
+ Author: Sergio Martins, <sergio.martins@kdab.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.
+
+ As a special exception, permission is given to link this program
+ with any edition of TQt, and distribute the resulting executable,
+ without including the source code for TQt in the source distribution.
+*/
+
+#ifndef PREVIEWDIALOG_H
+#define PREVIEWDIALOG_H
+
+#include <kdialogbase.h>
+#include <kurl.h>
+
+class KOListView;
+
+namespace KCal {
+ class CalendarLocal;
+}
+
+class PreviewDialog : public KDialogBase
+{
+ Q_OBJECT
+ public:
+ PreviewDialog( const KURL &url, TQWidget *parent );
+ ~PreviewDialog();
+ bool loadCalendar();
+
+ public slots:
+ void slotAdd();
+ void slotMerge();
+
+ signals:
+ void dialogFinished( PreviewDialog * );
+ void openURL( const KURL &, bool );
+ void addResource( const KURL & );
+
+ private:
+ // Checks if mOriginalUrl is a temp file, if it is we ask the user a place to
+ // keep the calendar file
+ bool isTempFile() const;
+ private:
+ KURL mOriginalUrl;
+ KURL *mLocalUrl;
+ KOListView *mListView;
+ KCal::CalendarLocal *mCalendar;
+};
+
+#endif
diff --git a/korganizer/printing/calprintdefaultplugins.cpp b/korganizer/printing/calprintdefaultplugins.cpp
index bc4c62496..38d9b4b72 100644
--- a/korganizer/printing/calprintdefaultplugins.cpp
+++ b/korganizer/printing/calprintdefaultplugins.cpp
@@ -4,6 +4,7 @@
Copyright (c) 1998 Preston Brown <pbrown@kde.org>
Copyright (c) 2003 Reinhold Kainhofer <reinhold@kainhofer.com>
Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+ Copyright (c) 2008 Ron Goodheart <ron.goodheart@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -38,6 +39,8 @@
#include <knuminput.h>
#include <kcombobox.h>
+#include <libkcal/incidenceformatter.h>
+
#include "calprintdefaultplugins.h"
#include "calprintincidenceconfig_base.h"
@@ -46,7 +49,6 @@
#include "calprintmonthconfig_base.h"
#include "calprinttodoconfig_base.h"
-
/**************************************************************
* Print Incidence
**************************************************************/
@@ -131,18 +133,18 @@ class TimePrintStringsVisitor : public IncidenceBase::Visitor
protected:
bool visit( Event *event ) {
if ( event->dtStart().isValid() ) {
- mStartCaption = i18n("Start date: ");
- // Show date/time or only date, depending on whether it's an all-day event
-// TODO: Add shortfmt param to dtStartStr, dtEndStr and dtDueStr!!!
- mStartString = (event->doesFloat()) ? (event->dtStartDateStr(false)) : (event->dtStartStr());
+ mStartCaption = i18n( "Start date: " );
+ mStartString = IncidenceFormatter::dateTimeToString(
+ event->dtStart(), event->doesFloat(), false );
} else {
- mStartCaption = i18n("No start date");
+ mStartCaption = i18n( "No start date" );
mStartString = TQString::null;
}
-
+
if ( event->hasEndDate() ) {
- mEndCaption = i18n("End date: ");
- mEndString = (event->doesFloat()) ? (event->dtEndDateStr(false)) : (event->dtEndStr());
+ mEndCaption = i18n( "End date: " );
+ mEndString = IncidenceFormatter::dateTimeToString(
+ event->dtEnd(), event->doesFloat(), false );
} else if ( event->hasDuration() ) {
mEndCaption = i18n("Duration: ");
int mins = event->duration() / 60;
@@ -160,18 +162,18 @@ class TimePrintStringsVisitor : public IncidenceBase::Visitor
}
bool visit( Todo *todo ) {
if ( todo->hasStartDate() ) {
- mStartCaption = i18n("Start date: ");
- // Show date/time or only date, depending on whether it's an all-day event
-// TODO: Add shortfmt param to dtStartStr, dtEndStr and dtDueStr!!!
- mStartString = (todo->doesFloat()) ? (todo->dtStartDateStr(false)) : (todo->dtStartStr());
+ mStartCaption = i18n( "Start date: " );
+ mStartString = IncidenceFormatter::dateTimeToString(
+ todo->dtStart(), todo->doesFloat(), false );
} else {
- mStartCaption = i18n("No start date");
+ mStartCaption = i18n( "No start date" );
mStartString = TQString::null;
}
-
+
if ( todo->hasDueDate() ) {
- mEndCaption = i18n("Due date: ");
- mEndString = (todo->doesFloat()) ? (todo->dtDueDateStr(false)) : (todo->dtDueStr());
+ mEndCaption = i18n( "Due date: " );
+ mEndString = IncidenceFormatter::dateTimeToString(
+ todo->dtDue(), todo->doesFloat(), false );
} else {
mEndCaption = i18n("No due date");
mEndString = TQString::null;
@@ -179,9 +181,9 @@ class TimePrintStringsVisitor : public IncidenceBase::Visitor
return true;
}
bool visit( Journal *journal ) {
- mStartCaption = i18n("Start date: ");
-// TODO: Add shortfmt param to dtStartStr, dtEndStr and dtDueStr!!!
- mStartString = (journal->doesFloat()) ? (journal->dtStartDateStr(false)) : (journal->dtStartStr());
+ mStartCaption = i18n( "Start date: " );
+ mStartString = IncidenceFormatter::dateTimeToString(
+ journal->dtStart(), journal->doesFloat(), false );
mEndCaption = TQString::null;
mEndString = TQString::null;
return true;
@@ -210,8 +212,6 @@ int CalPrintIncidence::printCaptionAndText( TQPainter &p, const TQRect &box, con
#include <tqfontdatabase.h>
void CalPrintIncidence::print( TQPainter &p, int width, int height )
{
- KLocale *local = KGlobal::locale();
-
TQFont oldFont(p.font());
TQFont textFont( "sans-serif", 11, TQFont::Normal );
TQFont captionFont( "sans-serif", 11, TQFont::Bold );
@@ -267,7 +267,7 @@ void CalPrintIncidence::print( TQPainter &p, int width, int height )
TQRect timesBox( titleBox );
timesBox.setTop( titleBox.bottom() + padding() );
timesBox.setHeight( height / 8 );
-
+
TimePrintStringsVisitor stringVis;
int h = timesBox.top();
if ( stringVis.act(*it) ) {
@@ -279,28 +279,41 @@ void CalPrintIncidence::print( TQPainter &p, int width, int height )
textRect.setRight( timesBox.right() - padding() );
h = QMAX( printCaptionAndText( p, textRect, stringVis.mEndCaption, stringVis.mEndString, captionFont, textFont ), h );
}
-
-
+
+ // Convert recurrence to a string
if ( (*it)->doesRecur() ) {
TQRect recurBox( timesBox.left()+padding(), h+padding(), timesBox.right()-padding(), lineHeight );
- // TODO: Convert the recurrence to a string and print it out!
- TQString recurString( "TODO: Convert Repeat to String!" );
- h = QMAX( printCaptionAndText( p, recurBox, i18n("Repeats: "), recurString, captionFont, textFont ), h );
+ KCal::Recurrence *recurs = (*it)->recurrence();
+
+ TQString displayString = IncidenceFormatter::recurrenceString((*it));
+ // exception dates
+ TQString exceptString;
+ if ( !recurs->exDates().isEmpty() ) {
+ exceptString = i18n("except for listed dates", " except");
+ for ( uint i = 0; i < recurs->exDates().size(); i++ ) {
+ exceptString.append(" ");
+ exceptString.append( KGlobal::locale()->formatDate(recurs->exDates()[i],
+ true) );
+ }
+ }
+ displayString.append(exceptString);
+ h = QMAX( printCaptionAndText( p, recurBox, i18n( "Repeats: "), displayString, captionFont, textFont ), h );
}
-
+
+ // Alarms Printing
TQRect alarmBox( timesBox.left()+padding(), h+padding(), timesBox.right()-padding(), lineHeight );
Alarm::List alarms = (*it)->alarms();
if ( alarms.count() == 0 ) {
cap = i18n("No reminders");
- txt = TQString::null;
+ txt = TQString();
} else {
cap = i18n("Reminder: ", "%n reminders: ", alarms.count() );
-
+
TQStringList alarmStrings;
KCal::Alarm::List::ConstIterator it;
for ( it = alarms.begin(); it != alarms.end(); ++it ) {
Alarm *alarm = *it;
-
+
// Alarm offset, copied from koeditoralarms.cpp:
TQString offsetstr;
int offset = 0;
@@ -345,7 +358,7 @@ void CalPrintIncidence::print( TQPainter &p, int width, int height )
TQRect organizerBox( timesBox.left()+padding(), h+padding(), timesBox.right()-padding(), lineHeight );
h = QMAX( printCaptionAndText( p, organizerBox, i18n("Organizer: "), (*it)->organizer().fullName(), captionFont, textFont ), h );
-
+
// Finally, draw the frame around the time information...
timesBox.setBottom( QMAX( timesBox.bottom(), h+padding() ) );
drawBox( p, BOX_BORDER_WIDTH, timesBox );
@@ -360,43 +373,67 @@ void CalPrintIncidence::print( TQPainter &p, int width, int height )
// Now start constructing the boxes from the bottom:
- TQRect categoriesBox( locationBox );
- categoriesBox.setBottom( box.bottom() );
- categoriesBox.setTop( categoriesBox.bottom() - lineHeight - 2*padding() );
+ TQRect footerBox( locationBox );
+ footerBox.setBottom( box.bottom() );
+ footerBox.setTop( footerBox.bottom() - lineHeight - 2*padding() );
+ TQRect categoriesBox( footerBox );
+ categoriesBox.setBottom( footerBox.top() );
+ categoriesBox.setTop( categoriesBox.bottom() - lineHeight - 2*padding() );
TQRect attendeesBox( box.left(), categoriesBox.top()-padding()-box.height()/9, box.width(), box.height()/9 );
- if ( !mShowAttendees ) {
- attendeesBox.setTop( categoriesBox.top() );
- }
+
TQRect attachmentsBox( box.left(), attendeesBox.top()-padding()-box.height()/9, box.width()*3/4 - padding(), box.height()/9 );
TQRect optionsBox( attachmentsBox.right() + padding(), attachmentsBox.top(), 0, 0 );
optionsBox.setRight( box.right() );
optionsBox.setBottom( attachmentsBox.bottom() );
TQRect notesBox( optionsBox.left(), locationBox.bottom() + padding(), optionsBox.width(), 0 );
notesBox.setBottom( optionsBox.top() - padding() );
-
- // TODO: Adjust boxes depending on the show options...
-// if ( !mShowOptions ) {
-// optionsBox.left()
-// bool mShowOptions;
-// // bool mShowSubitemsNotes;
-// bool mShowAttendees;
-// bool mShowAttachments;
-
TQRect descriptionBox( notesBox );
descriptionBox.setLeft( box.left() );
- descriptionBox.setRight( mShowOptions?(attachmentsBox.right()):(box.right()) );
+ descriptionBox.setRight( attachmentsBox.right() );
+ // Adjust boxes depending on the show options...
+ if (!mShowSubitemsNotes) {
+ descriptionBox.setRight( box.right() );
+ }
+ if (!mShowAttachments || !mShowAttendees) {
+ descriptionBox.setBottom( attachmentsBox.bottom() );
+ optionsBox.setTop( attendeesBox.top() );
+ optionsBox.setBottom( attendeesBox.bottom() );
+ notesBox.setBottom( attachmentsBox.bottom() );
+ if (mShowOptions) {
+ attendeesBox.setRight( attachmentsBox.right() );
+ }
+ if (!mShowAttachments && !mShowAttendees) {
+ if (mShowSubitemsNotes) {
+ descriptionBox.setBottom( attendeesBox.bottom() );
+ }
+ if (!mShowOptions) {
+ descriptionBox.setBottom( attendeesBox.bottom() );
+ notesBox.setBottom( attendeesBox.bottom() );
+ }
+ }
+ }
+ if (mShowAttachments) {
+ if (!mShowOptions) {
+ attachmentsBox.setRight( box.right() );
+ attachmentsBox.setRight( box.right() );
+ }
+ if (!mShowAttendees) {
+ attachmentsBox.setTop( attendeesBox.top() );
+ attachmentsBox.setBottom( attendeesBox.bottom() );
+ }
+ }
- drawBoxWithCaption( p, descriptionBox, i18n("Description:"),
- (*it)->description(), /*sameLine=*/false,
+ drawBoxWithCaption( p, descriptionBox, i18n("Description:"),
+ (*it)->description(), /*sameLine=*/false,
/*expand=*/false, captionFont, textFont );
-
+
if ( mShowSubitemsNotes ) {
if ( (*it)->relations().isEmpty() || (*it)->type() != "Todo" ) {
- int notesPosition = drawBoxWithCaption( p, notesBox, i18n("Notes:"),
- TQString::null, /*sameLine=*/false, /*expand=*/false,
+ int notesPosition = drawBoxWithCaption( p, notesBox, i18n("Notes:"),
+ TQString::null, /*sameLine=*/false, /*expand=*/false,
captionFont, textFont );
TQPen oldPen( p.pen() );
p.setPen( Qt::DotLine );
@@ -405,18 +442,104 @@ void CalPrintIncidence::print( TQPainter &p, int width, int height )
}
p.setPen( oldPen );
} else {
- int subitemsStart = drawBoxWithCaption( p, notesBox, i18n("Subitems:"),
- (*it)->description(), /*sameLine=*/false,
+ Incidence::List relations = (*it)->relations();
+ TQString subitemCaption;
+ if ( relations.count() == 0 ) {
+ subitemCaption = i18n( "No Subitems" );
+ txt == "";
+ } else {
+ subitemCaption = i18n( "1 Subitem:",
+ "%1 Subitems:",
+ relations.count() );
+ }
+ Incidence::List::ConstIterator rit;
+ TQString subitemString;
+ TQString statusString;
+ TQString datesString;
+ int count = 0;
+ for ( rit = relations.begin(); rit != relations.end(); ++rit ) {
+ ++count;
+ if ( !(*rit) ) { // defensive, skip any zero pointers
+ continue;
+ }
+ // format the status
+ statusString = (*rit)->statusStr();
+ if ( statusString.isEmpty() ) {
+ if ( (*rit)->status() == Incidence::StatusNone ) {
+ statusString = i18n( "no status", "none" );
+ } else {
+ statusString = i18n( "unknown status", "unknown" );
+ }
+ }
+ // format the dates if provided
+ datesString = "";
+ if ( (*rit)->dtStart().isValid() ) {
+ datesString += i18n(
+ "Start Date: %1\n").arg(
+ KGlobal::locale()->formatDate( (*rit)->dtStart().date(),
+ true ) );
+ if ( !(*rit)->doesFloat() ) {
+ datesString += i18n(
+ "Start Time: %1\n").arg(
+ KGlobal::locale()->formatTime((*rit)->dtStart().time(),
+ false, false) );
+ }
+ }
+ if ( (*rit)->dtEnd().isValid() ) {
+ subitemString += i18n(
+ "Due Date: %1\n").arg(
+ KGlobal::locale()->formatDate( (*rit)->dtEnd().date(),
+ true ) );
+ if ( !(*rit)->doesFloat() ) {
+ subitemString += i18n(
+ "subitem due time", "Due Time: %1\n").arg(
+ KGlobal::locale()->formatTime((*rit)->dtEnd().time(),
+ false, false) );
+ }
+ }
+ subitemString += i18n("subitem counter", "%1: ", count);
+ subitemString += (*rit)->summary();
+ subitemString += "\n";
+ if ( !datesString.isEmpty() ) {
+ subitemString += datesString;
+ subitemString += "\n";
+ }
+ subitemString += i18n( "subitem Status: statusString",
+ "Status: %1\n").arg( statusString );
+ subitemString += IncidenceFormatter::recurrenceString((*rit)) + "\n";
+ subitemString += i18n( "subitem Priority: N",
+ "Priority: %1\n").arg( (*rit)->priority() );
+ subitemString += i18n( "subitem Secrecy: secrecyString",
+ "Secrecy: %1\n").arg( (*rit)->secrecyStr() );
+ subitemString += "\n";
+ }
+ drawBoxWithCaption( p, notesBox, i18n("Subitems:"),
+ (*it)->description(), /*sameLine=*/false,
/*expand=*/false, captionFont, textFont );
- // TODO: Draw subitems
}
}
if ( mShowAttachments ) {
- int attachStart = drawBoxWithCaption( p, attachmentsBox,
- i18n("Attachments:"), TQString::null, /*sameLine=*/false,
- /*expand=*/false, captionFont, textFont );
- // TODO: Print out the attachments somehow
+ Attachment::List attachments = (*it)->attachments();
+ TQString attachmentCaption;
+ if ( attachments.count() == 0 ) {
+ attachmentCaption = i18n( "No Attachments" );
+ txt = TQString();
+ } else {
+ attachmentCaption = i18n( "1 Attachment:", "%1 Attachments:", attachments.count() );
+ }
+ TQString attachmentString;
+ Attachment::List::ConstIterator ait = attachments.begin();
+ for ( ; ait != attachments.end(); ++ait ) {
+ if (!attachmentString.isEmpty()) {
+ attachmentString += i18n( "Spacer for list of attachments", " " );
+ }
+ attachmentString.append((*ait)->label());
+ }
+ drawBoxWithCaption( p, attachmentsBox,
+ attachmentCaption, attachmentString,
+ /*sameLine=*/false, /*expand=*/false,
+ captionFont, textFont );
}
if ( mShowAttendees ) {
@@ -436,7 +559,7 @@ void CalPrintIncidence::print( TQPainter &p, int width, int height )
.arg( (*ait)->fullName() )
.arg( (*ait)->roleStr() ).arg( (*ait)->statusStr() );
}
- drawBoxWithCaption( p, attendeesBox, i18n("Attendees:"), attendeeString,
+ drawBoxWithCaption( p, attendeesBox, i18n("Attendees:"), attendeeString,
/*sameLine=*/false, /*expand=*/false, captionFont, textFont );
}
@@ -470,10 +593,12 @@ void CalPrintIncidence::print( TQPainter &p, int width, int height )
drawBoxWithCaption( p, optionsBox, i18n("Settings: "),
optionsString, /*sameLine=*/false, /*expand=*/false, captionFont, textFont );
}
-
+
drawBoxWithCaption( p, categoriesBox, i18n("Categories: "),
(*it)->categories().join( i18n("Spacer for the joined list of categories", ", ") ),
/*sameLine=*/true, /*expand=*/false, captionFont, textFont );
+
+ drawFooter( p, footerBox );
}
p.setFont( oldFont );
}
@@ -570,6 +695,12 @@ void CalPrintDay::print( TQPainter &p, int width, int height )
{
TQDate curDay( mFromDate );
+ TQRect headerBox( 0, 0, width, headerHeight() );
+ TQRect footerBox( 0, height - footerHeight(), width, footerHeight() );
+ height -= footerHeight();
+
+ KLocale *local = KGlobal::locale();
+
do {
TQTime curStartTime( mStartTime );
TQTime curEndTime( mEndTime );
@@ -581,35 +712,89 @@ void CalPrintDay::print( TQPainter &p, int width, int height )
curEndTime = curStartTime.addSecs( 3600 );
}
- KLocale *local = KGlobal::locale();
- TQRect headerBox( 0, 0, width, headerHeight() );
drawHeader( p, local->formatDate( curDay ), curDay, TQDate(), headerBox );
-
-
Event::List eventList = mCalendar->events( curDay,
EventSortStartDate,
SortDirectionAscending );
- p.setFont( TQFont( "sans-serif", 12 ) );
+ // split out the all day events as they will be printed in a separate box
+ Event::List alldayEvents, timedEvents;
+ Event::List::ConstIterator it;
+ for ( it = eventList.begin(); it != eventList.end(); ++it ) {
+ if ( (*it)->doesFloat() ) {
+ alldayEvents.append( *it );
+ } else {
+ timedEvents.append( *it );
+ }
+ }
+
+ int fontSize = 11;
+ TQFont textFont( "sans-serif", fontSize, TQFont::Normal );
+ p.setFont( textFont );
+ uint lineSpacing = p.fontMetrics().lineSpacing();
- // TODO: Find a good way to determine the height of the all-day box
+ uint maxAllDayEvents = 8; // the max we allow to be printed, sorry.
+ uint allDayHeight = QMIN( alldayEvents.count(), maxAllDayEvents ) * lineSpacing;
+ allDayHeight = QMAX( allDayHeight, ( 5 * lineSpacing ) ) + ( 2 * padding() );
TQRect allDayBox( TIMELINE_WIDTH + padding(), headerBox.bottom() + padding(),
- 0, height / 20 );
- allDayBox.setRight( width );
- int allDayHeight = drawAllDayBox( p, eventList, curDay, true, allDayBox );
+ width - TIMELINE_WIDTH - padding(), allDayHeight );
+ if ( alldayEvents.count() > 0 ) {
+ // draw the side bar for all-day events
+ TQFont oldFont( p.font() );
+ p.setFont( TQFont( "sans-serif", 9, TQFont::Normal ) );
+ drawVerticalBox( p,
+ BOX_BORDER_WIDTH,
+ TQRect( 0, headerBox.bottom() + padding(), TIMELINE_WIDTH, allDayHeight ),
+ i18n( "Today's Events" ),
+ TQt::AlignHCenter | TQt::AlignVCenter | TQt::WordBreak );
+ p.setFont( oldFont );
+
+ // now draw at most maxAllDayEvents in the all-day box
+ drawBox( p, BOX_BORDER_WIDTH, allDayBox );
+
+ Event::List::ConstIterator it;
+ TQRect eventBox( allDayBox );
+ eventBox.setLeft( TIMELINE_WIDTH + ( 2 * padding() ) );
+ eventBox.setTop( eventBox.top() + padding() );
+ eventBox.setBottom( eventBox.top() + lineSpacing );
+ uint count = 0;
+ for ( it = alldayEvents.begin(); it != alldayEvents.end(); ++it ) {
+ if ( count == maxAllDayEvents ) {
+ break;
+ }
+ count++;
+ TQString str;
+ if ( (*it)->location().isEmpty() ) {
+ str = cleanStr( (*it)->summary() );
+ } else {
+ str = i18n( "summary, location", "%1, %2" ).
+ arg( cleanStr( (*it)->summary() ), cleanStr( (*it)->location() ) );
+ }
+ printEventString( p, eventBox, str );
+ eventBox.setTop( eventBox.bottom() );
+ eventBox.setBottom( eventBox.top() + lineSpacing );
+ }
+ } else {
+ allDayBox.setBottom( headerBox.bottom() );
+ }
TQRect dayBox( allDayBox );
- dayBox.setTop( allDayHeight /*allDayBox.bottom()*/ );
+ dayBox.setTop( allDayBox.bottom() + padding() );
dayBox.setBottom( height );
- drawAgendaDayBox( p, eventList, curDay, mIncludeAllEvents,
+ drawAgendaDayBox( p, timedEvents, curDay, mIncludeAllEvents,
curStartTime, curEndTime, dayBox );
TQRect tlBox( dayBox );
tlBox.setLeft( 0 );
tlBox.setWidth( TIMELINE_WIDTH );
drawTimeLine( p, curStartTime, curEndTime, tlBox );
+
+ drawFooter( p, footerBox );
+
curDay = curDay.addDays( 1 );
- if ( curDay <= mToDate ) mPrinter->newPage();
+ if ( curDay <= mToDate ) {
+ mPrinter->newPage();
+ }
} while ( curDay <= mToDate );
}
@@ -728,6 +913,9 @@ void CalPrintWeek::print( TQPainter &p, int width, int height )
TQString line1, line2, title;
TQRect headerBox( 0, 0, width, headerHeight() );
+ TQRect footerBox( 0, height - footerHeight(), width, footerHeight() );
+ height -= footerHeight();
+
TQRect weekBox( headerBox );
weekBox.setTop( headerBox.bottom() + padding() );
weekBox.setBottom( height );
@@ -744,7 +932,11 @@ void CalPrintWeek::print( TQPainter &p, int width, int height )
}
title = title.arg( line1 ).arg( line2 );
drawHeader( p, title, curWeek.addDays( -6 ), TQDate(), headerBox );
+
drawWeek( p, curWeek, weekBox );
+
+ drawFooter( p, footerBox );
+
curWeek = curWeek.addDays( 7 );
if ( curWeek <= toWeek )
mPrinter->newPage();
@@ -763,11 +955,14 @@ void CalPrintWeek::print( TQPainter &p, int width, int height )
}
title = title.arg( line1 ).arg( line2 ).arg( curWeek.weekNumber() );
drawHeader( p, title, curWeek, TQDate(), headerBox );
+
TQRect weekBox( headerBox );
weekBox.setTop( headerBox.bottom() + padding() );
weekBox.setBottom( height );
-
drawTimeTable( p, fromWeek, curWeek, mStartTime, mEndTime, weekBox );
+
+ drawFooter( p, footerBox );
+
fromWeek = fromWeek.addDays( 7 );
curWeek = fromWeek.addDays( 6 );
if ( curWeek <= toWeek )
@@ -792,6 +987,8 @@ void CalPrintWeek::print( TQPainter &p, int width, int height )
drawTimeTable( p, endLeft.addDays( 1 ), curWeek,
mStartTime, mEndTime, weekBox1 );
+ drawFooter( p, footerBox );
+
fromWeek = fromWeek.addDays( 7 );
curWeek = fromWeek.addDays( 6 );
if ( curWeek <= toWeek )
@@ -910,6 +1107,9 @@ void CalPrintMonth::print( TQPainter &p, int width, int height )
if ( !calSys ) return;
TQRect headerBox( 0, 0, width, headerHeight() );
+ TQRect footerBox( 0, height - footerHeight(), width, footerHeight() );
+ height -= footerHeight();
+
TQRect monthBox( 0, 0, width, height );
monthBox.setTop( headerBox.bottom() + padding() );
@@ -924,6 +1124,9 @@ void CalPrintMonth::print( TQPainter &p, int width, int height )
drawHeader( p, title, curMonth.addMonths( -1 ), curMonth.addMonths( 1 ),
headerBox );
drawMonthTable( p, curMonth, mWeekNumbers, mRecurDaily, mRecurWeekly, monthBox );
+
+ drawFooter( p, footerBox );
+
curMonth = curMonth.addDays( curMonth.daysInMonth() );
if ( curMonth <= toMonth ) mPrinter->newPage();
} while ( curMonth <= toMonth );
@@ -1054,30 +1257,32 @@ void CalPrintTodos::saveConfig()
void CalPrintTodos::print( TQPainter &p, int width, int height )
{
// TODO: Find a good way to guarantee a nicely designed output
- int pospriority = 10;
- int possummary = 60;
+ int pospriority = 0;
+ int possummary = 100;
int posdue = width - 65;
int poscomplete = posdue - 70; //Complete column is to right of the Due column
int lineSpacing = 15;
int fontHeight = 10;
+ TQRect headerBox( 0, 0, width, headerHeight() );
+ TQRect footerBox( 0, height - footerHeight(), width, footerHeight() );
+ height -= footerHeight();
+
// Draw the First Page Header
- drawHeader( p, mPageTitle, mFromDate, TQDate(),
- TQRect( 0, 0, width, headerHeight() ) );
+ drawHeader( p, mPageTitle, mFromDate, TQDate(), headerBox );
// Draw the Column Headers
int mCurrentLinePos = headerHeight() + 5;
TQString outStr;
TQFont oldFont( p.font() );
- p.setFont( TQFont( "sans-serif", 10, TQFont::Bold ) );
+ p.setFont( TQFont( "sans-serif", 9, TQFont::Bold ) );
lineSpacing = p.fontMetrics().lineSpacing();
mCurrentLinePos += lineSpacing;
if ( mIncludePriority ) {
outStr += i18n( "Priority" );
p.drawText( pospriority, mCurrentLinePos - 2, outStr );
} else {
- possummary = 10;
pospriority = -1;
}
@@ -1179,8 +1384,9 @@ void CalPrintTodos::print( TQPainter &p, int width, int height )
0, 0, mCurrentLinePos, width, height, todoList );
}
}
+
+ drawFooter( p, footerBox );
p.setFont( oldFont );
}
-
#endif
diff --git a/korganizer/printing/calprintdefaultplugins.h b/korganizer/printing/calprintdefaultplugins.h
index 79a909a87..a16526433 100644
--- a/korganizer/printing/calprintdefaultplugins.h
+++ b/korganizer/printing/calprintdefaultplugins.h
@@ -42,10 +42,20 @@ class CalPrintIncidence : public CalPrintPluginBase
public:
CalPrintIncidence();
virtual ~CalPrintIncidence();
- virtual TQString description() { return i18n("Print &incidence"); }
- virtual TQString info() { return i18n("Prints an incidence on one page"); }
- virtual int sortID() { return CalPrinterBase::Incidence; }
- // Enable the Print Incidence option only if there are selected incidences.
+ virtual TQString description()
+ {
+ return i18n( "Print &incidence" );
+ }
+ virtual TQString info()
+ {
+ return i18n( "Prints an incidence on one page" );
+ }
+ virtual int sortID()
+ {
+ return CalPrinterBase::Incidence;
+ }
+
+ // Enable the Print Incidence option only if there are selected incidences.
virtual bool enabled()
{
if ( mSelectedIncidences.count() > 0 ) {
@@ -54,9 +64,11 @@ class CalPrintIncidence : public CalPrintPluginBase
return false;
}
}
- virtual TQWidget *createConfigWidget(TQWidget*);
+ virtual TQWidget *createConfigWidget( TQWidget * );
virtual KPrinter::Orientation defaultOrientation()
- { return KPrinter::Portrait; }
+ {
+ return KPrinter::Portrait;
+ }
public:
void print( TQPainter &p, int width, int height );
@@ -66,7 +78,7 @@ class CalPrintIncidence : public CalPrintPluginBase
virtual void saveConfig();
protected:
int printCaptionAndText( TQPainter &p, const TQRect &box, const TQString &caption,
- const TQString &text, TQFont captionFont, TQFont textFont );
+ const TQString &text, TQFont captionFont, TQFont textFont );
protected:
@@ -82,10 +94,22 @@ class CalPrintDay : public CalPrintPluginBase
public:
CalPrintDay();
virtual ~CalPrintDay();
- virtual TQString description() { return i18n("Print da&y"); }
- virtual TQString info() { return i18n("Prints all events of a single day on one page"); }
- virtual int sortID() { return CalPrinterBase::Day; }
- virtual bool enabled() { return true; }
+ virtual TQString description()
+ {
+ return i18n( "Print da&y" );
+ }
+ virtual TQString info()
+ {
+ return i18n( "Prints all events of a single day on one page" );
+ }
+ virtual int sortID()
+ {
+ return CalPrinterBase::Day;
+ }
+ virtual bool enabled()
+ {
+ return true;
+ }
virtual TQWidget *createConfigWidget( TQWidget* );
public:
@@ -107,11 +131,24 @@ class CalPrintWeek : public CalPrintPluginBase
public:
CalPrintWeek();
virtual ~CalPrintWeek();
- virtual TQString description() { return i18n("Print &week"); }
- virtual TQString info() { return i18n("Prints all events of one week on one page"); }
- virtual int sortID() { return CalPrinterBase::Week; }
- virtual bool enabled() { return true; }
- virtual TQWidget *createConfigWidget(TQWidget*);
+ virtual TQString description()
+ {
+ return i18n( "Print &week" );
+ }
+ virtual TQString info()
+ {
+ return i18n( "Prints all events of one week on one page" );
+ }
+ virtual int sortID()
+ {
+ return CalPrinterBase::Week;
+ }
+ virtual bool enabled()
+ {
+ return true;
+ }
+ virtual TQWidget *createConfigWidget( TQWidget * );
+
/**
Returns the default orientation for the eWeekPrintType.
*/
@@ -136,12 +173,28 @@ class CalPrintMonth : public CalPrintPluginBase
public:
CalPrintMonth();
virtual ~CalPrintMonth();
- virtual TQString description() { return i18n("Print mont&h"); }
- virtual TQString info() { return i18n("Prints all events of one month on one page"); }
- virtual int sortID() { return CalPrinterBase::Month; }
- virtual bool enabled() { return true; }
- virtual TQWidget *createConfigWidget(TQWidget*);
- virtual KPrinter::Orientation defaultOrientation() { return KPrinter::Landscape; }
+ virtual TQString description()
+ {
+ return i18n( "Print mont&h" );
+ }
+ virtual TQString info()
+ {
+ return i18n( "Prints all events of one month on one page" );
+ }
+ virtual int sortID()
+ {
+ return CalPrinterBase::Month;
+ }
+ virtual bool enabled()
+ {
+ return true;
+ }
+ virtual TQWidget *createConfigWidget( TQWidget * );
+ virtual KPrinter::Orientation defaultOrientation()
+ {
+ return KPrinter::Landscape;
+ }
+
public:
void print(TQPainter &p, int width, int height);
@@ -163,11 +216,23 @@ class CalPrintTodos : public CalPrintPluginBase
public:
CalPrintTodos();
virtual ~CalPrintTodos();
- virtual TQString description() { return i18n("Print to-&dos"); }
- virtual TQString info() { return i18n("Prints all to-dos in a (tree-like) list"); }
- virtual int sortID() { return CalPrinterBase::Todolist; }
- virtual bool enabled() { return true; }
- virtual TQWidget *createConfigWidget(TQWidget*);
+ virtual TQString description()
+ {
+ return i18n( "Print to-&dos" );
+ }
+ virtual TQString info()
+ {
+ return i18n( "Prints all to-dos in a (tree-like) list" );
+ }
+ virtual int sortID()
+ {
+ return CalPrinterBase::Todolist;
+ }
+ virtual bool enabled()
+ {
+ return true;
+ }
+ virtual TQWidget *createConfigWidget( TQWidget * );
public:
void print( TQPainter &p, int width, int height );
@@ -180,18 +245,23 @@ class CalPrintTodos : public CalPrintPluginBase
TQString mPageTitle;
enum eTodoPrintType {
- TodosAll = 0, TodosUnfinished, TodosDueRange
+ TodosAll = 0,
+ TodosUnfinished,
+ TodosDueRange
} mTodoPrintType;
enum eTodoSortField {
- TodoFieldSummary=0,
- TodoFieldStartDate, TodoFieldDueDate,
- TodoFieldPriority, TodoFieldPercentComplete,
+ TodoFieldSummary = 0,
+ TodoFieldStartDate,
+ TodoFieldDueDate,
+ TodoFieldPriority,
+ TodoFieldPercentComplete,
TodoFieldUnset
} mTodoSortField;
enum eTodoSortDirection {
- TodoDirectionAscending=0, TodoDirectionDescending,
+ TodoDirectionAscending = 0,
+ TodoDirectionDescending,
TodoDirectionUnset
} mTodoSortDirection;
@@ -205,5 +275,7 @@ class CalPrintTodos : public CalPrintPluginBase
bool mSortDirection;
};
+
#endif
+
#endif
diff --git a/korganizer/printing/calprintpluginbase.cpp b/korganizer/printing/calprintpluginbase.cpp
index 6f6762032..e16e72c6b 100644
--- a/korganizer/printing/calprintpluginbase.cpp
+++ b/korganizer/printing/calprintpluginbase.cpp
@@ -39,9 +39,16 @@
#ifndef KORG_NOPRINTER
inline int round(const double x)
- {
- return int(x > 0.0 ? x + 0.5 : x - 0.5);
- }
+{
+ return int(x > 0.0 ? x + 0.5 : x - 0.5);
+}
+
+static TQString cleanStr( const TQString &instr )
+{
+ TQString ret = instr;
+ return ret.replace( '\n', ' ' );
+}
+
/******************************************************************
** The Todo positioning structure **
******************************************************************/
@@ -108,8 +115,8 @@ class PrintCellItem : public KOrg::CellItem
CalPrintPluginBase::CalPrintPluginBase() : PrintPlugin(), mUseColors( true ),
- mHeaderHeight(-1), mSubHeaderHeight( SUBHEADER_HEIGHT ),
- mMargin( MARGIN_SIZE ), mPadding( PADDING_SIZE), mCalSys( 0 )
+ mHeaderHeight( -1 ), mSubHeaderHeight( SUBHEADER_HEIGHT ), mFooterHeight( -1 ),
+ mMargin( MARGIN_SIZE ), mPadding( PADDING_SIZE), mCalSys( 0 )
{
}
CalPrintPluginBase::~CalPrintPluginBase()
@@ -245,9 +252,9 @@ void CalPrintPluginBase::setCategoryColors( TQPainter &p, Incidence *incidence )
TQColor CalPrintPluginBase::categoryBgColor( Incidence *incidence )
{
- if (mCoreHelper && incidence)
+ if (mCoreHelper && incidence)
return mCoreHelper->categoryColor( incidence->categories() );
- else
+ else
return TQColor();
}
@@ -314,6 +321,20 @@ void CalPrintPluginBase::setSubHeaderHeight( const int height )
mSubHeaderHeight = height;
}
+int CalPrintPluginBase::footerHeight() const
+{
+ if ( mFooterHeight >= 0 )
+ return mFooterHeight;
+ else if ( orientation() == KPrinter::Portrait )
+ return PORTRAIT_FOOTER_HEIGHT;
+ else
+ return LANDSCAPE_FOOTER_HEIGHT;
+}
+void CalPrintPluginBase::setFooterHeight( const int height )
+{
+ mFooterHeight = height;
+}
+
int CalPrintPluginBase::margin() const
{
return mMargin;
@@ -370,7 +391,8 @@ void CalPrintPluginBase::printEventString( TQPainter &p, const TQRect &box, cons
}
-void CalPrintPluginBase::showEventBox( TQPainter &p, const TQRect &box, Incidence *incidence, const TQString &str, int flags )
+void CalPrintPluginBase::showEventBox( TQPainter &p, int linewidth, const TQRect &box,
+ Incidence *incidence, const TQString &str, int flags )
{
TQPen oldpen( p.pen() );
TQBrush oldbrush( p.brush() );
@@ -380,7 +402,7 @@ void CalPrintPluginBase::showEventBox( TQPainter &p, const TQRect &box, Incidenc
} else {
p.setBrush( TQColor( 232, 232, 232 ) );
}
- drawBox( p, EVENT_BORDER_WIDTH, box );
+ drawBox( p, ( linewidth > 0 ) ? linewidth : EVENT_BORDER_WIDTH, box );
if ( mUseColors && bgColor.isValid() ) {
p.setPen( textColor( bgColor ) );
@@ -391,8 +413,7 @@ void CalPrintPluginBase::showEventBox( TQPainter &p, const TQRect &box, Incidenc
}
-void CalPrintPluginBase::drawSubHeaderBox(TQPainter &p, const TQString &str,
- const TQRect &box )
+void CalPrintPluginBase::drawSubHeaderBox(TQPainter &p, const TQString &str, const TQRect &box )
{
drawShadedBox( p, BOX_BORDER_WIDTH, TQColor( 232, 232, 232 ), box );
TQFont oldfont( p.font() );
@@ -401,12 +422,14 @@ void CalPrintPluginBase::drawSubHeaderBox(TQPainter &p, const TQString &str,
p.setFont( oldfont );
}
-void CalPrintPluginBase::drawVerticalBox( TQPainter &p, const TQRect &box, const TQString &str )
+void CalPrintPluginBase::drawVerticalBox( TQPainter &p, int linewidth, const TQRect &box,
+ const TQString &str, int flags )
{
p.save();
p.rotate( -90 );
TQRect rotatedBox( -box.top()-box.height(), box.left(), box.height(), box.width() );
- showEventBox( p, rotatedBox, 0, str, Qt::AlignLeft | Qt::AlignVCenter | Qt::SingleLine );
+ showEventBox( p, linewidth, rotatedBox, 0, str,
+ ( flags == -1 ) ? Qt::AlignLeft | Qt::AlignVCenter | Qt::SingleLine : flags );
p.restore();
}
@@ -414,10 +437,10 @@ void CalPrintPluginBase::drawVerticalBox( TQPainter &p, const TQRect &box, const
///////////////////////////////////////////////////////////////////////////////
-// Return value: If expand, bottom of the printed box, otherwise vertical end
+// Return value: If expand, bottom of the printed box, otherwise vertical end
// of the printed contents inside the box.
-int CalPrintPluginBase::drawBoxWithCaption( TQPainter &p, const TQRect &allbox,
+int CalPrintPluginBase::drawBoxWithCaption( TQPainter &p, const TQRect &allbox,
const TQString &caption, const TQString &contents, bool sameLine, bool expand, const TQFont &captionFont, const TQFont &textFont )
{
TQFont oldFont( p.font() );
@@ -428,17 +451,17 @@ int CalPrintPluginBase::drawBoxWithCaption( TQPainter &p, const TQRect &allbox,
TQRect box( allbox );
-
+
// Bounding rectangle for caption, single-line, clip on the right
TQRect captionBox( box.left() + padding(), box.top() + padding(), 0, 0 );
p.setFont( captionFont );
captionBox = p.boundingRect( captionBox, Qt::AlignLeft | Qt::AlignTop | Qt::SingleLine, caption );
p.setFont( oldFont );
- if ( captionBox.right() > box.right() )
+ if ( captionBox.right() > box.right() )
captionBox.setRight( box.right() );
- if ( expand && captionBox.bottom() + padding() > box.bottom() )
+ if ( expand && captionBox.bottom() + padding() > box.bottom() )
box.setBottom( captionBox.bottom() + padding() );
-
+
// Bounding rectangle for the contents (if any), word break, clip on the bottom
TQRect textBox( captionBox );
if ( !contents.isEmpty() ) {
@@ -460,7 +483,7 @@ int CalPrintPluginBase::drawBoxWithCaption( TQPainter &p, const TQRect &allbox,
}
}
}
-
+
drawBox( p, BOX_BORDER_WIDTH, box );
p.setFont( captionFont );
p.drawText( captionBox, Qt::AlignLeft | Qt::AlignTop | Qt::SingleLine, caption );
@@ -469,7 +492,7 @@ int CalPrintPluginBase::drawBoxWithCaption( TQPainter &p, const TQRect &allbox,
p.drawText( textBox, Qt::WordBreak | Qt::AlignTop | Qt::AlignLeft, contents );
}
p.setFont( oldFont );
-
+
if ( expand ) {
return box.bottom();
} else {
@@ -494,8 +517,8 @@ int CalPrintPluginBase::drawHeader( TQPainter &p, TQString title,
TQRect textRect( allbox );
textRect.addCoords( 5, 0, 0, 0 );
textRect.setRight( right );
-
-
+
+
TQFont oldFont( p.font() );
TQFont newFont("sans-serif", (textRect.height()<60)?16:18, TQFont::Bold);
if ( expand ) {
@@ -525,11 +548,24 @@ int CalPrintPluginBase::drawHeader( TQPainter &p, TQString title,
p.setFont( newFont );
p.drawText( textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::WordBreak, title );
p.setFont( oldFont );
-
+
return textRect.bottom();
}
+int CalPrintPluginBase::drawFooter( TQPainter &p, TQRect &footbox )
+{
+ TQFont oldfont( p.font() );
+ p.setFont( TQFont( "sans-serif", 6 ) );
+ TQFontMetrics fm( p.font() );
+ TQString dateStr = KGlobal::locale()->formatDateTime( TQDateTime::currentDateTime(), false );
+ p.drawText( footbox, TQt::AlignCenter | TQt::AlignVCenter | TQt::SingleLine,
+ i18n( "print date: formatted-datetime", "printed: %1" ).arg( dateStr ) );
+ p.setFont( oldfont );
+
+ return footbox.bottom();
+}
+
void CalPrintPluginBase::drawSmallMonth(TQPainter &p, const TQDate &qd,
const TQRect &box )
{
@@ -623,79 +659,78 @@ void CalPrintPluginBase::drawDaysOfWeekBox(TQPainter &p, const TQDate &qd,
}
-void CalPrintPluginBase::drawTimeLine(TQPainter &p,
- const TQTime &fromTime, const TQTime &toTime,
- const TQRect &box)
+void CalPrintPluginBase::drawTimeLine( TQPainter &p, const TQTime &fromTime,
+ const TQTime &toTime, const TQRect &box )
{
drawBox( p, BOX_BORDER_WIDTH, box );
- int totalsecs=fromTime.secsTo(toTime);
- float minlen=(float)box.height()*60./(float)totalsecs;
- float cellHeight=(60.*(float)minlen);
- float currY=box.top();
+ int totalsecs = fromTime.secsTo( toTime );
+ float minlen = (float)box.height() * 60. / (float)totalsecs;
+ float cellHeight = ( 60. * (float)minlen );
+ float currY = box.top();
// TODO: Don't use half of the width, but less, for the minutes!
- int xcenter = box.left()+box.width()/2;
+ int xcenter = box.left() + box.width() / 2;
TQTime curTime( fromTime );
TQTime endTime( toTime );
- if ( fromTime.minute() > 30 )
+ if ( fromTime.minute() > 30 ) {
curTime = TQTime( fromTime.hour()+1, 0, 0 );
- else if ( fromTime.minute() > 0 ) {
+ } else if ( fromTime.minute() > 0 ) {
curTime = TQTime( fromTime.hour(), 30, 0 );
- float yy = currY + minlen*(float)fromTime.secsTo( curTime )/60.;
+ float yy = currY + minlen * (float)fromTime.secsTo( curTime ) / 60.;
p.drawLine( xcenter, (int)yy, box.right(), (int)yy );
- curTime = TQTime( fromTime.hour()+1, 0, 0 );
+ curTime = TQTime( fromTime.hour() + 1, 0, 0 );
}
- currY += ( float( fromTime.secsTo(curTime)*minlen ) / 60. );
+ currY += ( float( fromTime.secsTo( curTime ) * minlen ) / 60. );
while ( curTime < endTime ) {
p.drawLine( box.left(), (int)currY, box.right(), (int)currY );
- int newY=(int)(currY+cellHeight/2.);
+ int newY = (int)( currY + cellHeight / 2. );
TQString numStr;
if ( newY < box.bottom() ) {
TQFont oldFont( p.font() );
// draw the time:
if ( !KGlobal::locale()->use12Clock() ) {
- p.drawLine( xcenter, (int)newY, box.right(), (int)newY);
- numStr.setNum(curTime.hour());
- if (cellHeight > 30) {
- p.setFont(TQFont("sans-serif", 16, TQFont::Bold));
+ p.drawLine( xcenter, (int)newY, box.right(), (int)newY );
+ numStr.setNum( curTime.hour() );
+ if ( cellHeight > 30 ) {
+ p.setFont( TQFont( "sans-serif", 14, TQFont::Bold ) );
} else {
- p.setFont(TQFont("sans-serif", 12, TQFont::Bold));
+ p.setFont( TQFont( "sans-serif", 12, TQFont::Bold ) );
}
- p.drawText( box.left()+2, (int)currY+2, box.width()/2-2, (int)cellHeight,
- Qt::AlignTop | Qt::AlignRight, numStr);
- p.setFont(TQFont("sans-serif", 10, TQFont::Normal));
- p.drawText( xcenter, (int)currY+2, box.width()/2+2, (int)(cellHeight/2)-3,
- Qt::AlignTop | Qt::AlignLeft, "00");
+ p.drawText( box.left() + 4, (int)currY + 2, box.width() / 2 - 2, (int)cellHeight,
+ Qt::AlignTop | Qt::AlignRight, numStr );
+ p.setFont( TQFont ( "helvetica", 10, TQFont::Normal ) );
+ p.drawText( xcenter + 4, (int)currY + 2, box.width() / 2 + 2, (int)(cellHeight / 2 ) - 3,
+ Qt::AlignTop | Qt::AlignLeft, "00" );
} else {
- p.drawLine( box.left(), (int)newY, box.right(), (int)newY);
+ p.drawLine( box.left(), (int)newY, box.right(), (int)newY );
TQTime time( curTime.hour(), 0 );
numStr = KGlobal::locale()->formatTime( time );
if ( box.width() < 60 ) {
- p.setFont(TQFont("sans-serif", 8, TQFont::Bold)); // for weekprint
+ p.setFont( TQFont( "sans-serif", 7, TQFont::Bold ) ); // for weekprint
} else {
- p.setFont(TQFont("sans-serif", 12, TQFont::Bold)); // for dayprint
+ p.setFont( TQFont( "sans-serif", 12, TQFont::Bold ) ); // for dayprint
}
- p.drawText(box.left()+2, (int)currY+2, box.width()-4, (int)cellHeight/2-3,
- Qt::AlignTop|Qt::AlignLeft, numStr);
+ p.drawText( box.left() + 2, (int)currY + 2, box.width() - 4, (int)cellHeight / 2 - 3,
+ Qt::AlignTop|Qt::AlignLeft, numStr );
}
- currY+=cellHeight;
+ currY += cellHeight;
p.setFont( oldFont );
} // enough space for half-hour line and time
- if (curTime.secsTo(endTime)>3600)
- curTime=curTime.addSecs(3600);
- else curTime=endTime;
+ if ( curTime.secsTo( endTime ) > 3600 ) {
+ curTime = curTime.addSecs( 3600 );
+ } else {
+ curTime = endTime;
+ }
} // currTime<endTime
}
-
-///////////////////////////////////////////////////////////////////////////////
-
-/** prints the all-day box for the agenda print view. if expandable is set,
- height is the cell height of a single cell, and the returned height will
- be the total height used for the all-day events. If !expandable, only one
- cell will be used, and multiple events are concatenated using ", ".
+/**
+ prints the all-day box for the agenda print view. if expandable is set,
+ height is the cell height of a single cell, and the returned height will
+ be the total height used for the all-day events. If !expandable, only one
+ cell will be used, and multiple events are concatenated using ", ".
*/
int CalPrintPluginBase::drawAllDayBox(TQPainter &p, Event::List &eventList,
const TQDate &qd, bool expandable, const TQRect &box )
@@ -721,7 +756,7 @@ int CalPrintPluginBase::drawAllDayBox(TQPainter &p, Event::List &eventList,
if ( expandable ) {
TQRect eventBox( box );
eventBox.setTop( offset );
- showEventBox( p, eventBox, currEvent, currEvent->summary() );
+ showEventBox( p, EVENT_BORDER_WIDTH, eventBox, currEvent, currEvent->summary() );
offset += box.height();
} else {
if ( !multiDayStr.isEmpty() ) multiDayStr += ", ";
@@ -867,7 +902,22 @@ void CalPrintPluginBase::drawAgendaItem( PrintCellItem *item, TQPainter &p,
int currentHeight = int( box.top() + startPrintDate.secsTo( endTime ) * minlen / 60. ) - currentYPos;
TQRect eventBox( currentX, currentYPos, currentWidth, currentHeight );
- showEventBox( p, eventBox, event, event->summary() );
+ TQString str;
+ if ( event->location().isEmpty() ) {
+ str = i18n( "starttime - endtime summary",
+ "%1-%2 %3" ).
+ arg( KGlobal::locale()->formatTime( startTime.time() ) ).
+ arg( KGlobal::locale()->formatTime( endTime.time() ) ).
+ arg( cleanStr( event->summary() ) );
+ } else {
+ str = i18n( "starttime - endtime summary, location",
+ "%1-%2 %3, %4" ).
+ arg( KGlobal::locale()->formatTime( startTime.time() ) ).
+ arg( KGlobal::locale()->formatTime( endTime.time() ) ).
+ arg( cleanStr( event->summary() ) ).
+ arg( cleanStr( event->location() ) );
+ }
+ showEventBox( p, EVENT_BORDER_WIDTH, eventBox, event, str );
}
}
@@ -877,10 +927,8 @@ void CalPrintPluginBase::drawDayBox( TQPainter &p, const TQDate &qd,
bool fullDate, bool printRecurDaily, bool printRecurWeekly )
{
TQString dayNumStr;
- TQString ampm;
const KLocale*local = KGlobal::locale();
-
// This has to be localized
if ( fullDate && mCalSys ) {
@@ -915,7 +963,7 @@ void CalPrintPluginBase::drawDayBox( TQPainter &p, const TQDate &qd,
Event::List eventList = mCalendar->events( qd,
EventSortStartDate,
SortDirectionAscending );
- TQString text;
+ TQString timeText;
p.setFont( TQFont( "sans-serif", 8 ) );
int textY=mSubHeaderHeight+3; // gives the relative y-coord of the next printed entry
@@ -925,28 +973,60 @@ void CalPrintPluginBase::drawDayBox( TQPainter &p, const TQDate &qd,
Event *currEvent = *it;
if ( ( !printRecurDaily && currEvent->recurrenceType() == Recurrence::rDaily ) ||
( !printRecurWeekly && currEvent->recurrenceType() == Recurrence::rWeekly ) ) {
- continue; }
- if ( currEvent->doesFloat() || currEvent->isMultiDay() )
- text = "";
- else
- text = local->formatTime( currEvent->dtStart().time() );
+ continue;
+ }
+ if ( currEvent->doesFloat() || currEvent->isMultiDay() ) {
+ timeText = "";
+ } else {
+ timeText = local->formatTime( currEvent->dtStart().time() );
+ }
- drawIncidence( p, box, text, currEvent->summary(), textY );
+ TQString str;
+ if ( !currEvent->location().isEmpty() ) {
+ str = i18n( "summary, location", "%1, %2" ).
+ arg( currEvent->summary() ).arg( currEvent->location() );
+ } else {
+ str = currEvent->summary();
+ }
+ drawIncidence( p, box, timeText, str, textY );
}
- if ( textY<box.height() ) {
+ if ( textY < box.height() ) {
Todo::List todos = mCalendar->todos( qd );
Todo::List::ConstIterator it2;
- for( it2 = todos.begin(); it2 != todos.end() && textY<box.height(); ++it2 ) {
+ for ( it2 = todos.begin(); it2 != todos.end() && textY <box.height(); ++it2 ) {
Todo *todo = *it2;
if ( ( !printRecurDaily && todo->recurrenceType() == Recurrence::rDaily ) ||
- ( !printRecurWeekly && todo->recurrenceType() == Recurrence::rWeekly ) )
+ ( !printRecurWeekly && todo->recurrenceType() == Recurrence::rWeekly ) ) {
continue;
- if ( todo->hasDueDate() && !todo->doesFloat() )
- text += KGlobal::locale()->formatTime(todo->dtDue().time()) + " ";
- else
- text = "";
- drawIncidence( p, box, text, i18n("To-do: %1").arg(todo->summary()), textY );
+ }
+ if ( todo->hasStartDate() && !todo->doesFloat() ) {
+ timeText = KGlobal::locale()->formatTime( todo->dtStart().time() ) + " ";
+ } else {
+ timeText = "";
+ }
+ TQString summaryStr;
+ if ( !todo->location().isEmpty() ) {
+ summaryStr = i18n( "summary, location", "%1, %2" ).
+ arg( todo->summary() ).arg( todo->location() );
+ } else {
+ summaryStr = todo->summary();
+ }
+ TQString str;
+ if ( todo->hasDueDate() ) {
+ if ( !todo->doesFloat() ) {
+ str = i18n( "%1 (Due: %2)" ).
+ arg( summaryStr ).
+ arg( KGlobal::locale()->formatDateTime( todo->dtDue() ) );
+ } else {
+ str = i18n( "%1 (Due: %2)" ).
+ arg( summaryStr ).
+ arg( KGlobal::locale()->formatDate( todo->dtDue().date(), true ) );
+ }
+ } else {
+ str = summaryStr;
+ }
+ drawIncidence( p, box, timeText, i18n("To-do: %1").arg( str ), textY );
}
}
@@ -1088,14 +1168,14 @@ void CalPrintPluginBase::drawMonth( TQPainter &p, const TQDate &dt, const TQRect
int daysinmonth = calsys->daysInMonth( dt );
if ( maxdays <= 0 ) maxdays = daysinmonth;
-
+
int d;
float dayheight = float(daysBox.height()) / float( maxdays );
-
+
TQColor holidayColor( 240, 240, 240 );
TQColor workdayColor( 255, 255, 255 );
int dayNrWidth = p.fontMetrics().width( "99" );
-
+
// Fill the remaining space (if a month has less days than others) with a crossed-out pattern
if ( daysinmonth<maxdays ) {
TQRect dayBox( box.left(), daysBox.top() + round(dayheight*daysinmonth), box.width(), 0 );
@@ -1110,12 +1190,12 @@ void CalPrintPluginBase::drawMonth( TQPainter &p, const TQDate &dt, const TQRect
TQRect dayBox( daysBox.left()/*+rand()%50*/, daysBox.top() + round(dayheight*d), daysBox.width()/*-rand()%50*/, 0 );
// FIXME: When using a border width of 0 for event boxes, don't let the rectangles overlap, i.e. subtract 1 from the top or bottom!
dayBox.setBottom( daysBox.top()+round(dayheight*(d+1)) - 1 );
-
+
p.setBrush( isWorkingDay( day )?workdayColor:holidayColor );
p.drawRect( dayBox );
TQRect dateBox( dayBox );
dateBox.setWidth( dayNrWidth+3 );
- p.drawText( dateBox, Qt::AlignRight | Qt::AlignVCenter | Qt::SingleLine,
+ p.drawText( dateBox, Qt::AlignRight | Qt::AlignVCenter | Qt::SingleLine,
TQString::number(d+1) );
}
p.setBrush( oldbrush );
@@ -1154,16 +1234,16 @@ void CalPrintPluginBase::drawMonth( TQPainter &p, const TQDate &dt, const TQRect
}
}
}
-
+
TQValueList<MonthEventStruct> monthentries;
- for ( Event::List::ConstIterator evit = events.begin();
+ for ( Event::List::ConstIterator evit = events.begin();
evit != events.end(); ++evit ) {
Event *e = (*evit);
if (!e) continue;
if ( e->doesRecur() ) {
if ( e->recursOn( start ) ) {
- // This occurrence has possibly started before the beginning of the
+ // This occurrence has possibly started before the beginning of the
// month, so obtain the start date before the beginning of the month
TQValueList<TQDateTime> starttimes = e->startDateTimesForDate( start );
TQValueList<TQDateTime>::ConstIterator it = starttimes.begin();
@@ -1171,8 +1251,8 @@ void CalPrintPluginBase::drawMonth( TQPainter &p, const TQDate &dt, const TQRect
monthentries.append( MonthEventStruct( *it, e->endDateForStart( *it ), e ) );
}
}
- // Loop through all remaining days of the month and check if the event
- // begins on that day (don't use Event::recursOn, as that will
+ // Loop through all remaining days of the month and check if the event
+ // begins on that day (don't use Event::recursOn, as that will
// also return events that have started earlier. These start dates
// however, have already been treated!
Recurrence *recur = e->recurrence();
@@ -1216,7 +1296,7 @@ void CalPrintPluginBase::drawMonth( TQPainter &p, const TQDate &dt, const TQRect
timeboxItems.append( new PrintCellItem( (*mit).event, thisstart, thisend ) );
}
}
-
+
// For Multi-day events, line them up nicely so that the boxes don't overlap
TQPtrListIterator<KOrg::CellItem> it1( timeboxItems );
for( it1.toFirst(); it1.current(); ++it1 ) {
@@ -1225,7 +1305,7 @@ void CalPrintPluginBase::drawMonth( TQPainter &p, const TQDate &dt, const TQRect
}
TQDateTime starttime( start, TQTime( 0, 0, 0 ) );
int newxstartcont = xstartcont;
-
+
TQFont oldfont( p.font() );
p.setFont( TQFont( "sans-serif", 7 ) );
for( it1.toFirst(); it1.current(); ++it1 ) {
@@ -1233,11 +1313,11 @@ void CalPrintPluginBase::drawMonth( TQPainter &p, const TQDate &dt, const TQRect
int minsToStart = starttime.secsTo( placeItem->start() )/60;
int minsToEnd = starttime.secsTo( placeItem->end() )/60;
- TQRect eventBox( xstartcont + placeItem->subCell()*17,
- daysBox.top() + round( double( minsToStart*daysBox.height()) / double(maxdays*24*60) ),
+ TQRect eventBox( xstartcont + placeItem->subCell()*17,
+ daysBox.top() + round( double( minsToStart*daysBox.height()) / double(maxdays*24*60) ),
14, 0 );
eventBox.setBottom( daysBox.top() + round( double( minsToEnd*daysBox.height()) / double(maxdays*24*60) ) );
- drawVerticalBox( p, eventBox, placeItem->event()->summary() );
+ drawVerticalBox( p, 0, eventBox, placeItem->event()->summary() );
newxstartcont = QMAX( newxstartcont, eventBox.right() );
}
xstartcont = newxstartcont;
diff --git a/korganizer/printing/calprintpluginbase.h b/korganizer/printing/calprintpluginbase.h
index 16a3374d2..b845b379e 100644
--- a/korganizer/printing/calprintpluginbase.h
+++ b/korganizer/printing/calprintpluginbase.h
@@ -48,6 +48,8 @@ using namespace KCal;
#define PORTRAIT_HEADER_HEIGHT 72 // header height, for portrait orientation
#define LANDSCAPE_HEADER_HEIGHT 54 // header height, for landscape orientation
#define SUBHEADER_HEIGHT 20 // subheader height, for all orientations
+#define PORTRAIT_FOOTER_HEIGHT 16 // footer height, for portrait orientation
+#define LANDSCAPE_FOOTER_HEIGHT 14 // footer height, for landscape orientation
#define MARGIN_SIZE 36 // margins, for all orientations
#define PADDING_SIZE 7 // padding between the various top-level boxes
#define BOX_BORDER_WIDTH 2 // width of the border of all top-level boxes
@@ -115,7 +117,7 @@ class KDE_EXPORT CalPrintPluginBase : public KOrg::PrintPlugin
void setKOrgCoreHelper( KOrg::CoreHelper*helper );
bool useColors() const;
void setUseColors( bool useColors );
-
+
/** Helper functions to hide the KOrg::CoreHelper */
TQColor categoryBgColor( Incidence *incidence );
TQColor textColor( const TQColor &color );
@@ -123,7 +125,7 @@ class KDE_EXPORT CalPrintPluginBase : public KOrg::PrintPlugin
bool isWorkingDay( const TQDate &dt );
TQString holidayString( const TQDate &dt );
Event *holiday( const TQDate &dt );
-
+
/**
Determines the column of the given weekday ( 1=Monday, 7=Sunday ), taking the
start of the week setting into account as given in kcontrol.
@@ -135,7 +137,7 @@ class KDE_EXPORT CalPrintPluginBase : public KOrg::PrintPlugin
KPrinter::Orientation orientation() const;
/** Returns the height of the page header. If the height was explicitly
- set using setHeaderHeight, that value is returned, otherwise a
+ set using setHeaderHeight, that value is returned, otherwise a
default value based on the printer orientation.
\return height of the page header of the printout
*/
@@ -145,12 +147,20 @@ class KDE_EXPORT CalPrintPluginBase : public KOrg::PrintPlugin
int subHeaderHeight() const;
void setSubHeaderHeight( const int height );
+ /** Returns the height of the page footer. If the height was explicitly
+ set using setFooterHeight, that value is returned, otherwise a
+ default value based on the printer orientation.
+ \return height of the page footer of the printout
+ */
+ int footerHeight() const;
+ void setFooterHeight( const int height );
+
int margin() const;
void setMargin( const int margin );
-
+
int padding() const;
void setPadding( const int margin );
-
+
int borderWidth() const;
void setBorderWidth( const int border );
@@ -161,7 +171,7 @@ class KDE_EXPORT CalPrintPluginBase : public KOrg::PrintPlugin
/*****************************************************************
** PRINTING HELPER FUNCTIONS **
*****************************************************************/
- public:
+ public:
/**
Draw a box with given width at the given coordinates.
\param p The printer to be used
@@ -177,44 +187,51 @@ class KDE_EXPORT CalPrintPluginBase : public KOrg::PrintPlugin
\param rect The rectangle of the box
*/
static void drawShadedBox( TQPainter &p, int linewidth, const TQBrush &brush, const TQRect &rect );
-
+
/**
Print the given string (event summary) in the given rectangle. Margins
and justification (centered or not) are automatically adjusted.
\param p TQPainter of the printout
\param box Coordinates of the surrounding event box
\param str The text to be printed in the box
+ \param flags is a bitwise OR of TQt::AlignmentFlags and TQt::TextFlags values.
*/
void printEventString( TQPainter &p, const TQRect &box, const TQString &str, int flags = -1 );
/**
Print the box for the given event with the given string.
\param p QPainer of the printout
+ \param linewidth is the width of the line used to draw the box, ignored if less than 1.
\param box Coordinates of the event's box
\param incidence The incidence (if available), from which the category
color will be deduced, if applicable.
\param str The string to print inside the box
+ \param flags is a bitwise OR of TQt::AlignmentFlags and TQt::TextFlags values.
*/
- void showEventBox( TQPainter &p, const TQRect &box, Incidence *incidence, const TQString &str, int flags = -1 );
-
- /**
+ void showEventBox( TQPainter &p, int linewidth, const TQRect &box, Incidence *incidence,
+ const TQString &str, int flags = -1 );
+
+ /**
Draw a subheader box with a shaded background and the given string
\param p TQPainter of the printout
\param str Text to be printed inside the box
\param box Coordinates of the box
*/
void drawSubHeaderBox(TQPainter &p, const TQString &str, const TQRect &box );
-
+
/**
Draw an event box with vertical text.
\param p TQPainter of the printout
+ \param linewidth is the width of the line used to draw the box, ignored if less than 1.
\param box Coordinates of the box
\param str ext to be printed inside the box
+ \param flags is a bitwise OR of TQt::AlignmentFlags and TQt::TextFlags values.
*/
- void drawVerticalBox( TQPainter &p, const TQRect &box, const TQString &str );
-
+ void drawVerticalBox( TQPainter &p, int linewidth, const TQRect &box, const TQString &str,
+ int flags=-1 );
+
/**
- Draw a component box with a heading (printed in bold).
+ Draw a component box with a heading (printed in bold).
\param p TQPainter of the printout
\param box Coordinates of the box
\param caption Caption string to be printed inside the box
@@ -222,7 +239,7 @@ class KDE_EXPORT CalPrintPluginBase : public KOrg::PrintPlugin
then no text will be printed, only the caption.
\param sameLine Whether the contents should start on the same line as
the caption (the space below the caption text will be
- used as indentation in the subsequent lines) or on the
+ used as indentation in the subsequent lines) or on the
next line (no indentation of the contents)
\param expand Whether to expand the box vertically to fit the
whole text in it.
@@ -234,7 +251,7 @@ class KDE_EXPORT CalPrintPluginBase : public KOrg::PrintPlugin
custom contents in that case.
*/
int drawBoxWithCaption( TQPainter &p, const TQRect &box, const TQString &caption,
- const TQString &contents,
+ const TQString &contents,
bool sameLine, bool expand, const TQFont &captionFont, const TQFont &textFont );
/**
@@ -260,13 +277,23 @@ class KDE_EXPORT CalPrintPluginBase : public KOrg::PrintPlugin
\param box coordinates of the title bar
\param expand Whether to expand the box vertically to fit the
whole title in it.
- \return The bottom of the printed box. If expand==false, this
+ \return The bottom of the printed box. If expand==false, this
is box.bottom, otherwise it is larger than box.bottom
and matches the y-coordinate of the surrounding rectangle.
*/
int drawHeader( TQPainter &p, TQString title,
const TQDate &month1, const TQDate &month2,
const TQRect &box, bool expand = false );
+
+ /**
+ Draw a page footer containing the printing date and possibly
+ other things, like a page number.
+ \param p TQPainter of the printout
+ \param box coordinates of the footer
+ \return The bottom of the printed box.
+ */
+ int drawFooter( TQPainter &p, TQRect &box );
+
/**
Draw a small calendar with the days of a month into the given area.
Used for example in the title bar of the sheet.
@@ -309,7 +336,7 @@ class KDE_EXPORT CalPrintPluginBase : public KOrg::PrintPlugin
void drawTimeLine( TQPainter &p,
const TQTime &fromTime, const TQTime &toTime,
const TQRect &box );
-
+
/**
Draw the all-day box for the agenda print view (the box on top which
doesn't have a time on the time scale associated). If expandable is set,
@@ -359,7 +386,7 @@ class KDE_EXPORT CalPrintPluginBase : public KOrg::PrintPlugin
const TQDateTime &startPrintDate,
const TQDateTime &endPrintDate,
float minlen, const TQRect &box );
-
+
/**
Draw the box containing a list of all events of the given day (with their times,
of course). Used in the Filofax and the month print style.
@@ -429,8 +456,8 @@ class KDE_EXPORT CalPrintPluginBase : public KOrg::PrintPlugin
\param dt Arbitrary date within the month to be printed
\param box coordinates of the box reserved for the month
\param maxdays Days to print. If a value of -1 is given, the number of days
- is deduced from the month. If maxdays is larger than the
- number of days in the month, the remaining boxes are
+ is deduced from the month. If maxdays is larger than the
+ number of days in the month, the remaining boxes are
shaded to indicate they are not days of the month.
\param subDailyFlags Bitfield consisting of DisplayFlags flags to determine
how events that do not cross midnight should be printed.
@@ -501,6 +528,7 @@ class KDE_EXPORT CalPrintPluginBase : public KOrg::PrintPlugin
bool mUseColors;
int mHeaderHeight;
int mSubHeaderHeight;
+ int mFooterHeight;
int mMargin;
int mPadding;
int mBorder;
diff --git a/korganizer/publishdialog.cpp b/korganizer/publishdialog.cpp
index ac684069f..68d5c6307 100644
--- a/korganizer/publishdialog.cpp
+++ b/korganizer/publishdialog.cpp
@@ -160,9 +160,8 @@ void PublishDialog::updateInput()
if (!item) return;
mWidget->mNameLineEdit->setEnabled( true );
mWidget->mEmailLineEdit->setEnabled( true );
- TQString mail = item->text( 1 );
mWidget->mNameLineEdit->setText( item->text( 0 ) );
- mWidget->mEmailLineEdit->setText( mail );
+ mWidget->mEmailLineEdit->setText( item->text( 1 ) );
}
#include "publishdialog.moc"
diff --git a/korganizer/resourceview.cpp b/korganizer/resourceview.cpp
index d4a76f73e..150aa0143 100644
--- a/korganizer/resourceview.cpp
+++ b/korganizer/resourceview.cpp
@@ -24,7 +24,10 @@
*/
#include "resourceview.h"
+#include "koviewmanager.h"
+#include "multiagendaview.h"
+#include <dcopref.h>
#include <kcolordialog.h>
#include <kdialog.h>
#include <klistview.h>
@@ -37,6 +40,7 @@
#include <kresources/resource.h>
#include <kresources/configdialog.h>
#include <libkcal/calendarresources.h>
+#include <kconfig.h>
#include <tqhbox.h>
#include <tqheader.h>
@@ -45,6 +49,7 @@
#include <tqpainter.h>
#include <tqpushbutton.h>
#include <tqpopupmenu.h>
+#include <tqregexp.h>
#include <tqtooltip.h>
#include <tqwhatsthis.h>
@@ -52,20 +57,53 @@
using namespace KCal;
-ResourceViewFactory::ResourceViewFactory( KCal::CalendarResources *calendar,
- CalendarView *view )
- : mCalendar( calendar ), mView( view ), mResourceView( 0 )
+static TQString labelFromSubResName( ResourceCalendar *resource, const TQString &subRes )
+{
+
+ DCOPRef ref( "kmail", "KMailICalIface" );
+ DCOPReply reply = ref.call( "dimapAccounts" );
+ if ( !reply.isValid() ) {
+ kdDebug() << "DCOP Call dimapAccounts() failed " << endl;
+ return TQString();
+ }
+
+ TQString label;
+ if ( (int)reply > 1 ) {
+ if( resource && !resource->resourceName().isEmpty() ) {
+ label = i18n( "My %1 (%2)" ).arg( subRes, resource->resourceName() );
+ } else {
+ label = i18n( "My %1" ).arg( subRes );
+ }
+ } else {
+ label = i18n( "My %1" ).arg( subRes );
+ }
+ return label;
+}
+
+static TQString labelFromIdentifier( ResourceCalendar *resource, const TQString &identifier )
+{
+ TQString subResLabel;
+ if ( identifier.contains( "/.INBOX.directory/" ) ) { // my subresource
+ TQString subResName = identifier;
+ subResName.remove( TQRegExp( "^.*/\\.INBOX\\.directory/" ) );
+ subResLabel = labelFromSubResName( resource, subResName );
+ }
+ return subResLabel;
+}
+
+ResourceViewFactory::ResourceViewFactory( CalendarResources *calendar, CalendarView *view )
+ : mCalendar( calendar ), mCalendarView( view ), mResourceView( 0 )
{
}
CalendarViewExtension *ResourceViewFactory::create( TQWidget *parent )
{
- mResourceView = new ResourceView( mCalendar, parent );
+ mResourceView = new ResourceView( mCalendar, mCalendarView, parent );
TQObject::connect( mResourceView, TQT_SIGNAL( resourcesChanged() ),
- mView, TQT_SLOT( resourcesChanged() ) );
+ mCalendarView, TQT_SLOT( resourcesChanged() ) );
TQObject::connect( mResourceView, TQT_SIGNAL( resourcesChanged() ),
- mView, TQT_SLOT( updateCategories() ) );
+ mCalendarView, TQT_SLOT( updateCategories() ) );
TQObject::connect( mCalendar,
TQT_SIGNAL( signalResourceAdded( ResourceCalendar * ) ),
@@ -76,9 +114,9 @@ CalendarViewExtension *ResourceViewFactory::create( TQWidget *parent )
mResourceView,
TQT_SLOT( updateResourceItem( ResourceCalendar * ) ) );
TQObject::connect( mCalendar, TQT_SIGNAL( signalResourceAdded( ResourceCalendar * ) ),
- mView, TQT_SLOT( updateCategories() ) );
+ mCalendarView, TQT_SLOT( updateCategories() ) );
TQObject::connect( mCalendar, TQT_SIGNAL( signalResourceModified( ResourceCalendar * ) ),
- mView, TQT_SLOT( updateCategories() ) );
+ mCalendarView, TQT_SLOT( updateCategories() ) );
return mResourceView;
}
@@ -91,7 +129,7 @@ ResourceView *ResourceViewFactory::resourceView() const
ResourceItem::ResourceItem( ResourceCalendar *resource, ResourceView *view,
KListView *parent )
: TQCheckListItem( parent, resource->resourceName(), CheckBox ),
- mResource( resource ), mView( view ), mBlockStateChange( false ),
+ mResource( resource ), mResourceView( view ), mBlockStateChange( false ),
mIsSubresource( false ), mResourceIdentifier( TQString::null ),
mSubItemsCreated( false ), mIsStandardResource( false )
{
@@ -112,8 +150,11 @@ void ResourceItem::createSubresourceItems()
// This resource has subresources
TQStringList::ConstIterator it;
for ( it=subresources.begin(); it!=subresources.end(); ++it ) {
- ResourceItem *item = new ResourceItem( mResource, *it, mResource->labelForSubresource( *it ),
- mView, this );
+ TQString text = labelFromIdentifier( mResource, *it );
+ if ( text.isEmpty() ) {
+ text = mResource->labelForSubresource( *it );
+ }
+ ResourceItem *item = new ResourceItem( mResource, *it, text, mResourceView, this );
TQColor resourceColor = *KOPrefs::instance()->resourceColor( *it );
item->setResourceColor( resourceColor );
item->update();
@@ -122,16 +163,14 @@ void ResourceItem::createSubresourceItems()
mSubItemsCreated = true;
}
-ResourceItem::ResourceItem( KCal::ResourceCalendar *resource,
- const TQString& sub, const TQString& label,
- ResourceView *view, ResourceItem* parent )
-
+ResourceItem::ResourceItem( ResourceCalendar *resource, const TQString &identifier,
+ const TQString &label, ResourceView *view, ResourceItem *parent )
: TQCheckListItem( parent, label, CheckBox ), mResource( resource ),
- mView( view ), mBlockStateChange( false ), mIsSubresource( true ),
+ mResourceView( view ), mBlockStateChange( false ), mIsSubresource( true ),
mSubItemsCreated( false ), mIsStandardResource( false )
{
mResourceColor = TQColor();
- mResourceIdentifier = sub;
+ mResourceIdentifier = identifier;
setGuiState();
}
@@ -159,10 +198,12 @@ void ResourceItem::stateChange( bool active )
createSubresourceItems();
}
} else {
- // mView->requestClose must be called before mResource->save() because
+ // mResourceView->requestClose must be called before mResource->save() because
// save causes closeResource do be called.
- mView->requestClose( mResource );
- if ( mResource->save() ) mResource->setActive( false );
+ mResourceView->requestClose( mResource );
+ if ( mResource->save() ) {
+ mResource->setActive( false );
+ }
}
setOpen( mResource->isActive() && childCount() > 0 );
@@ -170,7 +211,7 @@ void ResourceItem::stateChange( bool active )
setGuiState();
}
- mView->emitResourcesChanged();
+ mResourceView->emitResourcesChanged();
}
void ResourceItem::update()
@@ -216,9 +257,9 @@ void ResourceItem::paintCell(TQPainter *p, const TQColorGroup &cg,
}
-ResourceView::ResourceView( KCal::CalendarResources *calendar,
- TQWidget *parent, const char *name )
- : CalendarViewExtension( parent, name ), mCalendar( calendar )
+ResourceView::ResourceView( CalendarResources *calendar,
+ CalendarView *view, TQWidget *parent, const char *name )
+ : CalendarViewExtension( parent, name ), mCalendar( calendar ), mCalendarView( view )
{
TQBoxLayout *topLayout = new TQVBoxLayout( this, 0, KDialog::spacingHint() );
@@ -305,9 +346,9 @@ void ResourceView::updateView()
{
mListView->clear();
- KCal::CalendarResourceManager *manager = mCalendar->resourceManager();
+ CalendarResourceManager *manager = mCalendar->resourceManager();
- KCal::CalendarResourceManager::Iterator it;
+ CalendarResourceManager::Iterator it;
for( it = manager->begin(); it != manager->end(); ++it ) {
addResourceItem( *it );
}
@@ -322,44 +363,47 @@ void ResourceView::emitResourcesChanged()
void ResourceView::addResource()
{
bool ok = false;
- KCal::CalendarResourceManager *manager = mCalendar->resourceManager();
- ResourceItem *i = static_cast<ResourceItem*>( mListView->selectedItem() );
- if ( i && ( i->isSubresource() || i->resource()->canHaveSubresources() ) ) {
- const TQString folderName = KInputDialog::getText( i18n( "Add Subresource" ),
- i18n( "Please enter a name for the new subresource" ), TQString::null,
- &ok, this );
+ CalendarResourceManager *manager = mCalendar->resourceManager();
+ ResourceItem *item = static_cast<ResourceItem*>( mListView->selectedItem() );
+ if ( item && ( item->isSubresource() || item->resource()->canHaveSubresources() ) ) {
+ const TQString folderName =
+ KInputDialog::getText( i18n( "Add Subresource" ),
+ i18n( "Please enter a name for the new subresource" ), TQString::null,
+ &ok, this );
if ( !ok )
return;
- const TQString parentId = i->isSubresource() ? i->resourceIdentifier() : TQString:: null;
- if ( !i->resource()->addSubresource( folderName, parentId ) ) {
- KMessageBox::error( this, i18n("<qt>Unable to create subresource <b>%1</b>.</qt>")
- .arg( folderName ) );
+ const TQString parentId = item->isSubresource() ? item->resourceIdentifier() : TQString:: null;
+ if ( !item->resource()->addSubresource( folderName, parentId ) ) {
+ KMessageBox::error(
+ this,
+ i18n( "<qt>Unable to create subresource <b>%1</b>.</qt>" ).arg( folderName ) );
}
return;
}
TQStringList types = manager->resourceTypeNames();
TQStringList descs = manager->resourceTypeDescriptions();
- TQString desc = KInputDialog::getItem( i18n( "Resource Configuration" ),
- i18n( "Please select type of the new resource:" ), descs, 0, false, &ok,
- this );
- if ( !ok )
+ TQString desc =
+ KInputDialog::getItem( i18n( "Resource Configuration" ),
+ i18n( "Please select type of the new resource:" ),
+ descs, 0, false, &ok, this );
+ if ( !ok ) {
return;
+ }
TQString type = types[ descs.findIndex( desc ) ];
// Create new resource
ResourceCalendar *resource = manager->createResource( type );
if( !resource ) {
- KMessageBox::error( this, i18n("<qt>Unable to create resource of type <b>%1</b>.</qt>")
- .arg( type ) );
+ KMessageBox::error(
+ this,
+ i18n( "<qt>Unable to create resource of type <b>%1</b>.</qt>" ).arg( type ) );
return;
}
- resource->setResourceName( i18n("%1 resource").arg( type ) );
-
- KRES::ConfigDialog *dlg = new KRES::ConfigDialog( this, TQString("calendar"), resource,
- "KRES::ConfigDialog" );
+ KRES::ConfigDialog *dlg =
+ new KRES::ConfigDialog( this, TQString( "calendar" ), resource, "KRES::ConfigDialog" );
bool success = true;
if ( !dlg || !dlg->exec() )
@@ -370,8 +414,7 @@ void ResourceView::addResource()
if ( resource->isActive() && ( !resource->open() || !resource->load() ) ) {
// ### There is a resourceLoadError() signal declared in ResourceCalendar
// but no subclass seems to make use of it. We could do better.
- KMessageBox::error( this, i18n("Unable to create the resource.")
- .arg( type ) );
+ KMessageBox::error( this, i18n("Unable to create the resource.").arg( type ) );
success = false;
}
}
@@ -396,7 +439,7 @@ void ResourceView::addResource()
void ResourceView::addResourceItem( ResourceCalendar *resource )
{
- ResourceItem *item=new ResourceItem( resource, this, mListView );
+ ResourceItem *item = new ResourceItem( resource, this, mListView );
// assign a color, but only if this is a resource that actually
// hold items at top level
@@ -427,38 +470,47 @@ void ResourceView::addResourceItem( ResourceCalendar *resource )
}
// Add a new entry
-void ResourceView::slotSubresourceAdded( ResourceCalendar *calendar,
- const TQString& /*type*/,
- const TQString& resource,
- const TQString& label)
+void ResourceView::slotSubresourceAdded( ResourceCalendar *resource,
+ const TQString &type,
+ const TQString &identifier,
+ const TQString &label )
{
- TQListViewItem *i = mListView->findItem( calendar->resourceName(), 0 );
- if ( !i )
+ Q_UNUSED( type );
+
+ TQListViewItem *lvitem = mListView->findItem( resource->resourceName(), 0 );
+ if ( !lvitem )
// Not found
return;
- if ( findItemByIdentifier( resource ) ) return;
+ if ( findItemByIdentifier( identifier ) ) return;
- ResourceItem *item = static_cast<ResourceItem *>( i );
- ResourceItem *newItem = new ResourceItem( calendar, resource, label, this, item );
- TQColor resourceColor = *KOPrefs::instance()->resourceColor( resource );
+ TQString text = labelFromIdentifier( resource, identifier );
+ if ( text.isEmpty() ) {
+ text = label;
+ }
+ ResourceItem *item = static_cast<ResourceItem *>( lvitem );
+ ResourceItem *newItem = new ResourceItem( resource, identifier, text, this, item );
+ TQColor resourceColor = *KOPrefs::instance()->resourceColor( identifier );
newItem->setResourceColor( resourceColor );
}
// Remove an entry
-void ResourceView::slotSubresourceRemoved( ResourceCalendar * /*calendar*/,
- const TQString &/*type*/,
- const TQString &resource )
+void ResourceView::slotSubresourceRemoved( ResourceCalendar *resource,
+ const TQString &type,
+ const TQString &identifier )
{
- delete findItemByIdentifier( resource );
+ Q_UNUSED( resource );
+ Q_UNUSED( type );
+
+ delete findItemByIdentifier( identifier );
emit resourcesChanged();
}
-void ResourceView::closeResource( ResourceCalendar *r )
+void ResourceView::closeResource( ResourceCalendar *resource )
{
- if ( mResourcesToClose.find( r ) >= 0 ) {
- r->close();
- mResourcesToClose.remove( r );
+ if ( mResourcesToClose.find( resource ) >= 0 ) {
+ resource->close();
+ mResourcesToClose.remove( resource );
}
}
@@ -482,31 +534,46 @@ void ResourceView::removeResource()
ResourceItem *item = currentItem();
if ( !item ) return;
- const TQString warningMsg = item->isSubresource() ?
- i18n("<qt>Do you really want to remove the subresource <b>%1</b>? "
- "Note that its contents will be completely deleted. This "
- "operation cannot be undone. </qt>").arg( item->text( 0 ) ) :
- i18n("<qt>Do you really want to remove the resource <b>%1</b>?</qt>").arg( item->text( 0 ) );
-
- int km = KMessageBox::warningContinueCancel( this, warningMsg, "",
- KGuiItem( i18n("&Remove" ), "editdelete") );
- if ( km == KMessageBox::Cancel ) return;
-
-// Don't be so restricitve
-#if 0
- if ( item->resource() == mCalendar->resourceManager()->standardResource() ) {
- KMessageBox::sorry( this,
- i18n( "You cannot delete your standard resource." ) );
+ // Do not allow a non-subresource folder to be removed if it is the standard resource.
+ if ( !item->isSubresource() ) {
+ if ( item->resource() == mCalendar->resourceManager()->standardResource() ) {
+ KMessageBox::sorry(
+ this,
+ i18n( "<qt>You may not delete your standard calendar resource.<p>"
+ "You can change the standard calendar resource in the "
+ "KDE Control Center using the KDE Resource settings under the "
+ "KDE Components area.</qt>" ) );
+ return;
+ }
+ }
+
+ TQString moreInfo;
+ if ( item->resource()->type() == "imap" || item->resource()->type() == "scalix" ) {
+ moreInfo = i18n( "This is a groupware folder so you can always re-subscribe to the folder "
+ "later as you desire." );
+ } else {
+ moreInfo = i18n( "The contents will not be removed so you can always re-add this calendar "
+ "later as you desire." );
+ }
+
+ int km =
+ KMessageBox::warningContinueCancel(
+ this,
+ i18n( "<qt>Do you really want to remove the calendar <b>%1</b>?<p><b>Note:</b> %2</qt>" ).
+ arg( item->text( 0 ), moreInfo ),
+ "", KGuiItem( i18n( "&Remove" ) ) );
+ if ( km == KMessageBox::Cancel ) {
return;
}
-#endif
+
if ( item->isSubresource() ) {
if ( !item->resource()->removeSubresource( item->resourceIdentifier() ) )
- KMessageBox::sorry( this,
- i18n ("<qt>Failed to remove the subresource <b>%1</b>. The "
- "reason could be that it is a built-in one which cannot "
- "be removed, or that the removal of the underlying storage "
- "folder failed.</qt>").arg( item->resource()->name() ) );
+ KMessageBox::sorry(
+ this,
+ i18n ("<qt>Failed to remove the subresource <b>%1</b>. The "
+ "reason could be that it is a built-in one which cannot "
+ "be removed, or that the removal of the underlying storage "
+ "folder failed.</qt>").arg( item->resource()->name() ) );
return;
} else {
mCalendar->resourceManager()->remove( item->resource() );
@@ -520,62 +587,103 @@ void ResourceView::removeResource()
void ResourceView::editResource()
{
+ bool ok = false;
ResourceItem *item = currentItem();
if (!item) return;
ResourceCalendar *resource = item->resource();
- KRES::ConfigDialog dlg( this, TQString("calendar"), resource,
- "KRES::ConfigDialog" );
+ if ( item->isSubresource() ) {
+ if ( resource->type() == "imap" || resource->type() == "scalix" ) {
+ TQString identifier = item->resourceIdentifier();
+ if ( !identifier.contains( "/.INBOX.directory/" ) ) {
+ KMessageBox::sorry(
+ this,
+ i18n( "Cannot rename someone else's calendar folder." ) );
+ return;
+ }
+
+ TQString oldSubResourceName = identifier;
+ oldSubResourceName.remove( TQRegExp( "^.*/\\.INBOX\\.directory/" ) );
+ TQString newSubResourceName =
+ KInputDialog::getText(
+ i18n( "Rename Subresource" ),
+ i18n( "<qt>Enter a new name for the subresource<p>"
+ "<b>Note:</b> the new name will take affect after the next sync.</qt>" ),
+ oldSubResourceName, &ok, this );
+ if ( !ok ) {
+ return;
+ }
- if ( dlg.exec() ) {
- item->setText( 0, resource->resourceName() );
+ DCOPRef ref( "kmail", "KMailICalIface" );
+ DCOPReply reply = ref.call( "changeResourceUIName", identifier, newSubResourceName );
+ if ( !reply.isValid() ) {
+ KMessageBox::sorry(
+ this,
+ i18n( "Communication with KMail failed when attempting to change the folder name." ) );
+ return;
+ }
+
+ item->setText( 0, labelFromSubResName( resource, newSubResourceName ) );
+
+ KOrg::BaseView *cV = mCalendarView->viewManager()->currentView();
+ if ( cV && cV == mCalendarView->viewManager()->multiAgendaView() ) {
+ mCalendarView->viewManager()->multiAgendaView()->deSelectAgendaView();
+ }
+ } else {
+ KMessageBox::sorry(
+ this,
+ i18n ("<qt>Cannot edit the subresource <b>%1</b>.</qt>").arg( item->resource()->name() ) );
+ }
+ } else {
+ KRES::ConfigDialog dlg( this, TQString("calendar"), resource, "KRES::ConfigDialog" );
- mCalendar->resourceManager()->change( resource );
+ if ( dlg.exec() ) {
+ item->setText( 0, resource->resourceName() );
+ mCalendar->resourceManager()->change( resource );
+ }
}
emitResourcesChanged();
}
-void ResourceView::currentChanged( TQListViewItem *item )
+void ResourceView::currentChanged( TQListViewItem *lvitem )
{
- ResourceItem *i = currentItem();
- if ( !item || i->isSubresource() ) {
- mDeleteButton->setEnabled( false );
- mEditButton->setEnabled( false );
- } else {
- mDeleteButton->setEnabled( true );
- mEditButton->setEnabled( true );
- }
+ ResourceItem *item = currentItem();
+ if ( !lvitem || item->isSubresource() ) {
+ mDeleteButton->setEnabled( false );
+ mEditButton->setEnabled( false );
+ } else {
+ mDeleteButton->setEnabled( true );
+ mEditButton->setEnabled( true );
+ }
}
-ResourceItem *ResourceView::findItem( ResourceCalendar *r )
+ResourceItem *ResourceView::findItem( ResourceCalendar *resource )
{
- TQListViewItem *item;
- ResourceItem *i = 0;
- for( item = mListView->firstChild(); item; item = item->nextSibling() ) {
- i = static_cast<ResourceItem *>( item );
- if ( i->resource() == r ) break;
+ TQListViewItem *lvitem;
+ ResourceItem *item = 0;
+ for( lvitem = mListView->firstChild(); lvitem; lvitem = lvitem->nextSibling() ) {
+ item = static_cast<ResourceItem *>( lvitem );
+ if ( item->resource() == resource ) break;
}
- return i;
+ return item;
}
-ResourceItem *ResourceView::findItemByIdentifier( const TQString& id )
+ResourceItem *ResourceView::findItemByIdentifier( const TQString &identifier )
{
- TQListViewItem *item;
- ResourceItem *i = 0;
- for( item = mListView->firstChild(); item; item = item->itemBelow() ) {
- i = static_cast<ResourceItem *>( item );
- if ( i->resourceIdentifier() == id )
- return i;
+ TQListViewItem *lvitem;
+ ResourceItem *item = 0;
+ for ( lvitem = mListView->firstChild(); lvitem; lvitem = lvitem->itemBelow() ) {
+ item = static_cast<ResourceItem *>( lvitem );
+ if ( item->resourceIdentifier() == identifier )
+ return item;
}
return 0;
}
-
-void ResourceView::contextMenuRequested ( TQListViewItem *i,
- const TQPoint &pos, int )
+void ResourceView::contextMenuRequested ( TQListViewItem *lvitem, const TQPoint &pos, int )
{
- KCal::CalendarResourceManager *manager = mCalendar->resourceManager();
- ResourceItem *item = static_cast<ResourceItem *>( i );
+ CalendarResourceManager *manager = mCalendar->resourceManager();
+ ResourceItem *item = static_cast<ResourceItem *>( lvitem );
TQPopupMenu *menu = new TQPopupMenu( this );
connect( menu, TQT_SIGNAL( aboutToHide() ), menu, TQT_SLOT( deleteLater() ) );
@@ -598,7 +706,14 @@ void ResourceView::contextMenuRequested ( TQListViewItem *i,
menu->insertItem( i18n( "Resources Colors" ), assignMenu );
}
- menu->insertItem( i18n("&Edit..."), this, TQT_SLOT( editResource() ) );
+ if ( item->isSubresource() &&
+ ( item->resource()->type() == "imap" || item->resource()->type() == "scalix" ) ) {
+ if ( item->resourceIdentifier().contains( "/.INBOX.directory/" ) ) {
+ menu->insertItem( i18n("&Rename..."), this, TQT_SLOT( editResource() ) );
+ }
+ } else {
+ menu->insertItem( i18n("&Edit..."), this, TQT_SLOT( editResource() ) );
+ }
menu->insertItem( i18n("&Remove"), this, TQT_SLOT( removeResource() ) );
if ( item->resource() != manager->standardResource() ) {
menu->insertSeparator();
@@ -620,7 +735,7 @@ void ResourceView::assignColor()
return;
// A color without initialized is a color invalid
TQColor myColor;
- KCal::ResourceCalendar *cal = item->resource();
+ ResourceCalendar *cal = item->resource();
TQString identifier = cal->identifier();
if ( item->isSubresource() )
@@ -641,13 +756,16 @@ void ResourceView::assignColor()
void ResourceView::disableColor()
{
ResourceItem *item = currentItem();
- if ( !item )
+ if ( !item ) {
return;
+ }
+
TQColor colorInvalid;
- KCal::ResourceCalendar *cal = item->resource();
+ ResourceCalendar *cal = item->resource();
TQString identifier = cal->identifier();
- if ( item->isSubresource() )
+ if ( item->isSubresource() ) {
identifier = item->resourceIdentifier();
+ }
KOPrefs::instance()->setResourceColor( identifier, colorInvalid );
item->setResourceColor( colorInvalid );
item->update();
@@ -658,7 +776,12 @@ void ResourceView::showInfo()
ResourceItem *item = currentItem();
if ( !item ) return;
- TQString txt = "<qt>" + item->resource()->infoText() + "</qt>";
+ TQString identifier;
+ if ( item->isSubresource() ) {
+ identifier = "<p>" + item->resourceIdentifier();
+ }
+
+ TQString txt = "<qt>" + item->resource()->infoText() + identifier + "</qt>";
KMessageBox::information( this, txt );
}
@@ -667,8 +790,8 @@ void ResourceView::reloadResource()
ResourceItem *item = currentItem();
if ( !item ) return;
- ResourceCalendar *r = item->resource();
- r->load();
+ ResourceCalendar *resource = item->resource();
+ resource->load();
}
void ResourceView::saveResource()
@@ -676,8 +799,8 @@ void ResourceView::saveResource()
ResourceItem *item = currentItem();
if ( !item ) return;
- ResourceCalendar *r = item->resource();
- r->save();
+ ResourceCalendar *resource = item->resource();
+ resource->save();
}
void ResourceView::setStandard()
@@ -685,9 +808,9 @@ void ResourceView::setStandard()
ResourceItem *item = currentItem();
if ( !item ) return;
- ResourceCalendar *r = item->resource();
- KCal::CalendarResourceManager *manager = mCalendar->resourceManager();
- manager->setStandardResource( r );
+ ResourceCalendar *resource = item->resource();
+ CalendarResourceManager *manager = mCalendar->resourceManager();
+ manager->setStandardResource( resource );
updateResourceList();
}
diff --git a/korganizer/resourceview.h b/korganizer/resourceview.h
index f34d0cf22..ee4060272 100644
--- a/korganizer/resourceview.h
+++ b/korganizer/resourceview.h
@@ -27,11 +27,11 @@
#include "calendarview.h"
-#include <libkcal/resourcecalendar.h>
#include <tqlistview.h>
namespace KCal {
-class CalendarResources;
+ class CalendarResources;
+ class ResourceCalendar;
}
using namespace KCal;
class KListView;
@@ -41,16 +41,15 @@ class TQPushButton;
class ResourceViewFactory : public CalendarViewExtension::Factory
{
public:
- ResourceViewFactory( KCal::CalendarResources *calendar,
- CalendarView *view );
+ ResourceViewFactory( CalendarResources *calendar, CalendarView *view );
CalendarViewExtension *create( TQWidget * );
ResourceView *resourceView() const;
private:
- KCal::CalendarResources *mCalendar;
- CalendarView *mView;
+ CalendarResources *mCalendar;
+ CalendarView *mCalendarView;
ResourceView *mResourceView;
};
@@ -58,18 +57,15 @@ class ResourceViewFactory : public CalendarViewExtension::Factory
class ResourceItem : public QCheckListItem
{
public:
- ResourceItem( KCal::ResourceCalendar *resource, ResourceView *view,
- KListView *parent );
- ResourceItem( KCal::ResourceCalendar *resource, const TQString& sub,
- const TQString& label, ResourceView *view,
- ResourceItem* parent );
+ ResourceItem( ResourceCalendar *resource, ResourceView *view, KListView *parent );
+ ResourceItem( ResourceCalendar *resource, const TQString &identifier,
+ const TQString &label, ResourceView *view, ResourceItem *parent );
- KCal::ResourceCalendar *resource() { return mResource; }
+ ResourceCalendar *resource() { return mResource; }
const TQString& resourceIdentifier() { return mResourceIdentifier; }
bool isSubresource() const { return mIsSubresource; }
void createSubresourceItems();
void setStandardResource( bool std );
-
void update();
virtual void paintCell(TQPainter *p, const TQColorGroup &cg,
@@ -77,15 +73,15 @@ class ResourceItem : public QCheckListItem
void setResourceColor(TQColor& color);
TQColor &resourceColor() {return mResourceColor;}
+
protected:
void stateChange( bool active );
-
void setGuiState();
TQColor mResourceColor;
private:
- KCal::ResourceCalendar *mResource;
- ResourceView *mView;
+ ResourceCalendar *mResource;
+ ResourceView *mResourceView;
bool mBlockStateChange;
bool mIsSubresource;
TQString mResourceIdentifier;
@@ -100,45 +96,45 @@ class ResourceView : public CalendarViewExtension
{
Q_OBJECT
public:
- ResourceView( KCal::CalendarResources *calendar, TQWidget *parent = 0,
- const char *name = 0 );
+ ResourceView( CalendarResources *calendar, CalendarView *view,
+ TQWidget *parent = 0, const char *name = 0 );
~ResourceView();
- KCal::CalendarResources *calendar() const { return mCalendar; }
+ CalendarResources *calendar() const { return mCalendar; }
void updateView();
void emitResourcesChanged();
- void requestClose( ResourceCalendar * );
+ void requestClose( ResourceCalendar *resource );
void showButtons( bool visible );
public slots:
- void addResourceItem( ResourceCalendar * );
- void updateResourceItem( ResourceCalendar * );
+ void addResourceItem( ResourceCalendar *resource );
+ void updateResourceItem( ResourceCalendar *resource );
signals:
void resourcesChanged();
protected:
- ResourceItem *findItem( ResourceCalendar * );
- ResourceItem *findItemByIdentifier( const TQString& id );
+ ResourceItem *findItem( ResourceCalendar *resource );
+ ResourceItem *findItemByIdentifier( const TQString &identifier );
ResourceItem *currentItem();
protected slots:
void addResource();
void removeResource();
void editResource();
- void currentChanged( TQListViewItem* );
- void slotSubresourceAdded( ResourceCalendar *, const TQString &,
- const TQString &resource,const TQString& label );
+ void currentChanged( TQListViewItem *lvitem );
+ void slotSubresourceAdded( ResourceCalendar *resource, const TQString &type,
+ const TQString &identifier, const TQString &label );
- void slotSubresourceRemoved( ResourceCalendar *, const TQString &,
- const TQString & );
- void closeResource( ResourceCalendar * );
+ void slotSubresourceRemoved( ResourceCalendar *resource, const TQString &type,
+ const TQString &identifier );
+ void closeResource( ResourceCalendar *resource );
- void contextMenuRequested ( TQListViewItem *i, const TQPoint &pos, int );
+ void contextMenuRequested ( TQListViewItem *lvitem, const TQPoint &pos, int );
void assignColor();
void disableColor();
@@ -152,7 +148,8 @@ class ResourceView : public CalendarViewExtension
private:
KListView *mListView;
- KCal::CalendarResources *mCalendar;
+ CalendarResources *mCalendar;
+ CalendarView *mCalendarView;
TQPushButton *mAddButton;
TQPushButton *mDeleteButton;
TQPushButton *mEditButton;
diff --git a/korganizer/searchdialog.cpp b/korganizer/searchdialog.cpp
index 487296a6d..2cc4bb442 100644
--- a/korganizer/searchdialog.cpp
+++ b/korganizer/searchdialog.cpp
@@ -120,12 +120,12 @@ SearchDialog::SearchDialog(Calendar *calendar,TQWidget *parent)
connect( this,TQT_SIGNAL(user1Clicked()),TQT_SLOT(doSearch()));
// Propagate edit and delete event signals from event list view
- connect( listView, TQT_SIGNAL( showIncidenceSignal( Incidence * ) ),
- TQT_SIGNAL( showIncidenceSignal( Incidence *) ) );
- connect( listView, TQT_SIGNAL( editIncidenceSignal( Incidence * ) ),
- TQT_SIGNAL( editIncidenceSignal( Incidence * ) ) );
- connect( listView, TQT_SIGNAL( deleteIncidenceSignal( Incidence * ) ),
- TQT_SIGNAL( deleteIncidenceSignal( Incidence * ) ) );
+ connect( listView, TQT_SIGNAL(showIncidenceSignal(Incidence *,const TQDate &)),
+ TQT_SIGNAL(showIncidenceSignal(Incidence *,const TQDate &)) );
+ connect( listView, TQT_SIGNAL(editIncidenceSignal(Incidence *,const TQDate &)),
+ TQT_SIGNAL(editIncidenceSignal(Incidence *,const TQDate &)) );
+ connect( listView, TQT_SIGNAL(deleteIncidenceSignal(Incidence *)),
+ TQT_SIGNAL(deleteIncidenceSignal(Incidence *)) );
}
SearchDialog::~SearchDialog()
@@ -155,7 +155,7 @@ void SearchDialog::doSearch()
search( re );
- listView->showIncidences( mMatchedEvents );
+ listView->showIncidences( mMatchedEvents, TQDate() );
if ( mMatchedEvents.count() == 0 ) {
KMessageBox::information( this,
@@ -176,7 +176,7 @@ void SearchDialog::updateView()
mMatchedEvents.clear();
}
- listView->showIncidences( mMatchedEvents );
+ listView->showIncidences( mMatchedEvents, TQDate() );
}
void SearchDialog::search( const TQRegExp &re )
diff --git a/korganizer/searchdialog.h b/korganizer/searchdialog.h
index cd535bd10..53195bc13 100644
--- a/korganizer/searchdialog.h
+++ b/korganizer/searchdialog.h
@@ -60,9 +60,9 @@ class SearchDialog : public KDialogBase
void searchTextChanged( const TQString &_text );
signals:
- void showIncidenceSignal(Incidence *);
- void editIncidenceSignal(Incidence *);
- void deleteIncidenceSignal(Incidence *);
+ void showIncidenceSignal( Incidence *, const TQDate & );
+ void editIncidenceSignal( Incidence *, const TQDate & );
+ void deleteIncidenceSignal( Incidence * );
private:
void search(const TQRegExp &);
diff --git a/korganizer/timelabels.cpp b/korganizer/timelabels.cpp
index 0c4956bd4..81b53c1f6 100644
--- a/korganizer/timelabels.cpp
+++ b/korganizer/timelabels.cpp
@@ -47,6 +47,7 @@ TimeLabels::TimeLabels(int rows,TQWidget *parent,const char *name,WFlags f) :
{
mRows = rows;
mMiniWidth = 0;
+ mAgenda = 0;
mCellHeight = KOPrefs::instance()->mHourSize*4;
@@ -204,16 +205,19 @@ void TimeLabels::updateConfig()
// If the agenda is zoomed out so that more then 24 would be shown,
// the agenda only shows 24 hours, so we need to take the cell height
// from the agenda, which is larger than the configured one!
- if ( mCellHeight < 4*mAgenda->gridSpacingY() )
+ if ( mAgenda && mCellHeight < 4*mAgenda->gridSpacingY() ) {
mCellHeight = 4*mAgenda->gridSpacingY();
+ }
resizeContents( mMiniWidth, int(mRows * mCellHeight+1) );
}
/** update time label positions */
void TimeLabels::positionChanged()
{
- int adjustment = mAgenda->contentsY();
- setContentsPos(0, adjustment);
+ if ( mAgenda ) {
+ int adjustment = mAgenda->contentsY();
+ setContentsPos( 0, adjustment );
+ }
}
void TimeLabels::positionChanged( int pos )
@@ -222,7 +226,7 @@ void TimeLabels::positionChanged( int pos )
}
/** */
-void TimeLabels::setAgenda(KOAgenda* agenda)
+void TimeLabels::setAgenda( KOAgenda* agenda )
{
mAgenda = agenda;
diff --git a/korganizer/timelineitem.cpp b/korganizer/timelineitem.cpp
index 7240e06d0..6ebff843f 100644
--- a/korganizer/timelineitem.cpp
+++ b/korganizer/timelineitem.cpp
@@ -31,8 +31,8 @@
using namespace KOrg;
using namespace KCal;
-TimelineItem::TimelineItem( const TQString &label, KDGanttView * parent) :
- KDGanttViewTaskItem( parent )
+TimelineItem::TimelineItem( const TQString &label, KCal::Calendar *calendar, KDGanttView * parent) :
+ KDGanttViewTaskItem( parent ), mCalendar( calendar )
{
setListViewText( 0, label );
setDisplaySubitemsAsGroup( true );
@@ -56,7 +56,7 @@ void TimelineItem::insertIncidence(KCal::Incidence * incidence, const TQDateTime
if ( (*it)->startTime() == start && (*it)->endTime() == end )
return;
- TimelineSubItem * item = new TimelineSubItem( incidence, this );
+ TimelineSubItem * item = new TimelineSubItem( mCalendar, incidence, this );
TQColor c1, c2, c3;
colors( c1, c2, c3 );
item->setColors( c1, c2, c3 );
@@ -91,14 +91,16 @@ void TimelineItem::moveItems(KCal::Incidence * incidence, int delta, int duratio
}
-TimelineSubItem::TimelineSubItem(KCal::Incidence * incidence, TimelineItem * parent) :
+TimelineSubItem::TimelineSubItem( KCal::Calendar *calendar,
+ KCal::Incidence *incidence, TimelineItem *parent) :
KDGanttViewTaskItem( parent ),
mIncidence( incidence ),
mLeft( 0 ),
mRight( 0 ),
mMarkerWidth( 0 )
{
- setTooltipText( IncidenceFormatter::toolTipString( incidence ) );
+ setTooltipText( IncidenceFormatter::toolTipStr( calendar, incidence,
+ originalStart().date(), true ) );
if ( !incidence->isReadOnly() ) {
setMoveable( true );
setResizeable( true );
diff --git a/korganizer/timelineitem.h b/korganizer/timelineitem.h
index 2ff3b2e06..a3406f115 100644
--- a/korganizer/timelineitem.h
+++ b/korganizer/timelineitem.h
@@ -42,7 +42,7 @@ class TimelineSubItem;
class TimelineItem : public KDGanttViewTaskItem
{
public:
- TimelineItem( const TQString &label, KDGanttView* parent );
+ TimelineItem( const TQString &label, KCal::Calendar *calendar, KDGanttView* parent );
void insertIncidence( KCal::Incidence *incidence,
const TQDateTime &start = TQDateTime(),
@@ -52,13 +52,14 @@ class TimelineItem : public KDGanttViewTaskItem
void moveItems( KCal::Incidence* incidence, int delta, int duration );
private:
+ KCal::Calendar *mCalendar;
TQMap<KCal::Incidence*, TQValueList<TimelineSubItem*> > mItemMap;
};
class TimelineSubItem : public KDGanttViewTaskItem
{
public:
- TimelineSubItem( KCal::Incidence *incidence, TimelineItem *parent );
+ TimelineSubItem( KCal::Calendar *calendar, KCal::Incidence *incidence, TimelineItem *parent );
~TimelineSubItem();
KCal::Incidence* incidence() const { return mIncidence; }
diff --git a/korganizer/tips b/korganizer/tips
index 50430aadc..31bf9fcb0 100644
--- a/korganizer/tips
+++ b/korganizer/tips
@@ -43,7 +43,7 @@
<tip category="KOrganizer|General">
<html>
-<p>...that you can import birthdays from your address book? There is a resource available which connects the birthdays to your calendar; it is even possible to set a reminder for each event.
+<p>...that your calender can display birthdays from your address book? It is even possible to set up reminders for them. To activate this, add the corresponding 'birthdays' resource to your calender.
</p>
</html>
</tip>
diff --git a/korganizer/urihandler.cpp b/korganizer/urihandler.cpp
index 4b7c7bdff..0c406318e 100644
--- a/korganizer/urihandler.cpp
+++ b/korganizer/urihandler.cpp
@@ -24,23 +24,58 @@
#include "urihandler.h"
+#include <libkcal/attachment.h>
+#include <libkcal/attachmenthandler.h>
+#include <libkcal/calendarresources.h>
+#include <libkcal/incidence.h>
+using namespace KCal;
+
#ifndef KORG_NODCOP
#include <dcopclient.h>
#include "kmailIface_stub.h"
#endif
-#include <kiconloader.h>
-#include <krun.h>
#include <kapplication.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kfiledialog.h>
+#include <kmessagebox.h>
+#include <kmimetype.h>
#include <kprocess.h>
+#include <krun.h>
+#include <ktempfile.h>
#include <kdebug.h>
+#include <kio/netaccess.h>
+
+#include <tqfile.h>
+
+TQString UriHandler::attachmentNameFromUri( const TQString &uri )
+{
+ TQString tmp;
+ if ( uri.startsWith( "ATTACH:" ) ) {
+ tmp = uri.mid( 9 ).section( ':', -1, -1 );
+ }
+ return tmp;
+}
+
+TQString UriHandler::uidFromUri( const TQString &uri )
+{
+ TQString tmp;
+ if ( uri.startsWith( "ATTACH:" ) ) {
+ tmp = uri.mid( 9 ).section( ':', 0, 0 );
+ } else if ( uri.startsWith( "uid:" ) ) {
+ tmp = uri.mid( 6 );
+ }
+ return tmp;
+}
-bool UriHandler::process( const TQString &uri )
+bool UriHandler::process( TQWidget *parent, const TQString &uri )
{
kdDebug(5850) << "UriHandler::process(): " << uri << endl;
#ifndef KORG_NODCOP
if ( uri.startsWith( "kmail:" ) ) {
+
// make sure kmail is running or the part is shown
kapp->startServiceByDesktopPath("kmail");
@@ -53,10 +88,15 @@ bool UriHandler::process( const TQString &uri )
KMailIface_stub kmailIface( "kmail", "KMailIface" );
kmailIface.showMail( serialNumberStr.toUInt(), TQString() );
return true;
+
} else if ( uri.startsWith( "mailto:" ) ) {
+
KApplication::kApplication()->invokeMailer( uri.mid(7), TQString::null );
return true;
+
} else if ( uri.startsWith( "uid:" ) ) {
+
+ TQString uid = uidFromUri( uri );
DCOPClient *client = KApplication::kApplication()->dcopClient();
const TQByteArray noParamData;
const TQByteArray paramData;
@@ -66,27 +106,31 @@ bool UriHandler::process( const TQString &uri )
"interfaces()", noParamData,
replyTypeStr, replyData );
if ( foundAbbrowser ) {
- //KAddressbook is already running, so just DCOP to it to bring up the contact editor
+ // KAddressbook is already running, so just DCOP to it to bring up the contact editor
#if KDE_IS_VERSION( 3, 2, 90 )
kapp->updateRemoteUserTimestamp("kaddressbook");
#endif
DCOPRef kaddressbook( "kaddressbook", "KAddressBookIface" );
- kaddressbook.send( "showContactEditor", uri.mid( 6 ) );
+ kaddressbook.send( "showContactEditor", uid );
return true;
} else {
- /*
- KaddressBook is not already running. Pass it the UID of the contact via the command line while starting it - its neater.
- We start it without its main interface
- */
+ // KaddressBook is not already running.
+ // Pass it the UID of the contact via the command line while starting it - its neater.
+ // We start it without its main interface
TQString iconPath = KGlobal::iconLoader()->iconPath( "go", KIcon::Small );
TQString tmpStr = "kaddressbook --editor-only --uid ";
- tmpStr += KProcess::quote( uri.mid( 6 ) );
+ tmpStr += KProcess::quote( uid );
KRun::runCommand( tmpStr, "KAddressBook", iconPath );
return true;
}
- }
- else { // no special URI, let KDE handle it
- new KRun(KURL( uri ));
+
+ } else if ( uri.startsWith( "ATTACH:" ) ) {
+
+ // a calendar incidence attachment
+ return AttachmentHandler::view( parent, attachmentNameFromUri( uri ), uidFromUri( uri ) );
+
+ } else { // no special URI, let KDE handle it
+ new KRun( KURL( uri ) );
}
#endif
diff --git a/korganizer/urihandler.h b/korganizer/urihandler.h
index 915b28578..1dc9264ca 100644
--- a/korganizer/urihandler.h
+++ b/korganizer/urihandler.h
@@ -24,16 +24,21 @@
#ifndef URIHANDLER_H
#define URIHANDLER_H
-#include <tqstring.h>
#include <kdepimmacros.h>
+class TQString;
+class TQWidget;
+
class KDE_EXPORT UriHandler
{
public:
/**
Process URI. Return true if handler handled the URI, otherwise false.
*/
- static bool process( const TQString &uri );
+ static bool process( TQWidget *parent, const TQString &uri );
+
+ static TQString attachmentNameFromUri( const TQString &uri );
+ static TQString uidFromUri( const TQString &uri );
};
#endif
diff --git a/korganizer/version.h b/korganizer/version.h
index 63a1b3a59..a25f926f2 100644
--- a/korganizer/version.h
+++ b/korganizer/version.h
@@ -53,6 +53,6 @@
3.2 alpha1
*/
-static const char korgVersion[] = "3.5.9";
+static const char korgVersion[] = "3.5.9 (enterprise35 0.20100827.1168748)";
#endif
diff --git a/korn/KOrn.desktop b/korn/KOrn.desktop
index 50f088ad7..baf41e58b 100644
--- a/korn/KOrn.desktop
+++ b/korn/KOrn.desktop
@@ -26,7 +26,6 @@ GenericName[hu]=Levélfigyelő
GenericName[is]=Póst áminning
GenericName[it]=Programma per controllare la posta
GenericName[ja]=メールの通知
-GenericName[ka]=საფოსტო სიგნალი
GenericName[kk]=Пошта келген туралы хабарлау
GenericName[km]=សញ្ញា​ជូនដំណឹងសំបុត្រ
GenericName[lt]=Pašto pranešėjas
@@ -55,8 +54,7 @@ GenericName[tg]=Маълумоти қабулшавии почта
GenericName[th]=แจ้งเตือนจดหมาย
GenericName[tr]=Midi Uyarısı
GenericName[uk]=Нагадування пошти
-GenericName[uz]=Yangi xat haqida xabar beruvchi
-GenericName[uz@cyrillic]=Янги хат ҳақида хабар берувчи
+GenericName[uz]=Янги хат ҳақида хабар берувчи
GenericName[ven]=U sedzesa poso
GenericName[xh]=Umposi Wokulumkisa
GenericName[zh_CN]=邮件警告
diff --git a/kpilot/conduits/abbrowserconduit/abbrowser_conduit.desktop b/kpilot/conduits/abbrowserconduit/abbrowser_conduit.desktop
index f25f458f2..5c95db5d9 100644
--- a/kpilot/conduits/abbrowserconduit/abbrowser_conduit.desktop
+++ b/kpilot/conduits/abbrowserconduit/abbrowser_conduit.desktop
@@ -24,7 +24,6 @@ Comment[hu]=Ezzel a csatolóval egy kéziszámítógép és a KDE címjegyzéke
Comment[is]=Þessi rás samstillir póstfangaskrár KDE og lófatölvunnar
Comment[it]=Questo condotto sincronizza il tuo palmare con la rubrica indirizzi di KDE
Comment[ja]=このコンジットはハンドヘルドのアドレス帳をKDEのアドレス帳と同期させます。
-Comment[ka]=ეს არხი KDE-ს წიგნაკის სინქრონიზაციას ახდენს პორტატიულ წიგნაკთან.
Comment[kk]=Қалта құрылғыдағы адрестік кітапшамен KDE-нің адрестік кітапшаларды қадамдастыру арнасы.
Comment[km]=បំពង់​នេះ​អាច​ឲ្យ​សៀវភៅ​អាសយដ្ឋាន​របស់​ឧបករណ៍​យួរដៃ ធ្វើ​សមកាលកម្ម​ជាមួយ​នឹង​សៀវភៅ​អាសយដ្ឋាន​របស់ KDE
Comment[lt]=Šis kanalas sinchronizuoja nešiojamą adresų knygelę su KDE adresų knygele.
@@ -81,7 +80,6 @@ Name[id]=Buku alamat
Name[is]=Póstfangaskrá
Name[it]=Rubrica degli indirizzi
Name[ja]=アドレス帳
-Name[ka]=წიგნაკი
Name[kk]=Адрестік кітапшасы
Name[km]=សៀវភៅ​អាសយដ្ឋាន
Name[lt]=Adresų knygelė
@@ -107,8 +105,7 @@ Name[ta]=முகவரிப்புத்தகம்
Name[tg]=Китоби адресӣ
Name[tr]=Adresdefteri
Name[uk]=Адресна книга
-Name[uz]=Manzillar daftari
-Name[uz@cyrillic]=Манзиллар дафтари
+Name[uz]=Манзиллар дафтари
Name[zh_CN]=地址簿
Name[zh_TW]=通訊錄
Implemented=file
diff --git a/kpilot/conduits/docconduit/doc_conduit.desktop b/kpilot/conduits/docconduit/doc_conduit.desktop
index 65f1ce425..324347e31 100644
--- a/kpilot/conduits/docconduit/doc_conduit.desktop
+++ b/kpilot/conduits/docconduit/doc_conduit.desktop
@@ -20,7 +20,6 @@ Comment[hu]=Szöveges fájlok hozzáadása a kézi számítógéphez, DOC-olvas
Comment[is]=Bætir textaskrám, sem hægt er að lesa í DOC lesara, við lófatölvuna þína.
Comment[it]=Aggiunge file di testo al tuo Pilot, adatti per lettori DOC.
Comment[ja]=テキストファイルを DOC リーダーに適した形式でハンドヘルドに追加します。
-Comment[ka]=უმატებს ტექსტურ ფაილებს თქვენს პროტატიულ მოწყობილობას, რომელიც შესაფერისია DOC წამკითხავებისთვის
Comment[kk]=DOC файлды оқи алатын қалта құрылғыға мәтінді көшіру.
Comment[km]=បន្ថែម​ឯកសារ​អត្ថបទ​ទៅ​ឧបករណ៍​យួរ​ដៃ​របស់​អ្នក (សមស្រប​សម្រាប់​កម្មវិធី​អាន DOC) ។
Comment[lt]=Prideda teksto bylas prie Jūsų nešiojamos knygelės, tinka DOC skaityklėms.
diff --git a/kpilot/conduits/docconduit/kpalmdoc.desktop b/kpilot/conduits/docconduit/kpalmdoc.desktop
index df897fb7d..6acbf66fd 100644
--- a/kpilot/conduits/docconduit/kpalmdoc.desktop
+++ b/kpilot/conduits/docconduit/kpalmdoc.desktop
@@ -29,7 +29,6 @@ GenericName[hu]=PalmDOC-konverter
GenericName[is]=PalmDOC umbreytir
GenericName[it]=Convertitore PalmDOC
GenericName[ja]= PalmDOC コンバータ
-GenericName[ka]=კონვერტორი PalmDOC
GenericName[kk]=PalmDOC аударғышы
GenericName[km]=កម្មវិធី​បម្លែង PalmDOC
GenericName[lt]=PalmDOC konverteris
diff --git a/kpilot/conduits/knotes/knotes-conduit.desktop b/kpilot/conduits/knotes/knotes-conduit.desktop
index 7f405cdb1..9155d4b03 100644
--- a/kpilot/conduits/knotes/knotes-conduit.desktop
+++ b/kpilot/conduits/knotes/knotes-conduit.desktop
@@ -24,7 +24,6 @@ Comment[hu]=Ezzel a csatolóval a Memo Pad program és a KNotes között lehet s
Comment[is]=Þessi rás samstillir lófatölvuna þína við KNotes.
Comment[it]=Questo condotto sincronizza l'applicazione Memo Pad con KNotes.
Comment[ja]=このコンジットはメモ帳アプリケーションを KNotes と同期させます。
-Comment[ka]=ეს არხი ახდენს Memo Pad პროგრამის სინქრონიზაციას KNotes-თან.
Comment[kk]=Memo Pad қолданбаны KNotes жазбаларымен қадамдастыру арнасы.
Comment[km]=បំពង់​នេះ​អាច​ឲ្យ​កម្មវិធី Memo Pad ធ្វើ​សមកាលកម្ម​ជាមួយ​នឹង KNotes ។
Comment[lt]=Šis kanalas sinchronizuoja Memo Pad programą su KNotes.
@@ -68,7 +67,6 @@ Name[hi]=के-नोट्स / मेमो
Name[hu]=KNotes / memók
Name[is]=KNotes / minnisblöð
Name[it]=KNotes / Memo
-Name[ka]=KNotes / ჩანიშვნები
Name[kk]=KNotes / Жазбалар
Name[km]=KNotes / អនុស្សរណៈ
Name[lt]=KNotes / Memo
diff --git a/kpilot/conduits/malconduit/mal_conduit.desktop b/kpilot/conduits/malconduit/mal_conduit.desktop
index 47bfe45b0..c502668dc 100644
--- a/kpilot/conduits/malconduit/mal_conduit.desktop
+++ b/kpilot/conduits/malconduit/mal_conduit.desktop
@@ -22,7 +22,6 @@ Name[hu]=MAL- (AvantGo) csatoló
Name[is]=MAL (AvantGo)-rás
Name[it]=Conduit MAL (AvantGo)
Name[ja]=MAL (AvantGo) コンジット
-Name[ka]=არხი MAL (AvantGo)
Name[kk]=MAL (AvantGo) арнасы
Name[km]=បំពង់ MAL (AvantGo)
Name[lt]=MAL (AvantGo) kanalas
@@ -68,7 +67,6 @@ Comment[hu]=AvantGo (vagy MAL-kiszolgáló) adatainak szinkronizálása a kézi
Comment[is]=Samstillir AvantGo (eða venjulega innihald MAL þjóns) við lófatölvuna. Þetta gerir þér kleyft að skoða vefsíður þegar þú ert ótengd(ur) vefnum, t.d. kvikmynda eða sjónvarpsdagskrá.
Comment[it]=Sincronizza AvantGo (o il contenuto di un generico server MAL) con il palmare. In questo modo potrai visualizzare le pagine web offline sul palmare come per esempio la programmazione di un cinema o una TV o qualsiasi altra pagina web.
Comment[ja]=AvantGo (または一般に MAL サーバのコンテンツ) とハンドヘルドを同期させます。これにより、ハンドヘルドで映画や TV 番組表、その他のウェブページをオフラインで閲覧できるようになります。
-Comment[ka]= AvantGo-ს სინქრონიზაცია (ძირითადად MAL სერვერების შემადგენლობით) პორტატიულ მოწყობილობასთან. ეს ვებ-გვერდების ავტონომიურ რეჟიმში დათვალიერების საშუალებას იძლევა,მაგ.: თქვენი კინო ან ტელე პროგრამა, ან სხვა ვებ-გვერდები.
Comment[kk]=AvantGo (немесе жалпы MAL сервердің мазмұнын) қалта құрылғымен қадамдастыру арнасы. Бұл сол құрылғыда кино, ТВ кестеңізді немесе басқа веб парақтарды желіге қосылмай көруге мүмкіндік береді.
Comment[km]=ធ្វើ​សមកាលកម្ម AvantGo (ជាទូទៅ​គឺ មាតិកា​របស់​ម៉ាស៊ីន​បម្រើ MAL) ទៅ​នឹង​ឧបករណ៍​យួរ​ដៃ ។ វា​អនុញ្ញាត​ឲ្យ​អ្នក​មើល​ទំព័រ​បណ្ដាញ (កាលវិភាគ​រោង​ភាពយន្ត ឬ ទូរទស្សន៍...) នៅ​ក្រៅ​បណ្ដាញ នៅ​លើ​ឧបករណ៍​យួរ​ដៃ​របស់​អ្នក ។
Comment[lt]=Sinchronizuoti AvantGo (ar MAL serverio turinį apskritai) su nešiojamu įrenginiu. Tai leis jums peržiūrėti žiniatinklio puslapius nešiojamame įrenginyje, tokius kaip kino teatro ar TV programas, bei bet kokį kitą puslapį, neprisijungus prie Interneto.
diff --git a/kpilot/conduits/memofileconduit/memofile-conduit.desktop b/kpilot/conduits/memofileconduit/memofile-conduit.desktop
index c453821f5..cb288d23e 100644
--- a/kpilot/conduits/memofileconduit/memofile-conduit.desktop
+++ b/kpilot/conduits/memofileconduit/memofile-conduit.desktop
@@ -22,7 +22,6 @@ Name[hu]=Memófájl
Name[is]=Minnismiðaskrá
Name[it]=File appunti
Name[ja]=メモファイル
-Name[ka]=ჩანიშვნა
Name[kk]=Жазба файлы
Name[km]=ឯកសារ​អនុស្សរណៈ
Name[lt]=Memo byla
@@ -65,7 +64,6 @@ Comment[hu]=Ezzel a csatolóval egy kézi számítógép memóit lehet szinkroni
Comment[is]=Þessi rás samstillir minnismiða lófatölvunnar þinnar við staðbundna möppu.
Comment[it]=Questo condotto sincronizza gli appunti del tuo palmare con una cartella locale.
Comment[ja]=このコンジットはハンドヘルドのメモをローカルのディレクトリと同期させます。
-Comment[ka]=ეს არხი თქვენი პორტატიული მოწყობილობის ლოკალურ დირექტორიასთან სინქრონიზაციას ახდენს .
Comment[kk]=Қалта құрылғыдағы жазбаларды қапшықтағы файлымен қадамдастыру арнасы.
Comment[km]=បំពង់​នេះ​អាច​ឲ្យ​អនុស្សរណៈ​ឧបករណ៍​យួរ​ដៃ​របស់​អ្នក ធ្វើ​សមកាលកម្ម​ជាមួយ​នឹង​ថត​មូលដ្ឋាន ។​
Comment[lt]=Šis kanalas sinchronizuoja Jūsų užrašus su vietiniu aplanku.
diff --git a/kpilot/conduits/notepadconduit/notepad-conduit.desktop b/kpilot/conduits/notepadconduit/notepad-conduit.desktop
index 4aa10dbee..484762198 100644
--- a/kpilot/conduits/notepadconduit/notepad-conduit.desktop
+++ b/kpilot/conduits/notepadconduit/notepad-conduit.desktop
@@ -30,14 +30,13 @@ Comment[et]=See kanal teeb NotePadi joonistustest varukoopia kohalikku kataloogi
Comment[eu]=Kanal honek Ohar-blokaren marrazkiak karpeta lokal batera gordetzen ditu.
Comment[fa]=این لوله، ترسیمهای NotePad را در پوشه‌ای محلی پشتیبانی می‌کند.
Comment[fi]=Tämä yhdyskäytävä tekee varmuuskopion NotePad -piirroksista paikalliseen kansioon.
-Comment[fr]=Ce conduit enregistre les dessins (Notes) dans un dossier local.
+Comment[fr]=Ce conduit sauvegarde les dessins (Notes) dans un dossier local
Comment[fy]=Dit conduit makket in reservekopy fan de notysje fan de notysje-oantekenings nei in lokale map.
Comment[gl]=Este conducto pon de volta os debuxos do NotePad a un cartafol local.
Comment[hu]=Bővítőmodul NotePad-rajzok helyi könyvtárba való lementéséhez.
Comment[is]=Þessi rás afritar NotePad teikningar í staðbundna möppu.
Comment[it]=Questo conduit archivia i disegni NotePad in una cartella locale.
Comment[ja]=このコンジットは NotePad の絵をローカルのフォルダにバックアップします。
-Comment[ka]=ეს არხი ლოკალურ საქაღალდეში ინახავს NotePad-ის სარეზერვო მონახაზებს
Comment[kk]=NotePad файлдарының сақтық көшірмелерін жергілікті қапшықта жасау арнасы.
Comment[km]=បំពង់​នេះ​អាច​បម្រុង​ទុក​គំនូរ NotePad ទៅ​ថត​មូលដ្ឋាន ។
Comment[lt]=Šis kanalas padaro NotePad piešinių atsargines kopijas į vietinį aplanką.
diff --git a/kpilot/conduits/null/null-conduit.desktop b/kpilot/conduits/null/null-conduit.desktop
index 1a0c225dc..3aa6fdf52 100644
--- a/kpilot/conduits/null/null-conduit.desktop
+++ b/kpilot/conduits/null/null-conduit.desktop
@@ -32,7 +32,6 @@ Comment[hu]=Ez a csatoló üres, csak tesztelési célokat szolgál
Comment[is]=Þessi rás gerir ekki neitt.
Comment[it]=Questo conduit non fa nulla.
Comment[ja]=このコンジットは未知です。
-Comment[ka]=ეს არხი არაფერს არ აკეთებს.
Comment[kk]=Ештеңе істемейтін арна.
Comment[km]=បំពង់​នេះ​មិន​ធ្វើ​អ្វី​ទាំងអស់ ។
Comment[lt]=Šis kanalas nieko neatlieka.
diff --git a/kpilot/conduits/popmail/popmail-conduit.desktop b/kpilot/conduits/popmail/popmail-conduit.desktop
index b4cdc0175..7f1b9a388 100644
--- a/kpilot/conduits/popmail/popmail-conduit.desktop
+++ b/kpilot/conduits/popmail/popmail-conduit.desktop
@@ -21,7 +21,6 @@ Comment[hu]=Ezzel a csatolóval kézi számítógépről lehet levelet küldeni
Comment[is]=Sendu tölvupóst frá lófatölvunni þinni gegnum KMail.
Comment[it]=Invia la posta dal tuo palmare tramite KMail.
Comment[ja]=KMail 経由でハンドヘルドからメールを送信します。
-Comment[ka]= ფოსტის გაგზავნა პორტატიული მოწყობილობიდან KMail-ის საშუალებით.
Comment[kk]=Қалта құрылғының поштасын KMail арқылы жіберу.
Comment[km]=ផ្ញើ​សំបុត្រ​ទៅ​ឧបករណ៍​យួរដៃ​របស់​អ្នក​តាម​រយៈ KMail ។
Comment[lt]=Siųsti paštą iš nešiojamo įrenginio per KMail.
@@ -72,7 +71,6 @@ Name[hu]=E-mail
Name[is]=Póstur
Name[it]=Posta
Name[ja]=メール
-Name[ka]=ფოსტა
Name[kk]=Пошта
Name[km]=សំបុត្រ
Name[lt]=Paštas
@@ -100,8 +98,7 @@ Name[tg]=Мактуб
Name[th]=จดหมาย
Name[tr]=Posta
Name[uk]=Пошта
-Name[uz]=Xat-xabar
-Name[uz@cyrillic]=Хат-хабар
+Name[uz]=Хат-хабар
Name[zh_CN]=邮件
Name[zh_TW]=郵件
Implemented=file
diff --git a/kpilot/conduits/recordconduit/record-conduit.desktop b/kpilot/conduits/recordconduit/record-conduit.desktop
index 55c953d17..a96f24ecc 100644
--- a/kpilot/conduits/recordconduit/record-conduit.desktop
+++ b/kpilot/conduits/recordconduit/record-conduit.desktop
@@ -14,7 +14,6 @@ Name[fr]=Enregistrements (expérimental)
Name[fy]=Opnames (eksperimenteel)
Name[gl]=Grava (Experimental)
Name[hu]=Rekordok (kísérleti)
-Name[is]=Færslur (á tilraunastigi)
Name[it]=Record (sperimentale)
Name[ja]=レコード (実験中)
Name[kk]=Жазулар (Эксперименталдық)
@@ -61,7 +60,6 @@ Comment[hu]=Ez a csatoló üres, csak tesztelési célokat szolgál
Comment[is]=Þessi rás gerir ekki neitt.
Comment[it]=Questo conduit non fa nulla.
Comment[ja]=このコンジットは未知です。
-Comment[ka]=ეს არხი არაფერს არ აკეთებს.
Comment[kk]=Ештеңе істемейтін арна.
Comment[km]=បំពង់​នេះ​មិន​ធ្វើ​អ្វី​ទាំងអស់ ។
Comment[lt]=Šis kanalas nieko neatlieka.
diff --git a/kpilot/conduits/sysinfoconduit/sysinfo_conduit.desktop b/kpilot/conduits/sysinfoconduit/sysinfo_conduit.desktop
index 7e7b04380..f31bd0653 100644
--- a/kpilot/conduits/sysinfoconduit/sysinfo_conduit.desktop
+++ b/kpilot/conduits/sysinfoconduit/sysinfo_conduit.desktop
@@ -23,7 +23,6 @@ Comment[hu]=Ezzel a csatolóval fájlba lehet kiíratni a kéziszámítógép é
Comment[is]=Þessi rás skrifar upplýsingar um lófatölvuna þína og samstillinguna í skrá.
Comment[it]=Questo conduit scrive in un file informazioni sul tuo palmare.
Comment[ja]=このコンジットはあなたのハンドヘルドの情報を書き出し、ファイルに同期します。
-Comment[ka]=ეს არხი ინფორმაციას წერს თქვენი პორტატიული მოწყობილობის შესახებ და ახდენს მის სინქრონიზაციას ფაილთან.
Comment[kk]=Қалта құрылғыңыз туралы мәліметті файла жазу арнасы.
Comment[km]=បំពង់​នេះ​សរសេរ​ព័ត៌មាន​អំពី​ឧបករណ៍​យួរដៃ​របស់​អ្នក និង​ការ​ធ្វើ​សមកាលកម្ម ទៅ​ឯកសារ​មួយ ។
Comment[lt]=Šis kanalas įrašo informaciją apie delninuką ir sinchronizavimą į bylą.
@@ -76,7 +75,6 @@ Name[hu]=Rendszerinformáció
Name[is]=Kerfisupplýsingar
Name[it]=Informazioni di sistema
Name[ja]=システム情報
-Name[ka]=სისტემის ინფორმაცია
Name[kk]=Жүйелік мәлімет
Name[km]=ព័ត៌មាន​អំពី​ប្រព័ន្ធ
Name[lt]=Sistemos informacija
@@ -102,8 +100,7 @@ Name[ta]=அமைப்பு தகவல்
Name[tg]=Иттилоот дар бораи система
Name[tr]=Sistem Bilgisi
Name[uk]=Системна інформація
-Name[uz]=Tizim haqida maʼlumot
-Name[uz@cyrillic]=Тизим ҳақида маълумот
+Name[uz]=Тизим ҳақида маълумот
Name[zh_CN]=系统信息
Name[zh_TW]=系統資訊
Implemented=file
diff --git a/kpilot/conduits/timeconduit/time_conduit.desktop b/kpilot/conduits/timeconduit/time_conduit.desktop
index cbdafc9f4..386868a66 100644
--- a/kpilot/conduits/timeconduit/time_conduit.desktop
+++ b/kpilot/conduits/timeconduit/time_conduit.desktop
@@ -23,7 +23,6 @@ Comment[hu]=Ez a csatoló beállítja a kéziszámítógép óráját a számít
Comment[is]=Þessi rás stillir klukku lófatölvunnar eftir klukku PC tölvunnar.
Comment[it]=Questo conduit imposta l'ora sul tuo palmare prendendola dall'orologio del PC
Comment[ja]=このコンジットはハンドヘルドの時間をPCの時計に合わせます。
-Comment[ka]=დროის მითითება კომპიუტერის საათისთვის.
Comment[km]=បំពង់​នេះ​កំណត់​ពេលវេលា​នៅ​លើ​ឧបករណ៍​យួរដៃ​របស់​អ្នក ពី​នាឡិកា​កុំព្យូទ័រ ។
Comment[lt]=Šis kanalas nustato delninuko laiką pagal PC laiką.
Comment[mk]=Овој канал го поставува времето на рачниот уред според времето на компјутерот.
@@ -75,7 +74,6 @@ Name[hu]=Időszinkronizálás
Name[is]=Tíma samstilling
Name[it]=Sincronizzazione temporale
Name[ja]=時間同期
-Name[ka]=დროის სინქრონიზაცია
Name[kk]=Уақытты қадамдастыру
Name[km]=សមកាលកម្ម​ពេលវេលា
Name[lt]=Laiko sinchronizavimas
diff --git a/kpilot/conduits/vcalconduit/todo-conduit.desktop b/kpilot/conduits/vcalconduit/todo-conduit.desktop
index dcf7c2225..d1101af14 100644
--- a/kpilot/conduits/vcalconduit/todo-conduit.desktop
+++ b/kpilot/conduits/vcalconduit/todo-conduit.desktop
@@ -24,7 +24,6 @@ Comment[hu]=Ezzel a csatolóval a Pilot tennivalólistája és a KOrganizer tenn
Comment[is]=Þessi rás samstillir verkþáttalista lófatölvunnar þinnar og KOrganizer.
Comment[it]=Questo condotto sincronizza il tuo Pilot con la lista delle cose da fare di KOrganizer.
Comment[ja]=このコンジットはハンドヘルドの To-Do と KOrganizer を同期させます。
-Comment[ka]=ამოცანათა სიების სინქრონიზაცია KOrganizer-ისთვის.
Comment[kk]=Қалта құрылғыдағы жоспар тізімін KOrganizer-мен қадамдастыру арнасы.
Comment[km]=បំពង់​នេះ​ធ្វើ​សមកាលកម្ម​បញ្ជី​ការងារ​ត្រូវ​ធ្វើ​ពី​ឧបករណ៍​យួរ​ដៃ​របស់​អ្នកទៅ KOrganizer ។
Comment[lt]=Šis kanalas sinchronizuoja Jūsų darbų sąrašą iš delninuko su su KOrganizer sąrašu.
@@ -76,7 +75,6 @@ Name[hu]=Feladatok (KOrganizer)
Name[is]=Verkþáttalistar (KOrganizer)
Name[it]=Cose da fare (KOrganizer)
Name[ja]=To-Do (KOrganizer)
-Name[ka]=ამოცანები (KOrganizer)
Name[kk]=Жоспарлар (KOrganizer)
Name[km]=ការងារ​ត្រូវ​ធ្វើ (KOrganizer)
Name[lt]=Darbai (KOrganizer)
diff --git a/kpilot/conduits/vcalconduit/vcal-conduit.desktop b/kpilot/conduits/vcalconduit/vcal-conduit.desktop
index e0a84c55f..c123bf168 100644
--- a/kpilot/conduits/vcalconduit/vcal-conduit.desktop
+++ b/kpilot/conduits/vcalconduit/vcal-conduit.desktop
@@ -27,7 +27,6 @@ Name[hu]=Naptár (KOrganizer)
Name[is]=Dagbók (KOrganizer)
Name[it]=Calendario (KOrganizer)
Name[ja]=カレンダー (KOrganizer)
-Name[ka]=კალენდარი (KOrganizer)
Name[kk]=Күнтізбе (KOrganizer)
Name[km]=ប្រតិទិន (KOrganizer)
Name[lt]=Kalendorius (KOrganizer)
@@ -76,7 +75,6 @@ Comment[hu]=Ezzel a csatolóval szinkronizálhatók a kézi számítógép és a
Comment[is]=Þessi rás samstillir lófatölvuna þína við dagbók KOrganizer.
Comment[it]=Questo conduit sincronizza il tuo palmare con il calendario di KOrganizer.
Comment[ja]=このコンジットはハンドヘルドを KOrganizer の手帳と同期させます。
-Comment[ka]=სინქრონიზაცია KOrganizer-ისთვის.
Comment[kk]=Қалта құрылғыдағы күнтізбені KOrganizer-мен қадамдастыру арнасы.
Comment[km]=បំពង់​នេះ​ធ្វើ​សមកាលកម្ម​ឧបករណ៍​យួរ​ដៃ​របស់​អ្នក​ជាមួយ​នឹង​សៀវភៅ​កាលបរិច្ឆេទ KOrganizer ។
Comment[lt]=Šis kanalas sinchronizuoja jūsų delninuką su KOrganizer datų knyga.
diff --git a/kpilot/kpilot/kpilot.desktop b/kpilot/kpilot/kpilot.desktop
index b3a9bdbb4..8d1a0ea97 100644
--- a/kpilot/kpilot/kpilot.desktop
+++ b/kpilot/kpilot/kpilot.desktop
@@ -42,7 +42,6 @@ GenericName[hu]=PalmPilot-kezelő
GenericName[is]=PalmPilot tól
GenericName[it]=Strumento per PalmPilot
GenericName[ja]=PalmPilot ツール
-GenericName[ka]=Palm Pilot ხელსაწყო
GenericName[kk]=PalmPilot құрылғысы
GenericName[km]=ឧបករណ៍ PalmPilot
GenericName[lt]=PalmPilot įrankis
diff --git a/kpilot/kpilot/kpilot_config.desktop b/kpilot/kpilot/kpilot_config.desktop
index 58cc75d5e..075e31cd9 100644
--- a/kpilot/kpilot/kpilot_config.desktop
+++ b/kpilot/kpilot/kpilot_config.desktop
@@ -36,7 +36,6 @@ Name[hu]=A KPilot beállításai
Name[is]=KPilot stillingar
Name[it]=Configurazione KPilot
Name[ja]=KPilot の設定
-Name[ka]=KPilot კონფიგურაცია
Name[kk]=KPilot параметрлері
Name[km]=ការ​កំណត់​រចនាសម្ព័ន្ធ KPilot
Name[lt]=Kpilot konfigūracija
@@ -87,7 +86,6 @@ Comment[hu]=A KPilot legfontosabb beállításai
Comment[is]=Aðalstillingar KPilot
Comment[it]=Configurazione principale di KPilot
Comment[ja]=KPilot 主要設定
-Comment[ka]=KPilot ძირითადი კონფიგურაცია
Comment[kk]=KPilot негізгі параметрлері
Comment[km]=ការ​កំណត់​រចនាសម្ព័ន្ធ​សំខាន់ៗ​របស់ KPilot
Comment[lt]=KPilot bendrasis konfigūravimas
@@ -134,7 +132,6 @@ Keywords[hu]=kpilot,alap
Keywords[is]=kpilot,aðal
Keywords[it]=kpilot,principale
Keywords[ja]=kpilot,主要
-Keywords[ka]=kpilot,ძირითადი
Keywords[km]=kpilot,សំខាន់
Keywords[lt]=kpilot,main,pagrindinis
Keywords[mk]=kpilot,main.кпилот,главно
diff --git a/kpilot/kpilot/kpilotconduit.desktop b/kpilot/kpilot/kpilotconduit.desktop
index 75eeaab19..21214231b 100644
--- a/kpilot/kpilot/kpilotconduit.desktop
+++ b/kpilot/kpilot/kpilotconduit.desktop
@@ -28,7 +28,6 @@ Comment[hu]=KPilot-csatoló
Comment[is]=KPilot rásir
Comment[it]=Conduit KPilot
Comment[ja]=KPilot コンジット
-Comment[ka]=არხი KPilot
Comment[kk]=KPilot арнасы
Comment[km]=បំពង់ KPilot
Comment[lt]=KPilot kanalas
diff --git a/kpilot/kpilot/kpilotdaemon.desktop b/kpilot/kpilot/kpilotdaemon.desktop
index cbeb9dada..917beab64 100644
--- a/kpilot/kpilot/kpilotdaemon.desktop
+++ b/kpilot/kpilot/kpilotdaemon.desktop
@@ -15,7 +15,6 @@ Name[hi]=के-पायलट-डेमन
Name[is]=KPilot þjónn
Name[it]=Demone KPilot
Name[ja]=KPilot デーモン
-Name[ka]=KPilot-ის დემონი
Name[lt]=KPilot tarnyba
Name[lv]=KPilotDēmons
Name[ms]=Daemon KPilot
diff --git a/kresources/Makefile.am b/kresources/Makefile.am
index eb2178697..1ae15a7d8 100644
--- a/kresources/Makefile.am
+++ b/kresources/Makefile.am
@@ -1,5 +1,5 @@
if include_exchange_SUBDIR
-EXCHANGE_SUBDIR=exchange
+EXCHANGE_SUBDIR=exchange
endif
SUBDIRS = lib remote egroupware $(EXCHANGE_SUBDIR) kolab slox groupwise featureplan groupdav birthdays newexchange scalix caldav carddav
diff --git a/kresources/birthdays/kabc.desktop b/kresources/birthdays/kabc.desktop
index aec8d565c..cea676fa6 100644
--- a/kresources/birthdays/kabc.desktop
+++ b/kresources/birthdays/kabc.desktop
@@ -28,7 +28,6 @@ Name[hu]=Születésnapok a KAddressBookból
Name[is]=Afmælisdagar úr KAddressBook
Name[it]=Compleanni da KAddessBook
Name[ja]=アドレス帳の誕生日
-Name[ka]=დაბადების დღეები KDE წიგნაკიდან
Name[kk]=KAddressBook-тағы туған күндер
Name[km]=ថ្ងៃ​ខួប​កំណើត​ពី KAddressBook
Name[lt]=Gimtadieniai iš KAddressBook
diff --git a/kresources/birthdays/resourcekabc.cpp b/kresources/birthdays/resourcekabc.cpp
index dc902c5bf..65830782e 100644
--- a/kresources/birthdays/resourcekabc.cpp
+++ b/kresources/birthdays/resourcekabc.cpp
@@ -46,6 +46,8 @@
#include "libkcal/filestorage.h"
#include "libkcal/alarm.h"
+#include <libemailfunctions/email.h>
+
#include <kresources/configwidget.h>
#include "resourcekabcconfig.h"
@@ -70,6 +72,8 @@ ResourceKABC::ResourceKABC( const KConfig* config )
{
if ( config ) {
readConfig( config );
+ } else {
+ setResourceName( i18n( "Birthdays" ) );
}
init();
@@ -227,7 +231,8 @@ bool ResourceKABC::doLoad()
bool found = false;
for ( addrIt = anniversaries.begin(); addrIt != anniversaries.end(); ++addrIt ) {
if ( name == (*addrIt).realName() ) {
- TQDateTime spouseAnniversary = TQDate::fromString( (*addrIt).custom( "KADDRESSBOOK", "X-Anniversary" ), Qt::ISODate );
+ TQDate spouseAnniversary =
+ TQDate::fromString( (*addrIt).custom( "KADDRESSBOOK", "X-Anniversary" ), Qt::ISODate );
if ( anniversary == spouseAnniversary ) {
found = true;
break;
@@ -255,22 +260,30 @@ bool ResourceKABC::doLoad()
TQString spouseName = (*addrIt).custom( "KADDRESSBOOK", "X-SpousesName" );
TQString name_2,email_2,uid_2;
if ( !spouseName.isEmpty() ) {
- //TODO: find a KABC:Addressee of the spouse
- // Probably easiest would be to use a TQMap (as the spouse's entry was already searched above!
+ TQString tname, temail;
+ KPIM::getNameAndMail( spouseName, tname, temail );
+ tname = KPIM::quoteNameIfNecessary( tname );
+ if ( ( tname[0] == '"' ) && ( tname[tname.length() - 1] == '"' ) ) {
+ tname.remove( 0, 1 );
+ tname.truncate( tname.length() - 1 );
+ }
KABC::Addressee spouse;
- spouse.setNameFromString( spouseName );
+ spouse.setNameFromString( tname );
+ name_2 = spouse.nickName();
uid_2 = spouse.uid();
email_2 = spouse.fullEmail();
- name_2 = spouse.nickName();
- if ( name_2.isEmpty() )
- name_2 = spouse.givenName();
- summary = i18n("insert names of both spouses", "%1's & %2's anniversary").arg( name_1 ).arg( name_2 );
+ if ( name_2.isEmpty() ) {
+ name_2 = spouse.realName();
+ }
+ summary = i18n("insert names of both spouses",
+ "%1's & %2's anniversary").arg( name_1 ).arg( name_2 );
} else {
- summary = i18n("only one spouse in addressbook, insert the name", "%1's anniversary").arg( name_1 );
+ summary = i18n("only one spouse in addressbook, insert the name",
+ "%1's anniversary").arg( name_1 );
}
Event *ev = new Event();
- ev->setUid( uid_1+"_KABC_Anniversary" );
+ ev->setUid( uid_1+"_KABC_Anniversary" );
ev->setDtStart(anniversary);
ev->setDtEnd(anniversary);
@@ -378,12 +391,17 @@ KABC::Lock *ResourceKABC::lock()
}
-bool ResourceKABC::addEvent(Event*)
+bool ResourceKABC::addEvent( Event * )
+{
+ return false;
+}
+
+bool ResourceKABC::addEvent( Event *, const TQString & )
{
return false;
}
-bool ResourceKABC::deleteEvent(Event*)
+bool ResourceKABC::deleteEvent( Event * )
{
return false;
}
@@ -417,12 +435,17 @@ Event::List ResourceKABC::rawEvents( EventSortField sortField, SortDirection sor
return mCalendar.rawEvents( sortField, sortDirection );
}
-bool ResourceKABC::addTodo(Todo*)
+bool ResourceKABC::addTodo( Todo * )
{
return false;
}
-bool ResourceKABC::deleteTodo(Todo*)
+bool ResourceKABC::addTodo( Todo *, const TQString & )
+{
+ return false;
+}
+
+bool ResourceKABC::deleteTodo( Todo * )
{
return false;
}
@@ -444,12 +467,17 @@ Todo::List ResourceKABC::rawTodosForDate( const TQDate &date )
}
-bool ResourceKABC::addJournal(Journal*)
+bool ResourceKABC::addJournal( Journal * )
+{
+ return false;
+}
+
+bool ResourceKABC::addJournal( Journal *, const TQString & )
{
return false;
}
-bool ResourceKABC::deleteJournal(Journal*)
+bool ResourceKABC::deleteJournal( Journal * )
{
return false;
}
diff --git a/kresources/birthdays/resourcekabc.h b/kresources/birthdays/resourcekabc.h
index eebe087e9..9dedd0ab6 100644
--- a/kresources/birthdays/resourcekabc.h
+++ b/kresources/birthdays/resourcekabc.h
@@ -76,7 +76,8 @@ class KDE_EXPORT ResourceKABC : public ResourceCalendar
KABC::Lock *lock();
/** Add Event to calendar. */
- bool addEvent(Event *anEvent);
+ KDE_DEPRECATED bool addEvent(Event *event);
+ bool addEvent( Event *event, const TQString &subresource );
/** deletes an event from this calendar. */
bool deleteEvent(Event *);
@@ -107,7 +108,8 @@ class KDE_EXPORT ResourceKABC : public ResourceCalendar
/**
Add a todo to the todolist.
*/
- bool addTodo( Todo *todo );
+ KDE_DEPRECATED bool addTodo( Todo *todo );
+ bool addTodo( Todo *todo, const TQString &subresource );
/**
Remove a todo from the todolist.
*/
@@ -126,7 +128,9 @@ class KDE_EXPORT ResourceKABC : public ResourceCalendar
*/
Todo::List rawTodosForDate( const TQDate &date );
/** Add a Journal entry to calendar */
- virtual bool addJournal(Journal *);
+ KDE_DEPRECATED bool addJournal( Journal *journal );
+ bool addJournal( Journal *journal, const TQString &subresource );
+
/** Remove journal from the calendar. */
bool deleteJournal( Journal * );
/** Return Journal with given UID */
diff --git a/kresources/blogging/blogging.desktop b/kresources/blogging/blogging.desktop
index 061b06341..23b367a93 100644
--- a/kresources/blogging/blogging.desktop
+++ b/kresources/blogging/blogging.desktop
@@ -19,7 +19,6 @@ Name[hu]=Naplók blogként tárolása a kiszolgálón
Name[is]=Dagbækur sem blogg á þjóni
Name[it]=Diari come blog su un server
Name[ja]=サーバ上のブログとしてのジャーナル
-Name[ka]=ბლოგისმაგვარი ჟურნალები სერვერზე
Name[kk]=Сервердегі күнделік блог ретінде
Name[km]=ទិនានុប្បវត្តិ​ជា​កំណត់ហេតុ​បណ្ដាញ​នៅ​លើ​ម៉ាស៊ីន​បម្រើ
Name[lt]=Dienynai kaip Blog'ai serveryje
diff --git a/kresources/blogging/kcal_resourceblogging.cpp b/kresources/blogging/kcal_resourceblogging.cpp
index 6f7ed46ec..07d097db9 100644
--- a/kresources/blogging/kcal_resourceblogging.cpp
+++ b/kresources/blogging/kcal_resourceblogging.cpp
@@ -38,7 +38,11 @@ ResourceBlogging::ResourceBlogging( const KConfig *config )
: ResourceGroupwareBase( config )
{
init();
- if ( config ) readConfig( config );
+ if ( config ) {
+ readConfig( config );
+ } else {
+ setResourceName( i18n( "Blogs" ) );
+ }
}
void ResourceBlogging::init()
diff --git a/kresources/caldav/config.cpp b/kresources/caldav/config.cpp
index 550e00c97..84a4798c6 100644
--- a/kresources/caldav/config.cpp
+++ b/kresources/caldav/config.cpp
@@ -89,7 +89,9 @@ void ResourceCalDavConfig::loadSettings( KRES::Resource *resource ) {
mRememberPassword->setChecked(p->rememberPassword());
mPassword->setText(p->password());
mTasksUrl->setText(p->tasksUrl());
+ mJournalsUrl->setText(p->journalsUrl());
mUseSTasks->setChecked(p->useSTasks());
+ mUseSJournals->setChecked(p->useSJournals());
mReloadConfig->loadSettings(res);
mSaveConfig->loadSettings(res);
@@ -110,6 +112,8 @@ void ResourceCalDavConfig::saveSettings( KRES::Resource *resource ) {
p->setPassword(mPassword->text());
p->setTasksUrl(mTasksUrl->text());
p->setUseSTasks(mUseSTasks->isChecked());
+ p->setJournalsUrl(mJournalsUrl->text());
+ p->setUseSJournals(mUseSJournals->isChecked());
}
}
}
@@ -128,34 +132,48 @@ void ResourceCalDavConfig::setupUI() {
// Tasks URL
TQLabel *tlabel = new TQLabel( i18n( "Tasks URL:" ), this );
mTasksUrl = new TQLineEdit( this );
- mainLayout->addWidget( tlabel, 2, 0 );
- mainLayout->addWidget( mTasksUrl, 2, 1 );
+ mainLayout->addWidget( tlabel, 3, 0 );
+ mainLayout->addWidget( mTasksUrl, 3, 1 );
// Use Task URL checkbox
mUseSTasks = new TQCheckBox( i18n("Use separate Tasks URL"), this );
- mainLayout->addWidget(mUseSTasks, 3, 0 );
+ mainLayout->addWidget(mUseSTasks, 2, 0 );
+
+ // Journals URL
+ TQLabel *jlabel = new TQLabel( i18n( "Journals URL:" ), this );
+ mJournalsUrl = new TQLineEdit( this );
+ mainLayout->addWidget( jlabel, 5, 0 );
+ mainLayout->addWidget( mJournalsUrl, 5, 1 );
+
+ // Use Journal URL checkbox
+ mUseSJournals = new TQCheckBox( i18n("Use separate Journals URL"), this );
+ mainLayout->addWidget(mUseSJournals, 4, 0 );
// Username
label = new TQLabel( i18n( "Username:" ), this );
mUsername = new TQLineEdit( this );
- mainLayout->addWidget( label, 4, 0 );
- mainLayout->addWidget( mUsername, 4, 1 );
+ mainLayout->addWidget( label, 6, 0 );
+ mainLayout->addWidget( mUsername, 6, 1 );
// Password
label = new TQLabel( i18n( "Password:" ), this );
mPassword = new TQLineEdit( this );
mPassword->setEchoMode( TQLineEdit::Password );
- mainLayout->addWidget( label, 5, 0 );
- mainLayout->addWidget( mPassword, 5, 1 );
+ mainLayout->addWidget( label, 7, 0 );
+ mainLayout->addWidget( mPassword, 7, 1 );
// Remember password checkbox
mRememberPassword = new TQCheckBox( i18n("Remember password"), this );
- mainLayout->addWidget(mRememberPassword, 6, 1);
+ mainLayout->addWidget(mRememberPassword, 8, 1);
mTasksUrl->setEnabled(mUseSTasks->isChecked());
connect( mUseSTasks, TQT_SIGNAL( toggled( bool ) ),
TQT_SLOT( slotSTasksToggled( bool ) ) );
+ mJournalsUrl->setEnabled(mUseSJournals->isChecked());
+ connect( mUseSJournals, TQT_SIGNAL( toggled( bool ) ),
+ TQT_SLOT( slotSJournalsToggled( bool ) ) );
+
// configs
TQHBoxLayout* horizontal = new TQHBoxLayout(this);
@@ -181,4 +199,8 @@ void ResourceCalDavConfig::slotSTasksToggled( bool enabled ) {
mTasksUrl->setEnabled(enabled);
}
+void ResourceCalDavConfig::slotSJournalsToggled( bool enabled ) {
+ mJournalsUrl->setEnabled(enabled);
+}
+
// EOF ========================================================================
diff --git a/kresources/caldav/config.h b/kresources/caldav/config.h
index 746c87aca..780674281 100644
--- a/kresources/caldav/config.h
+++ b/kresources/caldav/config.h
@@ -51,6 +51,7 @@ public slots:
virtual void saveSettings(KRES::Resource *resource);
void slotSTasksToggled( bool );
+ void slotSJournalsToggled( bool );
protected:
@@ -60,9 +61,11 @@ private:
TQLineEdit *mUrl;
TQLineEdit *mTasksUrl;
+ TQLineEdit *mJournalsUrl;
TQLineEdit *mUsername;
TQLineEdit *mPassword;
TQCheckBox *mUseSTasks;
+ TQCheckBox *mUseSJournals;
TQCheckBox *mRememberPassword;
CalDavReloadConfig* mReloadConfig;
CalDavSaveConfig* mSaveConfig;
diff --git a/kresources/caldav/job.cpp b/kresources/caldav/job.cpp
index 6edfbbfe8..8e49041f6 100644
--- a/kresources/caldav/job.cpp
+++ b/kresources/caldav/job.cpp
@@ -68,6 +68,12 @@ void CalDavJob::setTasksErrorString(const TQString& err, const long number) {
mTasksErrorNumber = number;
}
+void CalDavJob::setJournalsErrorString(const TQString& err, const long number) {
+ mJournalsError = true;
+ mJournalsErrorString = err;
+ mJournalsErrorNumber = number;
+}
+
void CalDavJob::processError(const caldav_error* err) {
TQString error_string;
@@ -100,6 +106,22 @@ void CalDavJob::processTasksError(const caldav_error* err) {
setTasksErrorString(error_string, code);
}
+void CalDavJob::processJournalsError(const caldav_error* err) {
+ TQString error_string;
+
+ long code = err->code;
+
+ if (-401 == code) { // unauthorized
+ error_string = i18n("Unauthorized. Username or password incorrect.");
+ } else if (-599 <= code && code <= -300) {
+ error_string = i18n("HTTP error %1. Please ensure that the URL is a valid CalDAV resource.").arg(-code);
+ } else {
+ error_string = err->str;
+ }
+
+ setJournalsErrorString(error_string, code);
+}
+
void CalDavJob::run() {
log("cleaning job");
@@ -107,6 +129,7 @@ void CalDavJob::run() {
int res = OK;
int tasksres = OK;
+ int journalsres = OK;
runtime_info* caldav_runtime = caldav_get_runtime_info();
@@ -131,6 +154,14 @@ void CalDavJob::run() {
processTasksError(caldav_runtime->error);
}
+ log("running journals job");
+ journalsres = runJournalsJob(caldav_runtime);
+
+ if (OK != journalsres) {
+ log("journals job failed");
+ processJournalsError(caldav_runtime->error);
+ }
+
caldav_free_runtime_info(&caldav_runtime);
// Signal done
diff --git a/kresources/caldav/job.h b/kresources/caldav/job.h
index bad00c98d..928e38143 100644
--- a/kresources/caldav/job.h
+++ b/kresources/caldav/job.h
@@ -61,6 +61,13 @@ public:
}
/**
+ * Sets a new Journals URL to load.
+ */
+ virtual void setJournalsUrl(const TQString& s) {
+ mJournalsUrl = s;
+ }
+
+ /**
* Sets the parent qobject.
*/
virtual void setParent(TQObject *s) {
@@ -89,6 +96,13 @@ public:
}
/**
+ * @return Journals URL to load.
+ */
+ virtual TQString journalsUrl() const {
+ return mJournalsUrl;
+ }
+
+ /**
* @return parent object
*/
virtual TQObject *parent() {
@@ -117,6 +131,13 @@ public:
}
/**
+ * @return true if journals downloading process failed.
+ */
+ virtual bool journalsError() const {
+ return mJournalsError;
+ }
+
+ /**
* @return an event error string.
*/
virtual TQString errorString() const {
@@ -131,6 +152,13 @@ public:
}
/**
+ * @return a journal error string.
+ */
+ virtual TQString journalsErrorString() const {
+ return mJournalsErrorString;
+ }
+
+ /**
* @return an event error number.
*/
virtual long errorNumber() const {
@@ -144,6 +172,13 @@ public:
return mTasksErrorNumber;
}
+ /**
+ * @return a journal error number.
+ */
+ virtual long journalsErrorNumber() const {
+ return mJournalsErrorNumber;
+ }
+
protected:
virtual void run();
@@ -167,6 +202,15 @@ protected:
virtual int runTasksJob(runtime_info* caldavRuntime) = 0;
/**
+ * Main run method for journal jobs. Jobs should not override run() method.
+ * Instead of this they should override this one.
+ * @param caldavRuntime specific libcaldav runtime information. This pointer should not be saved for the usage
+ * outside of runJob.
+ * @return libcaldav response code (see CALDAV_RESPONSE)
+ */
+ virtual int runJournalsJob(runtime_info* caldavRuntime) = 0;
+
+ /**
* Some cleaning. Jobs may (and usually should) override this method.
*/
virtual void cleanJob() {
@@ -176,6 +220,9 @@ protected:
mTasksError = false;
mTasksErrorString = "";
mTasksErrorNumber = 0;
+ mJournalsError = false;
+ mJournalsErrorString = "";
+ mJournalsErrorNumber = 0;
}
/**
@@ -189,6 +236,11 @@ protected:
void setTasksErrorString(const TQString& str, const long number);
/**
+ * Sets a journal error string to @p err. Also sets an error flag.
+ */
+ void setJournalsErrorString(const TQString& str, const long number);
+
+ /**
* Process an event error.
* Subclasses can overwrite this method, if some special error message handling
* should be done. Call setErrorString() to set the error after processing is done.
@@ -204,16 +256,28 @@ protected:
*/
virtual void processTasksError(const caldav_error* err);
+ /**
+ * Process a journal error.
+ * Subclasses can overwrite this method, if some special error message handling
+ * should be done. Call setErrorString() to set the error after processing is done.
+ * @param err error structure.
+ */
+ virtual void processJournalsError(const caldav_error* err);
+
private:
TQString mUrl;
TQString mTasksUrl;
+ TQString mJournalsUrl;
bool mError;
bool mTasksError;
+ bool mJournalsError;
TQString mErrorString;
TQString mTasksErrorString;
+ TQString mJournalsErrorString;
long mErrorNumber;
long mTasksErrorNumber;
+ long mJournalsErrorNumber;
TQObject *mParent;
int mType;
diff --git a/kresources/caldav/preferences.cpp b/kresources/caldav/preferences.cpp
index d70a35193..6eb87e450 100644
--- a/kresources/caldav/preferences.cpp
+++ b/kresources/caldav/preferences.cpp
@@ -234,7 +234,7 @@ TQString CalDavPrefs::getFullUrl() {
TQString CalDavPrefs::getFullTasksUrl() {
if (useSTasks() == 0)
- return TQString();
+ return getFullUrl();
TQUrl t(tasksUrl());
TQString safeURL;
@@ -259,5 +259,32 @@ TQString CalDavPrefs::getFullTasksUrl() {
return safeURL;
}
+TQString CalDavPrefs::getFullJournalsUrl() {
+ if (useSJournals() == 0)
+ return getFullUrl();
+
+ TQUrl t(journalsUrl());
+ TQString safeURL;
+ int firstAt;
+
+ t.setUser(username());
+ t.setPassword(password());
+
+ safeURL = t.toString();
+
+ firstAt = safeURL.find("@") + 1;
+ while (safeURL.find("@", firstAt) != -1) {
+ safeURL.replace(safeURL.find("@", firstAt), 1, "%40");
+ }
+
+ // Unencode the username, as Zimbra stupidly rejects the %40
+ safeURL.replace("%40", "@");
+
+ // Encode any spaces, as libcaldav stupidly fails otherwise
+ safeURL.replace(" ", "%20");
+
+ return safeURL;
+}
+
// EOF ========================================================================
diff --git a/kresources/caldav/preferences.h b/kresources/caldav/preferences.h
index 666b8ccf1..98245e6bb 100644
--- a/kresources/caldav/preferences.h
+++ b/kresources/caldav/preferences.h
@@ -92,6 +92,11 @@ public:
*/
TQString getFullTasksUrl();
+ /**
+ * @return A full URL to connect to CalDAV Journals server (including username and password).
+ */
+ TQString getFullJournalsUrl();
+
protected:
/**
diff --git a/kresources/caldav/prefsskel.kcfg b/kresources/caldav/prefsskel.kcfg
index bb05a75f6..7a72dd6b5 100644
--- a/kresources/caldav/prefsskel.kcfg
+++ b/kresources/caldav/prefsskel.kcfg
@@ -14,8 +14,18 @@
<label>URL</label>
</entry>
+ <entry key="JournalsUrl" type="String" >
+ <label>URL</label>
+ </entry>
+
<entry key="UseSTasks" type="Bool" >
<label>Use separate Tasks URL</label>
+ <default>false</default>
+ </entry>
+
+ <entry key="UseSJournals" type="Bool" >
+ <label>Use separate Journals URL</label>
+ <default>false</default>
</entry>
<entry key="Username" type="String">
diff --git a/kresources/caldav/reader.cpp b/kresources/caldav/reader.cpp
index a7956fe62..892b490c6 100644
--- a/kresources/caldav/reader.cpp
+++ b/kresources/caldav/reader.cpp
@@ -38,6 +38,11 @@ void CalDavReader::cleanTasksJob() {
mTasksData = "";
}
+void CalDavReader::cleanJournalsJob() {
+ CalDavJob::cleanJob();
+ mJournalsData = "";
+}
+
int CalDavReader::runJob(runtime_info* RT) {
kdDebug() << "reader::run, url: " << url();
@@ -104,4 +109,38 @@ int CalDavReader::runTasksJob(runtime_info* RT) {
return tasksres;
}
+int CalDavReader::runJournalsJob(runtime_info* RT) {
+ kdDebug() << "reader::run, journalsUrl: " << journalsUrl();
+
+ response* result = caldav_get_response();
+ CALDAV_RESPONSE journalsres = OK;
+
+ if ((OK == journalsres) && (journalsUrl() != "")) {
+ kdDebug() << "reader::run, url: " << journalsUrl();
+
+ if (mGetAll) {
+ kdDebug() << "getting all objects";
+ journalsres = caldav_tasks_getall_object(result, std::string(journalsUrl().ascii()).c_str(), RT);
+ } else {
+ kdDebug() << "getting object from the specified time range";
+ journalsres = caldav_tasks_get_object(result, mTimeStart.toTime_t(), mTimeEnd.toTime_t(), std::string(journalsUrl().ascii()).c_str(), RT);
+ }
+
+ if (OK == journalsres) {
+ kdDebug() << "success";
+ if (result->msg) {
+ mJournalsData = result->msg;
+ } else {
+ kdDebug() << "empty collection";
+ // empty collection
+ mJournalsData = "";
+ }
+ }
+
+ caldav_free_response(&result);
+ }
+
+ return journalsres;
+}
+
// EOF ========================================================================
diff --git a/kresources/caldav/reader.h b/kresources/caldav/reader.h
index b62a5931b..9bcc8c87a 100644
--- a/kresources/caldav/reader.h
+++ b/kresources/caldav/reader.h
@@ -78,18 +78,28 @@ public:
return mTasksData;
}
+ /**
+ * @return downloaded journal data in iCal format.
+ */
+ TQString journalsData() const {
+ return mJournalsData;
+ }
+
protected:
virtual int runJob(runtime_info* caldavRuntime);
virtual int runTasksJob(runtime_info* caldavRuntime);
+ virtual int runJournalsJob(runtime_info* caldavRuntime);
virtual void cleanJob();
virtual void cleanTasksJob();
+ virtual void cleanJournalsJob();
private:
TQString mData;
TQString mTasksData;
+ TQString mJournalsData;
bool mGetAll;
TQDateTime mTimeStart;
TQDateTime mTimeEnd;
diff --git a/kresources/caldav/resource.cpp b/kresources/caldav/resource.cpp
index c0bbf1159..003633a40 100644
--- a/kresources/caldav/resource.cpp
+++ b/kresources/caldav/resource.cpp
@@ -160,7 +160,7 @@ bool ResourceCalDav::doLoad() {
emit resourceLoaded(this);
log("starting download job");
- startLoading(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl());
+ startLoading(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl(), mPrefs->getFullJournalsUrl());
return true;
}
@@ -189,7 +189,7 @@ bool ResourceCalDav::doSave() {
}
log("start writing job");
- if (startWriting(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl()) == true) {
+ if (startWriting(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl(), mPrefs->getFullJournalsUrl()) == true) {
log("clearing changes");
// FIXME: Calling clearChanges() here is not the ideal way since the
// upload might fail, but there is no other place to call it...
@@ -334,6 +334,7 @@ void ResourceCalDav::loadingQueuePop() {
mLoader->setUrl(t->url);
mLoader->setTasksUrl(t->tasksUrl);
+ mLoader->setJournalsUrl(t->journalsUrl);
mLoader->setParent(this);
mLoader->setType(0);
@@ -353,10 +354,11 @@ void ResourceCalDav::loadingQueuePop() {
delete t;
}
-void ResourceCalDav::startLoading(const TQString& url, const TQString& tasksUrl) {
+void ResourceCalDav::startLoading(const TQString& url, const TQString& tasksUrl, const TQString& journalsUrl) {
LoadingTask *t = new LoadingTask;
t->url = url;
t->tasksUrl = tasksUrl;
+ t->journalsUrl = journalsUrl;
loadingQueuePush(t);
}
@@ -381,7 +383,7 @@ void ResourceCalDav::loadFinished() {
else {
// Set new password and try again
mPrefs->setPassword(TQString(newpass));
- startLoading(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl());
+ startLoading(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl(), mPrefs->getFullJournalsUrl());
}
}
else {
@@ -429,7 +431,7 @@ void ResourceCalDav::loadFinished() {
// else {
// // Set new password and try again
// mPrefs->setPassword(TQString(newpass));
-// startLoading(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl());
+// startLoading(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl(), mPrefs->getFullJournalsUrl());
// }
}
else {
@@ -466,6 +468,54 @@ void ResourceCalDav::loadFinished() {
}
}
+ if (loader->journalsError()) {
+ if (loader->journalsErrorNumber() == -401) {
+ if (NULL != mPrefs) {
+// TQCString newpass;
+// if (KPasswordDialog::getPassword (newpass, TQString("<b>") + i18n("Remote authorization required") + TQString("</b><p>") + i18n("Please input the password for") + TQString(" ") + mPrefs->getusername(), NULL) != 1) {
+// log("load error: " + loader->journalsErrorString() );
+// loadError(TQString("[%1] ").arg(abs(loader->journalsErrorNumber())) + loader->journalsErrorString());
+// }
+// else {
+// // Set new password and try again
+// mPrefs->setPassword(TQString(newpass));
+// startLoading(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl(), mPrefs->getFullJournalsUrl());
+// }
+ }
+ else {
+ log("load error: " + loader->journalsErrorString() );
+ loadError(TQString("[%1] ").arg(abs(loader->journalsErrorNumber())) + loader->journalsErrorString());
+ }
+ }
+ else {
+ log("load error: " + loader->journalsErrorString() );
+ loadError(TQString("[%1] ").arg(abs(loader->journalsErrorNumber())) + loader->journalsErrorString());
+ }
+ } else {
+ log("successful journals load");
+ TQString journalsData = loader->journalsData();
+
+ if (!journalsData.isNull() && !journalsData.isEmpty()) {
+ // TODO: I don't know why, but some schedules on http://caldav-test.ioda.net/ (I used it for testing)
+ // have some lines separated by single \r rather than \n or \r\n.
+ // ICalFormat fails to parse that.
+ journalsData.replace("\r\n", "\n"); // to avoid \r\n becomes \n\n after the next line
+ journalsData.replace('\r', '\n');
+
+ log("trying to parse...");
+ if (parseJournalsData(journalsData)) {
+ // FIXME: The agenda view can crash when a change is
+ // made on a remote server and a reload is requested!
+ log("... parsing is ok");
+ log("clearing changes");
+ enableChangeNotification();
+ clearChanges();
+ emit resourceChanged(this);
+ emit resourceLoaded(this);
+ }
+ }
+ }
+
// Loading queue and mLoadingQueueReady flag are not shared resources, i.e. only one thread has an access to them.
// That's why no mutexes are required.
mLoader->terminate();
@@ -602,6 +652,63 @@ bool ResourceCalDav::parseTasksData(const TQString& data) {
return ret;
}
+bool ResourceCalDav::parseJournalsData(const TQString& data) {
+ log("parseJournalsData()");
+
+ bool ret = true;
+
+ // check if the data is OK
+ // May be it's not efficient (parsing is done twice), but it should be safe
+ if (!checkData(data)) {
+ loadError(i18n("Parsing calendar data failed."));
+ return false;
+ }
+
+ log("clearing cache");
+ clearJournalsCache();
+
+ disableChangeNotification();
+
+ log("actually parsing the data");
+
+ ICalFormat ical;
+ if ( !ical.fromString( &mCalendar, data ) ) {
+ // this should never happen, but...
+ ret = false;
+ }
+
+ // debug code here -------------------------------------------------------
+#ifdef KCALDAV_DEBUG
+ const TQString fout_path = "/tmp/kcaldav_download_" + identifier() + ".tmp";
+
+ TQFile fout(fout_path);
+ if (fout.open(IO_WriteOnly | IO_Append)) {
+ TQTextStream sout(&fout);
+ sout << "---------- " << resourceName() << ": --------------------------------\n";
+ sout << data << "\n";
+ fout.close();
+ } else {
+ loadError(i18n("can't open file"));
+ }
+#endif // KCALDAV_DEBUG
+ // end of debug code ----------------------------------------------------
+
+ enableChangeNotification();
+
+ if (ret) {
+ log("parsing is ok");
+ //if ( !noReadOnlyOnLoad() && readOnly() ) {
+ if ( readOnly() ) {
+ log("ensuring read only flag honored");
+ ensureReadOnlyFlagHonored();
+ }
+ log("saving to cache");
+ saveCache();
+ }
+
+ return ret;
+}
+
/*=========================================================================
| WRITING METHODS
========================================================================*/
@@ -662,6 +769,7 @@ void ResourceCalDav::writingQueuePop() {
mWriter->setUrl(t->url);
mWriter->setTasksUrl(t->tasksUrl);
+ mWriter->setJournalsUrl(t->journalsUrl);
mWriter->setParent(this);
mWriter->setType(1);
@@ -689,6 +797,10 @@ void ResourceCalDav::writingQueuePop() {
mWriter->setChangedTasksObjects(t->tasksChanged);
mWriter->setDeletedTasksObjects(t->tasksDeleted);
+ mWriter->setAddedJournalsObjects(t->journalsAdded);
+ mWriter->setChangedJournalsObjects(t->journalsChanged);
+ mWriter->setDeletedJournalsObjects(t->journalsDeleted);
+
mWritingQueueReady = false;
log("starting actual write job");
@@ -719,7 +831,7 @@ void ResourceCalDav::releaseReadLockout() {
readLockout = false;
}
-bool ResourceCalDav::startWriting(const TQString& url, const TQString& tasksUrl) {
+bool ResourceCalDav::startWriting(const TQString& url, const TQString& tasksUrl, const TQString& journalsUrl) {
log("startWriting: url = " + url);
// WARNING: This will segfault if a separate read or write thread
@@ -757,16 +869,22 @@ bool ResourceCalDav::startWriting(const TQString& url, const TQString& tasksUrl)
t->url = url;
t->tasksUrl = tasksUrl;
+ t->journalsUrl = journalsUrl;
t->added = "";
t->changed = "";
t->deleted = "";
t->tasksAdded = "";
t->tasksChanged = "";
t->tasksDeleted = "";
+ t->journalsAdded = "";
+ t->journalsChanged = "";
+ t->journalsDeleted = "";
if (getICalString(currentIncidence).contains("BEGIN:VEVENT") > 0)
t->added = getICalString(currentIncidence);
else if (getICalString(currentIncidence).contains("BEGIN:VTODO") > 0)
t->tasksAdded = getICalString(currentIncidence);
+ else if (getICalString(currentIncidence).contains("BEGIN:VJOURNAL") > 0)
+ t->journalsAdded = getICalString(currentIncidence);
writingQueuePush(t);
}
@@ -785,11 +903,16 @@ bool ResourceCalDav::startWriting(const TQString& url, const TQString& tasksUrl)
t->tasksAdded = "";
t->tasksChanged = "";
t->tasksDeleted = "";
+ t->journalsAdded = "";
+ t->journalsChanged = "";
+ t->journalsDeleted = "";
if (getICalString(currentIncidence).contains("BEGIN:VEVENT") > 0)
t->changed = getICalString(currentIncidence);
else if (getICalString(currentIncidence).contains("BEGIN:VTODO") > 0)
t->tasksChanged = getICalString(currentIncidence);
+ else if (getICalString(currentIncidence).contains("BEGIN:VJOURNAL") > 0)
+ t->journalsChanged = getICalString(currentIncidence);
writingQueuePush(t);
}
@@ -808,11 +931,16 @@ bool ResourceCalDav::startWriting(const TQString& url, const TQString& tasksUrl)
t->tasksAdded = "";
t->tasksChanged = "";
t->tasksDeleted = "";
+ t->journalsAdded = "";
+ t->journalsChanged = "";
+ t->journalsDeleted = "";
if (getICalString(currentIncidence).contains("BEGIN:VEVENT") > 0)
t->deleted = getICalString(currentIncidence);
else if (getICalString(currentIncidence).contains("BEGIN:VTODO") > 0)
t->tasksDeleted = getICalString(currentIncidence);
+ else if (getICalString(currentIncidence).contains("BEGIN:VJOURNALS") > 0)
+ t->journalsDeleted = getICalString(currentIncidence);
writingQueuePush(t);
}
@@ -839,7 +967,7 @@ void ResourceCalDav::writingFinished() {
else {
// Set new password and try again
mPrefs->setPassword(TQString(newpass));
- startWriting(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl());
+ startWriting(mPrefs->getFullUrl(), mPrefs->getFullTasksUrl(), mPrefs->getFullJournalsUrl());
}
}
else {
diff --git a/kresources/caldav/resource.h b/kresources/caldav/resource.h
index bb69807be..033a19ce4 100644
--- a/kresources/caldav/resource.h
+++ b/kresources/caldav/resource.h
@@ -86,11 +86,13 @@ protected:
struct LoadingTask {
TQString url;
TQString tasksUrl;
+ TQString journalsUrl;
};
struct WritingTask {
TQString url;
TQString tasksUrl;
+ TQString journalsUrl;
TQString added;
TQString changed;
@@ -99,6 +101,10 @@ protected:
TQString tasksAdded;
TQString tasksChanged;
TQString tasksDeleted;
+
+ TQString journalsAdded;
+ TQString journalsChanged;
+ TQString journalsDeleted;
};
@@ -129,8 +135,9 @@ protected:
* Initiates calendar loading process.
* @param url URL to load calendar data from.
* @param tasksUrl URL to load task data from.
+ * @param journalsUrl URL to load journal data from.
*/
- void startLoading(const TQString& url, const TQString& tasksUrl);
+ void startLoading(const TQString& url, const TQString& tasksUrl, const TQString& journalsUrl);
/**
* Checks if the data is correct and can be parsed.
@@ -148,18 +155,26 @@ protected:
/**
* Parses the data and adds tasks to the calendar.
- * Unlike @ref parseData, this function does NOT clear the cache.
* @param data calendar data.
* @return true on success, false on fail.
*/
bool parseTasksData(const TQString& data);
/**
+ * Parses the data and adds journals to the calendar.
+ * @param data calendar data.
+ * @return true on success, false on fail.
+ */
+ bool parseJournalsData(const TQString& data);
+
+ /**
* Initiates calendar writing process.
- * @param url URL to save calendar data to.
+ * @param url URL to save event data to.
+ * @param tasksUrl URL to save task data to.
+ * @param journalsUrl URL to save journal data to.
* @return true if write was queued successfully, false if not
*/
- bool startWriting(const TQString& url, const TQString& tasksUrl);
+ bool startWriting(const TQString& url, const TQString& tasksUrl, const TQString& journalsUrl);
/**
* Returns a list of incidences as a valid iCalendar string.
diff --git a/kresources/caldav/writer.cpp b/kresources/caldav/writer.cpp
index e939f3d9c..a466322eb 100644
--- a/kresources/caldav/writer.cpp
+++ b/kresources/caldav/writer.cpp
@@ -103,6 +103,34 @@ int CalDavWriter::runJob(runtime_info* RT) {
}
}
+ int journalsres = OK;
+
+ if ((OK == journalsres) && (tasksUrl() != "")) {
+ kdDebug() << "pushing added tasks objects";
+ journalsres = pushJournalsObjects(mJournalsAdded, caldav_add_object, OK, RT);
+ if (OK == journalsres) {
+#ifdef USE_CALDAV_TASKS_MODIFY
+ kdDebug() << "pushing changed objects";
+ journalsres = pushJournalsObjects(mJournalsChanged, caldav_tasks_modify_object, OK, RT);
+ if (OK == journalsres) {
+ kdDebug() << "pushing deleted objects";
+ journalsres = pushJournalsObjects(mJournalsDeleted, caldav_tasks_delete_object, OK, RT);
+ }
+#else // if USE_CALDAV_TASKS_MODIFY
+ kdDebug() << "pushing changed objects (delete)";
+ journalsres = pushJournalsObjects(mJournalsChanged, caldav_tasks_delete_object, OK, RT);
+ if (OK == journalsres) {
+ kdDebug() << "pushing changed objects (add)";
+ journalsres = pushJournalsObjects(mJournalsChanged, caldav_add_object, OK, RT);
+ if (OK == journalsres) {
+ kdDebug() << "pushing deleted objects";
+ journalsres = pushJournalsObjects(mJournalsDeleted, caldav_tasks_delete_object, OK, RT);
+ }
+ }
+#endif // if USE_CALDAV_TASKS_MODIFY
+ }
+ }
+
if ((OK != res) || (OK != tasksres)) {
clearObjects();
}
@@ -122,4 +150,13 @@ void CalDavWriter::cleanTasksJob() {
// Stub function as there is no reason to split the writing jobs like the reading jobs
}
+int CalDavWriter::runJournalsJob(runtime_info* RT) {
+ // Stub function as there is no reason to split the writing jobs like the reading jobs
+ return OK;
+}
+
+void CalDavWriter::cleanJournalsJob() {
+ // Stub function as there is no reason to split the writing jobs like the reading jobs
+}
+
// EOF ========================================================================
diff --git a/kresources/caldav/writer.h b/kresources/caldav/writer.h
index 3b8f82a81..437eeed0e 100644
--- a/kresources/caldav/writer.h
+++ b/kresources/caldav/writer.h
@@ -82,6 +82,15 @@ public:
}
/**
+ * Sets the information about added journals writer should send to server.
+ * @param s icalendar-formatted string consists of all added journals plus necessary calendar info.
+ * May be an empty string, which means there are no added journals to send.
+ */
+ void setAddedJournalsObjects(const TQString& s) {
+ mJournalsAdded = s;
+ }
+
+ /**
* Sets the information about changed tasks writer should send to server.
* @param s icalendar-formatted string consists of all changed tasks plus necessary calendar info.
* May be an empty string, which means there are no changed tasks to send.
@@ -91,6 +100,15 @@ public:
}
/**
+ * Sets the information about changed journals writer should send to server.
+ * @param s icalendar-formatted string consists of all changed journals plus necessary calendar info.
+ * May be an empty string, which means there are no changed journals to send.
+ */
+ void setChangedJournalsObjects(const TQString& s) {
+ mJournalsChanged = s;
+ }
+
+ /**
* Sets the information about deleted tasks writer should send to server.
* @param s icalendar-formatted string consists of all deleted tasks plus necessary calendar info.
* May be an empty string, which means there are no deleted tasks to send.
@@ -100,6 +118,15 @@ public:
}
/**
+ * Sets the information about deleted journals writer should send to server.
+ * @param s icalendar-formatted string consists of all deleted journals plus necessary calendar info.
+ * May be an empty string, which means there are no deleted journals to send.
+ */
+ void setDeletedJournalsObjects(const TQString& s) {
+ mJournalsDeleted = s;
+ }
+
+ /**
* Clear all the information previously set.
*/
void clearObjects() {
@@ -109,15 +136,20 @@ public:
setAddedTasksObjects("");
setChangedTasksObjects("");
setDeletedTasksObjects("");
+ setAddedJournalsObjects("");
+ setChangedJournalsObjects("");
+ setDeletedJournalsObjects("");
}
protected:
virtual int runJob(runtime_info* caldavRuntime);
virtual int runTasksJob(runtime_info* caldavRuntime);
+ virtual int runJournalsJob(runtime_info* caldavRuntime);
virtual void cleanJob();
virtual void cleanTasksJob();
+ virtual void cleanJournalsJob();
/// Just a wrapper above libcaldav event writing functions.
template<typename Operation>
@@ -139,6 +171,16 @@ protected:
return r;
}
+ /// Just a wrapper above libcaldav journal writing functions.
+ template<typename Operation>
+ int pushJournalsObjects(const TQString& data, Operation op, int okCode, runtime_info* RT) {
+ int r = okCode;
+// if (!data.isNull() && !data.isEmpty()) {
+// r = op(std::string(data.ascii()).c_str(), std::string(journalsUrl().ascii()).c_str(), RT);
+// }
+ return r;
+ }
+
private:
TQString mAdded;
@@ -148,6 +190,10 @@ private:
TQString mTasksAdded;
TQString mTasksChanged;
TQString mTasksDeleted;
+
+ TQString mJournalsAdded;
+ TQString mJournalsChanged;
+ TQString mJournalsDeleted;
};
} // namespace KCal
diff --git a/kresources/egroupware/kabc_resourcexmlrpc.cpp b/kresources/egroupware/kabc_resourcexmlrpc.cpp
index ee1e74bea..115484c6a 100644
--- a/kresources/egroupware/kabc_resourcexmlrpc.cpp
+++ b/kresources/egroupware/kabc_resourcexmlrpc.cpp
@@ -64,8 +64,11 @@ ResourceXMLRPC::ResourceXMLRPC( const KConfig *config )
mPrefs->addGroupPrefix( identifier() );
- if ( config )
+ if ( config ) {
mPrefs->readConfig();
+ } else {
+ setResourceName( i18n( "eGroupware Server" ) );
+ }
initEGroupware();
}
diff --git a/kresources/egroupware/kabc_xmlrpc.desktop b/kresources/egroupware/kabc_xmlrpc.desktop
index c7386a593..d7f8d5d62 100644
--- a/kresources/egroupware/kabc_xmlrpc.desktop
+++ b/kresources/egroupware/kabc_xmlrpc.desktop
@@ -20,7 +20,6 @@ Name[hu]=eGroupware-kiszolgáló (XML-RPC-n keresztül)
Name[is]=eGroupware þjónn (gegnum XML-RPC)
Name[it]=Server eGroupware (via XML-RPC)
Name[ja]=eGroupware サーバ (XML-RPC 経由)
-Name[ka]=სერბერი eGroupware (XML-RPC-ის საშუალებით)
Name[kk]=eGroupware сервері (XML-RPC арқылы)
Name[km]=ម៉ាស៊ីន​បម្រើ eGroupware (តាម​រយៈ XML-RPC)
Name[lt]=eGroupware serveris (per XML-RPC)
diff --git a/kresources/egroupware/kcal_resourcexmlrpc.cpp b/kresources/egroupware/kcal_resourcexmlrpc.cpp
index bb92b2d5f..9072b1666 100644
--- a/kresources/egroupware/kcal_resourcexmlrpc.cpp
+++ b/kresources/egroupware/kcal_resourcexmlrpc.cpp
@@ -110,8 +110,11 @@ ResourceXMLRPC::ResourceXMLRPC( const KConfig* config )
mPrefs->addGroupPrefix( identifier() );
- if ( config )
+ if ( config ) {
readConfig( config );
+ } else {
+ setResourceName( i18n( "eGroupware Server" ) );
+ }
initEGroupware();
}
diff --git a/kresources/egroupware/kcal_xmlrpc.desktop b/kresources/egroupware/kcal_xmlrpc.desktop
index 5480d86b6..93a54217f 100644
--- a/kresources/egroupware/kcal_xmlrpc.desktop
+++ b/kresources/egroupware/kcal_xmlrpc.desktop
@@ -20,7 +20,6 @@ Name[hu]=eGroupware-kiszolgáló (XML-RPC-n keresztül)
Name[is]=eGroupware þjónn (gegnum XML-RPC)
Name[it]=Server eGroupware (via XML-RPC)
Name[ja]=eGroupware サーバ (XML-RPC 経由)
-Name[ka]=სერბერი eGroupware (XML-RPC-ის საშუალებით)
Name[kk]=eGroupware сервері (XML-RPC арқылы)
Name[km]=ម៉ាស៊ីន​បម្រើ eGroupware (តាម​រយៈ XML-RPC)
Name[lt]=eGroupware serveris (per XML-RPC)
diff --git a/kresources/egroupware/knotes_resourcexmlrpc.cpp b/kresources/egroupware/knotes_resourcexmlrpc.cpp
index b0bdb5b0d..774115d27 100644
--- a/kresources/egroupware/knotes_resourcexmlrpc.cpp
+++ b/kresources/egroupware/knotes_resourcexmlrpc.cpp
@@ -57,8 +57,11 @@ ResourceXMLRPC::ResourceXMLRPC( const KConfig* config )
mPrefs->addGroupPrefix( identifier() );
- if ( config )
+ if ( config ) {
readConfig( config );
+ } else {
+ setResourceName( i18n( "eGroupware Server" ) );
+ }
}
ResourceXMLRPC::ResourceXMLRPC( )
diff --git a/kresources/egroupware/knotes_xmlrpc.desktop b/kresources/egroupware/knotes_xmlrpc.desktop
index 61411ce01..b3f4faa6a 100644
--- a/kresources/egroupware/knotes_xmlrpc.desktop
+++ b/kresources/egroupware/knotes_xmlrpc.desktop
@@ -20,7 +20,6 @@ Name[hu]=eGroupware-kiszolgáló (XML-RPC-n keresztül)
Name[is]=eGroupware þjónn (gegnum XML-RPC)
Name[it]=Server eGroupware (via XML-RPC)
Name[ja]=eGroupware サーバ (XML-RPC 経由)
-Name[ka]=სერბერი eGroupware (XML-RPC-ის საშუალებით)
Name[kk]=eGroupware сервері (XML-RPC арқылы)
Name[km]=ម៉ាស៊ីន​បម្រើ eGroupware (តាម​រយៈ XML-RPC)
Name[lt]=eGroupware serveris (per XML-RPC)
diff --git a/kresources/exchange/exchange.desktop b/kresources/exchange/exchange.desktop
index 9342e3baa..5bfe8a1ed 100644
--- a/kresources/exchange/exchange.desktop
+++ b/kresources/exchange/exchange.desktop
@@ -26,7 +26,6 @@ Name[hu]=Exchange 2000-kiszolgáló
Name[is]=Exchange 2000 þjónn
Name[it]=Server Exchange 2000
Name[ja]=Exchange 2000 サーバ
-Name[ka]=სერვერი Exchange 2000
Name[kk]=MS Exchange 2000 сервері
Name[km]=ម៉ាស៊ីន​បម្រើ Exchange ២០០០
Name[lt]=Exchange 2000 serveris
diff --git a/kresources/exchange/exchange_deprecated.desktop b/kresources/exchange/exchange_deprecated.desktop
index 70ffbc63f..eba22eed2 100644
--- a/kresources/exchange/exchange_deprecated.desktop
+++ b/kresources/exchange/exchange_deprecated.desktop
@@ -21,7 +21,6 @@ Name[hu]=Exchange 2000-kiszolgáló (elavult)
Name[is]=Exchange 2000 þjónn (úrelt)
Name[it]=Server Exchange 2000 (deprecato)
Name[ja]=Exchange 2000 サーバ (廃止予定)
-Name[ka]=სერვერი Exchange 2000 (მოძველებული)
Name[kk]=MS Exchange 2000 сервері (ескірген)
Name[km]=ម៉ាស៊ីន​បម្រើ Exchange ២០០០ (មិន​សូវ​ល្អ)
Name[lt]=Exchange 2000 serveris (deprecated)
diff --git a/kresources/exchange/resourceexchange.cpp b/kresources/exchange/resourceexchange.cpp
index 8e877f9b0..82c0ab07d 100644
--- a/kresources/exchange/resourceexchange.cpp
+++ b/kresources/exchange/resourceexchange.cpp
@@ -91,6 +91,7 @@ ResourceExchange::ResourceExchange( const KConfig *config )
mCachedSeconds = config->readNumEntry( "ExchangeCacheTimeout", 600 );
mAutoMailbox = config->readBoolEntry( "ExchangeAutoMailbox", true );
} else {
+ setResourceName( i18n( "Exchange Server" ) );
mAccount = new ExchangeAccount( "", "", "", "" );
mCachedSeconds = 600;
}
@@ -248,19 +249,26 @@ void ResourceExchange::slotMonitorError( int errorCode, const TQString& moreInfo
}
-bool ResourceExchange::addEvent(Event *anEvent)
+bool ResourceExchange::addEvent( Event *event )
{
+ return addEvent( event, TQString() );
+}
+
+bool ResourceExchange::addEvent( Event *event, const TQString &subresource )
+{
+ Q_UNUSED( subresource ); //subresources are not supported
+
if( !mCache ) return false;
kdDebug() << "ResourceExchange::addEvent" << endl;
// FIXME: first check of upload finished successfully, only then
// add to cache
- mCache->addEvent( anEvent );
+ mCache->addEvent( event );
- uploadEvent( anEvent );
-// insertEvent(anEvent);
+ uploadEvent( event );
+// insertEvent( event );
- anEvent->registerObserver( this );
+ event->registerObserver( this );
// setModified( true );
return true;
@@ -341,8 +349,14 @@ void ResourceExchange::unsubscribeEvents( const TQDate &/*start*/, const TQDate
kdDebug() << "ResourceExchange::unsubscribeEvents()" << endl;
}
-bool ResourceExchange::addTodo(Todo */*todo*/)
+bool ResourceExchange::addTodo( Todo *todo )
+{
+ return addTodo( todo, TQString() );
+}
+
+bool ResourceExchange::addTodo( Todo */*todo*/, const TQString &subresource )
{
+ Q_UNUSED( subresource ); //subresources are not supported
// This resource doesn't handle todos yet!
return false;
/* if( !mCache)
@@ -356,6 +370,7 @@ bool ResourceExchange::addTodo(Todo */*todo*/)
return true;*/
}
+
bool ResourceExchange::deleteTodo(Todo */*todo*/)
{
// We don't handle todos yet
@@ -530,8 +545,15 @@ Event::List ResourceExchange::rawEvents( EventSortField sortField, SortDirection
return mCache->rawEvents( sortField, sortDirection );
}
-bool ResourceExchange::addJournal(Journal */*journal*/)
+bool ResourceExchange::addJournal( Journal *journal )
+{
+ return addJournal( journal, TQString() );
+}
+
+bool ResourceExchange::addJournal( Journal */*journal*/, const TQString &subresource )
{
+ Q_UNUSED( subresource ); //subresources are not supported
+
// This resource doesn't handle journals yet
return false;
/* kdDebug(5800) << "Adding Journal on " << journal->dtStart().toString() << endl;
diff --git a/kresources/exchange/resourceexchange.h b/kresources/exchange/resourceexchange.h
index d3492cf00..7328a27b0 100644
--- a/kresources/exchange/resourceexchange.h
+++ b/kresources/exchange/resourceexchange.h
@@ -83,7 +83,9 @@ class ResourceExchange : public ResourceCalendar, public IncidenceBase::Observer
// void close();
/** Add Event to calendar. */
- bool addEvent(Event *anEvent);
+ KDE_DEPRECATED bool addEvent( Event *event );
+ bool addEvent( Event *event, const TQString &subresource );
+
/** deletes an event from this calendar. */
bool deleteEvent(Event *);
@@ -118,7 +120,8 @@ class ResourceExchange : public ResourceCalendar, public IncidenceBase::Observer
/**
Add a todo to the todolist.
*/
- bool addTodo( Todo *todo );
+ KDE_DEPRECATED bool addTodo( Todo *todo );
+ bool addTodo( Todo *todo, const TQString &subresource );
/**
Remove a todo from the todolist.
*/
@@ -138,7 +141,8 @@ class ResourceExchange : public ResourceCalendar, public IncidenceBase::Observer
Todo::List rawTodosForDate( const TQDate &date );
/** Add a Journal entry to calendar */
- virtual bool addJournal(Journal *);
+ KDE_DEPRECATED bool addJournal( Journal *journal );
+ bool addJournal( Journal *journal, const TQString &subresource );
/** deletes an event from this calendar. */
virtual bool deleteJournal(Journal *);
/** Return Journals for given date */
diff --git a/kresources/groupware/kabc_groupware.desktop b/kresources/groupware/kabc_groupware.desktop
index 6750248b7..f2c56b26a 100644
--- a/kresources/groupware/kabc_groupware.desktop
+++ b/kresources/groupware/kabc_groupware.desktop
@@ -20,7 +20,6 @@ Name[hu]=Groupware kiszolgáló
Name[is]=Groupware þjónn
Name[it]=Server Groupware
Name[ja]=グループウェアサーバ
-Name[ka]=სერვერი Groupware
Name[kk]=Groupware сервері
Name[km]=ម៉ាស៊ីន​បម្រើ​កម្មវិធី​ពហុ​អ្នកប្រើ
Name[lt]=Grupinio darbo serveris
diff --git a/kresources/groupware/kabc_resourcegroupware.cpp b/kresources/groupware/kabc_resourcegroupware.cpp
index c04988aa0..c9fef7a0c 100644
--- a/kresources/groupware/kabc_resourcegroupware.cpp
+++ b/kresources/groupware/kabc_resourcegroupware.cpp
@@ -43,6 +43,8 @@ ResourceGroupware::ResourceGroupware( const KConfig *config )
if ( config ) {
readConfig( config );
+ } else {
+ setResourceName( i18n( "Groupware Server" ) );
}
}
diff --git a/kresources/groupware/kcal_groupware.desktop b/kresources/groupware/kcal_groupware.desktop
index 0b43536be..9692900dd 100644
--- a/kresources/groupware/kcal_groupware.desktop
+++ b/kresources/groupware/kcal_groupware.desktop
@@ -20,7 +20,6 @@ Name[hu]=Groupware kiszolgáló
Name[is]=Groupware þjónn
Name[it]=Server Groupware
Name[ja]=グループウェアサーバ
-Name[ka]=სერვერი Groupware
Name[kk]=Groupware сервері
Name[km]=ម៉ាស៊ីន​បម្រើ​កម្មវិធី​ពហុ​អ្នកប្រើ
Name[lt]=Grupinio darbo serveris
diff --git a/kresources/groupware/kcal_resourcegroupware.cpp b/kresources/groupware/kcal_resourcegroupware.cpp
index b651d7390..01a51684f 100644
--- a/kresources/groupware/kcal_resourcegroupware.cpp
+++ b/kresources/groupware/kcal_resourcegroupware.cpp
@@ -62,7 +62,11 @@ ResourceGroupware::ResourceGroupware( const KConfig *config )
mPrefs->addGroupPrefix( identifier() );
- if ( config ) readConfig( config );
+ if ( config ) {
+ readConfig( config );
+ } else {
+ setResourceName( i18n( "Groupware Server" ) );
+ }
}
ResourceGroupware::~ResourceGroupware()
diff --git a/kresources/kolab/kabc/contact.cpp b/kresources/kolab/kabc/contact.cpp
index fc9087316..26a91e679 100644
--- a/kresources/kolab/kabc/contact.cpp
+++ b/kresources/kolab/kabc/contact.cpp
@@ -35,6 +35,7 @@
#include <kabc/addressee.h>
#include <kabc/stdaddressbook.h>
+#include <libkcal/freebusyurlstore.h>
#include <libkdepim/distributionlist.h>
#include <kio/netaccess.h>
#include <kdebug.h>
@@ -222,15 +223,15 @@ TQString Contact::profession() const
return mProfession;
}
-// void Contact::setJobTitle( const TQString& title )
-// {
-// mJobTitle = title;
-// }
+void Contact::setJobTitle( const TQString& title )
+{
+ mJobTitle = title;
+}
-// TQString Contact::jobTitle() const
-// {
-// return mJobTitle;
-// }
+TQString Contact::jobTitle() const
+{
+ return mJobTitle;
+}
void Contact::setManagerName( const TQString& name )
{
@@ -485,6 +486,11 @@ void Contact::saveCustomAttributes( TQDomElement& element ) const
if ( (*it).app == s_unhandledTagAppName ) {
writeString( element, (*it).name, (*it).value );
} else {
+ // skip writing the freebusyurl as it is a hack we need to remove eventually
+ if ( (*it).name == TQString::fromLatin1( "FreeBusyURL" ) ) {
+ continue;
+ }
+
// Let's use attributes so that other tag-preserving-code doesn't need sub-elements
TQDomElement e = element.ownerDocument().createElement( "x-custom" );
element.appendChild( e );
@@ -659,7 +665,7 @@ bool Contact::loadAttribute( TQDomElement& element )
case 'j':
if ( tagName == "job-title" ) {
// see saveAttributes: <job-title> is mapped to the Role field
- setRole( element.text() );
+ setJobTitle( element.text() );
return true;
}
break;
@@ -766,7 +772,6 @@ bool Contact::saveAttributes( TQDomElement& element ) const
{
// Save the base class elements
KolabBase::saveAttributes( element );
-
if ( mIsDistributionList ) {
writeString( element, "display-name", fullName() );
saveDistrListMembers( element );
@@ -779,11 +784,8 @@ bool Contact::saveAttributes( TQDomElement& element ) const
writeString( element, "department", department() );
writeString( element, "office-location", officeLocation() );
writeString( element, "profession", profession() );
- // <role> is gone; jobTitle() is not shown in the addresseeeditor,
- // so let's bind <job-title> to role()
- //writeString( element, "role", role() );
- //writeString( element, "job-title", jobTitle() );
- writeString( element, "job-title", role() );
+ writeString( element, "role", role() );
+ writeString( element, "job-title", jobTitle() );
writeString( element, "manager-name", managerName() );
writeString( element, "assistant", assistant() );
writeString( element, "nick-name", nickName() );
@@ -891,28 +893,28 @@ static TQStringList phoneTypeToString( int /*KABC::PhoneNumber::Types*/ type )
type = type & ~KABC::PhoneNumber::Work;
}
- // To support both "home1" and "home2", map Home+Pref to home1
+ // To support both "home1" and "home2", map Home+Pref to home2
if ( ( type & KABC::PhoneNumber::Home ) && ( type & KABC::PhoneNumber::Pref ) )
{
- types << "home1";
+ types << "home2";
type = type & ~KABC::PhoneNumber::Home;
type = type & ~KABC::PhoneNumber::Pref;
}
- // To support both "business1" and "business2", map Work+Pref to business1
+ // To support both "business1" and "business2", map Work+Pref to business2
if ( ( type & KABC::PhoneNumber::Work ) && ( type & KABC::PhoneNumber::Pref ) )
{
- types << "business1";
+ types << "business2";
type = type & ~KABC::PhoneNumber::Work;
type = type & ~KABC::PhoneNumber::Pref;
}
if ( type & KABC::PhoneNumber::Home )
- types << "home2";
+ types << "home1";
if ( type & KABC::PhoneNumber::Msg ) // Msg==messaging
types << "company";
if ( type & KABC::PhoneNumber::Work )
- types << "business2";
+ types << "business1";
if ( type & KABC::PhoneNumber::Pref )
types << "primary";
if ( type & KABC::PhoneNumber::Voice )
@@ -942,13 +944,13 @@ static int /*KABC::PhoneNumber::Types*/ phoneTypeFromString( const TQString& typ
return KABC::PhoneNumber::Home | KABC::PhoneNumber::Fax;
if ( type == "businessfax" )
return KABC::PhoneNumber::Work | KABC::PhoneNumber::Fax;
- if ( type == "business1" )
- return KABC::PhoneNumber::Work | KABC::PhoneNumber::Pref;
if ( type == "business2" )
+ return KABC::PhoneNumber::Work | KABC::PhoneNumber::Pref;
+ if ( type == "business1" )
return KABC::PhoneNumber::Work;
- if ( type == "home1" )
- return KABC::PhoneNumber::Home | KABC::PhoneNumber::Pref;
if ( type == "home2" )
+ return KABC::PhoneNumber::Home | KABC::PhoneNumber::Pref;
+ if ( type == "home1" )
return KABC::PhoneNumber::Home;
if ( type == "company" )
return KABC::PhoneNumber::Msg;
@@ -1019,11 +1021,15 @@ void Contact::setFields( const KABC::Addressee* addressee )
setOrganization( addressee->organization() );
setWebPage( addressee->url().url() );
setIMAddress( addressee->custom( "KADDRESSBOOK", "X-IMAddress" ) );
+#if KDE_IS_VERSION(3,5,8)
+ setDepartment( addressee->department());
+#else
setDepartment( addressee->custom( "KADDRESSBOOK", "X-Department" ) );
+#endif
setOfficeLocation( addressee->custom( "KADDRESSBOOK", "X-Office" ) );
setProfession( addressee->custom( "KADDRESSBOOK", "X-Profession" ) );
setRole( addressee->role() );
- //setJobTitle( addressee->title() );
+ setJobTitle( addressee->title() );
setManagerName( addressee->custom( "KADDRESSBOOK", "X-ManagersName" ) );
setAssistant( addressee->custom( "KADDRESSBOOK", "X-AssistantsName" ) );
setNickName( addressee->nickName() );
@@ -1129,6 +1135,11 @@ void Contact::setFields( const KABC::Addressee* addressee )
}
}
+ TQString url = KCal::FreeBusyUrlStore::self()->readUrl( addressee->preferredEmail() );
+ if ( !url.isEmpty() ) {
+ setFreeBusyUrl( url );
+ }
+
// Those fields, although defined in Addressee, are not used in KDE
// (e.g. not visible in kaddressbook/addresseeeditorwidget.cpp)
// So it doesn't matter much if we don't have them in the XML.
@@ -1136,9 +1147,6 @@ void Contact::setFields( const KABC::Addressee* addressee )
// Things KAddressBook can't handle, so they are saved as unhandled tags:
// initials, children, gender, language
-
- // TODO: Free/Busy URL. This is done rather awkward in KAddressBook -
- // it stores it in a local file through a korganizer file :-(
}
// The loading is: xml -> Contact -> addressee, this is the second part
@@ -1173,11 +1181,15 @@ void Contact::saveTo( KABC::Addressee* addressee )
addressee->setOrganization( organization() );
addressee->setUrl( webPage() );
addressee->insertCustom( "KADDRESSBOOK", "X-IMAddress", imAddress() );
+#if KDE_IS_VERSION(3,5,8)
+ addressee->setDepartment( department() );
+#else
addressee->insertCustom( "KADDRESSBOOK", "X-Department", department() );
+#endif
addressee->insertCustom( "KADDRESSBOOK", "X-Office", officeLocation() );
addressee->insertCustom( "KADDRESSBOOK", "X-Profession", profession() );
addressee->setRole( role() );
- //addressee->setTitle( jobTitle() );
+ addressee->setTitle( jobTitle() );
addressee->insertCustom( "KADDRESSBOOK", "X-ManagersName", managerName() );
addressee->insertCustom( "KADDRESSBOOK", "X-AssistantsName", assistant() );
addressee->setNickName( nickName() );
diff --git a/kresources/kolab/kabc/contact.h b/kresources/kolab/kabc/contact.h
index 39a235cc2..a9465642f 100644
--- a/kresources/kolab/kabc/contact.h
+++ b/kresources/kolab/kabc/contact.h
@@ -121,9 +121,8 @@ public:
void setProfession( const TQString& profession );
TQString profession() const;
- // not shown in the kaddressbook GUI
- //void setJobTitle( const TQString& title );
- //TQString jobTitle() const;
+ void setJobTitle( const TQString& title );
+ TQString jobTitle() const;
void setManagerName( const TQString& name );
TQString managerName() const;
@@ -245,7 +244,7 @@ private:
TQString mDepartment;
TQString mOfficeLocation;
TQString mProfession;
- //TQString mJobTitle;
+ TQString mJobTitle;
TQString mManagerName;
TQString mAssistant;
TQString mNickName;
diff --git a/kresources/kolab/kabc/kolab.desktop b/kresources/kolab/kabc/kolab.desktop
index d75090a7a..8339f9c22 100644
--- a/kresources/kolab/kabc/kolab.desktop
+++ b/kresources/kolab/kabc/kolab.desktop
@@ -21,7 +21,6 @@ Name[hu]=IMAP-kiszolgálón tárolt címjegyzék a KMailen keresztül
Name[is]=Vistfangaskrá á IMAP þjóni gegnum KMail
Name[it]=Rubrica indirizzi su server IMAP via KMail
Name[ja]=KMail 経由 IMAP サーバのアドレス帳
-Name[ka]=წიგნაკი IMAP-ის სერვერზე KMail-ის საშუალებით
Name[kk]=KMail арқылы IMAP серверіндегі адрестік кітапша
Name[km]=សៀវភៅ​អាសយដ្ឋាន​លើ​ម៉ាស៊ីន​បម្រើ IMAP តាម​រយៈ KMail
Name[lt]=Adresų knygelė IMAP serveryje per KMail
diff --git a/kresources/kolab/kabc/resourcekolab.cpp b/kresources/kolab/kabc/resourcekolab.cpp
index 034c32d78..ae8e225fb 100644
--- a/kresources/kolab/kabc/resourcekolab.cpp
+++ b/kresources/kolab/kabc/resourcekolab.cpp
@@ -79,9 +79,12 @@ static const char* s_inlineMimeType = "text/x-vcard";
KABC::ResourceKolab::ResourceKolab( const KConfig *config )
: KPIM::ResourceABC( config ),
Kolab::ResourceKolabBase( "ResourceKolab-KABC" ),
- mCachedSubresource( TQString::null ), mLocked( false )
+ mCachedSubresource( TQString::null ), mCachedSubresourceNotFound( false ), mLocked( false )
{
setType( "imap" );
+ if ( !config ) {
+ setResourceName( i18n( "Kolab Server" ) );
+ }
}
KABC::ResourceKolab::~ResourceKolab()
@@ -124,14 +127,7 @@ bool KABC::ResourceKolab::doOpen()
void KABC::ResourceKolab::doClose()
{
- KConfig config( configFile() );
-
- Kolab::ResourceMap::ConstIterator it;
- for ( it = mSubResources.begin(); it != mSubResources.end(); ++it ) {
- config.setGroup( it.key() );
- config.writeEntry( "Active", it.data().active() );
- config.writeEntry( "CompletionWeight", it.data().completionWeight() );
- }
+ writeConfig();
}
KABC::Ticket * KABC::ResourceKolab::requestSaveTicket()
@@ -149,6 +145,7 @@ void KABC::ResourceKolab::releaseSaveTicket( Ticket* ticket )
{
mLocked = false;
mCachedSubresource = TQString::null;
+ mCachedSubresourceNotFound = false;
delete ticket;
}
@@ -163,7 +160,11 @@ TQString KABC::ResourceKolab::loadContact( const TQString& contactData,
contact.saveTo( &addr );
} else {
KABC::VCardConverter converter;
+#if defined(KABC_VCARD_ENCODING_FIX)
+ addr = converter.parseVCardRaw( contactData.utf8() );
+#else
addr = converter.parseVCard( contactData );
+#endif
}
addr.setResource( this );
@@ -301,11 +302,11 @@ void AttachmentList::updatePictureAttachment( const TQImage& image, const TQStri
{
assert( !name.isEmpty() );
if ( !image.isNull() ) {
- KTempFile* tempFile = new KTempFile;
- image.save( tempFile->file(), "PNG" );
- tempFile->close();
+ KTempFile tempFile;
+ image.save( tempFile.file(), "PNG" );
+ tempFile.close();
KURL url;
- url.setPath( tempFile->name() );
+ url.setPath( tempFile.name() );
kdDebug(5650) << "picture saved to " << url.path() << endl;
addAttachment( url.url(), name, "image/png" );
} else {
@@ -317,11 +318,11 @@ void AttachmentList::updateAttachment( const TQByteArray& data, const TQString&
{
assert( !name.isEmpty() );
if ( !data.isNull() ) {
- KTempFile* tempFile = new KTempFile;
- tempFile->file()->writeBlock( data );
- tempFile->close();
+ KTempFile tempFile;
+ tempFile.file()->writeBlock( data );
+ tempFile.close();
KURL url;
- url.setPath( tempFile->name() );
+ url.setPath( tempFile.name() );
kdDebug(5650) << "data saved to " << url.path() << endl;
addAttachment( url.url(), name, mimetype );
} else {
@@ -342,14 +343,20 @@ bool KABC::ResourceKolab::kmailUpdateAddressee( const Addressee& addr )
}
sernum = mUidMap[ uid ].serialNumber();
} else {
- if ( !mCachedSubresource.isNull() ) {
+ if ( !mCachedSubresource.isNull() || mCachedSubresourceNotFound ) {
subResource = mCachedSubresource;
} else {
- subResource = findWritableResource( mSubResources );
+ subResource = findWritableResource( Kolab::Contacts, mSubResources );
// We were locked, remember the subresource we are working with until
// we are unlocked
- if ( mLocked )
+ if ( mLocked ) {
mCachedSubresource = subResource;
+
+ // If the subresource is empty here, it means findWritableResource() failed, for example
+ // because the user cancelled the resource selection dialog. Remember that, so we avoid
+ // asking multiple times when locked.
+ mCachedSubresourceNotFound = subResource.isEmpty();
+ }
}
if ( subResource.isEmpty() )
return false;
@@ -374,7 +381,11 @@ bool KABC::ResourceKolab::kmailUpdateAddressee( const Addressee& addr )
} else {
mimetype = s_inlineMimeType;
KABC::VCardConverter converter;
+#if defined(KABC_VCARD_ENCODING_FIX)
+ data = TQString::fromUtf8( converter.createVCardRaw( addr ) );
+#else
data = converter.createVCard( addr );
+#endif
subject.prepend( "vCard " ); // as per kolab1 spec
}
bool rc = kmailUpdate( subResource, sernum, data, mimetype, subject,
@@ -652,6 +663,7 @@ void KABC::ResourceKolab::setSubresourceActive( const TQString &subresource, boo
} else {
kdDebug(5650) << "setSubresourceCompletionWeight: subresource " << subresource << " not found" << endl;
}
+ writeConfig();
}
@@ -667,4 +679,16 @@ bool KABC::ResourceKolab::removeSubresource( const TQString& id )
return kmailRemoveSubresource( id );
}
+void KABC::ResourceKolab::writeConfig()
+{
+ KConfig config( configFile() );
+
+ Kolab::ResourceMap::ConstIterator it;
+ for ( it = mSubResources.constBegin(); it != mSubResources.constEnd(); ++it ) {
+ config.setGroup( it.key() );
+ config.writeEntry( "Active", it.data().active() );
+ config.writeEntry( "CompletionWeight", it.data().completionWeight() );
+ }
+}
+
#include "resourcekolab.moc"
diff --git a/kresources/kolab/kabc/resourcekolab.h b/kresources/kolab/kabc/resourcekolab.h
index 1da472015..9158375a1 100644
--- a/kresources/kolab/kabc/resourcekolab.h
+++ b/kresources/kolab/kabc/resourcekolab.h
@@ -164,9 +164,12 @@ protected:
return Kolab::ResourceKolabBase::configFile( "kabc" );
}
+ void writeConfig();
+
// The list of subresources
Kolab::ResourceMap mSubResources;
TQString mCachedSubresource;
+ bool mCachedSubresourceNotFound;
bool mLocked;
};
diff --git a/kresources/kolab/kcal/event.cpp b/kresources/kolab/kcal/event.cpp
index 0f25eb73d..e1d58a13c 100644
--- a/kresources/kolab/kcal/event.cpp
+++ b/kresources/kolab/kcal/event.cpp
@@ -190,7 +190,9 @@ void Event::setFields( const KCal::Event* event )
{
Incidence::setFields( event );
- if ( event->hasEndDate() ) {
+ // note: if hasEndDate() is false and hasDuration() is true
+ // dtEnd() returns start+duration
+ if ( event->hasEndDate() || event->hasDuration() ) {
if ( event->doesFloat() ) {
// This is a floating event. Don't timezone move this one
mFloatingStatus = AllDay;
@@ -199,8 +201,9 @@ void Event::setFields( const KCal::Event* event )
mFloatingStatus = HasTime;
setEndDate( localToUTC( event->dtEnd() ) );
}
- } else
+ } else {
mHasEndDate = false;
+ }
setTransparency( event->transparency() );
}
diff --git a/kresources/kolab/kcal/incidence.cpp b/kresources/kolab/kcal/incidence.cpp
index 74f41fd8d..de076eb98 100644
--- a/kresources/kolab/kcal/incidence.cpp
+++ b/kresources/kolab/kcal/incidence.cpp
@@ -39,6 +39,8 @@
#include <libkcal/journal.h>
#include <korganizer/version.h>
+#include <libemailfunctions/email.h>
+
#include <kdebug.h>
#include <kmdcodec.h>
#include <kurl.h>
@@ -50,7 +52,6 @@ using namespace Kolab;
Incidence::Incidence( KCal::ResourceKolab *res, const TQString &subResource, Q_UINT32 sernum,
const TQString& tz )
: KolabBase( tz ), mFloatingStatus( Unset ), mHasAlarm( false ),
- mRevision( 0 ),
mResource( res ),
mSubResource( subResource ),
mSernum( sernum )
@@ -163,16 +164,6 @@ TQString Incidence::internalUID() const
return mInternalUID;
}
-void Incidence::setRevision( int revision )
-{
- mRevision = revision;
-}
-
-int Incidence::revision() const
-{
- return mRevision;
-}
-
bool Incidence::loadAttendeeAttribute( TQDomElement& element,
Attendee& attendee )
{
@@ -183,8 +174,16 @@ bool Incidence::loadAttendeeAttribute( TQDomElement& element,
TQDomElement e = n.toElement();
TQString tagName = e.tagName();
- if ( tagName == "display-name" )
- attendee.displayName = e.text();
+ if ( tagName == "display-name" ) {
+ // Quote the text in case it contains commas or other quotable chars.
+ TQString tusername = KPIM::quoteNameIfNecessary( e.text() );
+
+ TQString tname, temail;
+ // ignore the return value because it will always be false since
+ // tusername does not contain "@domain".
+ KPIM::getNameAndMail( tusername, tname, temail );
+ attendee.displayName = tname;
+ }
else if ( tagName == "smtp-address" )
attendee.smtpAddress = e.text();
else if ( tagName == "status" )
@@ -249,6 +248,69 @@ void Incidence::saveAttachments( TQDomElement& element ) const
}
}
+void Incidence::saveAlarms( TQDomElement& element ) const
+{
+ if ( mAlarms.isEmpty() ) return;
+
+ TQDomElement list = element.ownerDocument().createElement( "advanced-alarms" );
+ element.appendChild( list );
+ for ( KCal::Alarm::List::ConstIterator it = mAlarms.constBegin(); it != mAlarms.constEnd(); ++it ) {
+ KCal::Alarm* a = *it;
+ TQDomElement e = list.ownerDocument().createElement( "alarm" );
+ list.appendChild( e );
+
+ writeString( e, "enabled", a->enabled() ? "1" : "0" );
+ if ( a->hasStartOffset() ) {
+ writeString( e, "start-offset", TQString::number( a->startOffset().asSeconds()/60 ) );
+ }
+ if ( a->hasEndOffset() ) {
+ writeString( e, "end-offset", TQString::number( a->endOffset().asSeconds()/60 ) );
+ }
+ if ( a->repeatCount() ) {
+ writeString( e, "repeat-count", TQString::number( a->repeatCount() ) );
+ writeString( e, "repeat-interval", TQString::number( a->snoozeTime() ) );
+ }
+
+ switch ( a->type() ) {
+ case KCal::Alarm::Invalid:
+ break;
+ case KCal::Alarm::Display:
+ e.setAttribute( "type", "display" );
+ writeString( e, "text", a->text() );
+ break;
+ case KCal::Alarm::Procedure:
+ e.setAttribute( "type", "procedure" );
+ writeString( e, "program", a->programFile() );
+ writeString( e, "arguments", a->programArguments() );
+ break;
+ case KCal::Alarm::Email:
+ {
+ e.setAttribute( "type", "email" );
+ TQDomElement addresses = e.ownerDocument().createElement( "addresses" );
+ e.appendChild( addresses );
+ for ( TQValueList<KCal::Person>::ConstIterator it = a->mailAddresses().constBegin(); it != a->mailAddresses().constEnd(); ++it ) {
+ writeString( addresses, "address", (*it).fullName() );
+ }
+ writeString( e, "subject", a->mailSubject() );
+ writeString( e, "mail-text", a->mailText() );
+ TQDomElement attachments = e.ownerDocument().createElement( "attachments" );
+ e.appendChild( attachments );
+ for ( TQStringList::ConstIterator it = a->mailAttachments().constBegin(); it != a->mailAttachments().constEnd(); ++it ) {
+ writeString( attachments, "attachment", *it );
+ }
+ break;
+ }
+ case KCal::Alarm::Audio:
+ e.setAttribute( "type", "audio" );
+ writeString( e, "file", a->audioFile() );
+ break;
+ default:
+ kdWarning() << "Unhandled alarm type:" << a->type() << endl;
+ break;
+ }
+ }
+}
+
void Incidence::saveRecurrence( TQDomElement& element ) const
{
TQDomElement e = element.ownerDocument().createElement( "recurrence" );
@@ -289,8 +351,14 @@ void Incidence::loadRecurrence( const TQDomElement& element )
TQDomElement e = n.toElement();
TQString tagName = e.tagName();
- if ( tagName == "interval" )
- mRecurrence.interval = e.text().toInt();
+ if ( tagName == "interval" ) {
+ //kolab/issue4229, sometimes the interval value can be empty
+ if ( e.text().isEmpty() || e.text().toInt() <= 0 ) {
+ mRecurrence.interval = 1;
+ } else {
+ mRecurrence.interval = e.text().toInt();
+ }
+ }
else if ( tagName == "day" ) // can be present multiple times
mRecurrence.days.append( e.text() );
else if ( tagName == "daynumber" )
@@ -309,6 +377,118 @@ void Incidence::loadRecurrence( const TQDomElement& element )
}
}
+static void loadAddressesHelper( const TQDomElement& element, KCal::Alarm* a )
+{
+ for ( TQDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ TQDomElement e = n.toElement();
+ TQString tagName = e.tagName();
+
+ if ( tagName == "address" ) {
+ a->addMailAddress( KCal::Person( e.text() ) );
+ } else {
+ kdWarning() << "Unhandled tag" << tagName << endl;
+ }
+ }
+ }
+}
+
+static void loadAttachmentsHelper( const TQDomElement& element, KCal::Alarm* a )
+{
+ for ( TQDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ TQDomElement e = n.toElement();
+ TQString tagName = e.tagName();
+
+ if ( tagName == "attachment" ) {
+ a->addMailAttachment( e.text() );
+ } else {
+ kdWarning() << "Unhandled tag" << tagName << endl;
+ }
+ }
+ }
+}
+
+static void loadAlarmHelper( const TQDomElement& element, KCal::Alarm* a )
+{
+ for ( TQDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ TQDomElement e = n.toElement();
+ TQString tagName = e.tagName();
+
+ if ( tagName == "start-offset" ) {
+ a->setStartOffset( e.text().toInt()*60 );
+ } else if ( tagName == "end-offset" ) {
+ a->setEndOffset( e.text().toInt()*60 );
+ } else if ( tagName == "repeat-count" ) {
+ a->setRepeatCount( e.text().toInt() );
+ } else if ( tagName == "repeat-interval" ) {
+ a->setSnoozeTime( e.text().toInt() );
+ } else if ( tagName == "text" ) {
+ a->setText( e.text() );
+ } else if ( tagName == "program" ) {
+ a->setProgramFile( e.text() );
+ } else if ( tagName == "arguments" ) {
+ a->setProgramArguments( e.text() );
+ } else if ( tagName == "addresses" ) {
+ loadAddressesHelper( e, a );
+ } else if ( tagName == "subject" ) {
+ a->setMailSubject( e.text() );
+ } else if ( tagName == "mail-text" ) {
+ a->setMailText( e.text() );
+ } else if ( tagName == "attachments" ) {
+ loadAttachmentsHelper( e, a );
+ } else if ( tagName == "file" ) {
+ a->setAudioFile( e.text() );
+ } else if ( tagName == "enabled" ) {
+ a->setEnabled( e.text().toInt() != 0 );
+ } else {
+ kdWarning() << "Unhandled tag" << tagName << endl;
+ }
+ }
+ }
+}
+
+void Incidence::loadAlarms( const TQDomElement& element )
+{
+ for ( TQDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ if ( n.isComment() )
+ continue;
+ if ( n.isElement() ) {
+ TQDomElement e = n.toElement();
+ TQString tagName = e.tagName();
+
+ if ( tagName == "alarm" ) {
+ KCal::Alarm *a = new KCal::Alarm( 0 );
+ a->setEnabled( true ); // default to enabled, unless some XML attribute says otherwise.
+ TQString type = e.attribute( "type" );
+ if ( type == "display" ) {
+ a->setType( KCal::Alarm::Display );
+ } else if ( type == "procedure" ) {
+ a->setType( KCal::Alarm::Procedure );
+ } else if ( type == "email" ) {
+ a->setType( KCal::Alarm::Email );
+ } else if ( type == "audio" ) {
+ a->setType( KCal::Alarm::Audio );
+ } else {
+ kdWarning() << "Unhandled alarm type:" << type << endl;
+ }
+
+ loadAlarmHelper( e, a );
+ mAlarms << a;
+ } else {
+ kdWarning() << "Unhandled tag" << tagName << endl;
+ }
+ }
+ }
+}
+
bool Incidence::loadAttribute( TQDomElement& element )
{
TQString tagName = element.tagName();
@@ -340,20 +520,17 @@ bool Incidence::loadAttribute( TQDomElement& element )
} else if ( tagName == "alarm" )
// Alarms should be minutes before. Libkcal uses event time + alarm time
setAlarm( - element.text().toInt() );
+ else if ( tagName == "advanced-alarms" )
+ loadAlarms( element );
else if ( tagName == "x-kde-internaluid" )
setInternalUID( element.text() );
- else if ( tagName == "revision" ) {
- bool ok;
- int revision = element.text().toInt( &ok );
- if ( ok )
- setRevision( revision );
- } else if ( tagName == "x-custom" )
+ else if ( tagName == "x-custom" )
loadCustomAttributes( element );
else {
bool ok = KolabBase::loadAttribute( element );
if ( !ok ) {
// Unhandled tag - save for later storage
- kdDebug() << "Saving unhandled tag " << element.tagName() << endl;
+ //kdDebug() << "Saving unhandled tag " << element.tagName() << endl;
Custom c;
c.key = TQCString( "X-KDE-KolabUnhandled-" ) + element.tagName().latin1();
c.value = element.text();
@@ -385,8 +562,8 @@ bool Incidence::saveAttributes( TQDomElement& element ) const
int alarmTime = qRound( -alarm() );
writeString( element, "alarm", TQString::number( alarmTime ) );
}
+ saveAlarms( element );
writeString( element, "x-kde-internaluid", internalUID() );
- writeString( element, "revision", TQString::number( revision() ) );
saveCustomAttributes( element );
return true;
}
@@ -424,13 +601,15 @@ static KCal::Attendee::PartStat attendeeStringToStatus( const TQString& s )
return KCal::Attendee::NeedsAction;
if ( s == "tentative" )
return KCal::Attendee::Tentative;
+ if ( s == "accepted" )
+ return KCal::Attendee::Accepted;
if ( s == "declined" )
return KCal::Attendee::Declined;
if ( s == "delegated" )
return KCal::Attendee::Delegated;
// Default:
- return KCal::Attendee::Accepted;
+ return KCal::Attendee::None;
}
static TQString attendeeStatusToString( KCal::Attendee::PartStat status )
@@ -649,6 +828,14 @@ void Incidence::setFields( const KCal::Incidence* incidence )
mAttachments.push_back( a );
}
+ mAlarms.clear();
+
+ // Alarms
+ const KCal::Alarm::List alarms = incidence->alarms();
+ for ( KCal::Alarm::List::ConstIterator it = alarms.begin(); it != alarms.end(); ++it ) {
+ mAlarms.push_back( *it );
+ }
+
if ( incidence->doesRecur() ) {
setRecurrence( incidence->recurrence() );
mRecurrence.exclusions = incidence->recurrence()->exDates();
@@ -711,10 +898,17 @@ void Incidence::saveTo( KCal::Incidence* incidence )
incidence->setSummary( summary() );
incidence->setLocation( location() );
- if ( mHasAlarm ) {
+ if ( mHasAlarm && mAlarms.isEmpty() ) {
KCal::Alarm* alarm = incidence->newAlarm();
alarm->setStartOffset( qRound( mAlarm * 60.0 ) );
alarm->setEnabled( true );
+ alarm->setType( KCal::Alarm::Display );
+ } else if ( !mAlarms.isEmpty() ) {
+ for ( KCal::Alarm::List::ConstIterator it = mAlarms.constBegin(); it != mAlarms.constEnd(); ++it ) {
+ KCal::Alarm *alarm = *it;
+ alarm->setParent( incidence );
+ incidence->addAlarm( alarm );
+ }
}
if ( organizer().displayName.isEmpty() )
@@ -803,7 +997,7 @@ void Incidence::saveTo( KCal::Incidence* incidence )
if ( hasPilotSyncStatus() )
incidence->setSyncStatus( pilotSyncStatus() );
- for( TQValueList<Custom>::ConstIterator it = mCustomList.begin(); it != mCustomList.end(); ++it ) {
+ for( TQValueList<Custom>::ConstIterator it = mCustomList.constBegin(); it != mCustomList.constEnd(); ++it ) {
incidence->setNonKDECustomProperty( (*it).key, (*it).value );
}
@@ -836,7 +1030,7 @@ void Incidence::loadAttachments()
TQString Incidence::productID() const
{
- return TQString( "KOrganizer " ) + korgVersion + ", Kolab resource";
+ return TQString( "KOrganizer %1, Kolab resource" ).arg( korgVersion );
}
// Unhandled KCal::Incidence fields:
diff --git a/kresources/kolab/kcal/incidence.h b/kresources/kolab/kcal/incidence.h
index 32b112aaf..582d34c38 100644
--- a/kresources/kolab/kcal/incidence.h
+++ b/kresources/kolab/kcal/incidence.h
@@ -41,6 +41,7 @@ class TQDomElement;
namespace KCal {
class Incidence;
class Recurrence;
+ class Alarm;
class Attachment;
class ResourceKolab;
}
@@ -115,9 +116,6 @@ public:
void setInternalUID( const TQString& iuid );
TQString internalUID() const;
- virtual void setRevision( int );
- virtual int revision() const;
-
// Load the attributes of this class
virtual bool loadAttribute( TQDomElement& );
@@ -136,6 +134,9 @@ protected:
void saveAttendees( TQDomElement& element ) const;
void saveAttachments( TQDomElement& element ) const;
+ void loadAlarms( const TQDomElement& element );
+ void saveAlarms( TQDomElement& element ) const;
+
void loadRecurrence( const TQDomElement& element );
void saveRecurrence( TQDomElement& element ) const;
void saveCustomAttributes( TQDomElement& element ) const;
@@ -154,9 +155,9 @@ protected:
bool mHasAlarm;
Recurrence mRecurrence;
TQValueList<Attendee> mAttendees;
+ TQValueList<KCal::Alarm*> mAlarms;
TQValueList<KCal::Attachment*> mAttachments;
TQString mInternalUID;
- int mRevision;
struct Custom {
TQCString key;
diff --git a/kresources/kolab/kcal/kolab.desktop b/kresources/kolab/kcal/kolab.desktop
index 579e6406d..c0a7daa56 100644
--- a/kresources/kolab/kcal/kolab.desktop
+++ b/kresources/kolab/kcal/kolab.desktop
@@ -21,7 +21,6 @@ Name[hu]=IMAP-kiszolgálón tárolt naptár a KMailen keresztül
Name[is]=Dagatal á IMAP þjóni gegnum KMail
Name[it]=Calendario su server IMAP via KMail
Name[ja]=KMail 経由 IMAP サーバのカレンダー
-Name[ka]=კალენდარი IMAP სერვერზე KMail-ის საშუალებით
Name[kk]=KMail арқылы IMAP серверіндегі күнтізбе
Name[km]=ប្រតិទិន​លើ​ម៉ាស៊ីន​បម្រើ IMAP តាម​រយៈ KMail
Name[lt]=Kalendorius IMAP serveryje per KMail
diff --git a/kresources/kolab/kcal/resourcekolab.cpp b/kresources/kolab/kcal/resourcekolab.cpp
index b61b12110..1f5f486ff 100644
--- a/kresources/kolab/kcal/resourcekolab.cpp
+++ b/kresources/kolab/kcal/resourcekolab.cpp
@@ -41,7 +41,6 @@
#include <kio/uiserver_stub.h>
#include <kapplication.h>
#include <dcopclient.h>
-#include <libkcal/icalformat.h>
#include <libkdepim/kincidencechooser.h>
#include <kabc/locknull.h>
#include <kmainwindow.h>
@@ -72,8 +71,11 @@ static const char* incidenceInlineMimeType = "text/calendar";
ResourceKolab::ResourceKolab( const KConfig *config )
: ResourceCalendar( config ), ResourceKolabBase( "ResourceKolab-libkcal" ),
mCalendar( TQString::fromLatin1("UTC") ), mOpen( false ),mResourceChangedTimer( 0,
- "mResourceChangedTimer" )
+ "mResourceChangedTimer" ), mBatchAddingInProgress( false )
{
+ if ( !config ) {
+ setResourceName( i18n( "Kolab Server" ) );
+ }
setType( "imap" );
connect( &mResourceChangedTimer, TQT_SIGNAL( timeout() ),
this, TQT_SLOT( slotEmitResourceChanged() ) );
@@ -132,7 +134,7 @@ bool ResourceKolab::doOpen()
&& openResource( config, kmailJournalContentsType, mJournalSubResources );
}
-static void closeResource( KConfig& config, ResourceMap& map )
+static void writeResourceConfig( KConfig& config, ResourceMap& map )
{
ResourceMap::ConstIterator it;
for ( it = map.begin(); it != map.end(); ++it ) {
@@ -148,10 +150,7 @@ void ResourceKolab::doClose()
return;
mOpen = false;
- KConfig config( configFile() );
- closeResource( config, mEventSubResources );
- closeResource( config, mTodoSubResources );
- closeResource( config, mJournalSubResources );
+ writeConfig();
}
bool ResourceKolab::loadSubResource( const TQString& subResource,
@@ -217,11 +216,20 @@ bool ResourceKolab::loadSubResource( const TQString& subResource,
bool ResourceKolab::doLoad()
{
if (!mUidMap.isEmpty() ) {
+ emit resourceLoaded( this );
return true;
}
mUidMap.clear();
- return loadAllEvents() & loadAllTodos() & loadAllJournals();
+ bool result = loadAllEvents() & loadAllTodos() & loadAllJournals();
+ if ( result ) {
+ emit resourceLoaded( this );
+ } else {
+ // FIXME: anyone know if the resource correctly calls loadError()
+ // if it has one?
+ }
+
+ return result;
}
bool ResourceKolab::doLoadAll( ResourceMap& map, const char* mimetype )
@@ -297,19 +305,54 @@ bool ResourceKolab::doSave()
&& kmailTriggerSync( kmailJournalContentsType );
*/
}
-void ResourceKolab::incidenceUpdatedSilent( KCal::IncidenceBase* incidencebase)
+void ResourceKolab::incidenceUpdatedSilent( KCal::IncidenceBase* incidencebase )
{
- const TQString uid = incidencebase->uid();
+ const TQString uid = incidencebase->uid();
//kdDebug() << k_funcinfo << uid << endl;
if ( mUidsPendingUpdate.contains( uid ) || mUidsPendingAdding.contains( uid ) ) {
/* We are currently processing this event ( removing and readding or
* adding it ). If so, ignore this update. Keep the last of these around
* and process once we hear back from KMail on this event. */
- mPendingUpdates.replace( uid, incidencebase );
+ mPendingUpdates.remove( uid );
+ mPendingUpdates.insert( uid, incidencebase );
return;
}
+ { // start optimization
+ /**
+ KOrganizer and libkcal like calling two Incidence::updated()
+ for only one user change. That's because after a change,
+ IncidenceChanger calls incidence->setRevision( rev++ );
+ which also calls Incidence::updated().
+
+ Lets ignore the first updated() and only send to kmail
+ the second. This makes things faster.
+ */
+
+ //IncidenceBase doesn't have revision(), downcast needed.
+ Incidence *i = dynamic_cast<Incidence*>( incidencebase );
+
+ if ( i ) {
+ bool ignoreThisUpdate = false;
+
+ if ( !mLastKnownRevisions.contains( uid ) ) {
+ mLastKnownRevisions[uid] = i->revision();
+ }
+
+ // update the last known revision
+ if ( mLastKnownRevisions[uid] < i->revision() ) {
+ mLastKnownRevisions[uid] = i->revision();
+ } else {
+ ignoreThisUpdate = true;
+ }
+
+ if ( ignoreThisUpdate ) {
+ return;
+ }
+ }
+ } // end optimization
+
TQString subResource;
Q_UINT32 sernum = 0;
if ( mUidMap.contains( uid ) ) {
@@ -317,78 +360,85 @@ void ResourceKolab::incidenceUpdatedSilent( KCal::IncidenceBase* incidencebase)
sernum = mUidMap[ uid ].serialNumber();
mUidsPendingUpdate.append( uid );
}
- sendKMailUpdate( incidencebase, subResource, sernum );
+ sendKMailUpdate( incidencebase, subResource, sernum );
}
void ResourceKolab::incidenceUpdated( KCal::IncidenceBase* incidencebase )
{
- if ( incidencebase->isReadOnly() ) return;
+ if ( incidencebase->isReadOnly() ) {
+ return;
+ }
+
incidencebase->setSyncStatusSilent( KCal::Event::SYNCMOD );
incidencebase->setLastModified( TQDateTime::currentDateTime() );
+
// we should probably update the revision number here,
// or internally in the Event itself when certain things change.
// need to verify with ical documentation.
incidenceUpdatedSilent( incidencebase );
-
}
void ResourceKolab::resolveConflict( KCal::Incidence* inc, const TQString& subresource, Q_UINT32 sernum )
{
- if ( ! inc )
- return;
- if ( ! mResolveConflict ) {
- // we should do no conflict resolution
- delete inc;
- return;
- }
- const TQString origUid = inc->uid();
- Incidence* local = mCalendar.incidence( origUid );
- Incidence* localIncidence = 0;
- Incidence* addedIncidence = 0;
- Incidence* result = 0;
- if ( local ) {
- if (*local == *inc) {
- // real duplicate, remove the second one
- result = local;
- } else {
- KIncidenceChooser* ch = new KIncidenceChooser();
- ch->setIncidence( local ,inc );
- if ( KIncidenceChooser::chooseMode == KIncidenceChooser::ask ) {
- connect ( this, TQT_SIGNAL( useGlobalMode() ), ch, TQT_SLOT ( useGlobalMode() ) );
- if ( ch->exec() )
- if ( KIncidenceChooser::chooseMode != KIncidenceChooser::ask )
- emit useGlobalMode() ;
- }
- result = ch->getIncidence();
- delete ch;
- }
- } else {
- // nothing there locally, just take the new one. Can't Happen (TM)
- result = inc;
- }
- if ( result == local ) {
- delete inc;
- localIncidence = local;
- } else if ( result == inc ) {
- addedIncidence = inc;
- } else if ( result == 0 ) { // take both
- addedIncidence = inc;
- addedIncidence->setSummary( i18n("Copy of: %1").arg( addedIncidence->summary() ) );
- addedIncidence->setUid( CalFormat::createUniqueId() );
- localIncidence = local;
- }
- bool silent = mSilent;
- mSilent = false;
- if ( !localIncidence ) {
- deleteIncidence( local ); // remove local from kmail
- }
- mUidsPendingDeletion.append( origUid );
- if ( addedIncidence ) {
- sendKMailUpdate( addedIncidence, subresource, sernum );
- } else {
- kmailDeleteIncidence( subresource, sernum );// remove new from kmail
- }
- mSilent = silent;
+ if ( !inc ) {
+ return;
+ }
+
+ if ( !mResolveConflict ) {
+ // we should do no conflict resolution
+ delete inc;
+ return;
+ }
+ const TQString origUid = inc->uid();
+ Incidence* local = mCalendar.incidence( origUid );
+ Incidence* localIncidence = 0;
+ Incidence* addedIncidence = 0;
+ Incidence* result = 0;
+ if ( local ) {
+ if ( *local == *inc ) {
+ // real duplicate, remove the second one
+ result = local;
+ } else {
+ KIncidenceChooser* ch = new KIncidenceChooser();
+ ch->setIncidence( local ,inc );
+ if ( KIncidenceChooser::chooseMode == KIncidenceChooser::ask ) {
+ connect ( this, TQT_SIGNAL( useGlobalMode() ), ch, TQT_SLOT ( useGlobalMode() ) );
+ if ( ch->exec() ) {
+ if ( KIncidenceChooser::chooseMode != KIncidenceChooser::ask ) {
+ emit useGlobalMode() ;
+ }
+ }
+ }
+ result = ch->getIncidence();
+ delete ch;
+ }
+ } else {
+ // nothing there locally, just take the new one. Can't Happen (TM)
+ result = inc;
+ }
+ if ( result == local ) {
+ delete inc;
+ localIncidence = local;
+ } else if ( result == inc ) {
+ addedIncidence = inc;
+ } else if ( result == 0 ) { // take both
+ addedIncidence = inc;
+ addedIncidence->setSummary( i18n("Copy of: %1").arg( addedIncidence->summary() ) );
+ addedIncidence->setUid( CalFormat::createUniqueId() );
+ localIncidence = local;
+ }
+ const bool silent = mSilent;
+ mSilent = false;
+ if ( !localIncidence ) {
+ deleteIncidence( local ); // remove local from kmail
+ }
+ mUidsPendingDeletion.append( origUid );
+ if ( addedIncidence ) {
+ sendKMailUpdate( addedIncidence, subresource, sernum );
+ } else {
+ kmailDeleteIncidence( subresource, sernum );// remove new from kmail
+ }
+ mSilent = silent;
}
void ResourceKolab::addIncidence( const char* mimetype, const TQString& data,
const TQString& subResource, Q_UINT32 sernum )
@@ -457,15 +507,24 @@ bool ResourceKolab::sendKMailUpdate( KCal::IncidenceBase* incidencebase, const T
TQStringList attURLs, attMimeTypes, attNames;
TQValueList<KTempFile*> tmpFiles;
for ( KCal::Attachment::List::ConstIterator it = atts.constBegin(); it != atts.constEnd(); ++it ) {
- KTempFile* tempFile = new KTempFile;
- TQCString decoded = KCodecs::base64Decode( TQCString( (*it)->data() ) );
- tempFile->file()->writeBlock( decoded.data(), decoded.length() );
- tempFile->close();
- KURL url;
- url.setPath( tempFile->name() );
- attURLs.append( url.url() );
- attMimeTypes.append( (*it)->mimeType() );
- attNames.append( (*it)->label() );
+ if ( (*it)->isUri() ) {
+ continue;
+ }
+ KTempFile *tempFile = new KTempFile;
+ if ( tempFile->status() == 0 ) { // open ok
+ const TQByteArray decoded = (*it)->decodedData() ;
+
+ tempFile->file()->writeBlock( decoded.data(), decoded.count() );
+ KURL url;
+ url.setPath( tempFile->name() );
+ attURLs.append( url.url() );
+ attMimeTypes.append( (*it)->mimeType() );
+ attNames.append( (*it)->label() );
+ tempFile->close();
+ tmpFiles.append( tempFile );
+ } else {
+ kdWarning(5006) << "Cannot open temporary file for attachment";
+ }
}
TQStringList deletedAtts;
if ( kmailListAttachments( deletedAtts, subresource, sernum ) ) {
@@ -474,8 +533,9 @@ bool ResourceKolab::sendKMailUpdate( KCal::IncidenceBase* incidencebase, const T
}
}
CustomHeaderMap customHeaders;
- if ( incidence->schedulingID() != incidence->uid() )
+ if ( incidence->schedulingID() != incidence->uid() ) {
customHeaders.insert( "X-Kolab-SchedulingID", incidence->schedulingID() );
+ }
TQString subject = incidencebase->uid();
if ( !isXMLStorageFormat ) subject.prepend( "iCal " ); // conform to the old style
@@ -499,34 +559,49 @@ bool ResourceKolab::addIncidence( KCal::Incidence* incidence, const TQString& _s
Q_UINT32 sernum )
{
Q_ASSERT( incidence );
- if ( !incidence ) return false;
+ if ( !incidence ) {
+ return false;
+ }
+
+ kdDebug() << "Resourcekolab, adding incidence "
+ << incidence->summary()
+ << "; subresource = " << _subresource
+ << "; sernum = " << sernum
+ << "; mBatchAddingInProgress = " << mBatchAddingInProgress
+ << endl;
+
TQString uid = incidence->uid();
TQString subResource = _subresource;
Kolab::ResourceMap *map = &mEventSubResources; // don't use a ref here!
const TQString& type = incidence->type();
- if ( type == "Event" )
+ if ( type == "Event" ) {
map = &mEventSubResources;
- else if ( type == "Todo" )
+ } else if ( type == "Todo" ) {
map = &mTodoSubResources;
- else if ( type == "Journal" )
+ } else if ( type == "Journal" ) {
map = &mJournalSubResources;
- else
+ } else {
kdWarning() << "unknown type " << type << endl;
+ }
if ( !mSilent ) { /* We got this one from the user, tell KMail. */
// Find out if this event was previously stored in KMail
bool newIncidence = _subresource.isEmpty();
if ( newIncidence ) {
+ ResourceType type = Incidences;
// Add a description of the incidence
TQString text = "<b><font size=\"+1\">";
- if ( incidence->type() == "Event" )
+ if ( incidence->type() == "Event" ) {
+ type = Events;
text += i18n( "Choose the folder where you want to store this event" );
- else if ( incidence->type() == "Todo" )
+ } else if ( incidence->type() == "Todo" ) {
+ type = Tasks;
text += i18n( "Choose the folder where you want to store this task" );
- else
+ } else {
text += i18n( "Choose the folder where you want to store this incidence" );
+ }
text += "<font></b><br>";
if ( !incidence->summary().isEmpty() )
text += i18n( "<b>Summary:</b> %1" ).arg( incidence->summary() ) + "<br>";
@@ -541,24 +616,51 @@ bool ResourceKolab::addIncidence( KCal::Incidence* incidence, const TQString& _s
text += "<br>";
if ( incidence->type() == "Event" ) {
Event* event = static_cast<Event*>( incidence );
- if ( event->hasEndDate() )
- if ( !event->doesFloat() )
+ if ( event->hasEndDate() ) {
+ if ( !event->doesFloat() ) {
text += i18n( "<b>End:</b> %1, %2" )
.arg( event->dtEndDateStr(), event->dtEndTimeStr() );
- else
+ } else {
text += i18n( "<b>End:</b> %1" ).arg( event->dtEndDateStr() );
+ }
+ }
text += "<br>";
}
- subResource = findWritableResource( *map, text );
+
+ // Lets not warn the user 100 times that there's no writable resource
+ // and not ask 100 times which resource to use
+ if ( !mBatchAddingInProgress || !mLastUsedResources.contains( type ) ) {
+ subResource = findWritableResource( type, *map, text );
+ mLastUsedResources[type] = subResource;
+ } else {
+ subResource = mLastUsedResources[type];
+ }
+
+ if ( subResource.isEmpty() ) {
+ switch( mErrorCode ) {
+ case NoWritableFound:
+ setException( new ErrorFormat( ErrorFormat::NoWritableFound ) );
+ break;
+ case UserCancel:
+ setException( new ErrorFormat( ErrorFormat::UserCancel ) );
+ break;
+ case NoError:
+ break;
+ }
+ }
}
- if ( subResource.isEmpty() )
+ if ( subResource.isEmpty() ) {
+ endAddingIncidences(); // cleanup
+ kdDebug(5650) << "ResourceKolab: subResource is empty" << endl;
return false;
+ }
mNewIncidencesMap.insert( uid, subResource );
if ( !sendKMailUpdate( incidence, subResource, sernum ) ) {
kdError(5650) << "Communication problem in ResourceKolab::addIncidence()\n";
+ endAddingIncidences(); // cleanup
return false;
} else {
// KMail is doing it's best to add the event now, put a sticker on it,
@@ -568,13 +670,14 @@ bool ResourceKolab::addIncidence( KCal::Incidence* incidence, const TQString& _s
/* Add to the cache immediately if this is a new event coming from
* KOrganizer. It relies on the incidence being in the calendar when
* addIncidence returns. */
- if ( newIncidence ) {
+ if ( newIncidence || sernum == 0 ) {
mCalendar.addIncidence( incidence );
- incidence->registerObserver( this );
+ incidence->registerObserver( this );
}
}
} else { /* KMail told us */
- bool ourOwnUpdate = mUidsPendingUpdate.contains( uid );
+ const bool ourOwnUpdate = mUidsPendingUpdate.contains( uid );
+ kdDebug( 5650 ) << "addIncidence: ourOwnUpdate " << ourOwnUpdate << endl;
/* Check if we updated this one, which means kmail deleted and added it.
* We know the new state, so lets just not do much at all. The old incidence
* in the calendar remains valid, but the serial number changed, so we need to
@@ -592,6 +695,7 @@ bool ResourceKolab::addIncidence( KCal::Incidence* incidence, const TQString& _s
if ( mUidMap.contains( uid ) ) {
if ( mUidMap[ uid ].resource() == subResource ) {
if ( (*map)[ subResource ].writable() ) {
+ kdDebug( 5650 ) << "lets resolve the conflict " << endl;
resolveConflict( incidence, subResource, sernum );
} else {
kdWarning( 5650 ) << "Duplicate event in a read-only folder detected! "
@@ -601,8 +705,13 @@ bool ResourceKolab::addIncidence( KCal::Incidence* incidence, const TQString& _s
} else {
// duplicate uid in a different folder, do the internal-uid tango
incidence->setSchedulingID( uid );
- incidence->setUid(CalFormat::createUniqueId( ) );
+
+ incidence->setUid( CalFormat::createUniqueId( ) );
uid = incidence->uid();
+
+ /* Will be needed when kmail triggers a delete, so we don't delete the inocent
+ * incidence that's sharing the uid with this one */
+ mOriginalUID2fakeUID[qMakePair( incidence->schedulingID(), subResource )] = uid;
}
}
/* Add to the cache if the add didn't come from KOrganizer, in which case
@@ -636,13 +745,18 @@ bool ResourceKolab::addIncidence( KCal::Incidence* incidence, const TQString& _s
return true;
}
+bool ResourceKolab::addEvent( KCal::Event *event )
+{
+ return addEvent( event, TQString() );
+}
-bool ResourceKolab::addEvent( KCal::Event* event )
+bool ResourceKolab::addEvent( KCal::Event *event, const TQString &subResource )
{
- if ( mUidMap.contains( event->uid() ) )
+ if ( mUidMap.contains( event->uid() ) ) {
return true; //noop
- else
- return addIncidence( event, TQString::null, 0 );
+ } else {
+ return addIncidence( event, subResource, 0 );
+ }
}
void ResourceKolab::addEvent( const TQString& xml, const TQString& subresource,
@@ -650,14 +764,16 @@ void ResourceKolab::addEvent( const TQString& xml, const TQString& subresource,
{
KCal::Event* event = Kolab::Event::xmlToEvent( xml, mCalendar.timeZoneId(), this, subresource, sernum );
Q_ASSERT( event );
- if( event ) {
+ if ( event ) {
addIncidence( event, subresource, sernum );
}
}
bool ResourceKolab::deleteIncidence( KCal::Incidence* incidence )
{
- if ( incidence->isReadOnly() ) return false;
+ if ( incidence->isReadOnly() ) {
+ return false;
+ }
const TQString uid = incidence->uid();
if( !mUidMap.contains( uid ) ) return false; // Odd
@@ -709,12 +825,18 @@ KCal::Event::List ResourceKolab::rawEvents( const TQDate& start,
return mCalendar.rawEvents( start, end, inclusive );
}
-bool ResourceKolab::addTodo( KCal::Todo* todo )
+bool ResourceKolab::addTodo( KCal::Todo *todo )
{
- if ( mUidMap.contains( todo->uid() ) )
+ return addTodo( todo, TQString() );
+}
+
+bool ResourceKolab::addTodo( KCal::Todo *todo, const TQString &subResource )
+{
+ if ( mUidMap.contains( todo->uid() ) ) {
return true; //noop
- else
- return addIncidence( todo, TQString::null, 0 );
+ } else {
+ return addIncidence( todo, subResource, 0 );
+ }
}
void ResourceKolab::addTodo( const TQString& xml, const TQString& subresource,
@@ -722,8 +844,9 @@ void ResourceKolab::addTodo( const TQString& xml, const TQString& subresource,
{
KCal::Todo* todo = Kolab::Task::xmlToTask( xml, mCalendar.timeZoneId(), this, subresource, sernum );
Q_ASSERT( todo );
- if( todo )
- addIncidence( todo, subresource, sernum );
+ if ( todo ) {
+ addIncidence( todo, subresource, sernum );
+ }
}
bool ResourceKolab::deleteTodo( KCal::Todo* todo )
@@ -746,12 +869,17 @@ KCal::Todo::List ResourceKolab::rawTodosForDate( const TQDate& date )
return mCalendar.rawTodosForDate( date );
}
-bool ResourceKolab::addJournal( KCal::Journal* journal )
+bool ResourceKolab::addJournal( KCal::Journal *journal )
+{
+ return addJournal( journal, TQString() );
+}
+
+bool ResourceKolab::addJournal( KCal::Journal *journal, const TQString &subResource )
{
if ( mUidMap.contains( journal->uid() ) )
return true; //noop
else
- return addIncidence( journal, TQString::null, 0 );
+ return addIncidence( journal, subResource, 0 );
}
void ResourceKolab::addJournal( const TQString& xml, const TQString& subresource,
@@ -839,27 +967,33 @@ bool ResourceKolab::fromKMailAddIncidence( const TQString& type,
bool rc = true;
TemporarySilencer t( this ); // RAII
if ( type != kmailCalendarContentsType && type != kmailTodoContentsType
- && type != kmailJournalContentsType )
+ && type != kmailJournalContentsType ) {
// Not ours
return false;
- if ( !subresourceActive( subResource ) ) return true;
+ }
+
+ if ( !subresourceActive( subResource ) ) {
+ return true;
+ }
if ( format == KMailICalIface::StorageXML ) {
// If this data file is one of ours, load it here
- if ( type == kmailCalendarContentsType )
+ if ( type == kmailCalendarContentsType ) {
addEvent( data, subResource, sernum );
- else if ( type == kmailTodoContentsType )
+ } else if ( type == kmailTodoContentsType ) {
addTodo( data, subResource, sernum );
- else if ( type == kmailJournalContentsType )
+ } else if ( type == kmailJournalContentsType ) {
addJournal( data, subResource, sernum );
- else
+ } else {
rc = false;
+ }
} else {
Incidence *inc = mFormat.fromString( data );
- if ( !inc )
- rc = false;
- else
+ if ( inc ) {
addIncidence( inc, subResource, sernum );
+ } else {
+ rc = false;
+ }
}
return rc;
}
@@ -881,13 +1015,25 @@ void ResourceKolab::fromKMailDelIncidence( const TQString& type,
// It's good to know if was deleted, but we are waiting on a new one to
// replace it, so let's just sit tight.
} else {
+ TQString uidToUse;
+
+ QPair<TQString, TQString> p( uid, subResource );
+ if ( mOriginalUID2fakeUID.contains( p ) ) {
+ // Incidence with the same uid in a different folder...
+ // use the UID that addIncidence(...) generated
+ uidToUse = mOriginalUID2fakeUID[p];
+ } else {
+ uidToUse = uid;
+ }
+
// We didn't trigger this, so KMail did, remove the reference to the uid
- KCal::Incidence* incidence = mCalendar.incidence( uid );
+ KCal::Incidence* incidence = mCalendar.incidence( uidToUse );
if( incidence ) {
incidence->unRegisterObserver( this );
mCalendar.deleteIncidence( incidence );
}
- mUidMap.remove( uid );
+ mUidMap.remove( uidToUse );
+ mOriginalUID2fakeUID.remove( p );
mResourceChangedTimer.changeInterval( 100 );
}
}
@@ -1039,6 +1185,23 @@ void ResourceKolab::setSubresourceActive( const TQString &subresource, bool v )
}
mResourceChangedTimer.changeInterval( 100 );
}
+ TQTimer::singleShot( 0, this, TQT_SLOT(writeConfig()) );
+}
+
+bool ResourceKolab::subresourceWritable( const TQString& subresource ) const
+{
+ // Workaround: The ResourceView in KOrganizer wants to know this
+ // before it opens the resource :-( Make sure we are open
+ const_cast<ResourceKolab*>( this )->doOpen();
+
+ if ( mEventSubResources.contains( subresource ) )
+ return mEventSubResources[ subresource ].writable();
+ if ( mTodoSubResources.contains( subresource ) )
+ return mTodoSubResources[ subresource ].writable();
+ if ( mJournalSubResources.contains( subresource ) )
+ return mJournalSubResources[ subresource ].writable();
+
+ return false; //better a safe default
}
void ResourceKolab::slotEmitResourceChanged()
@@ -1053,7 +1216,6 @@ KABC::Lock* ResourceKolab::lock()
return new KABC::LockNull( true );
}
-
Kolab::ResourceMap* ResourceKolab::subResourceMap( const TQString& contentsType )
{
if ( contentsType == kmailCalendarContentsType ) {
@@ -1122,6 +1284,7 @@ bool ResourceKolab::unloadSubResource( const TQString& subResource )
const bool silent = mSilent;
mSilent = true;
Kolab::UidMap::Iterator mapIt = mUidMap.begin();
+ TQPtrList<KCal::Incidence> incidences;
while ( mapIt != mUidMap.end() )
{
Kolab::UidMap::Iterator it = mapIt++;
@@ -1130,11 +1293,18 @@ bool ResourceKolab::unloadSubResource( const TQString& subResource )
// FIXME incidence() is expensive
KCal::Incidence* incidence = mCalendar.incidence( it.key() );
if( incidence ) {
- incidence->unRegisterObserver( this );
- mCalendar.deleteIncidence( incidence );
+ // register all observers first before actually deleting them
+ // in case of inter-incidence relations the other part will get
+ // the change notification otherwise
+ incidence->unRegisterObserver( this );
+ incidences.append( incidence );
}
mUidMap.remove( it );
}
+ TQPtrListIterator<KCal::Incidence> it( incidences );
+ for ( ; it.current(); ++it ) {
+ mCalendar.deleteIncidence( it.current() );
+ }
mSilent = silent;
return true;
}
@@ -1150,4 +1320,23 @@ TQString ResourceKolab::subresourceType( const TQString &resource )
return TQString();
}
+void ResourceKolab::writeConfig()
+{
+ KConfig config( configFile() );
+ writeResourceConfig( config, mEventSubResources );
+ writeResourceConfig( config, mTodoSubResources );
+ writeResourceConfig( config, mJournalSubResources );
+}
+
+void ResourceKolab::beginAddingIncidences()
+{
+ mBatchAddingInProgress = true;
+}
+
+void ResourceKolab::endAddingIncidences()
+{
+ mBatchAddingInProgress = false;
+ mLastUsedResources.clear();
+}
+
#include "resourcekolab.moc"
diff --git a/kresources/kolab/kcal/resourcekolab.h b/kresources/kolab/kcal/resourcekolab.h
index e68c2c6bf..dda5ba32a 100644
--- a/kresources/kolab/kcal/resourcekolab.h
+++ b/kresources/kolab/kcal/resourcekolab.h
@@ -70,8 +70,9 @@ public:
void doClose();
// The libkcal functions. See the resource for descriptions
- bool addEvent( KCal::Event* anEvent );
- bool deleteEvent( KCal::Event* );
+ KDE_DEPRECATED bool addEvent( KCal::Event *event );
+ bool addEvent( KCal::Event *event, const TQString &subResource );
+ bool deleteEvent( KCal::Event * );
KCal::Event* event( const TQString &UniqueStr );
KCal::Event::List rawEvents( EventSortField sortField = EventSortUnsorted, SortDirection sortDirection = SortDirectionAscending );
KCal::Event::List rawEventsForDate(
@@ -82,15 +83,17 @@ public:
KCal::Event::List rawEvents( const TQDate& start, const TQDate& end,
bool inclusive = false );
- bool addTodo( KCal::Todo* todo );
- bool deleteTodo( KCal::Todo* );
- KCal::Todo* todo( const TQString& uid );
+ KDE_DEPRECATED bool addTodo( KCal::Todo * todo );
+ bool addTodo( KCal::Todo *todo, const TQString &subResource );
+ bool deleteTodo( KCal::Todo * );
+ KCal::Todo* todo( const TQString &uid );
KCal::Todo::List rawTodos( TodoSortField sortField = TodoSortUnsorted, SortDirection sortDirection = SortDirectionAscending );
KCal::Todo::List rawTodosForDate( const TQDate& date );
- bool addJournal( KCal::Journal* );
- bool deleteJournal( KCal::Journal* );
- KCal::Journal* journal( const TQString& uid );
+ KDE_DEPRECATED bool addJournal( KCal::Journal * );
+ bool addJournal( KCal::Journal *, const TQString &subResource );
+ bool deleteJournal( KCal::Journal * );
+ KCal::Journal* journal( const TQString &uid );
KCal::Journal::List rawJournals( JournalSortField sortField = JournalSortUnsorted, SortDirection sortDirection = SortDirectionAscending );
KCal::Journal::List rawJournalsForDate( const TQDate &date );
@@ -128,6 +131,9 @@ public:
/** (De)activate the subresource */
virtual void setSubresourceActive( const TQString &, bool );
+ /** Is this subresource writable? */
+ bool subresourceWritable( const TQString& ) const;
+
/** What is the label for this subresource? */
virtual const TQString labelForSubresource( const TQString& resource ) const;
@@ -140,10 +146,16 @@ public:
KABC::Lock* lock();
+ void beginAddingIncidences();
+
+ void endAddingIncidences();
+
signals:
void useGlobalMode();
protected slots:
void slotEmitResourceChanged();
+ void writeConfig();
+
protected:
/**
* Return list of alarms which are relevant for the current user. These
@@ -157,7 +169,11 @@ private:
void addIncidence( const char* mimetype, const TQString& xml,
const TQString& subResource, Q_UINT32 sernum );
- bool addIncidence( KCal::Incidence* i, const TQString& subresource,
+
+ /**
+ Caller guarantees i is not null.
+ */
+ bool addIncidence( KCal::Incidence *i, const TQString& subresource,
Q_UINT32 sernum );
void addEvent( const TQString& xml, const TQString& subresource,
@@ -215,6 +231,36 @@ private:
*/
TQMap<TQString, TQString> mNewIncidencesMap;
int mProgressDialogIncidenceLimit;
+
+ /**
+ * If a user has a subresource for viewing another user's folder then it can happen
+ * that addIncidence(...) adds an incidence with an already existing UID.
+ *
+ * When this happens, addIncidence(...) sets a new random UID and stores the
+ * original UID using incidence->setSchedulingID(uid) because KCal doesn't
+ * allow two incidences to have the same UID.
+ *
+ * This map keeps track of the generated UIDs (which are local) so we can delete the
+ * right incidence inside fromKMailDelIncidence(...) whenever we sync.
+ *
+ * The key is originalUID,subResource and the value is the fake UID.
+ */
+ TQMap< QPair<TQString, TQString>, TQString > mOriginalUID2fakeUID;
+
+ bool mBatchAddingInProgress;
+ TQMap<Kolab::ResourceType,TQString> mLastUsedResources;
+
+ /**
+ Indexed by uid, it holds the last known revision of an incidence.
+ If we receive an update where the incidence still has the same
+ revision as the last known, we ignore it and don't send it to kmail,
+ because shortly after, IncidenceChanger will increment the revision
+ and that will trigger another update.
+
+ If we didn't discard the first update, kmail would have been updated twice.
+ */
+ TQMap<TQString,int> mLastKnownRevisions;
+
};
struct TemporarySilencer {
diff --git a/kresources/kolab/kcal/task.cpp b/kresources/kolab/kcal/task.cpp
index 7bbdba978..36876b7d5 100644
--- a/kresources/kolab/kcal/task.cpp
+++ b/kresources/kolab/kcal/task.cpp
@@ -38,6 +38,41 @@
using namespace Kolab;
+// Kolab Storage Specification:
+// "The priority can be a number between 1 and 5, with 1 being the highest priority."
+// iCalendar (RFC 2445):
+// "The priority is specified as an integer in the range
+// zero to nine. A value of zero specifies an
+// undefined priority. A value of one is the
+// highest priority. A value of nine is the lowest
+// priority."
+
+static int kcalPriorityToKolab( const int kcalPriority )
+{
+ if ( kcalPriority >= 0 && kcalPriority <= 9 ) {
+ // We'll map undefined (0) to 3 (default)
+ // 0 1 2 3 4 5 6 7 8 9
+ static const int priorityMap[10] = { 3, 1, 1, 2, 2, 3, 3, 4, 4, 5 };
+ return priorityMap[kcalPriority];
+ }
+ else {
+ kdWarning() << "kcalPriorityToKolab(): Got invalid priority " << kcalPriority << endl;
+ return 3;
+ }
+}
+
+static int kolabPrioritytoKCal( const int kolabPriority )
+{
+ if ( kolabPriority >= 1 && kolabPriority <= 5 ) {
+ // 1 2 3 4 5
+ static const int priorityMap[5] = { 1, 3, 5, 7, 9 };
+ return priorityMap[kolabPriority - 1];
+ }
+ else {
+ kdWarning() << "kolabPrioritytoKCal(): Got invalid priority " << kolabPriority << endl;
+ return 5;
+ }
+}
KCal::Todo* Task::xmlToTask( const TQString& xml, const TQString& tz, KCal::ResourceKolab *res,
const TQString& subResource, Q_UINT32 sernum )
@@ -115,6 +150,26 @@ void Task::setDueDate( const TQDateTime& date )
{
mDueDate = date;
mHasDueDate = true;
+ mFloatingStatus = HasTime;
+}
+
+void Task::setDueDate( const TQDate &date )
+{
+ mDueDate = date;
+ mHasDueDate = true;
+ mFloatingStatus = AllDay;
+}
+
+
+void Task::setDueDate( const TQString &date )
+{
+ if ( date.length() > 10 ) {
+ // This is a date + time
+ setDueDate( stringToDateTime( date ) );
+ } else {
+ // This is only a date
+ setDueDate( stringToDate( date ) );
+ }
}
TQDateTime Task::dueDate() const
@@ -159,10 +214,18 @@ bool Task::loadAttribute( TQDomElement& element )
if ( tagName == "priority" ) {
bool ok;
- int priority = element.text().toInt( &ok );
- if ( !ok || priority < 0 || priority > 9 )
- priority = 5;
- setPriority( priority );
+ mKolabPriorityFromDom = element.text().toInt( &ok );
+ if ( !ok || mKolabPriorityFromDom < 1 || mKolabPriorityFromDom > 5 ) {
+ kdWarning() << "loadAttribute(): Invalid \"priority\" value: " << element.text() << endl;
+ mKolabPriorityFromDom = -1;
+ }
+ } else if ( tagName == "x-kcal-priority" ) {
+ bool ok;
+ mKCalPriorityFromDom = element.text().toInt( &ok );
+ if ( !ok || mKCalPriorityFromDom < 0 || mKCalPriorityFromDom > 9 ) {
+ kdWarning() << "loadAttribute(): Invalid \"x-kcal-priority\" value: " << element.text() << endl;
+ mKCalPriorityFromDom = -1;
+ }
} else if ( tagName == "completed" ) {
bool ok;
int percent = element.text().toInt( &ok );
@@ -182,13 +245,13 @@ bool Task::loadAttribute( TQDomElement& element )
else
// Default
setStatus( KCal::Incidence::StatusNone );
- } else if ( tagName == "due-date" )
- setDueDate( stringToDateTime( element.text() ) );
- else if ( tagName == "parent" )
+ } else if ( tagName == "due-date" ) {
+ setDueDate( element.text() );
+ } else if ( tagName == "parent" ) {
setParent( element.text() );
- else if ( tagName == "x-completed-date" )
+ } else if ( tagName == "x-completed-date" ) {
setCompletedDate( stringToDateTime( element.text() ) );
- else if ( tagName == "start-date" ) {
+ } else if ( tagName == "start-date" ) {
setHasStartDate( true );
setStartDate( element.text() );
} else
@@ -203,7 +266,11 @@ bool Task::saveAttributes( TQDomElement& element ) const
// Save the base class elements
Incidence::saveAttributes( element );
- writeString( element, "priority", TQString::number( priority() ) );
+ // We need to save x-kcal-priority as well, since the Kolab priority can only save values from
+ // 1 to 5, but we have values from 0 to 9, and do not want to loose them
+ writeString( element, "priority", TQString::number( kcalPriorityToKolab( priority() ) ) );
+ writeString( element, "x-kcal-priority", TQString::number( priority() ) );
+
writeString( element, "completed", TQString::number( percentCompleted() ) );
switch( status() ) {
@@ -232,14 +299,21 @@ bool Task::saveAttributes( TQDomElement& element ) const
break;
}
- if ( hasDueDate() )
- writeString( element, "due-date", dateTimeToString( dueDate() ) );
+ if ( hasDueDate() ) {
+ if ( mFloatingStatus == HasTime ) {
+ writeString( element, "due-date", dateTimeToString( dueDate() ) );
+ } else {
+ writeString( element, "due-date", dateToString( dueDate().date() ) );
+ }
+ }
- if ( !parent().isNull() )
+ if ( !parent().isNull() ) {
writeString( element, "parent", parent() );
+ }
- if ( hasCompletedDate() && percentCompleted() == 100)
+ if ( hasCompletedDate() && percentCompleted() == 100 ) {
writeString( element, "x-completed-date", dateTimeToString( completedDate() ) );
+ }
return true;
}
@@ -247,6 +321,9 @@ bool Task::saveAttributes( TQDomElement& element ) const
bool Task::loadXML( const TQDomDocument& document )
{
+ mKolabPriorityFromDom = -1;
+ mKCalPriorityFromDom = -1;
+
TQDomElement top = document.documentElement();
if ( top.tagName() != "task" ) {
@@ -269,6 +346,7 @@ bool Task::loadXML( const TQDomDocument& document )
}
loadAttachments();
+ decideAndSetPriority();
return true;
}
@@ -278,7 +356,7 @@ TQString Task::saveXML() const
TQDomElement element = document.createElement( "task" );
element.setAttribute( "version", "1.0" );
saveAttributes( element );
- if ( !hasStartDate() ) {
+ if ( !hasStartDate() && startDate().isValid() ) {
// events and journals always have a start date, but tasks don't.
// Remove the entry done by the inherited save above, because we
// don't have one.
@@ -299,21 +377,68 @@ void Task::setFields( const KCal::Todo* task )
setStatus( task->status() );
setHasStartDate( task->hasStartDate() );
- if ( task->hasDueDate() )
+ if ( task->hasDueDate() ) {
setDueDate( localToUTC( task->dtDue() ) );
- else
+ if ( task->doesFloat() ) {
+ // This is a floating task. Don't timezone move this one
+ mFloatingStatus = AllDay;
+ setDueDate( task->dtDue().date() );
+ } else {
+ mFloatingStatus = HasTime;
+ setDueDate( localToUTC( task->dtDue() ) );
+ }
+ } else {
mHasDueDate = false;
- if ( task->relatedTo() )
+ }
+
+ if ( task->relatedTo() ) {
setParent( task->relatedTo()->uid() );
- else if ( !task->relatedToUid().isEmpty() )
- setParent( task->relatedToUid() );
- else
+ } else if ( !task->relatedToUid().isEmpty() ) {
+ setParent( task->relatedToUid( ) );
+ } else {
setParent( TQString::null );
+ }
- if ( task->hasCompletedDate() && task->percentComplete() == 100 )
+ if ( task->hasCompletedDate() && task->percentComplete() == 100 ) {
setCompletedDate( localToUTC( task->completed() ) );
- else
+ } else {
mHasCompletedDate = false;
+ }
+}
+
+void Task::decideAndSetPriority()
+{
+ // If we have both Kolab and KCal values in the XML, we prefer the KCal value, but only if the
+ // values are still in sync
+ if ( mKolabPriorityFromDom != -1 && mKCalPriorityFromDom != -1 ) {
+ const bool inSync = ( kcalPriorityToKolab( mKCalPriorityFromDom ) == mKolabPriorityFromDom );
+ if ( inSync ) {
+ setPriority( mKCalPriorityFromDom );
+ }
+ else {
+ // Out of sync, some other client changed the Kolab priority, so we have to ignore our
+ // KCal priority
+ setPriority( kolabPrioritytoKCal( mKolabPriorityFromDom ) );
+ }
+ }
+
+ // Only KCal priority set, use that.
+ else if ( mKolabPriorityFromDom == -1 && mKCalPriorityFromDom != -1 ) {
+ kdWarning() << "decideAndSetPriority(): No Kolab priority found, only the KCal priority!" << endl;
+ setPriority( mKCalPriorityFromDom );
+ }
+
+ // Only Kolab priority set, use that
+ else if ( mKolabPriorityFromDom != -1 && mKCalPriorityFromDom == -1 ) {
+ setPriority( kolabPrioritytoKCal( mKolabPriorityFromDom ) );
+ }
+
+ // No priority set, use the default
+ else {
+ // According the RFC 2445, we should use 0 here, for undefined priority, but AFAIK KOrganizer
+ // doesn't support that, so we'll use 5.
+ setPriority( 5 );
+ }
}
void Task::saveTo( KCal::Todo* task )
diff --git a/kresources/kolab/kcal/task.h b/kresources/kolab/kcal/task.h
index 5dfb55854..f7e7c6d51 100644
--- a/kresources/kolab/kcal/task.h
+++ b/kresources/kolab/kcal/task.h
@@ -86,7 +86,9 @@ public:
virtual void setHasStartDate( bool );
virtual bool hasStartDate() const;
- virtual void setDueDate( const TQDateTime& date );
+ virtual void setDueDate( const TQDateTime &date );
+ virtual void setDueDate( const TQString &date );
+ virtual void setDueDate( const TQDate &date );
virtual TQDateTime dueDate() const;
virtual bool hasDueDate() const;
@@ -110,7 +112,19 @@ protected:
// Read all known fields from this ical todo
void setFields( const KCal::Todo* );
+ // This sets the priority of this task by looking at mKolabPriorityFromDom and
+ // mKCalPriorityFromDom.
+ void decideAndSetPriority();
+
+ // This is the KCal priority, not the Kolab priority.
+ // See kcalPriorityToKolab() and kolabPrioritytoKCal().
int mPriority;
+
+ // Those priority values are the raw values read by loadAttribute().
+ // They will be converted later in decideAndSetPriority().
+ int mKolabPriorityFromDom;
+ int mKCalPriorityFromDom;
+
int mPercentCompleted;
KCal::Incidence::Status mStatus;
TQString mParent;
diff --git a/kresources/kolab/knotes/kolabresource.desktop b/kresources/kolab/knotes/kolabresource.desktop
index d74e3f59b..317032d17 100644
--- a/kresources/kolab/knotes/kolabresource.desktop
+++ b/kresources/kolab/knotes/kolabresource.desktop
@@ -21,7 +21,6 @@ Name[hu]=IMAP-kiszolgáló a KMailen keresztül
Name[is]=IMAP þjónn gegnum KMail
Name[it]=Server IMAP via KMail
Name[ja]=KMail 経由 IMAP サーバ
-Name[ka]= IMAP-ს სერვერთან დაშვება KMail-ის საშუალებით
Name[kk]=KMail арқылы IMAP сервері
Name[km]=ម៉ាស៊ីន​បម្រើ IMAP តាម​រយៈ KMail
Name[lt]=IMAP serveris per KMail
diff --git a/kresources/kolab/knotes/note.cpp b/kresources/kolab/knotes/note.cpp
index 66556aaf8..168dae562 100644
--- a/kresources/kolab/knotes/note.cpp
+++ b/kresources/kolab/knotes/note.cpp
@@ -108,7 +108,6 @@ bool Note::richText() const
bool Note::loadAttribute( TQDomElement& element )
{
TQString tagName = element.tagName();
-
if ( tagName == "summary" )
setSummary( element.text() );
else if ( tagName == "foreground-color" )
@@ -136,8 +135,10 @@ bool Note::saveAttributes( TQDomElement& element ) const
#endif
writeString( element, "summary", summary() );
- writeString( element, "foreground-color", colorToString( foregroundColor() ) );
- writeString( element, "background-color", colorToString( backgroundColor() ) );
+ if ( foregroundColor().isValid() )
+ writeString( element, "foreground-color", colorToString( foregroundColor() ) );
+ if ( backgroundColor().isValid() )
+ writeString( element, "background-color", colorToString( backgroundColor() ) );
writeString( element, "knotes-richtext", mRichText ? "true" : "false" );
return true;
@@ -183,11 +184,27 @@ void Note::setFields( const KCal::Journal* journal )
{
KolabBase::setFields( journal );
- // TODO: background and foreground
setSummary( journal->summary() );
- setBackgroundColor( journal->customProperty( "KNotes", "BgColor" ) );
- setForegroundColor( journal->customProperty( "KNotes", "FgColor" ) );
- setRichText( journal->customProperty( "KNotes", "RichText" ) == "true" );
+
+ TQString property = journal->customProperty( "KNotes", "BgColor" );
+ if ( !property.isNull() ) {
+ setBackgroundColor( property );
+ } else {
+ setBackgroundColor( "yellow" );
+ }
+ property = journal->customProperty( "KNotes", "FgColor" );
+ if ( !property.isNull() ) {
+ setForegroundColor( property );
+ } else {
+ setForegroundColor( "black" );
+ }
+
+ property = journal->customProperty( "KNotes", "RichText" );
+ if ( !property.isNull() ) {
+ setRichText( property == "true" ? true : false );
+ } else {
+ setRichText( "false" );
+ }
}
void Note::saveTo( KCal::Journal* journal )
@@ -196,10 +213,12 @@ void Note::saveTo( KCal::Journal* journal )
// TODO: background and foreground
journal->setSummary( summary() );
- journal->setCustomProperty( "KNotes", "FgColor",
- colorToString( foregroundColor() ) );
- journal->setCustomProperty( "KNotes", "BgColor",
- colorToString( backgroundColor() ) );
+ if ( foregroundColor().isValid() )
+ journal->setCustomProperty( "KNotes", "FgColor",
+ colorToString( foregroundColor() ) );
+ if ( backgroundColor().isValid() )
+ journal->setCustomProperty( "KNotes", "BgColor",
+ colorToString( backgroundColor() ) );
journal->setCustomProperty( "KNotes", "RichText",
richText() ? "true" : "false" );
}
diff --git a/kresources/kolab/knotes/resourcekolab.cpp b/kresources/kolab/knotes/resourcekolab.cpp
index 1d633b62a..d917d0ac2 100644
--- a/kresources/kolab/knotes/resourcekolab.cpp
+++ b/kresources/kolab/knotes/resourcekolab.cpp
@@ -41,6 +41,7 @@
#include <kdebug.h>
#include <kglobal.h>
+#include <klocale.h>
using namespace Kolab;
@@ -53,6 +54,9 @@ ResourceKolab::ResourceKolab( const KConfig *config )
: ResourceNotes( config ), ResourceKolabBase( "ResourceKolab-KNotes" ),
mCalendar( TQString::fromLatin1("UTC") )
{
+ if ( !config ) {
+ setResourceName( i18n( "Kolab Server" ) );
+ }
setType( "imap" );
}
@@ -73,7 +77,7 @@ bool ResourceKolab::doOpen()
// Make the resource map from the folder list
TQValueList<KMailICalIface::SubResource>::ConstIterator it;
mSubResources.clear();
- for ( it = subResources.begin(); it != subResources.end(); ++it ) {
+ for ( it = subResources.constBegin(); it != subResources.constEnd(); ++it ) {
const TQString subResource = (*it).location;
const bool active = config.readBoolEntry( subResource, true );
mSubResources[ subResource ] = Kolab::SubResource( active, (*it).writable, (*it).label );
@@ -87,7 +91,7 @@ void ResourceKolab::doClose()
KConfig config( configFile() );
config.setGroup( configGroupName );
Kolab::ResourceMap::ConstIterator it;
- for ( it = mSubResources.begin(); it != mSubResources.end(); ++it )
+ for ( it = mSubResources.constBegin(); it != mSubResources.constEnd(); ++it )
config.writeEntry( it.key(), it.data().active() );
}
@@ -113,8 +117,8 @@ bool ResourceKolab::loadSubResource( const TQString& subResource,
// Populate with the new entries
const bool silent = mSilent;
mSilent = true;
- TQMap<Q_UINT32, TQString>::Iterator it;
- for ( it = lst.begin(); it != lst.end(); ++it ) {
+ TQMap<Q_UINT32, TQString>::ConstIterator it;
+ for ( it = lst.constBegin(); it != lst.constEnd(); ++it ) {
KCal::Journal* journal = addNote( it.data(), subResource, it.key(), mimetype );
if ( !journal )
kdDebug(5500) << "loading note " << it.key() << " failed" << endl;
@@ -134,7 +138,7 @@ bool ResourceKolab::load()
bool rc = true;
Kolab::ResourceMap::ConstIterator itR;
- for ( itR = mSubResources.begin(); itR != mSubResources.end(); ++itR ) {
+ for ( itR = mSubResources.constBegin(); itR != mSubResources.constEnd(); ++itR ) {
if ( !itR.data().active() )
// This subResource is disabled
continue;
@@ -162,25 +166,35 @@ bool ResourceKolab::addNote( KCal::Journal* journal )
KCal::Journal* ResourceKolab::addNote( const TQString& data, const TQString& subresource,
Q_UINT32 sernum, const TQString &mimetype )
{
- KCal::Journal* journal = 0;
- // FIXME: This does not take into account the time zone!
+ KCal::Journal *journal = 0;
+
+ // FIXME: This does not take into account the time zone!
KCal::ICalFormat formatter;
- if ( mimetype == attachmentMimeType )
+ if ( mimetype == attachmentMimeType ) {
journal = Note::xmlToJournal( data );
- else
+ } else {
journal = static_cast<KCal::Journal*>( formatter.fromString( data ) );
-
+ }
Q_ASSERT( journal );
- if( journal && !mUidMap.contains( journal->uid() ) )
- if ( addNote( journal, subresource, sernum ) )
- return journal;
- else
- delete journal;
- return 0;
+
+ bool addedOk = journal &&
+ !mUidMap.contains( journal->uid() ) &&
+ addNote( journal, subresource, sernum );
+
+ // for debugging
+ if ( journal && mUidMap.contains( journal->uid() ) ) {
+ kdDebug(5500) << "mUidMap already contains " << journal->uid() << endl;
+ }
+
+ if ( !addedOk ) {
+ delete journal;
+ journal = 0;
+ }
+
+ return journal;
}
-bool ResourceKolab::addNote( KCal::Journal* journal,
- const TQString& subresource, Q_UINT32 sernum )
+bool ResourceKolab::addNote( KCal::Journal *journal, const TQString &subresource, Q_UINT32 sernum )
{
kdDebug(5500) << "ResourceKolab::addNote( KCal::Journal*, '" << subresource << "', " << sernum << " )\n";
@@ -188,12 +202,15 @@ bool ResourceKolab::addNote( KCal::Journal* journal,
// Find out if this note was previously stored in KMail
bool newNote = subresource.isEmpty();
- mCalendar.addJournal( journal );
+ if ( !mCalendar.addJournal( journal ) ) {
+ return false;
+ }
- TQString resource =
- newNote ? findWritableResource( mSubResources ) : subresource;
- if ( resource.isEmpty() ) // canceled
+ TQString resource = newNote ? findWritableResource( Kolab::Notes, mSubResources ) : subresource;
+ if ( resource.isEmpty() ) {
+ // canceled
return false;
+ }
if ( !mSilent ) {
TQString xml = Note::journalToXML( journal );
@@ -209,7 +226,6 @@ bool ResourceKolab::addNote( KCal::Journal* journal,
mUidMap[ journal->uid() ] = StorageReference( resource, sernum );
return true;
}
-
return false;
}
@@ -225,9 +241,7 @@ bool ResourceKolab::deleteNote( KCal::Journal* journal )
mUidMap[ uid ].serialNumber() );
}
mUidMap.remove( uid );
- manager()->deleteNote( journal );
- mCalendar.deleteJournal( journal );
- return true;
+ return mCalendar.deleteJournal( journal );
}
KCal::Alarm::List ResourceKolab::alarms( const TQDateTime& from, const TQDateTime& to )
@@ -239,7 +253,7 @@ KCal::Alarm::List ResourceKolab::alarms( const TQDateTime& from, const TQDateTim
{
TQDateTime preTime = from.addSecs( -1 );
KCal::Alarm::List::ConstIterator it;
- for( it = (*note)->alarms().begin(); it != (*note)->alarms().end(); ++it )
+ for( it = (*note)->alarms().constBegin(); it != (*note)->alarms().constEnd(); ++it )
{
if ( (*it)->enabled() )
{
@@ -261,7 +275,7 @@ void ResourceKolab::incidenceUpdated( KCal::IncidenceBase* i )
subResource = mUidMap[ i->uid() ].resource();
sernum = mUidMap[ i->uid() ].serialNumber();
} else { // can this happen?
- subResource = findWritableResource( mSubResources );
+ subResource = findWritableResource( Kolab::Notes, mSubResources );
if ( subResource.isEmpty() ) // canceled
return;
sernum = 0;
@@ -313,8 +327,11 @@ void ResourceKolab::fromKMailDelIncidence( const TQString& type,
const bool silent = mSilent;
mSilent = true;
KCal::Journal* j = mCalendar.journal( uid );
- if( j )
- deleteNote( j );
+ if ( j ) {
+ if ( deleteNote( j ) ) {
+ manager()->deleteNote( j );
+ }
+ }
mSilent = silent;
}
@@ -370,7 +387,7 @@ void ResourceKolab::fromKMailDelSubresource( const TQString& type,
// Make a list of all uids to remove
Kolab::UidMap::ConstIterator mapIt;
TQStringList uids;
- for ( mapIt = mUidMap.begin(); mapIt != mUidMap.end(); ++mapIt )
+ for ( mapIt = mUidMap.constBegin(); mapIt != mUidMap.constEnd(); ++mapIt )
if ( mapIt.data().resource() == subResource )
// We have a match
uids << mapIt.key();
@@ -380,7 +397,7 @@ void ResourceKolab::fromKMailDelSubresource( const TQString& type,
const bool silent = mSilent;
mSilent = true;
TQStringList::ConstIterator it;
- for ( it = uids.begin(); it != uids.end(); ++it ) {
+ for ( it = uids.constBegin(); it != uids.constEnd(); ++it ) {
KCal::Journal* j = mCalendar.journal( *it );
if( j )
deleteNote( j );
@@ -405,7 +422,7 @@ void ResourceKolab::fromKMailAsyncLoadResult( const TQMap<Q_UINT32, TQString>& m
mimetype = attachmentMimeType;
else
mimetype = inlineMimeType;
- for( TQMap<Q_UINT32, TQString>::ConstIterator it = map.begin(); it != map.end(); ++it ) {
+ for( TQMap<Q_UINT32, TQString>::ConstIterator it = map.constBegin(); it != map.constEnd(); ++it ) {
KCal::Journal* journal = addNote( it.data(), folder, it.key(), mimetype );
if ( !journal )
kdDebug(5500) << "loading note " << it.key() << " failed" << endl;
@@ -433,5 +450,14 @@ bool ResourceKolab::subresourceActive( const TQString& res ) const
return true;
}
+bool ResourceKolab::subresourceWritable( const TQString& res ) const
+{
+ if ( mSubResources.contains( res ) ) {
+ return mSubResources[ res ].writable();
+ }
+
+ // Safe default bet:
+ return false;
+}
#include "resourcekolab.moc"
diff --git a/kresources/kolab/knotes/resourcekolab.h b/kresources/kolab/knotes/resourcekolab.h
index a738a30a5..6ff994ccf 100644
--- a/kresources/kolab/knotes/resourcekolab.h
+++ b/kresources/kolab/knotes/resourcekolab.h
@@ -102,6 +102,9 @@ public:
/** Is this subresource active? */
bool subresourceActive( const TQString& ) const;
+ /** Is this subresource writable? */
+ bool subresourceWritable( const TQString& ) const;
+
signals:
void signalSubresourceAdded( Resource*, const TQString&, const TQString& );
void signalSubresourceRemoved( Resource*, const TQString&, const TQString& );
diff --git a/kresources/kolab/shared/kmailconnection.cpp b/kresources/kolab/shared/kmailconnection.cpp
index 9135e16db..66674abfa 100644
--- a/kresources/kolab/shared/kmailconnection.cpp
+++ b/kresources/kolab/shared/kmailconnection.cpp
@@ -73,16 +73,38 @@ static const TQCString dcopObjectId = "KMailICalIface";
bool KMailConnection::connectToKMail()
{
if ( !mKMailIcalIfaceStub ) {
- TQString error;
TQCString dcopService;
- int result = KDCOPServiceStarter::self()->
- findServiceFor( "DCOP/ResourceBackend/IMAP", TQString::null,
- TQString::null, &error, &dcopService );
- if ( result != 0 ) {
- kdError(5650) << "Couldn't connect to the IMAP resource backend\n";
- // TODO: You might want to show "error" (if not empty) here,
- // using e.g. KMessageBox
- return false;
+
+ // if we are kmail (and probably kontact as well) ourselves, don't try to start us again
+ // this prevents a DCOP deadlock when launching the kmail while kontact is the IMAP backend
+ // provider (and probably vice versa)
+ if ( kapp->instanceName() == "kmail" ) {
+ // someone, probably ourselves, already offers the interface, if not stop here
+ const QCStringList services = kapp->dcopClient()->registeredApplications();
+ for ( uint i = 0; i < services.count(); ++i ) {
+ if ( services[i].find( "anonymous" ) == 0 ) // querying anonymous-XXXXX deadlocks as well, what are those anyway?
+ continue;
+ const QCStringList objs = kapp->dcopClient()->remoteObjects( services[i] );
+ if ( objs.contains( dcopObjectId ) ) {
+ dcopService = services[i];
+ break;
+ }
+ }
+ if ( dcopService.isEmpty() ) {
+ kdError(5650) << k_funcinfo << "Not connecting to KMail to prevent DCOP deadlock" << endl;
+ return false;
+ }
+ } else {
+ TQString error;
+ int result = KDCOPServiceStarter::self()->
+ findServiceFor( "DCOP/ResourceBackend/IMAP", TQString::null,
+ TQString::null, &error, &dcopService );
+ if ( result != 0 ) {
+ kdError(5650) << "Couldn't connect to the IMAP resource backend\n";
+ // TODO: You might want to show "error" (if not empty) here,
+ // using e.g. KMessageBox
+ return false;
+ }
}
mKMailIcalIfaceStub = new KMailICalIface_stub( kapp->dcopClient(),
diff --git a/kresources/kolab/shared/kolabbase.cpp b/kresources/kolab/shared/kolabbase.cpp
index 9a4a17f7c..b7f502576 100644
--- a/kresources/kolab/shared/kolabbase.cpp
+++ b/kresources/kolab/shared/kolabbase.cpp
@@ -36,6 +36,7 @@
#include <kabc/addressee.h>
#include <libkcal/journal.h>
#include <libkdepim/kpimprefs.h>
+#include <libemailfunctions/email.h>
#include <kdebug.h>
#include <tqfile.h>
@@ -257,8 +258,16 @@ bool KolabBase::loadEmailAttribute( TQDomElement& element, Email& email )
TQDomElement e = n.toElement();
const TQString tagName = e.tagName();
- if ( tagName == "display-name" )
- email.displayName = e.text();
+ if ( tagName == "display-name" ) {
+ // Quote the text in case it contains commas or other quotable chars.
+ TQString tusername = KPIM::quoteNameIfNecessary( e.text() );
+
+ TQString tname, temail;
+ // ignore the return value because it will always be false since
+ // tusername does not contain "@domain".
+ KPIM::getNameAndMail( tusername, tname, temail );
+ email.displayName = tname;
+ }
else if ( tagName == "smtp-address" )
email.smtpAddress = e.text();
else
@@ -411,7 +420,11 @@ TQString KolabBase::dateToString( const TQDate& date )
TQDateTime KolabBase::stringToDateTime( const TQString& _date )
{
TQString date( _date );
- if ( date.endsWith( "Z" ) )
+ //Deal with data from some clients that always append a Z to dates.
+ if ( date.endsWith( "ZZ" ) )
+ date.truncate( date.length() - 2 );
+ //In TQt3, TQt::ISODate cannot handle a trailing Z for UTC, so remove if found.
+ else if ( date.endsWith( "Z" ) )
date.truncate( date.length() - 1 );
return TQDateTime::fromString( date, Qt::ISODate );
}
diff --git a/kresources/kolab/shared/resourcekolabbase.cpp b/kresources/kolab/shared/resourcekolabbase.cpp
index 291910fb9..2db2117db 100644
--- a/kresources/kolab/shared/resourcekolabbase.cpp
+++ b/kresources/kolab/shared/resourcekolabbase.cpp
@@ -210,9 +210,12 @@ bool ResourceKolabBase::kmailRemoveSubresource( const TQString& resource )
return mConnection->kmailRemoveSubresource( resource );
}
-TQString ResourceKolabBase::findWritableResource( const ResourceMap& resources,
+TQString ResourceKolabBase::findWritableResource( const ResourceType &type,
+ const ResourceMap& resources,
const TQString& text )
{
+ mErrorCode = NoError;
+
// I have to use the label (shown in the dialog) as key here. But given how the
// label is made up, it should be unique. If it's not, well the dialog would suck anyway...
TQMap<TQString, TQString> possible;
@@ -227,7 +230,33 @@ TQString ResourceKolabBase::findWritableResource( const ResourceMap& resources,
if ( possible.isEmpty() ) { // None found!!
kdWarning(5650) << "No writable resource found!" << endl;
- KMessageBox::error( 0, i18n( "No writable resource was found, saving will not be possible. Reconfigure KMail first." ) );
+
+ TQString errorText;
+ switch( type ) {
+ case Events:
+ errorText = i18n( "You have no writable event folders so saving will not be possible.\n"
+ "Please create or activate at least one writable event folder and try again." );
+ break;
+ case Tasks:
+ errorText = i18n( "You have no writable task folders so saving will not be possible.\n"
+ "Please create or activate at least one writable task folder and try again." );
+ break;
+ case Incidences:
+ errorText = i18n( "You have no writable calendar folder so saving will not be possible.\n"
+ "Please create or activate at least one writable calendar folder and try again." );
+ break;
+ case Notes:
+ errorText = i18n( "You have no writable notes folders so saving will not be possible.\n"
+ "Please create or activate at least one writable notes folder and try again." );
+ break;
+ case Contacts:
+ errorText = i18n( "You have no writable addressbook folder so saving will not be possible.\n"
+ "Please create or activate at least one writable addressbook folder and try again." );
+ break;
+ }
+
+ KMessageBox::error( 0, errorText );
+ mErrorCode = NoWritableFound;
return TQString::null;
}
if ( possible.count() == 1 )
@@ -242,8 +271,11 @@ TQString ResourceKolabBase::findWritableResource( const ResourceMap& resources,
// Several found, ask the user
TQString chosenLabel = KPIM::FolderSelectDialog::getItem( i18n( "Select Resource Folder" ),
t, possible.keys() );
- if ( chosenLabel.isEmpty() ) // cancelled
+ if ( chosenLabel.isEmpty() ) {
+ // cancelled
+ mErrorCode = UserCancel;
return TQString::null;
+ }
return possible[chosenLabel];
}
diff --git a/kresources/kolab/shared/resourcekolabbase.h b/kresources/kolab/shared/resourcekolabbase.h
index b2ce0501f..1bd8b9515 100644
--- a/kresources/kolab/shared/resourcekolabbase.h
+++ b/kresources/kolab/shared/resourcekolabbase.h
@@ -46,6 +46,8 @@ class KURL;
namespace Kolab {
+enum ResourceType { Tasks, Events, Incidences, Contacts, Notes };
+
class KMailConnection;
/**
@@ -168,9 +170,17 @@ protected:
TQString configFile( const TQString& type ) const;
/// If only one of these is writable, return that. Otherwise return null.
- TQString findWritableResource( const ResourceMap& resources,
+ TQString findWritableResource( const ResourceType &type,
+ const ResourceMap& resources,
const TQString& text = TQString::null );
+ enum ErrorCode {
+ NoError,
+ NoWritableFound, /**< No writable resource is available */
+ UserCancel /**< User canceled the operation */
+ };
+ ErrorCode mErrorCode;
+
bool mSilent;
/**
diff --git a/kresources/lib/addressbookadaptor.cpp b/kresources/lib/addressbookadaptor.cpp
index 900772e56..80da39421 100644
--- a/kresources/lib/addressbookadaptor.cpp
+++ b/kresources/lib/addressbookadaptor.cpp
@@ -32,9 +32,9 @@
using namespace KABC;
-AddressBookUploadItem::AddressBookUploadItem(
- KPIM::GroupwareDataAdaptor *adaptor,
- KABC::Addressee addr,
+AddressBookUploadItem::AddressBookUploadItem(
+ KPIM::GroupwareDataAdaptor *adaptor,
+ KABC::Addressee addr,
GroupwareUploadItem::UploadType type )
: GroupwareUploadItem( type )
{
@@ -42,7 +42,11 @@ AddressBookUploadItem::AddressBookUploadItem(
setUrl( addr.custom( adaptor->identifier(), "storagelocation" ) );
setUid( addr.uid() );
KABC::VCardConverter vcard;
+#if defined(KABC_VCARD_ENCODING_FIX)
+ setData( vcard.createVCardRaw( addr ) );
+#else
setData( vcard.createVCard( addr ) );
+#endif
}
@@ -105,12 +109,12 @@ void AddressBookAdaptor::addressbookItemDownloaded( KABC::Addressee addr,
deleteItem( newLocalId );
TQString localId = idMapper()->localId( remoteId.path() );
if ( !localId.isEmpty() ) deleteItem( localId );
-
+
// add the new item
addr.insertCustom( identifier(), "storagelocation", storagelocation );
if ( !localId.isEmpty() ) addr.setUid( localId );
addItem( addr );
-
+
// update the fingerprint and the ids in the idMapper
idMapper()->removeRemoteId( localId );
idMapper()->removeRemoteId( newLocalId );
@@ -123,7 +127,7 @@ void AddressBookAdaptor::clearChange( const TQString &uid )
mResource->clearChange( uid );
}
-KPIM::GroupwareUploadItem *AddressBookAdaptor::newUploadItem(
+KPIM::GroupwareUploadItem *AddressBookAdaptor::newUploadItem(
KABC::Addressee addr, KPIM::GroupwareUploadItem::UploadType type )
{
return new AddressBookUploadItem( this, addr, type );
diff --git a/kresources/lib/folderselectdialog.cpp b/kresources/lib/folderselectdialog.cpp
index 0942f8223..c4d343598 100644
--- a/kresources/lib/folderselectdialog.cpp
+++ b/kresources/lib/folderselectdialog.cpp
@@ -39,7 +39,7 @@ using namespace KPIM;
FolderSelectDialog::FolderSelectDialog( const TQString& caption, const TQString& label,
const TQStringList& list )
- : KDialogBase(0, 0, true, caption, Ok, Ok, true)
+ : KDialogBase(0, 0, true, caption, Ok|Cancel, Ok, true)
{
TQFrame* frame = makeMainWidget();
TQVBoxLayout* layout = new TQVBoxLayout( frame, 0, spacingHint() );
@@ -81,3 +81,8 @@ void FolderSelectDialog::closeEvent(TQCloseEvent *event)
{
event->ignore();
}
+
+void FolderSelectDialog::reject()
+{
+}
+
diff --git a/kresources/lib/folderselectdialog.h b/kresources/lib/folderselectdialog.h
index a7879f9a0..e5901239a 100644
--- a/kresources/lib/folderselectdialog.h
+++ b/kresources/lib/folderselectdialog.h
@@ -49,6 +49,7 @@ public:
protected:
virtual void closeEvent(TQCloseEvent *event);
+ void reject();
private:
KListBox* mListBox;
};
diff --git a/kresources/lib/kcal_resourcegroupwarebase.cpp b/kresources/lib/kcal_resourcegroupwarebase.cpp
index 7499b224d..823943c2b 100644
--- a/kresources/lib/kcal_resourcegroupwarebase.cpp
+++ b/kresources/lib/kcal_resourcegroupwarebase.cpp
@@ -39,13 +39,13 @@
using namespace KCal;
ResourceGroupwareBase::ResourceGroupwareBase()
- : ResourceCached( 0 ), mPrefs(0), mFolderLister(0),
+ : ResourceCached( 0 ), mPrefs(0), mFolderLister(0),
mLock( true ), mAdaptor(0), mDownloadJob(0), mUploadJob(0)
{
}
ResourceGroupwareBase::ResourceGroupwareBase( const KConfig *config )
- : ResourceCached( config ), mPrefs(0), mFolderLister(0),
+ : ResourceCached( config ), mPrefs(0), mFolderLister(0),
mLock( true ), mAdaptor(0), mDownloadJob(0), mUploadJob(0)
{
if ( config ) readConfig( config );
@@ -69,7 +69,7 @@ bool ResourceGroupwareBase::addEvent( Event *event )
{
if ( adaptor() && ( adaptor()->supports( KPIM::FolderLister::Event ) ||
adaptor()->supports( KPIM::FolderLister::All ) ) ) {
- return ResourceCached::addEvent( event );
+ return ResourceCached::addEvent( event, TQString() );
} else return false;
}
@@ -77,7 +77,7 @@ bool ResourceGroupwareBase::addTodo( Todo *todo )
{
if ( adaptor() && ( adaptor()->supports( KPIM::FolderLister::Todo ) ||
adaptor()->supports( KPIM::FolderLister::All ) ) ) {
- return ResourceCached::addTodo( todo );
+ return ResourceCached::addTodo( todo, TQString() );
} else return false;
}
@@ -85,30 +85,30 @@ bool ResourceGroupwareBase::addJournal( Journal *journal )
{
if ( adaptor() && ( adaptor()->supports( KPIM::FolderLister::Journal ) ||
adaptor()->supports( KPIM::FolderLister::All ) ) ) {
- return ResourceCached::addJournal( journal );
+ return ResourceCached::addJournal( journal, TQString() );
} else return false;
}
-KPIM::GroupwareDownloadJob *ResourceGroupwareBase::createDownloadJob(
+KPIM::GroupwareDownloadJob *ResourceGroupwareBase::createDownloadJob(
CalendarAdaptor *adaptor )
{
return new KPIM::GroupwareDownloadJob( adaptor );
}
-KPIM::GroupwareUploadJob *ResourceGroupwareBase::createUploadJob(
+KPIM::GroupwareUploadJob *ResourceGroupwareBase::createUploadJob(
CalendarAdaptor *adaptor )
{
return new KPIM::GroupwareUploadJob( adaptor );
}
-void ResourceGroupwareBase::setPrefs( KPIM::GroupwarePrefsBase *newprefs )
+void ResourceGroupwareBase::setPrefs( KPIM::GroupwarePrefsBase *newprefs )
{
if ( !newprefs ) return;
if ( mPrefs ) delete mPrefs;
mPrefs = newprefs;
mPrefs->addGroupPrefix( identifier() );
-
+
mPrefs->readConfig();
if ( mFolderLister ) mFolderLister->readConfig( mPrefs );
}
@@ -236,7 +236,7 @@ void ResourceGroupwareBase::doClose()
ResourceCached::doClose();
if ( mDownloadJob ) mDownloadJob->kill();
- if ( adaptor() &&
+ if ( adaptor() &&
adaptor()->flags() & KPIM::GroupwareDataAdaptor::GWResNeedsLogoff ) {
KIO::Job *logoffJob = adaptor()->createLogoffJob( prefs()->url(), prefs()->user(), prefs()->password() );
connect( logoffJob, TQT_SIGNAL( result( KIO::Job * ) ),
@@ -267,7 +267,7 @@ bool ResourceGroupwareBase::doLoad()
kdWarning() << "Download still in progress" << endl;
return false;
}
-
+
mCalendar.close();
clearChanges();
disableChangeNotification();
@@ -292,7 +292,7 @@ void ResourceGroupwareBase::slotDownloadJobResult( KPIM::GroupwareJob *job )
mIsShowingError = false;
} else {
kdDebug(5800) << "Successfully downloaded data" << endl;
-
+
clearChanges();
saveCache();
enableChangeNotification();
@@ -318,9 +318,9 @@ bool ResourceGroupwareBase::doSave()
// to upload only certain changes and discard the rest. This is
// particularly important for resources like the blogging resource,
// where uploading would mean a republication of the blog, not only
- // a modifications.
+ // a modifications.
if ( !confirmSave() ) return false;
-
+
mUploadJob = createUploadJob( adaptor() );
connect( mUploadJob, TQT_SIGNAL( result( KPIM::GroupwareJob * ) ),
TQT_SLOT( slotUploadJobResult( KPIM::GroupwareJob * ) ) );
@@ -331,20 +331,20 @@ bool ResourceGroupwareBase::doSave()
inc = addedIncidences();
for( it = inc.begin(); it != inc.end(); ++it ) {
- addedItems.append( adaptor()->newUploadItem( *it,
+ addedItems.append( adaptor()->newUploadItem( *it,
KPIM::GroupwareUploadItem::Added ) );
}
// TODO: Check if the item has changed on the server...
- // In particular, check if the version we based our change on is still current
+ // In particular, check if the version we based our change on is still current
// on the server
inc = changedIncidences();
for( it = inc.begin(); it != inc.end(); ++it ) {
- changedItems.append( adaptor()->newUploadItem( *it,
+ changedItems.append( adaptor()->newUploadItem( *it,
KPIM::GroupwareUploadItem::Changed ) );
}
inc = deletedIncidences();
for( it = inc.begin(); it != inc.end(); ++it ) {
- deletedItems.append( adaptor()->newUploadItem( *it,
+ deletedItems.append( adaptor()->newUploadItem( *it,
KPIM::GroupwareUploadItem::Deleted ) );
}
@@ -368,10 +368,10 @@ void ResourceGroupwareBase::slotUploadJobResult( KPIM::GroupwareJob *job )
mIsShowingError = false;
} else {
kdDebug(5800) << "Successfully uploaded data" << endl;
- /*
+ /*
* After the put the server might have expanded recurring events and will
* also change the uids of the uploaded events. Remove them from the cache
- * and get the fresh delta and download.
+ * and get the fresh delta and download.
*/
if ( !mDownloadJob ) {
diff --git a/kresources/newexchange/exchangeconvertercontact.cpp b/kresources/newexchange/exchangeconvertercontact.cpp
index 0764d3101..732c9db15 100644
--- a/kresources/newexchange/exchangeconvertercontact.cpp
+++ b/kresources/newexchange/exchangeconvertercontact.cpp
@@ -52,7 +52,7 @@ void ExchangeConverterContact::createRequest( TQDomDocument &doc, TQDomElement &
TQDomAttr att_cal = doc.createAttribute( "xmlns:cal" );
att_cal.setValue( "urn:schemas:calendar:" );
doc.documentElement().setAttributeNode( att_cal );
-
+
propertyDAV( "contentclass" );
propertyDAV( "getcontenttype" );
propertyNS( "http://schemas.microsoft.com/exchange/", "outlookmessageclass" );
@@ -160,10 +160,10 @@ void ExchangeConverterContact::createRequest( TQDomDocument &doc, TQDomElement &
#undef property
-bool ExchangeConverterContact::extractAddress( const TQDomElement &node,
+bool ExchangeConverterContact::extractAddress( const TQDomElement &node,
Addressee &addressee, int type,
- const TQString &street, const TQString &pobox, const TQString &location,
- const TQString &postalcode, const TQString &state, const TQString &country,
+ const TQString &street, const TQString &pobox, const TQString &location,
+ const TQString &postalcode, const TQString &state, const TQString &country,
const TQString &/*countycode*/ )
{
bool haveAddr = false;
@@ -206,13 +206,13 @@ bool ExchangeConverterContact::extractAddress( const TQDomElement &node,
/**
-For the complete list of Exchange <=> KABC field mappings see the file
+For the complete list of Exchange <=> KABC field mappings see the file
Person.mapping */
-bool ExchangeConverterContact::readAddressee( const TQDomElement &node, Addressee &addressee )
+bool ExchangeConverterContact::readAddressee( const TQDomElement &node, Addressee &addressee )
{
TQString tmpstr;
long tmplng;
-
+
// The UID is absolutely required!
if ( WebdavHandler::extractString( node, "uid", tmpstr ) ) {
addressee.setUid( tmpstr );
@@ -224,7 +224,7 @@ bool ExchangeConverterContact::readAddressee( const TQDomElement &node, Addresse
addressee.insertCustom( "KDEPIM-Exchange-Resource", "fingerprint", tmpstr );
if ( WebdavHandler::extractString( node, "href", tmpstr ) )
addressee.insertCustom( "KDEPIM-Exchange-Resource", "href", tmpstr );
-
+
/* KDE4: addressee does not have any creation or modification date :-(( */
/* KDE4: read-only not supported by libkabc */
@@ -232,16 +232,16 @@ bool ExchangeConverterContact::readAddressee( const TQDomElement &node, Addresse
if ( WebdavHandler::extractString( node, "fileas", tmpstr ) ||
WebdavHandler::extractString( node, "cn", tmpstr ) )
addressee.setFormattedName( tmpstr );
- if ( WebdavHandler::extractString( node, "givenName", tmpstr ) )
+ if ( WebdavHandler::extractString( node, "givenName", tmpstr ) )
addressee.setGivenName( tmpstr );
- if ( WebdavHandler::extractString( node, "middlename", tmpstr ) )
+ if ( WebdavHandler::extractString( node, "middlename", tmpstr ) )
addressee.setAdditionalName( tmpstr );
- if ( WebdavHandler::extractString( node, "sn", tmpstr ) )
+ if ( WebdavHandler::extractString( node, "sn", tmpstr ) )
addressee.setFamilyName( tmpstr );
//urn:schemas:contacts:initials not used -
- if ( WebdavHandler::extractString( node, "namesuffix", tmpstr ) )
+ if ( WebdavHandler::extractString( node, "namesuffix", tmpstr ) )
addressee.setSuffix( tmpstr );
- if ( WebdavHandler::extractString( node, "personaltitle", tmpstr ) )
+ if ( WebdavHandler::extractString( node, "personaltitle", tmpstr ) )
addressee.setPrefix( tmpstr );
// Role
@@ -249,31 +249,37 @@ bool ExchangeConverterContact::readAddressee( const TQDomElement &node, Addresse
addressee.setRole( tmpstr );
// Company-Related settings
- if ( WebdavHandler::extractString( node, "o", tmpstr ) )
+ if ( WebdavHandler::extractString( node, "o", tmpstr ) )
addressee.setOrganization( tmpstr );
- if ( WebdavHandler::extractString( node, "department", tmpstr ) )
+ if ( WebdavHandler::extractString( node, "department", tmpstr ) )
+ {
+#if KDE_IS_VERSION(3,5,8)
+ addressee.setDepartment( tmpstr );
+#else
addressee.insertCustom( "KADDRESSBOOK", "X-Department", tmpstr );
- if ( WebdavHandler::extractString( node, "roomnumber", tmpstr ) )
+#endif
+ }
+ if ( WebdavHandler::extractString( node, "roomnumber", tmpstr ) )
addressee.insertCustom( "KADDRESSBOOK", "X-Office", tmpstr );
- if ( WebdavHandler::extractString( node, "profession", tmpstr ) )
+ if ( WebdavHandler::extractString( node, "profession", tmpstr ) )
addressee.insertCustom( "KADDRESSBOOK", "X-Profession", tmpstr );
- if ( WebdavHandler::extractString( node, "manager", tmpstr ) )
+ if ( WebdavHandler::extractString( node, "manager", tmpstr ) )
addressee.insertCustom( "KADDRESSBOOK", "X-ManagersName", tmpstr );
- if ( WebdavHandler::extractString( node, "secretarycn", tmpstr ) )
+ if ( WebdavHandler::extractString( node, "secretarycn", tmpstr ) )
addressee.insertCustom( "KADDRESSBOOK", "X-AssistantsName", tmpstr );
// Web-Related settings
if ( WebdavHandler::extractString( node, "email1", tmpstr ) )
addressee.insertEmail( tmpstr, true );
- if ( WebdavHandler::extractString( node, "email2", tmpstr ) )
+ if ( WebdavHandler::extractString( node, "email2", tmpstr ) )
addressee.insertEmail( tmpstr );
- if ( WebdavHandler::extractString( node, "email3", tmpstr ) )
+ if ( WebdavHandler::extractString( node, "email3", tmpstr ) )
addressee.insertEmail( tmpstr );
-
+
// No kabc field for personalHomePage
- if ( WebdavHandler::extractString( node, "businesshomepage", tmpstr ) )
+ if ( WebdavHandler::extractString( node, "businesshomepage", tmpstr ) )
addressee.setUrl( tmpstr );
if ( WebdavHandler::extractString( node, "fburl", tmpstr ) ) {
@@ -284,14 +290,14 @@ bool ExchangeConverterContact::readAddressee( const TQDomElement &node, Addresse
// General stuff:
TQStringList tmplst;
- if ( WebdavHandler::extractStringList( node, "Keywords", tmplst ) )
+ if ( WebdavHandler::extractStringList( node, "Keywords", tmplst ) )
addressee.setCategories( tmplst );
// Exchange sentitivity values:
// 0 None, 1 Personal, 2 Private, 3 Company Confidential
if ( WebdavHandler::extractLong( node, "sensitivity", tmplng ) ) {
switch( tmplng ) {
case 0: addressee.setSecrecy( KABC::Secrecy::Public ); break;
- case 1:
+ case 1:
case 2: addressee.setSecrecy( KABC::Secrecy::Private ); break;
case 3: addressee.setSecrecy( KABC::Secrecy::Confidential ); break;
default: kdWarning() << "Unknown sensitivity: " << tmplng << endl;
@@ -322,39 +328,39 @@ bool ExchangeConverterContact::readAddressee( const TQDomElement &node, Addresse
insertPhone( "callbackphone", PhoneNumber::Msg );
insertPhone( "telexnumber", PhoneNumber::Bbs );
insertPhone( "ttytddphone", PhoneNumber::Pcs );
-#undef insertPhone
+#undef insertPhone
// Addresses: Work, Home, Mailing and Other:
extractAddress( node, addressee, Address::Work | Address::Pref,
"street", "postofficebox", "l", "postalcode", "st", "co", "c" );
extractAddress( node, addressee, Address::Home,
- "homeStreet", "homepostofficebox", "homeCity", "homePostalCode",
+ "homeStreet", "homepostofficebox", "homeCity", "homePostalCode",
"homeState", "homeCountry", "homeCountrycode" );
// Exchange doesn't support writing/changing the mailing address fields,
// so don't download it. It's equal to either the home or work address anyway
/* extractAddress( node, addressee, Address::Postal,
- "mailingstreet", "mailingpostofficebox", "mailingcity", "mailingpostalcode",
+ "mailingstreet", "mailingpostofficebox", "mailingcity", "mailingpostalcode",
"mailingstate", "mailingcountry", "mailingcountrycode" );*/
extractAddress( node, addressee, 0,
- "otherstreet", "otherpostofficebox", "othercity", "otherpostalcode",
+ "otherstreet", "otherpostofficebox", "othercity", "otherpostalcode",
"otherstate", "othercountry", "othercountrycode" );
- if ( WebdavHandler::extractString( node, "nickname", tmpstr ) )
+ if ( WebdavHandler::extractString( node, "nickname", tmpstr ) )
addressee.setNickName( tmpstr );
- if ( WebdavHandler::extractString( node, "spousecn", tmpstr ) )
+ if ( WebdavHandler::extractString( node, "spousecn", tmpstr ) )
addressee.insertCustom( "KADDRESSBOOK", "X-SpousesName", tmpstr );
TQDateTime tmpdt;
- if ( WebdavHandler::extractDateTime( node, "bday", tmpdt ) )
+ if ( WebdavHandler::extractDateTime( node, "bday", tmpdt ) )
addressee.setBirthday( tmpdt.date() );
- if ( WebdavHandler::extractString( node, "weddinganniversary", tmpstr ) )
+ if ( WebdavHandler::extractString( node, "weddinganniversary", tmpstr ) )
addressee.insertCustom( "KADDRESSBOOK", "X-Anniversary", tmpstr );
// TODO? timeZone()
float lt,lng;
- if ( WebdavHandler::extractFloat( node, "geolatitude", lt ) &&
+ if ( WebdavHandler::extractFloat( node, "geolatitude", lt ) &&
WebdavHandler::extractFloat( node, "geolongitude", lng ) )
addressee.setGeo( Geo( lt, lng ) );
// TODO: mapurl
@@ -363,7 +369,7 @@ bool ExchangeConverterContact::readAddressee( const TQDomElement &node, Addresse
if ( WebdavHandler::extractString( node, "textdescription", tmpstr ) )
addressee.setNote( tmpstr );
-// if ( WebdavHandler::extractString( node, "usercertificate", tmpstr ) )
+// if ( WebdavHandler::extractString( node, "usercertificate", tmpstr ) )
// addressee.setKeys()
return true;
@@ -380,24 +386,24 @@ Addressee::List ExchangeConverterContact::parseWebDAV( const TQDomDocument& davd
kdDebug()<<"ExchangeConverterContact::parseWebDAV, no response->propstat->prop element!"<<endl;
return list;
}
-
+
TQString contentclass;
bool success = WebdavHandler::extractString( prop, "contentclass", contentclass );
if ( !success ) {
kdDebug()<<"ExchangeConverterContact::parseWebDAV, No contentclass entry"<<endl;
return list;
}
-
+
success = false;
Addressee addressee;
if ( contentclass == "urn:content-classes:person" ) {
success = readAddressee( prop, addressee );
- }
-
+ }
+
if ( success ) {
list.append( addressee );
} else {
-
+
}
return list;
}
@@ -420,11 +426,11 @@ TQDomDocument ExchangeConverterContact::createWebDAV( Addressee addr )
TQDomElement root = WebdavHandler::addDavElement( doc, doc, "d:propertyupdate" );
TQDomElement set = WebdavHandler::addElement( doc, root, "d:set" );
TQDomElement prop = WebdavHandler::addElement( doc, set, "d:prop" );
-
+
TQDomAttr att_c = doc.createAttribute( "xmlns:c" );
att_c.setValue( "urn:schemas:contacts:" );
doc.documentElement().setAttributeNode( att_c );
-
+
TQDomAttr att_b = doc.createAttribute( "xmlns:b" );
att_b.setValue( "urn:schemas-microsoft-com:datatypes" );
root.setAttributeNode( att_b );
@@ -433,25 +439,29 @@ TQDomDocument ExchangeConverterContact::createWebDAV( Addressee addr )
domProperty( "http://schemas.microsoft.com/exchange/",
"outlookmessageclass", "IPM.Contact" );
// domContactProperty( "uid", addr.uid() );
-
+
domContactProperty( "fileas", addr.formattedName() );
domContactProperty( "givenName", addr.givenName() );
domContactProperty( "middlename", addr.additionalName() );
domContactProperty( "sn", addr.familyName() );
domContactProperty( "namesuffix", addr.suffix() );
domContactProperty( "personaltitle", addr.prefix() );
-
+
domContactProperty( "title", addr.role() );
domContactProperty( "o", addr.organization() );
+#if KDE_IS_VERSION(3,5,8)
+ domContactProperty( "department", addr.department() );
+#else
domContactProperty( "department", addr.custom( "KADDRESSBOOK", "X-Department" ) );
+#endif
domContactProperty( "roomnumber", addr.custom( "KADDRESSBOOK", "X-Office" ) );
domContactProperty( "profession", addr.custom( "KADDRESSBOOK", "X-Profession" ) );
domContactProperty( "manager", addr.custom( "KADDRESSBOOK", "X-ManagersName" ) );
domContactProperty( "secretarycn", addr.custom( "KADDRESSBOOK", "X-AssistantsName" ) );
-
+
TQStringList emails = addr.emails();
TQString prefemail = addr.preferredEmail();
- if ( emails.contains( prefemail ) )
+ if ( emails.contains( prefemail ) )
emails.remove( prefemail );
emails.prepend( prefemail );
if ( emails.count() > 0 ) {
@@ -463,10 +473,10 @@ TQDomDocument ExchangeConverterContact::createWebDAV( Addressee addr )
if ( emails.count() > 2 ) {
domContactProperty( "email3", emails[2] );
}
-
+
// No value for "personalHomePage"
domContactProperty( "businesshomepage", addr.url().url() );
-
+
TQString fburl = KCal::FreeBusyUrlStore::self()->readUrl( addr.preferredEmail() );
if ( !fburl.isEmpty() ) {
domContactProperty( "fburl", fburl );
@@ -475,16 +485,16 @@ TQDomDocument ExchangeConverterContact::createWebDAV( Addressee addr )
/* FIXME: This doesn't work!
TQStringList cats = addr.categories();
if ( cats.isEmpty() ) {
- TQDomElement catsnode = WebdavHandler::addElementNS( doc, prop,
+ TQDomElement catsnode = WebdavHandler::addElementNS( doc, prop,
"urn:schemas-microsoft-com:office:office", "Keywords" );
for ( TQStringList::Iterator it = cats.begin(); it != cats.end(); ++it ) {
WebdavHandler::addElementNS( doc, catsnode, "xml:", "v", *it );
}
} else {
-// TQDomElement catsnode = addProperty( doc, prop,
+// TQDomElement catsnode = addProperty( doc, prop,
// "urn:schemas-microsoft-com:office:office", "Keywords", "" );
}*/
-
+
// Exchange sentitivity values:
// 0 None, 1 Personal, 2 Private, 3 Company Confidential
TQString value;
@@ -517,7 +527,7 @@ TQDomDocument ExchangeConverterContact::createWebDAV( Addressee addr )
domPhoneProperty( "telexnumber", PhoneNumber::Bbs );
domPhoneProperty( "ttytddphone", PhoneNumber::Pcs );
-
+
// work address:
Address workaddr = addr.address( Address::Work | Address::Pref );
if ( !workaddr.isEmpty() ) {
@@ -541,7 +551,7 @@ TQDomDocument ExchangeConverterContact::createWebDAV( Addressee addr )
domContactProperty( "homeCountry", homeaddr.country() );
// domContactProperty( "homeCountrycode", homeaddr.countryCode() );
}
-
+
// mailing address:
// Exchange doesn't support writing/changing the mailing address fields
/* Address mailingaddr = addr.address( Address::Postal );
@@ -566,8 +576,8 @@ TQDomDocument ExchangeConverterContact::createWebDAV( Addressee addr )
domContactProperty( "othercountry", otheraddr.country() );
// domContactProperty( "othercountrycode", otheraddr.countryCode() );
}
-
-
+
+
domContactProperty( "nickname", addr.nickName() );
domContactProperty( "spousecn", addr.custom( "KADDRESSBOOK", "X-SpousesName" ) );
@@ -606,7 +616,7 @@ TQDomDocument ExchangeConverterContact::createWebDAV( Addressee addr )
// TODO:usercertificate
// TODO: custom fields
kdDebug()<<"DOM document: "<<doc.toString() << endl;
-
+
return doc;
}
#undef domDavProperty
diff --git a/kresources/newexchange/kabc_newexchange.desktop b/kresources/newexchange/kabc_newexchange.desktop
index b829ace7d..d48d30f29 100644
--- a/kresources/newexchange/kabc_newexchange.desktop
+++ b/kresources/newexchange/kabc_newexchange.desktop
@@ -20,7 +20,6 @@ Name[hu]=Exchange-kiszolgáló címjegyzéke (kísérleti)
Name[is]=Vistfangaskrá Exchange þjóni (á tilraunarstigi)
Name[it]=Rubrica indirizzi su un server Exchange (sperimentale)
Name[ja]=Exchange サーバのアドレス帳 (実験版)
-Name[ka]=წიგნაკი Exchange სერვერზე(ექსპერიმენტული)
Name[kk]=Exchange серверіндегі адрестік кітапша (сынақтағы)
Name[km]=សៀវភៅ​អាសយដ្ឋាន​លើ​ម៉ាស៊ីន​បម្រើ Exchange (សម្រាប់​អ្នក​មាន​បទពិសោធន៍)
Name[lt]=Adresų knygelė Exchange serveryje (eksperimentine tvarka)
diff --git a/kresources/newexchange/kabc_newexchange_final.desktop b/kresources/newexchange/kabc_newexchange_final.desktop
index 7069b14d8..19cdda43e 100644
--- a/kresources/newexchange/kabc_newexchange_final.desktop
+++ b/kresources/newexchange/kabc_newexchange_final.desktop
@@ -22,7 +22,6 @@ Name[hu]=Exchange-kiszolgáló címjegyzéke
Name[is]=Vistfangaskrá á Exchange þjóni
Name[it]=Rubrica indirizzi su un server Exchange
Name[ja]=Exchange サーバのアドレス帳
-Name[ka]=წიგნაკი Exchange სერვერზე
Name[kk]=Exchange серверіндегі адрестік кітапша
Name[km]=សៀវភៅ​អាសយដ្ឋាន​លើ​ម៉ាស៊ីន​បម្រើ Exchange
Name[lt]=Adresų knygelė Exchange serveryje
diff --git a/kresources/newexchange/kabc_resourceexchange.cpp b/kresources/newexchange/kabc_resourceexchange.cpp
index 8b32a4fac..7b08423a5 100644
--- a/kresources/newexchange/kabc_resourceexchange.cpp
+++ b/kresources/newexchange/kabc_resourceexchange.cpp
@@ -26,13 +26,19 @@
#include "groupwareuploadjob.h"
#include "kresources_groupwareprefs.h"
+#include <klocale.h>
+
using namespace KABC;
ResourceExchange::ResourceExchange( const KConfig *config )
: ResourceGroupwareBase( config )
{
init();
- if ( config ) readConfig( config );
+ if ( config ) {
+ readConfig( config );
+ } else {
+ setResourceName( i18n( "Exchange Server" ) );
+ }
}
void ResourceExchange::init()
diff --git a/kresources/newexchange/kcal_newexchange.desktop b/kresources/newexchange/kcal_newexchange.desktop
index b94e28ce9..a0dd29c1e 100644
--- a/kresources/newexchange/kcal_newexchange.desktop
+++ b/kresources/newexchange/kcal_newexchange.desktop
@@ -20,7 +20,6 @@ Name[hu]=Exchange 2000-kiszolgáló naptára (kísérleti)
Name[is]=Dagatal á Exchange þjóni (á tilraunarstigi)
Name[it]=Calendario su un server Exchange (sperimentale)
Name[ja]=Exchange サーバのカレンダー (実験版)
-Name[ka]=კალენდარი Exchange სერვერზე (ექსპერიმენტული)
Name[kk]=Exchange серверіндегі күнтізбе (сынақтағы)
Name[km]=ប្រតិទិន​លើ​ម៉ាស៊ីន​បម្រើ Exchange (សម្រាប់​អ្នក​មាន​បទពិសោធន៍)
Name[lt]=Kalendorius Exchange serveryje (eksperimentine tvarka)
diff --git a/kresources/newexchange/kcal_newexchange_final.desktop b/kresources/newexchange/kcal_newexchange_final.desktop
index fd159051d..01904c54a 100644
--- a/kresources/newexchange/kcal_newexchange_final.desktop
+++ b/kresources/newexchange/kcal_newexchange_final.desktop
@@ -22,7 +22,6 @@ Name[hu]=Exchange 2000-kiszolgáló naptára
Name[is]=Dagatal á Exchange þjóni
Name[it]=Calendario su un server Exchange
Name[ja]=Exchange サーバのカレンダー
-Name[ka]=კალენდარი Exchange სერვერზე
Name[kk]=Exchange серверіндегі күнтізбе
Name[km]=ប្រតិទិន​លើ​ម៉ាស៊ីន​បម្រើ Exchange
Name[lt]=Kalendorius Exchange serveryje
diff --git a/kresources/newexchange/kcal_resourceexchange.cpp b/kresources/newexchange/kcal_resourceexchange.cpp
index 4c9f7726d..37d99d376 100644
--- a/kresources/newexchange/kcal_resourceexchange.cpp
+++ b/kresources/newexchange/kcal_resourceexchange.cpp
@@ -25,6 +25,7 @@
#include <groupwaredownloadjob.h>
#include <groupwareuploadjob.h>
#include <kresources_groupwareprefs.h>
+#include <klocale.h>
using namespace KCal;
@@ -38,7 +39,11 @@ ResourceExchange::ResourceExchange( const KConfig *config )
: ResourceGroupwareBase( config )
{
init();
- if ( config ) readConfig( config );
+ if ( config ) {
+ readConfig( config );
+ } else {
+ setResourceName( i18n( "Exchange Server" ) );
+ }
}
void ResourceExchange::init()
diff --git a/kresources/remote/remote.desktop b/kresources/remote/remote.desktop
index 66a1542af..2ddebc7e4 100644
--- a/kresources/remote/remote.desktop
+++ b/kresources/remote/remote.desktop
@@ -24,7 +24,6 @@ Name[hu]=Távoli fájlban tárolt naptár
Name[is]=Dagatal í fjarlægri skrá
Name[it]=Calendario in file remoto
Name[ja]=リモートファイルのカレンダー
-Name[ka]=კალენდარი გარე ფაილზე
Name[kk]=Қашықтағы файлдағы күнтізбе
Name[km]=ប្រតិទិន​នៅ​ក្នុង​ឯកសារ​នៅ​ឆ្ងាយ
Name[lt]=Kalendorius nutolusioje byloje
diff --git a/kresources/remote/resourceremote.cpp b/kresources/remote/resourceremote.cpp
index 2aceaad0c..229dd86bf 100644
--- a/kresources/remote/resourceremote.cpp
+++ b/kresources/remote/resourceremote.cpp
@@ -56,6 +56,8 @@ ResourceRemote::ResourceRemote( const KConfig *config )
{
if ( config ) {
readConfig( config );
+ } else {
+ setResourceName( i18n( "Remote Calendar" ) );
}
init();
diff --git a/kresources/scalix/kcal/resourcescalix.cpp b/kresources/scalix/kcal/resourcescalix.cpp
index d2849e862..63e964eb9 100644
--- a/kresources/scalix/kcal/resourcescalix.cpp
+++ b/kresources/scalix/kcal/resourcescalix.cpp
@@ -510,6 +510,12 @@ bool ResourceScalix::addEvent( KCal::Event* event )
return addIncidence( event, TQString::null, 0 );
}
+bool ResourceScalix::addEvent( KCal::Event *event, const TQString &subresource )
+{
+ Q_UNUSED( subresource ); // ResourceScalix does not support subresources
+ return this->addEvent( event );
+}
+
bool ResourceScalix::deleteIncidence( KCal::Incidence* incidence )
{
if ( incidence->isReadOnly() ) return false;
@@ -572,6 +578,12 @@ bool ResourceScalix::addTodo( KCal::Todo* todo )
return addIncidence( todo, TQString::null, 0 );
}
+bool ResourceScalix::addTodo( KCal::Todo *todo, const TQString &subresource )
+{
+ Q_UNUSED( subresource ); // ResourceScalix does not support subresources
+ return this->addTodo( todo );
+}
+
bool ResourceScalix::deleteTodo( KCal::Todo* todo )
{
return deleteIncidence( todo );
@@ -600,6 +612,12 @@ bool ResourceScalix::addJournal( KCal::Journal* journal )
return addIncidence( journal, TQString::null, 0 );
}
+bool ResourceScalix::addJournal( KCal::Journal *journal, const TQString &subresource )
+{
+ Q_UNUSED( subresource ); // ResourceScalix does not support subresources
+ return this->addJournal( journal );
+}
+
bool ResourceScalix::deleteJournal( KCal::Journal* journal )
{
return deleteIncidence( journal );
diff --git a/kresources/scalix/kcal/resourcescalix.h b/kresources/scalix/kcal/resourcescalix.h
index 223161b4b..11baa5ec0 100644
--- a/kresources/scalix/kcal/resourcescalix.h
+++ b/kresources/scalix/kcal/resourcescalix.h
@@ -70,6 +70,7 @@ public:
// The libkcal functions. See the resource for descriptions
bool addEvent( KCal::Event* anEvent );
+ bool addEvent( KCal::Event* anEvent, const TQString &subresource );
bool deleteEvent( KCal::Event* );
KCal::Event* event( const TQString &UniqueStr );
KCal::Event::List rawEvents( EventSortField sortField = EventSortUnsorted, SortDirection sortDirection = SortDirectionAscending );
@@ -82,12 +83,14 @@ public:
bool inclusive = false );
bool addTodo( KCal::Todo* todo );
+ bool addTodo( KCal::Todo* todo, const TQString &subresource );
bool deleteTodo( KCal::Todo* );
KCal::Todo* todo( const TQString& uid );
KCal::Todo::List rawTodos( TodoSortField sortField = TodoSortUnsorted, SortDirection sortDirection = SortDirectionAscending );
KCal::Todo::List rawTodosForDate( const TQDate& date );
bool addJournal( KCal::Journal* );
+ bool addJournal( KCal::Journal* journal, const TQString &subresource );
bool deleteJournal( KCal::Journal* );
KCal::Journal* journal( const TQString& uid );
KCal::Journal::List rawJournals( JournalSortField sortField = JournalSortUnsorted, SortDirection sortDirection = SortDirectionAscending );
diff --git a/kresources/slox/kabc_ox.desktop b/kresources/slox/kabc_ox.desktop
index 4f4fb8c22..8388f0800 100644
--- a/kresources/slox/kabc_ox.desktop
+++ b/kresources/slox/kabc_ox.desktop
@@ -18,7 +18,6 @@ Name[gl]=Servidor OpenXchange
Name[hu]=OpenXchange-kiszolgáló
Name[is]=OpenXchange þjónn
Name[ja]=OpenXchange サーバ
-Name[ka]=Openexchange სერვერი
Name[kk]=OpenXchange сервері
Name[km]=ម៉ាស៊ីន​បម្រើ OpenXchange
Name[lt]=OpenXchange serveris
diff --git a/kresources/slox/kabc_slox.desktop b/kresources/slox/kabc_slox.desktop
index bdfce204e..5a0192caa 100644
--- a/kresources/slox/kabc_slox.desktop
+++ b/kresources/slox/kabc_slox.desktop
@@ -21,7 +21,6 @@ Name[hu]=SUSE LINUX Openexchange-kiszolgáló
Name[is]=SUSE LINUX Openexchange þjónn
Name[it]=Server SUSE LINUX Openexchange
Name[ja]=SUSE LINUX Openexchange サーバ
-Name[ka]= SUSE LINUX Openexchange სერვერი
Name[kk]=SUSE LINUX Openexchange сервері
Name[km]=ម៉ាស៊ីន​បម្រើ Openexchange របស់​ស៊ូស៊ីលីនីក
Name[lt]=SUSE LINUX Openexchange serveris
diff --git a/kresources/slox/kabcresourceslox.cpp b/kresources/slox/kabcresourceslox.cpp
index 757bfae08..16d5aced5 100644
--- a/kresources/slox/kabcresourceslox.cpp
+++ b/kresources/slox/kabcresourceslox.cpp
@@ -49,6 +49,8 @@ ResourceSlox::ResourceSlox( const KConfig *config )
if ( config ) {
readConfig( config );
+ } else {
+ setResourceName( i18n( "OpenXchange Server" ) );
}
}
@@ -353,7 +355,11 @@ void ResourceSlox::parseContactAttribute( const TQDomElement &e, Addressee &a )
} else if ( tag == fieldName( Organization ) ) {
a.setOrganization( text );
} else if ( tag == fieldName( Department ) ) {
+#if KDE_IS_VERSION(3,5,8)
+ a.setDepartment( text );
+#else
a.insertCustom( "KADDRESSBOOK", "X-Department", text );
+#endif
} else if ( tag == fieldName( FamilyName ) ) {
a.setFamilyName( text );
} else if ( tag == fieldName( GivenName) ) {
@@ -542,8 +548,13 @@ void ResourceSlox::createAddresseeFields( TQDomDocument &doc, TQDomElement &prop
else
WebdavHandler::addSloxElement( this, doc, prop, fieldName( Birthday ) );
WebdavHandler::addSloxElement( this, doc, prop, fieldName( Role ), a.role() );
+#if KDE_IS_VERSION(3,5,8)
+ WebdavHandler::addSloxElement( this, doc, prop, fieldName( Department ),
+ a.department( ) );
+#else
WebdavHandler::addSloxElement( this, doc, prop, fieldName( Department ),
a.custom( "KADDRESSBOOK", "X-Department" ) );
+#endif
if ( type() == "ox" ) { // OX only fields
WebdavHandler::addSloxElement( this, doc, prop, fieldName( DisplayName ), a.formattedName() );
WebdavHandler::addSloxElement( this, doc, prop, fieldName( SecondName ), a.additionalName() );
diff --git a/kresources/slox/kcal_ox.desktop b/kresources/slox/kcal_ox.desktop
index e0eaa9224..5bc7600ae 100644
--- a/kresources/slox/kcal_ox.desktop
+++ b/kresources/slox/kcal_ox.desktop
@@ -18,7 +18,6 @@ Name[gl]=Servidor OpenXchange
Name[hu]=OpenXchange-kiszolgáló
Name[is]=OpenXchange þjónn
Name[ja]=OpenXchange サーバ
-Name[ka]=Openexchange სერვერი
Name[kk]=OpenXchange сервері
Name[km]=ម៉ាស៊ីន​បម្រើ OpenXchange
Name[lt]=OpenXchange serveris
diff --git a/kresources/slox/kcal_slox.desktop b/kresources/slox/kcal_slox.desktop
index 0daca0b2c..b4fe8e7a8 100644
--- a/kresources/slox/kcal_slox.desktop
+++ b/kresources/slox/kcal_slox.desktop
@@ -21,7 +21,6 @@ Name[hu]=SUSE LINUX Openexchange-kiszolgáló
Name[is]=SUSE LINUX Openexchange þjónn
Name[it]=Server SUSE LINUX Openexchange
Name[ja]=SUSE LINUX Openexchange サーバ
-Name[ka]= SUSE LINUX Openexchange სერვერი
Name[kk]=SUSE LINUX Openexchange сервері
Name[km]=ម៉ាស៊ីន​បម្រើ Openexchange របស់​ស៊ូស៊ីលីនីក
Name[lt]=SUSE LINUX Openexchange serveris
diff --git a/kresources/slox/kcalresourceslox.cpp b/kresources/slox/kcalresourceslox.cpp
index 2fcb0baa3..edd13e6f9 100644
--- a/kresources/slox/kcalresourceslox.cpp
+++ b/kresources/slox/kcalresourceslox.cpp
@@ -70,6 +70,8 @@ KCalResourceSlox::KCalResourceSlox( const KConfig *config )
if ( config ) {
readConfig( config );
+ } else {
+ setResourceName( i18n( "OpenXchange Server" ) );
}
}
diff --git a/ktnef/gui/ktnef.desktop b/ktnef/gui/ktnef.desktop
index 58145acbe..fd31062b1 100644
--- a/ktnef/gui/ktnef.desktop
+++ b/ktnef/gui/ktnef.desktop
@@ -25,7 +25,6 @@ GenericName[hu]=TNEF-fájlnézegető
GenericName[is]=TNEF skráarskoðari
GenericName[it]=Visualizzatore file TNEF
GenericName[ja]=TNEF ファイルビュー
-GenericName[ka]=TNEF ფაილების დამთვალიერებელი
GenericName[kk]=TNEF файлды қарау құралы
GenericName[km]=កម្មវិធី​មើល​ឯកសារ TNEF
GenericName[lt]=TNEF bylų žiūryklė
@@ -78,7 +77,6 @@ Comment[hu]=Nézegetőprogram TNEF-fájlokhoz
Comment[is]=Sýnir/lesari fyrir TNEF skrár
Comment[it]=Un visualizzatore/estrattore di file TNEF
Comment[ja]=TNEF ファイルのためのビューア/展開ツール
-Comment[ka]= TNEF ფაილების ექსტრაქტორი/დამთვალიერებელი
Comment[kk]=TNEF файдарды қарау/тарқату
Comment[km]=កម្មវិធី​មើល និង​ស្រង់​ឯកសារ TNEF
Comment[lt]=TNEF bylų žiūryklė - išpakuotojas
diff --git a/ktnef/gui/ms-tnef.desktop b/ktnef/gui/ms-tnef.desktop
index 309bd8cf5..81f71e514 100644
--- a/ktnef/gui/ms-tnef.desktop
+++ b/ktnef/gui/ms-tnef.desktop
@@ -31,7 +31,6 @@ Comment[hu]=TNEF-fájl
Comment[is]=TNEF skrá
Comment[it]=File TNEF
Comment[ja]=TNEF ファイル
-Comment[ka]=TNEF ფაილი
Comment[kk]=TNEF файлы
Comment[km]=ឯកសារ TNEF
Comment[lt]=TNEF byla
@@ -56,7 +55,6 @@ Comment[ta]=TNEF கோப்பு
Comment[tg]=Файли TNEF
Comment[tr]=TNEF Dosyası
Comment[uk]=Файл TNEF
-Comment[uz]=TNEF-fayli
-Comment[uz@cyrillic]=TNEF-файли
+Comment[uz]=TNEF-файли
Comment[zh_CN]=TNEF 文件
Comment[zh_TW]=TNEF 檔案
diff --git a/libemailfunctions/email.cpp b/libemailfunctions/email.cpp
index b5148736f..0f6b83617 100644
--- a/libemailfunctions/email.cpp
+++ b/libemailfunctions/email.cpp
@@ -685,7 +685,7 @@ bool KPIM::getNameAndMail(const TQString& aStr, TQString& name, TQString& mail)
}else if( bInQuotesOutsideOfEmail ){
if( cQuotes == c )
bInQuotesOutsideOfEmail = false;
- else
+ else if ( c != '\\' )
name.prepend( c );
}else{
// found the start of this addressee ?
@@ -695,8 +695,9 @@ bool KPIM::getNameAndMail(const TQString& aStr, TQString& name, TQString& mail)
if( iMailStart ){
if( cQuotes == c )
bInQuotesOutsideOfEmail = true; // end of quoted text found
- else
+ else {
name.prepend( c );
+ }
}else{
switch( c ){
case '<':
@@ -751,7 +752,7 @@ bool KPIM::getNameAndMail(const TQString& aStr, TQString& name, TQString& mail)
}else if( bInQuotesOutsideOfEmail ){
if( cQuotes == c )
bInQuotesOutsideOfEmail = false;
- else
+ else if ( c != '\\' )
name.append( c );
}else{
// found the end of this addressee ?
@@ -809,16 +810,22 @@ TQString KPIM::normalizedAddress( const TQString & displayName,
const TQString & addrSpec,
const TQString & comment )
{
- if ( displayName.isEmpty() && comment.isEmpty() )
+ TQString realDisplayName = displayName;
+ realDisplayName.remove( TQChar( 0x202D ) );
+ realDisplayName.remove( TQChar( 0x202E ) );
+ realDisplayName.remove( TQChar( 0x202A ) );
+ realDisplayName.remove( TQChar( 0x202B ) );
+
+ if ( realDisplayName.isEmpty() && comment.isEmpty() )
return addrSpec;
else if ( comment.isEmpty() )
- return quoteNameIfNecessary( displayName ) + " <" + addrSpec + ">";
- else if ( displayName.isEmpty() ) {
+ return quoteNameIfNecessary( realDisplayName ) + " <" + addrSpec + ">";
+ else if ( realDisplayName.isEmpty() ) {
TQString commentStr = comment;
return quoteNameIfNecessary( commentStr ) + " <" + addrSpec + ">";
}
else
- return displayName + " (" + comment + ") <" + addrSpec + ">";
+ return realDisplayName + " (" + comment + ") <" + addrSpec + ">";
}
diff --git a/libkcal/Makefile.am b/libkcal/Makefile.am
index f76d32044..2fa8c2889 100644
--- a/libkcal/Makefile.am
+++ b/libkcal/Makefile.am
@@ -10,15 +10,17 @@ libkcal_la_LDFLAGS = $(all_libraries) -no-undefined -version-info 2:0:0 $(LIB_QT
libkcal_la_LIBADD = versit/libversit.la $(LIB_KIO) \
-lical -licalss \
$(top_builddir)/ktnef/lib/libktnef.la \
+ ../libkmime/libkmime.la \
../libemailfunctions/libemailfunctions.la \
-lkresources -lkabc
libkcal_la_SOURCES = \
+ assignmentvisitor.cpp comparisonvisitor.cpp \
incidencebase.cpp incidence.cpp journal.cpp todo.cpp event.cpp \
freebusy.cpp attendee.cpp attachment.cpp recurrencerule.cpp recurrence.cpp alarm.cpp \
customproperties.cpp calendar.cpp calendarlocal.cpp \
calformat.cpp vcalformat.cpp icalformat.cpp icalformatimpl.cpp \
- incidenceformatter.cpp \
+ incidenceformatter.cpp calhelper.cpp calselectdialog.cpp \
vcaldrag.cpp icaldrag.cpp \
exceptions.cpp \
scheduler.cpp imipscheduler.cpp dummyscheduler.cpp \
@@ -34,18 +36,20 @@ libkcal_la_SOURCES = \
qtopiaformat.cpp \
htmlexportsettings.kcfgc htmlexport.cpp calendarnull.cpp \
freebusyurlstore.cpp \
- confirmsavedialog.cpp
+ confirmsavedialog.cpp \
+ attachmenthandler.cpp
libkcalincludedir = $(includedir)/libkcal
libkcalinclude_HEADERS = alarm.h attachment.h attendee.h calendar.h \
calendarlocal.h calendarnull.h calendarresources.h calfilter.h calformat.h \
calstorage.h customproperties.h dndfactory.h duration.h event.h \
exceptions.h filestorage.h freebusy.h htmlexportsettings.h htmlexport.h icaldrag.h icalformat.h \
- incidencebase.h incidence.h incidenceformatter.h journal.h kcalversion.h listbase.h period.h person.h \
+ incidencebase.h incidence.h incidenceformatter.h calhelper.h calselectdialog.h \
+ journal.h kcalversion.h listbase.h period.h person.h \
qtopiaformat.h recurrencerule.h recurrence.h resourcecached.h resourcecalendar.h \
resourcelocalconfig.h resourcelocaldirconfig.h resourcelocaldir.h \
resourcelocal.h scheduler.h libkcal_export.h \
- todo.h vcaldrag.h vcalformat.h
+ todo.h vcaldrag.h vcalformat.h attachmenthandler.h
kde_module_LTLIBRARIES = kcal_local.la kcal_localdir.la
diff --git a/libkcal/alarm.cpp b/libkcal/alarm.cpp
index b5b9b515a..8bc40f001 100644
--- a/libkcal/alarm.cpp
+++ b/libkcal/alarm.cpp
@@ -47,6 +47,30 @@ Alarm::~Alarm()
{
}
+Alarm *Alarm::clone()
+{
+ return new Alarm( *this );
+}
+
+Alarm &Alarm::operator=( const Alarm &a )
+{
+ mParent = a.mParent;
+ mType = a.mType;
+ mDescription = a.mDescription;
+ mFile = a.mFile;
+ mMailAttachFiles = a.mMailAttachFiles;
+ mMailAddresses = a.mMailAddresses;
+ mMailSubject = a.mMailSubject;
+ mAlarmSnoozeTime = a.mAlarmSnoozeTime;
+ mAlarmRepeatCount = a.mAlarmRepeatCount;
+ mAlarmTime = a.mAlarmTime;
+ mOffset = a.mOffset;
+ mEndOffset = a.mEndOffset;
+ mHasTime = a.mHasTime;
+ mAlarmEnabled = a.mAlarmEnabled;
+ return *this;
+}
+
bool Alarm::operator==( const Alarm& rhs ) const
{
if ( mType != rhs.mType ||
@@ -304,19 +328,22 @@ void Alarm::setTime(const TQDateTime &alarmTime)
TQDateTime Alarm::time() const
{
- if ( hasTime() )
+ if ( hasTime() ) {
return mAlarmTime;
- else if ( mParent )
- {
- if (mParent->type()=="Todo") {
- Todo *t = static_cast<Todo*>(mParent);
- return mOffset.end( t->dtDue() );
- } else if (mEndOffset) {
- return mOffset.end( mParent->dtEnd() );
+ } else if ( mParent ) {
+ if ( mEndOffset ) {
+ if ( mParent->type() == "Todo" ) {
+ Todo *t = static_cast<Todo*>( mParent );
+ return mOffset.end( t->dtDue() );
+ } else {
+ return mOffset.end( mParent->dtEnd() );
+ }
} else {
return mOffset.end( mParent->dtStart() );
}
- } else return TQDateTime();
+ } else {
+ return TQDateTime();
+ }
}
bool Alarm::hasTime() const
@@ -324,15 +351,15 @@ bool Alarm::hasTime() const
return mHasTime;
}
-void Alarm::setSnoozeTime(int alarmSnoozeTime)
+void Alarm::setSnoozeTime(const Duration &alarmSnoozeTime)
{
- if (alarmSnoozeTime > 0) {
+ if (alarmSnoozeTime.value() > 0) {
mAlarmSnoozeTime = alarmSnoozeTime;
if ( mParent ) mParent->updated();
}
}
-int Alarm::snoozeTime() const
+Duration Alarm::snoozeTime() const
{
return mAlarmSnoozeTime;
}
@@ -348,9 +375,10 @@ int Alarm::repeatCount() const
return mAlarmRepeatCount;
}
-int Alarm::duration() const
+Duration Alarm::duration() const
{
- return mAlarmRepeatCount * mAlarmSnoozeTime * 60;
+ return Duration( mAlarmSnoozeTime.value() * mAlarmRepeatCount,
+ mAlarmSnoozeTime.type() );
}
TQDateTime Alarm::nextRepetition(const TQDateTime& preTime) const
@@ -422,7 +450,7 @@ void Alarm::setStartOffset( const Duration &offset )
Duration Alarm::startOffset() const
{
- return (mHasTime || mEndOffset) ? 0 : mOffset;
+ return (mHasTime || mEndOffset) ? Duration( 0 ) : mOffset;
}
bool Alarm::hasStartOffset() const
@@ -445,7 +473,7 @@ void Alarm::setEndOffset( const Duration &offset )
Duration Alarm::endOffset() const
{
- return (mHasTime || !mEndOffset) ? 0 : mOffset;
+ return (mHasTime || !mEndOffset) ? Duration( 0 ) : mOffset;
}
void Alarm::setParent( Incidence *parent )
diff --git a/libkcal/alarm.h b/libkcal/alarm.h
index 7d82cf65d..893e7be41 100644
--- a/libkcal/alarm.h
+++ b/libkcal/alarm.h
@@ -2,6 +2,7 @@
This file is part of libkcal.
Copyright (c) 2001-2003 Cornelius Schumacher <schumacher@kde.org>
+ Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -58,6 +59,18 @@ class LIBKCAL_EXPORT Alarm : public CustomProperties
~Alarm();
/**
+ Returns an exact copy of this alarm. The returned object is owned by the caller.
+ @since 4.5
+ */
+ Alarm *clone();
+
+ /**
+ Copy operator.
+ @since 4.5
+ */
+ Alarm &operator=( const Alarm & );
+
+ /**
Compare this alarm with another one.
*/
bool operator==( const Alarm & ) const;
@@ -67,10 +80,11 @@ class LIBKCAL_EXPORT Alarm : public CustomProperties
Set the type of the alarm.
If the specified type is different from the current type of the alarm,
the alarm's type-specific properties are initialised to null.
-
+
@param type type of alarm.
*/
void setType( Type type );
+
/**
Return the type of the alarm.
*/
@@ -78,15 +92,17 @@ class LIBKCAL_EXPORT Alarm : public CustomProperties
/**
Set the alarm to be a display alarm.
-
+
@param text text to display when the alarm is triggered.
*/
void setDisplayAlarm( const TQString &text = TQString::null );
+
/**
Set the text to be displayed when the alarm is triggered.
Ignored if the alarm is not a display alarm.
*/
void setText( const TQString &text );
+
/**
Return the text string that displays when the alarm is triggered.
*/
@@ -94,7 +110,7 @@ class LIBKCAL_EXPORT Alarm : public CustomProperties
/**
Set the alarm to be an audio alarm.
-
+
@param audioFile optional file to play when the alarm is triggered.
*/
void setAudioAlarm( const TQString &audioFile = TQString::null );
@@ -105,14 +121,14 @@ class LIBKCAL_EXPORT Alarm : public CustomProperties
void setAudioFile( const TQString &audioFile );
/**
Return the name of the audio file for the alarm.
-
+
@return The audio file for the alarm, or TQString::null if not an audio alarm.
*/
TQString audioFile() const;
/**
Set the alarm to be a procedure alarm.
-
+
@param programFile program to execute when the alarm is triggered.
@param arguments arguments to supply to programFile.
*/
@@ -125,7 +141,7 @@ class LIBKCAL_EXPORT Alarm : public CustomProperties
void setProgramFile( const TQString &programFile );
/**
Return the name of the program file to execute when the alarm is triggered.
-
+
@return the program file name, or TQString::null if not a procedure alarm.
*/
TQString programFile() const;
@@ -136,14 +152,14 @@ class LIBKCAL_EXPORT Alarm : public CustomProperties
void setProgramArguments( const TQString &arguments );
/**
Return the arguments to the program to run when the alarm is triggered.
-
+
@return the program arguments, or TQString::null if not a procedure alarm.
*/
TQString programArguments() const;
/**
Set the alarm to be an email alarm.
-
+
@param subject subject line of email.
@param text body of email.
@param addressees email addresses of recipient(s).
@@ -210,7 +226,7 @@ class LIBKCAL_EXPORT Alarm : public CustomProperties
void setMailText( const TQString &text );
/**
Return the email body text.
-
+
@return the body text, or TQString::null if not an email alarm.
*/
TQString mailText() const;
@@ -267,17 +283,17 @@ class LIBKCAL_EXPORT Alarm : public CustomProperties
/**
Set the interval between snoozes for the alarm.
-
+
@param alarmSnoozeTime the time in minutes between snoozes.
*/
- void setSnoozeTime( int alarmSnoozeTime );
+ void setSnoozeTime( const Duration &alarmSnoozeTime );
/**
Get how long the alarm snooze interval is.
-
+
@return the number of minutes between snoozes.
*/
- int snoozeTime() const;
+ Duration snoozeTime() const;
/**
Set how many times an alarm is to repeat itself after its initial
@@ -308,7 +324,7 @@ class LIBKCAL_EXPORT Alarm : public CustomProperties
Get how long between the alarm's initial occurrence and its final repetition.
@return the number of seconds between the initial occurrence and final repetition.
*/
- int duration() const;
+ Duration duration() const;
/**
Toggles the value of alarm to be either on or off.
@@ -350,8 +366,8 @@ class LIBKCAL_EXPORT Alarm : public CustomProperties
TQValueList<Person> mMailAddresses; // who to mail for reminder
TQString mMailSubject; // subject of email
- int mAlarmSnoozeTime; // number of minutes after alarm to
- // snooze before ringing again
+ Duration mAlarmSnoozeTime; // how long after alarm to snooze before
+ // triggering again
int mAlarmRepeatCount; // number of times for alarm to repeat
// after the initial time
diff --git a/libkcal/assignmentvisitor.cpp b/libkcal/assignmentvisitor.cpp
new file mode 100644
index 000000000..023df8572
--- /dev/null
+++ b/libkcal/assignmentvisitor.cpp
@@ -0,0 +1,123 @@
+/*
+ Copyright (c) 2009 Kevin Krammer <kevin.krammer@gmx.at>
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+#include "assignmentvisitor.h"
+
+#include "event.h"
+#include "freebusy.h"
+#include "journal.h"
+#include "todo.h"
+
+#include <kdebug.h>
+
+using namespace KCal;
+
+class AssignmentVisitor::Private
+{
+ public:
+ Private() : mSource( 0 ) {}
+
+ public:
+ const IncidenceBase *mSource;
+};
+
+AssignmentVisitor::AssignmentVisitor() : d( new Private() )
+{
+}
+
+AssignmentVisitor::~AssignmentVisitor()
+{
+ delete d;
+}
+
+bool AssignmentVisitor::assign( IncidenceBase *target, const IncidenceBase *source )
+{
+ Q_ASSERT( target != 0 );
+ Q_ASSERT( source != 0 );
+
+ d->mSource = source;
+
+ bool result = target->accept( *this );
+
+ d->mSource = 0;
+
+ return result;
+}
+
+bool AssignmentVisitor::visit( Event *event )
+{
+ Q_ASSERT( event != 0 );
+
+ const Event *source = dynamic_cast<const Event*>( d->mSource );
+ if ( source == 0 ) {
+ kdError(5800) << "Type mismatch: source is" << d->mSource->type()
+ << "target is" << event->type();
+ return false;
+ }
+
+ *event = *source;
+ return true;
+}
+
+bool AssignmentVisitor::visit( Todo *todo )
+{
+ Q_ASSERT( todo != 0 );
+
+ const Todo *source = dynamic_cast<const Todo*>( d->mSource );
+ if ( source == 0 ) {
+ kdError(5800) << "Type mismatch: source is" << d->mSource->type()
+ << "target is" << todo->type();
+ return false;
+ }
+
+ *todo = *source;
+ return true;
+}
+
+bool AssignmentVisitor::visit( Journal *journal )
+{
+ Q_ASSERT( journal != 0 );
+
+ const Journal *source = dynamic_cast<const Journal*>( d->mSource );
+ if ( source == 0 ) {
+ kdError(5800) << "Type mismatch: source is" << d->mSource->type()
+ << "target is" << journal->type();
+ return false;
+ }
+
+ *journal = *source;
+ return true;
+}
+
+bool AssignmentVisitor::visit( FreeBusy *freebusy )
+{
+ Q_ASSERT( freebusy != 0 );
+
+ const FreeBusy *source = dynamic_cast<const FreeBusy*>( d->mSource );
+ if ( source == 0 ) {
+ kdError(5800) << "Type mismatch: source is" << d->mSource->type()
+ << "target is" << freebusy->type();
+ return false;
+ }
+
+ *freebusy = *source;
+ return true;
+}
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/libkcal/assignmentvisitor.h b/libkcal/assignmentvisitor.h
new file mode 100644
index 000000000..2be0215cc
--- /dev/null
+++ b/libkcal/assignmentvisitor.h
@@ -0,0 +1,122 @@
+/*
+ Copyright (c) 2009 Kevin Krammer <kevin.krammer@gmx.at>
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+#ifndef KCAL_ASSIGNMENTVISITOR_H
+#define KCAL_ASSIGNMENTVISITOR_H
+
+#include "incidencebase.h"
+
+namespace KCal {
+
+/**
+ Helper for type correct assignment of incidences via pointers.
+
+ This class provides a way of correctly assigning one incidence to another,
+ given two IncidenceBase derived pointers. It effectively provides a virtual
+ assignment method which first type checks the two pointers to ensure they
+ reference the same incidence type, before performing the assignment.
+
+ Usage example:
+ @code
+ KCal::Incidence *currentIncidence; // assume this is set somewhere else
+ KCal::Incidence *updatedIncidence; // assume this is set somewhere else
+
+ KCal::AssignmentVisitor visitor;
+
+ // assign
+ if ( !visitor.assign(currentIncidence, updatedIncidence) ) {
+ // not of same type
+ }
+ @endcode
+
+ @author Kevin Krammer \<kevin.krammer@gmx.at\>
+ */
+class AssignmentVisitor : public IncidenceBase::Visitor
+{
+ public:
+ /**
+ Creates a visitor instance.
+ */
+ AssignmentVisitor();
+
+ /**
+ Destroys the instance.
+ */
+ virtual ~AssignmentVisitor();
+
+ /**
+ Assigns the incidence referenced by @p source to the incidence referenced
+ by @p target, first ensuring that the @p source incidence can be cast to
+ the same class as the @p target incidence.
+
+ Basically it is a virtual equivalent of
+ @code
+ *target = *source
+ @endcode
+
+ @param target pointer to the instance to assign to
+ @param source pointer to the instance to assign from
+
+ @return @c false if the two objects are of different type
+ */
+ bool assign( IncidenceBase *target, const IncidenceBase *source );
+
+ /**
+ Tries to assign to the given @p event, using the source passed to
+ assign().
+
+ @return @c false if the source passed to assign() is not an Event
+ */
+ virtual bool visit( Event *event );
+
+ /**
+ Tries to assign to the given @p todo, using the source passed to
+ assign().
+
+ @return @c false if the source passed to assign() is not a Todo
+ */
+ virtual bool visit( Todo *todo );
+
+ /**
+ Tries to assign to the given @p journal, using the source passed to
+ assign().
+
+ @return @c false if the source passed to assign() is not a Journal
+ */
+ virtual bool visit( Journal *journal );
+
+ /**
+ Tries to assign to the given @p freebusy, using the source passed to
+ assign().
+
+ @return @c false if the source passed to assign() is not a FreeBusy
+ */
+ virtual bool visit( FreeBusy *freebusy );
+
+ private:
+ //@cond PRIVATE
+ class Private;
+ Private *const d;
+ //@endcond
+};
+
+}
+
+#endif
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/libkcal/attachment.cpp b/libkcal/attachment.cpp
index fc319b735..51858161c 100644
--- a/libkcal/attachment.cpp
+++ b/libkcal/attachment.cpp
@@ -20,34 +20,46 @@
*/
#include "attachment.h"
+#include <kmdcodec.h>
using namespace KCal;
-Attachment::Attachment( const Attachment &attachment)
+Attachment::Attachment( const Attachment &attachment )
{
+ mSize = attachment.mSize;
mMimeType = attachment.mMimeType;
- mData = attachment.mData;
+ mUri = attachment.mUri;
+ mData = qstrdup( attachment.mData );
+ mLabel = attachment.mLabel;
mBinary = attachment.mBinary;
- mShowInline = attachment.mShowInline;
- mLabel = attachment.mLabel;
+ mLocal = attachment.mLocal;
+ mShowInline = attachment.mShowInline;
}
-Attachment::Attachment(const TQString& uri, const TQString& mime)
+Attachment::Attachment( const TQString &uri, const TQString &mime )
{
+ mSize = 0;
mMimeType = mime;
- mData = uri;
+ mUri = uri;
+ mData = 0;
mBinary = false;
- mShowInline = false;
- mLabel = TQString::null;
+ mLocal = false;
+ mShowInline = false;
}
-Attachment::Attachment(const char *base64, const TQString& mime)
+Attachment::Attachment( const char *base64, const TQString &mime )
{
+ mSize = 0;
mMimeType = mime;
- mData = TQString::fromUtf8(base64);
+ mData = qstrdup( base64 );
mBinary = true;
- mShowInline = false;
- mLabel = TQString::null;
+ mLocal = false;
+ mShowInline = false;
+}
+
+Attachment::~Attachment()
+{
+ delete[] mData;
}
bool Attachment::isUri() const
@@ -57,15 +69,16 @@ bool Attachment::isUri() const
TQString Attachment::uri() const
{
- if (!mBinary)
- return mData;
- else
+ if ( !mBinary ) {
+ return mUri;
+ } else {
return TQString::null;
+ }
}
-void Attachment::setUri(const TQString& uri)
+void Attachment::setUri( const TQString &uri )
{
- mData = uri;
+ mUri = uri;
mBinary = false;
}
@@ -76,17 +89,60 @@ bool Attachment::isBinary() const
char *Attachment::data() const
{
- if (mBinary)
- // this method actually return a const char*, but that can't be done because of the uneededly non-const libical API
- return const_cast<char*>( mData.latin1() ); //mData.utf8().data();
- else
+ if ( mBinary ) {
+ return mData;
+ } else {
return 0;
+ }
+}
+
+TQByteArray &Attachment::decodedData()
+{
+ if ( mDataCache.isNull() && mData ) {
+ // base64Decode() sometimes appends a null byte when called
+ // with a TQCString so work on TQByteArray's instead
+ TQByteArray encoded;
+ encoded.duplicate( mData, strlen( mData ) );
+ TQByteArray decoded;
+ KCodecs::base64Decode( encoded, decoded );
+ mDataCache = decoded;
+ }
+
+ return mDataCache;
}
-void Attachment::setData(const char *base64)
+void Attachment::setDecodedData( const TQByteArray &data )
{
- mData = TQString::fromUtf8(base64);
+ TQByteArray encoded;
+ KCodecs::base64Encode( data, encoded );
+
+ encoded.resize( encoded.count() + 1 );
+ encoded[encoded.count()-1] = '\0';
+
+ setData( encoded.data() );
+ mDataCache = data;
+ mSize = mDataCache.size();
+}
+
+void Attachment::setData( const char *base64 )
+{
+ delete[] mData;
+ mData = qstrdup( base64 );
mBinary = true;
+ mDataCache = TQByteArray();
+ mSize = 0;
+}
+
+uint Attachment::size()
+{
+ if ( isUri() ) {
+ return 0;
+ }
+ if ( !mSize ) {
+ mSize = decodedData().size();
+ }
+
+ return mSize;
}
TQString Attachment::mimeType() const
@@ -119,3 +175,12 @@ void Attachment::setLabel( const TQString& label )
mLabel = label;
}
+bool Attachment::isLocal() const
+{
+ return mLocal;
+}
+
+void Attachment::setLocal( bool local )
+{
+ mLocal = local;
+}
diff --git a/libkcal/attachment.h b/libkcal/attachment.h
index 416701850..7727a5c69 100644
--- a/libkcal/attachment.h
+++ b/libkcal/attachment.h
@@ -38,14 +38,14 @@ class KDE_EXPORT Attachment
/**
Create a Reference to some URI by copying an existing Attachment.
-
+
@param attachment the attachment to be duplicated
*/
Attachment( const Attachment &attachment );
/**
Create a Reference to some URI.
-
+
@param uri the uri this attachment refers to
@param mime the mime type of the resource being linked to
*/
@@ -53,39 +53,66 @@ class KDE_EXPORT Attachment
/**
Create a binary attachment.
-
+
@param base64 the attachment in base64 format
@param mime the mime type of the attachment
*/
Attachment( const char *base64, const TQString &mime = TQString::null );
+ ~Attachment();
+
/* The VALUE parameter in iCal */
bool isUri() const;
TQString uri() const;
void setUri( const TQString &uri );
-
+
bool isBinary() const;
char *data() const;
void setData( const char *base64 );
+ void setDecodedData( const TQByteArray &data );
+ TQByteArray &decodedData();
+
+ uint size();
+
/* The optional FMTTYPE parameter in iCal */
TQString mimeType() const;
void setMimeType( const TQString &mime );
-
- /* The custom X-CONTENT-DISPOSITION parameter, used by OGo etc. */
- bool showInline() const;
- void setShowInline( bool showinline );
-
- /* The custom X-LABEL parameter to show a human-readable title */
- TQString label() const;
- void setLabel( const TQString &label );
+
+ /* The custom X-CONTENT-DISPOSITION parameter, used by OGo etc. */
+ bool showInline() const;
+ void setShowInline( bool showinline );
+
+ /* The custom X-LABEL parameter to show a human-readable title */
+ TQString label() const;
+ void setLabel( const TQString &label );
+
+ /**
+ Sets the attachment "local" option, which is derived from the
+ Calendar Incidence @b X-KONTACT-TYPE parameter.
+
+ @param local is the flag to set (true) or unset (false) for the
+ attachment "local" option.
+
+ @see local()
+ */
+ void setLocal( bool local );
+
+ /**
+ Returns the attachment "local" flag.
+ */
+ bool isLocal() const;
private:
+ TQByteArray mDataCache;
+ uint mSize;
TQString mMimeType;
- TQString mData;
+ TQString mUri;
+ char *mData;
+ TQString mLabel;
bool mBinary;
- bool mShowInline;
- TQString mLabel;
+ bool mLocal;
+ bool mShowInline;
class Private;
Private *d;
diff --git a/libkcal/attachmenthandler.cpp b/libkcal/attachmenthandler.cpp
new file mode 100644
index 000000000..3163def07
--- /dev/null
+++ b/libkcal/attachmenthandler.cpp
@@ -0,0 +1,258 @@
+/*
+ This file is part of the kcal library.
+
+ Copyright (c) 2010 Klar�lvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
+
+ 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+/**
+ @file
+ This file is part of the API for handling calendar data and provides
+ static functions for dealing with calendar incidence attachments.
+
+ @brief
+ vCalendar/iCalendar attachment handling.
+
+ @author Allen Winter \<winter@kde.org\>
+*/
+#include "attachmenthandler.h"
+#include "attachment.h"
+#include "calendarresources.h"
+#include "incidence.h"
+#include "scheduler.h"
+
+#include <kapplication.h>
+#include <kfiledialog.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kmimetype.h>
+#include <krun.h>
+#include <ktempfile.h>
+#include <kio/netaccess.h>
+
+#include <tqfile.h>
+
+namespace KCal {
+
+Attachment *AttachmentHandler::find( TQWidget *parent, const TQString &attachmentName,
+ Incidence *incidence )
+{
+ if ( !incidence ) {
+ return 0;
+ }
+
+ // get the attachment by name from the incidence
+ Attachment::List as = incidence->attachments();
+ Attachment *a = 0;
+ if ( as.count() > 0 ) {
+ Attachment::List::ConstIterator it;
+ for ( it = as.begin(); it != as.end(); ++it ) {
+ if ( (*it)->label() == attachmentName ) {
+ a = *it;
+ break;
+ }
+ }
+ }
+
+ if ( !a ) {
+ KMessageBox::error(
+ parent,
+ i18n( "No attachment named \"%1\" found in the incidence." ).arg( attachmentName ) );
+ return 0;
+ }
+
+ if ( a->isUri() ) {
+ if ( !KIO::NetAccess::exists( a->uri(), true, parent ) ) {
+ KMessageBox::sorry(
+ parent,
+ i18n( "The attachment \"%1\" is a web link that is inaccessible from this computer. " ).
+ arg( KURL::decode_string( a->uri() ) ) );
+ return 0;
+ }
+ }
+ return a;
+}
+
+Attachment *AttachmentHandler::find( TQWidget *parent,
+ const TQString &attachmentName, const TQString &uid )
+{
+ if ( uid.isEmpty() ) {
+ return 0;
+ }
+
+ CalendarResources *cal = new CalendarResources( "UTC" );
+ cal->readConfig();
+ cal->load();
+ Incidence *incidence = cal->incidence( uid );
+ if ( !incidence ) {
+ KMessageBox::error(
+ parent,
+ i18n( "The incidence that owns the attachment named \"%1\" could not be found. "
+ "Perhaps it was removed from your calendar?" ).arg( attachmentName ) );
+ return 0;
+ }
+
+ return find( parent, attachmentName, incidence );
+}
+
+Attachment *AttachmentHandler::find( TQWidget *parent, const TQString &attachmentName,
+ ScheduleMessage *message )
+{
+ if ( !message ) {
+ return 0;
+ }
+
+ Incidence *incidence = dynamic_cast<Incidence*>( message->event() );
+ if ( !incidence ) {
+ KMessageBox::error(
+ parent,
+ i18n( "The calendar invitation stored in this email message is broken in some way. "
+ "Unable to continue." ) );
+ return 0;
+ }
+
+ return find( parent, attachmentName, incidence );
+}
+
+static KTempFile *s_tempFile = 0;
+
+static KURL tempFileForAttachment( Attachment *attachment )
+{
+ KURL url;
+ TQStringList patterns = KMimeType::mimeType( attachment->mimeType() )->patterns();
+ if ( !patterns.empty() ) {
+ s_tempFile = new KTempFile( TQString::null,
+ TQString( patterns.first() ).remove( '*' ), 0600 );
+ } else {
+ s_tempFile = new KTempFile( TQString::null, TQString::null, 0600 );
+ }
+
+ TQFile *qfile = s_tempFile->file();
+ qfile->open( IO_WriteOnly );
+ TQTextStream stream( qfile );
+ stream.writeRawBytes( attachment->decodedData().data(), attachment->size() );
+ s_tempFile->close();
+ TQFile tf( s_tempFile->name() );
+ if ( tf.size() != attachment->size() ) {
+ //whoops. failed to write the entire attachment. return an invalid URL.
+ delete s_tempFile;
+ s_tempFile = 0;
+ return url;
+ }
+
+ url.setPath( s_tempFile->name() );
+ return url;
+}
+
+bool AttachmentHandler::view( TQWidget *parent, Attachment *attachment )
+{
+ if ( !attachment ) {
+ return false;
+ }
+
+ bool stat = true;
+ if ( attachment->isUri() ) {
+ kapp->invokeBrowser( attachment->uri() );
+ } else {
+ // put the attachment in a temporary file and launch it
+ KURL tempUrl = tempFileForAttachment( attachment );
+ if ( tempUrl.isValid() ) {
+ stat = KRun::runURL( tempUrl, attachment->mimeType(), false, true );
+ } else {
+ stat = false;
+ KMessageBox::error(
+ parent,
+ i18n( "Unable to create a temporary file for the attachment." ) );
+ }
+ delete s_tempFile;
+ s_tempFile = 0;
+ }
+ return stat;
+}
+
+bool AttachmentHandler::view( TQWidget *parent, const TQString &attachmentName, Incidence *incidence )
+{
+ return view( parent, find( parent, attachmentName, incidence ) );
+}
+
+bool AttachmentHandler::view( TQWidget *parent, const TQString &attachmentName, const TQString &uid )
+{
+ return view( parent, find( parent, attachmentName, uid ) );
+}
+
+bool AttachmentHandler::view( TQWidget *parent, const TQString &attachmentName,
+ ScheduleMessage *message )
+{
+ return view( parent, find( parent, attachmentName, message ) );
+}
+
+bool AttachmentHandler::saveAs( TQWidget *parent, Attachment *attachment )
+{
+ // get the saveas file name
+ TQString saveAsFile = KFileDialog::getSaveFileName( attachment->label(), TQString::null, parent,
+ i18n( "Save Attachment" ) );
+ if ( saveAsFile.isEmpty() ||
+ ( TQFile( saveAsFile ).exists() &&
+ ( KMessageBox::warningYesNo(
+ parent,
+ i18n( "%1 already exists. Do you want to overwrite it?").
+ arg( saveAsFile ) ) == KMessageBox::No ) ) ) {
+ return false;
+ }
+
+ bool stat = false;
+ if ( attachment->isUri() ) {
+ // save the attachment url
+ stat = KIO::NetAccess::file_copy( attachment->uri(), KURL( saveAsFile ), -1, true );
+ } else {
+ // put the attachment in a temporary file and save it
+ KURL tempUrl = tempFileForAttachment( attachment );
+ if ( tempUrl.isValid() ) {
+ stat = KIO::NetAccess::file_copy( tempUrl, KURL( saveAsFile ), -1, true );
+ if ( !stat && KIO::NetAccess::lastError() ) {
+ KMessageBox::error( parent, KIO::NetAccess::lastErrorString() );
+ }
+ } else {
+ stat = false;
+ KMessageBox::error(
+ parent,
+ i18n( "Unable to create a temporary file for the attachment." ) );
+ }
+ delete s_tempFile;
+ s_tempFile = 0;
+ }
+ return stat;
+}
+
+bool AttachmentHandler::saveAs( TQWidget *parent, const TQString &attachmentName,
+ Incidence *incidence )
+{
+ return saveAs( parent, find( parent, attachmentName, incidence ) );
+}
+
+bool AttachmentHandler::saveAs( TQWidget *parent, const TQString &attachmentName, const TQString &uid )
+{
+ return saveAs( parent, find( parent, attachmentName, uid ) );
+}
+
+bool AttachmentHandler::saveAs( TQWidget *parent, const TQString &attachmentName,
+ ScheduleMessage *message )
+{
+ return saveAs( parent, find( parent, attachmentName, message ) );
+}
+
+}
+
diff --git a/libkcal/attachmenthandler.h b/libkcal/attachmenthandler.h
new file mode 100644
index 000000000..6116f15ad
--- /dev/null
+++ b/libkcal/attachmenthandler.h
@@ -0,0 +1,178 @@
+/*
+ This file is part of the kcal library.
+
+ Copyright (c) 2010 Klar�lvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
+
+ 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+/**
+ @file
+ This file is part of the API for handling calendar data and provides
+ static functions for dealing with calendar incidence attachments.
+
+ @author Allen Winter \<winter@kde.org\>
+*/
+
+#ifndef KCAL_ATTACHMENTHANDLER_H
+#define KCAL_ATTACHMENTHANDLER_H
+
+class TQString;
+class TQWidget;
+
+namespace KCal {
+
+class Attachment;
+class Incidence;
+class ScheduleMessage;
+
+/**
+ @brief
+ Provides methods to handle incidence attachments.
+
+ Includes functions to view and save attachments.
+*/
+namespace AttachmentHandler {
+
+ /**
+ Finds the attachment in the user's calendar, by @p attachmentName and @p incidence.
+
+ @param parent is the parent widget for the dialogs used in this function.
+ @param attachmentName is the name of the attachment
+ @param incidence is a pointer to a valid Incidence object containing the attachment.
+
+ @return a pointer to the Attachment object located; 0 if no such attachment could be found.
+ */
+ Attachment *find( TQWidget *parent, const TQString &attachmentName, Incidence *incidence );
+
+ /**
+ Finds the attachment in the user's calendar, by @p attachmentName and a scheduler message;
+ in other words, this function is intended to retrieve attachments from calendar invitations.
+
+ @param parent is the parent widget for the dialogs used in this function.
+ @param attachmentName is the name of the attachment
+ @param message is a pointer to a valid ScheduleMessage object containing the attachment.
+
+ @return a pointer to the Attachment object located; 0 if no such attachment could be found.
+ */
+ Attachment *find( TQWidget *parent, const TQString &attachmentName, ScheduleMessage *message );
+
+ /**
+ Finds the attachment in the user's calendar, by @p attachmentName and @p uid.
+
+ @param parent is the parent widget for the dialogs used in this function.
+ @param attachmentName is the name of the attachment
+ @param uid is a TQString containing a UID of the incidence containing the attachment.
+
+ @return a pointer to the Attachment object located; 0 if no such attachment could be found.
+ */
+ Attachment *find( TQWidget *parent, const TQString &attachmentName, const TQString &uid );
+
+ /**
+ Launches a viewer on the specified attachment.
+
+ @param parent is the parent widget for the dialogs used in this function.
+ @param attachment is a pointer to a valid Attachment object.
+
+ @return true if the viewer program successfully launched; false otherwise.
+ */
+ bool view( TQWidget *parent, Attachment *attachment );
+
+ /**
+ Launches a viewer on the specified attachment.
+
+ @param parent is the parent widget for the dialogs used in this function.
+ @param attachmentName is the name of the attachment
+ @param incidence is a pointer to a valid Incidence object containing the attachment.
+
+ @return true if the attachment could be found and the viewer program successfully launched;
+ false otherwise.
+ */
+ bool view( TQWidget *parent, const TQString &attachmentName, Incidence *incidence );
+
+ /**
+ Launches a viewer on the specified attachment.
+
+ @param parent is the parent widget for the dialogs used in this function.
+ @param attachmentName is the name of the attachment
+ @param uid is a TQString containing a UID of the incidence containing the attachment.
+
+ @return true if the attachment could be found and the viewer program successfully launched;
+ false otherwise.
+ */
+ bool view( TQWidget *parent, const TQString &attachmentName, const TQString &uid );
+
+ /**
+ Launches a viewer on the specified attachment.
+
+ @param parent is the parent widget for the dialogs used in this function.
+ @param attachmentName is the name of the attachment
+ @param message is a pointer to a valid ScheduleMessage object containing the attachment.
+
+ @return true if the attachment could be found and the viewer program successfully launched;
+ false otherwise.
+ */
+ bool view( TQWidget *parent, const TQString &attachmentName, ScheduleMessage *message );
+
+ /**
+ Saves the specified attachment to a file of the user's choice.
+
+ @param parent is the parent widget for the dialogs used in this function.
+ @param attachment is a pointer to a valid Attachment object.
+
+ @return true if the save operation was successful; false otherwise.
+ */
+ bool saveAs( TQWidget *parent, Attachment *attachment );
+
+ /**
+ Saves the specified attachment to a file of the user's choice.
+
+ @param parent is the parent widget for the dialogs used in this function.
+ @param attachmentName is the name of the attachment
+ @param incidence is a pointer to a valid Incidence object containing the attachment.
+
+ @return true if the attachment could be found and the save operation was successful;
+ false otherwise.
+ */
+ bool saveAs( TQWidget *parent, const TQString &attachmentName, Incidence *incidence );
+
+ /**
+ Saves the specified attachment to a file of the user's choice.
+
+ @param parent is the parent widget for the dialogs used in this function.
+ @param attachmentName is the name of the attachment
+ @param uid is a TQString containing a UID of the incidence containing the attachment.
+
+ @return true if the attachment could be found and the save operation was successful;
+ false otherwise.
+ */
+ bool saveAs( TQWidget *parent, const TQString &attachmentName, const TQString &uid );
+
+ /**
+ Saves the specified attachment to a file of the user's choice.
+
+ @param parent is the parent widget for the dialogs used in this function.
+ @param attachmentName is the name of the attachment
+ @param message is a pointer to a valid ScheduleMessage object containing the attachment.
+
+ @return true if the attachment could be found and the save operation was successful;
+ false otherwise.
+ */
+ bool saveAs( TQWidget *parent, const TQString &attachmentName, ScheduleMessage *message );
+}
+
+}
+
+#endif
diff --git a/libkcal/attendee.cpp b/libkcal/attendee.cpp
index 3cb2afedf..9aa3d46f7 100644
--- a/libkcal/attendee.cpp
+++ b/libkcal/attendee.cpp
@@ -93,6 +93,9 @@ TQString Attendee::statusName( Attendee::PartStat s )
case InProcess:
return i18n("In Process");
break;
+ case None:
+ return i18n("attendee status unknown", "Unknown");
+ break;
}
}
diff --git a/libkcal/attendee.h b/libkcal/attendee.h
index f460665b6..161c77ed2 100644
--- a/libkcal/attendee.h
+++ b/libkcal/attendee.h
@@ -37,7 +37,7 @@ class LIBKCAL_EXPORT Attendee : public Person
{
public:
enum PartStat { NeedsAction, Accepted, Declined, Tentative,
- Delegated, Completed, InProcess };
+ Delegated, Completed, InProcess, None };
enum Role { ReqParticipant, OptParticipant, NonParticipant, Chair };
typedef ListBase<Attendee> List;
@@ -53,7 +53,7 @@ class LIBKCAL_EXPORT Attendee : public Person
@param u the uid for the attendee
*/
Attendee( const TQString &name, const TQString &email,
- bool rsvp = false, PartStat status = NeedsAction,
+ bool rsvp = false, PartStat status = None,
Role role = ReqParticipant, const TQString &u = TQString::null );
/**
Destruct Attendee.
diff --git a/libkcal/calendar.cpp b/libkcal/calendar.cpp
index c3c3a9e65..711cdc12a 100644
--- a/libkcal/calendar.cpp
+++ b/libkcal/calendar.cpp
@@ -50,6 +50,7 @@ Calendar::Calendar( const TQString &timeZoneId )
void Calendar::init()
{
+ mException = 0;
mNewObserver = false;
mObserversEnabled = true;
@@ -66,9 +67,27 @@ void Calendar::init()
Calendar::~Calendar()
{
+ clearException();
delete mDefaultFilter;
}
+void Calendar::clearException()
+{
+ delete mException;
+ mException = 0;
+}
+
+ErrorFormat *Calendar::exception() const
+{
+ return mException;
+}
+
+void Calendar::setException( ErrorFormat *e )
+{
+ delete mException;
+ mException = e;
+}
+
const Person &Calendar::getOwner() const
{
return mOwner;
@@ -122,6 +141,16 @@ CalFilter *Calendar::filter()
return mFilter;
}
+void Calendar::beginBatchAdding()
+{
+ emit batchAddingBegins();
+}
+
+void Calendar::endBatchAdding()
+{
+ emit batchAddingEnds();
+}
+
TQStringList Calendar::categories()
{
Incidence::List rawInc( rawIncidences() );
@@ -161,7 +190,7 @@ Event::List Calendar::sortEvents( Event::List *eventList,
SortDirection sortDirection )
{
Event::List eventListSorted;
- Event::List tempList, t;
+ Event::List tempList;
Event::List alphaList;
Event::List::Iterator sortIt;
Event::List::Iterator eit;
@@ -177,6 +206,10 @@ Event::List Calendar::sortEvents( Event::List *eventList,
case EventSortStartDate:
alphaList = sortEvents( eventList, EventSortSummary, sortDirection );
for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
+ if ( (*eit)->doesFloat() ) {
+ tempList.append( *eit );
+ continue;
+ }
sortIt = eventListSorted.begin();
if ( sortDirection == SortDirectionAscending ) {
while ( sortIt != eventListSorted.end() &&
@@ -191,6 +224,14 @@ Event::List Calendar::sortEvents( Event::List *eventList,
}
eventListSorted.insert( sortIt, *eit );
}
+ if ( sortDirection == SortDirectionAscending ) {
+ // Prepend the list of all-day Events
+ tempList += eventListSorted;
+ eventListSorted = tempList;
+ } else {
+ // Append the list of all-day Events
+ eventListSorted += tempList;
+ }
break;
case EventSortEndDate:
@@ -245,7 +286,149 @@ Event::List Calendar::sortEvents( Event::List *eventList,
}
return eventListSorted;
+}
+
+Event::List Calendar::sortEventsForDate( Event::List *eventList,
+ const TQDate &date,
+ EventSortField sortField,
+ SortDirection sortDirection )
+{
+ Event::List eventListSorted;
+ Event::List tempList;
+ Event::List alphaList;
+ Event::List::Iterator sortIt;
+ Event::List::Iterator eit;
+
+ switch( sortField ) {
+ case EventSortStartDate:
+ alphaList = sortEvents( eventList, EventSortSummary, sortDirection );
+ for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
+ if ( (*eit)->doesFloat() ) {
+ tempList.append( *eit );
+ continue;
+ }
+ sortIt = eventListSorted.begin();
+ if ( sortDirection == SortDirectionAscending ) {
+ while ( sortIt != eventListSorted.end() ) {
+ if ( !(*eit)->doesRecur() ) {
+ if ( (*eit)->dtStart().time() >= (*sortIt)->dtStart().time() ) {
+ ++sortIt;
+ } else {
+ break;
+ }
+ } else {
+ if ( (*eit)->recursOn( date ) ) {
+ if ( (*eit)->dtStart().time() >= (*sortIt)->dtStart().time() ) {
+ ++sortIt;
+ } else {
+ break;
+ }
+ } else {
+ ++sortIt;
+ }
+ }
+ }
+ } else { // descending
+ while ( sortIt != eventListSorted.end() ) {
+ if ( !(*eit)->doesRecur() ) {
+ if ( (*eit)->dtStart().time() < (*sortIt)->dtStart().time() ) {
+ ++sortIt;
+ } else {
+ break;
+ }
+ } else {
+ if ( (*eit)->recursOn( date ) ) {
+ if ( (*eit)->dtStart().time() < (*sortIt)->dtStart().time() ) {
+ ++sortIt;
+ } else {
+ break;
+ }
+ } else {
+ ++sortIt;
+ }
+ }
+ }
+ }
+ eventListSorted.insert( sortIt, *eit );
+ }
+ if ( sortDirection == SortDirectionAscending ) {
+ // Prepend the list of all-day Events
+ tempList += eventListSorted;
+ eventListSorted = tempList;
+ } else {
+ // Append the list of all-day Events
+ eventListSorted += tempList;
+ }
+ break;
+ case EventSortEndDate:
+ alphaList = sortEvents( eventList, EventSortSummary, sortDirection );
+ for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
+ if ( (*eit)->hasEndDate() ) {
+ sortIt = eventListSorted.begin();
+ if ( sortDirection == SortDirectionAscending ) {
+ while ( sortIt != eventListSorted.end() ) {
+ if ( !(*eit)->doesRecur() ) {
+ if ( (*eit)->dtEnd().time() >= (*sortIt)->dtEnd().time() ) {
+ ++sortIt;
+ } else {
+ break;
+ }
+ } else {
+ if ( (*eit)->recursOn( date ) ) {
+ if ( (*eit)->dtEnd().time() >= (*sortIt)->dtEnd().time() ) {
+ ++sortIt;
+ } else {
+ break;
+ }
+ } else {
+ ++sortIt;
+ }
+ }
+ }
+ } else { // descending
+ while ( sortIt != eventListSorted.end() ) {
+ if ( !(*eit)->doesRecur() ) {
+ if ( (*eit)->dtEnd().time() < (*sortIt)->dtEnd().time() ) {
+ ++sortIt;
+ } else {
+ break;
+ }
+ } else {
+ if ( (*eit)->recursOn( date ) ) {
+ if ( (*eit)->dtEnd().time() < (*sortIt)->dtEnd().time() ) {
+ ++sortIt;
+ } else {
+ break;
+ }
+ } else {
+ ++sortIt;
+ }
+ }
+ }
+ }
+ } else {
+ // Keep a list of the Events without End DateTimes
+ tempList.append( *eit );
+ }
+ eventListSorted.insert( sortIt, *eit );
+ }
+ if ( sortDirection == SortDirectionAscending ) {
+ // Prepend the list of Events without End DateTimes
+ tempList += eventListSorted;
+ eventListSorted = tempList;
+ } else {
+ // Append the list of Events without End DateTimes
+ eventListSorted += tempList;
+ }
+ break;
+
+ default:
+ eventListSorted = sortEvents( eventList, sortField, sortDirection );
+ break;
+ }
+
+ return eventListSorted;
}
Event::List Calendar::events( const TQDate &date,
diff --git a/libkcal/calendar.h b/libkcal/calendar.h
index a53ef5a06..005b513ef 100644
--- a/libkcal/calendar.h
+++ b/libkcal/calendar.h
@@ -31,13 +31,7 @@
#ifndef KCAL_CALENDAR_H
#define KCAL_CALENDAR_H
-#include <tqobject.h>
-#include <tqstring.h>
-#include <tqdatetime.h>
-#include <tqptrlist.h>
-#include <tqdict.h>
-#include <kdepimmacros.h>
-
+#include "exceptions.h"
#include "customproperties.h"
#include "event.h"
#include "todo.h"
@@ -45,6 +39,14 @@
#include "kcalversion.h"
#include "person.h"
+#include <kdepimmacros.h>
+
+#include <tqobject.h>
+#include <tqstring.h>
+#include <tqdatetime.h>
+#include <tqptrlist.h>
+#include <tqdict.h>
+
/**
@namespace KCal
Namespace KCal is for global classes, objects and/or functions in libkcal.
@@ -207,6 +209,17 @@ class LIBKCAL_EXPORT Calendar : public TQObject, public CustomProperties,
TQString productId();
/**
+ Clears the exception status.
+ */
+ void clearException();
+
+ /**
+ Returns an exception, if there is any, containing information about the
+ last error that occurred.
+ */
+ ErrorFormat *exception() const;
+
+ /**
Set the owner of the Calendar.
@param owner is a Person object.
@@ -472,6 +485,22 @@ class LIBKCAL_EXPORT Calendar : public TQObject, public CustomProperties,
static Event::List sortEvents( Event::List *eventList,
EventSortField sortField,
SortDirection sortDirection );
+
+ /**
+ Sort a list of Events that occur on a specified date.
+
+ @param eventList is a pointer to a list of Events occurring on @p date.
+ @param date is the date.
+ @param sortField specifies the EventSortField.
+ @param sortDirection specifies the SortDirection.
+
+ @return a list of Events sorted as specified.
+ */
+ static Event::List sortEventsForDate( Event::List *eventList,
+ const TQDate &date,
+ EventSortField sortField,
+ SortDirection sortDirection );
+
/**
Return a sorted, filtered list of all Events for this Calendar.
@@ -755,6 +784,30 @@ class LIBKCAL_EXPORT Calendar : public TQObject, public CustomProperties,
*/
virtual Journal *journal( const TQString &uid ) = 0;
+ /**
+ Emits the beginBatchAdding() signal.
+
+ This should be called before adding a batch of incidences with
+ addIncidence( Incidence *), addTodo( Todo *), addEvent( Event *)
+ or addJournal( Journal *). Some Calendars are connected to this
+ signal, e.g: CalendarResources uses it to know a series of
+ incidenceAdds are related so the user isn't prompted multiple
+ times which resource to save the incidence to
+
+ @since 4.4
+ */
+ void beginBatchAdding();
+
+ /**
+ Emits the endBatchAdding() signal.
+
+ Used with beginBatchAdding(). Should be called after
+ adding all incidences.
+
+ @since 4.4
+ */
+ void endBatchAdding();
+
// Relations Specific Methods //
/**
@@ -879,8 +932,26 @@ class LIBKCAL_EXPORT Calendar : public TQObject, public CustomProperties,
*/
void calendarLoaded();
+ /**
+ @see beginBatchAdding()
+ @since 4.4
+ */
+ void batchAddingBegins();
+
+ /**
+ @see endBatchAdding()
+ @since 4.4
+ */
+ void batchAddingEnds();
+
protected:
/**
+ Sets information about the last error occurred.
+ The previous exception is freed.
+ */
+ void setException( ErrorFormat *e );
+
+ /**
The Observer interface. So far not implemented.
@param incidenceBase is a pointer an IncidenceBase object.
@@ -941,6 +1012,7 @@ class LIBKCAL_EXPORT Calendar : public TQObject, public CustomProperties,
// returning static Alarm::List
private:
+
/**
Intialize a Calendar object with starting values.
*/
@@ -964,6 +1036,7 @@ class LIBKCAL_EXPORT Calendar : public TQObject, public CustomProperties,
TQDict<Incidence> mOrphans;
TQDict<Incidence> mOrphanUids;
+ ErrorFormat *mException;
class Private;
Private *d;
};
diff --git a/libkcal/calendarlocal.cpp b/libkcal/calendarlocal.cpp
index 27b27e0e2..2f2d7739b 100644
--- a/libkcal/calendarlocal.cpp
+++ b/libkcal/calendarlocal.cpp
@@ -327,7 +327,12 @@ Alarm::List CalendarLocal::alarms( const TQDateTime &from, const TQDateTime &to
Todo::List::ConstIterator it2;
for( it2 = mTodoList.begin(); it2 != mTodoList.end(); ++it2 ) {
- if (! (*it2)->isCompleted() ) appendAlarms( alarms, *it2, from, to );
+ Todo *t = *it2;
+ if ( t->isCompleted() ) {
+ continue;
+ }
+ if ( t->doesRecur() ) appendRecurringAlarms( alarms, t, from, to );
+ else appendAlarms( alarms, t, from, to );
}
return alarms;
@@ -340,13 +345,14 @@ void CalendarLocal::appendAlarms( Alarm::List &alarms, Incidence *incidence,
Alarm::List::ConstIterator it;
for( it = incidence->alarms().begin(); it != incidence->alarms().end();
++it ) {
- if ( (*it)->enabled() ) {
- TQDateTime dt = (*it)->nextRepetition(preTime);
+ Alarm *alarm = *it;
+ if ( alarm->enabled() ) {
+ TQDateTime dt = alarm->nextRepetition( preTime );
if ( dt.isValid() && dt <= to ) {
kdDebug(5800) << "CalendarLocal::appendAlarms() '"
<< incidence->summary() << "': "
<< dt.toString() << endl;
- alarms.append( *it );
+ alarms.append( alarm );
}
}
}
@@ -357,10 +363,14 @@ void CalendarLocal::appendRecurringAlarms( Alarm::List &alarms,
const TQDateTime &from,
const TQDateTime &to )
{
- TQDateTime qdt;
- int endOffset = 0;
+ TQDateTime dt;
+ Duration endOffset( 0 );
bool endOffsetValid = false;
- int period = from.secsTo(to);
+ Duration period( from, to );
+
+ Event *e = static_cast<Event *>( incidence );
+ Todo *t = static_cast<Todo *>( incidence );
+
Alarm::List::ConstIterator it;
for( it = incidence->alarms().begin(); it != incidence->alarms().end();
++it ) {
@@ -368,59 +378,118 @@ void CalendarLocal::appendRecurringAlarms( Alarm::List &alarms,
if ( alarm->enabled() ) {
if ( alarm->hasTime() ) {
// The alarm time is defined as an absolute date/time
- qdt = alarm->nextRepetition( from.addSecs(-1) );
- if ( !qdt.isValid() || qdt > to )
+ dt = alarm->nextRepetition( from.addSecs(-1) );
+ if ( !dt.isValid() || dt > to ) {
continue;
+ }
} else {
- // The alarm time is defined by an offset from the event start or end time.
+ // Alarm time is defined by an offset from the event start or end time.
// Find the offset from the event start time, which is also used as the
// offset from the recurrence time.
- int offset = 0;
+ Duration offset( 0 );
if ( alarm->hasStartOffset() ) {
offset = alarm->startOffset().asSeconds();
} else if ( alarm->hasEndOffset() ) {
+ offset = alarm->endOffset().asSeconds();
if ( !endOffsetValid ) {
- endOffset = incidence->dtStart().secsTo( incidence->dtEnd() );
- endOffsetValid = true;
+ if ( incidence->type() == "Event" ) {
+ endOffset = Duration( e->dtStart(), e->dtEnd() );
+ endOffsetValid = true;
+ } else if ( incidence->type() == "Todo" &&
+ t->hasStartDate() && t->hasDueDate() ) {
+ endOffset = Duration( t->dtStart(), t->dtDue() );
+ endOffsetValid = true;
+ }
}
- offset = alarm->endOffset().asSeconds() + endOffset;
}
- // Adjust the 'from' date/time and find the next recurrence at or after it
- qdt = incidence->recurrence()->getNextDateTime( from.addSecs(-offset - 1) );
- if ( !qdt.isValid()
- || (qdt = qdt.addSecs( offset )) > to ) // remove the adjustment to get the alarm time
+ // Find the incidence's earliest alarm
+ TQDateTime alarmStart;
+ if ( incidence->type() == "Event" ) {
+ alarmStart =
+ offset.end( alarm->hasEndOffset() ? e->dtEnd() : e->dtStart() );
+ } else if ( incidence->type() == "Todo" ) {
+ alarmStart =
+ offset.end( alarm->hasEndOffset() ? t->dtDue() : t->dtStart() );
+ }
+
+ if ( alarmStart.isValid() && alarmStart > to ) {
+ continue;
+ }
+
+ TQDateTime baseStart;
+ if ( incidence->type() == "Event" ) {
+ baseStart = e->dtStart();
+ } else if ( incidence->type() == "Todo" ) {
+ baseStart = t->dtDue();
+ }
+ if ( alarmStart.isValid() && from > alarmStart ) {
+ alarmStart = from; // don't look earlier than the earliest alarm
+ baseStart = (-offset).end( (-endOffset).end( alarmStart ) );
+ }
+
+ // Adjust the 'alarmStart' date/time and find the next recurrence
+ // at or after it. Treat the two offsets separately in case one
+ // is daily and the other not.
+ dt = incidence->recurrence()->getNextDateTime( baseStart.addSecs(-1) );
+ if ( !dt.isValid() ||
+ ( dt = endOffset.end( offset.end( dt ) ) ) > to ) // adjust 'dt' to get the alarm time
{
// The next recurrence is too late.
- if ( !alarm->repeatCount() )
+ if ( !alarm->repeatCount() ) {
continue;
- // The alarm has repetitions, so check whether repetitions of previous
- // recurrences fall within the time period.
+ }
+
+ // The alarm has repetitions, so check whether repetitions of
+ // previous recurrences fall within the time period.
bool found = false;
- qdt = from.addSecs( -offset );
- while ( (qdt = incidence->recurrence()->getPreviousDateTime( qdt )).isValid() ) {
- int toFrom = qdt.secsTo( from ) - offset;
- if ( toFrom > alarm->duration() )
- break; // this recurrence's last repetition is too early, so give up
- // The last repetition of this recurrence is at or after 'from' time.
- // Check if a repetition occurs between 'from' and 'to'.
- int snooze = alarm->snoozeTime() * 60; // in seconds
- if ( period >= snooze
- || toFrom % snooze == 0
- || (toFrom / snooze + 1) * snooze <= toFrom + period ) {
- found = true;
+ Duration alarmDuration = alarm->duration();
+ for ( TQDateTime base = baseStart;
+ ( dt = incidence->recurrence()->getPreviousDateTime( base ) ).isValid();
+ base = dt ) {
+ if ( alarm->duration().end( dt ) < base ) {
+ break; // recurrence's last repetition is too early, so give up
+ }
+
+ // The last repetition of this recurrence is on or after
+ // 'alarmStart' time. Check if a repetition occurs between
+ // 'alarmStart' and 'to'.
+ int snooze = alarm->snoozeTime().value(); // in seconds or days
+ if ( alarm->snoozeTime().isDaily() ) {
+ Duration toFromDuration( dt, base );
+ int toFrom = toFromDuration.asDays();
+ if ( alarm->snoozeTime().end( from ) <= to ||
+ ( toFromDuration.isDaily() && toFrom % snooze == 0 ) ||
+ ( toFrom / snooze + 1 ) * snooze <= toFrom + period.asDays() ) {
+ found = true;
+#ifndef NDEBUG
+ // for debug output
+ dt = offset.end( dt ).addDays( ( ( toFrom - 1 ) / snooze + 1 ) * snooze );
+#endif
+ break;
+ }
+ } else {
+ int toFrom = dt.secsTo( base );
+ if ( period.asSeconds() >= snooze ||
+ toFrom % snooze == 0 ||
+ ( toFrom / snooze + 1 ) * snooze <= toFrom + period.asSeconds() )
+ {
+ found = true;
#ifndef NDEBUG
- qdt = qdt.addSecs( offset + ((toFrom-1) / snooze + 1) * snooze ); // for debug output
+ // for debug output
+ dt = offset.end( dt ).addSecs( ( ( toFrom - 1 ) / snooze + 1 ) * snooze );
#endif
- break;
+ break;
+ }
}
}
- if ( !found )
+ if ( !found ) {
continue;
+ }
}
}
kdDebug(5800) << "CalendarLocal::appendAlarms() '" << incidence->summary()
- << "': " << qdt.toString() << endl;
+ << "': " << dt.toString() << endl;
alarms.append( alarm );
}
}
@@ -485,7 +554,7 @@ Event::List CalendarLocal::rawEventsForDate( const TQDate &qd,
}
}
- return sortEvents( &eventList, sortField, sortDirection );
+ return sortEventsForDate( &eventList, qd, sortField, sortDirection );
}
Event::List CalendarLocal::rawEvents( const TQDate &start, const TQDate &end,
diff --git a/libkcal/calendarresources.cpp b/libkcal/calendarresources.cpp
index 42f618dc3..abd1cc213 100644
--- a/libkcal/calendarresources.cpp
+++ b/libkcal/calendarresources.cpp
@@ -55,6 +55,35 @@
using namespace KCal;
+
+class CalendarResources::Private {
+ public:
+
+ Private() : mLastUsedResource( 0 ), mBatchAddingInProgress( false )
+ {
+ }
+
+ ResourceCalendar *mLastUsedResource;
+ bool mBatchAddingInProgress;
+};
+
+bool CalendarResources::DestinationPolicy::hasCalendarResources( )
+{
+ CalendarResourceManager::ActiveIterator it;
+ for ( it = resourceManager()->activeBegin();
+ it != resourceManager()->activeEnd(); ++it ) {
+ if ( !(*it)->readOnly() ) {
+ //Insert the first the Standard resource to get be the default selected.
+ if ( resourceManager()->standardResource() == *it ) {
+ return true;
+ } else {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
ResourceCalendar
*CalendarResources::StandardDestinationPolicy::destination( Incidence * )
{
@@ -85,7 +114,7 @@ ResourceCalendar
CalendarResources::CalendarResources( const TQString &timeZoneId,
const TQString &family )
- : Calendar( timeZoneId )
+ : Calendar( timeZoneId ), d( new Private() )
{
init( family );
}
@@ -100,6 +129,10 @@ void CalendarResources::init( const TQString &family )
mStandardPolicy = new StandardDestinationPolicy( mManager );
mAskPolicy = new AskDestinationPolicy( mManager );
mDestinationPolicy = mStandardPolicy;
+ mPendingDeleteFromResourceMap = false;
+
+ connect( this, TQT_SIGNAL(batchAddingBegins()), this, TQT_SLOT(beginAddingIncidences()) );
+ connect( this, TQT_SIGNAL(batchAddingEnds()), this, TQT_SLOT(endAddingIncidences()) );
}
CalendarResources::~CalendarResources()
@@ -158,6 +191,7 @@ void CalendarResources::load()
}
mOpen = true;
+ emit calendarLoaded();
}
bool CalendarResources::reload( const TQString &tz )
@@ -276,7 +310,8 @@ bool CalendarResources::isSaving()
}
bool CalendarResources::addIncidence( Incidence *incidence,
- ResourceCalendar *resource )
+ ResourceCalendar *resource,
+ const TQString &subresource )
{
// FIXME: Use proper locking via begin/endChange!
bool validRes = false;
@@ -285,52 +320,90 @@ bool CalendarResources::addIncidence( Incidence *incidence,
if ( (*it) == resource )
validRes = true;
}
+
+ kdDebug(5800)<< "CalendarResources: validRes is " << validRes << endl;
+
ResourceCalendar *oldResource = 0;
if ( mResourceMap.contains( incidence ) ) {
oldResource = mResourceMap[incidence];
}
mResourceMap[incidence] = resource;
- if ( validRes && beginChange( incidence ) &&
- resource->addIncidence( incidence ) ) {
-// mResourceMap[incidence] = resource;
+ if ( validRes && beginChange( incidence, resource, subresource ) &&
+ resource->addIncidence( incidence, subresource ) ) {
+ // mResourceMap[incidence] = resource;
incidence->registerObserver( this );
notifyIncidenceAdded( incidence );
setModified( true );
- endChange( incidence );
+ endChange( incidence, resource, subresource );
return true;
} else {
- if ( oldResource )
+ if ( oldResource ) {
mResourceMap[incidence] = oldResource;
- else
+ } else {
mResourceMap.remove( incidence );
+ }
}
return false;
}
+bool CalendarResources::addIncidence( Incidence *incidence,
+ ResourceCalendar *resource )
+{
+ return addIncidence( incidence, resource, TQString() );
+}
+
bool CalendarResources::addIncidence( Incidence *incidence )
{
- kdDebug(5800) << "CalendarResources::addIncidence" << this << endl;
+ kdDebug(5800) << "CalendarResources::addIncidence "
+ << incidence->summary()
+ << "; addingInProgress = " << d->mBatchAddingInProgress
+ << "; lastUsedResource = " << d->mLastUsedResource
+ << endl;
- ResourceCalendar *resource = mDestinationPolicy->destination( incidence );
+ clearException();
- if ( resource ) {
- mResourceMap[ incidence ] = resource;
+ ResourceCalendar *resource = d->mLastUsedResource;
+
+ if ( !d->mBatchAddingInProgress || d->mLastUsedResource == 0 ) {
+ resource = mDestinationPolicy->destination( incidence );
+ d->mLastUsedResource = resource;
+
+ if ( resource && d->mBatchAddingInProgress ) {
+ d->mLastUsedResource->beginAddingIncidences();
+ }
+ }
- if ( beginChange( incidence ) && resource->addIncidence( incidence ) ) {
+ if ( resource ) {
+ kdDebug(5800) << "CalendarResources:: resource= "
+ << resource->resourceName()
+ << " with id = " << resource->identifier()
+ << " with type = " << resource->type()
+ << endl;
+ mResourceMap[incidence] = resource;
+
+ if ( beginChange( incidence, resource, TQString() ) &&
+ resource->addIncidence( incidence ) ) {
incidence->registerObserver( this );
notifyIncidenceAdded( incidence );
-
mResourceMap[ incidence ] = resource;
setModified( true );
- endChange( incidence );
+ endChange( incidence, resource, TQString() );
return true;
} else {
+ if ( resource->exception() ) {
+ setException( new ErrorFormat( resource->exception()->errorCode() ) );
+ }
+
+ // the incidence isn't going to be added, do cleanup:
mResourceMap.remove( incidence );
+ d->mLastUsedResource->endAddingIncidences();
+ d->mLastUsedResource = 0;
}
- } else
- kdDebug(5800) << "CalendarResources::addIncidence(): no resource" << endl;
+ } else {
+ setException( new ErrorFormat( ErrorFormat::UserCancel ) );
+ }
return false;
}
@@ -343,7 +416,13 @@ bool CalendarResources::addEvent( Event *event )
bool CalendarResources::addEvent( Event *Event, ResourceCalendar *resource )
{
- return addIncidence( Event, resource );
+ return addIncidence( Event, resource, TQString() );
+}
+
+bool CalendarResources::addEvent( Event *Event, ResourceCalendar *resource,
+ const TQString &subresource )
+{
+ return addIncidence( Event, resource, subresource );
}
bool CalendarResources::deleteEvent( Event *event )
@@ -354,7 +433,7 @@ bool CalendarResources::deleteEvent( Event *event )
if ( mResourceMap.find( event ) != mResourceMap.end() ) {
status = mResourceMap[event]->deleteEvent( event );
if ( status )
- mResourceMap.remove( event );
+ mPendingDeleteFromResourceMap = true;
} else {
status = false;
CalendarResourceManager::ActiveIterator it;
@@ -363,6 +442,10 @@ bool CalendarResources::deleteEvent( Event *event )
}
}
+ if ( status ) {
+ notifyIncidenceDeleted( event );
+ }
+
setModified( status );
return status;
}
@@ -390,7 +473,13 @@ bool CalendarResources::addTodo( Todo *todo )
bool CalendarResources::addTodo( Todo *todo, ResourceCalendar *resource )
{
- return addIncidence( todo, resource );
+ return addIncidence( todo, resource, TQString() );
+}
+
+bool CalendarResources::addTodo( Todo *todo, ResourceCalendar *resource,
+ const TQString &subresource )
+{
+ return addIncidence( todo, resource, subresource );
}
bool CalendarResources::deleteTodo( Todo *todo )
@@ -401,7 +490,7 @@ bool CalendarResources::deleteTodo( Todo *todo )
if ( mResourceMap.find( todo ) != mResourceMap.end() ) {
status = mResourceMap[todo]->deleteTodo( todo );
if ( status )
- mResourceMap.remove( todo );
+ mPendingDeleteFromResourceMap = true;
} else {
CalendarResourceManager::ActiveIterator it;
status = false;
@@ -494,6 +583,11 @@ Alarm::List CalendarResources::alarms( const TQDateTime &from,
return result;
}
+bool CalendarResources::hasCalendarResources()
+{
+ return mDestinationPolicy->hasCalendarResources();
+}
+
/****************************** PROTECTED METHODS ****************************/
Event::List CalendarResources::rawEventsForDate( const TQDate &date,
@@ -510,7 +604,7 @@ Event::List CalendarResources::rawEventsForDate( const TQDate &date,
mResourceMap[ *it2 ] = *it;
}
}
- return sortEvents( &result, sortField, sortDirection );
+ return sortEventsForDate( &result, date, sortField, sortDirection );
}
Event::List CalendarResources::rawEvents( const TQDate &start, const TQDate &end,
@@ -574,6 +668,19 @@ bool CalendarResources::addJournal( Journal *journal )
return addIncidence( journal );
}
+bool CalendarResources::addJournal( Journal *journal, ResourceCalendar *resource )
+{
+ return addIncidence( journal, resource, TQString() );
+}
+
+
+bool CalendarResources::addJournal( Journal *journal, ResourceCalendar *resource,
+ const TQString &subresource )
+{
+ return addIncidence( journal, resource, subresource );
+}
+
+
bool CalendarResources::deleteJournal( Journal *journal )
{
kdDebug(5800) << "CalendarResources::deleteJournal" << endl;
@@ -582,7 +689,7 @@ bool CalendarResources::deleteJournal( Journal *journal )
if ( mResourceMap.find( journal ) != mResourceMap.end() ) {
status = mResourceMap[journal]->deleteJournal( journal );
if ( status )
- mResourceMap.remove( journal );
+ mPendingDeleteFromResourceMap = true;
} else {
CalendarResourceManager::ActiveIterator it;
status = false;
@@ -595,13 +702,6 @@ bool CalendarResources::deleteJournal( Journal *journal )
return status;
}
-bool CalendarResources::addJournal( Journal *journal,
- ResourceCalendar *resource
- )
-{
- return addIncidence( journal, resource );
-}
-
Journal *CalendarResources::journal( const TQString &uid )
{
kdDebug(5800) << "CalendarResources::journal(uid)" << endl;
@@ -762,28 +862,40 @@ void CalendarResources::releaseSaveTicket( Ticket *ticket )
bool CalendarResources::beginChange( Incidence *incidence )
{
+ return beginChange( incidence, 0, TQString() );
+}
+
+bool CalendarResources::beginChange( Incidence *incidence,
+ ResourceCalendar *res,
+ const TQString &subres )
+{
+ Q_UNUSED( subres ); // possible future use
+
kdDebug(5800) << "CalendarResources::beginChange()" << endl;
- ResourceCalendar *r = resource( incidence );
- if ( !r ) {
- r = mDestinationPolicy->destination( incidence );
- if ( !r ) {
+ if ( !res ) {
+ res = resource( incidence );
+ }
+ if ( !res ) {
+ res = mDestinationPolicy->destination( incidence );
+ if ( !res ) {
kdError() << "Unable to get destination resource." << endl;
return false;
}
- mResourceMap[ incidence ] = r;
+ mResourceMap[ incidence ] = res;
}
+ mPendingDeleteFromResourceMap = false;
- int count = incrementChangeCount( r );
+ int count = incrementChangeCount( res );
if ( count == 1 ) {
- Ticket *ticket = requestSaveTicket( r );
+ Ticket *ticket = requestSaveTicket( res );
if ( !ticket ) {
kdDebug(5800) << "CalendarResources::beginChange(): unable to get ticket."
<< endl;
- decrementChangeCount( r );
+ decrementChangeCount( res );
return false;
} else {
- mTickets[ r ] = ticket;
+ mTickets[ res ] = ticket;
}
}
@@ -792,18 +904,34 @@ bool CalendarResources::beginChange( Incidence *incidence )
bool CalendarResources::endChange( Incidence *incidence )
{
+ return endChange( incidence, 0, TQString() );
+}
+
+bool CalendarResources::endChange( Incidence *incidence,
+ ResourceCalendar *res,
+ const TQString &subres )
+{
+ Q_UNUSED( subres ); // possible future use
+
kdDebug(5800) << "CalendarResource::endChange()" << endl;
- ResourceCalendar *r = resource( incidence );
- if ( !r )
+ if ( !res ) {
+ res = resource( incidence );
+ }
+ if ( !res )
return false;
- int count = decrementChangeCount( r );
+ int count = decrementChangeCount( res );
+
+ if ( mPendingDeleteFromResourceMap ) {
+ mResourceMap.remove( incidence );
+ mPendingDeleteFromResourceMap = false;
+ }
if ( count == 0 ) {
- bool ok = save( mTickets[ r ], incidence );
+ bool ok = save( mTickets[ res ], incidence );
if ( ok ) {
- mTickets.remove( r );
+ mTickets.remove( res );
} else {
return false;
}
@@ -812,6 +940,24 @@ bool CalendarResources::endChange( Incidence *incidence )
return true;
}
+void CalendarResources::beginAddingIncidences()
+{
+ kdDebug(5800) << "CalendarResources: beginAddingIncidences() " << endl;
+ d->mBatchAddingInProgress = true;
+}
+
+void CalendarResources::endAddingIncidences()
+{
+ kdDebug(5800) << "CalendarResources: endAddingIncidences() " << endl;
+ d->mBatchAddingInProgress = false;
+
+ if ( d->mLastUsedResource ) {
+ d->mLastUsedResource->endAddingIncidences();
+ }
+
+ d->mLastUsedResource = 0;
+}
+
int CalendarResources::incrementChangeCount( ResourceCalendar *r )
{
if ( !mChangeCounts.contains( r ) ) {
diff --git a/libkcal/calendarresources.h b/libkcal/calendarresources.h
index 32c48ba41..a78b77bbc 100644
--- a/libkcal/calendarresources.h
+++ b/libkcal/calendarresources.h
@@ -80,7 +80,7 @@ class LIBKCAL_EXPORT CalendarResources :
virtual ResourceCalendar *destination( Incidence *incidence ) = 0;
virtual TQWidget *parent() { return mParent; }
virtual void setParent( TQWidget *newparent ) { mParent = newparent; }
-
+ bool hasCalendarResources();
protected:
CalendarResourceManager *resourceManager()
{ return mManager; }
@@ -268,20 +268,20 @@ class LIBKCAL_EXPORT CalendarResources :
Resource which is queried.
*/
void setAskDestinationPolicy();
-
- /**
+
+ /**
Returns the current parent for new dialogs. This is a bad hack, but we need
to properly set the parent for the resource selection dialog. Otherwise
- the dialog will not be modal to the editor dialog in korganizer and
+ the dialog will not be modal to the editor dialog in korganizer and
the user can still work in the editor dialog (and thus crash korganizer).
- Afterwards we need to reset it (to avoid pointers to widgets that are
+ Afterwards we need to reset it (to avoid pointers to widgets that are
already deleted) so we also need the accessor
*/
TQWidget *dialogParentWidget();
- /**
+ /**
Set the widget parent for new dialogs. This is a bad hack, but we need
to properly set the parent for the resource selection dialog. Otherwise
- the dialog will not be modal to the editor dialog in korganizer and
+ the dialog will not be modal to the editor dialog in korganizer and
the user can still work in the editor dialog (and thus crash korganizer).
*/
void setDialogParentWidget( TQWidget *parent );
@@ -333,22 +333,70 @@ class LIBKCAL_EXPORT CalendarResources :
@param resource is a pointer to the ResourceCalendar to be added to.
@return true if the Incidence was successfully inserted; false otherwise.
+ @deprecated use
+ addIncidence(Incidence *,ResourceCalendar *,const TQString &) instead.
+ */
+ KDE_DEPRECATED bool addIncidence( Incidence *incidence, ResourceCalendar *resource );
+
+ /**
+ Insert an Incidence into a Calendar Resource.
+
+ @param incidence is a pointer to the Incidence to insert.
+ @param resource is a pointer to the ResourceCalendar to be added to.
+ @param subresource is the subresource name, which may not be used
+ by some calendar resources.
+
+ @return true if the Incidence was successfully inserted; false otherwise.
*/
- bool addIncidence( Incidence *incidence, ResourceCalendar *resource );
+ bool addIncidence( Incidence *incidence,
+ ResourceCalendar *resource, const TQString &subresource );
/**
Flag that a change to a Calendar Incidence is starting.
+ @param incidence is a pointer to the Incidence that will be changing.
+
+ @return false if the resource could not be computed or if a ticket
+ request fails; true otherwise.
+ */
+ KDE_DEPRECATED bool beginChange( Incidence *incidence );
+ /**
+ Flag that a change to a Calendar Incidence is starting.
@param incidence is a pointer to the Incidence that will be changing.
+ @param resource is a pointer to the ResourceCalendar that @p incidence
+ belongs to; if this is 0 then the resource is queried via the
+ DestinationPolicy.
+ @param subresource is the @p Incidence subresource name, which may not
+ be used by some calendar resources.
+
+ @return false if the resource could not be computed or if a ticket
+ request fails; true otherwise.
*/
- bool beginChange( Incidence *incidence );
+ bool beginChange( Incidence *incidence, ResourceCalendar *resource, const TQString &subresource );
/**
Flag that a change to a Calendar Incidence has completed.
+ @param incidence is a pointer to the Incidence that was changed.
+ @return false if the resource could not be computed or if a ticket
+ save fails; true otherwise.
+ */
+ KDE_DEPRECATED bool endChange( Incidence *incidence );
+
+ /**
+ Flag that a change to a Calendar Incidence has completed.
@param incidence is a pointer to the Incidence that was changed.
+ @param resource is a pointer to the ResourceCalendar that @p incidence
+ belongs to; if this is 0 then the resource is queried via the
+ DestinationPolicy.
+ @param subresource is the @p Incidence subresource name, which may not
+ be used by some calendar resources.
+
+ @return false if the resource could not be computed or if a ticket
+ save fails; true otherwise.
*/
- bool endChange( Incidence *incidence );
+ bool endChange( Incidence *incidence,
+ ResourceCalendar *resource, const TQString &subresource );
// Event Specific Methods //
@@ -372,10 +420,25 @@ class LIBKCAL_EXPORT CalendarResources :
@return true if the Event was successfully inserted; false otherwise.
+ @deprecated use
+ addIncidence(Incidence *,ResourceCalendar *,const TQString&) instead.
+ */
+ KDE_DEPRECATED bool addEvent( Event *event, ResourceCalendar *resource );
+
+ /**
+ Insert an Event into a Calendar Resource.
+
+ @param event is a pointer to the Event to insert.
+ @param resource is a pointer to the ResourceCalendar to be added to.
+ @param subresource is the subresource name, which may not be used
+ by some calendar resources.
+
+ @return true if the Event was successfully inserted; false otherwise.
+
@note In most cases use
- addIncidence( Incidence *incidence, ResourceCalendar *resource ) instead.
+ addIncidence(Incidence *,ResourceCalendar *,const TQString &) instead.
*/
- bool addEvent( Event *event, ResourceCalendar *resource );
+ bool addEvent( Event *event, ResourceCalendar *resource, const TQString &subresource );
/**
Remove an Event from the Calendar.
@@ -474,10 +537,25 @@ class LIBKCAL_EXPORT CalendarResources :
@return true if the Todo was successfully inserted; false otherwise.
+ @deprecated use
+ addIncidence(Incidence *,ResourceCalendar *,const TQString &) instead.
+ */
+ KDE_DEPRECATED bool addTodo( Todo *todo, ResourceCalendar *resource );
+
+ /**
+ Insert an Todo into a Calendar Resource.
+
+ @param todo is a pointer to the Todo to insert.
+ @param resource is a pointer to the ResourceCalendar to be added to.
+ @param subresource is the subresource name, which may not be used
+ by some calendar resources.
+
+ @return true if the Todo was successfully inserted; false otherwise.
+
@note In most cases use
- addIncidence( Incidence *incidence, ResourceCalendar *resource ) instead.
+ addIncidence(Incidence *, ResourceCalendar *,const TQString &) instead.
*/
- bool addTodo( Todo *todo, ResourceCalendar *resource );
+ bool addTodo( Todo *todo, ResourceCalendar *resource, const TQString &subresource );
/**
Remove an Todo from the Calendar.
@@ -544,10 +622,25 @@ class LIBKCAL_EXPORT CalendarResources :
@return true if the Journal was successfully inserted; false otherwise.
+ @deprecated use
+ addIncidence(Incidence *,ResourceCalendar *,const TQString &) instead.
+ */
+ KDE_DEPRECATED bool addJournal( Journal *journal, ResourceCalendar *resource );
+
+ /**
+ Insert a Journal into a Calendar Resource.
+
+ @param journal is a pointer to the Journal to insert.
+ @param resource is a pointer to the ResourceCalendar to be added to.
+ @param subresource is the subresource name, which may not be used
+ by some calendar resources.
+
+ @return true if the Journal was successfully inserted; false otherwise.
+
@note In most cases use
- addIncidence( Incidence *incidence, ResourceCalendar *resource ) instead.
+ addIncidence(Incidence *,ResourceCalendar *,const TQString &) instead.
*/
- bool addJournal( Journal *journal, ResourceCalendar *resource );
+ bool addJournal( Journal *journal, ResourceCalendar *resource, const TQString &subresource );
/**
Remove a Journal from the Calendar.
@@ -622,6 +715,8 @@ class LIBKCAL_EXPORT CalendarResources :
*/
void setTimeZoneIdViewOnly( const TQString& tz );
+ //issue 2508
+ bool hasCalendarResources();
signals:
/**
Signal that the Resource has been modified.
@@ -684,7 +779,22 @@ class LIBKCAL_EXPORT CalendarResources :
void slotLoadError( ResourceCalendar *resource, const TQString &err );
void slotSaveError( ResourceCalendar *resource, const TQString &err );
+ /**
+ All addIncidence( Incidence * ), addTodo( Todo * ) addEvent( Event * )
+ and addJournal( Journal * ) calls made between beginAddingIncidences()
+ and endAddingIncidences() will only ask the user to choose a resource once.
+ @since 4.4
+ */
+ void beginAddingIncidences();
+
+ /**
+ @see beginAddingIncidences()
+ @since 4.4
+ */
+ void endAddingIncidences();
+
private:
+
/**
Initialize the Resource object with starting values.
*/
@@ -698,6 +808,7 @@ class LIBKCAL_EXPORT CalendarResources :
DestinationPolicy *mDestinationPolicy;
StandardDestinationPolicy *mStandardPolicy;
AskDestinationPolicy *mAskPolicy;
+ bool mPendingDeleteFromResourceMap;
TQMap<ResourceCalendar *, Ticket *> mTickets;
TQMap<ResourceCalendar *, int> mChangeCounts;
diff --git a/libkcal/calformat.cpp b/libkcal/calformat.cpp
index 6ec0260cd..e506b8dfe 100644
--- a/libkcal/calformat.cpp
+++ b/libkcal/calformat.cpp
@@ -47,7 +47,7 @@ void CalFormat::clearException()
mException = 0;
}
-void CalFormat::setException(ErrorFormat *exception)
+void CalFormat::setException( ErrorFormat *exception )
{
delete mException;
mException = exception;
diff --git a/libkcal/calformat.h b/libkcal/calformat.h
index 59c585538..b3b7160db 100644
--- a/libkcal/calformat.h
+++ b/libkcal/calformat.h
@@ -95,7 +95,7 @@ class LIBKCAL_EXPORT CalFormat
Set exception for this object. This is used by the functions of this
class to report errors.
*/
- void setException(ErrorFormat *error);
+ void setException( ErrorFormat *error );
protected:
TQString mLoadedProductId; // PRODID string loaded from calendar file
diff --git a/libkcal/calhelper.cpp b/libkcal/calhelper.cpp
new file mode 100644
index 000000000..cae5c102f
--- /dev/null
+++ b/libkcal/calhelper.cpp
@@ -0,0 +1,167 @@
+/*
+ This file is part of the kcal library.
+
+ Copyright (c) 2009-2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
+
+ 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+/**
+ @file
+ This file is part of the API for handling calendar data and provides
+ static convenience functions for making decisions about calendar data.
+
+ @brief
+ Provides methods for making decisions about calendar data.
+
+ @author Allen Winter \<allen@kdab.net\>
+*/
+
+#include "calhelper.h"
+#include "calendarresources.h"
+
+using namespace KCal;
+
+bool CalHelper::isMyKolabIncidence( Calendar *calendar, Incidence *incidence )
+{
+ CalendarResources *cal = dynamic_cast<CalendarResources*>( calendar );
+ if ( !cal || !incidence ) {
+ return true;
+ }
+
+ CalendarResourceManager *manager = cal->resourceManager();
+ CalendarResourceManager::Iterator it;
+ for ( it = manager->begin(); it != manager->end(); ++it ) {
+ TQString subRes = (*it)->subresourceIdentifier( incidence );
+ if ( !subRes.isEmpty() && !subRes.contains( "/.INBOX.directory/" ) ) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool CalHelper::isMyCalendarIncidence( Calendar *calendar, Incidence *incidence )
+{
+ return isMyKolabIncidence( calendar, incidence );
+}
+
+Incidence *CalHelper::findMyCalendarIncidenceByUid( Calendar *calendar, const TQString &uid )
+{
+ // Determine if this incidence is in my calendar (and owned by me)
+ Incidence *existingIncidence = 0;
+ if ( calendar ) {
+ existingIncidence = calendar->incidence( uid );
+ if ( !isMyCalendarIncidence( calendar, existingIncidence ) ) {
+ existingIncidence = 0;
+ }
+ if ( !existingIncidence ) {
+ const Incidence::List list = calendar->incidences();
+ for ( Incidence::List::ConstIterator it = list.begin(), end = list.end(); it != end; ++it ) {
+ if ( (*it)->schedulingID() == uid && isMyCalendarIncidence( calendar, *it ) ) {
+ existingIncidence = *it;
+ break;
+ }
+ }
+ }
+ }
+ return existingIncidence;
+}
+
+bool CalHelper::usingGroupware( Calendar *calendar )
+{
+ CalendarResources *cal = dynamic_cast<CalendarResources*>( calendar );
+ if ( !cal ) {
+ return true;
+ }
+
+ CalendarResourceManager *manager = cal->resourceManager();
+ CalendarResourceManager::Iterator it;
+ for ( it = manager->begin(); it != manager->end(); ++it ) {
+ TQString res = (*it)->type();
+ if ( res == "imap" ) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CalHelper::hasMyWritableEventsFolders( const TQString &family )
+{
+ TQString myfamily = family;
+ if ( family.isEmpty() ) {
+ myfamily = "calendar";
+ }
+
+ CalendarResourceManager manager( myfamily );
+ manager.readConfig();
+
+ CalendarResourceManager::ActiveIterator it;
+ for ( it=manager.activeBegin(); it != manager.activeEnd(); ++it ) {
+ if ( (*it)->readOnly() ) {
+ continue;
+ }
+
+ const TQStringList subResources = (*it)->subresources();
+ if ( subResources.isEmpty() ) {
+ return true;
+ }
+
+ TQStringList::ConstIterator subIt;
+ for ( subIt=subResources.begin(); subIt != subResources.end(); ++subIt ) {
+ if ( !(*it)->subresourceActive( (*subIt) ) ) {
+ continue;
+ }
+ if ( (*it)->type() == "imap" || (*it)->type() == "kolab" ) {
+ if ( (*it)->subresourceType( ( *subIt ) ) == "todo" ||
+ (*it)->subresourceType( ( *subIt ) ) == "journal" ||
+ !(*subIt).contains( "/.INBOX.directory/" ) ) {
+ continue;
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+ResourceCalendar *CalHelper::incResourceCalendar( Calendar *calendar, Incidence *incidence )
+{
+ CalendarResources *cal = dynamic_cast<CalendarResources*>( calendar );
+ if ( !cal || !incidence ) {
+ return 0;
+ }
+
+ return cal->resource( incidence );
+}
+
+QPair<ResourceCalendar *, TQString> CalHelper::incSubResourceCalendar( Calendar *calendar,
+ Incidence *incidence )
+{
+ QPair<ResourceCalendar *, TQString> p( 0, TQString() );
+
+ CalendarResources *cal = dynamic_cast<CalendarResources*>( calendar );
+ if ( !cal || !incidence ) {
+ return p;
+ }
+
+ ResourceCalendar *res = cal->resource( incidence );
+
+ TQString subRes;
+ if ( res && res->canHaveSubresources() ) {
+ subRes = res->subresourceIdentifier( incidence );
+ }
+ p = qMakePair( res, subRes );
+ return p;
+}
diff --git a/libkcal/calhelper.h b/libkcal/calhelper.h
new file mode 100644
index 000000000..edebecf92
--- /dev/null
+++ b/libkcal/calhelper.h
@@ -0,0 +1,135 @@
+/*
+ This file is part of libkcal.
+
+ Copyright (c) 2009-2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
+
+ 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+/**
+ @file
+ This file is part of the API for handling calendar data and provides
+ static convenience functions for making decisions about calendar data.
+
+ @author Allen Winter \<allen@kdab.net\>
+*/
+
+#ifndef KCAL_CALHELPER_H
+#define KCAL_CALHELPER_H
+
+class TQString;
+#include <tqpair.h>
+
+namespace KCal {
+class Calendar;
+class Incidence;
+class ResourceCalendar;
+
+/**
+ @brief
+ Provides methods for making decisions about calendar data.
+*/
+namespace CalHelper {
+
+ /**
+ Determine if the specified incidence is likely a Kolab incidence
+ owned by the the user.
+
+ @param calendar is a pointer to a valid Calendar object.
+ @param incidence is a pointer to an Incidence object.
+
+ @return true if it is likely that the specified incidence belongs
+ to the user in their Kolab resource; false otherwise.
+ */
+ bool isMyKolabIncidence( Calendar *calendar, Incidence *incidence );
+
+ /**
+ Determine if the specified incidence is likely owned by the the user,
+ independent of the Resource type.
+
+ @param calendar is a pointer to a valid Calendar object.
+ @param incidence is a pointer to an Incidence object.
+
+ @return true if it is likely that the specified incidence belongs
+ to the user; false otherwise.
+ */
+ bool isMyCalendarIncidence( Calendar *calendar, Incidence *incidence );
+
+ /**
+ Searches for the specified Incidence by UID, returning an Incidence pointer
+ if and only if the found Incidence is owned by the user.
+
+ @param calendar is a pointer to a valid Calendar object.
+ @param Uid is a TQString containing an Incidence UID.
+
+ @return a pointer to the Incidence found; 0 if the Incidence is not found
+ or the Incidence is found but is not owned by the user.
+ */
+ Incidence *findMyCalendarIncidenceByUid( Calendar *calendar, const TQString &uid );
+
+ /**
+ Determines if the Calendar is using a Groupware resource type.
+ @param calendar is a pointer to a valid Calendar object.
+
+ @return true if the Calendar is using a known Groupware resource type;
+ false otherwise.
+ @since 4.4
+ */
+ bool usingGroupware( Calendar *calendar );
+
+ /**
+ Determines if the Calendar has any writable folders with Events content
+ that are owned by me.
+ @param family is the resource family name or "calendar" if empty.
+
+ @return true if the any such writable folders are found; false otherwise.
+ @since 4.5
+ */
+ bool hasMyWritableEventsFolders( const TQString &family );
+
+ /**
+ Returns the ResourceCalendar where the Incidence is stored, if any.
+ @param calendar is a pointer to a valid Calendar object.
+ @param incidence is a pointer to an Incidence object.
+
+ @return a pointer to the ResourceCalendar where the Incidence is stored;
+ else 0 if none can be found.
+ @since 4.5
+ */
+ ResourceCalendar *incResourceCalendar( Calendar *calendar, Incidence *incidence );
+
+ /**
+ Returns the (ResourceCalendar, SubResourceCalendar) pair where the
+ Incidence is stored, if any.
+ @param calendar is a pointer to a valid Calendar object.
+ @param incidence is a pointer to an Incidence object.
+
+ @return a QPair containing a pointer to the Incidence's ResourceCalendar
+ in the 'first' element of the QPair and the SubResourceCalendar in the
+ 'second' element.
+
+ @note many resource types do not support subresources, so the 'second'
+ element will be an empty TQString in those situations.
+ @since 4.5
+ */
+ QPair<ResourceCalendar *, TQString> incSubResourceCalendar( Calendar *calendar,
+ Incidence *incidence );
+
+}
+
+}
+
+#endif
+
diff --git a/libkcal/calselectdialog.cpp b/libkcal/calselectdialog.cpp
new file mode 100644
index 000000000..9c346f483
--- /dev/null
+++ b/libkcal/calselectdialog.cpp
@@ -0,0 +1,101 @@
+/*
+ This file is part of libkcal.
+
+ Copyright (c) 2008 Kevin Ottens <ervin@kde.org>
+ Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
+
+ 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., 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 TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), 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
+ TQt. 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.
+*/
+/**
+ @file
+ This file is part of the API for handling calendar data and provides a
+ dialog for asking the user to select from a list of available calendars.
+
+ @brief
+ Calendar selector dialog.
+
+ @author Kevin Ottens \<ervin@kde.org\>
+ @author Allen Winter \<allen@kdab.net\>
+*/
+
+#include "calselectdialog.h"
+
+#include <tqlabel.h>
+#include <tqlayout.h>
+
+using namespace KCal;
+
+CalSelectDialog::CalSelectDialog( const TQString &caption, const TQString &label,
+ const TQStringList &list )
+ : KDialogBase( 0, 0, true, caption, Ok|Cancel, Ok, true )
+{
+ TQFrame *frame = makeMainWidget();
+ TQVBoxLayout *layout = new TQVBoxLayout( frame, 0, spacingHint() );
+
+ TQLabel *labelWidget = new TQLabel( label, frame );
+ layout->addWidget( labelWidget );
+
+ mListBox = new KListBox( frame );
+ mListBox->insertStringList( list );
+ mListBox->setSelected( 0, true );
+ mListBox->ensureCurrentVisible();
+ layout->addWidget( mListBox, 10 );
+
+ connect( mListBox, TQT_SIGNAL(doubleClicked(TQListBoxItem *)),
+ TQT_SLOT(slotOk()) );
+ connect( mListBox, TQT_SIGNAL(returnPressed(TQListBoxItem *)),
+ TQT_SLOT(slotOk()) );
+
+ mListBox->setFocus();
+
+ layout->addStretch();
+
+ setMinimumWidth( 320 );
+}
+
+TQString CalSelectDialog::getItem( const TQString &caption, const TQString &label,
+ const TQStringList &list )
+{
+ CalSelectDialog dlg( caption, label, list );
+
+ TQString result;
+ if ( dlg.exec() == Accepted ) {
+ result = dlg.mListBox->currentText();
+ }
+
+ return result;
+}
+
+void CalSelectDialog::closeEvent( TQCloseEvent *event )
+{
+ event->ignore();
+}
+
+void CalSelectDialog::reject()
+{
+}
+
diff --git a/libkcal/calselectdialog.h b/libkcal/calselectdialog.h
new file mode 100644
index 000000000..40b2811b4
--- /dev/null
+++ b/libkcal/calselectdialog.h
@@ -0,0 +1,69 @@
+/*
+ This file is part of libkcal.
+
+ Copyright (c) 2008 Kevin Ottens <ervin@kde.org>
+ Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
+
+ 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., 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 TQt library by Trolltech AS, Norway (or with modified versions
+ of TQt that use the same license as TQt), 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
+ TQt. 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.
+*/
+/**
+ @file
+ This file is part of the API for handling calendar data and provides a
+ dialog for asking the user to select from a list of available calendars.
+
+ @author Kevin Ottens \<ervin@kde.org\>
+ @author Allen Winter \<allen@kdab.net\>
+*/
+
+#ifndef CALSELECTDIALOG_H
+#define CALSELECTDIALOG_H
+
+#include <kdialogbase.h>
+
+namespace KCal {
+
+class CalSelectDialog : public KDialogBase
+{
+ private:
+ CalSelectDialog( const TQString &caption, const TQString &label,
+ const TQStringList &list );
+
+ public:
+ static TQString getItem( const TQString &caption, const TQString &label,
+ const TQStringList &list );
+
+ protected:
+ virtual void closeEvent( TQCloseEvent *event );
+ void reject();
+
+ private:
+ KListBox *mListBox;
+};
+
+}
+
+#endif
diff --git a/libkcal/comparisonvisitor.cpp b/libkcal/comparisonvisitor.cpp
new file mode 100644
index 000000000..79a61e2fc
--- /dev/null
+++ b/libkcal/comparisonvisitor.cpp
@@ -0,0 +1,107 @@
+/*
+ Copyright 2009 Ingo Klöcker <kloecker@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., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+#include "comparisonvisitor.h"
+#include "event.h"
+#include "freebusy.h"
+#include "journal.h"
+#include "todo.h"
+
+using namespace KCal;
+
+class ComparisonVisitor::Private
+{
+ public:
+ Private() : mReference( 0 ) {}
+
+ public:
+ const IncidenceBase *mReference;
+};
+
+ComparisonVisitor::ComparisonVisitor() : d( new Private() )
+{
+}
+
+ComparisonVisitor::~ComparisonVisitor()
+{
+ delete d;
+}
+
+bool ComparisonVisitor::compare( IncidenceBase *incidence, const IncidenceBase *reference )
+{
+ d->mReference = reference;
+
+ const bool result = incidence ? incidence->accept( *this ) : reference == 0;
+
+ d->mReference = 0;
+
+ return result;
+}
+
+bool ComparisonVisitor::visit( Event *event )
+{
+ Q_ASSERT( event != 0 );
+
+ const Event *refEvent = dynamic_cast<const Event*>( d->mReference );
+ if ( refEvent ) {
+ return *event == *refEvent;
+ } else {
+ // refEvent is no Event and thus cannot be equal to event
+ return false;
+ }
+}
+
+bool ComparisonVisitor::visit( Todo *todo )
+{
+ Q_ASSERT( todo != 0 );
+
+ const Todo *refTodo = dynamic_cast<const Todo*>( d->mReference );
+ if ( refTodo ) {
+ return *todo == *refTodo;
+ } else {
+ // refTodo is no Todo and thus cannot be equal to todo
+ return false;
+ }
+}
+
+bool ComparisonVisitor::visit( Journal *journal )
+{
+ Q_ASSERT( journal != 0 );
+
+ const Journal *refJournal = dynamic_cast<const Journal*>( d->mReference );
+ if ( refJournal ) {
+ return *journal == *refJournal;
+ } else {
+ // refJournal is no Journal and thus cannot be equal to journal
+ return false;
+ }
+}
+
+bool ComparisonVisitor::visit( FreeBusy *freebusy )
+{
+ Q_ASSERT( freebusy != 0 );
+
+ const FreeBusy *refFreeBusy = dynamic_cast<const FreeBusy*>( d->mReference );
+ if ( refFreeBusy ) {
+ return *freebusy == *refFreeBusy;
+ } else {
+ // refFreeBusy is no FreeBusy and thus cannot be equal to freebusy
+ return false;
+ }
+}
diff --git a/libkcal/comparisonvisitor.h b/libkcal/comparisonvisitor.h
new file mode 100644
index 000000000..0712f9c04
--- /dev/null
+++ b/libkcal/comparisonvisitor.h
@@ -0,0 +1,122 @@
+/*
+ Copyright 2009 Ingo Klöcker <kloecker@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., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+#ifndef KCAL_COMPARISONVISITOR_H
+#define KCAL_COMPARISONVISITOR_H
+
+#include "incidencebase.h"
+
+namespace KCal {
+
+/**
+ Helper for type correct comparison of incidences via pointers.
+
+ This class provides a way of correctly comparing one incidence to another,
+ given two IncidenceBase derived pointers. It effectively provides a virtual
+ comparison method which first type checks the two pointers to ensure they
+ reference the same incidence type, before performing the comparison.
+
+ Usage example:
+ @code
+ KCal::Incidence *incidence; // assume this is set somewhere else
+ KCal::Incidence *referenceIncidence; // assume this is set somewhere else
+
+ KCal::ComparisonVisitor visitor;
+
+ // compare
+ if ( visitor.compare( incidence, referenceIncidence ) ) {
+ // incidence and referenceIncidence point to identical incidences
+ }
+ @endcode
+
+ @author Ingo Klöcker <kloecker@kde.org>
+ */
+class ComparisonVisitor : public IncidenceBase::Visitor
+{
+ public:
+ /**
+ Creates a visitor instance.
+ */
+ ComparisonVisitor();
+
+ /**
+ Destroys the instance.
+ */
+ virtual ~ComparisonVisitor();
+
+ /**
+ Compares the incidence referenced by @p incidence to the incidence
+ referenced by @p reference. Returns true, if the incidence referenced
+ by @p incidence is identical to the incidence referenced by @p reference.
+ Also returns true, if @p incidence and @p reference are both @c 0.
+
+ Basically it is a virtual equivalent of
+ @code
+ *incidence == *reference
+ @endcode
+
+ @param incidence pointer to the incidence to compare with the reference incidence
+ @param reference pointer to the reference incidence
+
+ @return @c true if the two incidences are identical or both @c 0
+ */
+ bool compare( IncidenceBase *incidence, const IncidenceBase *reference );
+
+ /**
+ Compares the event referenced by @p event to the incidence passed to
+ compare().
+
+ @return @c true if the event is identical to the reference incidence
+ */
+ virtual bool visit( Event *event );
+
+ /**
+ Compares the todo referenced by @p todo to the incidence passed to
+ compare().
+
+ @return @c true if the todo is identical to the reference incidence
+ */
+ virtual bool visit( Todo *todo );
+
+ /**
+ Compares the journal referenced by @p journal to the incidence passed to
+ compare().
+
+ @return @c true if the journal is identical to the reference incidence
+ */
+ virtual bool visit( Journal *journal );
+
+ /**
+ Compares the freebusy object referenced by @p freebusy to the incidence passed to
+ compare().
+
+ @return @c true if the freebusy object is identical to the reference incidence
+ */
+ virtual bool visit( FreeBusy *freebusy );
+
+ private:
+ //@cond PRIVATE
+ class Private;
+ Private *const d;
+ //@endcond
+};
+
+}
+
+#endif // KCAL_COMPARISONVISITOR_H
diff --git a/libkcal/dndfactory.cpp b/libkcal/dndfactory.cpp
index 9f5292d1d..b94c1707b 100644
--- a/libkcal/dndfactory.cpp
+++ b/libkcal/dndfactory.cpp
@@ -23,6 +23,7 @@
#include <tqapplication.h>
#include <tqclipboard.h>
+#include <tqmap.h>
#include <kiconloader.h>
#include <kdebug.h>
@@ -40,11 +41,68 @@
using namespace KCal;
+class DndFactory::Private
+{
+ public:
+ Incidence * pasteIncidence( Incidence *inc,
+ const TQDate &newDate,
+ const TQTime *newTime = 0 )
+ {
+ if ( inc ) {
+ inc = inc->clone();
+ inc->recreate();
+ }
+
+ if ( inc && newDate.isValid() ) {
+ if ( inc->type() == "Event" ) {
+ Event *anEvent = static_cast<Event*>( inc );
+ // Calculate length of event
+ int daysOffset = anEvent->dtStart().date().daysTo(
+ anEvent->dtEnd().date() );
+ // new end date if event starts at the same time on the new day
+ TQDateTime endDate( newDate.addDays(daysOffset), anEvent->dtEnd().time() );
+
+ if ( newTime ) {
+ // additional offset for new time of day
+ int addSecsOffset( anEvent->dtStart().time().secsTo( *newTime ));
+ endDate=endDate.addSecs( addSecsOffset );
+ anEvent->setDtStart( TQDateTime( newDate, *newTime ) );
+ } else {
+ anEvent->setDtStart( TQDateTime( newDate, anEvent->dtStart().time() ) );
+ }
+ anEvent->setDtEnd( endDate );
+ } else if ( inc->type() == "Todo" ) {
+ Todo *anTodo = static_cast<Todo*>( inc );
+ if ( newTime ) {
+ anTodo->setDtDue( TQDateTime( newDate, *newTime ) );
+ } else {
+ anTodo->setDtDue( TQDateTime( newDate, anTodo->dtDue().time() ) );
+ }
+ } else if ( inc->type() == "Journal" ) {
+ Journal *anJournal = static_cast<Journal*>( inc );
+ if ( newTime ) {
+ anJournal->setDtStart( TQDateTime( newDate, *newTime ) );
+ } else {
+ anJournal->setDtStart( TQDateTime( newDate ) );
+ }
+ } else {
+ kdDebug(5850) << "Trying to paste unknown incidence of type " << inc->type() << endl;
+ }
+ }
+ return inc;
+ }
+};
+
DndFactory::DndFactory( Calendar *cal ) :
- mCalendar( cal )
+ mCalendar( cal ), d( new Private )
{
}
+DndFactory::~DndFactory()
+{
+ delete d;
+}
+
ICalDrag *DndFactory::createDrag( Incidence *incidence, TQWidget *owner )
{
CalendarLocal cal( mCalendar->timeZoneId() );
@@ -98,90 +156,111 @@ Todo *DndFactory::createDropTodo(TQDropEvent *de)
return 0;
}
-
void DndFactory::cutIncidence( Incidence *selectedInc )
{
- if ( copyIncidence( selectedInc ) ) {
- mCalendar->deleteIncidence( selectedInc );
- }
+ Incidence::List list;
+ list.append( selectedInc );
+ cutIncidences( list );
}
-bool DndFactory::copyIncidence( Incidence *selectedInc )
+bool DndFactory::cutIncidences( const Incidence::List &incidences )
{
- if ( !selectedInc )
+ if ( copyIncidences( incidences ) ) {
+ Incidence::List::ConstIterator it;
+ for ( it = incidences.constBegin(); it != incidences.constEnd(); ++it ) {
+ mCalendar->deleteIncidence( *it );
+ }
+ return true;
+ } else {
return false;
- QClipboard *cb = TQApplication::clipboard();
+ }
+}
+bool DndFactory::copyIncidences( const Incidence::List &incidences )
+{
+ QClipboard *cb = TQApplication::clipboard();
CalendarLocal cal( mCalendar->timeZoneId() );
- Incidence *inc = selectedInc->clone();
- cal.addIncidence( inc );
- cb->setData( new ICalDrag( &cal ) );
+ Incidence::List::ConstIterator it;
- return true;
+ for ( it = incidences.constBegin(); it != incidences.constEnd(); ++it ) {
+ if ( *it ) {
+ cal.addIncidence( ( *it )->clone() );
+ }
+ }
+
+ if ( cal.incidences().isEmpty() ) {
+ return false;
+ } else {
+ cb->setData( new ICalDrag( &cal ) );
+ return true;
+ }
}
-Incidence *DndFactory::pasteIncidence(const TQDate &newDate, const TQTime *newTime)
+bool DndFactory::copyIncidence( Incidence *selectedInc )
{
-// kdDebug(5800) << "DnDFactory::pasteEvent()" << endl;
+ Incidence::List list;
+ list.append( selectedInc );
+ return copyIncidences( list );
+}
+Incidence::List DndFactory::pasteIncidences( const TQDate &newDate, const TQTime *newTime )
+{
CalendarLocal cal( mCalendar->timeZoneId() );
-
QClipboard *cb = TQApplication::clipboard();
+ Incidence::List list;
if ( !ICalDrag::decode( cb->data(), &cal ) &&
!VCalDrag::decode( cb->data(), &cal ) ) {
kdDebug(5800) << "Can't parse clipboard" << endl;
- return 0;
+ return list;
}
- Incidence::List incList = cal.incidences();
- Incidence *inc = incList.first();
-
- if ( !incList.isEmpty() && inc ) {
- inc = inc->clone();
-
- inc->recreate();
-
- if ( inc->type() == "Event" ) {
-
- Event *anEvent = static_cast<Event*>( inc );
- // Calculate length of event
- int daysOffset = anEvent->dtStart().date().daysTo(
- anEvent->dtEnd().date() );
- // new end date if event starts at the same time on the new day
- TQDateTime endDate( newDate.addDays(daysOffset), anEvent->dtEnd().time() );
+ // All pasted incidences get new uids, must keep track of old uids,
+ // so we can update child's parents
+ TQMap<TQString,Incidence*> oldUidToNewInc;
+
+ Incidence::List::ConstIterator it;
+ const Incidence::List incs = cal.incidences();
+ for ( it = incs.constBegin(); it != incs.constEnd(); ++it ) {
+ Incidence *inc = d->pasteIncidence( *it, newDate, newTime );
+ if ( inc ) {
+ list.append( inc );
+ oldUidToNewInc[( *it )->uid()] = inc;
+ }
+ }
- if ( newTime ) {
- // additional offset for new time of day
- int addSecsOffset( anEvent->dtStart().time().secsTo( *newTime ));
- endDate=endDate.addSecs( addSecsOffset );
- anEvent->setDtStart( TQDateTime( newDate, *newTime ) );
- } else {
- anEvent->setDtStart( TQDateTime( newDate, anEvent->dtStart().time() ) );
- }
- anEvent->setDtEnd( endDate );
-
- } else if ( inc->type() == "Todo" ) {
- Todo *anTodo = static_cast<Todo*>( inc );
- if ( newTime ) {
- anTodo->setDtDue( TQDateTime( newDate, *newTime ) );
- } else {
- anTodo->setDtDue( TQDateTime( newDate, anTodo->dtDue().time() ) );
- }
- } else if ( inc->type() == "Journal" ) {
- Journal *anJournal = static_cast<Journal*>( inc );
- if ( newTime ) {
- anJournal->setDtStart( TQDateTime( newDate, *newTime ) );
- } else {
- anJournal->setDtStart( TQDateTime( newDate ) );
- }
+ // update relations
+ for ( it = list.constBegin(); it != list.constEnd(); ++it ) {
+ Incidence *inc = *it;
+ if ( oldUidToNewInc.contains( inc->relatedToUid() ) ) {
+ Incidence *parentInc = oldUidToNewInc[inc->relatedToUid()];
+ inc->setRelatedToUid( parentInc->uid() );
+ inc->setRelatedTo( parentInc );
} else {
- kdDebug(5850) << "Trying to paste unknown incidence of type " << inc->type() << endl;
+ // not related to anything in the clipboard
+ inc->setRelatedToUid( TQString() );
+ inc->setRelatedTo( 0 );
}
+ }
- return inc;
+ return list;
+}
+
+Incidence *DndFactory::pasteIncidence( const TQDate &newDate, const TQTime *newTime )
+{
+ CalendarLocal cal( mCalendar->timeZoneId() );
+ QClipboard *cb = TQApplication::clipboard();
+ if ( !ICalDrag::decode( cb->data(), &cal ) &&
+ !VCalDrag::decode( cb->data(), &cal ) ) {
+ kdDebug(5800) << "Can't parse clipboard" << endl;
+ return 0;
}
- return 0;
+ Incidence::List incList = cal.incidences();
+ Incidence *inc = incList.isEmpty() ? 0 : incList.first();
+
+ Incidence *newInc = d->pasteIncidence( inc, newDate, newTime );
+ newInc->setRelatedTo( 0 );
+ return newInc;
}
diff --git a/libkcal/dndfactory.h b/libkcal/dndfactory.h
index 441a0a405..a8712f2b8 100644
--- a/libkcal/dndfactory.h
+++ b/libkcal/dndfactory.h
@@ -43,6 +43,7 @@ class LIBKCAL_EXPORT DndFactory
{
public:
DndFactory( Calendar * );
+ ~DndFactory();
/**
Create a drag object.
@@ -58,9 +59,20 @@ class LIBKCAL_EXPORT DndFactory
void cutIncidence( Incidence * );
/** copy the incidence to clipboard */
bool copyIncidence( Incidence * );
+
+ /** cuts a list of incidences to the clipboard */
+ bool cutIncidences( const Incidence::List &incidences );
+
+ /** copies a list of incidences to the clipboard */
+ bool copyIncidences( const Incidence::List &incidences );
+
/** pastes the event or todo and returns a pointer to the new incidence pasted. */
Incidence *pasteIncidence( const TQDate &, const TQTime *newTime = 0 );
+ /** pastes and returns the incidences from the clipboard
+ If no date and time are given, the incidences will be pasted at their original time */
+ Incidence::List pasteIncidences( const TQDate &newDate = TQDate(), const TQTime *newTime = 0 );
+
private:
Calendar *mCalendar;
diff --git a/libkcal/duration.cpp b/libkcal/duration.cpp
index 0dfd8781c..fdb5a3701 100644
--- a/libkcal/duration.cpp
+++ b/libkcal/duration.cpp
@@ -19,42 +19,160 @@
Boston, MA 02110-1301, USA.
*/
-#include <kdebug.h>
-#include <klocale.h>
-
#include "duration.h"
using namespace KCal;
Duration::Duration()
{
- mSeconds = 0;
+ mDuration = 0;
}
Duration::Duration( const TQDateTime &start, const TQDateTime &end )
{
- mSeconds = start.secsTo( end );
+ if ( start.time() == end.time() ) {
+ mDuration = start.daysTo( end );
+ mDaily = true;
+ } else {
+ mDuration = start.secsTo( end );
+ mDaily = false;
+ }
+}
+
+Duration::Duration( const TQDateTime &start, const TQDateTime &end, Type type )
+{
+ if ( type == Days ) {
+ mDuration = start.daysTo( end );
+ if ( mDuration ) {
+ // Round down to whole number of days if necessary
+ if ( start < end ) {
+ if ( end.time() < start.time() ) {
+ --mDuration;
+ }
+ } else {
+ if ( end.time() > start.time() ) {
+ ++mDuration;
+ }
+ }
+ }
+ mDaily = true;
+ } else {
+ mDuration = start.secsTo( end );
+ mDaily = false;
+ }
+}
+
+Duration::Duration( int duration, Type type )
+{
+ mDuration = duration;
+ mDaily = ( type == Days );
+}
+
+Duration::Duration( const Duration &duration )
+{
+ mDuration = duration.mDuration;
+ mDaily = duration.mDaily;
+}
+
+Duration &Duration::operator=( const Duration &duration )
+{
+ // check for self assignment
+ if ( &duration == this ) {
+ return *this;
+ }
+
+ mDuration = duration.mDuration;
+ mDaily = duration.mDaily;
+
+ return *this;
+}
+
+Duration::operator bool() const
+{
+ return mDuration;
+}
+
+bool Duration::operator<( const Duration &other ) const
+{
+ if ( mDaily == other.mDaily ) {
+ // guard against integer overflow for two daily durations
+ return mDuration < other.mDuration;
+ }
+ return seconds() < other.seconds();
}
-Duration::Duration( int seconds )
+bool Duration::operator==( const Duration &other ) const
{
- mSeconds = seconds;
+ // Note: daily and non-daily durations are always unequal, since a day's
+ // duration may differ from 24 hours if it happens to span a daylight saving
+ // time change.
+ return
+ mDuration == other.mDuration &&
+ mDaily == other.mDaily;
}
-bool KCal::operator==( const Duration& d1, const Duration& d2 )
+Duration &Duration::operator+=( const Duration &other )
{
- return ( d1.asSeconds() == d2.asSeconds() );
+ if ( mDaily == other.mDaily ) {
+ mDuration += other.mDuration;
+ } else if ( mDaily ) {
+ mDuration = mDuration * 86400 + other.mDuration;
+ mDaily = false;
+ } else {
+ mDuration += other.mDuration + 86400;
+ }
+ return *this;
}
+Duration Duration::operator-() const
+{
+ return Duration( -mDuration, ( mDaily ? Days : Seconds ) );
+}
+Duration &Duration::operator-=( const Duration &duration )
+{
+ return operator+=( -duration );
+}
+
+Duration &Duration::operator*=( int value )
+{
+ mDuration *= value;
+ return *this;
+}
+
+Duration &Duration::operator/=( int value )
+{
+ mDuration /= value;
+ return *this;
+}
TQDateTime Duration::end( const TQDateTime &start ) const
{
- return start.addSecs( mSeconds );
+ return mDaily ? start.addDays( mDuration )
+ : start.addSecs( mDuration );
+}
+Duration::Type Duration::type() const
+{
+ return mDaily ? Days : Seconds;
+}
+
+bool Duration::isDaily() const
+{
+ return mDaily;
}
int Duration::asSeconds() const
{
- return mSeconds;
+ return seconds();
+}
+
+int Duration::asDays() const
+{
+ return mDaily ? mDuration : mDuration / 86400;
+}
+
+int Duration::value() const
+{
+ return mDuration;
}
diff --git a/libkcal/duration.h b/libkcal/duration.h
index b4655d6c0..9cddf6958 100644
--- a/libkcal/duration.h
+++ b/libkcal/duration.h
@@ -33,27 +33,246 @@ namespace KCal {
class LIBKCAL_EXPORT Duration
{
public:
+ /**
+ The unit of time used to define the duration.
+ */
+ enum Type {
+ Seconds, /**< duration is a number of seconds */
+ Days /**< duration is a number of days */
+ };
+
+ /**
+ Constructs a duration of 0 seconds.
+ */
Duration();
+
+ /**
+ Constructs a duration from @p start to @p end.
+
+ If the time of day in @p start and @p end is equal, and their time
+ specifications (i.e. time zone etc.) are the same, the duration will be
+ set in terms of days. Otherwise, the duration will be set in terms of
+ seconds.
+
+ @param start is the time the duration begins.
+ @param end is the time the duration ends.
+ */
Duration( const TQDateTime &start, const TQDateTime &end );
- Duration( int seconds );
+ /**
+ Constructs a duration from @p start to @p end.
+
+ If @p type is Days, and the time of day in @p start's time zone differs
+ between @p start and @p end, the duration will be rounded down to the
+ nearest whole number of days.
+
+ @param start is the time the duration begins.
+ @param end is the time the duration ends.
+ @param type the unit of time to use (seconds or days)
+ */
+ Duration( const TQDateTime &start, const TQDateTime &end, Type type );
+
+ /**
+ Constructs a duration with a number of seconds or days.
+
+ @param duration the number of seconds or days in the duration
+ @param type the unit of time to use (seconds or days)
+ */
+ Duration( int duration, Type type = Seconds ); //krazy:exclude=explicit
+
+ /**
+ Constructs a duration by copying another duration object.
+
+ @param duration is the duration to copy.
+ */
+ Duration( const Duration &duration );
+
+ /**
+ Sets this duration equal to @p duration.
+
+ @param duration is the duration to copy.
+ */
+ Duration &operator=( const Duration &duration );
+
+ /**
+ Returns true if this duration is non-zero.
+ */
+ operator bool() const;
+
+ /**
+ Returns true if this duration is zero.
+ */
+ bool operator!() const { return !operator bool(); }
+
+ /**
+ Returns true if this duration is smaller than the @p other.
+ @param other is the other duration to compare.
+ */
+ bool operator<( const Duration &other ) const;
+
+ /**
+ Returns true if this duration is smaller than or equal to the @p other.
+ @param other is the other duration to compare.
+ */
+ bool operator<=( const Duration &other ) const
+ { return !other.operator<( *this ); }
+
+
+ /**
+ Returns true if this duration is greater than the @p other.
+ @param other is the other duration to compare.
+ */
+ bool operator>( const Duration &other ) const
+ { return other.operator<( *this ); }
+
+ /**
+ Returns true if this duration is greater than or equal to the @p other.
+ @param other is the other duration to compare.
+ */
+ bool operator>=( const Duration &other ) const
+ { return !operator<( other ); }
+
+ /**
+ Returns true if this duration is equal to the @p other.
+ Daily and non-daily durations are always considered unequal, since a
+ day's duration may differ from 24 hours if it happens to span a daylight
+ saving time change.
+ @param other the other duration to compare
+ */
+ bool operator==( const Duration &other ) const;
+
+ /**
+ Returns true if this duration is not equal to the @p other.
+ Daily and non-daily durations are always considered unequal, since a
+ day's duration may differ from 24 hours if it happens to span a daylight
+ saving time change.
+ @param other is the other duration to compare.
+ */
+ bool operator!=( const Duration &other ) const
+ { return !operator==( other ); }
+
+ /**
+ Adds another duration to this one.
+ If one is in terms of days and the other in terms of seconds,
+ the result is in terms of seconds.
+ @param other the other duration to add
+ */
+ Duration &operator+=( const Duration &other );
+
+ /**
+ Adds two durations.
+ If one is in terms of days and the other in terms of seconds,
+ the result is in terms of seconds.
+
+ @param other the other duration to add
+ @return combined duration
+ */
+ Duration operator+( const Duration &other ) const
+ { return Duration( *this ) += other; }
+
+ /**
+ Returns the negative of this duration.
+ */
+ Duration operator-() const;
+
+ /**
+ Subtracts another duration from this one.
+ If one is in terms of days and the other in terms of seconds,
+ the result is in terms of seconds.
+
+ @param other the other duration to subtract
+ */
+ Duration &operator-=( const Duration &other );
+
+ /**
+ Returns the difference between another duration and this.
+ If one is in terms of days and the other in terms of seconds,
+ the result is in terms of seconds.
+
+ @param other the other duration to subtract
+ @return difference in durations
+ */
+ Duration operator-( const Duration &other ) const
+ { return Duration( *this ) += other; }
+
+ /**
+ Multiplies this duration by a value.
+ @param value value to multiply by
+ */
+ Duration &operator*=( int value );
+
+ /**
+ Multiplies a duration by a value.
+
+ @param value value to multiply by
+ @return resultant duration
+ */
+ Duration operator*( int value ) const
+ { return Duration( *this ) *= value; }
+
+ /**
+ Divides this duration by a value.
+ @param value value to divide by
+ */
+ Duration &operator/=( int value );
+
+ /**
+ Divides a duration by a value.
+
+ @param value value to divide by
+ @return resultant duration
+ */
+ Duration operator/( int value ) const
+ { return Duration( *this ) /= value; }
+
+ /**
+ Computes a duration end time by adding the number of seconds or
+ days in the duration to the specified @p start time.
+
+ @param start is the start time.
+ @return end time.
+ */
TQDateTime end( const TQDateTime &start ) const;
+ /**
+ Returns the time units (seconds or days) used to specify the duration.
+ */
+ Type type() const;
+
+ /**
+ Returns whether the duration is specified in terms of days rather
+ than seconds.
+ */
+ bool isDaily() const;
+
+ /**
+ Returns the length of the duration in seconds.
+ */
int asSeconds() const;
+ /**
+ Returns the length of the duration in days. If the duration is
+ not an exact number of days, it is rounded down to return the
+ number of whole days.
+ */
+ int asDays() const;
+
+ /**
+ Returns the length of the duration in seconds or days.
+
+ @return if isDaily(), duration in days, else duration in seconds
+ */
+ int value() const;
+
private:
- int mSeconds;
+ int seconds() const { return mDaily ? mDuration * 86400 : mDuration; }
+ int mDuration;
+ bool mDaily;
class Private;
Private *d;
};
-bool operator==( const Duration&, const Duration& );
-inline bool operator!=( const Duration &d1, const Duration &d2 )
-{
- return !operator==( d1, d2 );
-}
-
}
#endif
diff --git a/libkcal/event.cpp b/libkcal/event.cpp
index 0f286e7f6..5bd3a8188 100644
--- a/libkcal/event.cpp
+++ b/libkcal/event.cpp
@@ -87,8 +87,8 @@ TQDateTime Event::dtEnd() const
if (hasEndDate()) return mDtEnd;
if (hasDuration()) return dtStart().addSecs(duration());
- kdDebug(5800) << "Warning! Event '" << summary()
- << "' has neither end date nor duration." << endl;
+ // It is valid for a VEVENT to be without a DTEND. See RFC2445, Sect4.6.1.
+ // Be careful to use Event::dateEnd() as appropriate due to this possibility.
return dtStart();
}
diff --git a/libkcal/event.h b/libkcal/event.h
index 39980556c..fed0e41a0 100644
--- a/libkcal/event.h
+++ b/libkcal/event.h
@@ -72,21 +72,24 @@ class LIBKCAL_EXPORT Event : public Incidence
/**
Return end time as string formatted according to the users locale
settings.
+ @deprecated use IncidenceFormatter::timeToString()
*/
- TQString dtEndTimeStr() const;
+ TQString KDE_DEPRECATED dtEndTimeStr() const;
/**
Return end date as string formatted according to the users locale
settings.
@param shortfmt if true return string in short format, if false return
long format
+ @deprecated use IncidenceFormatter::dateToString()
*/
- TQString dtEndDateStr( bool shortfmt = true ) const;
+ TQString KDE_DEPRECATED dtEndDateStr( bool shortfmt = true ) const;
/**
Return end date and time as string formatted according to the users locale
settings.
+ @deprecated use IncidenceFormatter::dateTimeToString()
*/
- TQString dtEndStr() const;
+ TQString KDE_DEPRECATED dtEndStr() const;
/**
Set whether the event has an end date/time.
diff --git a/libkcal/exceptions.cpp b/libkcal/exceptions.cpp
index 98d7153eb..99c804ddf 100644
--- a/libkcal/exceptions.cpp
+++ b/libkcal/exceptions.cpp
@@ -26,7 +26,7 @@
using namespace KCal;
-Exception::Exception(const TQString &message)
+Exception::Exception( const TQString &message )
{
mMessage = message;
}
@@ -37,13 +37,16 @@ Exception::~Exception()
TQString Exception::message()
{
- if (mMessage.isEmpty()) return i18n("%1 Error").arg(CalFormat::application());
- else return mMessage;
+ if ( mMessage.isEmpty() ) {
+ return i18n( "%1 Error" ).arg( CalFormat::application() );
+ } else {
+ return mMessage;
+ }
}
-ErrorFormat::ErrorFormat(ErrorCodeFormat code,const TQString &message) :
- Exception(message)
+ErrorFormat::ErrorFormat( ErrorCodeFormat code, const TQString &message )
+ : Exception( message )
{
mCode = code;
}
@@ -52,35 +55,45 @@ TQString ErrorFormat::message()
{
TQString message = "";
- switch (mCode) {
- case LoadError:
- message = i18n("Load Error");
- break;
- case SaveError:
- message = i18n("Save Error");
- break;
- case ParseErrorIcal:
- message = i18n("Parse Error in libical");
- break;
- case ParseErrorKcal:
- message = i18n("Parse Error in libkcal");
- break;
- case NoCalendar:
- message = i18n("No calendar component found.");
- break;
- case CalVersion1:
- message = i18n("vCalendar Version 1.0 detected.");
- break;
- case CalVersion2:
- message = i18n("iCalendar Version 2.0 detected.");
- break;
- case Restriction:
- message = i18n("Restriction violation");
- default:
- break;
+ switch ( mCode ) {
+ case LoadError:
+ message = i18n( "Load Error" );
+ break;
+ case SaveError:
+ message = i18n( "Save Error" );
+ break;
+ case ParseErrorIcal:
+ message = i18n( "Parse Error in libical" );
+ break;
+ case ParseErrorKcal:
+ message = i18n( "Parse Error in libkcal" );
+ break;
+ case NoCalendar:
+ message = i18n( "No calendar component found." );
+ break;
+ case CalVersion1:
+ message = i18n( "vCalendar Version 1.0 detected." );
+ break;
+ case CalVersion2:
+ message = i18n( "iCalendar Version 2.0 detected." );
+ break;
+ case CalVersionUnknown:
+ message = i18n( "Unknown calendar format detected." );
+ break;
+ case Restriction:
+ message = i18n( "Restriction violation" );
+ break;
+ case NoWritableFound:
+ message = i18n( "No writable resource found" );
+ break;
+ case UserCancel:
+ // no real error; the user canceled the operation
+ break;
}
- if (!mMessage.isEmpty()) message += ": " + mMessage;
+ if ( !mMessage.isEmpty() ) {
+ message += ": " + mMessage;
+ }
return message;
}
diff --git a/libkcal/exceptions.h b/libkcal/exceptions.h
index 1ae90d516..8bdf7fa0f 100644
--- a/libkcal/exceptions.h
+++ b/libkcal/exceptions.h
@@ -47,9 +47,9 @@ class Exception
/**
Return descriptive message of exception.
- */
+ */
virtual TQString message();
-
+
protected:
TQString mMessage;
@@ -64,18 +64,28 @@ class Exception
class ErrorFormat : public Exception
{
public:
- enum ErrorCodeFormat { LoadError, SaveError,
- ParseErrorIcal, ParseErrorKcal,
- NoCalendar,
- CalVersion1,CalVersion2,
- CalVersionUnknown,
- Restriction };
-
+ /**
+ The different types of Calendar format errors.
+ */
+ enum ErrorCodeFormat {
+ LoadError, /**< Load error */
+ SaveError, /**< Save error */
+ ParseErrorIcal, /**< Parse error in libical */
+ ParseErrorKcal, /**< Parse error in libkcal */
+ NoCalendar, /**< No calendar component found */
+ CalVersion1, /**< vCalendar v1.0 detected */
+ CalVersion2, /**< iCalendar v2.0 detected */
+ CalVersionUnknown, /**< Unknown calendar format detected */
+ Restriction, /**< Restriction violation */
+ NoWritableFound, /**< No writable resource is available */
+ UserCancel /**< User canceled the operation */
+ };
+
/**
Create format error exception.
*/
ErrorFormat( ErrorCodeFormat code, const TQString &message = TQString::null );
-
+
/**
Return format error message.
*/
@@ -84,7 +94,7 @@ class ErrorFormat : public Exception
Return format error code.
*/
ErrorCodeFormat errorCode();
-
+
private:
ErrorCodeFormat mCode;
diff --git a/libkcal/freebusy.cpp b/libkcal/freebusy.cpp
index 75d0e7db4..2935f4baf 100644
--- a/libkcal/freebusy.cpp
+++ b/libkcal/freebusy.cpp
@@ -222,3 +222,12 @@ void FreeBusy::merge( FreeBusy *freeBusy )
for ( it = periods.begin(); it != periods.end(); ++it )
addPeriod( (*it).start(), (*it).end() );
}
+
+bool FreeBusy::operator==( const FreeBusy &freebusy ) const
+{
+ return
+ static_cast<const IncidenceBase &>( *this ) == static_cast<const IncidenceBase &>( freebusy ) &&
+ dtEnd() == freebusy.dtEnd() &&
+ mCalendar == freebusy.mCalendar &&
+ mBusyPeriods == freebusy.mBusyPeriods;
+}
diff --git a/libkcal/freebusy.h b/libkcal/freebusy.h
index d87234f30..f736092df 100644
--- a/libkcal/freebusy.h
+++ b/libkcal/freebusy.h
@@ -47,7 +47,7 @@ class LIBKCAL_EXPORT FreeBusy : public IncidenceBase
FreeBusy( PeriodList busyPeriods );
~FreeBusy();
-
+
TQCString type() const { return "FreeBusy"; }
virtual TQDateTime dtEnd() const;
@@ -65,7 +65,14 @@ class LIBKCAL_EXPORT FreeBusy : public IncidenceBase
void sortList();
void merge( FreeBusy *freebusy );
-
+
+ /**
+ Compare this with @p freebusy for equality.
+
+ @param freebusy is the FreeBusy to compare.
+ */
+ bool operator==( const FreeBusy &freebusy ) const;
+
private:
bool accept( Visitor &v ) { return v.visit( this ); }
//This is used for creating a freebusy object for the current user
diff --git a/libkcal/htmlexport.cpp b/libkcal/htmlexport.cpp
index fd994fca2..c945b88f0 100644
--- a/libkcal/htmlexport.cpp
+++ b/libkcal/htmlexport.cpp
@@ -34,6 +34,7 @@
#include <libkcal/calendar.h>
#include <libkcal/event.h>
+#include <libkcal/incidenceformatter.h>
#include <libkcal/todo.h>
#ifndef KORG_NOKABC
@@ -184,20 +185,23 @@ void HtmlExport::createMonthView(TQTextStream *ts)
*ts << "</td></tr><tr><td valign=\"top\">";
- Event::List events = mCalendar->events( start,
- EventSortStartDate,
- SortDirectionAscending );
- if (events.count()) {
- *ts << "<table>";
- Event::List::ConstIterator it;
- for( it = events.begin(); it != events.end(); ++it ) {
+ // Only print events within the from-to range
+ if ( start >= fromDate() && start <= toDate() ) {
+ Event::List events = mCalendar->events( start,
+ EventSortStartDate,
+ SortDirectionAscending );
+ if (events.count()) {
+ *ts << "<table>";
+ Event::List::ConstIterator it;
+ for( it = events.begin(); it != events.end(); ++it ) {
if ( checkSecrecy( *it ) ) {
createEvent( ts, *it, start, false );
}
+ }
+ *ts << "</table>";
+ } else {
+ *ts << "&nbsp;";
}
- *ts << "</table>";
- } else {
- *ts << "&nbsp;";
}
*ts << "</td></tr></table></td>\n";
@@ -275,12 +279,16 @@ void HtmlExport::createEvent (TQTextStream *ts, Event *event,
if (event->isMultiDay() && (event->dtStart().date() != date)) {
*ts << " <td>&nbsp;</td>\n";
} else {
- *ts << " <td valign=\"top\">" << event->dtStartTimeStr() << "</td>\n";
+ *ts << " <td valign=\"top\">"
+ << IncidenceFormatter::timeToString( event->dtStart(), true )
+ << "</td>\n";
}
if (event->isMultiDay() && (event->dtEnd().date() != date)) {
*ts << " <td>&nbsp;</td>\n";
} else {
- *ts << " <td valign=\"top\">" << event->dtEndTimeStr() << "</td>\n";
+ *ts << " <td valign=\"top\">"
+ << IncidenceFormatter::timeToString( event->dtEnd(), true )
+ << "</td>\n";
}
} else {
*ts << " <td>&nbsp;</td><td>&nbsp;</td>\n";
@@ -459,7 +467,7 @@ void HtmlExport::createTodo (TQTextStream *ts,Todo *todo)
if (completed) *ts << " class=\"done\"";
*ts << ">\n";
if (todo->hasDueDate()) {
- *ts << " " << todo->dtDueDateStr() << "\n";
+ *ts << " " << IncidenceFormatter::dateToString( todo->dtDue( true ) ) << "\n";
} else {
*ts << " &nbsp;\n";
}
diff --git a/libkcal/icalformatimpl.cpp b/libkcal/icalformatimpl.cpp
index a1655409f..613d492e9 100644
--- a/libkcal/icalformatimpl.cpp
+++ b/libkcal/icalformatimpl.cpp
@@ -55,6 +55,7 @@ static TQDateTime ICalDate2TQDate(const icaltimetype& t)
return TQDateTime(TQDate(year,t.month,t.day), TQTime(t.hour,t.minute,t.second));
}
+/*
static void _dumpIcaltime( const icaltimetype& t)
{
kdDebug(5800) << "--- Y: " << t.year << " M: " << t.month << " D: " << t.day
@@ -64,6 +65,16 @@ static void _dumpIcaltime( const icaltimetype& t)
kdDebug(5800) << "--- isUtc: " << icaltime_is_utc( t )<< endl;
kdDebug(5800) << "--- zoneId: " << icaltimezone_get_tzid( const_cast<icaltimezone*>( t.zone ) )<< endl;
}
+*/
+
+static TQString quoteForParam( const TQString &text )
+{
+ TQString tmp = text;
+ tmp.remove( '"' );
+ if ( tmp.contains( ';' ) || tmp.contains( ':' ) || tmp.contains( ',' ) )
+ return tmp; // libical quotes in this case already, see icalparameter_as_ical_string()
+ return TQString::fromLatin1( "\"" ) + tmp + TQString::fromLatin1( "\"" );
+}
const int gSecondsPerMinute = 60;
const int gSecondsPerHour = gSecondsPerMinute * 60;
@@ -565,7 +576,7 @@ icalproperty *ICalFormatImpl::writeOrganizer( const Person &organizer )
icalproperty *p = icalproperty_new_organizer("MAILTO:" + organizer.email().utf8());
if (!organizer.name().isEmpty()) {
- icalproperty_add_parameter( p, icalparameter_new_cn(organizer.name().utf8()) );
+ icalproperty_add_parameter( p, icalparameter_new_cn(quoteForParam(organizer.name()).utf8()) );
}
// TODO: Write dir, sent-by and language
@@ -578,7 +589,7 @@ icalproperty *ICalFormatImpl::writeAttendee(Attendee *attendee)
icalproperty *p = icalproperty_new_attendee("mailto:" + attendee->email().utf8());
if (!attendee->name().isEmpty()) {
- icalproperty_add_parameter(p,icalparameter_new_cn(attendee->name().utf8()));
+ icalproperty_add_parameter(p,icalparameter_new_cn(quoteForParam(attendee->name()).utf8()));
}
@@ -649,14 +660,15 @@ icalproperty *ICalFormatImpl::writeAttendee(Attendee *attendee)
return p;
}
-icalproperty *ICalFormatImpl::writeAttachment(Attachment *att)
+icalproperty *ICalFormatImpl::writeAttachment( Attachment *att )
{
icalattach *attach;
- if (att->isUri())
- attach = icalattach_new_from_url( att->uri().utf8().data());
- else
- attach = icalattach_new_from_data ( (unsigned char *)att->data(), 0, 0);
- icalproperty *p = icalproperty_new_attach(attach);
+ if ( att->isUri() ) {
+ attach = icalattach_new_from_url( att->uri().utf8().data() );
+ } else {
+ attach = icalattach_new_from_data ( (unsigned char *)att->data(), 0, 0 );
+ }
+ icalproperty *p = icalproperty_new_attach( attach );
if ( !att->mimeType().isEmpty() ) {
icalproperty_add_parameter( p,
@@ -853,7 +865,7 @@ icalcomponent *ICalFormatImpl::writeAlarm(Alarm *alarm)
for (TQValueList<Person>::Iterator ad = addresses.begin(); ad != addresses.end(); ++ad) {
icalproperty *p = icalproperty_new_attendee("MAILTO:" + (*ad).email().utf8());
if (!(*ad).name().isEmpty()) {
- icalproperty_add_parameter(p,icalparameter_new_cn((*ad).name().utf8()));
+ icalproperty_add_parameter(p,icalparameter_new_cn(quoteForParam((*ad).name()).utf8()));
}
icalcomponent_add_property(a,p);
}
@@ -892,7 +904,7 @@ icalcomponent *ICalFormatImpl::writeAlarm(Alarm *alarm)
offset = alarm->startOffset();
else
offset = alarm->endOffset();
- trigger.duration = icaldurationtype_from_int( offset.asSeconds() );
+ trigger.duration = writeICalDuration( offset.asSeconds() );
}
icalproperty *p = icalproperty_new_trigger(trigger);
if ( alarm->hasEndOffset() )
@@ -903,7 +915,7 @@ icalcomponent *ICalFormatImpl::writeAlarm(Alarm *alarm)
if (alarm->repeatCount()) {
icalcomponent_add_property(a,icalproperty_new_repeat(alarm->repeatCount()));
icalcomponent_add_property(a,icalproperty_new_duration(
- icaldurationtype_from_int(alarm->snoozeTime()*60)));
+ writeICalDuration(alarm->snoozeTime().value())));
}
// Custom properties
@@ -1000,9 +1012,9 @@ Event *ICalFormatImpl::readEvent( icalcomponent *vevent, icalcomponent *vtimezon
readIncidence( vevent, tz, event);
- icalproperty *p = icalcomponent_get_first_property(vevent,ICAL_ANY_PROPERTY);
+ icalproperty *p = icalcomponent_get_first_property( vevent, ICAL_ANY_PROPERTY );
-// int intvalue;
+ // int intvalue;
icaltimetype icaltime;
TQStringList categories;
@@ -1010,16 +1022,19 @@ Event *ICalFormatImpl::readEvent( icalcomponent *vevent, icalcomponent *vtimezon
bool dtEndProcessed = false;
- while (p) {
- icalproperty_kind kind = icalproperty_isa(p);
- switch (kind) {
+ while ( p ) {
+ icalproperty_kind kind = icalproperty_isa( p );
+ switch ( kind ) {
case ICAL_DTEND_PROPERTY: // start date and time
- icaltime = icalproperty_get_dtend(p);
- if (icaltime.is_date) {
+ icaltime = icalproperty_get_dtend( p );
+ if ( icaltime.is_date ) {
// End date is non-inclusive
TQDate endDate = readICalDate( icaltime ).addDays( -1 );
- if ( mCompat ) mCompat->fixFloatingEnd( endDate );
+ if ( mCompat ) {
+ mCompat->fixFloatingEnd( endDate );
+ }
+
if ( endDate < event->dtStart().date() ) {
endDate = event->dtStart().date();
}
@@ -1032,26 +1047,26 @@ Event *ICalFormatImpl::readEvent( icalcomponent *vevent, icalcomponent *vtimezon
break;
case ICAL_RELATEDTO_PROPERTY: // related event (parent)
- event->setRelatedToUid(TQString::fromUtf8(icalproperty_get_relatedto(p)));
- mEventsRelate.append(event);
+ event->setRelatedToUid( TQString::fromUtf8( icalproperty_get_relatedto( p ) ) );
+ mEventsRelate.append( event );
break;
-
case ICAL_TRANSP_PROPERTY: // Transparency
- transparency = icalproperty_get_transp(p);
- if( transparency == ICAL_TRANSP_TRANSPARENT )
+ transparency = icalproperty_get_transp( p );
+ if ( transparency == ICAL_TRANSP_TRANSPARENT ) {
event->setTransparency( Event::Transparent );
- else
+ } else {
event->setTransparency( Event::Opaque );
+ }
break;
default:
-// kdDebug(5800) << "ICALFormat::readEvent(): Unknown property: " << kind
-// << endl;
+ // kdDebug(5800) << "ICALFormat::readEvent(): Unknown property: " << kind
+ // << endl;
break;
}
- p = icalcomponent_get_next_property(vevent,ICAL_ANY_PROPERTY);
+ p = icalcomponent_get_next_property( vevent, ICAL_ANY_PROPERTY );
}
// according to rfc2445 the dtend shouldn't be written when it equals
@@ -1060,13 +1075,15 @@ Event *ICalFormatImpl::readEvent( icalcomponent *vevent, icalcomponent *vtimezon
event->setDtEnd( event->dtStart() );
}
- TQString msade = event->nonKDECustomProperty("X-MICROSOFT-CDO-ALLDAYEVENT");
- if (!msade.isEmpty()) {
- bool floats = (msade == TQString::fromLatin1("TRUE"));
+ const TQString msade = event->nonKDECustomProperty("X-MICROSOFT-CDO-ALLDAYEVENT");
+ if ( !msade.isEmpty() ) {
+ const bool floats = ( msade == TQString::fromLatin1("TRUE") );
event->setFloats(floats);
}
- if ( mCompat ) mCompat->fixEmptySummary( event );
+ if ( mCompat ) {
+ mCompat->fixEmptySummary( event );
+ }
return event;
}
@@ -1096,7 +1113,8 @@ FreeBusy *ICalFormatImpl::readFreeBusy(icalcomponent *vfreebusy)
freebusy->setDtEnd(readICalDateTime(p, icaltime));
break;
- case ICAL_FREEBUSY_PROPERTY: { //Any FreeBusy Times
+ case ICAL_FREEBUSY_PROPERTY: //Any FreeBusy Times
+ {
icalperiodtype icalperiod = icalproperty_get_freebusy(p);
TQDateTime period_start = readICalDateTime(p, icalperiod.start);
Period period;
@@ -1107,12 +1125,21 @@ FreeBusy *ICalFormatImpl::readFreeBusy(icalcomponent *vfreebusy)
Duration duration = readICalDuration( icalperiod.duration );
period = Period(period_start, duration);
}
- TQCString param = icalproperty_get_parameter_as_string( p, "X-SUMMARY" );
- period.setSummary( TQString::fromUtf8( KCodecs::base64Decode( param ) ) );
- param = icalproperty_get_parameter_as_string( p, "X-LOCATION" );
- period.setLocation( TQString::fromUtf8( KCodecs::base64Decode( param ) ) );
+ icalparameter *param = icalproperty_get_first_parameter( p, ICAL_X_PARAMETER );
+ while ( param ) {
+ if ( strncmp( icalparameter_get_xname( param ), "X-SUMMARY", 9 ) == 0 ) {
+ period.setSummary( TQString::fromUtf8(
+ KCodecs::base64Decode( icalparameter_get_xvalue( param ) ) ) );
+ }
+ if ( strncmp( icalparameter_get_xname( param ), "X-LOCATION", 10 ) == 0 ) {
+ period.setLocation( TQString::fromUtf8(
+ KCodecs::base64Decode( icalparameter_get_xvalue( param ) ) ) );
+ }
+ param = icalproperty_get_next_parameter( p, ICAL_X_PARAMETER );
+ }
periods.append( period );
- break;}
+ break;
+ }
default:
// kdDebug(5800) << "ICalFormatImpl::readFreeBusy(): Unknown property: "
@@ -1256,31 +1283,70 @@ Attachment *ICalFormatImpl::readAttachment(icalproperty *attach)
{
Attachment *attachment = 0;
- icalvalue_kind value_kind = icalvalue_isa(icalproperty_get_value(attach));
+ const char *p;
+ icalvalue *value = icalproperty_get_value( attach );
- if ( value_kind == ICAL_ATTACH_VALUE || value_kind == ICAL_BINARY_VALUE ) {
- icalattach *a = icalproperty_get_attach(attach);
-
- int isurl = icalattach_get_is_url (a);
- if (isurl == 0)
- attachment = new Attachment((const char*)icalattach_get_data(a));
- else {
- attachment = new Attachment(TQString::fromUtf8(icalattach_get_url(a)));
+ switch( icalvalue_isa( value ) ) {
+ case ICAL_ATTACH_VALUE:
+ {
+ icalattach *a = icalproperty_get_attach( attach );
+ if ( !icalattach_get_is_url( a ) ) {
+ p = (const char *)icalattach_get_data( a );
+ if ( p ) {
+ attachment = new Attachment( p );
+ }
+ } else {
+ p = icalattach_get_url( a );
+ if ( p ) {
+ attachment = new Attachment( TQString::fromUtf8( p ) );
+ }
+ }
+ break;
+ }
+ case ICAL_BINARY_VALUE:
+ {
+ icalattach *a = icalproperty_get_attach( attach );
+ p = (const char *)icalattach_get_data( a );
+ if ( p ) {
+ attachment = new Attachment( p );
}
+ break;
}
- else if ( value_kind == ICAL_URI_VALUE ) {
- attachment = new Attachment(TQString::fromUtf8(icalvalue_get_uri(icalproperty_get_value(attach))));
+ case ICAL_URI_VALUE:
+ p = icalvalue_get_uri( value );
+ attachment = new Attachment( TQString::fromUtf8( p ) );
+ break;
+ default:
+ break;
}
- icalparameter *p = icalproperty_get_first_parameter(attach, ICAL_FMTTYPE_PARAMETER);
- if (p && attachment)
- attachment->setMimeType(TQString(icalparameter_get_fmttype(p)));
+ if ( attachment ) {
+ icalparameter *p =
+ icalproperty_get_first_parameter( attach, ICAL_FMTTYPE_PARAMETER );
+ if ( p ) {
+ attachment->setMimeType( TQString( icalparameter_get_fmttype( p ) ) );
+ }
- p = icalproperty_get_first_parameter(attach,ICAL_X_PARAMETER);
- while (p) {
- if ( strncmp (icalparameter_get_xname(p), "X-LABEL", 7) == 0 )
- attachment->setLabel( icalparameter_get_xvalue(p) );
- p = icalproperty_get_next_parameter(attach, ICAL_X_PARAMETER);
+ p = icalproperty_get_first_parameter( attach, ICAL_X_PARAMETER );
+ while ( p ) {
+ TQString xname = TQString( icalparameter_get_xname( p ) ).upper();
+ TQString xvalue = TQString::fromUtf8( icalparameter_get_xvalue( p ) );
+ if ( xname == "X-CONTENT-DISPOSITION" ) {
+ attachment->setShowInline( xvalue.lower() == "inline" );
+ }
+ if ( xname == "X-LABEL" ) {
+ attachment->setLabel( xvalue );
+ }
+ p = icalproperty_get_next_parameter( attach, ICAL_X_PARAMETER );
+ }
+
+ p = icalproperty_get_first_parameter( attach, ICAL_X_PARAMETER );
+ while ( p ) {
+ if ( strncmp( icalparameter_get_xname( p ), "X-LABEL", 7 ) == 0 ) {
+ attachment->setLabel( TQString::fromUtf8( icalparameter_get_xvalue( p ) ) );
+ }
+ p = icalproperty_get_next_parameter( attach, ICAL_X_PARAMETER );
+ }
}
return attachment;
@@ -1482,32 +1548,48 @@ void ICalFormatImpl::readIncidenceBase(icalcomponent *parent,IncidenceBase *inci
{
icalproperty *p = icalcomponent_get_first_property(parent,ICAL_ANY_PROPERTY);
- while (p) {
- icalproperty_kind kind = icalproperty_isa(p);
+ bool uidProcessed = false;
+
+ while ( p ) {
+ icalproperty_kind kind = icalproperty_isa( p );
switch (kind) {
case ICAL_UID_PROPERTY: // unique id
- incidenceBase->setUid(TQString::fromUtf8(icalproperty_get_uid(p)));
+ uidProcessed = true;
+ incidenceBase->setUid( TQString::fromUtf8(icalproperty_get_uid( p ) ) );
break;
case ICAL_ORGANIZER_PROPERTY: // organizer
- incidenceBase->setOrganizer( readOrganizer(p));
+ incidenceBase->setOrganizer( readOrganizer( p ) );
break;
case ICAL_ATTENDEE_PROPERTY: // attendee
- incidenceBase->addAttendee(readAttendee(p));
+ incidenceBase->addAttendee( readAttendee( p ) );
break;
case ICAL_COMMENT_PROPERTY:
incidenceBase->addComment(
- TQString::fromUtf8(icalproperty_get_comment(p)));
+ TQString::fromUtf8( icalproperty_get_comment( p ) ) );
break;
default:
break;
}
- p = icalcomponent_get_next_property(parent,ICAL_ANY_PROPERTY);
+ p = icalcomponent_get_next_property( parent, ICAL_ANY_PROPERTY );
+ }
+
+ if ( !uidProcessed ) {
+ kdWarning() << "The incidence didn't have any UID! Report a bug "
+ << "to the application that generated this file."
+ << endl;
+
+ // Our in-memory incidence has a random uid generated in Event's ctor.
+ // Make it empty so it matches what's in the file:
+ incidenceBase->setUid( TQString() );
+
+ // Otherwise, next time we read the file, this function will return
+ // an event with another random uid and we will have two events in the calendar.
}
// kpilot stuff
@@ -1736,7 +1818,7 @@ void ICalFormatImpl::readAlarm(icalcomponent *alarm,Incidence *incidence)
}
case ICAL_DURATION_PROPERTY: {
icaldurationtype duration = icalproperty_get_duration(p);
- ialarm->setSnoozeTime(icaldurationtype_as_int(duration)/60);
+ ialarm->setSnoozeTime( readICalDuration( duration ) );
break;
}
case ICAL_REPEAT_PROPERTY:
@@ -1937,13 +2019,16 @@ TQDate ICalFormatImpl::readICalDate(icaltimetype t)
icaldurationtype ICalFormatImpl::writeICalDuration(int seconds)
{
+ // should be able to use icaldurationtype_from_int(), except we know
+ // that some older tools do not properly support weeks. So we never
+ // set a week duration, only days
+
icaldurationtype d;
d.is_neg = (seconds<0)?1:0;
if (seconds<0) seconds = -seconds;
- d.weeks = seconds / gSecondsPerWeek;
- seconds %= gSecondsPerWeek;
+ d.weeks = 0;
d.days = seconds / gSecondsPerDay;
seconds %= gSecondsPerDay;
d.hours = seconds / gSecondsPerHour;
@@ -2001,7 +2086,7 @@ icalcomponent *ICalFormatImpl::createCalendarComponent(Calendar *cal)
// take a raw vcalendar (i.e. from a file on disk, clipboard, etc. etc.
// and break it down from its tree-like format into the dictionary format
// that is used internally in the ICalFormatImpl.
-bool ICalFormatImpl::populate( Calendar *cal, icalcomponent *calendar)
+bool ICalFormatImpl::populate( Calendar *cal, icalcomponent *calendar )
{
// this function will populate the caldict dictionary and other event
// lists. It turns vevents into Events and then inserts them.
@@ -2031,6 +2116,14 @@ bool ICalFormatImpl::populate( Calendar *cal, icalcomponent *calendar)
return false;
} else {
const char *version = icalproperty_get_version(p);
+ if ( !version ) {
+ kdDebug(5800) << "No VERSION property found" << endl;
+ mParent->setException( new ErrorFormat(
+ ErrorFormat::CalVersionUnknown,
+ i18n( "No VERSION property found" ) ) );
+ return false;
+ }
+
// kdDebug(5800) << "VCALENDAR version: '" << version << "'" << endl;
if (strcmp(version,"1.0") == 0) {
@@ -2071,7 +2164,11 @@ bool ICalFormatImpl::populate( Calendar *cal, icalcomponent *calendar)
TQString originalUid = todo->uid();
todo->setUid(originalUid + QString("-recur-%1").arg(todo->recurrenceID().toTime_t()));
if (!cal->todo(todo->uid())) {
- cal->addTodo(todo);
+ if ( !cal->addTodo( todo ) ) {
+ cal->endBatchAdding();
+ // If the user pressed cancel, return true, it's not an error.
+ return cal->exception() && cal->exception()->errorCode() == ErrorFormat::UserCancel;
+ }
if (!cal->event(originalUid)) {
printf("FIXME! [WARNING] Parent for child event does not yet exist!\n\r");
}
@@ -2085,7 +2182,11 @@ bool ICalFormatImpl::populate( Calendar *cal, icalcomponent *calendar)
}
else {
if (!cal->todo(todo->uid())) {
- cal->addTodo(todo);
+ if ( !cal->addTodo( todo ) ) {
+ cal->endBatchAdding();
+ // If the user pressed cancel, return true, it's not an error.
+ return cal->exception() && cal->exception()->errorCode() == ErrorFormat::UserCancel;
+ }
} else {
delete todo;
mTodosRelate.remove( todo );
@@ -2119,7 +2220,11 @@ bool ICalFormatImpl::populate( Calendar *cal, icalcomponent *calendar)
}
else {
if (!cal->event(event->uid())) {
- cal->addEvent(event);
+ if ( !cal->addEvent( event ) ) {
+ cal->endBatchAdding();
+ // If the user pressed cancel, return true, it's not an error.
+ return cal->exception() && cal->exception()->errorCode() == ErrorFormat::UserCancel;
+ }
} else {
delete event;
mEventsRelate.remove( event );
@@ -2153,7 +2258,11 @@ bool ICalFormatImpl::populate( Calendar *cal, icalcomponent *calendar)
}
else {
if (!cal->journal(journal->uid())) {
- cal->addJournal(journal);
+ if ( !cal->addJournal(journal) ) {
+ cal->endBatchAdding();
+ // If the user pressed cancel, return true, it's not an error.
+ return cal->exception() && cal->exception()->errorCode() == ErrorFormat::UserCancel;
+ }
} else {
delete journal;
}
@@ -2162,6 +2271,8 @@ bool ICalFormatImpl::populate( Calendar *cal, icalcomponent *calendar)
c = icalcomponent_get_next_component(calendar,ICAL_VJOURNAL_COMPONENT);
}
+ cal->endBatchAdding();
+
// Post-Process list of events with relations, put Event objects in relation
Event::List::ConstIterator eIt;
for ( eIt = mEventsRelate.begin(); eIt != mEventsRelate.end(); ++eIt ) {
diff --git a/libkcal/incidence.h b/libkcal/incidence.h
index 477b758c6..89d45b085 100644
--- a/libkcal/incidence.h
+++ b/libkcal/incidence.h
@@ -66,6 +66,36 @@ class LIBKCAL_EXPORT Incidence : public IncidenceBase, public Recurrence::Observ
};
/**
+ This class implements a visitor for adding an Incidence to a resource
+ plus subresource supporting addEvent(), addTodo() and addJournal() calls.
+ */
+ template<class T>
+ class AddSubResourceVisitor : public IncidenceBase::Visitor
+ {
+ public:
+ AddSubResourceVisitor( T *r, const TQString &subResource )
+ : mResource( r ), mSubResource( subResource ) {}
+
+ protected:
+ bool visit( Event *e )
+ {
+ return mResource->addEvent( e, mSubResource );
+ }
+ bool visit( Todo *t )
+ {
+ return mResource->addTodo( t, mSubResource );
+ }
+ bool visit( Journal *j )
+ {
+ return mResource->addJournal( j, mSubResource );
+ }
+
+ private:
+ T *mResource;
+ TQString mSubResource;
+ };
+
+ /**
This class implements a visitor for deleting an Incidence from a resource
supporting deleteEvent(), deleteTodo() and deleteJournal() calls.
*/
diff --git a/libkcal/incidencebase.cpp b/libkcal/incidencebase.cpp
index 2aeba830f..a8a6bdb05 100644
--- a/libkcal/incidencebase.cpp
+++ b/libkcal/incidencebase.cpp
@@ -59,6 +59,10 @@ IncidenceBase::IncidenceBase(const IncidenceBase &i) :
mSyncStatus = i.mSyncStatus;
mComments = i.mComments;
+ // The copied object is a new one, so it isn't observed by the observer
+ // of the original object.
+ mObservers.clear();
+
mAttendees.setAutoDelete( true );
}
@@ -404,7 +408,9 @@ void IncidenceBase::updated()
while( it.current() ) {
Observer *o = it.current();
++it;
- o->incidenceUpdated( this );
+ if ( o ) {
+ o->incidenceUpdated( this );
+ }
}
}
diff --git a/libkcal/incidencebase.h b/libkcal/incidencebase.h
index 72455b432..fa3a1a619 100644
--- a/libkcal/incidencebase.h
+++ b/libkcal/incidencebase.h
@@ -131,16 +131,28 @@ class LIBKCAL_EXPORT IncidenceBase : public CustomProperties
/** for setting the event's starting date/time with a TQDateTime. */
virtual void setDtStart( const TQDateTime &dtStart );
/** returns an event's starting date/time as a TQDateTime. */
+
virtual TQDateTime dtStart() const;
- /** returns an event's starting time as a string formatted according to the
- users locale settings */
- virtual TQString dtStartTimeStr() const;
- /** returns an event's starting date as a string formatted according to the
- users locale settings */
- virtual TQString dtStartDateStr( bool shortfmt = true ) const;
- /** returns an event's starting date and time as a string formatted according
- to the users locale settings */
- virtual TQString dtStartStr() const;
+
+ /**
+ returns an event's starting time as a string formatted according to the
+ users locale settings.
+ @deprecated use IncidenceFormatter::timeToString()
+ */
+ virtual KDE_DEPRECATED TQString dtStartTimeStr() const;
+
+ /**
+ returns an event's starting date as a string formatted according to the
+ users locale settings
+ @deprecated use IncidenceFormatter::dateToString()
+ */
+ virtual KDE_DEPRECATED TQString dtStartDateStr( bool shortfmt = true ) const;
+ /**
+ returns an event's starting date and time as a string formatted according
+ to the users locale settings
+ @deprecated use IncidenceFormatter::dateTimeToString()
+ */
+ virtual KDE_DEPRECATED TQString dtStartStr() const;
virtual void setDuration( int seconds );
int duration() const;
diff --git a/libkcal/incidenceformatter.cpp b/libkcal/incidenceformatter.cpp
index 618611712..cebdd0b16 100644
--- a/libkcal/incidenceformatter.cpp
+++ b/libkcal/incidenceformatter.cpp
@@ -3,6 +3,7 @@
Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
+ Copyright (c) 2009-2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -42,27 +43,28 @@
#include <kabc/stdaddressbook.h>
#include <kapplication.h>
-// #include <kdebug.h>
+#include <kemailsettings.h>
#include <klocale.h>
#include <kglobal.h>
#include <kiconloader.h>
+#include <kcalendarsystem.h>
+#include <kmimetype.h>
#include <tqbuffer.h>
#include <tqstylesheet.h>
#include <tqdatetime.h>
+#include <tqregexp.h>
#include <time.h>
-
using namespace KCal;
+/*******************
+ * General helpers
+ *******************/
-/*******************************************************************
- * Helper functions for the extensive display (event viewer)
- *******************************************************************/
-
-static TQString eventViewerAddLink( const TQString &ref, const TQString &text,
+static TQString htmlAddLink( const TQString &ref, const TQString &text,
bool newline = true )
{
TQString tmpStr( "<a href=\"" + ref + "\">" + text + "</a>" );
@@ -70,7 +72,7 @@ static TQString eventViewerAddLink( const TQString &ref, const TQString &text,
return tmpStr;
}
-static TQString eventViewerAddTag( const TQString & tag, const TQString & text )
+static TQString htmlAddTag( const TQString & tag, const TQString & text )
{
int numLineBreaks = text.contains( "\n" );
TQString str = "<" + tag + ">";
@@ -94,134 +96,299 @@ static TQString eventViewerAddTag( const TQString & tag, const TQString & text )
return tmpStr;
}
-static TQString linkPerson( const TQString& email, TQString name, TQString uid )
+static bool iamAttendee( Attendee *attendee )
+{
+ // Check if I'm this attendee
+
+ bool iam = false;
+ KEMailSettings settings;
+ TQStringList profiles = settings.profiles();
+ for( TQStringList::Iterator it=profiles.begin(); it!=profiles.end(); ++it ) {
+ settings.setProfile( *it );
+ if ( settings.getSetting( KEMailSettings::EmailAddress ) == attendee->email() ) {
+ iam = true;
+ break;
+ }
+ }
+ return iam;
+}
+
+static bool iamOrganizer( Incidence *incidence )
+{
+ // Check if I'm the organizer for this incidence
+
+ if ( !incidence ) {
+ return false;
+ }
+
+ bool iam = false;
+ KEMailSettings settings;
+ TQStringList profiles = settings.profiles();
+ for( TQStringList::Iterator it=profiles.begin(); it!=profiles.end(); ++it ) {
+ settings.setProfile( *it );
+ if ( settings.getSetting( KEMailSettings::EmailAddress ) == incidence->organizer().email() ) {
+ iam = true;
+ break;
+ }
+ }
+ return iam;
+}
+
+static bool senderIsOrganizer( Incidence *incidence, const TQString &sender )
+{
+ // Check if the specified sender is the organizer
+
+ if ( !incidence || sender.isEmpty() ) {
+ return true;
+ }
+ bool isorg = true;
+ TQString senderName, senderEmail;
+ if ( KPIM::getNameAndMail( sender, senderName, senderEmail ) ) {
+ // for this heuristic, we say the sender is the organizer if either the name or the email match.
+ if ( incidence->organizer().email() != senderEmail &&
+ incidence->organizer().name() != senderName ) {
+ isorg = false;
+ }
+ }
+ return isorg;
+}
+
+static TQString firstAttendeeName( Incidence *incidence, const TQString &defName )
+{
+ TQString name;
+ if ( !incidence ) {
+ return name;
+ }
+
+ Attendee::List attendees = incidence->attendees();
+ if( attendees.count() > 0 ) {
+ Attendee *attendee = *attendees.begin();
+ name = attendee->name();
+ if ( name.isEmpty() ) {
+ name = attendee->email();
+ }
+ if ( name.isEmpty() ) {
+ name = defName;
+ }
+ }
+ return name;
+}
+
+/*******************************************************************
+ * Helper functions for the extensive display (display viewer)
+ *******************************************************************/
+
+static TQString displayViewLinkPerson( const TQString& email, TQString name, TQString uid )
{
// Make the search, if there is an email address to search on,
// and either name or uid is missing
if ( !email.isEmpty() && ( name.isEmpty() || uid.isEmpty() ) ) {
KABC::AddressBook *add_book = KABC::StdAddressBook::self( true );
KABC::Addressee::List addressList = add_book->findByEmail( email );
- KABC::Addressee o = addressList.first();
- if ( !o.isEmpty() && addressList.size() < 2 ) {
- if ( name.isEmpty() )
- // No name set, so use the one from the addressbook
- name = o.formattedName();
- uid = o.uid();
- } else
- // Email not found in the addressbook. Don't make a link
- uid = TQString::null;
+ if ( !addressList.isEmpty() ) {
+ KABC::Addressee o = addressList.first();
+ if ( !o.isEmpty() && addressList.size() < 2 ) {
+ if ( name.isEmpty() ) {
+ // No name set, so use the one from the addressbook
+ name = o.formattedName();
+ }
+ uid = o.uid();
+ } else {
+ // Email not found in the addressbook. Don't make a link
+ uid = TQString::null;
+ }
+ }
}
- kdDebug(5850) << "formatAttendees: uid = " << uid << endl;
// Show the attendee
- TQString tmpString = "<li>";
+ TQString tmpString;
if ( !uid.isEmpty() ) {
// There is a UID, so make a link to the addressbook
- if ( name.isEmpty() )
+ if ( name.isEmpty() ) {
// Use the email address for text
- tmpString += eventViewerAddLink( "uid:" + uid, email );
- else
- tmpString += eventViewerAddLink( "uid:" + uid, name );
+ tmpString += htmlAddLink( "uid:" + uid, email );
+ } else {
+ tmpString += htmlAddLink( "uid:" + uid, name );
+ }
} else {
// No UID, just show some text
tmpString += ( name.isEmpty() ? email : name );
}
- tmpString += '\n';
// Make the mailto link
if ( !email.isEmpty() ) {
- KCal::Person person( name, email );
KURL mailto;
mailto.setProtocol( "mailto" );
- mailto.setPath( person.fullName() );
- tmpString += eventViewerAddLink( mailto.url(), TQString::null );
+ mailto.setPath( email );
+ const TQString iconPath =
+ KGlobal::iconLoader()->iconPath( "mail_new", KIcon::Small );
+ tmpString += "&nbsp;" +
+ htmlAddLink( mailto.url(),
+ "<img valign=\"top\" src=\"" + iconPath + "\">" );
}
- tmpString += "</li>\n";
return tmpString;
}
-static TQString eventViewerFormatAttendees( Incidence *event )
+static TQString displayViewFormatAttendeeRoleList( Incidence *incidence, Attendee::Role role )
{
TQString tmpStr;
- Attendee::List attendees = event->attendees();
- if ( attendees.count() ) {
-
- // Add organizer link
- tmpStr += eventViewerAddTag( "i", i18n("Organizer") );
- tmpStr += "<ul>";
- tmpStr += linkPerson( event->organizer().email(),
- event->organizer().name(), TQString::null );
- tmpStr += "</ul>";
-
- // Add attendees links
- tmpStr += eventViewerAddTag( "i", i18n("Attendees") );
- tmpStr += "<ul>";
- Attendee::List::ConstIterator it;
- for( it = attendees.begin(); it != attendees.end(); ++it ) {
- Attendee *a = *it;
- tmpStr += linkPerson( a->email(), a->name(), a->uid() );
- if ( !a->delegator().isEmpty() ) {
- tmpStr += i18n(" (delegated by %1)" ).arg( a->delegator() );
- }
- if ( !a->delegate().isEmpty() ) {
- tmpStr += i18n(" (delegated to %1)" ).arg( a->delegate() );
- }
+ Attendee::List::ConstIterator it;
+ Attendee::List attendees = incidence->attendees();
+
+ for ( it = attendees.begin(); it != attendees.end(); ++it ) {
+ Attendee *a = *it;
+ if ( a->role() != role ) {
+ // skip this role
+ continue;
+ }
+ if ( a->email() == incidence->organizer().email() ) {
+ // skip attendee that is also the organizer
+ continue;
}
- tmpStr += "</ul>";
+ tmpStr += displayViewLinkPerson( a->email(), a->name(), a->uid() );
+ if ( !a->delegator().isEmpty() ) {
+ tmpStr += i18n(" (delegated by %1)" ).arg( a->delegator() );
+ }
+ if ( !a->delegate().isEmpty() ) {
+ tmpStr += i18n(" (delegated to %1)" ).arg( a->delegate() );
+ }
+ tmpStr += "<br>";
+ }
+ if ( tmpStr.endsWith( "<br>" ) ) {
+ tmpStr.truncate( tmpStr.length() - 4 );
}
return tmpStr;
}
-static TQString eventViewerFormatAttachments( Incidence *i )
+static TQString displayViewFormatAttendees( Incidence *incidence )
+{
+ TQString tmpStr, str;
+
+ // Add organizer link
+ int attendeeCount = incidence->attendees().count();
+ if ( attendeeCount > 1 ||
+ ( attendeeCount == 1 &&
+ incidence->organizer().email() != incidence->attendees().first()->email() ) ) {
+ tmpStr += "<tr>";
+ tmpStr += "<td><b>" + i18n( "Organizer:" ) + "</b></td>";
+ tmpStr += "<td>" +
+ displayViewLinkPerson( incidence->organizer().email(),
+ incidence->organizer().name(),
+ TQString::null ) +
+ "</td>";
+ tmpStr += "</tr>";
+ }
+
+ // Add "chair"
+ str = displayViewFormatAttendeeRoleList( incidence, Attendee::Chair );
+ if ( !str.isEmpty() ) {
+ tmpStr += "<tr>";
+ tmpStr += "<td><b>" + i18n( "Chair:" ) + "</b></td>";
+ tmpStr += "<td>" + str + "</td>";
+ tmpStr += "</tr>";
+ }
+
+ // Add required participants
+ str = displayViewFormatAttendeeRoleList( incidence, Attendee::ReqParticipant );
+ if ( !str.isEmpty() ) {
+ tmpStr += "<tr>";
+ tmpStr += "<td><b>" + i18n( "Required Participants:" ) + "</b></td>";
+ tmpStr += "<td>" + str + "</td>";
+ tmpStr += "</tr>";
+ }
+
+ // Add optional participants
+ str = displayViewFormatAttendeeRoleList( incidence, Attendee::OptParticipant );
+ if ( !str.isEmpty() ) {
+ tmpStr += "<tr>";
+ tmpStr += "<td><b>" + i18n( "Optional Participants:" ) + "</b></td>";
+ tmpStr += "<td>" + str + "</td>";
+ tmpStr += "</tr>";
+ }
+
+ // Add observers
+ str = displayViewFormatAttendeeRoleList( incidence, Attendee::NonParticipant );
+ if ( !str.isEmpty() ) {
+ tmpStr += "<tr>";
+ tmpStr += "<td><b>" + i18n( "Observers:" ) + "</b></td>";
+ tmpStr += "<td>" + str + "</td>";
+ tmpStr += "</tr>";
+ }
+
+ return tmpStr;
+}
+
+static TQString displayViewFormatAttachments( Incidence *incidence )
{
TQString tmpStr;
- Attachment::List as = i->attachments();
- if ( as.count() > 0 ) {
- Attachment::List::ConstIterator it;
- for( it = as.begin(); it != as.end(); ++it ) {
- if ( (*it)->isUri() ) {
- TQString name;
- if ( (*it)->uri().startsWith( "kmail:" ) )
- name = i18n( "Show mail" );
- else
+ Attachment::List as = incidence->attachments();
+ Attachment::List::ConstIterator it;
+ uint count = 0;
+ for( it = as.begin(); it != as.end(); ++it ) {
+ count++;
+ if ( (*it)->isUri() ) {
+ TQString name;
+ if ( (*it)->uri().startsWith( "kmail:" ) ) {
+ name = i18n( "Show mail" );
+ } else {
+ if ( (*it)->label().isEmpty() ) {
name = (*it)->uri();
- tmpStr += eventViewerAddLink( (*it)->uri(), name );
- tmpStr += "<br>";
+ } else {
+ name = (*it)->label();
+ }
}
+ tmpStr += htmlAddLink( (*it)->uri(), name );
+ } else {
+ tmpStr += htmlAddLink( "ATTACH:" + incidence->uid() + ':' + (*it)->label(),
+ (*it)->label(), false );
+ }
+ if ( count < as.count() ) {
+ tmpStr += "<br>";
}
}
return tmpStr;
}
-/*
- FIXME:This function depends of kaddressbook. Is necessary a new
- type of event?
-*/
-static TQString eventViewerFormatBirthday( Event *event )
+static TQString displayViewFormatCategories( Incidence *incidence )
{
- if ( !event) return TQString::null;
- if ( event->customProperty("KABC","BIRTHDAY") != "YES" ) return TQString::null;
+ // We do not use Incidence::categoriesStr() since it does not have whitespace
+ return incidence->categories().join( ", " );
+}
+
+static TQString displayViewFormatCreationDate( Incidence *incidence )
+{
+ return i18n( "Creation date: %1" ).
+ arg( IncidenceFormatter::dateTimeToString( incidence->created(), false, true ) );
+}
+
+static TQString displayViewFormatBirthday( Event *event )
+{
+ if ( !event ) {
+ return TQString::null;
+ }
+ if ( event->customProperty("KABC","BIRTHDAY") != "YES" ) {
+ return TQString::null;
+ }
TQString uid = event->customProperty("KABC","UID-1");
TQString name = event->customProperty("KABC","NAME-1");
TQString email= event->customProperty("KABC","EMAIL-1");
- TQString tmpString = "<ul>";
- tmpString += linkPerson( email, name, uid );
+ TQString tmpStr = displayViewLinkPerson( email, name, uid );
if ( event->customProperty( "KABC", "ANNIVERSARY") == "YES" ) {
uid = event->customProperty("KABC","UID-2");
name = event->customProperty("KABC","NAME-2");
email= event->customProperty("KABC","EMAIL-2");
- tmpString += linkPerson( email, name, uid );
+ tmpStr += "<br>";
+ tmpStr += displayViewLinkPerson( email, name, uid );
}
- tmpString += "</ul>";
- return tmpString;
+ return tmpStr;
}
-static TQString eventViewerFormatHeader( Incidence *incidence )
+static TQString displayViewFormatHeader( Incidence *incidence )
{
TQString tmpStr = "<table><tr>";
@@ -230,32 +397,41 @@ static TQString eventViewerFormatHeader( Incidence *incidence )
tmpStr += "<td>";
if ( incidence->type() == "Event" ) {
- tmpStr += "<img src=\"" +
- KGlobal::iconLoader()->iconPath( "appointment", KIcon::Small ) +
- "\">";
+ TQString iconPath;
+ if ( incidence->customProperty( "KABC", "BIRTHDAY" ) == "YES" ) {
+ if ( incidence->customProperty( "KABC", "ANNIVERSARY" ) == "YES" ) {
+ iconPath =
+ KGlobal::iconLoader()->iconPath( "calendaranniversary", KIcon::Small );
+ } else {
+ iconPath = KGlobal::iconLoader()->iconPath( "calendarbirthday", KIcon::Small );
+ }
+ } else {
+ iconPath = KGlobal::iconLoader()->iconPath( "appointment", KIcon::Small );
+ }
+ tmpStr += "<img valign=\"top\" src=\"" + iconPath + "\">";
}
if ( incidence->type() == "Todo" ) {
- tmpStr += "<img src=\"" +
+ tmpStr += "<img valign=\"top\" src=\"" +
KGlobal::iconLoader()->iconPath( "todo", KIcon::Small ) +
"\">";
}
if ( incidence->type() == "Journal" ) {
- tmpStr += "<img src=\"" +
+ tmpStr += "<img valign=\"top\" src=\"" +
KGlobal::iconLoader()->iconPath( "journal", KIcon::Small ) +
"\">";
}
if ( incidence->isAlarmEnabled() ) {
- tmpStr += "<img src=\"" +
+ tmpStr += "<img valign=\"top\" src=\"" +
KGlobal::iconLoader()->iconPath( "bell", KIcon::Small ) +
"\">";
}
if ( incidence->doesRecur() ) {
- tmpStr += "<img src=\"" +
+ tmpStr += "<img valign=\"top\" src=\"" +
KGlobal::iconLoader()->iconPath( "recur", KIcon::Small ) +
"\">";
}
if ( incidence->isReadOnly() ) {
- tmpStr += "<img src=\"" +
+ tmpStr += "<img valign=\"top\" src=\"" +
KGlobal::iconLoader()->iconPath( "readonlyevent", KIcon::Small ) +
"\">";
}
@@ -263,245 +439,409 @@ static TQString eventViewerFormatHeader( Incidence *incidence )
tmpStr += "</td>";
}
- tmpStr += "<td>"
- + eventViewerAddTag( "u",
- eventViewerAddTag( "b", incidence->summary() ) )
- + "</td>";
- tmpStr += "</tr></table><br>";
+ tmpStr += "<td>";
+ tmpStr += "<b><u>" + incidence->summary() + "</u></b>";
+ tmpStr += "</td>";
+
+ tmpStr += "</tr></table>";
return tmpStr;
}
-static TQString eventViewerFormatEvent( Event *event )
+static TQString displayViewFormatEvent( Calendar *calendar, Event *event,
+ const TQDate &date )
{
- if ( !event ) return TQString::null;
- TQString tmpStr = eventViewerFormatHeader( event );
+ if ( !event ) {
+ return TQString::null;
+ }
+
+ TQString tmpStr = displayViewFormatHeader( event );
tmpStr += "<table>";
+ tmpStr += "<col width=\"25%\"/>";
+ tmpStr += "<col width=\"75%\"/>";
+
+ if ( calendar ) {
+ TQString calStr = IncidenceFormatter::resourceString( calendar, event );
+ if ( !calStr.isEmpty() ) {
+ tmpStr += "<tr>";
+ tmpStr += "<td><b>" + i18n( "Calendar:" ) + "</b></td>";
+ tmpStr += "<td>" + calStr + "</td>";
+ tmpStr += "</tr>";
+ }
+ }
+
+ if ( !event->location().isEmpty() ) {
+ tmpStr += "<tr>";
+ tmpStr += "<td><b>" + i18n( "Location:" ) + "</b></td>";
+ tmpStr += "<td>" + event->location() + "</td>";
+ tmpStr += "</tr>";
+ }
+
+ TQDateTime startDt = event->dtStart();
+ TQDateTime endDt = event->dtEnd();
+ if ( event->doesRecur() ) {
+ if ( date.isValid() ) {
+ TQDateTime dt( date, TQTime( 0, 0, 0 ) );
+ int diffDays = startDt.daysTo( dt );
+ dt = dt.addSecs( -1 );
+ startDt.setDate( event->recurrence()->getNextDateTime( dt ).date() );
+ if ( event->hasEndDate() ) {
+ endDt = endDt.addDays( diffDays );
+ if ( startDt > endDt ) {
+ startDt.setDate( event->recurrence()->getPreviousDateTime( dt ).date() );
+ endDt = startDt.addDays( event->dtStart().daysTo( event->dtEnd() ) );
+ }
+ }
+ }
+ }
tmpStr += "<tr>";
if ( event->doesFloat() ) {
if ( event->isMultiDay() ) {
- tmpStr += "<td align=\"right\"><b>" + i18n( "Time" ) + "</b></td>";
- tmpStr += "<td>" + i18n("<beginTime> - <endTime>","%1 - %2")
- .arg( event->dtStartDateStr() )
- .arg( event->dtEndDateStr() ) + "</td>";
+ tmpStr += "<td><b>" + i18n( "Date:" ) + "</b></td>";
+ tmpStr += "<td>" +
+ i18n("<beginDate> - <endDate>","%1 - %2").
+ arg( IncidenceFormatter::dateToString( startDt, false ) ).
+ arg( IncidenceFormatter::dateToString( endDt, false ) ) +
+ "</td>";
} else {
- tmpStr += "<td align=\"right\"><b>" + i18n( "Date" ) + "</b></td>";
- tmpStr += "<td>" + i18n("date as string","%1").arg( event->dtStartDateStr() ) + "</td>";
+ tmpStr += "<td><b>" + i18n( "Date:" ) + "</b></td>";
+ tmpStr += "<td>" +
+ i18n("date as string","%1").
+ arg( IncidenceFormatter::dateToString( startDt, false ) ) +
+ "</td>";
}
} else {
if ( event->isMultiDay() ) {
- tmpStr += "<td align=\"right\"><b>" + i18n( "Time" ) + "</b></td>";
- tmpStr += "<td>" + i18n("<beginTime> - <endTime>","%1 - %2")
- .arg( event->dtStartStr() )
- .arg( event->dtEndStr() ) + "</td>";
+ tmpStr += "<td><b>" + i18n( "Date:" ) + "</b></td>";
+ tmpStr += "<td>" +
+ i18n("<beginDate> - <endDate>","%1 - %2").
+ arg( IncidenceFormatter::dateToString( startDt, false ) ).
+ arg( IncidenceFormatter::dateToString( endDt, false ) ) +
+ "</td>";
} else {
- tmpStr += "<td align=\"right\"><b>" + i18n( "Time" ) + "</b></td>";
- if ( event->hasEndDate() && event->dtStart() != event->dtEnd()) {
- tmpStr += "<td>" + i18n("<beginTime> - <endTime>","%1 - %2")
- .arg( event->dtStartTimeStr() )
- .arg( event->dtEndTimeStr() ) + "</td>";
+ tmpStr += "<td><b>" + i18n( "Date:" ) + "</b></td>";
+ tmpStr += "<td>" +
+ i18n("date as string","%1").
+ arg( IncidenceFormatter::dateToString( startDt, false ) ) +
+ "</td>";
+
+ tmpStr += "</tr><tr>";
+ tmpStr += "<td><b>" + i18n( "Time:" ) + "</b></td>";
+ if ( event->hasEndDate() && startDt != endDt ) {
+ tmpStr += "<td>" +
+ i18n("<beginTime> - <endTime>","%1 - %2").
+ arg( IncidenceFormatter::timeToString( startDt, true ) ).
+ arg( IncidenceFormatter::timeToString( endDt, true ) ) +
+ "</td>";
} else {
- tmpStr += "<td>" + event->dtStartTimeStr() + "</td>";
+ tmpStr += "<td>" +
+ IncidenceFormatter::timeToString( startDt, true ) +
+ "</td>";
}
- tmpStr += "</tr><tr>";
- tmpStr += "<td align=\"right\"><b>" + i18n( "Date" ) + "</b></td>";
- tmpStr += "<td>" + i18n("date as string","%1")
- .arg( event->dtStartDateStr() ) + "</td>";
}
}
tmpStr += "</tr>";
- if ( event->customProperty("KABC","BIRTHDAY")== "YES" ) {
+ TQString durStr = IncidenceFormatter::durationString( event );
+ if ( !durStr.isEmpty() ) {
tmpStr += "<tr>";
- tmpStr += "<td align=\"right\"><b>" + i18n( "Birthday" ) + "</b></td>";
- tmpStr += "<td>" + eventViewerFormatBirthday( event ) + "</td>";
+ tmpStr += "<td><b>" + i18n( "Duration:" ) + "</b></td>";
+ tmpStr += "<td>" + durStr + "</td>";
tmpStr += "</tr>";
- tmpStr += "</table>";
- return tmpStr;
}
- if ( !event->description().isEmpty() ) {
+ if ( event->doesRecur() ) {
tmpStr += "<tr>";
- tmpStr += "<td align=\"right\"><b>" + i18n( "Description" ) + "</b></td>";
- tmpStr += "<td>" + eventViewerAddTag( "p", event->description() ) + "</td>";
+ tmpStr += "<td><b>" + i18n( "Recurrence:" ) + "</b></td>";
+ tmpStr += "<td>" +
+ IncidenceFormatter::recurrenceString( event ) +
+ "</td>";
tmpStr += "</tr>";
}
- if ( !event->location().isEmpty() ) {
+ if ( event->customProperty("KABC","BIRTHDAY")== "YES" ) {
tmpStr += "<tr>";
- tmpStr += "<td align=\"right\"><b>" + i18n( "Location" ) + "</b></td>";
- tmpStr += "<td>" + event->location() + "</td>";
+ if ( event->customProperty( "KABC", "ANNIVERSARY" ) == "YES" ) {
+ tmpStr += "<td><b>" + i18n( "Anniversary:" ) + "</b></td>";
+ } else {
+ tmpStr += "<td><b>" + i18n( "Birthday:" ) + "</b></td>";
+ }
+ tmpStr += "<td>" + displayViewFormatBirthday( event ) + "</td>";
tmpStr += "</tr>";
+ tmpStr += "</table>";
+ return tmpStr;
}
- if ( event->categories().count() > 0 ) {
+ if ( !event->description().isEmpty() ) {
tmpStr += "<tr>";
- tmpStr += "<td align=\"right\"><b>" + i18n( "1 Category", "%n Categories", event->categories().count() )+ "</b></td>";
- tmpStr += "<td>" + event->categoriesStr() + "</td>";
+ tmpStr += "<td><b>" + i18n( "Description:" ) + "</b></td>";
+ tmpStr += "<td>" + event->description() + "</td>";
tmpStr += "</tr>";
}
- if ( event->doesRecur() ) {
- TQDateTime dt =
- event->recurrence()->getNextDateTime( TQDateTime::currentDateTime() );
+ // TODO: print comments?
+
+ int reminderCount = event->alarms().count();
+ if ( reminderCount > 0 && event->isAlarmEnabled() ) {
tmpStr += "<tr>";
- tmpStr += "<td align=\"right\"><b>" + i18n( "Next on" ) + "</b></td>";
- if ( !event->doesFloat() ) {
- tmpStr += "<td>" +
- KGlobal::locale()->formatDateTime( dt, true ) + "</td>";
- } else {
- tmpStr += "<td>" +
- KGlobal::locale()->formatDate( dt.date(), true ) + "</td>";
- }
+ tmpStr += "<td><b>" +
+ i18n( "Reminder:", "%n Reminders:", reminderCount ) +
+ "</b></td>";
+ tmpStr += "<td>" + IncidenceFormatter::reminderStringList( event ).join( "<br>" ) + "</td>";
tmpStr += "</tr>";
}
- int attendeeCount = event->attendees().count();
- if ( attendeeCount > 0 ) {
- tmpStr += "<tr><td colspan=\"2\">";
- tmpStr += eventViewerFormatAttendees( event );
- tmpStr += "</td></tr>";
+ tmpStr += displayViewFormatAttendees( event );
+
+ int categoryCount = event->categories().count();
+ if ( categoryCount > 0 ) {
+ tmpStr += "<tr>";
+ tmpStr += "<td><b>" +
+ i18n( "Category:", "%n Categories:", categoryCount ) +
+ "</b></td>";
+ tmpStr += "<td>" + displayViewFormatCategories( event ) + "</td>";
+ tmpStr += "</tr>";
}
int attachmentCount = event->attachments().count();
if ( attachmentCount > 0 ) {
tmpStr += "<tr>";
- tmpStr += "<td align=\"right\"><b>" + i18n( "1 attachment", "%n attachments", attachmentCount )+ "</b></td>";
- tmpStr += "<td>" + eventViewerFormatAttachments( event ) + "</td>";
+ tmpStr += "<td><b>" +
+ i18n( "Attachment:", "%n Attachments:", attachmentCount ) +
+ "</b></td>";
+ tmpStr += "<td>" + displayViewFormatAttachments( event ) + "</td>";
tmpStr += "</tr>";
}
-
tmpStr += "</table>";
- tmpStr += "<em>" + i18n( "Creation date: %1.").arg(
- KGlobal::locale()->formatDateTime( event->created() , true ) ) + "</em>";
+
+ tmpStr += "<em>" + displayViewFormatCreationDate( event ) + "</em>";
+
return tmpStr;
}
-static TQString eventViewerFormatTodo( Todo *todo )
+static TQString displayViewFormatTodo( Calendar *calendar, Todo *todo,
+ const TQDate &date )
{
- if ( !todo ) return TQString::null;
- TQString tmpStr = eventViewerFormatHeader( todo );
+ if ( !todo ) {
+ return TQString::null;
+ }
+
+ TQString tmpStr = displayViewFormatHeader( todo );
tmpStr += "<table>";
+ tmpStr += "<col width=\"25%\"/>";
+ tmpStr += "<col width=\"75%\"/>";
+
+ if ( calendar ) {
+ TQString calStr = IncidenceFormatter::resourceString( calendar, todo );
+ if ( !calStr.isEmpty() ) {
+ tmpStr += "<tr>";
+ tmpStr += "<td><b>" + i18n( "Calendar:" ) + "</b></td>";
+ tmpStr += "<td>" + calStr + "</td>";
+ tmpStr += "</tr>";
+ }
+ }
- if ( todo->hasDueDate() ) {
+ if ( !todo->location().isEmpty() ) {
tmpStr += "<tr>";
- tmpStr += "<td align=\"right\"><b>" + i18n( "Due on" ) + "</b></td>";
- if ( !todo->doesFloat() ) {
- tmpStr += "<td>" +
- KGlobal::locale()->formatDateTime( todo->dtDue(), true ) +
- "</td>";
- } else {
- tmpStr += "<td>" +
- KGlobal::locale()->formatDate( todo->dtDue().date(), true ) +
- "</td>";
+ tmpStr += "<td><b>" + i18n( "Location:" ) + "</b></td>";
+ tmpStr += "<td>" + todo->location() + "</td>";
+ tmpStr += "</tr>";
+ }
+
+ if ( todo->hasStartDate() && todo->dtStart().isValid() ) {
+ TQDateTime startDt = todo->dtStart();
+ if ( todo->doesRecur() ) {
+ if ( date.isValid() ) {
+ startDt.setDate( date );
+ }
}
+ tmpStr += "<tr>";
+ tmpStr += "<td><b>" + i18n( "Start:" ) + "</b></td>";
+ tmpStr += "<td>" +
+ IncidenceFormatter::dateTimeToString( startDt,
+ todo->doesFloat(), false ) +
+ "</td>";
tmpStr += "</tr>";
}
- if ( !todo->description().isEmpty() ) {
+ if ( todo->hasDueDate() && todo->dtDue().isValid() ) {
+ TQDateTime dueDt = todo->dtDue();
+ if ( todo->doesRecur() ) {
+ if ( date.isValid() ) {
+ TQDateTime dt( date, TQTime( 0, 0, 0 ) );
+ dt = dt.addSecs( -1 );
+ dueDt.setDate( todo->recurrence()->getNextDateTime( dt ).date() );
+ }
+ }
tmpStr += "<tr>";
- tmpStr += "<td align=\"right\"><b>" + i18n( "Description" ) + "</b></td>";
- tmpStr += "<td>" + todo->description() + "</td>";
+ tmpStr += "<td><b>" + i18n( "Due:" ) + "</b></td>";
+ tmpStr += "<td>" +
+ IncidenceFormatter::dateTimeToString( dueDt,
+ todo->doesFloat(), false ) +
+ "</td>";
tmpStr += "</tr>";
}
- if ( !todo->location().isEmpty() ) {
+ TQString durStr = IncidenceFormatter::durationString( todo );
+ if ( !durStr.isEmpty() ) {
tmpStr += "<tr>";
- tmpStr += "<td align=\"right\"><b>" + i18n( "Location" ) + "</b></td>";
- tmpStr += "<td>" + todo->location() + "</td>";
+ tmpStr += "<td><b>" + i18n( "Duration:" ) + "</b></td>";
+ tmpStr += "<td>" + durStr + "</td>";
tmpStr += "</tr>";
}
- if ( todo->categories().count() > 0 ) {
+ if ( todo->doesRecur() ) {
tmpStr += "<tr>";
- tmpStr += "<td align=\"right\"><b>" + i18n( "1 Category", "%n Categories", todo->categories().count() )+ "</b></td>";
- tmpStr += "<td>" + todo->categoriesStr() + "</td>";
+ tmpStr += "<td><b>" + i18n( "Recurrence:" ) + "</b></td>";
+ tmpStr += "<td>" +
+ IncidenceFormatter::recurrenceString( todo ) +
+ "</td>";
tmpStr += "</tr>";
}
- tmpStr += "<tr>";
- tmpStr += "<td align=\"right\"><b>" + i18n( "Priority" ) + "</b></td>";
- if ( todo->priority() > 0 ) {
- tmpStr += "<td>" + TQString::number( todo->priority() ) + "</td>";
- } else {
- tmpStr += "<td>" + i18n( "Unspecified" ) + "</td>";
+ if ( !todo->description().isEmpty() ) {
+ tmpStr += "<tr>";
+ tmpStr += "<td><b>" + i18n( "Description:" ) + "</b></td>";
+ tmpStr += "<td>" + todo->description() + "</td>";
+ tmpStr += "</tr>";
}
- tmpStr += "</tr>";
- tmpStr += "<tr>";
- tmpStr += "<td align=\"right\"><b>" + i18n( "Completed" ) + "</b></td>";
- tmpStr += "<td>" + i18n( "%1 %" ).arg( todo->percentComplete() ) + "</td>";
- tmpStr += "</tr>";
+ // TODO: print comments?
- if ( todo->doesRecur() ) {
- TQDateTime dt =
- todo->recurrence()->getNextDateTime( TQDateTime::currentDateTime() );
+ int reminderCount = todo->alarms().count();
+ if ( reminderCount > 0 && todo->isAlarmEnabled() ) {
tmpStr += "<tr>";
- tmpStr += "<td align=\"right\"><b>" + i18n( "Next on" ) + "</b></td>";
- if ( !todo->doesFloat() ) {
- tmpStr += "<td>" +
- KGlobal::locale()->formatDateTime( dt, true ) + "</td>";
- } else {
- tmpStr += "<td>" +
- KGlobal::locale()->formatDate( dt.date(), true ) + "</td>";
- }
+ tmpStr += "<td><b>" +
+ i18n( "Reminder:", "%n Reminders:", reminderCount ) +
+ "</b></td>";
+ tmpStr += "<td>" + IncidenceFormatter::reminderStringList( todo ).join( "<br>" ) + "</td>";
+ tmpStr += "</tr>";
+ }
+
+ tmpStr += displayViewFormatAttendees( todo );
+
+ int categoryCount = todo->categories().count();
+ if ( categoryCount > 0 ) {
+ tmpStr += "<tr>";
+ tmpStr += "<td><b>" +
+ i18n( "Category:", "%n Categories:", categoryCount ) +
+ "</b></td>";
+ tmpStr += "<td>" + displayViewFormatCategories( todo ) + "</td>";
+ tmpStr += "</tr>";
+ }
+
+ if ( todo->priority() > 0 ) {
+ tmpStr += "<tr>";
+ tmpStr += "<td><b>" + i18n( "Priority:" ) + "</b></td>";
+ tmpStr += "<td>";
+ tmpStr += TQString::number( todo->priority() );
+ tmpStr += "</td>";
tmpStr += "</tr>";
}
- int attendeeCount = todo->attendees().count();
- if ( attendeeCount > 0 ) {
- tmpStr += "<tr><td colspan=\"2\">";
- tmpStr += eventViewerFormatAttendees( todo );
- tmpStr += "</td></tr>";
+ tmpStr += "<tr>";
+ if ( todo->isCompleted() ) {
+ tmpStr += "<td><b>" + i18n( "Completed:" ) + "</b></td>";
+ tmpStr += "<td>";
+ tmpStr += todo->completedStr();
+ } else {
+ tmpStr += "<td><b>" + i18n( "Percent Done:" ) + "</b></td>";
+ tmpStr += "<td>";
+ tmpStr += i18n( "%1%" ).arg( todo->percentComplete() );
}
+ tmpStr += "</td>";
+ tmpStr += "</tr>";
int attachmentCount = todo->attachments().count();
if ( attachmentCount > 0 ) {
tmpStr += "<tr>";
- tmpStr += "<td align=\"right\"><b>" + i18n( "1 attachment", "%n attachments", attachmentCount )+ "</b></td>";
- tmpStr += "<td>" + eventViewerFormatAttachments( todo ) + "</td>";
+ tmpStr += "<td><b>" +
+ i18n( "Attachment:", "Attachments:", attachmentCount ) +
+ "</b></td>";
+ tmpStr += "<td>" + displayViewFormatAttachments( todo ) + "</td>";
tmpStr += "</tr>";
}
tmpStr += "</table>";
- tmpStr += "<em>" + i18n( "Creation date: %1.").arg(
- KGlobal::locale()->formatDateTime( todo->created(), true ) ) + "</em>";
+
+ tmpStr += "<em>" + displayViewFormatCreationDate( todo ) + "</em>";
+
return tmpStr;
}
-static TQString eventViewerFormatJournal( Journal *journal )
+static TQString displayViewFormatJournal( Calendar *calendar, Journal *journal )
{
- if ( !journal ) return TQString::null;
+ if ( !journal ) {
+ return TQString::null;
+ }
- TQString tmpStr;
- if ( !journal->summary().isEmpty() ) {
- tmpStr += eventViewerAddTag( "u",
- eventViewerAddTag( "b", journal->summary() ) );
+ TQString tmpStr = displayViewFormatHeader( journal );
+
+ tmpStr += "<table>";
+ tmpStr += "<col width=\"25%\"/>";
+ tmpStr += "<col width=\"75%\"/>";
+
+ if ( calendar ) {
+ TQString calStr = IncidenceFormatter::resourceString( calendar, journal );
+ if ( !calStr.isEmpty() ) {
+ tmpStr += "<tr>";
+ tmpStr += "<td><b>" + i18n( "Calendar:" ) + "</b></td>";
+ tmpStr += "<td>" + calStr + "</td>";
+ tmpStr += "</tr>";
+ }
}
- tmpStr += eventViewerAddTag( "b", i18n("Journal for %1").arg( journal->dtStartDateStr( false ) ) );
- if ( !journal->description().isEmpty() )
- tmpStr += eventViewerAddTag( "p", journal->description() );
+
+ tmpStr += "<tr>";
+ tmpStr += "<td><b>" + i18n( "Date:" ) + "</b></td>";
+ tmpStr += "<td>" +
+ IncidenceFormatter::dateToString( journal->dtStart(), false ) +
+ "</td>";
+ tmpStr += "</tr>";
+
+ if ( !journal->description().isEmpty() ) {
+ tmpStr += "<tr>";
+ tmpStr += "<td><b>" + i18n( "Description:" ) + "</b></td>";
+ tmpStr += "<td>" + journal->description() + "</td>";
+ tmpStr += "</tr>";
+ }
+
+ int categoryCount = journal->categories().count();
+ if ( categoryCount > 0 ) {
+ tmpStr += "<tr>";
+ tmpStr += "<td><b>" +
+ i18n( "Category:", "%n Categories:", categoryCount ) +
+ "</b></td>";
+ tmpStr += "<td>" + displayViewFormatCategories( journal ) + "</td>";
+ tmpStr += "</tr>";
+ }
+ tmpStr += "</table>";
+
+ tmpStr += "<em>" + displayViewFormatCreationDate( journal ) + "</em>";
+
return tmpStr;
}
-static TQString eventViewerFormatFreeBusy( FreeBusy *fb )
+static TQString displayViewFormatFreeBusy( Calendar * /*calendar*/, FreeBusy *fb )
{
- if ( !fb ) return TQString::null;
+ if ( !fb ) {
+ return TQString::null;
+ }
+
+ TQString tmpStr = htmlAddTag( "h2",
+ htmlAddTag( "b",
+ i18n("Free/Busy information for %1").
+ arg( fb->organizer().fullName() ) ) );
- TQString tmpStr =
- eventViewerAddTag( "u",
- eventViewerAddTag( "b", i18n("Free/Busy information for %1")
- .arg( fb->organizer().fullName() ) ) );
- tmpStr += eventViewerAddTag( "i", i18n("Busy times in date range %1 - %2:")
- .arg( KGlobal::locale()->formatDate( fb->dtStart().date(), true ) )
- .arg( KGlobal::locale()->formatDate( fb->dtEnd().date(), true ) ) );
+ tmpStr += htmlAddTag( "h4", i18n("Busy times in date range %1 - %2:").
+ arg( IncidenceFormatter::dateToString( fb->dtStart(), true ) ).
+ arg( IncidenceFormatter::dateToString( fb->dtEnd(), true ) ) );
TQValueList<Period> periods = fb->busyPeriods();
- TQString text = eventViewerAddTag( "em", eventViewerAddTag( "b", i18n("Busy:") ) );
+ TQString text = htmlAddTag( "em", htmlAddTag( "b", i18n("Busy:") ) );
TQValueList<Period>::iterator it;
for ( it = periods.begin(); it != periods.end(); ++it ) {
Period per = *it;
@@ -519,91 +859,121 @@ static TQString eventViewerFormatFreeBusy( FreeBusy *fb )
if ( dur > 0 ) {
cont += i18n("1 second", "%n seconds", dur);
}
- text += i18n("startDate for duration", "%1 for %2")
- .arg( KGlobal::locale()->formatDateTime( per.start(), false ) )
- .arg( cont );
+ text += i18n("startDate for duration", "%1 for %2").
+ arg( IncidenceFormatter::dateTimeToString( per.start(), false, true ) ).
+ arg( cont );
text += "<br>";
} else {
if ( per.start().date() == per.end().date() ) {
- text += i18n("date, fromTime - toTime ", "%1, %2 - %3")
- .arg( KGlobal::locale()->formatDate( per.start().date() ) )
- .arg( KGlobal::locale()->formatTime( per.start().time() ) )
- .arg( KGlobal::locale()->formatTime( per.end().time() ) );
+ text += i18n("date, fromTime - toTime ", "%1, %2 - %3").
+ arg( IncidenceFormatter::dateToString( per.start().date(), true ) ).
+ arg( IncidenceFormatter::timeToString( per.start(), true ) ).
+ arg( IncidenceFormatter::timeToString( per.end(), true ) );
} else {
- text += i18n("fromDateTime - toDateTime", "%1 - %2")
- .arg( KGlobal::locale()->formatDateTime( per.start(), false ) )
- .arg( KGlobal::locale()->formatDateTime( per.end(), false ) );
+ text += i18n("fromDateTime - toDateTime", "%1 - %2").
+ arg( IncidenceFormatter::dateTimeToString( per.start(), false, true ) ).
+ arg( IncidenceFormatter::dateTimeToString( per.end(), false, true ) );
}
text += "<br>";
}
}
- tmpStr += eventViewerAddTag( "p", text );
+ tmpStr += htmlAddTag( "p", text );
return tmpStr;
}
class IncidenceFormatter::EventViewerVisitor : public IncidenceBase::Visitor
{
public:
- EventViewerVisitor() { mResult = ""; }
- bool act( IncidenceBase *incidence ) { return incidence->accept( *this ); }
+ EventViewerVisitor()
+ : mCalendar( 0 ), mResult( "" ) {}
+
+ bool act( Calendar *calendar, IncidenceBase *incidence, const TQDate &date )
+ {
+ mCalendar = calendar;
+ mDate = date;
+ mResult = "";
+ return incidence->accept( *this );
+ }
TQString result() const { return mResult; }
+
protected:
bool visit( Event *event )
{
- mResult = eventViewerFormatEvent( event );
+ mResult = displayViewFormatEvent( mCalendar, event, mDate );
return !mResult.isEmpty();
}
bool visit( Todo *todo )
{
- mResult = eventViewerFormatTodo( todo );
+ mResult = displayViewFormatTodo( mCalendar, todo, mDate );
return !mResult.isEmpty();
}
bool visit( Journal *journal )
{
- mResult = eventViewerFormatJournal( journal );
+ mResult = displayViewFormatJournal( mCalendar, journal );
return !mResult.isEmpty();
}
bool visit( FreeBusy *fb )
{
- mResult = eventViewerFormatFreeBusy( fb );
+ mResult = displayViewFormatFreeBusy( mCalendar, fb );
return !mResult.isEmpty();
}
protected:
+ Calendar *mCalendar;
+ TQDate mDate;
TQString mResult;
};
TQString IncidenceFormatter::extensiveDisplayString( IncidenceBase *incidence )
{
- if ( !incidence ) return TQString::null;
+ return extensiveDisplayStr( 0, incidence, TQDate() );
+}
+
+TQString IncidenceFormatter::extensiveDisplayStr( Calendar *calendar,
+ IncidenceBase *incidence,
+ const TQDate &date )
+{
+ if ( !incidence ) {
+ return TQString::null;
+ }
+
EventViewerVisitor v;
- if ( v.act( incidence ) ) {
+ if ( v.act( calendar, incidence, date ) ) {
return v.result();
- } else
+ } else {
return TQString::null;
+ }
}
-
-
-
-/*******************************************************************
- * Helper functions for the body part formatter of kmail
- *******************************************************************/
+/***********************************************************************
+ * Helper functions for the body part formatter of kmail (Invitations)
+ ***********************************************************************/
static TQString string2HTML( const TQString& str )
{
return TQStyleSheet::convertFromPlainText(str, TQStyleSheetItem::WhiteSpaceNormal);
}
+static TQString cleanHtml( const TQString &html )
+{
+ TQRegExp rx( "<body[^>]*>(.*)</body>" );
+ rx.setCaseSensitive( false );
+ rx.search( html );
+ TQString body = rx.cap( 1 );
+
+ return TQStyleSheet::escape( body.remove( TQRegExp( "<[^>]*>" ) ).stripWhiteSpace() );
+}
+
static TQString eventStartTimeStr( Event *event )
{
TQString tmp;
- if ( ! event->doesFloat() ) {
- tmp = i18n("%1: Start Date, %2: Start Time", "%1 %2")
- .arg( event->dtStartDateStr(), event->dtStartTimeStr() );
+ if ( !event->doesFloat() ) {
+ tmp = i18n( "%1: Start Date, %2: Start Time", "%1 %2" ).
+ arg( IncidenceFormatter::dateToString( event->dtStart(), true ),
+ IncidenceFormatter::timeToString( event->dtStart(), true ) );
} else {
- tmp = i18n("%1: Start Date", "%1 (time unspecified)")
- .arg( event->dtStartDateStr() );
+ tmp = i18n( "%1: Start Date", "%1 (all day)" ).
+ arg( IncidenceFormatter::dateToString( event->dtStart(), true ) );
}
return tmp;
}
@@ -611,16 +981,15 @@ static TQString eventStartTimeStr( Event *event )
static TQString eventEndTimeStr( Event *event )
{
TQString tmp;
- if ( event->hasEndDate() ) {
- if ( ! event->doesFloat() ) {
- tmp = i18n("%1: End Date, %2: End Time", "%1 %2")
- .arg( event->dtEndDateStr(), event->dtEndTimeStr() );
+ if ( event->hasEndDate() && event->dtEnd().isValid() ) {
+ if ( !event->doesFloat() ) {
+ tmp = i18n( "%1: End Date, %2: End Time", "%1 %2" ).
+ arg( IncidenceFormatter::dateToString( event->dtEnd(), true ),
+ IncidenceFormatter::timeToString( event->dtEnd(), true ) );
} else {
- tmp = i18n("%1: End Date", "%1 (time unspecified)")
- .arg( event->dtEndDateStr() );
+ tmp = i18n( "%1: End Date", "%1 (all day)" ).
+ arg( IncidenceFormatter::dateToString( event->dtEnd(), true ) );
}
- } else {
- tmp = i18n( "Unspecified" );
}
return tmp;
}
@@ -630,198 +999,495 @@ static TQString invitationRow( const TQString &cell1, const TQString &cell2 )
return "<tr><td>" + cell1 + "</td><td>" + cell2 + "</td></tr>\n";
}
-static TQString invitationsDetailsIncidence( Incidence *incidence )
+static Attendee *findDelegatedFromMyAttendee( Incidence *incidence )
+{
+ // Return the first attendee that was delegated-from me
+
+ Attendee *attendee = 0;
+ if ( !incidence ) {
+ return attendee;
+ }
+
+ KEMailSettings settings;
+ TQStringList profiles = settings.profiles();
+ for( TQStringList::Iterator it=profiles.begin(); it!=profiles.end(); ++it ) {
+ settings.setProfile( *it );
+
+ TQString delegatorName, delegatorEmail;
+ Attendee::List attendees = incidence->attendees();
+ Attendee::List::ConstIterator it2;
+ for ( it2 = attendees.begin(); it2 != attendees.end(); ++it2 ) {
+ Attendee *a = *it2;
+ KPIM::getNameAndMail( a->delegator(), delegatorName, delegatorEmail );
+ if ( settings.getSetting( KEMailSettings::EmailAddress ) == delegatorEmail ) {
+ attendee = a;
+ break;
+ }
+ }
+ }
+ return attendee;
+}
+
+static Attendee *findMyAttendee( Incidence *incidence )
+{
+ // Return the attendee for the incidence that is probably me
+
+ Attendee *attendee = 0;
+ if ( !incidence ) {
+ return attendee;
+ }
+
+ KEMailSettings settings;
+ TQStringList profiles = settings.profiles();
+ for( TQStringList::Iterator it=profiles.begin(); it!=profiles.end(); ++it ) {
+ settings.setProfile( *it );
+
+ Attendee::List attendees = incidence->attendees();
+ Attendee::List::ConstIterator it2;
+ for ( it2 = attendees.begin(); it2 != attendees.end(); ++it2 ) {
+ Attendee *a = *it2;
+ if ( settings.getSetting( KEMailSettings::EmailAddress ) == a->email() ) {
+ attendee = a;
+ break;
+ }
+ }
+ }
+ return attendee;
+}
+
+static Attendee *findAttendee( Incidence *incidence, const TQString &email )
+{
+ // Search for an attendee by email address
+
+ Attendee *attendee = 0;
+ if ( !incidence ) {
+ return attendee;
+ }
+
+ Attendee::List attendees = incidence->attendees();
+ Attendee::List::ConstIterator it;
+ for ( it = attendees.begin(); it != attendees.end(); ++it ) {
+ Attendee *a = *it;
+ if ( email == a->email() ) {
+ attendee = a;
+ break;
+ }
+ }
+ return attendee;
+}
+
+static bool rsvpRequested( Incidence *incidence )
+{
+ if ( !incidence ) {
+ return false;
+ }
+
+ //use a heuristic to determine if a response is requested.
+
+ bool rsvp = true; // better send superfluously than not at all
+ Attendee::List attendees = incidence->attendees();
+ Attendee::List::ConstIterator it;
+ for ( it = attendees.begin(); it != attendees.end(); ++it ) {
+ if ( it == attendees.begin() ) {
+ rsvp = (*it)->RSVP(); // use what the first one has
+ } else {
+ if ( (*it)->RSVP() != rsvp ) {
+ rsvp = true; // they differ, default
+ break;
+ }
+ }
+ }
+ return rsvp;
+}
+
+static TQString rsvpRequestedStr( bool rsvpRequested, const TQString &role )
+{
+ if ( rsvpRequested ) {
+ if ( role.isEmpty() ) {
+ return i18n( "Your response is requested" );
+ } else {
+ return i18n( "Your response as <b>%1</b> is requested" ).arg( role );
+ }
+ } else {
+ if ( role.isEmpty() ) {
+ return i18n( "No response is necessary" );
+ } else {
+ return i18n( "No response as <b>%1</b> is necessary" ).arg( role );
+ }
+ }
+}
+
+static TQString myStatusStr( Incidence *incidence )
+{
+ TQString ret;
+ Attendee *a = findMyAttendee( incidence );
+ if ( a &&
+ a->status() != Attendee::NeedsAction && a->status() != Attendee::Delegated ) {
+ ret = i18n( "(<b>Note</b>: the Organizer preset your response to <b>%1</b>)" ).
+ arg( Attendee::statusName( a->status() ) );
+ }
+ return ret;
+}
+
+static TQString invitationPerson( const TQString& email, TQString name, TQString uid )
{
+ // Make the search, if there is an email address to search on,
+ // and either name or uid is missing
+ if ( !email.isEmpty() && ( name.isEmpty() || uid.isEmpty() ) ) {
+ KABC::AddressBook *add_book = KABC::StdAddressBook::self( true );
+ KABC::Addressee::List addressList = add_book->findByEmail( email );
+ if ( !addressList.isEmpty() ) {
+ KABC::Addressee o = addressList.first();
+ if ( !o.isEmpty() && addressList.size() < 2 ) {
+ if ( name.isEmpty() ) {
+ // No name set, so use the one from the addressbook
+ name = o.formattedName();
+ }
+ uid = o.uid();
+ } else {
+ // Email not found in the addressbook. Don't make a link
+ uid = TQString::null;
+ }
+ }
+ }
+
+ // Show the attendee
+ TQString tmpString;
+ if ( !uid.isEmpty() ) {
+ // There is a UID, so make a link to the addressbook
+ if ( name.isEmpty() ) {
+ // Use the email address for text
+ tmpString += htmlAddLink( "uid:" + uid, email );
+ } else {
+ tmpString += htmlAddLink( "uid:" + uid, name );
+ }
+ } else {
+ // No UID, just show some text
+ tmpString += ( name.isEmpty() ? email : name );
+ }
+ tmpString += '\n';
+
+ // Make the mailto link
+ if ( !email.isEmpty() ) {
+ KCal::Person person( name, email );
+ KURL mailto;
+ mailto.setProtocol( "mailto" );
+ mailto.setPath( person.fullName() );
+ const TQString iconPath =
+ KGlobal::iconLoader()->iconPath( "mail_new", KIcon::Small );
+ tmpString += "&nbsp;" +
+ htmlAddLink( mailto.url(), "<img src=\"" + iconPath + "\">" )
+;
+ }
+ tmpString += "\n";
+
+ return tmpString;
+}
+
+static TQString invitationsDetailsIncidence( Incidence *incidence, bool noHtmlMode )
+{
+ // if description and comment -> use both
+ // if description, but no comment -> use the desc as the comment (and no desc)
+ // if comment, but no description -> use the comment and no description
+
TQString html;
- TQString descr = incidence->description();
+ TQString descr;
+ TQStringList comments;
+
+ if ( incidence->comments().isEmpty() ) {
+ if ( !incidence->description().isEmpty() ) {
+ // use description as comments
+ if ( !TQStyleSheet::mightBeRichText( incidence->description() ) ) {
+ comments << string2HTML( incidence->description() );
+ } else {
+ comments << incidence->description();
+ if ( noHtmlMode ) {
+ comments[0] = cleanHtml( comments[0] );
+ }
+ comments[0] = htmlAddTag( "p", comments[0] );
+ }
+ }
+ //else desc and comments are empty
+ } else {
+ // non-empty comments
+ TQStringList cl = incidence->comments();
+ uint i = 0;
+ for( TQStringList::Iterator it=cl.begin(); it!=cl.end(); ++it ) {
+ if ( !TQStyleSheet::mightBeRichText( *it ) ) {
+ comments.append( string2HTML( *it ) );
+ } else {
+ if ( noHtmlMode ) {
+ comments.append( cleanHtml( "<body>" + (*it) + "</body>" ) );
+ } else {
+ comments.append( *it );
+ }
+ }
+ i++;
+ }
+ if ( !incidence->description().isEmpty() ) {
+ // use description too
+ if ( !TQStyleSheet::mightBeRichText( incidence->description() ) ) {
+ descr = string2HTML( incidence->description() );
+ } else {
+ descr = incidence->description();
+ if ( noHtmlMode ) {
+ descr = cleanHtml( descr );
+ }
+ descr = htmlAddTag( "p", descr );
+ }
+ }
+ }
+
if( !descr.isEmpty() ) {
- html += "<br/><u>" + i18n("Description:")
- + "</u><table border=\"0\"><tr><td>&nbsp;</td><td>";
- html += string2HTML(descr) + "</td></tr></table>";
+ html += "<p>";
+ html += "<table border=\"0\" style=\"margin-top:4px;\">";
+ html += "<tr><td><center>" +
+ htmlAddTag( "u", i18n( "Description:" ) ) +
+ "</center></td></tr>";
+ html += "<tr><td>" + descr + "</td></tr>";
+ html += "</table>";
}
- TQStringList comments = incidence->comments();
+
if ( !comments.isEmpty() ) {
- html += "<br><u>" + i18n("Comments:")
- + "</u><table border=\"0\"><tr><td>&nbsp;</td><td><ul>";
- for ( uint i = 0; i < comments.count(); ++i )
- html += "<li>" + string2HTML( comments[i] ) + "</li>";
- html += "</ul></td></tr></table>";
+ html += "<p>";
+ html += "<table border=\"0\" style=\"margin-top:4px;\">";
+ html += "<tr><td><center>" +
+ htmlAddTag( "u", i18n( "Comments:" ) ) +
+ "</center></td></tr>";
+ html += "<tr><td>";
+ if ( comments.count() > 1 ) {
+ html += "<ul>";
+ for ( uint i=0; i < comments.count(); ++i ) {
+ html += "<li>" + comments[i] + "</li>";
+ }
+ html += "</ul>";
+ } else {
+ html += comments[0];
+ }
+ html += "</td></tr>";
+ html += "</table>";
}
return html;
}
-static TQString invitationDetailsEvent( Event* event )
+static TQString invitationDetailsEvent( Event* event, bool noHtmlMode )
{
- // Meeting details are formatted into an HTML table
- if ( !event )
+ // Invitation details are formatted into an HTML table
+ if ( !event ) {
return TQString::null;
-
- TQString html;
- TQString tmp;
+ }
TQString sSummary = i18n( "Summary unspecified" );
- if ( ! event->summary().isEmpty() ) {
- sSummary = string2HTML( event->summary() );
+ if ( !event->summary().isEmpty() ) {
+ if ( !TQStyleSheet::mightBeRichText( event->summary() ) ) {
+ sSummary = TQStyleSheet::escape( event->summary() );
+ } else {
+ sSummary = event->summary();
+ if ( noHtmlMode ) {
+ sSummary = cleanHtml( sSummary );
+ }
+ }
}
TQString sLocation = i18n( "Location unspecified" );
- if ( ! event->location().isEmpty() ) {
- sLocation = string2HTML( event->location() );
+ if ( !event->location().isEmpty() ) {
+ if ( !TQStyleSheet::mightBeRichText( event->location() ) ) {
+ sLocation = TQStyleSheet::escape( event->location() );
+ } else {
+ sLocation = event->location();
+ if ( noHtmlMode ) {
+ sLocation = cleanHtml( sLocation );
+ }
+ }
}
TQString dir = ( TQApplication::reverseLayout() ? "rtl" : "ltr" );
- html = TQString("<div dir=\"%1\">\n").arg(dir);
+ TQString html = TQString("<div dir=\"%1\">\n").arg(dir);
html += "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n";
- // Meeting summary & location rows
+ // Invitation summary & location rows
html += invitationRow( i18n( "What:" ), sSummary );
html += invitationRow( i18n( "Where:" ), sLocation );
- // Meeting Start Time Row
if (event->doesRecur() == true) {
html += invitationRow( i18n( "First Start Time:" ), eventStartTimeStr( event ) );
- }
- else {
- html += invitationRow( i18n( "Start Time:" ), eventStartTimeStr( event ) );
- }
-
- // Meeting End Time Row
- if (event->doesRecur() == true) {
html += invitationRow( i18n( "First End Time:" ), eventEndTimeStr( event ) );
}
- else {
- html += invitationRow( i18n( "End Time:" ), eventEndTimeStr( event ) );
- }
-
- // Meeting Duration Row
- if ( !event->doesFloat() && event->hasEndDate() ) {
- tmp = TQString::null;
- TQTime sDuration(0,0,0), t;
- int secs = event->dtStart().secsTo( event->dtEnd() );
- t = sDuration.addSecs( secs );
- if ( t.hour() > 0 ) {
- tmp += i18n( "1 hour ", "%n hours ", t.hour() );
- }
- if ( t.minute() > 0 ) {
- tmp += i18n( "1 minute ", "%n minutes ", t.minute() );
+// else {
+ // If a 1 day event
+ if ( event->dtStart().date() == event->dtEnd().date() ) {
+ html += invitationRow( i18n( "Date:" ),
+ IncidenceFormatter::dateToString( event->dtStart(), false ) );
+ if ( !event->doesFloat() ) {
+ html += invitationRow( i18n( "Time:" ),
+ IncidenceFormatter::timeToString( event->dtStart(), true ) +
+ " - " +
+ IncidenceFormatter::timeToString( event->dtEnd(), true ) );
+ }
+ } else {
+ html += invitationRow( i18n( "Starting date of an event", "From:" ),
+ IncidenceFormatter::dateToString( event->dtStart(), false ) );
+ if ( !event->doesFloat() ) {
+ html += invitationRow( i18n( "Starting time of an event", "At:" ),
+ IncidenceFormatter::timeToString( event->dtStart(), true ) );
+ }
+ if ( event->hasEndDate() ) {
+ html += invitationRow( i18n( "Ending date of an event", "To:" ),
+ IncidenceFormatter::dateToString( event->dtEnd(), false ) );
+ if ( !event->doesFloat() ) {
+ html += invitationRow( i18n( "Starting time of an event", "At:" ),
+ IncidenceFormatter::timeToString( event->dtEnd(), true ) );
+ }
+ } else {
+ html += invitationRow( i18n( "Ending date of an event", "To:" ),
+ i18n( "no end date specified" ) );
+ }
}
+// }
- html += invitationRow( i18n( "Duration:" ), tmp );
-
- if ( event->doesRecur() ) {
- TQString recurrence[]= {i18n("no recurrence", "None"),
- i18n("Minutely"), i18n("Hourly"), i18n("Daily"),
- i18n("Weekly"), i18n("Monthly Same Day"), i18n("Monthly Same Position"),
- i18n("Yearly"), i18n("Yearly"), i18n("Yearly")};
+ // Invitation Duration Row
+ QString durStr = IncidenceFormatter::durationString( event );
+ if ( !durStr.isEmpty() ) {
+ html += invitationRow( i18n( "Duration:" ), durStr );
+ }
- Recurrence *recur = event->recurrence();
- if (event->doesRecur() == true) {
- html += invitationRow( " ", " " );
- html += invitationRow( i18n( "Recurs:" ), recurrence[ recur->recurrenceType() ] );
- html += invitationRow( i18n("Frequency:"), i18n("%1").arg(event->recurrence()->frequency()) );
+ // Recurrence Information Rows
+ if ( event->doesRecur() ) {
+ Recurrence *recur = event->recurrence();
+ html += invitationRow( i18n( "Recurrence:" ), IncidenceFormatter::recurrenceString( event ) );
- if ( recur->duration() > 0 ) {
- if ( recur->duration() == 1 )
- html += invitationRow( i18n("Repeats:"), i18n("Once") );
- else
- html += invitationRow( i18n("Repeats:"), i18n("%1 times").arg(recur->duration()));
- } else {
- if ( recur->duration() != -1 ) {
- TQString endstr;
- if ( event->doesFloat() ) {
- endstr = KGlobal::locale()->formatDate( recur->endDate() );
- } else {
- endstr = KGlobal::locale()->formatDateTime( recur->endDateTime() );
- }
- html += invitationRow( i18n("Repeats until:"), endstr );
- } else {
- html += invitationRow( i18n("Repeats:"), i18n("Forever") );
- }
+ DateList exceptions = recur->exDates();
+ if (exceptions.isEmpty() == false) {
+ bool isFirstExRow;
+ isFirstExRow = true;
+ DateList::ConstIterator ex_iter;
+ for ( ex_iter = exceptions.begin(); ex_iter != exceptions.end(); ++ex_iter ) {
+ if (isFirstExRow == true) {
+ isFirstExRow = false;
+ html += invitationRow( i18n("Cancelled on:"), KGlobal::locale()->formatDate(* ex_iter ) );
}
-
- DateList exceptions = recur->exDates();
- if (exceptions.isEmpty() == false) {
- bool isFirstExRow;
- isFirstExRow = true;
- DateList::ConstIterator ex_iter;
- for ( ex_iter = exceptions.begin(); ex_iter != exceptions.end(); ++ex_iter ) {
- if (isFirstExRow == true) {
- isFirstExRow = false;
- html += invitationRow( i18n("Cancelled on:"), KGlobal::locale()->formatDate(* ex_iter ) );
- }
- else {
- html += invitationRow(" ", KGlobal::locale()->formatDate(* ex_iter ) );
- }
- }
+ else {
+ html += invitationRow(" ", KGlobal::locale()->formatDate(* ex_iter ) );
}
}
}
}
html += "</table>\n";
- html += invitationsDetailsIncidence( event );
+ html += invitationsDetailsIncidence( event, noHtmlMode );
html += "</div>\n";
return html;
}
-static TQString invitationDetailsTodo( Todo *todo )
+static TQString invitationDetailsTodo( Todo *todo, bool noHtmlMode )
{
// Task details are formatted into an HTML table
- if ( !todo )
+ if ( !todo ) {
return TQString::null;
+ }
TQString sSummary = i18n( "Summary unspecified" );
- TQString sDescr = i18n( "Description unspecified" );
- if ( ! todo->summary().isEmpty() ) {
- sSummary = todo->summary();
+ if ( !todo->summary().isEmpty() ) {
+ if ( !TQStyleSheet::mightBeRichText( todo->summary() ) ) {
+ sSummary = TQStyleSheet::escape( todo->summary() );
+ } else {
+ sSummary = todo->summary();
+ if ( noHtmlMode ) {
+ sSummary = cleanHtml( sSummary );
+ }
+ }
+ }
+
+ TQString sLocation = i18n( "Location unspecified" );
+ if ( !todo->location().isEmpty() ) {
+ if ( !TQStyleSheet::mightBeRichText( todo->location() ) ) {
+ sLocation = TQStyleSheet::escape( todo->location() );
+ } else {
+ sLocation = todo->location();
+ if ( noHtmlMode ) {
+ sLocation = cleanHtml( sLocation );
+ }
+ }
}
- if ( ! todo->description().isEmpty() ) {
- sDescr = todo->description();
+
+ TQString dir = ( TQApplication::reverseLayout() ? "rtl" : "ltr" );
+ TQString html = TQString("<div dir=\"%1\">\n").arg(dir);
+ html += "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n";
+
+ // Invitation summary & location rows
+ html += invitationRow( i18n( "What:" ), sSummary );
+ html += invitationRow( i18n( "Where:" ), sLocation );
+
+ if ( todo->hasStartDate() && todo->dtStart().isValid() ) {
+ html += invitationRow( i18n( "Start Date:" ),
+ IncidenceFormatter::dateToString( todo->dtStart(), false ) );
+ if ( !todo->doesFloat() ) {
+ html += invitationRow( i18n( "Start Time:" ),
+ IncidenceFormatter::timeToString( todo->dtStart(), false ) );
+ }
+ }
+ if ( todo->hasDueDate() && todo->dtDue().isValid() ) {
+ html += invitationRow( i18n( "Due Date:" ),
+ IncidenceFormatter::dateToString( todo->dtDue(), false ) );
+ if ( !todo->doesFloat() ) {
+ html += invitationRow( i18n( "Due Time:" ),
+ IncidenceFormatter::timeToString( todo->dtDue(), false ) );
+ }
+
+ } else {
+ html += invitationRow( i18n( "Due Date:" ), i18n( "Due Date: None", "None" ) );
}
- TQString html( "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n" );
- html += invitationRow( i18n( "Summary:" ), sSummary );
- html += invitationRow( i18n( "Description:" ), sDescr );
- html += "</table>\n";
- html += invitationsDetailsIncidence( todo );
+
+ html += "</table></div>\n";
+ html += invitationsDetailsIncidence( todo, noHtmlMode );
return html;
}
-static TQString invitationDetailsJournal( Journal *journal )
+static TQString invitationDetailsJournal( Journal *journal, bool noHtmlMode )
{
- if ( !journal )
+ if ( !journal ) {
return TQString::null;
+ }
TQString sSummary = i18n( "Summary unspecified" );
TQString sDescr = i18n( "Description unspecified" );
if ( ! journal->summary().isEmpty() ) {
sSummary = journal->summary();
+ if ( noHtmlMode ) {
+ sSummary = cleanHtml( sSummary );
+ }
}
if ( ! journal->description().isEmpty() ) {
sDescr = journal->description();
+ if ( noHtmlMode ) {
+ sDescr = cleanHtml( sDescr );
+ }
}
TQString html( "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n" );
html += invitationRow( i18n( "Summary:" ), sSummary );
- html += invitationRow( i18n( "Date:" ), journal->dtStartDateStr( false ) );
+ html += invitationRow( i18n( "Date:" ),
+ IncidenceFormatter::dateToString( journal->dtStart(), false ) );
html += invitationRow( i18n( "Description:" ), sDescr );
html += "</table>\n";
- html += invitationsDetailsIncidence( journal );
+ html += invitationsDetailsIncidence( journal, noHtmlMode );
return html;
}
-static TQString invitationDetailsFreeBusy( FreeBusy *fb )
+static TQString invitationDetailsFreeBusy( FreeBusy *fb, bool /*noHtmlMode*/ )
{
if ( !fb )
return TQString::null;
TQString html( "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n" );
html += invitationRow( i18n("Person:"), fb->organizer().fullName() );
- html += invitationRow( i18n("Start date:"), fb->dtStartDateStr() );
+ html += invitationRow( i18n("Start date:"),
+ IncidenceFormatter::dateToString( fb->dtStart(), true ) );
html += invitationRow( i18n("End date:"),
- KGlobal::locale()->formatDate( fb->dtEnd().date(), true ) );
+ KGlobal::locale()->formatDate( fb->dtEnd().date(), true ) );
html += "<tr><td colspan=2><hr></td></tr>\n";
html += "<tr><td colspan=2>Busy periods given in this free/busy object:</td></tr>\n";
@@ -868,259 +1534,524 @@ static TQString invitationDetailsFreeBusy( FreeBusy *fb )
return html;
}
-static TQString invitationHeaderEvent( Event *event, ScheduleMessage *msg )
+static bool replyMeansCounter( Incidence */*incidence*/ )
+{
+ return false;
+/**
+ see kolab/issue 3665 for an example of when we might use this for something
+
+ bool status = false;
+ if ( incidence ) {
+ // put code here that looks at the incidence and determines that
+ // the reply is meant to be a counter proposal. We think this happens
+ // with Outlook counter proposals, but we aren't sure how yet.
+ if ( condition ) {
+ status = true;
+ }
+ }
+ return status;
+*/
+}
+
+static TQString invitationHeaderEvent( Event *event, Incidence *existingIncidence,
+ ScheduleMessage *msg, const TQString &sender )
{
if ( !msg || !event )
return TQString::null;
+
switch ( msg->method() ) {
- case Scheduler::Publish:
- return i18n("This event has been published");
- case Scheduler::Request:
- if ( event->revision() > 0 )
- return i18n( "This meeting has been updated" );
- return i18n( "You have been invited to this meeting" );
- case Scheduler::Refresh:
- return i18n( "This invitation was refreshed" );
- case Scheduler::Cancel:
- return i18n( "This meeting has been canceled" );
- case Scheduler::Add:
- return i18n( "Addition to the meeting invitation" );
- case Scheduler::Reply: {
- Attendee::List attendees = event->attendees();
- if( attendees.count() == 0 ) {
- kdDebug(5850) << "No attendees in the iCal reply!\n";
- return TQString::null;
+ case Scheduler::Publish:
+ return i18n( "This invitation has been published" );
+ case Scheduler::Request:
+ if ( existingIncidence && event->revision() > 0 ) {
+ return i18n( "This invitation has been updated by the organizer %1" ).
+ arg( event->organizer().fullName() );
+ }
+ if ( iamOrganizer( event ) ) {
+ return i18n( "I created this invitation" );
+ } else {
+ TQString orgStr;
+ if ( !event->organizer().fullName().isEmpty() ) {
+ orgStr = event->organizer().fullName();
+ } else if ( !event->organizer().email().isEmpty() ) {
+ orgStr = event->organizer().email();
+ }
+ if ( senderIsOrganizer( event, sender ) ) {
+ if ( !orgStr.isEmpty() ) {
+ return i18n( "You received an invitation from %1" ).arg( orgStr );
+ } else {
+ return i18n( "You received an invitation" );
}
- if( attendees.count() != 1 )
- kdDebug(5850) << "Warning: attendeecount in the reply should be 1 "
- << "but is " << attendees.count() << endl;
- Attendee* attendee = *attendees.begin();
- TQString attendeeName = attendee->name();
- if ( attendeeName.isEmpty() )
- attendeeName = attendee->email();
- if ( attendeeName.isEmpty() )
- attendeeName = i18n( "Sender" );
-
- TQString delegatorName, dummy;
- KPIM::getNameAndMail( attendee->delegator(), delegatorName, dummy );
- if ( delegatorName.isEmpty() )
- delegatorName = attendee->delegator();
-
- switch( attendee->status() ) {
- case Attendee::NeedsAction:
- return i18n( "%1 indicates this invitation still needs some action" ).arg( attendeeName );
- case Attendee::Accepted:
- if ( delegatorName.isEmpty() )
- return i18n( "%1 accepts this meeting invitation" ).arg( attendeeName );
- return i18n( "%1 accepts this meeting invitation on behalf of %2" )
- .arg( attendeeName ).arg( delegatorName );
- case Attendee::Tentative:
- if ( delegatorName.isEmpty() )
- return i18n( "%1 tentatively accepts this meeting invitation" ).arg( attendeeName );
- return i18n( "%1 tentatively accepts this meeting invitation on behalf of %2" )
- .arg( attendeeName ).arg( delegatorName );
- case Attendee::Declined:
- if ( delegatorName.isEmpty() )
- return i18n( "%1 declines this meeting invitation" ).arg( attendeeName );
- return i18n( "%1 declines this meeting invitation on behalf of %2" )
- .arg( attendeeName ).arg( delegatorName );
- case Attendee::Delegated: {
- TQString delegate, dummy;
- KPIM::getNameAndMail( attendee->delegate(), delegate, dummy );
- if ( delegate.isEmpty() )
- delegate = attendee->delegate();
- if ( !delegate.isEmpty() )
- return i18n( "%1 has delegated this meeting invitation to %2" )
- .arg( attendeeName ) .arg( delegate );
- return i18n( "%1 has delegated this meeting invitation" ).arg( attendeeName );
- }
- case Attendee::Completed:
- return i18n( "This meeting invitation is now completed" );
- case Attendee::InProcess:
- return i18n( "%1 is still processing the invitation" ).arg( attendeeName );
- default:
- return i18n( "Unknown response to this meeting invitation" );
+ } else {
+ if ( !orgStr.isEmpty() ) {
+ return i18n( "You received an invitation from %1 as a representative of %2" ).
+ arg( sender, orgStr );
+ } else {
+ return i18n( "You received an invitation from %1 as the organizer's representative" ).
+ arg( sender );
}
- break; }
- case Scheduler::Counter:
- return i18n( "Sender makes this counter proposal" );
- case Scheduler::Declinecounter:
- return i18n( "Sender declines the counter proposal" );
- case Scheduler::NoMethod:
- return i18n("Error: iMIP message with unknown method: '%1'")
- .arg( msg->method() );
+ }
+ }
+ case Scheduler::Refresh:
+ return i18n( "This invitation was refreshed" );
+ case Scheduler::Cancel:
+ return i18n( "This invitation has been canceled" );
+ case Scheduler::Add:
+ return i18n( "Addition to the invitation" );
+ case Scheduler::Reply:
+ {
+ if ( replyMeansCounter( event ) ) {
+ return i18n( "%1 makes this counter proposal" ).
+ arg( firstAttendeeName( event, i18n( "Sender" ) ) );
+ }
+
+ Attendee::List attendees = event->attendees();
+ if( attendees.count() == 0 ) {
+ kdDebug(5850) << "No attendees in the iCal reply!" << endl;
+ return TQString::null;
+ }
+ if( attendees.count() != 1 ) {
+ kdDebug(5850) << "Warning: attendeecount in the reply should be 1 "
+ << "but is " << attendees.count() << endl;
+ }
+ TQString attendeeName = firstAttendeeName( event, i18n( "Sender" ) );
+
+ TQString delegatorName, dummy;
+ Attendee* attendee = *attendees.begin();
+ KPIM::getNameAndMail( attendee->delegator(), delegatorName, dummy );
+ if ( delegatorName.isEmpty() ) {
+ delegatorName = attendee->delegator();
+ }
+
+ switch( attendee->status() ) {
+ case Attendee::NeedsAction:
+ return i18n( "%1 indicates this invitation still needs some action" ).arg( attendeeName );
+ case Attendee::Accepted:
+ if ( event->revision() > 0 ) {
+ if ( !sender.isEmpty() ) {
+ return i18n( "This invitation has been updated by attendee %1" ).arg( sender );
+ } else {
+ return i18n( "This invitation has been updated by an attendee" );
+ }
+ } else {
+ if ( delegatorName.isEmpty() ) {
+ return i18n( "%1 accepts this invitation" ).arg( attendeeName );
+ } else {
+ return i18n( "%1 accepts this invitation on behalf of %2" ).
+ arg( attendeeName ).arg( delegatorName );
+ }
+ }
+ case Attendee::Tentative:
+ if ( delegatorName.isEmpty() ) {
+ return i18n( "%1 tentatively accepts this invitation" ).
+ arg( attendeeName );
+ } else {
+ return i18n( "%1 tentatively accepts this invitation on behalf of %2" ).
+ arg( attendeeName ).arg( delegatorName );
+ }
+ case Attendee::Declined:
+ if ( delegatorName.isEmpty() ) {
+ return i18n( "%1 declines this invitation" ).arg( attendeeName );
+ } else {
+ return i18n( "%1 declines this invitation on behalf of %2" ).
+ arg( attendeeName ).arg( delegatorName );
+ }
+ case Attendee::Delegated: {
+ TQString delegate, dummy;
+ KPIM::getNameAndMail( attendee->delegate(), delegate, dummy );
+ if ( delegate.isEmpty() ) {
+ delegate = attendee->delegate();
+ }
+ if ( !delegate.isEmpty() ) {
+ return i18n( "%1 has delegated this invitation to %2" ).
+ arg( attendeeName ) .arg( delegate );
+ } else {
+ return i18n( "%1 has delegated this invitation" ).arg( attendeeName );
+ }
+ }
+ case Attendee::Completed:
+ return i18n( "This invitation is now completed" );
+ case Attendee::InProcess:
+ return i18n( "%1 is still processing the invitation" ).
+ arg( attendeeName );
+ default:
+ return i18n( "Unknown response to this invitation" );
+ }
+ break;
+ }
+
+ case Scheduler::Counter:
+ return i18n( "%1 makes this counter proposal" ).
+ arg( firstAttendeeName( event, i18n( "Sender" ) ) );
+
+ case Scheduler::Declinecounter:
+ return i18n( "%1 declines the counter proposal" ).
+ arg( firstAttendeeName( event, i18n( "Sender" ) ) );
+
+ case Scheduler::NoMethod:
+ return i18n("Error: iMIP message with unknown method: '%1'").
+ arg( msg->method() );
}
return TQString::null;
}
-static TQString invitationHeaderTodo( Todo *todo, ScheduleMessage *msg )
+static TQString invitationHeaderTodo( Todo *todo, Incidence *existingIncidence,
+ ScheduleMessage *msg, const TQString &sender )
{
- if ( !msg || !todo )
+ if ( !msg || !todo ) {
return TQString::null;
+ }
+
switch ( msg->method() ) {
- case Scheduler::Publish:
- return i18n("This task has been published");
- case Scheduler::Request:
- if ( todo->revision() > 0 )
- return i18n( "This task has been updated" );
- return i18n( "You have been assigned this task" );
- case Scheduler::Refresh:
- return i18n( "This task was refreshed" );
- case Scheduler::Cancel:
- return i18n( "This task was canceled" );
- case Scheduler::Add:
- return i18n( "Addition to the task" );
- case Scheduler::Reply: {
- Attendee::List attendees = todo->attendees();
- if( attendees.count() == 0 ) {
- kdDebug(5850) << "No attendees in the iCal reply!\n";
- return TQString::null;
+ case Scheduler::Publish:
+ return i18n("This task has been published");
+ case Scheduler::Request:
+ if ( existingIncidence && todo->revision() > 0 ) {
+ return i18n( "This task has been updated by the organizer %1" ).
+ arg( todo->organizer().fullName() );
+ } else {
+ if ( iamOrganizer( todo ) ) {
+ return i18n( "I created this task" );
+ } else {
+ TQString orgStr;
+ if ( !todo->organizer().fullName().isEmpty() ) {
+ orgStr = todo->organizer().fullName();
+ } else if ( !todo->organizer().email().isEmpty() ) {
+ orgStr = todo->organizer().email();
}
- if( attendees.count() != 1 )
- kdDebug(5850) << "Warning: attendeecount in the reply should be 1 "
- << "but is " << attendees.count() << endl;
- Attendee* attendee = *attendees.begin();
-
- switch( attendee->status() ) {
- case Attendee::NeedsAction:
- return i18n( "Sender indicates this task assignment still needs some action" );
- case Attendee::Accepted:
- return i18n( "Sender accepts this task" );
- case Attendee::Tentative:
- return i18n( "Sender tentatively accepts this task" );
- case Attendee::Declined:
- return i18n( "Sender declines this task" );
- case Attendee::Delegated: {
- TQString delegate, dummy;
- KPIM::getNameAndMail( attendee->delegate(), delegate, dummy );
- if ( delegate.isEmpty() )
- delegate = attendee->delegate();
- if ( !delegate.isEmpty() )
- return i18n( "Sender has delegated this request for the task to %1" ).arg( delegate );
- return i18n( "Sender has delegated this request for the task " );
+ if ( senderIsOrganizer( todo, sender ) ) {
+ if ( !orgStr.isEmpty() ) {
+ return i18n( "You have been assigned this task by %1" ).arg( orgStr );
+ } else {
+ return i18n( "You have been assigned this task" );
}
- case Attendee::Completed:
- return i18n( "The request for this task is now completed" );
- case Attendee::InProcess:
- return i18n( "Sender is still processing the invitation" );
- default:
- return i18n( "Unknown response to this task" );
+ } else {
+ if ( !orgStr.isEmpty() ) {
+ return i18n( "You have been assigned this task by %1 as a representative of %2" ).
+ arg( sender, orgStr );
+ } else {
+ return i18n( "You have been assigned this task by %1 as the organizer's representative" ).
+ arg( sender );
}
- break; }
- case Scheduler::Counter:
- return i18n( "Sender makes this counter proposal" );
- case Scheduler::Declinecounter:
- return i18n( "Sender declines the counter proposal" );
- case Scheduler::NoMethod:
- return i18n("Error: iMIP message with unknown method: '%1'")
- .arg( msg->method() );
+ }
+ }
+ }
+ case Scheduler::Refresh:
+ return i18n( "This task was refreshed" );
+ case Scheduler::Cancel:
+ return i18n( "This task was canceled" );
+ case Scheduler::Add:
+ return i18n( "Addition to the task" );
+ case Scheduler::Reply:
+ {
+ if ( replyMeansCounter( todo ) ) {
+ return i18n( "%1 makes this counter proposal" ).
+ arg( firstAttendeeName( todo, i18n( "Sender" ) ) );
+ }
+
+ Attendee::List attendees = todo->attendees();
+ if( attendees.count() == 0 ) {
+ kdDebug(5850) << "No attendees in the iCal reply!" << endl;
+ return TQString::null;
+ }
+ if( attendees.count() != 1 ) {
+ kdDebug(5850) << "Warning: attendeecount in the reply should be 1 "
+ << "but is " << attendees.count() << endl;
+ }
+ TQString attendeeName = firstAttendeeName( todo, i18n( "Sender" ) );
+
+ TQString delegatorName, dummy;
+ Attendee* attendee = *attendees.begin();
+ KPIM::getNameAndMail( attendee->delegator(), delegatorName, dummy );
+ if ( delegatorName.isEmpty() ) {
+ delegatorName = attendee->delegator();
+ }
+
+ switch( attendee->status() ) {
+ case Attendee::NeedsAction:
+ return i18n( "%1 indicates this task assignment still needs some action" ).arg( attendeeName );
+ case Attendee::Accepted:
+ if ( todo->revision() > 0 ) {
+ if ( !sender.isEmpty() ) {
+ if ( todo->isCompleted() ) {
+ return i18n( "This task has been completed by assignee %1" ).arg( sender );
+ } else {
+ return i18n( "This task has been updated by assignee %1" ).arg( sender );
+ }
+ } else {
+ if ( todo->isCompleted() ) {
+ return i18n( "This task has been completed by an assignee" );
+ } else {
+ return i18n( "This task has been updated by an assignee" );
+ }
+ }
+ } else {
+ if ( delegatorName.isEmpty() ) {
+ return i18n( "%1 accepts this task" ).arg( attendeeName );
+ } else {
+ return i18n( "%1 accepts this task on behalf of %2" ).
+ arg( attendeeName ).arg( delegatorName );
+ }
+ }
+ case Attendee::Tentative:
+ if ( delegatorName.isEmpty() ) {
+ return i18n( "%1 tentatively accepts this task" ).
+ arg( attendeeName );
+ } else {
+ return i18n( "%1 tentatively accepts this task on behalf of %2" ).
+ arg( attendeeName ).arg( delegatorName );
+ }
+ case Attendee::Declined:
+ if ( delegatorName.isEmpty() ) {
+ return i18n( "%1 declines this task" ).arg( attendeeName );
+ } else {
+ return i18n( "%1 declines this task on behalf of %2" ).
+ arg( attendeeName ).arg( delegatorName );
+ }
+ case Attendee::Delegated: {
+ TQString delegate, dummy;
+ KPIM::getNameAndMail( attendee->delegate(), delegate, dummy );
+ if ( delegate.isEmpty() ) {
+ delegate = attendee->delegate();
+ }
+ if ( !delegate.isEmpty() ) {
+ return i18n( "%1 has delegated this request for the task to %2" ).
+ arg( attendeeName ).arg( delegate );
+ } else {
+ return i18n( "%1 has delegated this request for the task" ).
+ arg( attendeeName );
+ }
+ }
+ case Attendee::Completed:
+ return i18n( "The request for this task is now completed" );
+ case Attendee::InProcess:
+ return i18n( "%1 is still processing the task" ).
+ arg( attendeeName );
+ default:
+ return i18n( "Unknown response to this task" );
+ }
+ break;
+ }
+
+ case Scheduler::Counter:
+ return i18n( "%1 makes this counter proposal" ).
+ arg( firstAttendeeName( todo, i18n( "Sender" ) ) );
+
+ case Scheduler::Declinecounter:
+ return i18n( "%1 declines the counter proposal" ).
+ arg( firstAttendeeName( todo, i18n( "Sender" ) ) );
+
+ case Scheduler::NoMethod:
+ return i18n( "Error: iMIP message with unknown method: '%1'" ).
+ arg( msg->method() );
}
return TQString::null;
}
static TQString invitationHeaderJournal( Journal *journal, ScheduleMessage *msg )
{
- // TODO: Several of the methods are not allowed for journals, so remove them.
- if ( !msg || !journal )
+ if ( !msg || !journal ) {
return TQString::null;
+ }
+
switch ( msg->method() ) {
- case Scheduler::Publish:
- return i18n("This journal has been published");
- case Scheduler::Request:
- return i18n( "You have been assigned this journal" );
- case Scheduler::Refresh:
- return i18n( "This journal was refreshed" );
- case Scheduler::Cancel:
- return i18n( "This journal was canceled" );
- case Scheduler::Add:
- return i18n( "Addition to the journal" );
- case Scheduler::Reply: {
- Attendee::List attendees = journal->attendees();
- if( attendees.count() == 0 ) {
- kdDebug(5850) << "No attendees in the iCal reply!\n";
- return TQString::null;
- }
- if( attendees.count() != 1 )
- kdDebug(5850) << "Warning: attendeecount in the reply should be 1 "
- << "but is " << attendees.count() << endl;
- Attendee* attendee = *attendees.begin();
-
- switch( attendee->status() ) {
- case Attendee::NeedsAction:
- return i18n( "Sender indicates this journal assignment still needs some action" );
- case Attendee::Accepted:
- return i18n( "Sender accepts this journal" );
- case Attendee::Tentative:
- return i18n( "Sender tentatively accepts this journal" );
- case Attendee::Declined:
- return i18n( "Sender declines this journal" );
- case Attendee::Delegated:
- return i18n( "Sender has delegated this request for the journal" );
- case Attendee::Completed:
- return i18n( "The request for this journal is now completed" );
- case Attendee::InProcess:
- return i18n( "Sender is still processing the invitation" );
- default:
- return i18n( "Unknown response to this journal" );
- }
- break; }
- case Scheduler::Counter:
- return i18n( "Sender makes this counter proposal" );
- case Scheduler::Declinecounter:
- return i18n( "Sender declines the counter proposal" );
- case Scheduler::NoMethod:
- return i18n("Error: iMIP message with unknown method: '%1'")
- .arg( msg->method() );
+ case Scheduler::Publish:
+ return i18n("This journal has been published");
+ case Scheduler::Request:
+ return i18n( "You have been assigned this journal" );
+ case Scheduler::Refresh:
+ return i18n( "This journal was refreshed" );
+ case Scheduler::Cancel:
+ return i18n( "This journal was canceled" );
+ case Scheduler::Add:
+ return i18n( "Addition to the journal" );
+ case Scheduler::Reply:
+ {
+ if ( replyMeansCounter( journal ) ) {
+ return i18n( "Sender makes this counter proposal" );
+ }
+
+ Attendee::List attendees = journal->attendees();
+ if( attendees.count() == 0 ) {
+ kdDebug(5850) << "No attendees in the iCal reply!" << endl;
+ return TQString::null;
+ }
+ if( attendees.count() != 1 ) {
+ kdDebug(5850) << "Warning: attendeecount in the reply should be 1 "
+ << "but is " << attendees.count() << endl;
+ }
+ Attendee* attendee = *attendees.begin();
+
+ switch( attendee->status() ) {
+ case Attendee::NeedsAction:
+ return i18n( "Sender indicates this journal assignment still needs some action" );
+ case Attendee::Accepted:
+ return i18n( "Sender accepts this journal" );
+ case Attendee::Tentative:
+ return i18n( "Sender tentatively accepts this journal" );
+ case Attendee::Declined:
+ return i18n( "Sender declines this journal" );
+ case Attendee::Delegated:
+ return i18n( "Sender has delegated this request for the journal" );
+ case Attendee::Completed:
+ return i18n( "The request for this journal is now completed" );
+ case Attendee::InProcess:
+ return i18n( "Sender is still processing the invitation" );
+ default:
+ return i18n( "Unknown response to this journal" );
+ }
+ break;
+ }
+ case Scheduler::Counter:
+ return i18n( "Sender makes this counter proposal" );
+ case Scheduler::Declinecounter:
+ return i18n( "Sender declines the counter proposal" );
+ case Scheduler::NoMethod:
+ return i18n("Error: iMIP message with unknown method: '%1'").
+ arg( msg->method() );
}
return TQString::null;
}
static TQString invitationHeaderFreeBusy( FreeBusy *fb, ScheduleMessage *msg )
{
- if ( !msg || !fb )
+ if ( !msg || !fb ) {
return TQString::null;
+ }
+
switch ( msg->method() ) {
- case Scheduler::Publish:
- return i18n("This free/busy list has been published");
- case Scheduler::Request:
- return i18n( "The free/busy list has been requested" );
- case Scheduler::Refresh:
- return i18n( "This free/busy list was refreshed" );
- case Scheduler::Cancel:
- return i18n( "This free/busy list was canceled" );
- case Scheduler::Add:
- return i18n( "Addition to the free/busy list" );
- case Scheduler::NoMethod:
- default:
- return i18n("Error: Free/Busy iMIP message with unknown method: '%1'")
- .arg( msg->method() );
+ case Scheduler::Publish:
+ return i18n("This free/busy list has been published");
+ case Scheduler::Request:
+ return i18n( "The free/busy list has been requested" );
+ case Scheduler::Refresh:
+ return i18n( "This free/busy list was refreshed" );
+ case Scheduler::Cancel:
+ return i18n( "This free/busy list was canceled" );
+ case Scheduler::Add:
+ return i18n( "Addition to the free/busy list" );
+ case Scheduler::NoMethod:
+ default:
+ return i18n("Error: Free/Busy iMIP message with unknown method: '%1'").
+ arg( msg->method() );
+ }
+}
+
+static TQString invitationAttendees( Incidence *incidence )
+{
+ TQString tmpStr;
+ if ( !incidence ) {
+ return tmpStr;
+ }
+
+ if ( incidence->type() == "Todo" ) {
+ tmpStr += htmlAddTag( "u", i18n( "Assignees" ) );
+ } else {
+ tmpStr += htmlAddTag( "u", i18n( "Attendees" ) );
+ }
+ tmpStr += "<br/>";
+
+ int count=0;
+ Attendee::List attendees = incidence->attendees();
+ if ( !attendees.isEmpty() ) {
+
+ Attendee::List::ConstIterator it;
+ for( it = attendees.begin(); it != attendees.end(); ++it ) {
+ Attendee *a = *it;
+ if ( !iamAttendee( a ) ) {
+ count++;
+ if ( count == 1 ) {
+ tmpStr += "<table border=\"1\" cellpadding=\"1\" cellspacing=\"0\" columns=\"2\">";
+ }
+ tmpStr += "<tr>";
+ tmpStr += "<td>";
+ tmpStr += invitationPerson( a->email(), a->name(), TQString::null );
+ if ( !a->delegator().isEmpty() ) {
+ tmpStr += i18n(" (delegated by %1)" ).arg( a->delegator() );
+ }
+ if ( !a->delegate().isEmpty() ) {
+ tmpStr += i18n(" (delegated to %1)" ).arg( a->delegate() );
+ }
+ tmpStr += "</td>";
+ tmpStr += "<td>" + a->statusStr() + "</td>";
+ tmpStr += "</tr>";
+ }
+ }
+ }
+ if ( count ) {
+ tmpStr += "</table>";
+ } else {
+ tmpStr += "<i>" + i18n( "No attendee", "None" ) + "</i>";
+ }
+
+ return tmpStr;
+}
+
+static TQString invitationAttachments( InvitationFormatterHelper *helper, Incidence *incidence )
+{
+ TQString tmpStr;
+ if ( !incidence ) {
+ return tmpStr;
+ }
+
+ Attachment::List attachments = incidence->attachments();
+ if ( !attachments.isEmpty() ) {
+ tmpStr += i18n( "Attached Documents:" ) + "<ol>";
+
+ Attachment::List::ConstIterator it;
+ for( it = attachments.begin(); it != attachments.end(); ++it ) {
+ Attachment *a = *it;
+ tmpStr += "<li>";
+ // Attachment icon
+ KMimeType::Ptr mimeType = KMimeType::mimeType( a->mimeType() );
+ const TQString iconStr = mimeType ? mimeType->icon( a->uri(), false ) : TQString( "application-octet-stream" );
+ const TQString iconPath = KGlobal::iconLoader()->iconPath( iconStr, KIcon::Small );
+ if ( !iconPath.isEmpty() ) {
+ tmpStr += "<img valign=\"top\" src=\"" + iconPath + "\">";
+ }
+ tmpStr += helper->makeLink( "ATTACH:" + a->label(), a->label() );
+ tmpStr += "</li>";
+ }
+ tmpStr += "</ol>";
}
+
+ return tmpStr;
}
-class IncidenceFormatter::ScheduleMessageVisitor : public IncidenceBase::Visitor
+class IncidenceFormatter::ScheduleMessageVisitor
+ : public IncidenceBase::Visitor
{
public:
- ScheduleMessageVisitor() : mMessage(0) { mResult = ""; }
- bool act( IncidenceBase *incidence, ScheduleMessage *msg ) { mMessage = msg; return incidence->accept( *this ); }
+ ScheduleMessageVisitor() : mExistingIncidence( 0 ), mMessage( 0 ) { mResult = ""; }
+ bool act( IncidenceBase *incidence, Incidence *existingIncidence, ScheduleMessage *msg,
+ const TQString &sender )
+ {
+ mExistingIncidence = existingIncidence;
+ mMessage = msg;
+ mSender = sender;
+ return incidence->accept( *this );
+ }
TQString result() const { return mResult; }
protected:
TQString mResult;
+ Incidence *mExistingIncidence;
ScheduleMessage *mMessage;
+ TQString mSender;
};
-class IncidenceFormatter::InvitationHeaderVisitor :
- public IncidenceFormatter::ScheduleMessageVisitor
+class IncidenceFormatter::InvitationHeaderVisitor
+ : public IncidenceFormatter::ScheduleMessageVisitor
{
protected:
bool visit( Event *event )
{
- mResult = invitationHeaderEvent( event, mMessage );
+ mResult = invitationHeaderEvent( event, mExistingIncidence, mMessage, mSender );
return !mResult.isEmpty();
}
bool visit( Todo *todo )
{
- mResult = invitationHeaderTodo( todo, mMessage );
+ mResult = invitationHeaderTodo( todo, mExistingIncidence, mMessage, mSender );
return !mResult.isEmpty();
}
bool visit( Journal *journal )
@@ -1135,47 +2066,59 @@ class IncidenceFormatter::InvitationHeaderVisitor :
}
};
-class IncidenceFormatter::InvitationBodyVisitor :
- public IncidenceFormatter::ScheduleMessageVisitor
+class IncidenceFormatter::InvitationBodyVisitor
+ : public IncidenceFormatter::ScheduleMessageVisitor
{
+ public:
+ InvitationBodyVisitor( bool noHtmlMode )
+ : ScheduleMessageVisitor(), mNoHtmlMode( noHtmlMode ) {}
+
protected:
bool visit( Event *event )
{
- mResult = invitationDetailsEvent( event );
+ mResult = invitationDetailsEvent( event, mNoHtmlMode );
return !mResult.isEmpty();
}
bool visit( Todo *todo )
{
- mResult = invitationDetailsTodo( todo );
+ mResult = invitationDetailsTodo( todo, mNoHtmlMode );
return !mResult.isEmpty();
}
bool visit( Journal *journal )
{
- mResult = invitationDetailsJournal( journal );
+ mResult = invitationDetailsJournal( journal, mNoHtmlMode );
return !mResult.isEmpty();
}
bool visit( FreeBusy *fb )
{
- mResult = invitationDetailsFreeBusy( fb );
+ mResult = invitationDetailsFreeBusy( fb, mNoHtmlMode );
return !mResult.isEmpty();
}
+
+ private:
+ bool mNoHtmlMode;
};
-class IncidenceFormatter::IncidenceCompareVisitor :
- public IncidenceBase::Visitor
+class IncidenceFormatter::IncidenceCompareVisitor
+ : public IncidenceBase::Visitor
{
public:
IncidenceCompareVisitor() : mExistingIncidence(0) {}
- bool act( IncidenceBase *incidence, Incidence* existingIncidence )
+ bool act( IncidenceBase *incidence, Incidence *existingIncidence, int method )
{
+ Incidence *inc = dynamic_cast<Incidence*>( incidence );
+ if ( !inc || !existingIncidence || inc->revision() <= existingIncidence->revision() )
+ return false;
mExistingIncidence = existingIncidence;
+ mMethod = method;
return incidence->accept( *this );
}
TQString result() const
{
- if ( mChanges.isEmpty() )
- return TQString();
+ if ( mChanges.isEmpty() ) {
+ return TQString::null;
+ }
TQString html = "<div align=\"left\"><ul><li>";
html += mChanges.join( "</li><li>" );
html += "</li><ul></div>";
@@ -1186,17 +2129,18 @@ class IncidenceFormatter::IncidenceCompareVisitor :
bool visit( Event *event )
{
compareEvents( event, dynamic_cast<Event*>( mExistingIncidence ) );
- compareIncidences( event, mExistingIncidence );
+ compareIncidences( event, mExistingIncidence, mMethod );
return !mChanges.isEmpty();
}
bool visit( Todo *todo )
{
- compareIncidences( todo, mExistingIncidence );
+ compareTodos( todo, dynamic_cast<Todo*>( mExistingIncidence ) );
+ compareIncidences( todo, mExistingIncidence, mMethod );
return !mChanges.isEmpty();
}
bool visit( Journal *journal )
{
- compareIncidences( journal, mExistingIncidence );
+ compareIncidences( journal, mExistingIncidence, mMethod );
return !mChanges.isEmpty();
}
bool visit( FreeBusy *fb )
@@ -1211,60 +2155,60 @@ class IncidenceFormatter::IncidenceCompareVisitor :
if ( !oldEvent || !newEvent )
return;
if ( oldEvent->dtStart() != newEvent->dtStart() || oldEvent->doesFloat() != newEvent->doesFloat() )
- mChanges += i18n( "The begin of the meeting has been changed from %1 to %2" )
- .arg( eventStartTimeStr( oldEvent ) ).arg( eventStartTimeStr( newEvent ) );
+ mChanges += i18n( "The invitation starting time has been changed from %1 to %2" )
+ .arg( eventStartTimeStr( oldEvent ) ).arg( eventStartTimeStr( newEvent ) );
if ( oldEvent->dtEnd() != newEvent->dtEnd() || oldEvent->doesFloat() != newEvent->doesFloat() )
- mChanges += i18n( "The end of the meeting has been changed from %1 to %2" )
- .arg( eventEndTimeStr( oldEvent ) ).arg( eventEndTimeStr( newEvent ) );
- if ( newEvent->doesRecur() ) {
- TQString recurrence[]= {i18n("no recurrence", "None"),
- i18n("Minutely"), i18n("Hourly"), i18n("Daily"),
- i18n("Weekly"), i18n("Monthly Same Day"), i18n("Monthly Same Position"),
- i18n("Yearly"), i18n("Yearly"), i18n("Yearly")};
-
- Recurrence *recur = newEvent->recurrence();
- if (oldEvent->doesRecur() == false) {
- mChanges += i18n( "The meeting now recurs %1" ).arg( recurrence[ recur->recurrenceType() ] );
- DateList exceptions = recur->exDates();
- if (exceptions.isEmpty() == false) {
- mChanges += i18n("This recurring meeting has been cancelled on the following days:<br>");
- DateList::ConstIterator ex_iter;
- for ( ex_iter = exceptions.begin(); ex_iter != exceptions.end(); ++ex_iter ) {
- mChanges += i18n("&nbsp&nbsp%1<br>").arg( KGlobal::locale()->formatDate(* ex_iter ) );
- }
- }
- }
- else {
- Recurrence *oldRecur = oldEvent->recurrence();
- DateList exceptions = recur->exDates();
- DateList oldExceptions = oldRecur->exDates();
- bool existsInOldEvent;
- bool atLeastOneModified;
- if (exceptions.isEmpty() == false) {
- atLeastOneModified = false;
- DateList::ConstIterator ex_iter;
- DateList::ConstIterator ex_iter_old;
- for ( ex_iter = exceptions.begin(); ex_iter != exceptions.end(); ++ex_iter ) {
- existsInOldEvent = false;
- for ( ex_iter_old = oldExceptions.begin(); ex_iter_old != oldExceptions.end(); ++ex_iter_old ) {
- if ( KGlobal::locale()->formatDate(* ex_iter ) == KGlobal::locale()->formatDate(* ex_iter_old ) ) {
- existsInOldEvent = true;
- if (atLeastOneModified == false) {
- mChanges += i18n("This recurring meeting has been cancelled on the following days:<br>");
- }
- atLeastOneModified = true;
- }
- }
- if (existsInOldEvent == false ) {
- mChanges += i18n("&nbsp&nbsp%1<br>").arg( KGlobal::locale()->formatDate(* ex_iter ) );
- }
- }
- }
- }
+ mChanges += i18n( "The invitation ending time has been changed from %1 to %2" )
+ .arg( eventEndTimeStr( oldEvent ) ).arg( eventEndTimeStr( newEvent ) );
+ }
+
+ void compareTodos( Todo *newTodo, Todo *oldTodo )
+ {
+ if ( !oldTodo || !newTodo ) {
+ return;
+ }
+
+ if ( !oldTodo->isCompleted() && newTodo->isCompleted() ) {
+ mChanges += i18n( "The task has been completed" );
+ }
+ if ( oldTodo->isCompleted() && !newTodo->isCompleted() ) {
+ mChanges += i18n( "The task is no longer completed" );
+ }
+ if ( oldTodo->percentComplete() != newTodo->percentComplete() ) {
+ const TQString oldPer = i18n( "%1%" ).arg( oldTodo->percentComplete() );
+ const TQString newPer = i18n( "%1%" ).arg( newTodo->percentComplete() );
+ mChanges += i18n( "The task completed percentage has changed from %1 to %2" ).
+ arg( oldPer, newPer );
+ }
+
+ if ( !oldTodo->hasStartDate() && newTodo->hasStartDate() ) {
+ mChanges += i18n( "A task starting time has been added" );
+ }
+ if ( oldTodo->hasStartDate() && !newTodo->hasStartDate() ) {
+ mChanges += i18n( "The task starting time has been removed" );
+ }
+ if ( oldTodo->hasStartDate() && newTodo->hasStartDate() &&
+ oldTodo->dtStart() != newTodo->dtStart() ) {
+ mChanges += i18n( "The task starting time has been changed from %1 to %2" ).
+ arg( dateTimeToString( oldTodo->dtStart(), oldTodo->doesFloat(), false ),
+ dateTimeToString( newTodo->dtStart(), newTodo->doesFloat(), false ) );
+ }
+
+ if ( !oldTodo->hasDueDate() && newTodo->hasDueDate() ) {
+ mChanges += i18n( "A task due time has been added" );
+ }
+ if ( oldTodo->hasDueDate() && !newTodo->hasDueDate() ) {
+ mChanges += i18n( "The task due time has been removed" );
+ }
+ if ( oldTodo->hasDueDate() && newTodo->hasDueDate() &&
+ oldTodo->dtDue() != newTodo->dtDue() ) {
+ mChanges += i18n( "The task due time has been changed from %1 to %2" ).
+ arg( dateTimeToString( oldTodo->dtDue(), oldTodo->doesFloat(), false ),
+ dateTimeToString( newTodo->dtDue(), newTodo->doesFloat(), false ) );
}
}
- void compareIncidences( Incidence *newInc, Incidence *oldInc )
+ void compareIncidences( Incidence *newInc, Incidence *oldInc, int method )
{
if ( !oldInc || !newInc )
return;
@@ -1276,56 +2220,176 @@ class IncidenceFormatter::IncidenceCompareVisitor :
mChanges += i18n( "The description has been changed to: \"%1\"" ).arg( newInc->description() );
Attendee::List oldAttendees = oldInc->attendees();
Attendee::List newAttendees = newInc->attendees();
- for ( Attendee::List::ConstIterator it = newAttendees.constBegin(); it != newAttendees.constEnd(); ++it ) {
+ for ( Attendee::List::ConstIterator it = newAttendees.constBegin();
+ it != newAttendees.constEnd(); ++it ) {
Attendee *oldAtt = oldInc->attendeeByMail( (*it)->email() );
if ( !oldAtt ) {
mChanges += i18n( "Attendee %1 has been added" ).arg( (*it)->fullName() );
} else {
if ( oldAtt->status() != (*it)->status() )
- mChanges += i18n( "The status of attendee %1 has been changed to: %2" ).arg( (*it)->fullName() )
- .arg( (*it)->statusStr() );
+ mChanges += i18n( "The status of attendee %1 has been changed to: %2" ).
+ arg( (*it)->fullName() ).arg( (*it)->statusStr() );
}
}
- for ( Attendee::List::ConstIterator it = oldAttendees.constBegin(); it != oldAttendees.constEnd(); ++it ) {
- Attendee *newAtt = newInc->attendeeByMail( (*it)->email() );
- if ( !newAtt )
- mChanges += i18n( "Attendee %1 has been removed" ).arg( (*it)->fullName() );
+ if ( method == Scheduler::Request ) {
+ for ( Attendee::List::ConstIterator it = oldAttendees.constBegin();
+ it != oldAttendees.constEnd(); ++it ) {
+ if ( (*it)->email() != oldInc->organizer().email() ) {
+ Attendee *newAtt = newInc->attendeeByMail( (*it)->email() );
+ if ( !newAtt ) {
+ mChanges += i18n( "Attendee %1 has been removed" ).arg( (*it)->fullName() );
+ }
+ }
+ }
}
}
private:
- Incidence* mExistingIncidence;
+ Incidence *mExistingIncidence;
+ int mMethod;
TQStringList mChanges;
};
TQString InvitationFormatterHelper::makeLink( const TQString &id, const TQString &text )
{
- TQString res( "<a href=\"%1\"><b>%2</b></a>" );
- return res.arg( generateLinkURL( id ) ).arg( text );
- return res;
+ if ( !id.startsWith( "ATTACH:" ) ) {
+ TQString res = TQString( "<a href=\"%1\"><b>%2</b></a>" ).
+ arg( generateLinkURL( id ), text );
+ return res;
+ } else {
+ // draw the attachment links in non-bold face
+ TQString res = TQString( "<a href=\"%1\">%2</a>" ).
+ arg( generateLinkURL( id ), text );
+ return res;
+ }
}
// Check if the given incidence is likely one that we own instead one from
// a shared calendar (Kolab-specific)
-static bool incidenceOwnedByMe( Calendar* calendar, Incidence *incidence )
+static bool incidenceOwnedByMe( Calendar *calendar, Incidence *incidence )
{
- CalendarResources* cal = dynamic_cast<CalendarResources*>( calendar );
- if ( !cal || !incidence )
+ CalendarResources *cal = dynamic_cast<CalendarResources*>( calendar );
+ if ( !cal || !incidence ) {
return true;
- ResourceCalendar* res = cal->resource( incidence );
- if ( !res )
+ }
+ ResourceCalendar *res = cal->resource( incidence );
+ if ( !res ) {
return true;
+ }
const TQString subRes = res->subresourceIdentifier( incidence );
- if ( !subRes.contains( "/.INBOX.directory/" ) )
+ if ( !subRes.contains( "/.INBOX.directory/" ) ) {
return false;
+ }
return true;
}
-TQString IncidenceFormatter::formatICalInvitation( TQString invitation, Calendar *mCalendar,
- InvitationFormatterHelper *helper )
+// The spacer for the invitation buttons
+static TQString spacer = "<td> &nbsp; </td>";
+// The open & close table cell tags for the invitation buttons
+static TQString tdOpen = "<td>";
+static TQString tdClose = "</td>" + spacer;
+
+static TQString responseButtons( Incidence *inc, bool rsvpReq, bool rsvpRec,
+ InvitationFormatterHelper *helper )
+{
+ TQString html;
+ if ( !helper ) {
+ return html;
+ }
+
+ if ( !rsvpReq && ( inc && inc->revision() == 0 ) ) {
+ // Record only
+ html += tdOpen;
+ html += helper->makeLink( "record", i18n( "[Record]" ) );
+ html += tdClose;
+
+ // Move to trash
+ html += tdOpen;
+ html += helper->makeLink( "delete", i18n( "[Move to Trash]" ) );
+ html += tdClose;
+
+ } else {
+
+ // Accept
+ html += tdOpen;
+ html += helper->makeLink( "accept", i18n( "[Accept]" ) );
+ html += tdClose;
+
+ // Tentative
+ html += tdOpen;
+ html += helper->makeLink( "accept_conditionally",
+ i18n( "Accept conditionally", "[Accept cond.]" ) );
+ html += tdClose;
+
+ // Counter proposal
+ html += tdOpen;
+ html += helper->makeLink( "counter", i18n( "[Counter proposal]" ) );
+ html += tdClose;
+
+ // Decline
+ html += tdOpen;
+ html += helper->makeLink( "decline", i18n( "[Decline]" ) );
+ html += tdClose;
+ }
+
+ if ( !rsvpRec || ( inc && inc->revision() > 0 ) ) {
+ // Delegate
+ html += tdOpen;
+ html += helper->makeLink( "delegate", i18n( "[Delegate]" ) );
+ html += tdClose;
+
+ // Forward
+ html += tdOpen;
+ html += helper->makeLink( "forward", i18n( "[Forward]" ) );
+ html += tdClose;
+
+ // Check calendar
+ if ( inc && inc->type() == "Event" ) {
+ html += tdOpen;
+ html += helper->makeLink( "check_calendar", i18n("[Check my calendar]" ) );
+ html += tdClose;
+ }
+ }
+ return html;
+}
+
+static TQString counterButtons( Incidence *incidence,
+ InvitationFormatterHelper *helper )
+{
+ TQString html;
+ if ( !helper ) {
+ return html;
+ }
+
+ // Accept proposal
+ html += tdOpen;
+ html += helper->makeLink( "accept_counter", i18n("[Accept]") );
+ html += tdClose;
+
+ // Decline proposal
+ html += tdOpen;
+ html += helper->makeLink( "decline_counter", i18n("[Decline]") );
+ html += tdClose;
+
+ // Check calendar
+ if ( incidence && incidence->type() == "Event" ) {
+ html += tdOpen;
+ html += helper->makeLink( "check_calendar", i18n("[Check my calendar]" ) );
+ html += tdClose;
+ }
+ return html;
+}
+
+TQString IncidenceFormatter::formatICalInvitationHelper( TQString invitation,
+ Calendar *mCalendar,
+ InvitationFormatterHelper *helper,
+ bool noHtmlMode,
+ const TQString &sender )
{
- if ( invitation.isEmpty() ) return TQString::null;
+ if ( invitation.isEmpty() ) {
+ return TQString::null;
+ }
ICalFormat format;
// parseScheduleMessage takes the tz from the calendar, no need to set it manually here for the format!
@@ -1340,15 +2404,18 @@ TQString IncidenceFormatter::formatICalInvitation( TQString invitation, Calendar
IncidenceBase *incBase = msg->event();
- Incidence* existingIncidence = 0;
- if ( helper->calendar() ) {
+ // Determine if this incidence is in my calendar (and owned by me)
+ Incidence *existingIncidence = 0;
+ if ( incBase && helper->calendar() ) {
existingIncidence = helper->calendar()->incidence( incBase->uid() );
- if ( !incidenceOwnedByMe( helper->calendar(), existingIncidence ) )
+ if ( !incidenceOwnedByMe( helper->calendar(), existingIncidence ) ) {
existingIncidence = 0;
+ }
if ( !existingIncidence ) {
const Incidence::List list = helper->calendar()->incidences();
for ( Incidence::List::ConstIterator it = list.begin(), end = list.end(); it != end; ++it ) {
- if ( (*it)->schedulingID() == incBase->uid() && incidenceOwnedByMe( helper->calendar(), *it ) ) {
+ if ( (*it)->schedulingID() == incBase->uid() &&
+ incidenceOwnedByMe( helper->calendar(), *it ) ) {
existingIncidence = *it;
break;
}
@@ -1369,115 +2436,262 @@ TQString IncidenceFormatter::formatICalInvitation( TQString invitation, Calendar
html += tableHead;
InvitationHeaderVisitor headerVisitor;
// The InvitationHeaderVisitor returns false if the incidence is somehow invalid, or not handled
- if ( !headerVisitor.act( incBase, msg ) )
+ if ( !headerVisitor.act( incBase, existingIncidence, msg, sender ) )
return TQString::null;
html += "<b>" + headerVisitor.result() + "</b>";
- InvitationBodyVisitor bodyVisitor;
- if ( !bodyVisitor.act( incBase, msg ) )
+ InvitationBodyVisitor bodyVisitor( noHtmlMode );
+ if ( !bodyVisitor.act( incBase, existingIncidence, msg, sender ) )
return TQString::null;
html += bodyVisitor.result();
- if ( msg->method() == Scheduler::Request ) { // ### Scheduler::Publish/Refresh/Add as well?
+ if ( msg->method() == Scheduler::Request ) {
+ IncidenceCompareVisitor compareVisitor;
+ if ( compareVisitor.act( incBase, existingIncidence, msg->method() ) ) {
+ html += "<p align=\"left\">";
+ html += i18n( "The following changes have been made by the organizer:" );
+ html += "</p>";
+ html += compareVisitor.result();
+ }
+ }
+ if ( msg->method() == Scheduler::Reply ) {
IncidenceCompareVisitor compareVisitor;
- if ( compareVisitor.act( incBase, existingIncidence ) ) {
- html += i18n("<p align=\"left\">The following changes have been made by the organizer:</p>");
+ if ( compareVisitor.act( incBase, existingIncidence, msg->method() ) ) {
+ html += "<p align=\"left\">";
+ if ( !sender.isEmpty() ) {
+ html += i18n( "The following changes have been made by %1:" ).arg( sender );
+ } else {
+ html += i18n( "The following changes have been made by an attendee:" );
+ }
+ html += "</p>";
html += compareVisitor.result();
}
}
- html += "<br/>";
- html += "<table border=\"0\" cellspacing=\"0\"><tr><td>&nbsp;</td></tr><tr>";
+ Incidence *inc = dynamic_cast<Incidence*>( incBase );
+
+ // determine if I am the organizer for this invitation
+ bool myInc = iamOrganizer( inc );
-#if 0
- html += helper->makeLinkURL( "accept", i18n("[Enter this into my calendar]") );
- html += "</td><td> &nbsp; </td><td>";
-#endif
+ // determine if the invitation response has already been recorded
+ bool rsvpRec = false;
+ Attendee *ea = 0;
+ if ( !myInc ) {
+ Incidence *rsvpIncidence = existingIncidence;
+ if ( !rsvpIncidence && inc && inc->revision() > 0 ) {
+ rsvpIncidence = inc;
+ }
+ if ( rsvpIncidence ) {
+ ea = findMyAttendee( rsvpIncidence );
+ }
+ if ( ea &&
+ ( ea->status() == Attendee::Accepted ||
+ ea->status() == Attendee::Declined ||
+ ea->status() == Attendee::Tentative ) ) {
+ rsvpRec = true;
+ }
+ }
+
+ // determine invitation role
+ TQString role;
+ bool isDelegated = false;
+ Attendee *a = findMyAttendee( inc );
+ if ( !a && inc ) {
+ if ( !inc->attendees().isEmpty() ) {
+ a = inc->attendees().first();
+ }
+ }
+ if ( a ) {
+ isDelegated = ( a->status() == Attendee::Delegated );
+ role = Attendee::roleName( a->role() );
+ }
+
+ // determine if RSVP needed, not-needed, or response already recorded
+ bool rsvpReq = rsvpRequested( inc );
+ if ( !myInc && a ) {
+ html += "<br/>";
+ html += "<i><u>";
+ if ( rsvpRec && inc ) {
+ if ( inc->revision() == 0 ) {
+ html += i18n( "Your <b>%1</b> response has already been recorded" ).
+ arg( ea->statusStr() );
+ } else {
+ html += i18n( "Your status for this invitation is <b>%1</b>" ).
+ arg( ea->statusStr() );
+ }
+ rsvpReq = false;
+ } else if ( msg->method() == Scheduler::Cancel ) {
+ html += i18n( "This invitation was declined" );
+ } else if ( msg->method() == Scheduler::Add ) {
+ html += i18n( "This invitation was accepted" );
+ } else {
+ if ( !isDelegated ) {
+ html += rsvpRequestedStr( rsvpReq, role );
+ } else {
+ html += i18n( "Awaiting delegation response" );
+ }
+ }
+ html += "</u></i>";
+ }
+
+ // Print if the organizer gave you a preset status
+ if ( !myInc ) {
+ if ( inc && inc->revision() == 0 ) {
+ TQString statStr = myStatusStr( inc );
+ if ( !statStr.isEmpty() ) {
+ html += "<br/>";
+ html += "<i>";
+ html += statStr;
+ html += "</i>";
+ }
+ }
+ }
// Add groupware links
+ html += "<br><table border=\"0\" cellspacing=\"0\"><tr><td>&nbsp;</td></tr>";
+
switch ( msg->method() ) {
case Scheduler::Publish:
case Scheduler::Request:
case Scheduler::Refresh:
case Scheduler::Add:
{
- Incidence *inc = dynamic_cast<Incidence*>( incBase );
- if ( inc && inc->revision() > 0 && (existingIncidence || !helper->calendar()) ) {
- if ( incBase->type() == "Todo" ) {
- html += "<td colspan=\"9\">";
- html += helper->makeLink( "reply", i18n( "[Enter this into my task list]" ) );
- } else {
- html += "<td colspan=\"13\">";
- html += helper->makeLink( "reply", i18n( "[Enter this into my calendar]" ) );
- }
- html += "</td></tr><tr>";
- }
- html += "<td>";
-
- if ( !existingIncidence ) {
- // Accept
- html += helper->makeLink( "accept", i18n( "[Accept]" ) );
- html += "</td><td> &nbsp; </td><td>";
- html += helper->makeLink( "accept_conditionally",
- i18n( "Accept conditionally", "[Accept cond.]" ) );
- html += "</td><td> &nbsp; </td><td>";
- // counter proposal
- html += helper->makeLink( "counter", i18n( "[Counter proposal]" ) );
- html += "</td><td> &nbsp; </td><td>";
- // Decline
- html += helper->makeLink( "decline", i18n( "[Decline]" ) );
- html += "</td><td> &nbsp; </td><td>";
-
- // Delegate
- html += helper->makeLink( "delegate", i18n( "[Delegate]" ) );
- html += "</td><td> &nbsp; </td><td>";
-
- // Forward
- html += helper->makeLink( "forward", i18n( "[Forward]" ) );
-
- if ( incBase->type() == "Event" ) {
- html += "</b></a></td><td> &nbsp; </td><td>";
- html += helper->makeLink( "check_calendar", i18n("[Check my calendar]" ) );
- }
+ if ( inc && inc->revision() > 0 && ( existingIncidence || !helper->calendar() ) ) {
+ html += "<tr>";
+ if ( inc->type() == "Todo" ) {
+ html += "<td colspan=\"9\">";
+ html += helper->makeLink( "reply", i18n( "[Record invitation in my task list]" ) );
+ } else {
+ html += "<td colspan=\"13\">";
+ html += helper->makeLink( "reply", i18n( "[Record invitation in my calendar]" ) );
}
- break;
+ html += "</td></tr>";
+ }
+
+ if ( !myInc && a ) {
+ html += "<tr>" + responseButtons( inc, rsvpReq, rsvpRec, helper ) + "</tr>";
+ }
+ break;
}
case Scheduler::Cancel:
- // Cancel event from my calendar
- html += helper->makeLink( "cancel", i18n( "[Remove this from my calendar]" ) );
- break;
+ // Remove invitation
+ if ( inc ) {
+ html += "<tr>";
+ if ( inc->type() == "Todo" ) {
+ html += "<td colspan=\"9\">";
+ html += helper->makeLink( "cancel", i18n( "[Remove invitation from my task list]" ) );
+ } else {
+ html += "<td colspan=\"13\">";
+ html += helper->makeLink( "cancel", i18n( "[Remove invitation from my calendar]" ) );
+ }
+ html += "</td></tr>";
+ }
+ break;
case Scheduler::Reply:
- // Enter this into my calendar
- if ( incBase->type() == "Todo" ) {
- html += helper->makeLink( "reply", i18n( "[Enter this into my task list]" ) );
- } else {
- html += helper->makeLink( "reply", i18n( "[Enter this into my calendar]" ) );
+ {
+ // Record invitation response
+ Attendee *a = 0;
+ Attendee *ea = 0;
+ if ( inc ) {
+ // First, determine if this reply is really a counter in disguise.
+ if ( replyMeansCounter( inc ) ) {
+ html += "<tr>" + counterButtons( inc, helper ) + "</tr>";
+ break;
}
- break;
+
+ // Next, maybe this is a declined reply that was delegated from me?
+ // find first attendee who is delegated-from me
+ // look a their PARTSTAT response, if the response is declined,
+ // then we need to start over which means putting all the action
+ // buttons and NOT putting on the [Record response..] button
+ a = findDelegatedFromMyAttendee( inc );
+ if ( a ) {
+ if ( a->status() != Attendee::Accepted ||
+ a->status() != Attendee::Tentative ) {
+ html += "<tr>" + responseButtons( inc, rsvpReq, rsvpRec, helper ) + "</tr>";
+ break;
+ }
+ }
+
+ // Finally, simply allow a Record of the reply
+ if ( !inc->attendees().isEmpty() ) {
+ a = inc->attendees().first();
+ }
+ if ( a ) {
+ ea = findAttendee( existingIncidence, a->email() );
+ }
+ }
+ if ( ea && ( ea->status() != Attendee::NeedsAction ) && ( ea->status() == a->status() ) ) {
+ if ( inc && inc->revision() > 0 ) {
+ html += "<br><u><i>";
+ html += i18n( "The response has been recorded [%1]" ).arg( ea->statusStr() );
+ html += "</i></u>";
+ }
+ } else {
+ if ( inc ) {
+ html += "<tr><td>";
+ if ( inc->type() == "Todo" ) {
+ html += helper->makeLink( "reply", i18n( "[Record response in my task list]" ) );
+ } else {
+ html += helper->makeLink( "reply", i18n( "[Record response in my calendar]" ) );
+ }
+ html += "</td></tr>";
+ }
+ }
+ break;
+ }
case Scheduler::Counter:
- html += helper->makeLink( "accept_counter", i18n("[Accept]") );
- html += "&nbsp;";
- html += helper->makeLink( "decline_counter", i18n("[Decline]") );
- html += "&nbsp;";
- html += helper->makeLink( "check_calendar", i18n("[Check my calendar]" ) );
- break;
+ // Counter proposal
+ html += "<tr>" + counterButtons( inc, helper ) + "</tr>";
+ break;
+
case Scheduler::Declinecounter:
case Scheduler::NoMethod:
- break;
+ break;
}
+ // close the groupware table
html += "</td></tr></table>";
+ // Add the attendee list if I am the organizer
+ if ( myInc && helper->calendar() ) {
+ html += invitationAttendees( helper->calendar()->incidence( inc->uid() ) );
+ }
+
+ // close the top-level table
html += "</td></tr></table><br></div>";
+ // Add the attachment list
+ html += invitationAttachments( helper, inc );
+
return html;
}
+TQString IncidenceFormatter::formatICalInvitation( TQString invitation,
+ Calendar *mCalendar,
+ InvitationFormatterHelper *helper )
+{
+ return formatICalInvitationHelper( invitation, mCalendar, helper, false, TQString() );
+}
+
+TQString IncidenceFormatter::formatICalInvitationNoHtml( TQString invitation,
+ Calendar *mCalendar,
+ InvitationFormatterHelper *helper )
+{
+ return formatICalInvitationHelper( invitation, mCalendar, helper, true, TQString() );
+}
+TQString IncidenceFormatter::formatICalInvitationNoHtml( TQString invitation,
+ Calendar *mCalendar,
+ InvitationFormatterHelper *helper,
+ const TQString &sender )
+{
+ return formatICalInvitationHelper( invitation, mCalendar, helper, true, sender );
+}
/*******************************************************************
@@ -1944,10 +3158,14 @@ TQString IncidenceFormatter::formatTNEFInvitation( const TQByteArray& tnef,
class IncidenceFormatter::ToolTipVisitor : public IncidenceBase::Visitor
{
public:
- ToolTipVisitor() : mRichText( true ), mResult( "" ) {}
+ ToolTipVisitor()
+ : mCalendar( 0 ), mRichText( true ), mResult( "" ) {}
- bool act( IncidenceBase *incidence, bool richText=true)
+ bool act( Calendar *calendar, IncidenceBase *incidence,
+ const TQDate &date=TQDate(), bool richText=true )
{
+ mCalendar = calendar;
+ mDate = date;
mRichText = richText;
mResult = "";
return incidence ? incidence->accept( *this ) : false;
@@ -1960,43 +3178,65 @@ class IncidenceFormatter::ToolTipVisitor : public IncidenceBase::Visitor
bool visit( Journal *journal );
bool visit( FreeBusy *fb );
- TQString dateRangeText( Event*event );
- TQString dateRangeText( Todo *todo );
+ TQString dateRangeText( Event *event, const TQDate &date );
+ TQString dateRangeText( Todo *todo, const TQDate &date );
TQString dateRangeText( Journal *journal );
TQString dateRangeText( FreeBusy *fb );
TQString generateToolTip( Incidence* incidence, TQString dtRangeText );
protected:
+ Calendar *mCalendar;
+ TQDate mDate;
bool mRichText;
TQString mResult;
};
-TQString IncidenceFormatter::ToolTipVisitor::dateRangeText( Event*event )
+TQString IncidenceFormatter::ToolTipVisitor::dateRangeText( Event *event, const TQDate &date )
{
TQString ret;
TQString tmp;
+
+ TQDateTime startDt = event->dtStart();
+ TQDateTime endDt = event->dtEnd();
+ if ( event->doesRecur() ) {
+ if ( date.isValid() ) {
+ TQDateTime dt( date, TQTime( 0, 0, 0 ) );
+ int diffDays = startDt.daysTo( dt );
+ dt = dt.addSecs( -1 );
+ startDt.setDate( event->recurrence()->getNextDateTime( dt ).date() );
+ if ( event->hasEndDate() ) {
+ endDt = endDt.addDays( diffDays );
+ if ( startDt > endDt ) {
+ startDt.setDate( event->recurrence()->getPreviousDateTime( dt ).date() );
+ endDt = startDt.addDays( event->dtStart().daysTo( event->dtEnd() ) );
+ }
+ }
+ }
+ }
if ( event->isMultiDay() ) {
tmp = "<br>" + i18n("Event start", "<i>From:</i>&nbsp;%1");
if (event->doesFloat())
- ret += tmp.arg( event->dtStartDateStr().replace(" ", "&nbsp;") );
+ ret += tmp.arg( IncidenceFormatter::dateToString( startDt, false ).replace(" ", "&nbsp;") );
else
- ret += tmp.arg( event->dtStartStr().replace(" ", "&nbsp;") );
+ ret += tmp.arg( IncidenceFormatter::dateToString( startDt ).replace(" ", "&nbsp;") );
tmp = "<br>" + i18n("Event end","<i>To:</i>&nbsp;%1");
if (event->doesFloat())
- ret += tmp.arg( event->dtEndDateStr().replace(" ", "&nbsp;") );
+ ret += tmp.arg( IncidenceFormatter::dateToString( endDt, false ).replace(" ", "&nbsp;") );
else
- ret += tmp.arg( event->dtEndStr().replace(" ", "&nbsp;") );
+ ret += tmp.arg( IncidenceFormatter::dateToString( endDt ).replace(" ", "&nbsp;") );
} else {
ret += "<br>"+i18n("<i>Date:</i>&nbsp;%1").
- arg( event->dtStartDateStr().replace(" ", "&nbsp;") );
+ arg( IncidenceFormatter::dateToString( startDt, false ).replace(" ", "&nbsp;") );
if ( !event->doesFloat() ) {
- const TQString dtStartTime = event->dtStartTimeStr().replace( " ", "&nbsp;" );
- const TQString dtEndTime = event->dtEndTimeStr().replace( " ", "&nbsp;" );
+ const TQString dtStartTime =
+ IncidenceFormatter::timeToString( startDt, true ).replace( " ", "&nbsp;" );
+ const TQString dtEndTime =
+ IncidenceFormatter::timeToString( endDt, true ).replace( " ", "&nbsp;" );
if ( dtStartTime == dtEndTime ) { // to prevent 'Time: 17:00 - 17:00'
tmp = "<br>" + i18n("time for event, &nbsp; to prevent ugly line breaks",
"<i>Time:</i>&nbsp;%1").
@@ -2013,27 +3253,55 @@ TQString IncidenceFormatter::ToolTipVisitor::dateRangeText( Event*event )
return ret;
}
-TQString IncidenceFormatter::ToolTipVisitor::dateRangeText( Todo*todo )
+TQString IncidenceFormatter::ToolTipVisitor::dateRangeText( Todo *todo, const TQDate &date )
{
TQString ret;
bool floats( todo->doesFloat() );
- if (todo->hasStartDate())
- // No need to add <i> here. This is separated issue and each line
- // is very visible on its own. On the other hand... Yes, I like it
- // italics here :)
- ret += "<br>" + i18n("<i>Start:</i>&nbsp;%1").arg(
- (floats)
- ?(todo->dtStartDateStr().replace(" ", "&nbsp;"))
- :(todo->dtStartStr().replace(" ", "&nbsp;")) ) ;
- if (todo->hasDueDate())
- ret += "<br>" + i18n("<i>Due:</i>&nbsp;%1").arg(
- (floats)
- ?(todo->dtDueDateStr().replace(" ", "&nbsp;"))
- :(todo->dtDueStr().replace(" ", "&nbsp;")) );
- if (todo->isCompleted())
- ret += "<br>" + i18n("<i>Completed:</i>&nbsp;%1").arg( todo->completedStr().replace(" ", "&nbsp;") );
- else
- ret += "<br>" + i18n("%1 % completed").arg(todo->percentComplete());
+
+ if ( todo->hasStartDate() && todo->dtStart().isValid() ) {
+ TQDateTime startDt = todo->dtStart();
+ if ( todo->doesRecur() ) {
+ if ( date.isValid() ) {
+ startDt.setDate( date );
+ }
+ }
+ ret += "<br>" +
+ i18n("<i>Start:</i>&nbsp;%1").
+ arg( IncidenceFormatter::dateTimeToString( startDt, floats, false ).
+ replace( " ", "&nbsp;" ) );
+ }
+
+ if ( todo->hasDueDate() && todo->dtDue().isValid() ) {
+ TQDateTime dueDt = todo->dtDue();
+ if ( todo->doesRecur() ) {
+ if ( date.isValid() ) {
+ TQDateTime dt( date, TQTime( 0, 0, 0 ) );
+ dt = dt.addSecs( -1 );
+ dueDt.setDate( todo->recurrence()->getNextDateTime( dt ).date() );
+ }
+ }
+ ret += "<br>" +
+ i18n("<i>Due:</i>&nbsp;%1").
+ arg( IncidenceFormatter::dateTimeToString( dueDt, floats, false ).
+ replace( " ", "&nbsp;" ) );
+ }
+
+ // Print priority and completed info here, for lack of a better place
+
+ if ( todo->priority() > 0 ) {
+ ret += "<br>";
+ ret += "<i>" + i18n( "Priority:" ) + "</i>" + "&nbsp;";
+ ret += TQString::number( todo->priority() );
+ }
+
+ ret += "<br>";
+ if ( todo->isCompleted() ) {
+ ret += "<i>" + i18n( "Completed:" ) + "</i>" + "&nbsp;";
+ ret += todo->completedStr().replace( " ", "&nbsp;" );
+ } else {
+ ret += "<i>" + i18n( "Percent Done:" ) + "</i>" + "&nbsp;";
+ ret += i18n( "%1%" ).arg( todo->percentComplete() );
+ }
return ret;
}
@@ -2042,7 +3310,9 @@ TQString IncidenceFormatter::ToolTipVisitor::dateRangeText( Journal*journal )
{
TQString ret;
if (journal->dtStart().isValid() ) {
- ret += "<br>" + i18n("<i>Date:</i>&nbsp;%1").arg( journal->dtStartDateStr( false ) );
+ ret += "<br>" +
+ i18n("<i>Date:</i>&nbsp;%1").
+ arg( IncidenceFormatter::dateToString( journal->dtStart(), false ) );
}
return ret;
}
@@ -2060,13 +3330,13 @@ TQString IncidenceFormatter::ToolTipVisitor::dateRangeText( FreeBusy *fb )
bool IncidenceFormatter::ToolTipVisitor::visit( Event *event )
{
- mResult = generateToolTip( event, dateRangeText( event ) );
+ mResult = generateToolTip( event, dateRangeText( event, mDate ) );
return !mResult.isEmpty();
}
bool IncidenceFormatter::ToolTipVisitor::visit( Todo *todo )
{
- mResult = generateToolTip( todo, dateRangeText( todo ) );
+ mResult = generateToolTip( todo, dateRangeText( todo, mDate ) );
return !mResult.isEmpty();
}
@@ -2085,43 +3355,209 @@ bool IncidenceFormatter::ToolTipVisitor::visit( FreeBusy *fb )
return !mResult.isEmpty();
}
+static TQString tooltipPerson( const TQString& email, TQString name )
+{
+ // Make the search, if there is an email address to search on,
+ // and name is missing
+ if ( name.isEmpty() && !email.isEmpty() ) {
+ KABC::AddressBook *add_book = KABC::StdAddressBook::self( true );
+ KABC::Addressee::List addressList = add_book->findByEmail( email );
+ if ( !addressList.isEmpty() ) {
+ KABC::Addressee o = addressList.first();
+ if ( !o.isEmpty() && addressList.size() < 2 ) {
+ // use the name from the addressbook
+ name = o.formattedName();
+ }
+ }
+ }
+
+ // Show the attendee
+ TQString tmpString = ( name.isEmpty() ? email : name );
+
+ return tmpString;
+}
+
+static TQString etc = i18n( "elipsis", "..." );
+static TQString tooltipFormatAttendeeRoleList( Incidence *incidence, Attendee::Role role )
+{
+ int maxNumAtts = 8; // maximum number of people to print per attendee role
+ TQString sep = i18n( "separator for lists of people names", ", " );
+ int sepLen = sep.length();
+
+ int i = 0;
+ TQString tmpStr;
+ Attendee::List::ConstIterator it;
+ Attendee::List attendees = incidence->attendees();
+
+ for( it = attendees.begin(); it != attendees.end(); ++it ) {
+ Attendee *a = *it;
+ if ( a->role() != role ) {
+ // skip not this role
+ continue;
+ }
+ if ( a->email() == incidence->organizer().email() ) {
+ // skip attendee that is also the organizer
+ continue;
+ }
+ if ( i == maxNumAtts ) {
+ tmpStr += etc;
+ break;
+ }
+ tmpStr += tooltipPerson( a->email(), a->name() );
+ if ( !a->delegator().isEmpty() ) {
+ tmpStr += i18n(" (delegated by %1)" ).arg( a->delegator() );
+ }
+ if ( !a->delegate().isEmpty() ) {
+ tmpStr += i18n(" (delegated to %1)" ).arg( a->delegate() );
+ }
+ tmpStr += sep;
+ i++;
+ }
+ if ( tmpStr.endsWith( sep ) ) {
+ tmpStr.truncate( tmpStr.length() - sepLen );
+ }
+ return tmpStr;
+}
+
+static TQString tooltipFormatAttendees( Incidence *incidence )
+{
+ TQString tmpStr, str;
+
+ // Add organizer link
+ int attendeeCount = incidence->attendees().count();
+ if ( attendeeCount > 1 ||
+ ( attendeeCount == 1 &&
+ incidence->organizer().email() != incidence->attendees().first()->email() ) ) {
+ tmpStr += "<i>" + i18n( "Organizer:" ) + "</i>" + "&nbsp;";
+ tmpStr += tooltipPerson( incidence->organizer().email(),
+ incidence->organizer().name() );
+ }
+
+ // Add "chair"
+ str = tooltipFormatAttendeeRoleList( incidence, Attendee::Chair );
+ if ( !str.isEmpty() ) {
+ tmpStr += "<br><i>" + i18n( "Chair:" ) + "</i>" + "&nbsp;";
+ tmpStr += str;
+ }
+
+ // Add required participants
+ str = tooltipFormatAttendeeRoleList( incidence, Attendee::ReqParticipant );
+ if ( !str.isEmpty() ) {
+ tmpStr += "<br><i>" + i18n( "Required Participants:" ) + "</i>" + "&nbsp;";
+ tmpStr += str;
+ }
+
+ // Add optional participants
+ str = tooltipFormatAttendeeRoleList( incidence, Attendee::OptParticipant );
+ if ( !str.isEmpty() ) {
+ tmpStr += "<br><i>" + i18n( "Optional Participants:" ) + "</i>" + "&nbsp;";
+ tmpStr += str;
+ }
+
+ // Add observers
+ str = tooltipFormatAttendeeRoleList( incidence, Attendee::NonParticipant );
+ if ( !str.isEmpty() ) {
+ tmpStr += "<br><i>" + i18n( "Observers:" ) + "</i>" + "&nbsp;";
+ tmpStr += str;
+ }
+
+ return tmpStr;
+}
+
TQString IncidenceFormatter::ToolTipVisitor::generateToolTip( Incidence* incidence, TQString dtRangeText )
{
- if ( !incidence )
+ uint maxDescLen = 120; // maximum description chars to print (before elipsis)
+
+ if ( !incidence ) {
return TQString::null;
+ }
- TQString tmp = "<qt><b>"+ incidence->summary().replace("\n", "<br>")+"</b>";
+ TQString tmp = "<qt>";
+
+ // header
+ tmp += "<b>" + incidence->summary().replace( "\n", "<br>" ) + "</b>";
+ //NOTE: using <hr> seems to confuse TQt3 tooltips in some cases so use "-----"
+ tmp += "<br>----------<br>";
+
+ if ( mCalendar ) {
+ TQString calStr = IncidenceFormatter::resourceString( mCalendar, incidence );
+ if ( !calStr.isEmpty() ) {
+ tmp += "<i>" + i18n( "Calendar:" ) + "</i>" + "&nbsp;";
+ tmp += calStr;
+ }
+ }
tmp += dtRangeText;
- if (!incidence->location().isEmpty()) {
- // Put Location: in italics
- tmp += "<br>"+i18n("<i>Location:</i>&nbsp;%1").
- arg( incidence->location().replace("\n", "<br>") );
+ if ( !incidence->location().isEmpty() ) {
+ tmp += "<br>";
+ tmp += "<i>" + i18n( "Location:" ) + "</i>" + "&nbsp;";
+ tmp += incidence->location().replace( "\n", "<br>" );
+ }
+
+ TQString durStr = IncidenceFormatter::durationString( incidence );
+ if ( !durStr.isEmpty() ) {
+ tmp += "<br>";
+ tmp += "<i>" + i18n( "Duration:" ) + "</i>" + "&nbsp;";
+ tmp += durStr;
+ }
+
+ if ( incidence->doesRecur() ) {
+ tmp += "<br>";
+ tmp += "<i>" + i18n( "Recurrence:" ) + "</i>" + "&nbsp;";
+ tmp += IncidenceFormatter::recurrenceString( incidence );
}
- if (!incidence->description().isEmpty()) {
- TQString desc(incidence->description());
- if (desc.length()>120) {
- desc = desc.left(120) + "...";
+
+ if ( !incidence->description().isEmpty() ) {
+ TQString desc( incidence->description() );
+ if ( desc.length() > maxDescLen ) {
+ desc = desc.left( maxDescLen ) + etc;
}
- tmp += "<br>----------<br>" + i18n("<i>Description:</i><br>") + desc.replace("\n", "<br>");
+ tmp += "<br>----------<br>";
+ tmp += "<i>" + i18n( "Description:" ) + "</i>" + "<br>";
+ tmp += desc.replace( "\n", "<br>" );
+ tmp += "<br>----------";
+ }
+
+ int reminderCount = incidence->alarms().count();
+ if ( reminderCount > 0 && incidence->isAlarmEnabled() ) {
+ tmp += "<br>";
+ tmp += "<i>" + i18n( "Reminder:", "%n Reminders:", reminderCount ) + "</i>" + "&nbsp;";
+ tmp += IncidenceFormatter::reminderStringList( incidence ).join( ", " );
}
+
+ tmp += "<br>";
+ tmp += tooltipFormatAttendees( incidence );
+
+ int categoryCount = incidence->categories().count();
+ if ( categoryCount > 0 ) {
+ tmp += "<br>";
+ tmp += "<i>" + i18n( "Category:", "%n Categories:", categoryCount ) + "</i>" + "&nbsp;";
+ tmp += incidence->categories().join( ", " );
+ }
+
tmp += "</qt>";
return tmp;
}
TQString IncidenceFormatter::toolTipString( IncidenceBase *incidence, bool richText )
{
+ return toolTipStr( 0, incidence, TQDate(), richText );
+}
+
+TQString IncidenceFormatter::toolTipStr( Calendar *calendar,
+ IncidenceBase *incidence,
+ const TQDate &date,
+ bool richText )
+{
ToolTipVisitor v;
- if ( v.act( incidence, richText ) ) {
+ if ( v.act( calendar, incidence, date, richText ) ) {
return v.result();
- } else
+ } else {
return TQString::null;
+ }
}
-
-
-
/*******************************************************************
* Helper functions for the Incidence tooltips
*******************************************************************/
@@ -2171,15 +3607,19 @@ bool IncidenceFormatter::MailBodyVisitor::visit( Event *event )
i18n("Yearly"), i18n("Yearly"), i18n("Yearly")};
mResult = mailBodyIncidence( event );
- mResult += i18n("Start Date: %1\n").arg( event->dtStartDateStr() );
+ mResult += i18n("Start Date: %1\n").
+ arg( IncidenceFormatter::dateToString( event->dtStart(), true ) );
if ( !event->doesFloat() ) {
- mResult += i18n("Start Time: %1\n").arg( event->dtStartTimeStr() );
+ mResult += i18n("Start Time: %1\n").
+ arg( IncidenceFormatter::timeToString( event->dtStart(), true ) );
}
if ( event->dtStart() != event->dtEnd() ) {
- mResult += i18n("End Date: %1\n").arg( event->dtEndDateStr() );
+ mResult += i18n("End Date: %1\n").
+ arg( IncidenceFormatter::dateToString( event->dtEnd(), true ) );
}
if ( !event->doesFloat() ) {
- mResult += i18n("End Time: %1\n").arg( event->dtEndTimeStr() );
+ mResult += i18n("End Time: %1\n").
+ arg( IncidenceFormatter::timeToString( event->dtEnd(), true ) );
}
if ( event->doesRecur() ) {
Recurrence *recur = event->recurrence();
@@ -2228,15 +3668,19 @@ bool IncidenceFormatter::MailBodyVisitor::visit( Todo *todo )
mResult = mailBodyIncidence( todo );
if ( todo->hasStartDate() ) {
- mResult += i18n("Start Date: %1\n").arg( todo->dtStartDateStr() );
+ mResult += i18n("Start Date: %1\n").
+ arg( IncidenceFormatter::dateToString( todo->dtStart( false ), true ) );
if ( !todo->doesFloat() ) {
- mResult += i18n("Start Time: %1\n").arg( todo->dtStartTimeStr() );
+ mResult += i18n("Start Time: %1\n").
+ arg( IncidenceFormatter::timeToString( todo->dtStart( false ),true ) );
}
}
if ( todo->hasDueDate() ) {
- mResult += i18n("Due Date: %1\n").arg( todo->dtDueDateStr() );
+ mResult += i18n("Due Date: %1\n").
+ arg( IncidenceFormatter::dateToString( todo->dtDue(), true ) );
if ( !todo->doesFloat() ) {
- mResult += i18n("Due Time: %1\n").arg( todo->dtDueTimeStr() );
+ mResult += i18n("Due Time: %1\n").
+ arg( IncidenceFormatter::timeToString( todo->dtDue(), true ) );
}
}
TQString details = todo->description();
@@ -2249,9 +3693,11 @@ bool IncidenceFormatter::MailBodyVisitor::visit( Todo *todo )
bool IncidenceFormatter::MailBodyVisitor::visit( Journal *journal )
{
mResult = mailBodyIncidence( journal );
- mResult += i18n("Date: %1\n").arg( journal->dtStartDateStr() );
+ mResult += i18n("Date: %1\n").
+ arg( IncidenceFormatter::dateToString( journal->dtStart(), true ) );
if ( !journal->doesFloat() ) {
- mResult += i18n("Time: %1\n").arg( journal->dtStartTimeStr() );
+ mResult += i18n("Time: %1\n").
+ arg( IncidenceFormatter::timeToString( journal->dtStart(), true ) );
}
if ( !journal->description().isEmpty() )
mResult += i18n("Text of the journal:\n%1\n").arg( journal->description() );
@@ -2283,47 +3729,479 @@ static TQString recurEnd( Incidence *incidence )
return endstr;
}
-TQString IncidenceFormatter::recurrenceString(Incidence * incidence)
+/************************************
+ * More static formatting functions
+ ************************************/
+TQString IncidenceFormatter::recurrenceString( Incidence *incidence )
{
- if ( !incidence->doesRecur() )
+ if ( !incidence->doesRecur() ) {
return i18n( "No recurrence" );
-
+ }
+ TQStringList dayList;
+ dayList.append( i18n( "31st Last" ) );
+ dayList.append( i18n( "30th Last" ) );
+ dayList.append( i18n( "29th Last" ) );
+ dayList.append( i18n( "28th Last" ) );
+ dayList.append( i18n( "27th Last" ) );
+ dayList.append( i18n( "26th Last" ) );
+ dayList.append( i18n( "25th Last" ) );
+ dayList.append( i18n( "24th Last" ) );
+ dayList.append( i18n( "23rd Last" ) );
+ dayList.append( i18n( "22nd Last" ) );
+ dayList.append( i18n( "21st Last" ) );
+ dayList.append( i18n( "20th Last" ) );
+ dayList.append( i18n( "19th Last" ) );
+ dayList.append( i18n( "18th Last" ) );
+ dayList.append( i18n( "17th Last" ) );
+ dayList.append( i18n( "16th Last" ) );
+ dayList.append( i18n( "15th Last" ) );
+ dayList.append( i18n( "14th Last" ) );
+ dayList.append( i18n( "13th Last" ) );
+ dayList.append( i18n( "12th Last" ) );
+ dayList.append( i18n( "11th Last" ) );
+ dayList.append( i18n( "10th Last" ) );
+ dayList.append( i18n( "9th Last" ) );
+ dayList.append( i18n( "8th Last" ) );
+ dayList.append( i18n( "7th Last" ) );
+ dayList.append( i18n( "6th Last" ) );
+ dayList.append( i18n( "5th Last" ) );
+ dayList.append( i18n( "4th Last" ) );
+ dayList.append( i18n( "3rd Last" ) );
+ dayList.append( i18n( "2nd Last" ) );
+ dayList.append( i18n( "last day of the month", "Last" ) );
+ dayList.append( i18n( "unknown day of the month", "unknown" ) ); //#31 - zero offset from UI
+ dayList.append( i18n( "1st" ) );
+ dayList.append( i18n( "2nd" ) );
+ dayList.append( i18n( "3rd" ) );
+ dayList.append( i18n( "4th" ) );
+ dayList.append( i18n( "5th" ) );
+ dayList.append( i18n( "6th" ) );
+ dayList.append( i18n( "7th" ) );
+ dayList.append( i18n( "8th" ) );
+ dayList.append( i18n( "9th" ) );
+ dayList.append( i18n( "10th" ) );
+ dayList.append( i18n( "11th" ) );
+ dayList.append( i18n( "12th" ) );
+ dayList.append( i18n( "13th" ) );
+ dayList.append( i18n( "14th" ) );
+ dayList.append( i18n( "15th" ) );
+ dayList.append( i18n( "16th" ) );
+ dayList.append( i18n( "17th" ) );
+ dayList.append( i18n( "18th" ) );
+ dayList.append( i18n( "19th" ) );
+ dayList.append( i18n( "20th" ) );
+ dayList.append( i18n( "21st" ) );
+ dayList.append( i18n( "22nd" ) );
+ dayList.append( i18n( "23rd" ) );
+ dayList.append( i18n( "24th" ) );
+ dayList.append( i18n( "25th" ) );
+ dayList.append( i18n( "26th" ) );
+ dayList.append( i18n( "27th" ) );
+ dayList.append( i18n( "28th" ) );
+ dayList.append( i18n( "29th" ) );
+ dayList.append( i18n( "30th" ) );
+ dayList.append( i18n( "31st" ) );
+ int weekStart = KGlobal::locale()->weekStartDay();
+ TQString dayNames;
+ TQString recurStr, txt;
+ const KCalendarSystem *calSys = KGlobal::locale()->calendar();
Recurrence *recur = incidence->recurrence();
switch ( recur->recurrenceType() ) {
- case Recurrence::rNone:
- return i18n( "No recurrence" );
- case Recurrence::rMinutely:
- if ( recur->duration() != -1 )
- return i18n( "Recurs every minute until %1", "Recurs every %n minutes until %1", recur->frequency() )
- .arg( recurEnd( incidence ) );
- return i18n( "Recurs every minute", "Recurs every %n minutes", recur->frequency() );
- case Recurrence::rHourly:
- if ( recur->duration() != -1 )
- return i18n( "Recurs hourly until %1", "Recurs every %n hours until %1", recur->frequency() )
- .arg( recurEnd( incidence ) );
- return i18n( "Recurs hourly", "Recurs every %n hours", recur->frequency() );
- case Recurrence::rDaily:
- if ( recur->duration() != -1 )
- return i18n( "Recurs daily until %1", "Recurs every %n days until %1", recur->frequency() )
- .arg( recurEnd( incidence ) );
- return i18n( "Recurs daily", "Recurs every %n days", recur->frequency() );
- case Recurrence::rWeekly:
- if ( recur->duration() != -1 )
- return i18n( "Recurs weekly until %1", "Recurs every %n weeks until %1", recur->frequency() )
- .arg( recurEnd( incidence ) );
- return i18n( "Recurs weekly", "Recurs every %n weeks", recur->frequency() );
- case Recurrence::rMonthlyPos:
- case Recurrence::rMonthlyDay:
- if ( recur->duration() != -1 )
- return i18n( "Recurs monthly until %1" ).arg( recurEnd( incidence ) );
- return i18n( "Recurs monthly" );
- case Recurrence::rYearlyMonth:
- case Recurrence::rYearlyDay:
- case Recurrence::rYearlyPos:
- if ( recur->duration() != -1 )
- return i18n( "Recurs yearly until %1" ).arg( recurEnd( incidence ) );
- return i18n( "Recurs yearly" );
- default:
- return i18n( "Incidence recurs" );
+ case Recurrence::rNone:
+ return i18n( "No recurrence" );
+
+ case Recurrence::rMinutely:
+ recurStr = i18n( "Recurs every minute", "Recurs every %n minutes", recur->frequency() );
+ if ( recur->duration() != -1 ) {
+ txt = i18n( "%1 until %2" ).arg( recurStr ).arg( recurEnd( incidence ) );
+ if ( recur->duration() > 0 ) {
+ txt += i18n( " (%1 occurrences)" ).arg( recur->duration() );
+ }
+ return txt;
+ }
+ return recurStr;
+
+ case Recurrence::rHourly:
+ recurStr = i18n( "Recurs hourly", "Recurs every %n hours", recur->frequency() );
+ if ( recur->duration() != -1 ) {
+ txt = i18n( "%1 until %2" ).arg( recurStr ).arg( recurEnd( incidence ) );
+ if ( recur->duration() > 0 ) {
+ txt += i18n( " (%1 occurrences)" ).arg( recur->duration() );
+ }
+ return txt;
+ }
+ return recurStr;
+
+ case Recurrence::rDaily:
+ recurStr = i18n( "Recurs daily", "Recurs every %n days", recur->frequency() );
+ if ( recur->duration() != -1 ) {
+
+ txt = i18n( "%1 until %2" ).arg( recurStr ).arg( recurEnd( incidence ) );
+ if ( recur->duration() > 0 ) {
+ txt += i18n( " (%1 occurrences)" ).arg( recur->duration() );
+ }
+ return txt;
+ }
+ return recurStr;
+
+ case Recurrence::rWeekly:
+ {
+ recurStr = i18n( "Recurs weekly", "Recurs every %n weeks", recur->frequency() );
+
+ bool addSpace = false;
+ for ( int i = 0; i < 7; ++i ) {
+ if ( recur->days().testBit( ( i + weekStart + 6 ) % 7 ) ) {
+ if ( addSpace ) {
+ dayNames.append( i18n( "separator for list of days", ", " ) );
+ }
+ dayNames.append( calSys->weekDayName( ( ( i + weekStart + 6 ) % 7 ) + 1, true ) );
+ addSpace = true;
+ }
+ }
+ if ( dayNames.isEmpty() ) {
+ dayNames = i18n( "Recurs weekly on no days", "no days" );
+ }
+ if ( recur->duration() != -1 ) {
+ txt = i18n( "%1 on %2 until %3" ).
+ arg( recurStr ).arg( dayNames ).arg( recurEnd( incidence ) );
+ if ( recur->duration() > 0 ) {
+ txt += i18n( " (%1 occurrences)" ).arg( recur->duration() );
+ }
+ return txt;
+ }
+ txt = i18n( "%1 on %2" ).arg( recurStr ).arg( dayNames );
+ return txt;
+ }
+ case Recurrence::rMonthlyPos:
+ {
+ recurStr = i18n( "Recurs monthly", "Recurs every %n months", recur->frequency() );
+
+ if ( !recur->monthPositions().isEmpty() ) {
+ KCal::RecurrenceRule::WDayPos rule = recur->monthPositions()[0];
+ if ( recur->duration() != -1 ) {
+ txt = i18n( "%1 on the %2 %3 until %4" ).
+ arg( recurStr ).
+ arg( dayList[rule.pos() + 31] ).
+ arg( calSys->weekDayName( rule.day(), false ) ).
+ arg( recurEnd( incidence ) );
+ if ( recur->duration() > 0 ) {
+ txt += i18n( " (%1 occurrences)" ).arg( recur->duration() );
+ }
+ return txt;
+ }
+ txt = i18n( "%1 on the %2 %3" ).
+ arg( recurStr ).
+ arg( dayList[rule.pos() + 31] ).
+ arg( calSys->weekDayName( rule.day(), false ) );
+ return txt;
+ } else {
+ return recurStr;
+ }
+ break;
+ }
+ case Recurrence::rMonthlyDay:
+ {
+ recurStr = i18n( "Recurs monthly", "Recurs every %n months", recur->frequency() );
+
+ if ( !recur->monthDays().isEmpty() ) {
+ int days = recur->monthDays()[0];
+ if ( recur->duration() != -1 ) {
+ txt = i18n( "%1 on the %2 day until %3" ).
+ arg( recurStr ).
+ arg( dayList[days + 31] ).
+ arg( recurEnd( incidence ) );
+ if ( recur->duration() > 0 ) {
+ txt += i18n( " (%1 occurrences)" ).arg( recur->duration() );
+ }
+ return txt;
+ }
+ txt = i18n( "%1 on the %2 day" ).arg( recurStr ).arg( dayList[days + 31] );
+ return txt;
+ } else {
+ return recurStr;
+ }
+ break;
+ }
+ case Recurrence::rYearlyMonth:
+ {
+ recurStr = i18n( "Recurs yearly", "Recurs every %n years", recur->frequency() );
+
+ if ( recur->duration() != -1 ) {
+ if ( !recur->yearDates().isEmpty() ) {
+ txt = i18n( "%1 on %2 %3 until %4" ).
+ arg( recurStr ).
+ arg( calSys->monthName( recur->yearMonths()[0], recur->startDate().year() ) ).
+ arg( dayList[ recur->yearDates()[0] + 31 ] ).
+ arg( recurEnd( incidence ) );
+ if ( recur->duration() > 0 ) {
+ txt += i18n( " (%1 occurrences)" ).arg( recur->duration() );
+ }
+ return txt;
+ }
+ }
+ if ( !recur->yearDates().isEmpty() ) {
+ txt = i18n( "%1 on %2 %3" ).
+ arg( recurStr ).
+ arg( calSys->monthName( recur->yearMonths()[0], recur->startDate().year() ) ).
+ arg( dayList[ recur->yearDates()[0] + 31 ] );
+ return txt;
+ } else {
+ if ( !recur->yearMonths().isEmpty() ) {
+ txt = i18n( "Recurs yearly on %1 %2" ).
+ arg( calSys->monthName( recur->yearMonths()[0],
+ recur->startDate().year() ) ).
+ arg( dayList[ recur->startDate().day() + 31 ] );
+ } else {
+ txt = i18n( "Recurs yearly on %1 %2" ).
+ arg( calSys->monthName( recur->startDate().month(),
+ recur->startDate().year() ) ).
+ arg( dayList[ recur->startDate().day() + 31 ] );
+ }
+ return txt;
+ }
+ break;
+ }
+ case Recurrence::rYearlyDay:
+ {
+ recurStr = i18n( "Recurs yearly", "Recurs every %n years", recur->frequency() );
+ if ( !recur->yearDays().isEmpty() ) {
+ if ( recur->duration() != -1 ) {
+ txt = i18n( "%1 on day %2 until %3" ).
+ arg( recurStr ).
+ arg( recur->yearDays()[0] ).
+ arg( recurEnd( incidence ) );
+ if ( recur->duration() > 0 ) {
+ txt += i18n( " (%1 occurrences)" ).arg( recur->duration() );
+ }
+ return txt;
+ }
+ txt = i18n( "%1 on day %2" ).arg( recurStr ).arg( recur->yearDays()[0] );
+ return txt;
+ } else {
+ return recurStr;
+ }
+ break;
+ }
+ case Recurrence::rYearlyPos:
+ {
+ recurStr = i18n( "Every year", "Every %n years", recur->frequency() );
+ if ( !recur->yearPositions().isEmpty() && !recur->yearMonths().isEmpty() ) {
+ KCal::RecurrenceRule::WDayPos rule = recur->yearPositions()[0];
+ if ( recur->duration() != -1 ) {
+ txt = i18n( "%1 on the %2 %3 of %4 until %5" ).
+ arg( recurStr ).
+ arg( dayList[rule.pos() + 31] ).
+ arg( calSys->weekDayName( rule.day(), false ) ).
+ arg( calSys->monthName( recur->yearMonths()[0], recur->startDate().year() ) ).
+ arg( recurEnd( incidence ) );
+ if ( recur->duration() > 0 ) {
+ txt += i18n( " (%1 occurrences)" ).arg( recur->duration() );
+ }
+ return txt;
+ }
+ txt = i18n( "%1 on the %2 %3 of %4" ).
+ arg( recurStr ).
+ arg( dayList[rule.pos() + 31] ).
+ arg( calSys->weekDayName( rule.day(), false ) ).
+ arg( calSys->monthName( recur->yearMonths()[0], recur->startDate().year() ) );
+ return txt;
+ } else {
+ return recurStr;
+ }
+ break;
+ }
+ }
+
+ return i18n( "Incidence recurs" );
+}
+
+TQString IncidenceFormatter::timeToString( const TQDateTime &date, bool shortfmt )
+{
+ return KGlobal::locale()->formatTime( date.time(), !shortfmt );
+}
+
+TQString IncidenceFormatter::dateToString( const TQDateTime &date, bool shortfmt )
+{
+ return
+ KGlobal::locale()->formatDate( date.date(), shortfmt );
+}
+
+TQString IncidenceFormatter::dateTimeToString( const TQDateTime &date,
+ bool allDay, bool shortfmt )
+{
+ if ( allDay ) {
+ return dateToString( date, shortfmt );
}
+
+ return KGlobal::locale()->formatDateTime( date, shortfmt );
+}
+
+TQString IncidenceFormatter::resourceString( Calendar *calendar, Incidence *incidence )
+{
+ if ( !calendar || !incidence ) {
+ return TQString::null;
+ }
+
+ CalendarResources *calendarResource = dynamic_cast<CalendarResources*>( calendar );
+ if ( !calendarResource ) {
+ return TQString::null;
+ }
+
+ ResourceCalendar *resourceCalendar = calendarResource->resource( incidence );
+ if ( resourceCalendar ) {
+ if ( !resourceCalendar->subresources().isEmpty() ) {
+ TQString subRes = resourceCalendar->subresourceIdentifier( incidence );
+ if ( subRes.isEmpty() ) {
+ return resourceCalendar->resourceName();
+ } else {
+ return resourceCalendar->labelForSubresource( subRes );
+ }
+ }
+ return resourceCalendar->resourceName();
+ }
+
+ return TQString::null;
+}
+
+static TQString secs2Duration( int secs )
+{
+ TQString tmp;
+ int days = secs / 86400;
+ if ( days > 0 ) {
+ tmp += i18n( "1 day", "%n days", days );
+ tmp += ' ';
+ secs -= ( days * 86400 );
+ }
+ int hours = secs / 3600;
+ if ( hours > 0 ) {
+ tmp += i18n( "1 hour", "%n hours", hours );
+ tmp += ' ';
+ secs -= ( hours * 3600 );
+ }
+ int mins = secs / 60;
+ if ( mins > 0 ) {
+ tmp += i18n( "1 minute", "%n minutes", mins );
+ }
+ return tmp;
+}
+
+TQString IncidenceFormatter::durationString( Incidence *incidence )
+{
+ TQString tmp;
+ if ( incidence->type() == "Event" ) {
+ Event *event = static_cast<Event *>( incidence );
+ if ( event->hasEndDate() ) {
+ if ( !event->doesFloat() ) {
+ tmp = secs2Duration( event->dtStart().secsTo( event->dtEnd() ) );
+ } else {
+ tmp = i18n( "1 day", "%n days",
+ event->dtStart().date().daysTo( event->dtEnd().date() ) + 1 );
+ }
+ } else {
+ tmp = i18n( "forever" );
+ }
+ } else if ( incidence->type() == "Todo" ) {
+ Todo *todo = static_cast<Todo *>( incidence );
+ if ( todo->hasDueDate() ) {
+ if ( todo->hasStartDate() ) {
+ if ( !todo->doesFloat() ) {
+ tmp = secs2Duration( todo->dtStart().secsTo( todo->dtDue() ) );
+ } else {
+ tmp = i18n( "1 day", "%n days",
+ todo->dtStart().date().daysTo( todo->dtDue().date() ) + 1 );
+ }
+ }
+ }
+ }
+ return tmp;
+}
+
+TQStringList IncidenceFormatter::reminderStringList( Incidence *incidence, bool shortfmt )
+{
+ //TODO: implement shortfmt=false
+ Q_UNUSED( shortfmt );
+
+ TQStringList reminderStringList;
+
+ if ( incidence ) {
+ Alarm::List alarms = incidence->alarms();
+ Alarm::List::ConstIterator it;
+ for ( it = alarms.begin(); it != alarms.end(); ++it ) {
+ Alarm *alarm = *it;
+ int offset = 0;
+ TQString remStr, atStr, offsetStr;
+ if ( alarm->hasTime() ) {
+ offset = 0;
+ if ( alarm->time().isValid() ) {
+ atStr = KGlobal::locale()->formatDateTime( alarm->time() );
+ }
+ } else if ( alarm->hasStartOffset() ) {
+ offset = alarm->startOffset().asSeconds();
+ if ( offset < 0 ) {
+ offset = -offset;
+ offsetStr = i18n( "N days/hours/minutes before the start datetime",
+ "%1 before the start" );
+ } else if ( offset > 0 ) {
+ offsetStr = i18n( "N days/hours/minutes after the start datetime",
+ "%1 after the start" );
+ } else { //offset is 0
+ if ( incidence->dtStart().isValid() ) {
+ atStr = KGlobal::locale()->formatDateTime( incidence->dtStart() );
+ }
+ }
+ } else if ( alarm->hasEndOffset() ) {
+ offset = alarm->endOffset().asSeconds();
+ if ( offset < 0 ) {
+ offset = -offset;
+ if ( incidence->type() == "Todo" ) {
+ offsetStr = i18n( "N days/hours/minutes before the due datetime",
+ "%1 before the to-do is due" );
+ } else {
+ offsetStr = i18n( "N days/hours/minutes before the end datetime",
+ "%1 before the end" );
+ }
+ } else if ( offset > 0 ) {
+ if ( incidence->type() == "Todo" ) {
+ offsetStr = i18n( "N days/hours/minutes after the due datetime",
+ "%1 after the to-do is due" );
+ } else {
+ offsetStr = i18n( "N days/hours/minutes after the end datetime",
+ "%1 after the end" );
+ }
+ } else { //offset is 0
+ if ( incidence->type() == "Todo" ) {
+ Todo *t = static_cast<Todo *>( incidence );
+ if ( t->dtDue().isValid() ) {
+ atStr = KGlobal::locale()->formatDateTime( t->dtDue() );
+ }
+ } else {
+ Event *e = static_cast<Event *>( incidence );
+ if ( e->dtEnd().isValid() ) {
+ atStr = KGlobal::locale()->formatDateTime( e->dtEnd() );
+ }
+ }
+ }
+ }
+ if ( offset == 0 ) {
+ if ( !atStr.isEmpty() ) {
+ remStr = i18n( "reminder occurs at datetime", "at %1" ).arg( atStr );
+ }
+ } else {
+ remStr = offsetStr.arg( secs2Duration( offset ) );
+ }
+
+ if ( alarm->repeatCount() > 0 ) {
+ TQString countStr = i18n( "repeats once", "repeats %n times", alarm->repeatCount() );
+ TQString intervalStr = i18n( "interval is N days/hours/minutes", "interval is %1" ).
+ arg( secs2Duration( alarm->snoozeTime().asSeconds() ) );
+ TQString repeatStr = i18n( "(repeat string, interval string)", "(%1, %2)" ).
+ arg( countStr, intervalStr );
+ remStr = remStr + ' ' + repeatStr;
+
+ }
+ reminderStringList << remStr;
+ }
+ }
+
+ return reminderStringList;
}
diff --git a/libkcal/incidenceformatter.h b/libkcal/incidenceformatter.h
index ce37b0164..b2dcd4324 100644
--- a/libkcal/incidenceformatter.h
+++ b/libkcal/incidenceformatter.h
@@ -3,6 +3,7 @@
Copyright (c) 2001-2003 Cornelius Schumacher <schumacher@kde.org>
Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
+ Copyright (c) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -22,10 +23,12 @@
#ifndef KCAL_INCIDENCEFORMATTER_H
#define KCAL_INCIDENCEFORMATTER_H
-#include <tqstring.h>
-
#include "libkcal_export.h"
+#include <tqdatetime.h>
+#include <tqstring.h>
+#include <tqstringlist.h>
+
namespace KCal {
class Calendar;
class Incidence;
@@ -36,7 +39,7 @@ class LIBKCAL_EXPORT InvitationFormatterHelper
public:
virtual TQString generateLinkURL( const TQString &id ) { return id; }
virtual TQString makeLink( const TQString &id, const TQString &text );
- virtual Calendar* calendar() const { return 0; }
+ virtual Calendar *calendar() const { return 0; }
};
/**
@@ -49,12 +52,27 @@ class LIBKCAL_EXPORT InvitationFormatterHelper
class LIBKCAL_EXPORT IncidenceFormatter
{
public:
- static TQString toolTipString( IncidenceBase *incidence, bool richText = true );
+ static TQString KDE_DEPRECATED toolTipString( IncidenceBase *incidence, bool richText = true );
+ static TQString toolTipStr( Calendar *calendar,
+ IncidenceBase *incidence,
+ const TQDate &date=TQDate(),
+ bool richText = true );
static TQString mailBodyString( IncidenceBase *incidencebase );
- static TQString extensiveDisplayString( IncidenceBase *incidence );
+ static TQString KDE_DEPRECATED extensiveDisplayString( IncidenceBase *incidence );
+ static TQString extensiveDisplayStr( Calendar *calendar,
+ IncidenceBase *incidence,
+ const TQDate &date=TQDate() );
static TQString formatICalInvitation( TQString invitation, Calendar *mCalendar,
InvitationFormatterHelper *helper );
+ static TQString KDE_DEPRECATED formatICalInvitationNoHtml( TQString invitation,
+ Calendar *mCalendar,
+ InvitationFormatterHelper *helper );
+ static TQString formatICalInvitationNoHtml( TQString invitation,
+ Calendar *mCalendar,
+ InvitationFormatterHelper *helper,
+ const TQString &sender );
+
// Format a TNEF attachment to an HTML mail
static TQString formatTNEFInvitation( const TQByteArray& tnef,
Calendar *mCalendar,
@@ -63,7 +81,44 @@ class LIBKCAL_EXPORT IncidenceFormatter
static TQString msTNEFToVPart( const TQByteArray& tnef );
static TQString recurrenceString( Incidence *incidence );
+
+ /*
+ Returns a reminder string computed for the specified Incidence.
+ Each item of the returning TQStringList corresponds to a string
+ representation of an reminder belonging to this incidence.
+ @param incidence is a pointer to the Incidence.
+ @param shortfmt if false, a short version of each reminder is printed;
+ else a longer version of each reminder is printed.
+ */
+ static TQStringList reminderStringList( Incidence *incidence, bool shortfmt = true );
+
+ static TQString timeToString( const TQDateTime &date, bool shortfmt = true );
+
+ static TQString dateToString( const TQDateTime &date, bool shortfmt = true );
+
+ static TQString dateTimeToString( const TQDateTime &date,
+ bool dateOnly = false,
+ bool shortfmt = true );
+ /**
+ Returns a Calendar Resource label name for the specified Incidence.
+ @param calendar is a pointer to the Calendar.
+ @param incidence is a pointer to the Incidence.
+ */
+ static TQString resourceString( Calendar *calendar, Incidence *incidence );
+
+ /**
+ Returns a duration string computed for the specified Incidence.
+ Only makes sense for Events and Todos.
+ @param incidence is a pointer to the Incidence.
+ */
+ static TQString durationString( Incidence *incidence );
+
private:
+ static TQString formatICalInvitationHelper( TQString invitation,
+ Calendar *mCalendar,
+ InvitationFormatterHelper *helper,
+ bool noHtmlMode,
+ const TQString &sender );
class EventViewerVisitor;
class ScheduleMessageVisitor;
class InvitationHeaderVisitor;
diff --git a/libkcal/kcal_manager.desktop b/libkcal/kcal_manager.desktop
index e606a9d6b..a0a72e282 100644
--- a/libkcal/kcal_manager.desktop
+++ b/libkcal/kcal_manager.desktop
@@ -29,7 +29,6 @@ Name[hu]=Naptár
Name[is]=Dagatal
Name[it]=Calendario
Name[ja]=カレンダー
-Name[ka]=კალენდარი
Name[kk]=Күнтізбе
Name[km]=ប្រតិទិន
Name[lt]=Kalendorius
@@ -56,8 +55,7 @@ Name[tg]=Тақвим
Name[th]=บันทึกประจำวัน
Name[tr]=Takvim
Name[uk]=Календар
-Name[uz]=Kalendar
-Name[uz@cyrillic]=Календар
+Name[uz]=Календар
Name[zh_CN]=日历
Name[zh_TW]=行事曆
Type=Service
diff --git a/libkcal/libical/configure.in.in b/libkcal/libical/configure.in.in
new file mode 100644
index 000000000..79aafbc30
--- /dev/null
+++ b/libkcal/libical/configure.in.in
@@ -0,0 +1,20 @@
+dnl Checks for programs.
+AC_PROG_YACC
+AM_PROG_LEX
+
+AC_CHECK_PROGS(PERL, perl5 perl)
+
+AC_DEFINE(ICAL_SAFESAVES,1, [safe saves])
+AC_DEFINE(ICAL_UNIX_NEWLINE,1, [unix newline])
+
+AC_CHECK_HEADERS(time.h sys/types.h assert.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_SIZE_T
+AC_STRUCT_TM
+AM_PROG_LEX
+
+dnl Checks for library functions.
+AC_CHECK_FUNCS(strdup)
+
diff --git a/libkcal/libical/src/libical/icalattach.c b/libkcal/libical/src/libical/icalattach.c
new file mode 100644
index 000000000..106096bf9
--- /dev/null
+++ b/libkcal/libical/src/libical/icalattach.c
@@ -0,0 +1,151 @@
+/* -*- Mode: C -*-
+ ======================================================================
+ FILE: icalattach.c
+ CREATOR: acampi 28 May 02
+
+ $Id: icalattach.c 1024886 2009-09-17 13:28:13Z winterz $
+ $Locker: $
+
+
+ (C) COPYRIGHT 2000, Andrea Campi
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ The original code is icaltypes.c
+
+ ======================================================================*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "icaltypes.h"
+#include "icalerror.h"
+#include "icalmemory.h"
+#include "icalattachimpl.h"
+#include <stdlib.h> /* for malloc and abs() */
+#include <errno.h> /* for errno */
+#include <string.h> /* for icalmemory_strdup */
+#include <assert.h>
+
+icalattach *
+icalattach_new_from_url (const char *url)
+{
+ icalattach *attach;
+ char *url_copy;
+
+ icalerror_check_arg_rz ((url != NULL), "url");
+
+ if ((attach = malloc (sizeof (icalattach))) == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ if ((url_copy = strdup (url)) == NULL) {
+ free (attach);
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ attach->refcount = 1;
+ attach->is_url = 1;
+ attach->u.url.url = url_copy;
+
+ return attach;
+}
+
+icalattach *
+icalattach_new_from_data (unsigned char *data, icalattach_free_fn_t free_fn,
+ void *free_fn_data)
+{
+ icalattach *attach;
+ char *data_copy;
+
+ icalerror_check_arg_rz ((data != NULL), "data");
+
+ if ((attach = malloc (sizeof (icalattach))) == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ if ((data_copy = strdup (data)) == NULL) {
+ free (attach);
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ attach->refcount = 1;
+ attach->is_url = 0;
+ attach->u.data.data = data_copy;
+ attach->u.data.free_fn = free_fn;
+ attach->u.data.free_fn_data = free_fn_data;
+
+ return attach;
+}
+
+void
+icalattach_ref (icalattach *attach)
+{
+ icalerror_check_arg_rv ((attach != NULL), "attach");
+ icalerror_check_arg_rv ((attach->refcount > 0), "attach->refcount > 0");
+
+ attach->refcount++;
+}
+
+void
+icalattach_unref (icalattach *attach)
+{
+ icalerror_check_arg_rv ((attach != NULL), "attach");
+ icalerror_check_arg_rv ((attach->refcount > 0), "attach->refcount > 0");
+
+ attach->refcount--;
+
+ if (attach->refcount != 0)
+ return;
+
+ if (attach->is_url) {
+ free (attach->u.url.url);
+ } else {
+ free (attach->u.data.data);
+/* unused for now
+ if (attach->u.data.free_fn)
+ (* attach->u.data.free_fn) (attach->u.data.data, attach->u.data.free_fn_data);
+*/
+ }
+
+ free (attach);
+}
+
+int
+icalattach_get_is_url (icalattach *attach)
+{
+ icalerror_check_arg_rz ((attach != NULL), "attach");
+
+ return attach->is_url ? 1 : 0;
+}
+
+const char *
+icalattach_get_url (icalattach *attach)
+{
+ icalerror_check_arg_rz ((attach != NULL), "attach");
+ icalerror_check_arg_rz ((attach->is_url), "attach->is_url");
+
+ return attach->u.url.url;
+}
+
+unsigned char *
+icalattach_get_data (icalattach *attach)
+{
+ icalerror_check_arg_rz ((attach != NULL), "attach");
+ icalerror_check_arg_rz ((!attach->is_url), "!attach->is_url");
+
+ return attach->u.data.data;
+}
diff --git a/libkcal/local.desktop b/libkcal/local.desktop
index 669565922..9cf91413e 100644
--- a/libkcal/local.desktop
+++ b/libkcal/local.desktop
@@ -26,7 +26,6 @@ Name[hu]=Helyi fájlban tárolt naptár
Name[is]=Dagatal í staðbundinni skrá
Name[it]=Calendario in file locale
Name[ja]=ローカルファイルのカレンダー
-Name[ka]=კალენდარი ლოკალურ ფაილში
Name[kk]=Жергілікті файлдағы күнтізбе
Name[km]=ប្រតិទិន​នៅ​ក្នុង​ឯកសារ​មូលដ្ឋាន
Name[lt]=Kalendorius vietinėje byloje
diff --git a/libkcal/localdir.desktop b/libkcal/localdir.desktop
index f65fe7450..d7e4b4137 100644
--- a/libkcal/localdir.desktop
+++ b/libkcal/localdir.desktop
@@ -26,7 +26,6 @@ Name[hu]=Helyi könyvtárban tárolt naptár
Name[is]=Dagatal í staðbundinni möppu
Name[it]=Calendario nella directory locale
Name[ja]=ローカルディレクトリのカレンダー
-Name[ka]=კალენდარი ლოკალურ დირექტორიაში
Name[kk]=Жергілікті каталогтағы күнтізбе
Name[km]=ប្រតិទិន​នៅ​ក្នុង​ថត​មូលដ្ឋាន
Name[lt]=Kalendorius vietiniame aplanke
diff --git a/libkcal/period.cpp b/libkcal/period.cpp
index be07d7d3b..ff944ee94 100644
--- a/libkcal/period.cpp
+++ b/libkcal/period.cpp
@@ -51,6 +51,14 @@ bool Period::operator<( const Period& other )
return start() < other.start();
}
+bool Period::operator==( const Period &other ) const
+{
+ return
+ mStart == other.mStart &&
+ mEnd == other.mEnd &&
+ mHasDuration == other.mHasDuration;
+}
+
TQDateTime Period::start() const
{
return mStart;
diff --git a/libkcal/period.h b/libkcal/period.h
index 64dd24d9c..b0ca32a33 100644
--- a/libkcal/period.h
+++ b/libkcal/period.h
@@ -42,6 +42,24 @@ class KDE_EXPORT Period
/** Returns true if this element is smaller than the @param other one */
bool operator<( const Period& other );
+ /**
+ Returns true if this period is equal to the @p other one.
+ Even if their start and end times are the same, two periods are
+ considered not equal if one is defined in terms of a duration and the
+ other in terms of a start and end time.
+
+ @param other the other period to compare
+ */
+ bool operator==( const Period &other ) const;
+
+ /**
+ Returns true if this period is not equal to the @p other one.
+
+ @param other the other period to compare
+ @see operator==()
+ */
+ bool operator!=( const Period &other ) const { return !operator==( other ); }
+
TQDateTime start() const;
TQDateTime end() const;
Duration duration();
diff --git a/libkcal/recurrence.cpp b/libkcal/recurrence.cpp
index c2d7897a0..ae47db326 100644
--- a/libkcal/recurrence.cpp
+++ b/libkcal/recurrence.cpp
@@ -34,7 +34,6 @@
using namespace KCal;
-
Recurrence::Recurrence()
: mFloating( false ),
mRecurReadOnly(false),
@@ -282,9 +281,8 @@ bool Recurrence::recursOn(const TQDate &qd) const
if ( mRDates.contains( qd ) ) return true;
- // Check if it might recur today at all.
bool recurs = false;
- if ( startDate() == qd ) recurs = true;
+
for ( RecurrenceRule::List::ConstIterator rr = mRRules.begin(); rr != mRRules.end(); ++rr ) {
recurs = recurs || (*rr)->recursOn( qd );
}
@@ -770,10 +768,74 @@ TimeList Recurrence::recurTimesOn( const TQDate &date ) const
return times;
}
+DateTimeList Recurrence::timesInInterval( const TQDateTime &start, const TQDateTime &end ) const
+{
+ int i, count;
+ DateTimeList times;
+ for ( i = 0, count = mRRules.count(); i < count; ++i ) {
+ times += mRRules[i]->timesInInterval( start, end );
+ }
+
+ // add rdatetimes that fit in the interval
+ for ( i = 0, count = mRDateTimes.count(); i < count; ++i ) {
+ if ( mRDateTimes[i] >= start && mRDateTimes[i] <= end ) {
+ times += mRDateTimes[i];
+ }
+ }
+
+ // add rdates that fit in the interval
+ TQDateTime qdt( mStartDateTime );
+ for ( i = 0, count = mRDates.count(); i < count; ++i ) {
+ qdt.setDate( mRDates[i] );
+ if ( qdt >= start && qdt <= end ) {
+ times += qdt;
+ }
+ }
+
+ // Recurrence::timesInInterval(...) doesn't explicitly add mStartDateTime to the list
+ // of times to be returned. It calls mRRules[i]->timesInInterval(...) which include
+ // mStartDateTime.
+ // So, If we have rdates/rdatetimes but don't have any rrule we must explicitly
+ // add mStartDateTime to the list, otherwise we won't see the first occurrence.
+ if ( ( !mRDates.isEmpty() || !mRDateTimes.isEmpty() ) &&
+ mRRules.isEmpty() &&
+ start <= mStartDateTime &&
+ end >= mStartDateTime ) {
+ times += mStartDateTime;
+ }
+
+ qSortUnique( times );
+
+ // Remove excluded times
+ int idt = 0;
+ int enddt = times.count();
+ for ( i = 0, count = mExDates.count(); i < count && idt < enddt; ++i ) {
+ while ( idt < enddt && times[idt].date() < mExDates[i] ) ++idt;
+ while ( idt < enddt && times[idt].date() == mExDates[i] ) {
+ times.remove( times.at( idt ) );
+ --enddt;
+ }
+ }
+ DateTimeList extimes;
+ for ( i = 0, count = mExRules.count(); i < count; ++i ) {
+ extimes += mExRules[i]->timesInInterval( start, end );
+ }
+ extimes += mExDateTimes;
+ qSortUnique( extimes );
+
+ int st = 0;
+ for ( i = 0, count = extimes.count(); i < count; ++i ) {
+ int j = removeSorted( times, extimes[i], st );
+ if ( j >= 0 ) {
+ st = j;
+ }
+ }
+
+ return times;
+}
TQDateTime Recurrence::getNextDateTime( const TQDateTime &preDateTime ) const
{
-//kdDebug(5800) << " Recurrence::getNextDateTime after " << preDateTime << endl;
TQDateTime nextDT = preDateTime;
// prevent infinite loops, e.g. when an exrule extinguishes an rrule (e.g.
// the exrule is identical to the rrule). If an occurrence is found, break
@@ -795,40 +857,51 @@ TQDateTime Recurrence::getNextDateTime( const TQDateTime &preDateTime ) const
++loop;
// First, get the next recurrence from the RDate lists
DateTimeList dates;
- if ( nextDT < startDateTime() ) dates << startDateTime();
- DateTimeList::ConstIterator it = mRDateTimes.begin();
+ if ( nextDT < startDateTime() ) {
+ dates << startDateTime();
+ }
+
+ int end;
// Assume that the rdatetime list is sorted
- while ( it != mRDateTimes.end() && (*it) <= nextDT ) ++it;
- if ( it != mRDateTimes.end() ) dates << (*it);
+ int i = findGT( mRDateTimes, nextDT, 0 );
+ if ( i >= 0 ) {
+ dates << mRDateTimes[i];
+ }
-/*kdDebug(5800) << " nextDT: " << nextDT << ", startDT: " << startDateTime() << endl;
-kdDebug(5800) << " getNextDateTime: found " << dates.count() << " RDATES and DTSTART in loop " << loop << endl;*/
- DateList::ConstIterator dit = mRDates.begin();
- while ( dit != mRDates.end() && TQDateTime( (*dit), startDateTime().time() ) <= nextDT ) ++dit;
- if ( dit != mRDates.end() ) dates << TQDateTime( (*dit), startDateTime().time() );
+ TQDateTime qdt( startDateTime() );
+ for ( i = 0, end = mRDates.count(); i < end; ++i ) {
+ qdt.setDate( mRDates[i] );
+ if ( qdt > nextDT ) {
+ dates << qdt;
+ break;
+ }
+ }
// Add the next occurrences from all RRULEs.
- for ( RecurrenceRule::List::ConstIterator rr = mRRules.begin(); rr != mRRules.end(); ++rr ) {
- TQDateTime dt = (*rr)->getNextDate( nextDT );
- if ( dt.isValid() ) dates << dt;
+ for ( i = 0, end = mRRules.count(); i < end; ++i ) {
+ TQDateTime dt = mRRules[i]->getNextDate( nextDT );
+ if ( dt.isValid() ) {
+ dates << dt;
+ }
}
// Take the first of these (all others can't be used later on)
qSortUnique( dates );
-// kdDebug(5800) << " getNextDateTime: found " << dates.count() << " dates in loop " << loop << endl;
-
- if ( dates.isEmpty() ) return TQDateTime();
+ if ( dates.isEmpty() ) {
+ return TQDateTime();
+ }
nextDT = dates.first();
// Check if that date/time is excluded explicitly or by an exrule:
- if ( !mExDates.contains( nextDT.date() ) && !mExDateTimes.contains( nextDT ) ) {
-// kdDebug(5800) << " NextDT" << nextDT << " not excluded by EXDATE " << endl;
+ if ( !containsSorted( mExDates, nextDT.date() ) &&
+ !containsSorted( mExDateTimes, nextDT ) ) {
bool allowed = true;
- for ( RecurrenceRule::List::ConstIterator rr = mExRules.begin(); rr != mExRules.end(); ++rr ) {
- allowed = allowed && !( (*rr)->recursAt( nextDT ) );
+ for ( i = 0, end = mExRules.count(); i < end; ++i ) {
+ allowed = allowed && !( mExRules[i]->recursAt( nextDT ) );
+ }
+ if ( allowed ) {
+ return nextDT;
}
-// kdDebug(5800) << " NextDT " << nextDT << ", allowed=" << allowed << endl;
- if ( allowed ) return nextDT;
}
}
@@ -856,44 +929,50 @@ TQDateTime Recurrence::getPreviousDateTime( const TQDateTime &afterDateTime ) co
++loop;
// First, get the next recurrence from the RDate lists
DateTimeList dates;
- if ( prevDT > startDateTime() ) dates << startDateTime();
-
- DateTimeList::ConstIterator dtit = mRDateTimes.end();
- if ( dtit != mRDateTimes.begin() ) {
- do {
- --dtit;
- } while ( dtit != mRDateTimes.begin() && (*dtit) >= prevDT );
- if ( (*dtit) < prevDT ) dates << (*dtit);
+ if ( prevDT > startDateTime() ) {
+ dates << startDateTime();
+ }
+
+ int i = findLT( mRDateTimes, prevDT, 0 );
+ if ( i >= 0 ) {
+ dates << mRDateTimes[i];
}
- DateList::ConstIterator dit = mRDates.end();
- if ( dit != mRDates.begin() ) {
- do {
- --dit;
- } while ( dit != mRDates.begin() && TQDateTime((*dit), startDateTime().time()) >= prevDT );
- if ( TQDateTime((*dit), startDateTime().time()) < prevDT )
- dates << TQDateTime( (*dit), startDateTime().time() );
+ TQDateTime qdt( startDateTime() );
+ for ( i = mRDates.count(); --i >= 0; ) {
+ qdt.setDate( mRDates[i] );
+ if ( qdt < prevDT ) {
+ dates << qdt;
+ break;
+ }
}
// Add the previous occurrences from all RRULEs.
- for ( RecurrenceRule::List::ConstIterator rr = mRRules.begin(); rr != mRRules.end(); ++rr ) {
- TQDateTime dt = (*rr)->getPreviousDate( prevDT );
- if ( dt.isValid() ) dates << dt;
+ int end;
+ for ( i = 0, end = mRRules.count(); i < end; ++i ) {
+ TQDateTime dt = mRRules[i]->getPreviousDate( prevDT );
+ if ( dt.isValid() ) {
+ dates << dt;
+ }
}
-//kdDebug(5800) << " getPreviousDateTime: found " << dates.count() << " dates in loop " << loop << endl;
// Take the last of these (all others can't be used later on)
qSortUnique( dates );
- if ( dates.isEmpty() ) return TQDateTime();
+ if ( dates.isEmpty() ) {
+ return TQDateTime();
+ }
prevDT = dates.last();
// Check if that date/time is excluded explicitly or by an exrule:
- if ( !mExDates.contains( prevDT.date() ) && !mExDateTimes.contains( prevDT ) ) {
+ if ( !containsSorted( mExDates, prevDT.date() ) &&
+ !containsSorted( mExDateTimes, prevDT ) ) {
bool allowed = true;
- for ( RecurrenceRule::List::ConstIterator rr = mExRules.begin(); rr != mExRules.end(); ++rr ) {
- allowed = allowed && !( (*rr)->recursAt( prevDT ) );
+ for ( i = 0, end = mExRules.count(); i < end; ++i ) {
+ allowed = allowed && !( mExRules[i]->recursAt( prevDT ) );
+ }
+ if ( allowed ) {
+ return prevDT;
}
- if ( allowed ) return prevDT;
}
}
diff --git a/libkcal/recurrence.h b/libkcal/recurrence.h
index ec6965977..0a594a6fb 100644
--- a/libkcal/recurrence.h
+++ b/libkcal/recurrence.h
@@ -166,6 +166,21 @@ class LIBKCAL_EXPORT Recurrence : public RecurrenceRule::Observer
*/
TQValueList<TQTime> recurTimesOn(const TQDate &date) const;
+ /** Returns a list of all the times at which the recurrence will occur
+ * between two specified times.
+ *
+ * There is a (large) maximum limit to the number of times returned. If due to
+ * this limit the list is incomplete, this is indicated by the last entry being
+ * set to an invalid TQDateTime value. If you need further values, call the
+ * method again with a start time set to just after the last valid time returned.
+ *
+ * @param start inclusive start of interval
+ * @param end inclusive end of interval
+ * @return list of date/time values
+ */
+ DateTimeList timesInInterval( const TQDateTime &start, const TQDateTime &end ) const;
+
+
/** Returns the date and time of the next recurrence, after the specified date/time.
* If the recurrence has no time, the next date after the specified date is returned.
* @param preDateTime the date/time after which to find the recurrence.
diff --git a/libkcal/recurrencerule.cpp b/libkcal/recurrencerule.cpp
index ce64aadc1..17292ec53 100644
--- a/libkcal/recurrencerule.cpp
+++ b/libkcal/recurrencerule.cpp
@@ -32,6 +32,8 @@
using namespace KCal;
+// Maximum number of intervals to process
+const int LOOP_LIMIT = 10000;
// FIXME: If Qt is ever changed so that TQDateTime:::addSecs takes into account
// DST shifts, we need to use our own addSecs method, too, since we
@@ -774,6 +776,8 @@ void RecurrenceRule::setWeekStart( short weekStart )
void RecurrenceRule::buildConstraints()
{
+ mTimedRepetition = 0;
+ mNoByRules = mBySetPos.isEmpty();
mConstraints.clear();
Constraint con;
if ( mWeekStart > 0 ) con.weekstart = mWeekStart;
@@ -785,6 +789,7 @@ void RecurrenceRule::buildConstraints()
#define intConstraint( list, element ) \
if ( !list.isEmpty() ) { \
+ mNoByRules = false; \
for ( it = mConstraints.constBegin(); it != mConstraints.constEnd(); ++it ) { \
for ( intit = list.constBegin(); intit != list.constEnd(); ++intit ) { \
con = (*it); \
@@ -806,6 +811,7 @@ void RecurrenceRule::buildConstraints()
#undef intConstraint
if ( !mByDays.isEmpty() ) {
+ mNoByRules = false;
for ( it = mConstraints.constBegin(); it != mConstraints.constEnd(); ++it ) {
TQValueList<WDayPos>::const_iterator dayit;
for ( dayit = mByDays.constBegin(); dayit != mByDays.constEnd(); ++dayit ) {
@@ -866,12 +872,28 @@ void RecurrenceRule::buildConstraints()
}
#undef fixConstraint
- Constraint::List::Iterator conit = mConstraints.begin();
- while ( conit != mConstraints.end() ) {
- if ( (*conit).isConsistent( mPeriod ) ) {
- ++conit;
- } else {
- conit = mConstraints.remove( conit );
+ if ( mNoByRules ) {
+ switch ( mPeriod ) {
+ case rHourly:
+ mTimedRepetition = mFrequency * 3600;
+ break;
+ case rMinutely:
+ mTimedRepetition = mFrequency * 60;
+ break;
+ case rSecondly:
+ mTimedRepetition = mFrequency;
+ break;
+ default:
+ break;
+ }
+ } else {
+ Constraint::List::Iterator conit = mConstraints.begin();
+ while ( conit != mConstraints.end() ) {
+ if ( (*conit).isConsistent( mPeriod ) ) {
+ ++conit;
+ } else {
+ conit = mConstraints.remove( conit );
+ }
}
}
}
@@ -941,81 +963,179 @@ bool RecurrenceRule::dateMatchesRules( const TQDateTime &qdt ) const
bool RecurrenceRule::recursOn( const TQDate &qd ) const
{
-// kdDebug(5800) << " RecurrenceRule::recursOn: " << qd << endl;
- if ( qd < startDt().date() ) return false;
+ int i, iend;
+ if ( doesFloat() ) {
+ // It's a date-only rule, so it has no time specification.
+ if ( qd < mDateStart.date() ) {
+ return false;
+ }
+ // Start date is only included if it really matches
+ TQDate endDate;
+ if ( mDuration >= 0 ) {
+ endDate = endDt().date();
+ if ( qd > endDate ) {
+ return false;
+ }
+ }
+
+ // The date must be in an appropriate interval (getNextValidDateInterval),
+ // Plus it must match at least one of the constraints
+ bool match = false;
+ for ( i = 0, iend = mConstraints.count(); i < iend && !match; ++i ) {
+ match = mConstraints[i].matches( qd, recurrenceType() );
+ }
+ if ( !match ) {
+ return false;
+ }
+
+ TQDateTime start( qd, TQTime( 0, 0, 0 ) );
+ Constraint interval( getNextValidDateInterval( start, recurrenceType() ) );
+ // Constraint::matches is quite efficient, so first check if it can occur at
+ // all before we calculate all actual dates.
+ if ( !interval.matches( qd, recurrenceType() ) ) {
+ return false;
+ }
+ // We really need to obtain the list of dates in this interval, since
+ // otherwise BYSETPOS will not work (i.e. the date will match the interval,
+ // but BYSETPOS selects only one of these matching dates!
+ TQDateTime end = start.addDays(1);
+ do {
+ DateTimeList dts = datesForInterval( interval, recurrenceType() );
+ for ( i = 0, iend = dts.count(); i < iend; ++i ) {
+ if ( dts[i].date() >= qd ) {
+ return dts[i].date() == qd;
+ }
+ }
+ interval.increase( recurrenceType(), frequency() );
+ } while ( interval.intervalDateTime( recurrenceType() ) < end );
+ return false;
+ }
+
+ // It's a date-time rule, so we need to take the time specification into account.
+ TQDateTime start( qd, TQTime( 0, 0, 0 ) );
+ TQDateTime end = start.addDays( 1 );
+ if ( end < mDateStart ) {
+ return false;
+ }
+ if ( start < mDateStart ) {
+ start = mDateStart;
+ }
+
// Start date is only included if it really matches
-// if ( qd == startDt().date() ) return true;
- if ( mDuration >= 0 && qd > endDt().date() ) return false;
+ if ( mDuration >= 0 ) {
+ TQDateTime endRecur = endDt();
+ if ( endRecur.isValid() ) {
+ if ( start > endRecur ) {
+ return false;
+ }
+ if ( end > endRecur ) {
+ end = endRecur; // limit end-of-day time to end of recurrence rule
+ }
+ }
+ }
+
+ if ( mTimedRepetition ) {
+ // It's a simple sub-daily recurrence with no constraints
+ int n = static_cast<int>( ( mDateStart.secsTo( start ) - 1 ) % mTimedRepetition );
+ return start.addSecs( mTimedRepetition - n ) < end;
+ }
+
+ // Find the start and end dates in the time spec for the rule
+ TQDate startDay = start.date();
+ TQDate endDay = end.addSecs( -1 ).date();
+ int dayCount = startDay.daysTo( endDay ) + 1;
// The date must be in an appropriate interval (getNextValidDateInterval),
// Plus it must match at least one of the constraints
bool match = false;
- for ( Constraint::List::ConstIterator it = mConstraints.begin();
- it!=mConstraints.end(); ++it ) {
- match = match || ( (*it).matches( qd, recurrenceType() ) );
+ for ( i = 0, iend = mConstraints.count(); i < iend && !match; ++i ) {
+ match = mConstraints[i].matches( startDay, recurrenceType() );
+ for ( int day = 1; day < dayCount && !match; ++day ) {
+ match = mConstraints[i].matches( startDay.addDays( day ), recurrenceType() );
+ }
+ }
+ if ( !match ) {
+ return false;
}
- if ( !match ) return false;
- TQDateTime tmp( qd, TQTime( 0, 0, 0 ) );
- Constraint interval( getNextValidDateInterval( tmp, recurrenceType() ) );
+
+ Constraint interval( getNextValidDateInterval( start, recurrenceType() ) );
// Constraint::matches is quite efficient, so first check if it can occur at
// all before we calculate all actual dates.
- if ( !interval.matches( qd, recurrenceType() ) ) return false;
+ match = false;
+ Constraint intervalm = interval;
+ do {
+ match = intervalm.matches( startDay, recurrenceType() );
+ for ( int day = 1; day < dayCount && !match; ++day ) {
+ match = intervalm.matches( startDay.addDays( day ), recurrenceType() );
+ }
+ if ( match ) {
+ break;
+ }
+ intervalm.increase( recurrenceType(), frequency() );
+ } while ( intervalm.intervalDateTime( recurrenceType() ) < end );
+ if ( !match ) {
+ return false;
+ }
+
// We really need to obtain the list of dates in this interval, since
// otherwise BYSETPOS will not work (i.e. the date will match the interval,
// but BYSETPOS selects only one of these matching dates!
- DateTimeList times = datesForInterval( interval, recurrenceType() );
- DateTimeList::ConstIterator it = times.begin();
- while ( ( it != times.end() ) && ( (*it).date() < qd ) )
- ++it;
- if ( it != times.end() ) {
- // If we are beyond the end...
- if ( mDuration >= 0 && (*it) > endDt() )
- return false;
- if ( (*it).date() == qd )
- return true;
- }
+ do {
+ DateTimeList dts = datesForInterval( interval, recurrenceType() );
+ int i = findGE( dts, start, 0 );
+ if ( i >= 0 ) {
+ return dts[i] < end;
+ }
+ interval.increase( recurrenceType(), frequency() );
+ } while ( interval.intervalDateTime( recurrenceType() ) < end );
+
return false;
}
-
-bool RecurrenceRule::recursAt( const TQDateTime &qd ) const
+bool RecurrenceRule::recursAt( const TQDateTime &dt ) const
{
-// kdDebug(5800) << " RecurrenceRule::recursAt: " << qd << endl;
- if ( doesFloat() ) return recursOn( qd.date() );
- if ( qd < startDt() ) return false;
+ if ( doesFloat() ) {
+ return recursOn( dt.date() );
+ }
+ if ( dt < mDateStart ) {
+ return false;
+ }
// Start date is only included if it really matches
-// if ( qd == startDt() ) return true;
- if ( mDuration >= 0 && qd > endDt() ) return false;
+ if ( mDuration >= 0 && dt > endDt() ) {
+ return false;
+ }
+
+ if ( mTimedRepetition ) {
+ // It's a simple sub-daily recurrence with no constraints
+ return !( mDateStart.secsTo( dt ) % mTimedRepetition );
+ }
// The date must be in an appropriate interval (getNextValidDateInterval),
// Plus it must match at least one of the constraints
- bool match = dateMatchesRules( qd );
- if ( !match ) return false;
+ if ( !dateMatchesRules( dt ) ) {
+ return false;
+ }
// if it recurs every interval, speed things up...
-// if ( mFrequency == 1 && mBySetPos.isEmpty() && mByDays.isEmpty() ) return true;
- Constraint interval( getNextValidDateInterval( qd, recurrenceType() ) );
+// if ( d->mFrequency == 1 && d->mBySetPos.isEmpty() && d->mByDays.isEmpty() ) return true;
+ Constraint interval( getNextValidDateInterval( dt, recurrenceType() ) );
// TODO_Recurrence: Does this work with BySetPos???
- if ( interval.matches( qd, recurrenceType() ) ) return true;
-
+ if ( interval.matches( dt, recurrenceType() ) ) {
+ return true;
+ }
return false;
}
-
TimeList RecurrenceRule::recurTimesOn( const TQDate &date ) const
{
-// kdDebug(5800) << " RecurrenceRule::recurTimesOn: " << date << endl;
TimeList lst;
- if ( !recursOn( date ) ) return lst;
-
- if ( doesFloat() ) return lst;
-
- TQDateTime dt( date, TQTime( 0, 0, 0 ) );
- bool valid = dt.isValid() && ( dt.date() == date );
- while ( valid ) {
- // TODO: Add a flag so that the date is never increased!
- dt = getNextDate( dt );
- valid = dt.isValid() && ( dt.date() == date );
- if ( valid ) lst.append( dt.time() );
+ if ( doesFloat() ) {
+ return lst;
+ }
+ TQDateTime start( date, TQTime( 0, 0, 0 ) );
+ TQDateTime end = start.addDays( 1 ).addSecs( -1 );
+ DateTimeList dts = timesInInterval( start, end ); // returns between start and end inclusive
+ for ( int i = 0, iend = dts.count(); i < iend; ++i ) {
+ lst += dts[i].time();
}
return lst;
}
@@ -1150,6 +1270,104 @@ TQDateTime RecurrenceRule::getNextDate( const TQDateTime &preDate ) const
return TQDateTime();
}
+DateTimeList RecurrenceRule::timesInInterval( const TQDateTime &dtStart,
+ const TQDateTime &dtEnd ) const
+{
+ TQDateTime start = dtStart;
+ TQDateTime end = dtEnd;
+ DateTimeList result;
+ if ( end < mDateStart ) {
+ return result; // before start of recurrence
+ }
+ TQDateTime enddt = end;
+ if ( mDuration >= 0 ) {
+ TQDateTime endRecur = endDt();
+ if ( endRecur.isValid() ) {
+ if ( start > endRecur ) {
+ return result; // beyond end of recurrence
+ }
+ if ( end > endRecur ) {
+ enddt = endRecur; // limit end time to end of recurrence rule
+ }
+ }
+ }
+
+ if ( mTimedRepetition ) {
+ // It's a simple sub-daily recurrence with no constraints
+ int n = static_cast<int>( ( mDateStart.secsTo( start ) - 1 ) % mTimedRepetition );
+ TQDateTime dt = start.addSecs( mTimedRepetition - n );
+ if ( dt < enddt ) {
+ n = static_cast<int>( ( dt.secsTo( enddt ) - 1 ) / mTimedRepetition ) + 1;
+ // limit n by a sane value else we can "explode".
+ n = QMIN( n, LOOP_LIMIT );
+ for ( int i = 0; i < n; dt = dt.addSecs( mTimedRepetition ), ++i ) {
+ result += dt;
+ }
+ }
+ return result;
+ }
+
+ TQDateTime st = start;
+ bool done = false;
+ if ( mDuration > 0 ) {
+ if ( !mCached ) {
+ buildCache();
+ }
+ if ( mCachedDateEnd.isValid() && start > mCachedDateEnd ) {
+ return result; // beyond end of recurrence
+ }
+ int i = findGE( mCachedDates, start, 0 );
+ if ( i >= 0 ) {
+ int iend = findGT( mCachedDates, enddt, i );
+ if ( iend < 0 ) {
+ iend = mCachedDates.count();
+ } else {
+ done = true;
+ }
+ while ( i < iend ) {
+ result += mCachedDates[i++];
+ }
+ }
+ if ( mCachedDateEnd.isValid() ) {
+ done = true;
+ } else if ( !result.isEmpty() ) {
+ result += TQDateTime(); // indicate that the returned list is incomplete
+ done = true;
+ }
+ if ( done ) {
+ return result;
+ }
+ // We don't have any result yet, but we reached the end of the incomplete cache
+ st = mCachedLastDate.addSecs( 1 );
+ }
+
+ Constraint interval( getNextValidDateInterval( st, recurrenceType() ) );
+ int loop = 0;
+ do {
+ DateTimeList dts = datesForInterval( interval, recurrenceType() );
+ int i = 0;
+ int iend = dts.count();
+ if ( loop == 0 ) {
+ i = findGE( dts, st, 0 );
+ if ( i < 0 ) {
+ i = iend;
+ }
+ }
+ int j = findGT( dts, enddt, i );
+ if ( j >= 0 ) {
+ iend = j;
+ loop = LOOP_LIMIT;
+ }
+ while ( i < iend ) {
+ result += dts[i++];
+ }
+ // Increase the interval.
+ interval.increase( recurrenceType(), frequency() );
+ } while ( ++loop < LOOP_LIMIT &&
+ interval.intervalDateTime( recurrenceType() ) < end );
+ return result;
+}
+
RecurrenceRule::Constraint RecurrenceRule::getPreviousValidDateInterval( const TQDateTime &preDate, PeriodType type ) const
{
// kdDebug(5800) << " (o) getPreviousValidDateInterval after " << preDate << ", type=" << type << endl;
diff --git a/libkcal/recurrencerule.h b/libkcal/recurrencerule.h
index 049d9c523..86b8ca8ea 100644
--- a/libkcal/recurrencerule.h
+++ b/libkcal/recurrencerule.h
@@ -50,6 +50,109 @@ Q_INLINE_TEMPLATES void qSortUnique( TQValueList<T> &lst )
}
}
+template <class T>
+Q_INLINE_TEMPLATES int findGE( const TQValueList<T> &lst, const T &value, int start )
+{
+ // Do a binary search to find the first item >= value
+ int st = start - 1;
+ int end = lst.count();
+ while ( end - st > 1 ) {
+ int i = ( st + end ) / 2;
+ if ( value <= lst[i] ) {
+ end = i;
+ } else {
+ st = i;
+ }
+ }
+ ++st;
+ return ( st == int( lst.count() ) ) ? -1 : st;
+}
+
+template <class T>
+Q_INLINE_TEMPLATES int findGT( const TQValueList<T> &lst, const T &value, int start )
+{
+ // Do a binary search to find the first item > value
+ int st = start - 1;
+ int end = lst.count();
+ while ( end - st > 1 ) {
+ int i = ( st + end ) / 2;
+ if ( value < lst[i] ) {
+ end = i;
+ } else {
+ st = i;
+ }
+ }
+ ++st;
+ return ( st == int( lst.count() ) ) ? -1 : st;
+}
+
+template <class T>
+Q_INLINE_TEMPLATES int findLE( const TQValueList<T> &lst, const T &value, int start )
+{
+ // Do a binary search to find the last item <= value
+ int st = start - 1;
+ int end = lst.count();
+ while ( end - st > 1 ) {
+ int i = ( st + end ) / 2;
+ if ( value < lst[i] ) {
+ end = i;
+ } else {
+ st = i;
+ }
+ }
+ return ( end > start ) ? st : -1;
+}
+
+template <class T>
+Q_INLINE_TEMPLATES int findLT( const TQValueList<T> &lst, const T &value, int start )
+{
+ // Do a binary search to find the last item < value
+ int st = start - 1;
+ int end = lst.count();
+ while ( end - st > 1 ) {
+ int i = ( st + end ) / 2;
+ if ( value <= lst[i] ) {
+ end = i;
+ } else {
+ st = i;
+ }
+ }
+ return ( end > start ) ? st : -1;
+}
+
+template <class T>
+Q_INLINE_TEMPLATES int findSorted( const TQValueList<T> &lst, const T &value, int start )
+{
+ // Do a binary search to find the item == value
+ int st = start - 1;
+ int end = lst.count();
+ while ( end - st > 1 ) {
+ int i = ( st + end ) / 2;
+ if ( value < lst[i] ) {
+ end = i;
+ } else {
+ st = i;
+ }
+ }
+ return ( end > start && value == lst[st] ) ? st : -1;
+}
+
+template <class T>
+Q_INLINE_TEMPLATES int removeSorted( TQValueList<T> &lst, const T &value, int start )
+{
+ int i = findSorted( lst, value, start );
+ if ( i >= 0 ) {
+ lst.remove( lst.at( i ) );
+ }
+ return i;
+}
+
+template <class T>
+Q_INLINE_TEMPLATES bool containsSorted( const TQValueList<T> &lst, const T &value )
+{
+ return findSorted( lst, value, 0 ) >= 0;
+}
+
namespace KCal {
@@ -188,6 +291,18 @@ class LIBKCAL_EXPORT RecurrenceRule
*/
TimeList recurTimesOn( const TQDate &date ) const;
+ /** Returns a list of all the times at which the recurrence will occur
+ * between two specified times.
+ *
+ * There is a (large) maximum limit to the number of times returned. If due to
+ * this limit the list is incomplete, this is indicated by the last entry being
+ * set to an invalid KDateTime value. If you need further values, call the
+ * method again with a start time set to just after the last valid time returned.
+ * @param start inclusive start of interval
+ * @param end inclusive end of interval
+ * @return list of date/time values
+ */
+ DateTimeList timesInInterval( const TQDateTime &start, const TQDateTime &end ) const;
/** Returns the date and time of the next recurrence, after the specified date/time.
* If the recurrence has no time, the next date after the specified date is returned.
@@ -331,8 +446,12 @@ class LIBKCAL_EXPORT RecurrenceRule
// Cache for duration
mutable DateTimeList mCachedDates;
- mutable bool mCached;
mutable TQDateTime mCachedDateEnd;
+ mutable TQDateTime mCachedLastDate; // when mCachedDateEnd invalid, last date checked
+ mutable bool mCached;
+
+ bool mNoByRules; // no BySeconds, ByMinutes, ... rules exist
+ uint mTimedRepetition; // repeats at a regular number of seconds interval, or 0
class Private;
Private *d;
diff --git a/libkcal/resourcecached.cpp b/libkcal/resourcecached.cpp
index 1a4e8b19e..dacab7e9d 100644
--- a/libkcal/resourcecached.cpp
+++ b/libkcal/resourcecached.cpp
@@ -50,7 +50,7 @@ static bool m_editoropen = false;
ResourceCached::ResourceCached( const KConfig* config )
: ResourceCalendar( config ), mCalendar( TQString::fromLatin1( "UTC" ) ),
- mReloadPolicy( ReloadNever ), mReloadInterval( 10 ),
+ mReloadPolicy( ReloadNever ), mReloadInterval( 10 ),
mReloadTimer( 0, "mReloadTimer" ), mReloaded( false ),
mSavePolicy( SaveNever ), mSaveInterval( 10 ),
mSaveTimer( 0, "mSaveTimer" ), mIdMapper( "kcal/uidmaps/" )
@@ -161,6 +161,12 @@ bool ResourceCached::addEvent(Event *event)
return mCalendar.addEvent( event );
}
+bool ResourceCached::addEvent(Event *event, const TQString &subresource )
+{
+ Q_UNUSED( subresource ); // CalendarLocal does not support subresources
+ return mCalendar.addEvent( event );
+}
+
// probably not really efficient, but...it works for now.
bool ResourceCached::deleteEvent( Event *event )
{
@@ -205,6 +211,12 @@ bool ResourceCached::addTodo( Todo *todo )
return mCalendar.addTodo( todo );
}
+bool ResourceCached::addTodo( Todo *todo, const TQString &subresource )
+{
+ Q_UNUSED( subresource ); // CalendarLocal does not support subresources
+ return mCalendar.addTodo( todo );
+}
+
bool ResourceCached::deleteTodo( Todo *todo )
{
return mCalendar.deleteTodo( todo );
@@ -231,11 +243,14 @@ Todo::List ResourceCached::rawTodosForDate( const TQDate &date )
return mCalendar.rawTodosForDate( date );
}
-
bool ResourceCached::addJournal( Journal *journal )
{
- kdDebug(5800) << "Adding Journal on " << journal->dtStart().toString() << endl;
+ return mCalendar.addJournal( journal );
+}
+bool ResourceCached::addJournal( Journal *journal, const TQString &subresource )
+{
+ Q_UNUSED( subresource ); // CalendarLocal does not support subresources
return mCalendar.addJournal( journal );
}
diff --git a/libkcal/resourcecached.h b/libkcal/resourcecached.h
index 60976698a..74fcf5d62 100644
--- a/libkcal/resourcecached.h
+++ b/libkcal/resourcecached.h
@@ -136,7 +136,9 @@ class KDE_EXPORT ResourceCached : public ResourceCalendar,
/**
Add event to calendar.
*/
- bool addEvent(Event *anEvent);
+ KDE_DEPRECATED bool addEvent( Event *event );
+ bool addEvent( Event *event, const TQString &subresource );
+
/**
Deletes an event from this calendar.
*/
@@ -174,7 +176,9 @@ class KDE_EXPORT ResourceCached : public ResourceCalendar,
/**
Add a todo to the todolist.
*/
- bool addTodo( Todo *todo );
+ KDE_DEPRECATED bool addTodo( Todo *todo );
+ bool addTodo( Todo *todo, const TQString &subresource );
+
/**
Remove a todo from the todolist.
*/
@@ -195,15 +199,17 @@ class KDE_EXPORT ResourceCached : public ResourceCalendar,
/**
Add a Journal entry to calendar
*/
- virtual bool addJournal( Journal * );
+ KDE_DEPRECATED bool addJournal( Journal *journal );
+ bool addJournal( Journal *journal, const TQString &subresource );
+
/**
Remove a Journal from the calendar
*/
- virtual bool deleteJournal( Journal * );
+ bool deleteJournal( Journal * );
/**
Return Journal with given unique id.
*/
- virtual Journal *journal( const TQString &uid );
+ Journal *journal( const TQString &uid );
/**
Return list of all journals.
*/
diff --git a/libkcal/resourcecalendar.cpp b/libkcal/resourcecalendar.cpp
index c008f0308..9f611e75e 100644
--- a/libkcal/resourcecalendar.cpp
+++ b/libkcal/resourcecalendar.cpp
@@ -33,18 +33,38 @@
using namespace KCal;
ResourceCalendar::ResourceCalendar( const KConfig *config )
- : KRES::Resource( config ),mResolveConflict( false )
+ : KRES::Resource( config ), mResolveConflict( false )
{
+ mException = 0;
}
ResourceCalendar::~ResourceCalendar()
{
+ delete mException;
+}
+
+void ResourceCalendar::clearException()
+{
+ delete mException;
+ mException = 0;
+}
+
+void ResourceCalendar::setException( ErrorFormat *exception )
+{
+ delete mException;
+ mException = exception;
+}
+
+ErrorFormat *ResourceCalendar::exception()
+{
+ return mException;
}
void ResourceCalendar::setResolveConflict( bool b)
{
mResolveConflict = b;
}
+
TQString ResourceCalendar::infoText() const
{
TQString txt;
@@ -84,6 +104,12 @@ bool ResourceCalendar::addIncidence( Incidence *incidence )
return incidence->accept( v );
}
+bool ResourceCalendar::addIncidence( Incidence *incidence, const TQString &subresource )
+{
+ Incidence::AddSubResourceVisitor<ResourceCalendar> v( this, subresource );
+ return incidence->accept( v );
+}
+
bool ResourceCalendar::deleteIncidence( Incidence *incidence )
{
Incidence::DeleteVisitor<ResourceCalendar> v( this );
@@ -192,6 +218,8 @@ void ResourceCalendar::saveError( const TQString &err )
bool ResourceCalendar::setValue( const TQString &key, const TQString &value )
{
+ Q_UNUSED( key );
+ Q_UNUSED( value );
return false;
}
@@ -201,5 +229,21 @@ TQString ResourceCalendar::subresourceType( const TQString &resource )
return TQString();
}
+bool ResourceCalendar::subresourceWritable( const TQString &resource ) const
+{
+ if ( resource.isEmpty() ) {
+ return !readOnly();
+ } else {
+ return false;
+ }
+}
+
+void ResourceCalendar::beginAddingIncidences()
+{
+}
+
+void ResourceCalendar::endAddingIncidences()
+{
+}
#include "resourcecalendar.moc"
diff --git a/libkcal/resourcecalendar.h b/libkcal/resourcecalendar.h
index 3fea84a1b..91f3d1aee 100644
--- a/libkcal/resourcecalendar.h
+++ b/libkcal/resourcecalendar.h
@@ -36,6 +36,7 @@
#include "event.h"
#include "journal.h"
#include "calendar.h"
+#include "exceptions.h"
#include <kresources/resource.h>
#include <kresources/manager.h>
@@ -55,11 +56,28 @@ class CalFormat;
*/
class LIBKCAL_EXPORT ResourceCalendar : public KRES::Resource
{
- Q_OBJECT
+ Q_OBJECT
public:
ResourceCalendar( const KConfig * );
virtual ~ResourceCalendar();
+ /**
+ Clears the exception status.
+ */
+ void clearException();
+
+ /**
+ Set exception for this object. This is used by the functions of this
+ class to report errors.
+ */
+ void setException( ErrorFormat *error );
+
+ /**
+ Returns an exception, if there is any, containing information about the
+ last error that occurred.
+ */
+ ErrorFormat *exception();
+
void setResolveConflict( bool b);
virtual void writeConfig( KConfig* config );
@@ -123,8 +141,14 @@ class LIBKCAL_EXPORT ResourceCalendar : public KRES::Resource
/**
Add incidence to resource.
+ @deprecated use addIncidence(Incidence *,const TQString &) instead.
+ */
+ virtual KDE_DEPRECATED bool addIncidence( Incidence * );
+
+ /**
+ Add incidence to resource and subresource.
*/
- virtual bool addIncidence( Incidence * );
+ virtual bool addIncidence( Incidence *, const TQString &subresource );
/**
Delete incidence from resource.
@@ -139,8 +163,10 @@ class LIBKCAL_EXPORT ResourceCalendar : public KRES::Resource
/**
Add event to resource.
+ @deprecated use addEvent(Event *,const TQString&) instead.
*/
- virtual bool addEvent( Event *event ) = 0;
+ virtual KDE_DEPRECATED bool addEvent( Event *event ) = 0;
+ virtual bool addEvent( Event *event, const TQString &subresource ) = 0;
/**
Delete event from this resource.
@@ -241,8 +267,11 @@ class LIBKCAL_EXPORT ResourceCalendar : public KRES::Resource
public:
/**
Add a todo to the todolist.
+ @deprecated use addTodo(Todo *,const TQString &) instead.
*/
- virtual bool addTodo( Todo *todo ) = 0;
+ virtual KDE_DEPRECATED bool addTodo( Todo *todo ) = 0;
+ virtual bool addTodo( Todo *todo, const TQString &subresource ) = 0;
+
/**
Remove a todo from the todolist.
*/
@@ -265,8 +294,10 @@ class LIBKCAL_EXPORT ResourceCalendar : public KRES::Resource
/**
Add a Journal entry to the resource.
+ @deprecated use addJournal(Journal *,const TQString &) instead.
*/
- virtual bool addJournal( Journal * ) = 0;
+ virtual KDE_DEPRECATED bool addJournal( Journal * ) = 0;
+ virtual bool addJournal( Journal *journal, const TQString &subresource ) = 0;
/**
Remove a Journal entry from calendar.
@@ -324,6 +355,11 @@ class LIBKCAL_EXPORT ResourceCalendar : public KRES::Resource
virtual bool subresourceActive( const TQString& ) const { return true; }
/**
+ Is this subresource writable or not?
+ */
+ virtual bool subresourceWritable( const TQString& ) const;
+
+ /**
What is the label for this subresource?
*/
virtual const TQString labelForSubresource( const TQString& resource ) const
@@ -360,6 +396,18 @@ class LIBKCAL_EXPORT ResourceCalendar : public KRES::Resource
*/
virtual TQString subresourceType( const TQString &resource );
+ /**
+ * Called when we starting adding a batch of incidences.
+ * So we don't show the same warnings for each incidence.
+ */
+ virtual void beginAddingIncidences();
+
+ /**
+ * Called when we finish adding a batch of incidences.
+ * @see beginAddingIncidences()
+ */
+ virtual void endAddingIncidences();
+
public slots:
/**
(De-)activate a subresource.
@@ -402,6 +450,8 @@ class LIBKCAL_EXPORT ResourceCalendar : public KRES::Resource
bool mReceivedLoadError;
bool mReceivedSaveError;
+ ErrorFormat *mException;
+
class Private;
Private *d;
};
diff --git a/libkcal/resourcelocaldir.cpp b/libkcal/resourcelocaldir.cpp
index 1d5c9caa8..f1e00f327 100644
--- a/libkcal/resourcelocaldir.cpp
+++ b/libkcal/resourcelocaldir.cpp
@@ -128,7 +128,7 @@ bool ResourceLocalDir::doLoad()
TQString dirName = mURL.path();
if ( !( KStandardDirs::exists( dirName ) || KStandardDirs::exists( dirName + "/") ) ) {
- kdDebug(5800) << "ResourceLocalDir::load(): Directory '" << dirName
+ kdDebug(5800) << "ResourceLocalDir::load(): Directory '" << dirName
<< "' doesn't exist yet. Creating it..." << endl;
// Create the directory. Use 0775 to allow group-writable if the umask
// allows it (permissions will be 0775 & ~umask). This is desired e.g. for
@@ -139,7 +139,7 @@ bool ResourceLocalDir::doLoad()
// The directory exists. Now try to open (the files in) it.
kdDebug(5800) << "ResourceLocalDir::load(): '" << dirName << "'" << endl;
TQFileInfo dirInfo( dirName );
- if ( !( dirInfo.isDir() && dirInfo.isReadable() &&
+ if ( !( dirInfo.isDir() && dirInfo.isReadable() &&
( dirInfo.isWritable() || readOnly() ) ) )
return false;
@@ -193,6 +193,11 @@ bool ResourceLocalDir::doSave()
bool ResourceLocalDir::doSave( Incidence *incidence )
{
+ if ( mDeletedIncidences.contains( incidence ) ) {
+ mDeletedIncidences.remove( incidence );
+ return true;
+ }
+
mDirWatch.stopScan(); // do prohibit the dirty() signal and a following reload()
TQString fileName = mURL.path() + "/" + incidence->uid();
@@ -231,28 +236,46 @@ void ResourceLocalDir::reload( const TQString &file )
bool ResourceLocalDir::deleteEvent(Event *event)
{
kdDebug(5800) << "ResourceLocalDir::deleteEvent" << endl;
- if ( deleteIncidenceFile(event) )
- return( mCalendar.deleteEvent( event ) );
- else
- return( false );
+ if ( deleteIncidenceFile(event) ) {
+ if ( mCalendar.deleteEvent( event ) ) {
+ mDeletedIncidences.append( event );
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
}
bool ResourceLocalDir::deleteTodo(Todo *todo)
{
- if ( deleteIncidenceFile(todo) )
- return( mCalendar.deleteTodo( todo ) );
- else
- return( false );
+ if ( deleteIncidenceFile(todo) ) {
+ if ( mCalendar.deleteTodo( todo ) ) {
+ mDeletedIncidences.append( todo );
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
}
bool ResourceLocalDir::deleteJournal( Journal *journal )
{
- if ( deleteIncidenceFile( journal ) )
- return( mCalendar.deleteJournal( journal ) );
- else
- return( false );
+ if ( deleteIncidenceFile( journal ) ) {
+ if ( mCalendar.deleteJournal( journal ) ) {
+ mDeletedIncidences.append( journal );
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
}
diff --git a/libkcal/resourcelocaldir.h b/libkcal/resourcelocaldir.h
index e6c5526a9..e1316f212 100644
--- a/libkcal/resourcelocaldir.h
+++ b/libkcal/resourcelocaldir.h
@@ -94,6 +94,7 @@ class LIBKCAL_EXPORT ResourceLocalDir : public ResourceCached
KABC::Lock *mLock;
+ TQPtrList<Incidence>mDeletedIncidences;
class Private;
Private *d;
};
diff --git a/libkcal/resourcelocaldirconfig.cpp b/libkcal/resourcelocaldirconfig.cpp
index 2c8d89838..df2412b3d 100644
--- a/libkcal/resourcelocaldirconfig.cpp
+++ b/libkcal/resourcelocaldirconfig.cpp
@@ -26,6 +26,7 @@
#include <klocale.h>
#include <kdebug.h>
+#include <kmessagebox.h>
#include <kstandarddirs.h>
#include "vcaldrag.h"
@@ -41,7 +42,7 @@ using namespace KCal;
ResourceLocalDirConfig::ResourceLocalDirConfig( TQWidget* parent, const char* name )
: KRES::ConfigWidget( parent, name )
{
- resize( 245, 115 );
+ resize( 245, 115 );
TQGridLayout *mainLayout = new TQGridLayout( this, 2, 2 );
TQLabel *label = new TQLabel( i18n( "Location:" ), this );
@@ -65,6 +66,14 @@ void ResourceLocalDirConfig::saveSettings( KRES::Resource *resource )
ResourceLocalDir* res = static_cast<ResourceLocalDir*>( resource );
if (res) {
res->mURL = mURL->url();
+ if ( mURL->url().isEmpty() && !resource->readOnly() ) {
+ KMessageBox::information(
+ this,
+ i18n( "No location specified. The calendar will be read-only." ),
+ TQString(),
+ "ResourceLocalDirUrl" );
+ resource->setReadOnly( true );
+ }
} else
kdDebug(5700) << "ERROR: ResourceLocalDirConfig::saveSettings(): no ResourceLocalDir, cast failed" << endl;
}
diff --git a/libkcal/scheduler.cpp b/libkcal/scheduler.cpp
index 802c977f6..6e3cf3850 100644
--- a/libkcal/scheduler.cpp
+++ b/libkcal/scheduler.cpp
@@ -25,12 +25,15 @@
#include <kmessagebox.h>
#include <kstandarddirs.h>
+#include "calhelper.h"
#include "event.h"
#include "todo.h"
#include "freebusy.h"
#include "icalformat.h"
#include "calendar.h"
+#include "calendarresources.h"
#include "freebusycache.h"
+#include "assignmentvisitor.h"
#include "scheduler.h"
@@ -94,7 +97,10 @@ FreeBusyCache *Scheduler::freeBusyCache() const
return d->mFreeBusyCache;
}
-bool Scheduler::acceptTransaction(IncidenceBase *incidence,Method method,ScheduleMessage::Status status)
+bool Scheduler::acceptTransaction( IncidenceBase *incidence,
+ Method method,
+ ScheduleMessage::Status status,
+ const TQString &attendee )
{
kdDebug(5800) << "Scheduler::acceptTransaction, method="
<< methodName( method ) << endl;
@@ -103,11 +109,11 @@ bool Scheduler::acceptTransaction(IncidenceBase *incidence,Method method,Schedul
case Publish:
return acceptPublish(incidence, status, method);
case Request:
- return acceptRequest(incidence, status);
+ return acceptRequest( incidence, status, attendee );
case Add:
return acceptAdd(incidence, status);
case Cancel:
- return acceptCancel(incidence, status);
+ return acceptCancel(incidence, status, attendee );
case Declinecounter:
return acceptDeclineCounter(incidence, status);
case Reply:
@@ -185,24 +191,28 @@ bool Scheduler::acceptPublish( IncidenceBase *newIncBase,
bool res = false;
kdDebug(5800) << "Scheduler::acceptPublish, status="
- << ScheduleMessage::statusName( status ) << endl;
+ << ScheduleMessage::statusName( status ) << endl;
Incidence *newInc = static_cast<Incidence *>( newIncBase );
Incidence *calInc = mCalendar->incidence( newIncBase->uid() );
switch ( status ) {
case ScheduleMessage::Unknown:
case ScheduleMessage::PublishNew:
case ScheduleMessage::PublishUpdate:
- res = true;
- if ( calInc ) {
+ if ( calInc && newInc ) {
if ( (newInc->revision() > calInc->revision()) ||
(newInc->revision() == calInc->revision() &&
newInc->lastModified() > calInc->lastModified() ) ) {
- mCalendar->deleteIncidence( calInc );
- } else
- res = false;
+ AssignmentVisitor visitor;
+ const TQString oldUid = calInc->uid();
+ if ( !visitor.assign( calInc, newInc ) ) {
+ kdError(5800) << "assigning different incidence types" << endl;
+ } else {
+ calInc->setUid( oldUid );
+ calInc->setSchedulingID( newInc->uid() );
+ res = true;
+ }
+ }
}
- if ( res )
- mCalendar->addIncidence( newInc );
break;
case ScheduleMessage::Obsolete:
res = true;
@@ -214,36 +224,169 @@ bool Scheduler::acceptPublish( IncidenceBase *newIncBase,
return res;
}
-bool Scheduler::acceptRequest(IncidenceBase *newIncBase, ScheduleMessage::Status /* status */)
+bool Scheduler::acceptRequest( IncidenceBase *incidence,
+ ScheduleMessage::Status status,
+ const TQString &attendee )
{
- if (newIncBase->type()=="FreeBusy") {
+ Incidence *inc = static_cast<Incidence *>(incidence);
+ if ( !inc )
+ return false;
+ if (inc->type()=="FreeBusy") {
// reply to this request is handled in korganizer's incomingdialog
return true;
}
- Incidence *newInc = dynamic_cast<Incidence *>( newIncBase );
- if ( newInc ) {
- bool res = true;
- Incidence *exInc = mCalendar->incidenceFromSchedulingID( newIncBase->uid() );
- if ( exInc ) {
- res = false;
- if ( (newInc->revision() > exInc->revision()) ||
- (newInc->revision() == exInc->revision() &&
- newInc->lastModified()>exInc->lastModified()) ) {
- mCalendar->deleteIncidence( exInc );
- res = true;
+
+ const Incidence::List existingIncidences = mCalendar->incidencesFromSchedulingID( inc->uid() );
+ kdDebug(5800) << "Scheduler::acceptRequest status=" << ScheduleMessage::statusName( status ) << ": found " << existingIncidences.count() << " incidences with schedulingID " << inc->schedulingID() << endl;
+ Incidence::List::ConstIterator incit = existingIncidences.begin();
+ for ( ; incit != existingIncidences.end() ; ++incit ) {
+ Incidence* const i = *incit;
+ kdDebug(5800) << "Considering this found event ("
+ << ( i->isReadOnly() ? "readonly" : "readwrite" )
+ << ") :" << mFormat->toString( i ) << endl;
+ // If it's readonly, we can't possible update it.
+ if ( i->isReadOnly() )
+ continue;
+ if ( i->revision() <= inc->revision() ) {
+ // The new incidence might be an update for the found one
+ bool isUpdate = true;
+ // Code for new invitations:
+ // If you think we could check the value of "status" to be RequestNew: we can't.
+ // It comes from a similar check inside libical, where the event is compared to
+ // other events in the calendar. But if we have another version of the event around
+ // (e.g. shared folder for a group), the status could be RequestNew, Obsolete or Updated.
+ kdDebug(5800) << "looking in " << i->uid() << "'s attendees" << endl;
+ // This is supposed to be a new request, not an update - however we want to update
+ // the existing one to handle the "clicking more than once on the invitation" case.
+ // So check the attendee status of the attendee.
+ const KCal::Attendee::List attendees = i->attendees();
+ KCal::Attendee::List::ConstIterator ait;
+ for ( ait = attendees.begin(); ait != attendees.end(); ++ait ) {
+ if( (*ait)->email() == attendee && (*ait)->status() == Attendee::NeedsAction ) {
+ // This incidence wasn't created by me - it's probably in a shared folder
+ // and meant for someone else, ignore it.
+ kdDebug(5800) << "ignoring " << i->uid() << " since I'm still NeedsAction there" << endl;
+ isUpdate = false;
+ break;
+ }
+ }
+ if ( isUpdate ) {
+ if ( i->revision() == inc->revision() &&
+ i->lastModified() > inc->lastModified() ) {
+ // This isn't an update - the found incidence was modified more recently
+ kdDebug(5800) << "This isn't an update - the found incidence was modified more recently" << endl;
+ deleteTransaction(incidence);
+ return false;
+ }
+ kdDebug(5800) << "replacing existing incidence " << i->uid() << endl;
+ bool res = true;
+ AssignmentVisitor visitor;
+ const TQString oldUid = i->uid();
+ if ( !visitor.assign( i, inc ) ) {
+ kdError(5800) << "assigning different incidence types" << endl;
+ res = false;
+ } else {
+ i->setUid( oldUid );
+ i->setSchedulingID( inc->uid() );
+ }
+ deleteTransaction( incidence );
+ return res;
}
+ } else {
+ // This isn't an update - the found incidence has a bigger revision number
+ kdDebug(5800) << "This isn't an update - the found incidence has a bigger revision number" << endl;
+ deleteTransaction(incidence);
+ return false;
+ }
+ }
+
+ // Move the uid to be the schedulingID and make a unique UID
+ inc->setSchedulingID( inc->uid() );
+ inc->setUid( CalFormat::createUniqueId() );
+ // notify the user in case this is an update and we didn't find the to-be-updated incidence
+ if ( existingIncidences.count() == 0 && inc->revision() > 0 ) {
+ KMessageBox::information(
+ 0,
+ i18n( "<qt>"
+ "You accepted an invitation update, but an earlier version of the "
+ "item could not be found in your calendar.<p>"
+ "This may have occurred because:<ul>"
+ "<li>the organizer did not include you in the original invitation</li>"
+ "<li>you did not accept the original invitation yet</li>"
+ "<li>you deleted the original invitation from your calendar</li>"
+ "<li>you no longer have access to the calendar containing the invitation</li>"
+ "</ul>"
+ "This is not a problem, but we thought you should know.</qt>" ),
+ i18n( "Cannot find invitation to be updated" ), "AcceptCantFindIncidence" );
+ }
+ kdDebug(5800) << "Storing new incidence with scheduling uid=" << inc->schedulingID()
+ << " and uid=" << inc->uid() << endl;
+
+ CalendarResources *stdcal = dynamic_cast<CalendarResources *>( mCalendar );
+ if( stdcal && !stdcal->hasCalendarResources() ) {
+ KMessageBox::sorry(
+ 0,
+ i18n( "No calendars found, unable to save the invitation." ) );
+ return false;
+ }
+
+ // FIXME: This is a nasty hack, since we need to set a parent for the
+ // resource selection dialog. However, we don't have any UI methods
+ // in the calendar, only in the CalendarResources::DestinationPolicy
+ // So we need to type-cast it and extract it from the CalendarResources
+ TQWidget *tmpparent = 0;
+ if ( stdcal ) {
+ tmpparent = stdcal->dialogParentWidget();
+ stdcal->setDialogParentWidget( 0 );
+ }
+
+TryAgain:
+ bool success = false;
+ if ( stdcal ) {
+ success = stdcal->addIncidence( inc );
+ } else {
+ success = mCalendar->addIncidence( inc );
+ }
+
+ if ( !success ) {
+ ErrorFormat *e = stdcal ? stdcal->exception() : 0;
+
+ if ( e && e->errorCode() == KCal::ErrorFormat::UserCancel &&
+ KMessageBox::warningYesNo(
+ 0,
+ i18n( "You canceled the save operation. Therefore, the appointment will not be "
+ "stored in your calendar even though you accepted the invitation. "
+ "Are you certain you want to discard this invitation? " ),
+ i18n( "Discard this invitation?" ),
+ i18n( "Discard" ), i18n( "Go Back to Folder Selection" ) ) == KMessageBox::Yes ) {
+ KMessageBox::information(
+ 0,
+ i18n( "The invitation \"%1\" was not saved to your calendar "
+ "but you are still listed as an attendee for that appointment.\n"
+ "If you mistakenly accepted the invitation or do not plan to attend, please notify "
+ "the organizer %2 and ask them to remove you from the attendee list.").
+ arg( inc->summary(), inc->organizer().fullName() ) );
+ deleteTransaction( incidence );
+ return true;
+ } else {
+ goto TryAgain;
}
- if ( res ) {
- // Move the uid to be the schedulingID and make a unique UID
- newInc->setSchedulingID( newInc->uid() );
- newInc->setUid( CalFormat::createUniqueId() );
- mCalendar->addIncidence(newInc);
+ // We can have a failure if the user pressed [cancel] in the resource
+ // selectdialog, so check the exception.
+ if ( !e ||
+ ( e && ( e->errorCode() != KCal::ErrorFormat::UserCancel &&
+ e->errorCode() != KCal::ErrorFormat::NoWritableFound ) ) ) {
+ TQString errMessage = i18n( "Unable to save %1 \"%2\"." ).
+ arg( i18n( inc->type() ) ).
+ arg( inc->summary() );
+ KMessageBox::sorry( 0, errMessage );
}
- deleteTransaction( newIncBase );
- return res;
+ return false;
}
- return false;
+
+ deleteTransaction( incidence );
+ return true;
}
bool Scheduler::acceptAdd(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
@@ -252,22 +395,131 @@ bool Scheduler::acceptAdd(IncidenceBase *incidence,ScheduleMessage::Status /* st
return false;
}
-bool Scheduler::acceptCancel(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
+bool Scheduler::acceptCancel( IncidenceBase *incidence,
+ ScheduleMessage::Status status,
+ const TQString &attendee )
{
+ Incidence *inc = static_cast<Incidence *>( incidence );
+ if ( !inc ) {
+ return false;
+ }
+
+ if ( inc->type() == "FreeBusy" ) {
+ // reply to this request is handled in korganizer's incomingdialog
+ return true;
+ }
+
+ const Incidence::List existingIncidences = mCalendar->incidencesFromSchedulingID( inc->uid() );
+ kdDebug(5800) << "Scheduler::acceptCancel="
+ << ScheduleMessage::statusName( status )
+ << ": found " << existingIncidences.count()
+ << " incidences with schedulingID " << inc->schedulingID()
+ << endl;
+
+ // Remove existing incidences that aren't stored in my calendar as we
+ // will never attempt to remove those -- even if we have write-access.
+ Incidence::List myExistingIncidences;
+ Incidence::List::ConstIterator incit = existingIncidences.begin();
+ for ( ; incit != existingIncidences.end() ; ++incit ) {
+ Incidence *i = *incit;
+ if ( CalHelper::isMyCalendarIncidence( mCalendar, i ) ) {
+ myExistingIncidences.append( i );
+ }
+ }
+
bool ret = false;
+ incit = myExistingIncidences.begin();
+ for ( ; incit != myExistingIncidences.end() ; ++incit ) {
+ Incidence *i = *incit;
+ kdDebug(5800) << "Considering this found event ("
+ << ( i->isReadOnly() ? "readonly" : "readwrite" )
+ << ") :" << mFormat->toString( i ) << endl;
+
+ // If it's readonly, we can't possible remove it.
+ if ( i->isReadOnly() ) {
+ continue;
+ }
+
+ // Code for new invitations:
+ // We cannot check the value of "status" to be RequestNew because
+ // "status" comes from a similar check inside libical, where the event
+ // is compared to other events in the calendar. But if we have another
+ // version of the event around (e.g. shared folder for a group), the
+ // status could be RequestNew, Obsolete or Updated.
+ kdDebug(5800) << "looking in " << i->uid() << "'s attendees" << endl;
+
+ // This is supposed to be a new request, not an update - however we want
+ // to update the existing one to handle the "clicking more than once
+ // on the invitation" case. So check the attendee status of the attendee.
+ bool isMine = true;
+ const KCal::Attendee::List attendees = i->attendees();
+ KCal::Attendee::List::ConstIterator ait;
+ for ( ait = attendees.begin(); ait != attendees.end(); ++ait ) {
+ if ( (*ait)->email() == attendee &&
+ (*ait)->status() == Attendee::NeedsAction ) {
+ // This incidence wasn't created by me - it's probably in a shared
+ // folder and meant for someone else, ignore it.
+ kdDebug(5800) << "ignoring " << i->uid()
+ << " since I'm still NeedsAction there" << endl;
+ isMine = false;
+ break;
+ }
+ }
+
+ if ( isMine ) {
+ kdDebug(5800) << "removing existing incidence " << i->uid() << endl;
+ if ( i->type() == "Event" ) {
+ Event *event = mCalendar->event( i->uid() );
+ ret = ( event && mCalendar->deleteEvent( event ) );
+ } else if ( i->type() == "Todo" ) {
+ Todo *todo = mCalendar->todo( i->uid() );
+ ret = ( todo && mCalendar->deleteTodo( todo ) );
+ }
+ deleteTransaction( incidence );
+ return ret;
+ }
+ }
+
+ // in case we didn't find the to-be-removed incidence
+ if ( myExistingIncidences.count() > 0 && inc->revision() > 0 ) {
+ KMessageBox::information(
+ 0,
+ i18n( "The event or task could not be removed from your calendar. "
+ "Maybe it has already been deleted or is not owned by you. "
+ "Or it might belong to a read-only or disabled calendar." ) );
+ }
+ deleteTransaction( incidence );
+ return ret;
+}
+
+bool Scheduler::acceptCancel(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
+{
const IncidenceBase *toDelete = mCalendar->incidenceFromSchedulingID( incidence->uid() );
+
+ bool ret = true;
if ( toDelete ) {
- Event *even = mCalendar->event(toDelete->uid());
- if (even) {
- mCalendar->deleteEvent(even);
- ret = true;
- } else {
- Todo *todo = mCalendar->todo(toDelete->uid());
- if (todo) {
- mCalendar->deleteTodo(todo);
- ret = true;
- }
+ if ( toDelete->type() == "Event" ) {
+ Event *event = mCalendar->event( toDelete->uid() );
+ ret = ( event && mCalendar->deleteEvent( event ) );
+ } else if ( toDelete->type() == "Todo" ) {
+ Todo *todo = mCalendar->todo( toDelete->uid() );
+ ret = ( todo && mCalendar->deleteTodo( todo ) );
}
+ } else {
+ // only complain if we failed to determine the toDelete incidence
+ // on non-initial request.
+ Incidence *inc = static_cast<Incidence *>( incidence );
+ if ( inc->revision() > 0 ) {
+ ret = false;
+ }
+ }
+
+ if ( !ret ) {
+ KMessageBox::information(
+ 0,
+ i18n( "The event or task to be canceled could not be removed from your calendar. "
+ "Maybe it has already been deleted or is not owned by you. "
+ "Or it might belong to a read-only or disabled calendar." ) );
}
deleteTransaction(incidence);
return ret;
@@ -370,13 +622,25 @@ bool Scheduler::acceptReply(IncidenceBase *incidence,ScheduleMessage::Status /*
// send update about new participants
if ( attendeeAdded ) {
+ bool sendMail = false;
+ if ( ev || to ) {
+ if ( KMessageBox::questionYesNo( 0, i18n( "An attendee was added to the incidence. "
+ "Do you want to email the attendees an update message?" ),
+ i18n( "Attendee Added" ), i18n( "Send Messages" ),
+ i18n( "Do Not Send" ) ) == KMessageBox::Yes ) {
+ sendMail = true;
+ }
+ }
+
if ( ev ) {
ev->setRevision( ev->revision() + 1 );
- performTransaction( ev, Scheduler::Request );
+ if ( sendMail )
+ performTransaction( ev, Scheduler::Request );
}
if ( to ) {
- to->setRevision( ev->revision() + 1 );
- performTransaction( to, Scheduler::Request );
+ to->setRevision( to->revision() + 1 );
+ if ( sendMail )
+ performTransaction( to, Scheduler::Request );
}
}
diff --git a/libkcal/scheduler.h b/libkcal/scheduler.h
index 17e19ec47..bf22c9c81 100644
--- a/libkcal/scheduler.h
+++ b/libkcal/scheduler.h
@@ -49,14 +49,14 @@ class ScheduleMessage
*/
enum Status { PublishNew, PublishUpdate, Obsolete, RequestNew,
RequestUpdate, Unknown };
-
+
/**
Create a scheduling message with method as defined in Scheduler::Method
and a status.
*/
ScheduleMessage( IncidenceBase *, int method, Status status );
~ScheduleMessage() {};
-
+
/**
Return event associated with this message.
*/
@@ -102,13 +102,13 @@ class LIBKCAL_EXPORT Scheduler
*/
enum Method { Publish,Request,Refresh,Cancel,Add,Reply,Counter,
Declinecounter,NoMethod };
-
+
/**
Create scheduler for calendar specified as argument.
*/
Scheduler( Calendar *calendar );
virtual ~Scheduler();
-
+
/**
iTIP publish action
*/
@@ -121,8 +121,8 @@ class LIBKCAL_EXPORT Scheduler
virtual bool performTransaction( IncidenceBase *incidence,
Method method ) = 0;
/**
- Perform iTIP transaction on incidence to specified recipient(s). The
- method is specified as the method argumanet and can be any valid iTIP
+ Perform iTIP transaction on incidence to specified recipient(s). The
+ method is specified as the method argumanet and can be any valid iTIP
method.
*/
virtual bool performTransaction( IncidenceBase *incidence, Method method,
@@ -136,10 +136,12 @@ class LIBKCAL_EXPORT Scheduler
Accept transaction. The incidence argument specifies the iCal compoennt
on which the transaction acts. The status is the result of processing a
iTIP message with the current calendar and specifies the action to be
- taken for this incidence.
+ taken for this incidence. The attendee is the email address of the person
+ on who's behalf this transaction is to be performed.
*/
bool acceptTransaction( IncidenceBase *, Method method,
- ScheduleMessage::Status status );
+ ScheduleMessage::Status status,
+ const TQString& attendee = TQString::null );
/**
Return a machine-readable name for a iTIP method.
@@ -151,7 +153,7 @@ class LIBKCAL_EXPORT Scheduler
static TQString translatedMethodName( Method );
virtual bool deleteTransaction( IncidenceBase *incidence );
-
+
/**
Returns the directory where the free-busy information is stored.
*/
@@ -169,9 +171,12 @@ class LIBKCAL_EXPORT Scheduler
protected:
bool acceptPublish( IncidenceBase *, ScheduleMessage::Status status,
Method method );
- bool acceptRequest( IncidenceBase *, ScheduleMessage::Status status );
+ bool acceptRequest( IncidenceBase *, ScheduleMessage::Status status,
+ const TQString & attendee );
bool acceptAdd( IncidenceBase *, ScheduleMessage::Status status );
- bool acceptCancel( IncidenceBase *, ScheduleMessage::Status status );
+ KDE_DEPRECATED bool acceptCancel( IncidenceBase *, ScheduleMessage::Status status );
+ bool acceptCancel( IncidenceBase *, ScheduleMessage::Status status,
+ const TQString & attendee );
bool acceptDeclineCounter( IncidenceBase *,
ScheduleMessage::Status status );
bool acceptReply( IncidenceBase *, ScheduleMessage::Status status,
diff --git a/libkcal/tests/Makefile.am b/libkcal/tests/Makefile.am
index 6e7096a12..1a09143ef 100644
--- a/libkcal/tests/Makefile.am
+++ b/libkcal/tests/Makefile.am
@@ -18,7 +18,8 @@ check_PROGRAMS = testtostring \
testrecurson \
testrecurrencetype \
testvcalexport \
- testfb
+ testfb \
+ testcalselectdialog
METASOURCES = AUTO
@@ -76,6 +77,10 @@ testfb_SOURCES = testfb.cpp
testfb_LDFLAGS = $(all_libraries) $(KDE_RPATH)
testfb_LDADD = ../libkcal.la
+testcalselectdialog_SOURCES = testcalselectdialog.cpp
+testcalselectdialog_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+testcalselectdialog_LDADD = ../libkcal.la
+
TESTFILES = test1.ics test2.ics test3.ics test4.ics test5.ics test_Mozilla.ics
check-local: readandwrite testrecurrence testrecurprevious testrecurson testvcalexport
diff --git a/libkcal/tests/data/RecurrenceRule/ConnectDaily/ConnectDaily11.ics.recurson.ref b/libkcal/tests/data/RecurrenceRule/ConnectDaily/ConnectDaily11.ics.recurson.ref
index 1698d7d26..783c984af 100644
--- a/libkcal/tests/data/RecurrenceRule/ConnectDaily/ConnectDaily11.ics.recurson.ref
+++ b/libkcal/tests/data/RecurrenceRule/ConnectDaily/ConnectDaily11.ics.recurson.ref
@@ -1,4 +1,3 @@
-2005-04-01
2005-05-03
2005-05-05
2005-06-07
diff --git a/libkcal/tests/data/RecurrenceRule/KAlarm_3.4/KAlarm_TestCase06.ics.recurson.ref b/libkcal/tests/data/RecurrenceRule/KAlarm_3.4/KAlarm_TestCase06.ics.recurson.ref
index 2562eae7c..8b1378917 100644
--- a/libkcal/tests/data/RecurrenceRule/KAlarm_3.4/KAlarm_TestCase06.ics.recurson.ref
+++ b/libkcal/tests/data/RecurrenceRule/KAlarm_3.4/KAlarm_TestCase06.ics.recurson.ref
@@ -1,2 +1 @@
-2005-05-31
diff --git a/libkcal/tests/data/RecurrenceRule/LibICal/LibICal_TestCase02.ics.recurson.ref b/libkcal/tests/data/RecurrenceRule/LibICal/LibICal_TestCase02.ics.recurson.ref
index eb9f81585..a17df247a 100644
--- a/libkcal/tests/data/RecurrenceRule/LibICal/LibICal_TestCase02.ics.recurson.ref
+++ b/libkcal/tests/data/RecurrenceRule/LibICal/LibICal_TestCase02.ics.recurson.ref
@@ -1,4 +1,3 @@
-2002-04-02
2002-04-04
2002-04-11
2002-04-18
diff --git a/libkcal/tests/data/RecurrenceRule/LibICal/LibICal_TestCase24.ics.recurson.ref b/libkcal/tests/data/RecurrenceRule/LibICal/LibICal_TestCase24.ics.recurson.ref
index 7abf1e5ad..13edfa434 100644
--- a/libkcal/tests/data/RecurrenceRule/LibICal/LibICal_TestCase24.ics.recurson.ref
+++ b/libkcal/tests/data/RecurrenceRule/LibICal/LibICal_TestCase24.ics.recurson.ref
@@ -1,4 +1,3 @@
-1997-09-02
1997-09-03
1997-09-05
1997-09-15
diff --git a/libkcal/tests/data/RecurrenceRule/LibICal/LibICal_TestCase42.ics.recurson.ref b/libkcal/tests/data/RecurrenceRule/LibICal/LibICal_TestCase42.ics.recurson.ref
index 887df0de5..e1d367ade 100644
--- a/libkcal/tests/data/RecurrenceRule/LibICal/LibICal_TestCase42.ics.recurson.ref
+++ b/libkcal/tests/data/RecurrenceRule/LibICal/LibICal_TestCase42.ics.recurson.ref
@@ -1,4 +1,3 @@
-1997-09-02
1998-02-13
1998-03-13
1998-11-13
diff --git a/libkcal/tests/data/RecurrenceRule/RFC2445/RFC2445_RRULETestCase12.ics.recurson.ref b/libkcal/tests/data/RecurrenceRule/RFC2445/RFC2445_RRULETestCase12.ics.recurson.ref
index 7abf1e5ad..24ad0551f 100644
--- a/libkcal/tests/data/RecurrenceRule/RFC2445/RFC2445_RRULETestCase12.ics.recurson.ref
+++ b/libkcal/tests/data/RecurrenceRule/RFC2445/RFC2445_RRULETestCase12.ics.recurson.ref
@@ -1,4 +1,3 @@
-1997-09-02
1997-09-03
1997-09-05
1997-09-15
@@ -23,4 +22,3 @@
1997-12-10
1997-12-12
1997-12-22
-
diff --git a/libkcal/tests/data/RecurrenceRule/UntilInUTC/Until_TestCase02.ics.recurson.ref b/libkcal/tests/data/RecurrenceRule/UntilInUTC/Until_TestCase02.ics.recurson.ref
index 2f3a7e16f..e69de29bb 100644
--- a/libkcal/tests/data/RecurrenceRule/UntilInUTC/Until_TestCase02.ics.recurson.ref
+++ b/libkcal/tests/data/RecurrenceRule/UntilInUTC/Until_TestCase02.ics.recurson.ref
@@ -1 +0,0 @@
-1997-12-15
diff --git a/libkcal/tests/data/RecurrenceRule/UntilInUTC/Until_TestCase04.ics.recurson.ref b/libkcal/tests/data/RecurrenceRule/UntilInUTC/Until_TestCase04.ics.recurson.ref
index 6fca0d2fd..f57f89d0e 100644
--- a/libkcal/tests/data/RecurrenceRule/UntilInUTC/Until_TestCase04.ics.recurson.ref
+++ b/libkcal/tests/data/RecurrenceRule/UntilInUTC/Until_TestCase04.ics.recurson.ref
@@ -1,2 +1 @@
1997-09-02
-
diff --git a/libkcal/tests/data/RecurrenceRule/unsorted/lastworkday.ics.recurson.ref b/libkcal/tests/data/RecurrenceRule/unsorted/lastworkday.ics.recurson.ref
index 05df6b377..c55b5583d 100644
--- a/libkcal/tests/data/RecurrenceRule/unsorted/lastworkday.ics.recurson.ref
+++ b/libkcal/tests/data/RecurrenceRule/unsorted/lastworkday.ics.recurson.ref
@@ -1,4 +1,3 @@
-2005-05-12
2005-05-31
2005-06-30
2005-07-29
diff --git a/libkcal/tests/data/RecurrenceRule/unsorted/monthly.ics.recurson.ref b/libkcal/tests/data/RecurrenceRule/unsorted/monthly.ics.recurson.ref
index bbf1358c2..4c2c61aae 100644
--- a/libkcal/tests/data/RecurrenceRule/unsorted/monthly.ics.recurson.ref
+++ b/libkcal/tests/data/RecurrenceRule/unsorted/monthly.ics.recurson.ref
@@ -1,4 +1,3 @@
-2005-05-12
2005-05-18
2005-05-24
2005-06-15
diff --git a/libkcal/tests/data/RecurrenceRule/unsorted/rdate.ics.recurson.ref b/libkcal/tests/data/RecurrenceRule/unsorted/rdate.ics.recurson.ref
index 4082c9c20..70712a5e1 100644
--- a/libkcal/tests/data/RecurrenceRule/unsorted/rdate.ics.recurson.ref
+++ b/libkcal/tests/data/RecurrenceRule/unsorted/rdate.ics.recurson.ref
@@ -1,4 +1,3 @@
-2005-05-12
2005-05-14
2005-05-16
2005-05-17
diff --git a/libkcal/tests/data/RecurrenceRule/unsorted/test1.ics.recurson.ref b/libkcal/tests/data/RecurrenceRule/unsorted/test1.ics.recurson.ref
index 71cfa3b67..5bd295fc9 100644
--- a/libkcal/tests/data/RecurrenceRule/unsorted/test1.ics.recurson.ref
+++ b/libkcal/tests/data/RecurrenceRule/unsorted/test1.ics.recurson.ref
@@ -1,4 +1,3 @@
-2005-05-12
2007-01-07
2007-01-14
2007-01-21
diff --git a/libkcal/tests/data/RecurrenceRule/unsorted/weekly.ics.recurson.ref b/libkcal/tests/data/RecurrenceRule/unsorted/weekly.ics.recurson.ref
index 59d81cdc1..1b1e01918 100644
--- a/libkcal/tests/data/RecurrenceRule/unsorted/weekly.ics.recurson.ref
+++ b/libkcal/tests/data/RecurrenceRule/unsorted/weekly.ics.recurson.ref
@@ -1,4 +1,3 @@
-2005-05-12
2005-05-23
2005-05-25
2005-06-06
@@ -293,3 +292,210 @@
2010-12-15
2010-12-27
2010-12-29
+2011-01-10
+2011-01-12
+2011-01-24
+2011-01-26
+2011-02-07
+2011-02-09
+2011-02-21
+2011-02-23
+2011-03-07
+2011-03-09
+2011-03-21
+2011-03-23
+2011-04-04
+2011-04-06
+2011-04-18
+2011-04-20
+2011-05-02
+2011-05-04
+2011-05-16
+2011-05-18
+2011-05-30
+2011-06-01
+2011-06-13
+2011-06-15
+2011-06-27
+2011-06-29
+2011-07-11
+2011-07-13
+2011-07-25
+2011-07-27
+2011-08-08
+2011-08-10
+2011-08-22
+2011-08-24
+2011-09-05
+2011-09-07
+2011-09-19
+2011-09-21
+2011-10-03
+2011-10-05
+2011-10-17
+2011-10-19
+2011-10-31
+2011-11-02
+2011-11-14
+2011-11-16
+2011-11-28
+2011-11-30
+2011-12-12
+2011-12-14
+2011-12-26
+2011-12-28
+2012-01-09
+2012-01-11
+2012-01-23
+2012-01-25
+2012-02-06
+2012-02-08
+2012-02-20
+2012-02-22
+2012-03-05
+2012-03-07
+2012-03-19
+2012-03-21
+2012-04-02
+2012-04-04
+2012-04-16
+2012-04-18
+2012-04-30
+2012-05-02
+2012-05-14
+2012-05-16
+2012-05-28
+2012-05-30
+2012-06-11
+2012-06-13
+2012-06-25
+2012-06-27
+2012-07-09
+2012-07-11
+2012-07-23
+2012-07-25
+2012-08-06
+2012-08-08
+2012-08-20
+2012-08-22
+2012-09-03
+2012-09-05
+2012-09-17
+2012-09-19
+2012-10-01
+2012-10-03
+2012-10-15
+2012-10-17
+2012-10-29
+2012-10-31
+2012-11-12
+2012-11-14
+2012-11-26
+2012-11-28
+2012-12-10
+2012-12-12
+2012-12-24
+2012-12-26
+2013-01-07
+2013-01-09
+2013-01-21
+2013-01-23
+2013-02-04
+2013-02-06
+2013-02-18
+2013-02-20
+2013-03-04
+2013-03-06
+2013-03-18
+2013-03-20
+2013-04-01
+2013-04-03
+2013-04-15
+2013-04-17
+2013-04-29
+2013-05-01
+2013-05-13
+2013-05-15
+2013-05-27
+2013-05-29
+2013-06-10
+2013-06-12
+2013-06-24
+2013-06-26
+2013-07-08
+2013-07-10
+2013-07-22
+2013-07-24
+2013-08-05
+2013-08-07
+2013-08-19
+2013-08-21
+2013-09-02
+2013-09-04
+2013-09-16
+2013-09-18
+2013-09-30
+2013-10-02
+2013-10-14
+2013-10-16
+2013-10-28
+2013-10-30
+2013-11-11
+2013-11-13
+2013-11-25
+2013-11-27
+2013-12-09
+2013-12-11
+2013-12-23
+2013-12-25
+2014-01-06
+2014-01-08
+2014-01-20
+2014-01-22
+2014-02-03
+2014-02-05
+2014-02-17
+2014-02-19
+2014-03-03
+2014-03-05
+2014-03-17
+2014-03-19
+2014-03-31
+2014-04-02
+2014-04-14
+2014-04-16
+2014-04-28
+2014-04-30
+2014-05-12
+2014-05-14
+2014-05-26
+2014-05-28
+2014-06-09
+2014-06-11
+2014-06-23
+2014-06-25
+2014-07-07
+2014-07-09
+2014-07-21
+2014-07-23
+2014-08-04
+2014-08-06
+2014-08-18
+2014-08-20
+2014-09-01
+2014-09-03
+2014-09-15
+2014-09-17
+2014-09-29
+2014-10-01
+2014-10-13
+2014-10-15
+2014-10-27
+2014-10-29
+2014-11-10
+2014-11-12
+2014-11-24
+2014-11-26
+2014-12-08
+2014-12-10
+2014-12-22
diff --git a/libkcal/tests/runtestcase.pl b/libkcal/tests/runtestcase.pl
index 52e6ead1e..4cad27cc6 100755
--- a/libkcal/tests/runtestcase.pl
+++ b/libkcal/tests/runtestcase.pl
@@ -78,7 +78,7 @@ sub checkfile()
exit 1;
}
while( <REF> ) {
- push @ref, $_;
+ push @ref, $_ if($_ !~ m/^\s*$/); #skip blank lines in the ref
}
close REF;
@@ -92,10 +92,13 @@ sub checkfile()
$line = 0;
my $errorlines = 0;
while( <READ> ) {
+ next if ($_ =~ m/^\s*$/); #skip blank lines in the output
$out = $_;
$ref = @ref[$i++];
$line++;
+ $out =~ s/\s*$//; #remove trailing whitespace
+ $ref =~ s/\s*$//; #remove trailing whitespace
# DTSTAMP, LAST-MODIFIED and CREATED might be different to the reference...
if ( $out =~ /^DTSTAMP:[0-9ZT]+\r?$/ && $ref =~ /^DTSTAMP:[0-9ZT]+\r?$/ ) {
next;
@@ -122,7 +125,6 @@ sub checkfile()
print " <Remaining error suppressed>\n";
}
}
-
}
close READ;
@@ -150,7 +152,7 @@ sub checkfile()
} else {
print "\n FAILED: $error errors found.\n";
if ( $error > 5 ) {
- system( "diff -u $file.$id.ref $outfile" );
+ system( "diff -u $file.$id.ref $outfile" );
}
system( "touch FAILED" );
exit 1;
diff --git a/libkcal/tests/testcalselectdialog.cpp b/libkcal/tests/testcalselectdialog.cpp
new file mode 100644
index 000000000..5c5130450
--- /dev/null
+++ b/libkcal/tests/testcalselectdialog.cpp
@@ -0,0 +1,45 @@
+/*
+ Copyright (c) 2010 Klar�lvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
+
+ 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "calselectdialog.h"
+using namespace KCal;
+
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+int main( int argc, char **argv )
+{
+ KCmdLineArgs::init( argc, argv, "testcalselectdialog", 0,
+ "KCalSelectDialogTest", "1.0",
+ "kcalselectedialog test app" );
+ KApplication app;
+ TQStringList cals;
+ cals << "standard" << "shared" << "mine" << "yours";
+ TQString cal = CalSelectDialog::getItem( i18n( "Calendar Selection" ),
+ i18n( "Please select a calendar" ),
+ cals );
+
+ if ( !cal.isEmpty() ) {
+ kdDebug() << "Selected calendar " << cal << endl;
+ } else {
+ kdDebug() << "nothing selected. user cancel" << endl;
+ }
+}
diff --git a/libkcal/todo.cpp b/libkcal/todo.cpp
index 9787ff2ad..b3fe65d9c 100644
--- a/libkcal/todo.cpp
+++ b/libkcal/todo.cpp
@@ -116,10 +116,13 @@ void Todo::setDtDue(const TQDateTime &dtDue, bool first )
TQDateTime Todo::dtDue( bool first ) const
{
- if ( doesRecur() && !first && mDtRecurrence.isValid() )
+ if ( doesRecur() && !first && mDtRecurrence.isValid() ) {
return mDtRecurrence;
-
- return mDtDue;
+ } else if ( hasDueDate() ) {
+ return mDtDue;
+ } else {
+ return TQDateTime();
+ }
}
TQString Todo::dtDueTimeStr() const
@@ -173,10 +176,17 @@ void Todo::setHasStartDate(bool f)
TQDateTime Todo::dtStart( bool first ) const
{
- if ( doesRecur() && !first )
- return mDtRecurrence.addDays( dtDue( first ).daysTo( IncidenceBase::dtStart() ) );
- else
+ if ( doesRecur() && !first ) {
+ TQDateTime dt = mDtRecurrence.addDays( dtDue( true ).daysTo( IncidenceBase::dtStart() ) );
+
+ // We want the dtStart's time, not dtDue's
+ dt.setTime( IncidenceBase::dtStart().time() );
+ return dt;
+ } else if ( hasStartDate() ) {
return IncidenceBase::dtStart();
+ } else {
+ return TQDateTime();
+ }
}
void Todo::setDtStart( const TQDateTime &dtStart )
@@ -255,10 +265,14 @@ int Todo::percentComplete() const
return mPercentComplete;
}
-void Todo::setPercentComplete(int v)
+void Todo::setPercentComplete( int v )
{
mPercentComplete = v;
- if ( v != 100 ) mHasCompletedDate = false;
+ if ( v != 100 ) {
+ mHasCompletedDate = false;
+ mCompleted = TQDateTime();
+ }
+
updated();
}
@@ -292,7 +306,8 @@ bool Todo::recurTodo()
while ( !recursAt( nextDate ) || nextDate <= TQDateTime::currentDateTime() ) {
- if ( !nextDate.isValid() || nextDate > endDateTime ) {
+ if ( !nextDate.isValid() ||
+ ( nextDate > endDateTime && r->duration() != -1 ) ) {
return false;
}
diff --git a/libkcal/todo.h b/libkcal/todo.h
index 1a7b050d4..74e1b39df 100644
--- a/libkcal/todo.h
+++ b/libkcal/todo.h
@@ -66,21 +66,26 @@ class LIBKCAL_EXPORT Todo : public Incidence
/**
Returns due time as string formatted according to the users locale
settings.
+ @deprecated use IncidenceFormatter::timeToString()
*/
- TQString dtDueTimeStr() const;
+ KDE_DEPRECATED TQString dtDueTimeStr() const;
+
/**
Returns due date as string formatted according to the users locale
settings.
@param shortfmt If set to true, use short date format, if set to false use
long format.
+ @deprecated use IncidenceFormatter::dateToString()
*/
- TQString dtDueDateStr( bool shortfmt = true ) const;
+ KDE_DEPRECATED TQString dtDueDateStr( bool shortfmt = true ) const;
+
/**
Returns due date and time as string formatted according to the users locale
settings.
+ @deprecated use IncidenceFormatter::dateTimeToString()
*/
- TQString dtDueStr() const;
+ KDE_DEPRECATED TQString dtDueStr() const;
/**
Returns true if the todo has a due date, otherwise return false.
@@ -218,7 +223,14 @@ class LIBKCAL_EXPORT Todo : public Incidence
private:
bool accept(Visitor &v) { return v.visit( this ); }
- /** Returns true if the todo got a new date, else false will be returned. */
+
+ /**
+ * If the todo recurs, mDtRecurrence is set to the next occurrence
+ * that's after today, mPercentComplete is set to 0 and true is returned.
+ *
+ * If the todo doesn't recur or if there aren't anymore occurrences
+ * it just returns false.
+ */
bool recurTodo();
TQDateTime mDtDue; // due date of todo
diff --git a/libkdenetwork/gpgmepp/context.cpp b/libkdenetwork/gpgmepp/context.cpp
index c0286fcbd..547adde95 100644
--- a/libkdenetwork/gpgmepp/context.cpp
+++ b/libkdenetwork/gpgmepp/context.cpp
@@ -43,6 +43,7 @@
//#include <string>
//using std::string;
+#include <istream>
#ifndef NDEBUG
#include <iostream>
using std::cerr;
@@ -77,6 +78,10 @@ namespace GpgME {
return code() == GPG_ERR_CANCELED;
}
+ std::ostream & operator<<( std::ostream & os, Error err ) {
+ return os << "GpgME::Error(" << err.operator int() << " (" << err.asString() << "))";
+ }
+
Context::Context( gpgme_ctx_t ctx ) {
d = new Private( ctx );
}
@@ -628,6 +633,89 @@ namespace GpgME {
return d->lasterr;
}
+ std::ostream & operator<<( std::ostream & os, Context::Protocol proto ) {
+ os << "GpgME::Context::Protocol(";
+ switch ( proto ) {
+ case Context::OpenPGP:
+ os << "OpenPGP";
+ break;
+ case Context::CMS:
+ os << "CMS";
+ break;
+ default:
+ case Context::Unknown:
+ os << "Unknown";
+ break;
+ }
+ return os << ')';
+ }
+
+ std::ostream & operator<<( std::ostream & os, Context::CertificateInclusion incl ) {
+ os << "GpgME::Context::CertificateInclusion(" << static_cast<int>( incl );
+ switch ( incl ) {
+ case Context::DefaultCertificates:
+ os << "(DefaultCertificates)";
+ break;
+ case Context::AllCertificatesExceptRoot:
+ os << "(AllCertificatesExceptRoot)";
+ break;
+ case Context::AllCertificates:
+ os << "(AllCertificates)";
+ break;
+ case Context::NoCertificates:
+ os << "(NoCertificates)";
+ break;
+ case Context::OnlySenderCertificate:
+ os << "(OnlySenderCertificate)";
+ break;
+ }
+ return os << ')';
+ }
+
+ std::ostream & operator<<( std::ostream & os, Context::KeyListMode mode ) {
+ os << "GpgME::Context::KeyListMode(";
+#define CHECK( x ) if ( !(mode & (Context::x)) ) {} else do { os << #x " "; } while (0)
+ CHECK( Local );
+ CHECK( Extern );
+ CHECK( Signatures );
+ CHECK( Validate );
+#undef CHECK
+ return os << ')';
+ }
+
+ std::ostream & operator<<( std::ostream & os, Context::SignatureMode mode ) {
+ os << "GpgME::Context::SignatureMode(";
+ switch ( mode ) {
+#define CHECK( x ) case Context::x: os << #x; break
+ CHECK( Normal );
+ CHECK( Detached );
+ CHECK( Clearsigned );
+#undef CHECK
+ default:
+ os << "???" "(" << static_cast<int>( mode ) << ')';
+ break;
+ }
+ return os << ')';
+ }
+
+ std::ostream & operator<<( std::ostream & os, Context::EncryptionFlags flags ) {
+ os << "GpgME::Context::EncryptionFlags(";
+#define CHECK( x ) if ( !(flags & (Context::x)) ) {} else do { os << #x " "; } while (0)
+ CHECK( AlwaysTrust );
+#undef CHECK
+ return os << ')';
+ }
+
+ std::ostream & operator<<( std::ostream & os, Context::AuditLogFlags flags ) {
+ os << "GpgME::Context::AuditLogFlags(";
+#define CHECK( x ) if ( !(flags & (Context::x)) ) {} else do { os << #x " "; } while (0)
+ CHECK( HtmlAuditLog );
+ CHECK( AuditLogWithHelp );
+#undef CHECK
+ return os << ')';
+ }
+
+
} // namespace GpgME
diff --git a/libkdenetwork/gpgmepp/context.h b/libkdenetwork/gpgmepp/context.h
index aae69f86a..b07e722ef 100644
--- a/libkdenetwork/gpgmepp/context.h
+++ b/libkdenetwork/gpgmepp/context.h
@@ -25,6 +25,8 @@
#include <vector>
#include <utility>
+#include <iosfwd>
+
#include <kdepimmacros.h>
namespace GpgME {
@@ -64,6 +66,8 @@ namespace GpgME {
int mErr;
};
+ KDE_EXPORT std::ostream & operator<<( std::ostream & os, Error err );
+
class KDE_EXPORT Context {
Context( gpgme_ctx_t );
public:
@@ -281,6 +285,13 @@ namespace GpgME {
const Context & operator=( const Context & );
};
+ KDE_EXPORT std::ostream & operator<<( std::ostream & os, Context::Protocol proto );
+ KDE_EXPORT std::ostream & operator<<( std::ostream & os, Context::CertificateInclusion incl );
+ KDE_EXPORT std::ostream & operator<<( std::ostream & os, Context::KeyListMode mode );
+ KDE_EXPORT std::ostream & operator<<( std::ostream & os, Context::SignatureMode mode );
+ KDE_EXPORT std::ostream & operator<<( std::ostream & os, Context::EncryptionFlags flags );
+ KDE_EXPORT std::ostream & operator<<( std::ostream & os, Context::AuditLogFlags flags );
+
//
//
// Globals
diff --git a/libkdenetwork/gpgmepp/data.cpp b/libkdenetwork/gpgmepp/data.cpp
index 52c96544b..52471be9b 100644
--- a/libkdenetwork/gpgmepp/data.cpp
+++ b/libkdenetwork/gpgmepp/data.cpp
@@ -133,11 +133,11 @@ GpgME::Data::Data( DataProvider * dp ) {
if ( e )
d->data = 0;
#ifndef NDEBUG
- std::cerr << "GpgME::Data(): DataProvider supports: "
- << ( d->cbs.read ? "read" : "no read" ) << ", "
- << ( d->cbs.write ? "write" : "no write" ) << ", "
- << ( d->cbs.seek ? "seek" : "no seek" ) << ", "
- << ( d->cbs.release ? "release" : "no release" ) << std::endl;
+// std::cerr << "GpgME::Data(): DataProvider supports: "
+// << ( d->cbs.read ? "read" : "no read" ) << ", "
+// << ( d->cbs.write ? "write" : "no write" ) << ", "
+// << ( d->cbs.seek ? "seek" : "no seek" ) << ", "
+// << ( d->cbs.release ? "release" : "no release" ) << std::endl;
#endif
}
diff --git a/libkdenetwork/gpgmepp/decryptionresult.cpp b/libkdenetwork/gpgmepp/decryptionresult.cpp
index cdefefe9b..2efcc67d9 100644
--- a/libkdenetwork/gpgmepp/decryptionresult.cpp
+++ b/libkdenetwork/gpgmepp/decryptionresult.cpp
@@ -25,11 +25,13 @@
#include <gpgmepp/decryptionresult.h>
#include "shared.h"
#include "result_p.h"
+#include "util.h"
#include <gpgme.h>
#include <cstring>
#include <cstdlib>
+#include <istream>
class GpgME::DecryptionResult::Private : public GpgME::Shared {
public:
@@ -71,3 +73,13 @@ bool GpgME::DecryptionResult::wrongKeyUsage() const {
#endif
return false;
}
+
+std::ostream & GpgME::operator<<( std::ostream & os, const DecryptionResult & result ) {
+ os << "GpgME::DecryptionResult(";
+ if ( !result.isNull() )
+ os << "\n error: " << result.error()
+ << "\n unsupportedAlgortihm: " << protect( result.unsupportedAlgortihm() )
+ << "\n wrongKeyUsage: " << result.wrongKeyUsage()
+ << '\n';
+ return os << ')';
+}
diff --git a/libkdenetwork/gpgmepp/decryptionresult.h b/libkdenetwork/gpgmepp/decryptionresult.h
index b6307a05b..b97f59aed 100644
--- a/libkdenetwork/gpgmepp/decryptionresult.h
+++ b/libkdenetwork/gpgmepp/decryptionresult.h
@@ -23,6 +23,9 @@
#include <gpgmepp/gpgmefw.h>
#include <gpgmepp/result.h>
+
+#include <iosfwd>
+
#include <kdepimmacros.h>
namespace GpgME {
@@ -49,6 +52,8 @@ namespace GpgME {
Private * d;
};
+ KDE_EXPORT std::ostream & operator<<( std::ostream & os, const DecryptionResult & result );
+
}
-#endif // __GPGMEPP_KEYGENERATIONRESULT_H__
+#endif // __GPGMEPP_DECRYPTIONRESULT_H__
diff --git a/libkdenetwork/gpgmepp/encryptionresult.cpp b/libkdenetwork/gpgmepp/encryptionresult.cpp
index deec8f9d5..f827ca839 100644
--- a/libkdenetwork/gpgmepp/encryptionresult.cpp
+++ b/libkdenetwork/gpgmepp/encryptionresult.cpp
@@ -25,11 +25,15 @@
#include <gpgmepp/encryptionresult.h>
#include "shared.h"
#include "result_p.h"
+#include "util.h"
#include <gpgme.h>
#include <cstring>
#include <cstdlib>
+#include <istream>
+#include <algorithm>
+#include <iterator>
class GpgME::EncryptionResult::Private : public GpgME::Shared {
public:
@@ -137,3 +141,25 @@ GpgME::Error GpgME::InvalidRecipient::reason() const {
return isNull() ? 0 : d->invalid[idx]->reason ;
}
+
+
+std::ostream & GpgME::operator<<( std::ostream & os, const EncryptionResult & result ) {
+ os << "GpgME::EncryptionResult(";
+ if ( !result.isNull() ) {
+ os << "\n error: " << result.error()
+ << "\n invalid recipients:\n";
+ const std::vector<InvalidRecipient> ir = result.invalidEncryptionKeys();
+ std::copy( ir.begin(), ir.end(),
+ std::ostream_iterator<InvalidRecipient>( os, "\n" ) );
+ }
+ return os << ')';
+}
+
+std::ostream & GpgME::operator<<( std::ostream & os, const InvalidRecipient & ir ) {
+ os << "GpgME::InvalidRecipient(";
+ if ( !ir.isNull() )
+ os << "\n fingerprint: " << protect( ir.fingerprint() )
+ << "\n reason: " << ir.reason()
+ << '\n';
+ return os << ')';
+}
diff --git a/libkdenetwork/gpgmepp/encryptionresult.h b/libkdenetwork/gpgmepp/encryptionresult.h
index ba59554ef..7267afc01 100644
--- a/libkdenetwork/gpgmepp/encryptionresult.h
+++ b/libkdenetwork/gpgmepp/encryptionresult.h
@@ -25,6 +25,8 @@
#include <gpgmepp/result.h>
#include <vector>
+#include <iosfwd>
+
#include <kdepimmacros.h>
namespace GpgME {
@@ -53,6 +55,8 @@ namespace GpgME {
Private * d;
};
+ KDE_EXPORT std::ostream & operator<<( std::ostream & os, const EncryptionResult & result );
+
class KDE_EXPORT InvalidRecipient {
friend class EncryptionResult;
InvalidRecipient( EncryptionResult::Private * parent, unsigned int index );
@@ -73,6 +77,8 @@ namespace GpgME {
unsigned int idx;
};
+ KDE_EXPORT std::ostream & operator<<( std::ostream & os, const InvalidRecipient & recipient );
+
}
#endif // __GPGMEPP_ENCRYPTIONRESULT_H__
diff --git a/libkdenetwork/gpgmepp/signingresult.cpp b/libkdenetwork/gpgmepp/signingresult.cpp
index bd5e0a3b8..6996eef7a 100644
--- a/libkdenetwork/gpgmepp/signingresult.cpp
+++ b/libkdenetwork/gpgmepp/signingresult.cpp
@@ -25,11 +25,15 @@
#include <gpgmepp/signingresult.h>
#include "shared.h"
#include "result_p.h"
+#include "util.h"
#include <gpgme.h>
#include <cstring>
#include <cstdlib>
+#include <algorithm>
+#include <istream>
+#include <iterator>
class GpgME::SigningResult::Private : public GpgME::Shared {
public:
@@ -239,3 +243,41 @@ unsigned int GpgME::CreatedSignature::signatureClass() const {
return isNull() ? 0 : d->created[idx]->sig_class ;
}
+
+std::ostream & GpgME::operator<<( std::ostream & os, const SigningResult & result ) {
+ os << "GpgME::SigningResult(";
+ if ( !result.isNull() ) {
+ os << "\n error: " << result.error()
+ << "\n createdSignatures:\n";
+ const std::vector<CreatedSignature> cs = result.createdSignatures();
+ std::copy( cs.begin(), cs.end(),
+ std::ostream_iterator<CreatedSignature>( os, "\n" ) );
+ os << " invalidSigningKeys:\n";
+ const std::vector<InvalidSigningKey> isk = result.invalidSigningKeys();
+ std::copy( isk.begin(), isk.end(),
+ std::ostream_iterator<InvalidSigningKey>( os, "\n" ) );
+ }
+ return os << ')';
+}
+
+std::ostream & GpgME::operator<<( std::ostream & os, const CreatedSignature & sig ) {
+ os << "GpgME::CreatedSignature(";
+ if ( !sig.isNull() )
+ os << "\n fingerprint: " << protect( sig.fingerprint() )
+ << "\n creationTime: " << sig.creationTime()
+ << "\n mode: " << sig.mode()
+ << "\n publicKeyAlgorithm: " << protect( sig.publicKeyAlgorithmAsString() )
+ << "\n hashAlgorithm: " << protect( sig.hashAlgorithmAsString() )
+ << "\n signatureClass: " << sig.signatureClass()
+ << '\n';
+ return os << ')';
+}
+
+std::ostream & GpgME::operator<<( std::ostream & os, const InvalidSigningKey & key ) {
+ os << "GpgME::InvalidSigningKey(";
+ if ( !key.isNull() )
+ os << "\n fingerprint: " << protect( key.fingerprint() )
+ << "\n reason: " << key.reason()
+ << '\n';
+ return os << ')';
+}
diff --git a/libkdenetwork/gpgmepp/signingresult.h b/libkdenetwork/gpgmepp/signingresult.h
index e9684abb9..202d09b41 100644
--- a/libkdenetwork/gpgmepp/signingresult.h
+++ b/libkdenetwork/gpgmepp/signingresult.h
@@ -28,7 +28,10 @@
#include <time.h>
#include <vector>
+#include <iosfwd>
+
#include <kdepimmacros.h>
+
namespace GpgME {
class Error;
@@ -57,6 +60,8 @@ namespace GpgME {
Private * d;
};
+ KDE_EXPORT std::ostream & operator<<( std::ostream & os, const SigningResult & result );
+
class KDE_EXPORT InvalidSigningKey {
friend class SigningResult;
InvalidSigningKey( SigningResult::Private * parent, unsigned int index );
@@ -77,6 +82,8 @@ namespace GpgME {
unsigned int idx;
};
+ KDE_EXPORT std::ostream & operator<<( std::ostream & os, const InvalidSigningKey & key );
+
class KDE_EXPORT CreatedSignature {
friend class SigningResult;
CreatedSignature( SigningResult::Private * parent, unsigned int index );
@@ -110,6 +117,8 @@ namespace GpgME {
unsigned int idx;
};
+ KDE_EXPORT std::ostream & operator<<( std::ostream & os, const CreatedSignature & sig );
+
}
#endif // __GPGMEPP_SIGNINGRESULT_H__
diff --git a/libkdenetwork/gpgmepp/util.h b/libkdenetwork/gpgmepp/util.h
index c8786bdcb..8246cfc32 100644
--- a/libkdenetwork/gpgmepp/util.h
+++ b/libkdenetwork/gpgmepp/util.h
@@ -28,6 +28,10 @@
#include <iostream>
#endif
+static inline const char * protect( const char * s ) {
+ return s ? s : "<null>" ;
+}
+
static inline gpgme_keylist_mode_t add_to_gpgme_keylist_mode_t( unsigned int oldmode, unsigned int newmodes ) {
if ( newmodes & GpgME::Context::Local ) oldmode |= GPGME_KEYLIST_MODE_LOCAL;
if ( newmodes & GpgME::Context::Extern ) oldmode |= GPGME_KEYLIST_MODE_EXTERN;
diff --git a/libkdenetwork/gpgmepp/verificationresult.cpp b/libkdenetwork/gpgmepp/verificationresult.cpp
index decf5bce9..abf30d96c 100644
--- a/libkdenetwork/gpgmepp/verificationresult.cpp
+++ b/libkdenetwork/gpgmepp/verificationresult.cpp
@@ -25,10 +25,13 @@
#include <gpgmepp/verificationresult.h>
#include "shared.h"
#include "result_p.h"
+#include "util.h"
#include <gpgme.h>
+#include <istream>
#include <algorithm>
+#include <iterator>
#include <cstring>
#include <cstdlib>
@@ -299,3 +302,56 @@ const char * GpgME::Signature::Notation::value() const {
return isNull() ? 0 : d->nota[sidx][nidx].value ;
}
+
+std::ostream & GpgME::operator<<( std::ostream & os, const VerificationResult & result ) {
+ os << "GpgME::VerificationResult(";
+ if ( !result.isNull() ) {
+ os << "\n error: " << result.error()
+ << "\n signatures:\n";
+ const std::vector<Signature> sigs = result.signatures();
+ std::copy( sigs.begin(), sigs.end(),
+ std::ostream_iterator<Signature>( os, "\n" ) );
+ }
+ return os << ')';
+}
+
+std::ostream & GpgME::operator<<( std::ostream & os, Signature::Summary summary ) {
+#define OUTPUT( x ) if ( !(summary & (GpgME::Signature:: x)) ) {} else do { os << #x " "; } while(0)
+ os << "GpgME::Signature::Summary(";
+ OUTPUT( Valid );
+ OUTPUT( Green );
+ OUTPUT( Red );
+ OUTPUT( KeyRevoked );
+ OUTPUT( KeyExpired );
+ OUTPUT( SigExpired );
+ OUTPUT( KeyMissing );
+ OUTPUT( CrlMissing );
+ OUTPUT( CrlTooOld );
+ OUTPUT( BadPolicy );
+ OUTPUT( SysError );
+#undef OUTPUT
+ return os << ')';
+}
+
+std::ostream & GpgME::operator<<( std::ostream & os, const Signature & sig ) {
+ os << "GpgME::Signature(";
+ if ( !sig.isNull() ) {
+ os << "\n Summary: " << sig.summary()
+ << "\n Fingerprint: " << protect( sig.fingerprint() )
+ << "\n Status: " << sig.status()
+ << "\n creationTime: " << sig.creationTime()
+ << "\n expirationTime: " << sig.expirationTime()
+ << "\n wrongKeyUsage: " << sig.wrongKeyUsage()
+ << "\n validity: " << sig.validityAsString()
+ << "\n nonValidityReason: " << sig.nonValidityReason()
+ << "\n notations:\n";
+ const std::vector<Signature::Notation> nota = sig.notations();
+ std::copy( nota.begin(), nota.end(),
+ std::ostream_iterator<Signature::Notation>( os, "\n" ) );
+ }
+ return os << ')';
+}
+
+std::ostream & GpgME::operator<<( std::ostream & os, const Signature::Notation & nota ) {
+ return os << "GpgME::Signature::Notation( \"" << protect( nota.name() ) << "\", \"" << protect( nota.value() ) << "\")";
+}
diff --git a/libkdenetwork/gpgmepp/verificationresult.h b/libkdenetwork/gpgmepp/verificationresult.h
index 86e3525f8..edcd02787 100644
--- a/libkdenetwork/gpgmepp/verificationresult.h
+++ b/libkdenetwork/gpgmepp/verificationresult.h
@@ -27,6 +27,7 @@
#include <time.h>
#include <vector>
+#include <iosfwd>
#include <kdepimmacros.h>
@@ -54,6 +55,8 @@ namespace GpgME {
Private * d;
};
+ KDE_EXPORT std::ostream & operator<<( std::ostream & os, const VerificationResult & result );
+
class KDE_EXPORT Signature {
friend class VerificationResult;
Signature( VerificationResult::Private * parent, unsigned int index );
@@ -110,6 +113,9 @@ namespace GpgME {
unsigned int idx;
};
+ KDE_EXPORT std::ostream & operator<<( std::ostream & os, const Signature & sig );
+ KDE_EXPORT std::ostream & operator<<( std::ostream & os, Signature::Summary summary );
+
class KDE_EXPORT Signature::Notation {
friend class Signature;
Notation( VerificationResult::Private * parent, unsigned int sindex, unsigned int nindex );
@@ -131,6 +137,8 @@ namespace GpgME {
unsigned int nidx;
};
+ KDE_EXPORT std::ostream & operator<<( std::ostream & os, const Signature::Notation & nota );
+
}
#endif // __GPGMEPP_VERIFICATIONRESULT_H__
diff --git a/libkdepim/addresseelineedit.cpp b/libkdepim/addresseelineedit.cpp
index 7031a83eb..5e3d0cf39 100644
--- a/libkdepim/addresseelineedit.cpp
+++ b/libkdepim/addresseelineedit.cpp
@@ -70,12 +70,23 @@ KPIM::LdapSearch* AddresseeLineEdit::s_LDAPSearch = 0L;
TQString* AddresseeLineEdit::s_LDAPText = 0L;
AddresseeLineEdit* AddresseeLineEdit::s_LDAPLineEdit = 0L;
+// The weights associated with the completion sources in s_completionSources.
+// Both are maintained by addCompletionSource(), don't attempt to modifiy those yourself.
+TQMap<TQString,int>* s_completionSourceWeights = 0;
+
+// maps LDAP client indices to completion source indices
+// the assumption that they are always the first n indices in s_completion
+// does not hold when clients are added later on
+TQMap<int, int>* AddresseeLineEdit::s_ldapClientToCompletionSourceMap = 0;
+
static KStaticDeleter<KMailCompletion> completionDeleter;
static KStaticDeleter<KPIM::CompletionItemsMap> completionItemsDeleter;
static KStaticDeleter<TQTimer> ldapTimerDeleter;
static KStaticDeleter<KPIM::LdapSearch> ldapSearchDeleter;
static KStaticDeleter<TQString> ldapTextDeleter;
static KStaticDeleter<TQStringList> completionSourcesDeleter;
+static KStaticDeleter<TQMap<TQString,int> > completionSourceWeightsDeleter;
+static KStaticDeleter<TQMap<int, int> > ldapClientToCompletionSourceMapDeleter;
// needs to be unique, but the actual name doesn't matter much
static TQCString newLineEditDCOPObjectName()
@@ -100,7 +111,8 @@ static bool itemIsHeader( const TQListBoxItem* item )
AddresseeLineEdit::AddresseeLineEdit( TQWidget* parent, bool useCompletion,
const char *name )
- : ClickLineEdit( parent, TQString::null, name ), DCOPObject( newLineEditDCOPObjectName() )
+ : ClickLineEdit( parent, TQString::null, name ), DCOPObject( newLineEditDCOPObjectName() ),
+ m_useSemiColonAsSeparator( false ), m_allowDistLists( true )
{
m_useCompletion = useCompletion;
m_completionInitialized = false;
@@ -114,6 +126,18 @@ AddresseeLineEdit::AddresseeLineEdit( TQWidget* parent, bool useCompletion,
s_addressesDirty = true;
}
+void AddresseeLineEdit::updateLDAPWeights()
+{
+ /* Add completion sources for all ldap server, 0 to n. Added first so
+ * that they map to the ldapclient::clientNumber() */
+ s_LDAPSearch->updateCompletionWeights();
+ TQValueList< LdapClient* > clients = s_LDAPSearch->clients();
+ int clientIndex = 0;
+ for ( TQValueList<LdapClient*>::iterator it = clients.begin(); it != clients.end(); ++it, ++clientIndex ) {
+ const int sourceIndex = addCompletionSource( "LDAP server: " + (*it)->server().host(), (*it)->completionWeight() );
+ s_ldapClientToCompletionSourceMap->insert( clientIndex, sourceIndex );
+ }
+}
void AddresseeLineEdit::init()
{
@@ -124,8 +148,9 @@ void AddresseeLineEdit::init()
completionItemsDeleter.setObject( s_completionItemMap, new KPIM::CompletionItemsMap() );
completionSourcesDeleter.setObject( s_completionSources, new TQStringList() );
+ completionSourceWeightsDeleter.setObject( s_completionSourceWeights, new TQMap<TQString,int> );
+ ldapClientToCompletionSourceMapDeleter.setObject( s_ldapClientToCompletionSourceMap, new TQMap<int,int> );
}
-
// connect( s_completion, TQT_SIGNAL( match( const TQString& ) ),
// this, TQT_SLOT( slotMatched( const TQString& ) ) );
@@ -134,14 +159,10 @@ void AddresseeLineEdit::init()
ldapTimerDeleter.setObject( s_LDAPTimer, new TQTimer( 0, "ldapTimerDeleter" ) );
ldapSearchDeleter.setObject( s_LDAPSearch, new KPIM::LdapSearch );
ldapTextDeleter.setObject( s_LDAPText, new TQString );
-
- /* Add completion sources for all ldap server, 0 to n. Added first so
- * that they map to the ldapclient::clientNumber() */
- TQValueList< LdapClient* > clients = s_LDAPSearch->clients();
- for ( TQValueList<LdapClient*>::iterator it = clients.begin(); it != clients.end(); ++it ) {
- addCompletionSource( "LDAP server: " + (*it)->server().host() );
- }
}
+
+ updateLDAPWeights();
+
if ( !m_completionInitialized ) {
setCompletionObject( s_completion, false );
connect( this, TQT_SIGNAL( completion( const TQString& ) ),
@@ -187,6 +208,11 @@ void AddresseeLineEdit::allowSemiColonAsSeparator( bool useSemiColonAsSeparator
m_useSemiColonAsSeparator = useSemiColonAsSeparator;
}
+void AddresseeLineEdit::allowDistributionLists( bool allowDistLists )
+{
+ m_allowDistLists = allowDistLists;
+}
+
void AddresseeLineEdit::keyPressEvent( TQKeyEvent *e )
{
bool accept = false;
@@ -206,9 +232,15 @@ void AddresseeLineEdit::keyPressEvent( TQKeyEvent *e )
}
}
+ const TQString oldContent = text();
if ( !accept )
KLineEdit::keyPressEvent( e );
+ // if the text didn't change (eg. because a cursor navigation key was pressed)
+ // we don't need to trigger a new search
+ if ( oldContent == text() )
+ return;
+
if ( e->isAccepted() ) {
updateSearchString();
TQString searchString( m_searchString );
@@ -264,24 +296,25 @@ void AddresseeLineEdit::insert( const TQString &t )
TQString contents = text();
int start_sel = 0;
- int end_sel = 0;
int pos = cursorPosition( );
- if ( getSelection( &start_sel, &end_sel ) ) {
+
+ if ( hasSelectedText() ) {
// Cut away the selection.
- if ( pos > end_sel )
- pos -= (end_sel - start_sel);
- else if ( pos > start_sel )
- pos = start_sel;
- contents = contents.left( start_sel ) + contents.right( end_sel + 1 );
+ start_sel = selectionStart();
+ pos = start_sel;
+ contents = contents.left( start_sel ) + contents.mid( start_sel + selectedText().length() );
}
int eot = contents.length();
- while ((eot > 0) && contents[ eot - 1 ].isSpace() ) eot--;
- if ( eot == 0 )
+ while ( ( eot > 0 ) && contents[ eot - 1 ].isSpace() ) {
+ eot--;
+ }
+ if ( eot == 0 ) {
contents = TQString::null;
- else if ( pos >= eot ) {
- if ( contents[ eot - 1 ] == ',' )
+ } else if ( pos >= eot ) {
+ if ( contents[ eot - 1 ] == ',' ) {
eot--;
+ }
contents.truncate( eot );
contents += ", ";
pos = eot + 2;
@@ -324,35 +357,45 @@ void AddresseeLineEdit::mouseReleaseEvent( TQMouseEvent *e )
void AddresseeLineEdit::dropEvent( TQDropEvent *e )
{
KURL::List uriList;
- if ( !isReadOnly()
- && KURLDrag::canDecode(e) && KURLDrag::decode( e, uriList ) ) {
- TQString contents = text();
- // remove trailing white space and comma
- int eot = contents.length();
- while ( ( eot > 0 ) && contents[ eot - 1 ].isSpace() )
- eot--;
- if ( eot == 0 )
- contents = TQString::null;
- else if ( contents[ eot - 1 ] == ',' ) {
- eot--;
- contents.truncate( eot );
- }
- bool mailtoURL = false;
- // append the mailto URLs
- for ( KURL::List::Iterator it = uriList.begin();
- it != uriList.end(); ++it ) {
- if ( !contents.isEmpty() )
- contents.append( ", " );
- KURL u( *it );
- if ( u.protocol() == "mailto" ) {
- mailtoURL = true;
- contents.append( (*it).path() );
+ if ( !isReadOnly() ) {
+ if ( KURLDrag::canDecode(e) && KURLDrag::decode( e, uriList ) ) {
+ TQString contents = text();
+ // remove trailing white space and comma
+ int eot = contents.length();
+ while ( ( eot > 0 ) && contents[ eot - 1 ].isSpace() )
+ eot--;
+ if ( eot == 0 )
+ contents = TQString::null;
+ else if ( contents[ eot - 1 ] == ',' ) {
+ eot--;
+ contents.truncate( eot );
+ }
+ bool mailtoURL = false;
+ // append the mailto URLs
+ for ( KURL::List::Iterator it = uriList.begin();
+ it != uriList.end(); ++it ) {
+ if ( !contents.isEmpty() )
+ contents.append( ", " );
+ KURL u( *it );
+ if ( u.protocol() == "mailto" ) {
+ mailtoURL = true;
+ contents.append( (*it).path() );
+ }
+ }
+ if ( mailtoURL ) {
+ setText( contents );
+ setEdited( true );
+ return;
+ }
+ } else {
+ // Let's see if this drop contains a comma separated list of emails
+ TQString dropData = TQString::fromUtf8( e->encodedData( "text/plain" ) );
+ TQStringList addrs = splitEmailAddrList( dropData );
+ if ( addrs.count() > 0 ) {
+ setText( normalizeAddressesAndDecodeIDNs( dropData ) );
+ setEdited( true );
+ return;
}
- }
- if ( mailtoURL ) {
- setText( contents );
- setEdited( true );
- return;
}
}
@@ -526,21 +569,19 @@ void AddresseeLineEdit::loadContacts()
TQString uid = (*it).uid();
TQMap<TQString, TQString>::const_iterator wit = uidToResourceMap.find( uid );
const TQString subresourceLabel = resabc->subresourceLabel( *wit );
- int idx = s_completionSources->findIndex( subresourceLabel );
- if ( idx == -1 ) {
- s_completionSources->append( subresourceLabel );
- idx = s_completionSources->size() -1;
- }
- int weight = ( wit != uidToResourceMap.end() ) ? resabc->subresourceCompletionWeight( *wit ) : 80;
+ const int weight = ( wit != uidToResourceMap.end() ) ? resabc->subresourceCompletionWeight( *wit ) : 80;
+ const int idx = addCompletionSource( subresourceLabel, weight );
+
//kdDebug(5300) << (*it).fullEmail() << " subres=" << *wit << " weight=" << weight << endl;
addContact( *it, weight, idx );
}
} else { // KABC non-imap resource
int weight = config.readNumEntry( resource->identifier(), 60 );
- s_completionSources->append( resource->resourceName() );
+ int sourceIndex = addCompletionSource( resource->resourceName(), weight );
KABC::Resource::Iterator it;
- for ( it = resource->begin(); it != resource->end(); ++it )
- addContact( *it, weight, s_completionSources->size()-1 );
+ for ( it = resource->begin(); it != resource->end(); ++it ) {
+ addContact( *it, weight, sourceIndex );
+ }
}
}
@@ -577,12 +618,14 @@ void AddresseeLineEdit::addContact( const KABC::Addressee& addr, int weight, int
if ( KPIM::DistributionList::isDistributionList( addr ) ) {
//kdDebug(5300) << "AddresseeLineEdit::addContact() distribution list \"" << addr.formattedName() << "\" weight=" << weight << endl;
- //for CompletionAuto
- addCompletionItem( addr.formattedName(), weight, source );
+ if ( m_allowDistLists ) {
+ //for CompletionAuto
+ addCompletionItem( addr.formattedName(), weight, source );
- //for CompletionShell, CompletionPopup
- TQStringList sl( addr.formattedName() );
- addCompletionItem( addr.formattedName(), weight, source, &sl );
+ //for CompletionShell, CompletionPopup
+ TQStringList sl( addr.formattedName() );
+ addCompletionItem( addr.formattedName(), weight, source, &sl );
+ }
return;
}
@@ -730,6 +773,11 @@ void AddresseeLineEdit::addCompletionItem( const TQString& string, int weight, i
void AddresseeLineEdit::slotStartLDAPLookup()
{
+ KGlobalSettings::Completion mode = completionMode();
+
+ if ( mode == KGlobalSettings::CompletionNone )
+ return;
+
if ( !s_LDAPSearch->isAvailable() ) {
return;
}
@@ -765,7 +813,7 @@ void AddresseeLineEdit::startLoadingLDAPEntries()
void AddresseeLineEdit::slotLDAPSearchData( const KPIM::LdapResultList& adrs )
{
- if ( s_LDAPLineEdit != this )
+ if ( adrs.isEmpty() || s_LDAPLineEdit != this )
return;
for ( KPIM::LdapResultList::ConstIterator it = adrs.begin(); it != adrs.end(); ++it ) {
@@ -773,14 +821,20 @@ void AddresseeLineEdit::slotLDAPSearchData( const KPIM::LdapResultList& adrs )
addr.setNameFromString( (*it).name );
addr.setEmails( (*it).email );
- addContact( addr, (*it).completionWeight, (*it ).clientNumber );
+ if ( !s_ldapClientToCompletionSourceMap->contains( (*it).clientNumber ) )
+ updateLDAPWeights(); // we got results from a new source, so update the completion sources
+
+ addContact( addr, (*it).completionWeight, (*s_ldapClientToCompletionSourceMap)[ (*it ).clientNumber ] );
}
if ( (hasFocus() || completionBox()->hasFocus() )
&& completionMode() != KGlobalSettings::CompletionNone
- && completionMode() != KGlobalSettings::CompletionShell) {
+ && completionMode() != KGlobalSettings::CompletionShell ) {
setText( m_previousAddresses + m_searchString );
- doCompletion( m_lastSearchMode );
+ // only complete again if the user didn't change the selection while we were waiting
+ // otherwise the completion box will be closed
+ if ( m_searchString.stripWhiteSpace() != completionBox()->currentText().stripWhiteSpace() )
+ doCompletion( m_lastSearchMode );
}
}
@@ -881,6 +935,10 @@ void AddresseeLineEdit::slotEditCompletionOrder()
init(); // for s_LDAPSearch
CompletionOrderEditor editor( s_LDAPSearch, this );
editor.exec();
+ if ( m_useCompletion ) {
+ updateLDAPWeights();
+ s_addressesDirty = true;
+ }
}
void KPIM::AddresseeLineEdit::slotIMAPCompletionOrderChanged()
@@ -902,15 +960,23 @@ void AddresseeLineEdit::updateSearchString()
int n = -1;
bool inQuote = false;
- for ( uint i = 0; i < m_searchString.length(); ++i ) {
- if ( m_searchString[ i ] == '"' )
+ uint searchStringLength = m_searchString.length();
+ for ( uint i = 0; i < searchStringLength; ++i ) {
+ if ( m_searchString[ i ] == '"' ) {
inQuote = !inQuote;
- if ( m_searchString[ i ] == '\\' && (i + 1) < m_searchString.length() && m_searchString[ i + 1 ] == '"' )
+ }
+ if ( m_searchString[ i ] == '\\' &&
+ (i + 1) < searchStringLength && m_searchString[ i + 1 ] == '"' ) {
++i;
- if ( inQuote )
+ }
+ if ( inQuote ) {
continue;
- if ( m_searchString[ i ] == ',' || ( m_useSemiColonAsSeparator && m_searchString[ i ] == ';' ) )
+ }
+ if ( i < searchStringLength &&
+ ( m_searchString[ i ] == ',' ||
+ ( m_useSemiColonAsSeparator && m_searchString[ i ] == ';' ) ) ) {
n = i;
+ }
}
if ( n >= 0 ) {
@@ -924,9 +990,7 @@ void AddresseeLineEdit::updateSearchString()
m_previousAddresses = m_searchString.left( n );
m_searchString = m_searchString.mid( n ).stripWhiteSpace();
- }
- else
- {
+ } else {
m_previousAddresses = TQString::null;
}
}
@@ -954,18 +1018,30 @@ KCompletion::CompOrder KPIM::AddresseeLineEdit::completionOrder()
return KCompletion::Sorted;
}
-int KPIM::AddresseeLineEdit::addCompletionSource( const TQString &source )
+int KPIM::AddresseeLineEdit::addCompletionSource( const TQString &source, int weight )
{
- s_completionSources->append( source );
- return s_completionSources->size()-1;
+ TQMap<TQString,int>::iterator it = s_completionSourceWeights->find( source );
+ if ( it == s_completionSourceWeights->end() )
+ s_completionSourceWeights->insert( source, weight );
+ else
+ (*s_completionSourceWeights)[source] = weight;
+
+ int sourceIndex = s_completionSources->findIndex( source );
+ if ( sourceIndex == -1 ) {
+ s_completionSources->append( source );
+ return s_completionSources->size() - 1;
+ }
+ else
+ return sourceIndex;
}
bool KPIM::AddresseeLineEdit::eventFilter(TQObject *obj, TQEvent *e)
{
if ( obj == completionBox() ) {
- if ( e->type() == TQEvent::MouseButtonPress
- || e->type() == TQEvent::MouseMove
- || e->type() == TQEvent::MouseButtonRelease ) {
+ if ( e->type() == TQEvent::MouseButtonPress ||
+ e->type() == TQEvent::MouseMove ||
+ e->type() == TQEvent::MouseButtonRelease ||
+ e->type() == TQEvent::MouseButtonDblClick ) {
TQMouseEvent* me = static_cast<TQMouseEvent*>( e );
// find list box item at the event position
TQListBoxItem *item = completionBox()->itemAt( me->pos() );
@@ -1003,26 +1079,35 @@ bool KPIM::AddresseeLineEdit::eventFilter(TQObject *obj, TQEvent *e)
}
}
if ( ( obj == this ) &&
- ( e->type() == TQEvent::KeyPress ) &&
- completionBox()->isVisible() ) {
+ ( e->type() == TQEvent::KeyPress || e->type() == TQEvent::KeyRelease ) &&
+ completionBox()->isVisible() ) {
TQKeyEvent *ke = static_cast<TQKeyEvent*>( e );
- unsigned int currentIndex = completionBox()->currentItem();
+ int currentIndex = completionBox()->currentItem();
+ if ( currentIndex < 0 ) {
+ return true;
+ }
+
if ( ke->key() == Key_Up ) {
//kdDebug() << "EVENTFILTER: Key_Up currentIndex=" << currentIndex << endl;
// figure out if the item we would be moving to is one we want
// to ignore. If so, go one further
- TQListBoxItem *itemAbove = completionBox()->item( currentIndex - 1 );
+ TQListBoxItem *itemAbove = completionBox()->item( currentIndex );
if ( itemAbove && itemIsHeader(itemAbove) ) {
// there is a header above us, check if there is even further up
// and if so go one up, so it'll be selected
- if ( currentIndex > 1 && completionBox()->item( currentIndex - 2 ) ) {
+ if ( currentIndex > 0 && completionBox()->item( currentIndex - 1 ) ) {
//kdDebug() << "EVENTFILTER: Key_Up -> skipping " << currentIndex - 1 << endl;
completionBox()->setCurrentItem( itemAbove->prev() );
- completionBox()->setSelected( currentIndex - 2, true );
- } else if ( currentIndex == 1 ) {
+ completionBox()->setSelected( currentIndex - 1, true );
+ } else if ( currentIndex == 0 ) {
// nothing to skip to, let's stay where we are, but make sure the
// first header becomes visible, if we are the first real entry
completionBox()->ensureVisible( 0, 0 );
+ //Kolab issue 2941: be sure to add email even if it's the only element.
+ if ( itemIsHeader( completionBox()->item( currentIndex ) ) ) {
+ currentIndex++;
+ }
+ completionBox()->setCurrentItem( itemAbove );
completionBox()->setSelected( currentIndex, true );
}
return true;
@@ -1030,14 +1115,15 @@ bool KPIM::AddresseeLineEdit::eventFilter(TQObject *obj, TQEvent *e)
} else if ( ke->key() == Key_Down ) {
// same strategy for downwards
//kdDebug() << "EVENTFILTER: Key_Down. currentIndex=" << currentIndex << endl;
- TQListBoxItem *itemBelow = completionBox()->item( currentIndex + 1 );
+ TQListBoxItem *itemBelow = completionBox()->item( currentIndex );
if ( itemBelow && itemIsHeader( itemBelow ) ) {
- if ( completionBox()->item( currentIndex + 2 ) ) {
+ if ( completionBox()->item( currentIndex + 1 ) ) {
//kdDebug() << "EVENTFILTER: Key_Down -> skipping " << currentIndex+1 << endl;
completionBox()->setCurrentItem( itemBelow->next() );
- completionBox()->setSelected( currentIndex + 2, true );
+ completionBox()->setSelected( currentIndex + 1, true );
} else {
// nothing to skip to, let's stay where we are
+ completionBox()->setCurrentItem( itemBelow );
completionBox()->setSelected( currentIndex, true );
}
return true;
@@ -1052,11 +1138,14 @@ bool KPIM::AddresseeLineEdit::eventFilter(TQObject *obj, TQEvent *e)
TQListBoxItem *item = completionBox()->item( currentIndex );
if ( item && itemIsHeader(item) ) {
completionBox()->setSelected( currentIndex, true );
- }
- } else if ( ke->key() == Key_Tab || ke->key() == Key_Backtab ) {
- /// first, find the header of teh current section
+ }
+ } else if ( e->type() == TQEvent::KeyRelease &&
+ ( ke->key() == Key_Tab || ke->key() == Key_Backtab ) ) {
+ //kdDebug() << "EVENTFILTER: Key_Tab. currentIndex=" << currentIndex << endl;
+ /// first, find the header of the current section
TQListBoxItem *myHeader = 0;
- int i = currentIndex;
+ const int iterationstep = ke->key() == Key_Tab ? 1 : -1;
+ int i = QMIN( QMAX( currentIndex - iterationstep, 0 ), completionBox()->count() - 1 );
while ( i>=0 ) {
if ( itemIsHeader( completionBox()->item(i) ) ) {
myHeader = completionBox()->item( i );
@@ -1066,22 +1155,31 @@ bool KPIM::AddresseeLineEdit::eventFilter(TQObject *obj, TQEvent *e)
}
Q_ASSERT( myHeader ); // we should always be able to find a header
- // find the next header (searching backwards, for Key_Backtab
+ // find the next header (searching backwards, for Key_Backtab)
TQListBoxItem *nextHeader = 0;
- const int iterationstep = ke->key() == Key_Tab ? 1 : -1;
// when iterating forward, start at the currentindex, when backwards,
// one up from our header, or at the end
- uint j = ke->key() == Key_Tab ? currentIndex : i==0 ? completionBox()->count()-1 : (i-1) % completionBox()->count();
+ uint j;
+ if ( ke->key() == Key_Tab ) {
+ j = currentIndex;
+ } else {
+ i = completionBox()->index( myHeader );
+ if ( i == 0 ) {
+ j = completionBox()->count() - 1;
+ } else {
+ j = ( i - 1 ) % completionBox()->count();
+ }
+ }
while ( ( nextHeader = completionBox()->item( j ) ) && nextHeader != myHeader ) {
if ( itemIsHeader(nextHeader) ) {
- break;
+ break;
}
j = (j + iterationstep) % completionBox()->count();
}
if ( nextHeader && nextHeader != myHeader ) {
TQListBoxItem *item = completionBox()->item( j + 1 );
if ( item && !itemIsHeader(item) ) {
- completionBox()->setSelected( j+1, true );
+ completionBox()->setSelected( item, true );
completionBox()->setCurrentItem( item );
completionBox()->ensureCurrentVisible();
}
@@ -1092,20 +1190,49 @@ bool KPIM::AddresseeLineEdit::eventFilter(TQObject *obj, TQEvent *e)
return ClickLineEdit::eventFilter( obj, e );
}
+class SourceWithWeight {
+ public:
+ int weight; // the weight of the source
+ TQString sourceName; // the name of the source, e.g. "LDAP Server"
+ int index; // index into s_completionSources
+
+ bool operator< ( const SourceWithWeight &other ) {
+ if ( weight > other.weight )
+ return true;
+ if ( weight < other.weight )
+ return false;
+ return sourceName < other.sourceName;
+ }
+};
+
const TQStringList KPIM::AddresseeLineEdit::getAdjustedCompletionItems( bool fullSearch )
{
TQStringList items = fullSearch ?
s_completion->allMatches( m_searchString )
: s_completion->substringCompletion( m_searchString );
+ // For weighted mode, the algorithm is the following:
+ // In the first loop, we add each item to its section (there is one section per completion source)
+ // We also add spaces in front of the items.
+ // The sections are appended to the items list.
+ // In the second loop, we then walk through the sections and add all the items in there to the
+ // sorted item list, which is the final result.
+ //
+ // The algo for non-weighted mode is different.
+
int lastSourceIndex = -1;
unsigned int i = 0;
+
+ // Maps indices of the items list, which are section headers/source items,
+ // to a TQStringList which are the items of that section/source.
TQMap<int, TQStringList> sections;
TQStringList sortedItems;
for ( TQStringList::Iterator it = items.begin(); it != items.end(); ++it, ++i ) {
CompletionItemsMap::const_iterator cit = s_completionItemMap->find(*it);
- if ( cit == s_completionItemMap->end() )continue;
+ if ( cit == s_completionItemMap->end() )
+ continue;
int idx = (*cit).second;
+
if ( s_completion->order() == KCompletion::Weighted ) {
if ( lastSourceIndex == -1 || lastSourceIndex != idx ) {
const TQString sourceLabel( (*s_completionSources)[idx] );
@@ -1124,11 +1251,30 @@ const TQStringList KPIM::AddresseeLineEdit::getAdjustedCompletionItems( bool ful
sortedItems.append( *it );
}
}
+
if ( s_completion->order() == KCompletion::Weighted ) {
- for ( TQMap<int, TQStringList>::Iterator it( sections.begin() ), end( sections.end() ); it != end; ++it ) {
- sortedItems.append( (*s_completionSources)[it.key()] );
- for ( TQStringList::Iterator sit( (*it).begin() ), send( (*it).end() ); sit != send; ++sit ) {
- sortedItems.append( *sit );
+
+ // Sort the sections
+ TQValueList<SourceWithWeight> sourcesAndWeights;
+ for ( uint i = 0; i < s_completionSources->size(); i++ ) {
+ SourceWithWeight sww;
+ sww.sourceName = (*s_completionSources)[i];
+ sww.weight = (*s_completionSourceWeights)[sww.sourceName];
+ sww.index = i;
+ sourcesAndWeights.append( sww );
+ }
+ qHeapSort( sourcesAndWeights );
+
+ // Add the sections and their items to the final sortedItems result list
+ for( uint i = 0; i < sourcesAndWeights.size(); i++ ) {
+ TQStringList sectionItems = sections[sourcesAndWeights[i].index];
+ if ( !sectionItems.isEmpty() ) {
+ sortedItems.append( sourcesAndWeights[i].sourceName );
+ TQStringList sectionItems = sections[sourcesAndWeights[i].index];
+ for ( TQStringList::Iterator sit( sectionItems.begin() ), send( sectionItems.end() );
+ sit != send; ++sit ) {
+ sortedItems.append( *sit );
+ }
}
}
} else {
diff --git a/libkdepim/addresseelineedit.h b/libkdepim/addresseelineedit.h
index 5f8d2f496..86d8d8db2 100644
--- a/libkdepim/addresseelineedit.h
+++ b/libkdepim/addresseelineedit.h
@@ -63,6 +63,12 @@ class KDE_EXPORT AddresseeLineEdit : public ClickLineEdit, public DCOPObject
virtual void setFont( const TQFont& );
void allowSemiColonAsSeparator( bool );
+ /// Sets if distribution lists will be used for completion.
+ /// This is true by default.
+ /// Call this right after the constructor, before anything calls loadContacts(),
+ /// otherwise this has no effect.
+ void allowDistributionLists( bool allowDistLists );
+
public slots:
void cursorAtEnd();
void enableCompletion( bool enable );
@@ -96,8 +102,10 @@ class KDE_EXPORT AddresseeLineEdit : public ClickLineEdit, public DCOPObject
* Adds the name of a completion source to the internal list of
* such sources and returns its index, such that that can be used
* for insertion of items associated with that source.
+ *
+ * If the source already exists, the weight will be updated.
*/
- int addCompletionSource( const TQString& );
+ int addCompletionSource( const TQString&, int weight );
/** return whether we are using sorted or weighted display */
static KCompletion::CompOrder completionOrder();
@@ -120,6 +128,7 @@ class KDE_EXPORT AddresseeLineEdit : public ClickLineEdit, public DCOPObject
void init();
void startLoadingLDAPEntries();
void stopLDAPLookup();
+ void updateLDAPWeights();
void setCompletedItems( const TQStringList& items, bool autoSuggest );
void addCompletionItem( const TQString& string, int weight, int source, const TQStringList * keyWords=0 );
@@ -136,6 +145,7 @@ class KDE_EXPORT AddresseeLineEdit : public ClickLineEdit, public DCOPObject
bool m_lastSearchMode;
bool m_searchExtended; //has \" been added?
bool m_useSemiColonAsSeparator;
+ bool m_allowDistLists;
//TQMap<TQString, KABC::Addressee> m_contactMap;
@@ -147,6 +157,7 @@ class KDE_EXPORT AddresseeLineEdit : public ClickLineEdit, public DCOPObject
static TQString *s_LDAPText;
static AddresseeLineEdit *s_LDAPLineEdit;
static TQStringList *s_completionSources;
+ static TQMap<int,int> *s_ldapClientToCompletionSourceMap;
class AddresseeLineEditPrivate;
AddresseeLineEditPrivate *d;
diff --git a/libkdepim/addressesdialog.cpp b/libkdepim/addressesdialog.cpp
index 8a33d7999..14feafb67 100644
--- a/libkdepim/addressesdialog.cpp
+++ b/libkdepim/addressesdialog.cpp
@@ -67,7 +67,7 @@ struct AddresseeViewItem::AddresseeViewItemPrivate {
};
struct AddressesDialog::AddressesDialogPrivate {
- AddressesDialogPrivate() :
+ AddressesDialogPrivate() :
ui(0), personal(0), recent(0),
toItem(0), ccItem(0), bccItem(0),
ldapSearchDialog(0)
@@ -77,6 +77,8 @@ struct AddressesDialog::AddressesDialogPrivate {
AddresseeViewItem *personal;
AddresseeViewItem *recent;
+ AddresseeViewItem *topdist;
+ TQPtrList<AddresseeViewItem> dists;
AddresseeViewItem *toItem;
AddresseeViewItem *ccItem;
@@ -181,11 +183,11 @@ void AddresseeViewItem::setSelected(bool selected)
{
if (selected == isSelected())
{
- return;
+ return;
}
- emit addressSelected( this, selected );
- TQListViewItem::setSelected(selected);
+ emit addressSelected( this, selected );
+ TQListViewItem::setSelected(selected);
}
int
@@ -223,6 +225,9 @@ AddressesDialog::AddressesDialog( TQWidget *widget, const char *name )
initConnections();
d->ui->mAvailableView->setFocus();
+
+ setMainWidget( page );
+ page->setMinimumSize( 750, 400 );
}
AddressesDialog::~AddressesDialog()
@@ -331,6 +336,7 @@ AddressesDialog::updateRecentAddresses()
addAddresseeToAvailable( *it, d->recent );
if ( d->recent->childCount() > 0 ) {
+ d->recent->setOpen( true );
d->recent->setVisible( true );
}
}
@@ -472,8 +478,10 @@ AddressesDialog::updateAvailableAddressees()
d->recent = 0;
updateRecentAddresses();
+ d->topdist = 0;
addDistributionLists();
if ( d->personal->childCount() > 0 ) {
+ d->personal->setOpen( true );
d->personal->setVisible( true );
}
@@ -724,10 +732,9 @@ AddressesDialog::addSelectedTo()
addAddresseesToSelected( d->toItem, selectedAvailableAddresses );
selectedAvailableAddresses.clear();
- if ( d->toItem->childCount() > 0 )
+ if ( d->toItem->childCount() > 0 ) {
d->toItem->setVisible( true );
- else
- {
+ } else {
delete d->toItem;
d->toItem = 0;
}
@@ -746,10 +753,9 @@ AddressesDialog::addSelectedCC()
addAddresseesToSelected( d->ccItem, selectedAvailableAddresses );
selectedAvailableAddresses.clear();
- if ( d->ccItem->childCount() > 0 )
+ if ( d->ccItem->childCount() > 0 ) {
d->ccItem->setVisible( true );
- else
- {
+ } else {
delete d->ccItem;
d->ccItem = 0;
}
@@ -768,10 +774,9 @@ AddressesDialog::addSelectedBCC()
addAddresseesToSelected( d->bccItem, selectedAvailableAddresses );
selectedAvailableAddresses.clear();
- if ( d->bccItem->childCount() > 0 )
+ if ( d->bccItem->childCount() > 0 ) {
d->bccItem->setVisible( true );
- else
- {
+ } else {
delete d->bccItem;
d->bccItem = 0;
}
@@ -950,7 +955,7 @@ AddressesDialog::searchLdap()
void
AddressesDialog::ldapSearchResult()
{
- TQStringList emails = TQStringList::split(',', d->ldapSearchDialog->selectedEMails() );
+ TQStringList emails = KPIM::splitEmailAddrList( d->ldapSearchDialog->selectedEMails() );
TQStringList::iterator it( emails.begin() );
TQStringList::iterator end( emails.end() );
for ( ; it != end; ++it ){
@@ -979,22 +984,81 @@ AddressesDialog::filterChanged( const TQString& txt )
if ( txt.isEmpty() )
showAll = true;
+ int personalVisible = 0;
+ int recentVisible = 0;
while ( it.current() ) {
AddresseeViewItem* item = static_cast<AddresseeViewItem*>( it.current() );
++it;
+
if ( showAll ) {
+ item->setOpen( true );
item->setVisible( true );
- if ( item->category() == AddresseeViewItem::Group )
- item->setOpen( false );//close to not have too many entries
+ // allen: I do not like the following behavior. comment out and see if anyone screams
+ //if ( item->category() == AddresseeViewItem::Group )
+ // item->setOpen( false );//close to not have too many entries
continue;
}
+
if ( item->category() == AddresseeViewItem::Entry ) {
- bool matches = item->matches( txt ) ;
+ bool matches = item->matches( txt );
item->setVisible( matches );
- if ( matches && static_cast<TQListViewItem*>(item)->parent() ) {
- static_cast<TQListViewItem*>(item)->parent()->setOpen( true );//open the parents with found entries
+ TQListViewItem *parent = static_cast<TQListViewItem*>( item )->parent();
+ if ( matches && parent ) {
+ if ( parent == d->personal ) {
+ personalVisible++;
+ } else if ( parent == d->recent ) {
+ recentVisible++;
+ }
}
}
+ if ( item->category() == AddresseeViewItem::Group ) {
+ item->setOpen( true );
+ item->setVisible( true );
+ }
+ }
+
+ if ( !showAll && personalVisible == 0 ) {
+ d->personal->setOpen( false );
+ d->personal->setVisible( false );
+ }
+ if ( !showAll && recentVisible == 0 ) {
+ d->recent->setOpen( false );
+ d->recent->setVisible( false );
+ }
+
+ int distlistgroupVisible = 0;
+ if ( !showAll ) {
+ TQPtrListIterator<AddresseeViewItem> it( d->dists );
+ for ( ; it.current(); ++it ) {
+ TQListViewItem *p = *it;
+ p->setVisible( true );
+ AddresseeViewItem *p2 = static_cast<AddresseeViewItem*>( p->firstChild() );
+ int pcount = 0;
+ while ( p2 ) {
+ if ( p2->matches( txt ) ) {
+ p2->setVisible( true );
+ pcount++;
+ } else {
+ p2->setVisible( false );
+ }
+ p2 = static_cast<AddresseeViewItem*>( p2->nextSibling() );
+ }
+ if ( !pcount && !p->text( 0 ).contains( txt, false ) ) {
+ p->setVisible( false );
+ }
+ distlistgroupVisible += pcount;
+ if ( p->text( 0 ).contains( txt, false ) ) {
+ distlistgroupVisible++;
+ }
+ }
+ }
+ if ( d->topdist ) {
+ if ( showAll || distlistgroupVisible > 0 ) {
+ d->topdist->setOpen( true );
+ } else {
+ d->topdist->setOpen( false );
+ d->topdist->setVisible( false );
+ }
}
}
@@ -1084,14 +1148,16 @@ AddressesDialog::addDistributionLists()
if ( distLists.isEmpty() )
return;
- AddresseeViewItem *topItem = new AddresseeViewItem( d->ui->mAvailableView,
- i18n( "Distribution Lists" ) );
+ if ( !d->topdist ) {
+ d->topdist = new AddresseeViewItem( d->ui->mAvailableView, i18n( "Distribution Lists" ) );
+ }
#ifdef KDEPIM_NEW_DISTRLISTS
TQValueList<KPIM::DistributionList>::ConstIterator listIt;
#else
TQStringList::Iterator listIt;
#endif
+ int total = 0;
for ( listIt = distLists.begin(); listIt != distLists.end(); ++listIt ) {
#ifdef KDEPIM_NEW_DISTRLISTS
KPIM::DistributionList dlist = *listIt;
@@ -1101,7 +1167,8 @@ AddressesDialog::addDistributionLists()
KABC::DistributionList::Entry::List entries = dlist.entries();
#endif
- AddresseeViewItem *item = new AddresseeViewItem( topItem, dlist.name() );
+ AddresseeViewItem *item = new AddresseeViewItem( d->topdist, dlist.name() );
+ d->dists.append( item );
connect( item, TQT_SIGNAL( addressSelected( AddresseeViewItem*, bool ) ),
this, TQT_SLOT( availableAddressSelected( AddresseeViewItem*, bool ) ) );
@@ -1110,8 +1177,18 @@ AddressesDialog::addDistributionLists()
#else
KABC::DistributionList::Entry::List::Iterator itemIt;
#endif
- for ( itemIt = entries.begin(); itemIt != entries.end(); ++itemIt )
+ for ( itemIt = entries.begin(); itemIt != entries.end(); ++itemIt ) {
addAddresseeToAvailable( (*itemIt).addressee, item, false );
+ }
+ if ( item->childCount() > 0 ) {
+ item->setOpen( true );
+ item->setVisible( true );
+ }
+ total += item->childCount();
+ }
+ if ( total > 0 ) {
+ d->topdist->setOpen( true );
+ d->topdist->setVisible( true );
}
}
diff --git a/libkdepim/calendardiffalgo.h b/libkdepim/calendardiffalgo.h
index 43d855134..47e5efd4c 100644
--- a/libkdepim/calendardiffalgo.h
+++ b/libkdepim/calendardiffalgo.h
@@ -22,9 +22,10 @@
#ifndef KPIM_CALENDARDIFFALGO_H
#define KPIM_CALENDARDIFFALGO_H
+#include "diffalgo.h"
+
#include <libkcal/event.h>
#include <libkcal/todo.h>
-#include <libkdepim/diffalgo.h>
namespace KPIM {
diff --git a/libkdepim/completionordereditor.cpp b/libkdepim/completionordereditor.cpp
index b507d9b97..9fd4950aa 100644
--- a/libkdepim/completionordereditor.cpp
+++ b/libkdepim/completionordereditor.cpp
@@ -27,6 +27,7 @@
* you do not wish to do so, delete this exception statement from
* your version.
*/
+#include <config.h> // FOR KDEPIM_NEW_DISTRLISTS
#include "completionordereditor.h"
#include "ldapclient.h"
@@ -54,11 +55,11 @@ Several items are used in addresseelineedit's completion object:
LDAP servers, KABC resources (imap and non-imap), Recent addresses (in kmail only).
The default completion weights are as follow:
+ Recent addresses (kmail) : 10 (see kmail/kmlineeditspell.cpp)
LDAP: 50, 49, 48 etc. (see ldapclient.cpp)
KABC non-imap resources: 60 (see addresseelineedit.cpp and SimpleCompletionItem here)
Distribution lists: 60 (see addresseelineedit.cpp and SimpleCompletionItem here)
KABC imap resources: 80 (see kresources/imap/kabc/resourceimap.cpp)
- Recent addresses (kmail) : 120 (see kmail/kmcomposewin.cpp)
This dialog allows to change those weights, by showing one item per:
- LDAP server
@@ -99,21 +100,21 @@ private:
void LDAPCompletionItem::save( CompletionOrderEditor* )
{
- KConfig config( "kabldaprc" );
- config.setGroup( "LDAP" );
- config.writeEntry( TQString( "SelectedCompletionWeight%1" ).arg( mLdapClient->clientNumber() ),
- mWeight );
- config.sync();
+ KConfig * config = LdapSearch::config();
+ config->setGroup( "LDAP" );
+ config->writeEntry( TQString( "SelectedCompletionWeight%1" ).arg( mLdapClient->clientNumber() ),
+ mWeight );
+ config->sync();
}
// A simple item saved into kpimcompletionorder (no subresources, just name/identifier/weight)
class SimpleCompletionItem : public CompletionItem
{
public:
- SimpleCompletionItem( CompletionOrderEditor* editor, const TQString& label, const TQString& identifier )
+ SimpleCompletionItem( CompletionOrderEditor* editor, const TQString& label, const TQString& identifier, int weight )
: mLabel( label ), mIdentifier( identifier ) {
KConfigGroup group( editor->configFile(), "CompletionWeights" );
- mWeight = group.readNumEntry( mIdentifier, 60 );
+ mWeight = group.readNumEntry( mIdentifier, weight );
}
virtual TQString label() const { return mLabel; }
virtual int completionWeight() const { return mWeight; }
@@ -195,15 +196,17 @@ CompletionOrderEditor::CompletionOrderEditor( KPIM::LdapSearch* ldapSearch,
}
} else { // non-IMAP KABC resource
mItems.append( new SimpleCompletionItem( this, (*resit)->resourceName(),
- (*resit)->identifier() ) );
+ (*resit)->identifier(), 60 ) );
}
}
#ifndef KDEPIM_NEW_DISTRLISTS // new distr lists are normal contact, so no separate item if using them
// Add an item for distribution lists
- mItems.append( new SimpleCompletionItem( this, i18n( "Distribution Lists" ), "DistributionLists" ) );
+ mItems.append( new SimpleCompletionItem( this, i18n( "Distribution Lists" ), "DistributionLists" ), 60 );
#endif
+ mItems.append( new SimpleCompletionItem( this, i18n( "Recent Addresses" ), "Recent Addresses", 10 ) );
+
// Now sort the items, then create the GUI
mItems.sort();
diff --git a/libkdepim/csshelper.cpp b/libkdepim/csshelper.cpp
index b65713dd2..6b37fbf13 100644
--- a/libkdepim/csshelper.cpp
+++ b/libkdepim/csshelper.cpp
@@ -238,6 +238,7 @@ namespace KPIM {
TQString::number( printFont.pointSize() ) )
+
TQString( "tr.textAtmH,\n"
+ "tr.signInProgressH,\n"
"tr.rfc822H,\n"
"tr.encrH,\n"
"tr.signOkKeyOkH,\n"
@@ -367,6 +368,10 @@ namespace KPIM {
" color: white ! important;\n"
"}\n\n"
+ "a.black {\n"
+ " color: black ! important;\n"
+ "}\n\n"
+
"table.textAtm { background-color: %2 ! important; }\n\n"
"tr.textAtmH {\n"
@@ -378,10 +383,12 @@ namespace KPIM {
" background-color: %3 ! important;\n"
"}\n\n"
+ "table.signInProgress,\n"
"table.rfc822 {\n"
" background-color: %3 ! important;\n"
"}\n\n"
+ "tr.signInProgressH,\n"
"tr.rfc822H {\n"
"%4"
"}\n\n" )
@@ -538,6 +545,7 @@ namespace KPIM {
" font-weight: normal ! important;\n"
"}\n\n"
+ "tr.signInProgressH,\n"
"tr.rfc822H,\n"
"tr.encrH,\n"
"tr.signOkKeyOkH,\n"
@@ -565,6 +573,7 @@ namespace KPIM {
"table.signErr,\n"
"table.signOkKeyBad,\n"
"table.signOkKeyOk,\n"
+ "table.signInProgress,\n"
"div.fancy.header table {\n"
" width: 100% ! important;\n"
" border-width: 0px ! important;\n"
@@ -630,4 +639,9 @@ namespace KPIM {
mPrintFont = font;
}
+ TQColor CSSHelper::pgpWarnColor() const
+ {
+ return cPgpWarnH;
+ }
+
} // namespace KPIM
diff --git a/libkdepim/csshelper.h b/libkdepim/csshelper.h
index 5d668713c..3dbc80c03 100644
--- a/libkdepim/csshelper.h
+++ b/libkdepim/csshelper.h
@@ -67,6 +67,8 @@ class CSSHelper {
void setBodyFont( const TQFont& font );
void setPrintFont( const TQFont& font );
+ TQColor pgpWarnColor() const;
+
protected:
/** Recalculate PGP frame and body colors (should be called after changing
color settings) */
diff --git a/libkdepim/distributionlist.cpp b/libkdepim/distributionlist.cpp
index e70b77b57..2ccdeb525 100644
--- a/libkdepim/distributionlist.cpp
+++ b/libkdepim/distributionlist.cpp
@@ -37,15 +37,13 @@ static ParseList parseCustom( const TQString& str )
if ( (*it).isEmpty() )
continue;
// parse "uid,email"
- TQStringList helpList = TQStringList::split( ',', (*it) );
+ TQStringList helpList = TQStringList::split( ',', (*it), true );
Q_ASSERT( !helpList.isEmpty() );
if ( helpList.isEmpty() )
continue;
- const TQString uid = helpList.first();
- TQString email;
Q_ASSERT( helpList.count() < 3 ); // 1 or 2 items, but not more
- if ( helpList.count() == 2 )
- email = helpList.last();
+ const TQString uid = helpList.first();
+ const TQString email = helpList.last();
res.append( qMakePair( uid, email ) );
}
return res;
diff --git a/libkdepim/htmldiffalgodisplay.h b/libkdepim/htmldiffalgodisplay.h
index 23da21f4c..4495e2003 100644
--- a/libkdepim/htmldiffalgodisplay.h
+++ b/libkdepim/htmldiffalgodisplay.h
@@ -22,8 +22,9 @@
#ifndef KPIM_HTMLDIFFALGODISPLAY_H
#define KPIM_HTMLDIFFALGODISPLAY_H
+#include "diffalgo.h"
+
#include <ktextbrowser.h>
-#include <libkdepim/diffalgo.h>
#include <kdepimmacros.h>
namespace KPIM {
diff --git a/libkdepim/kabcresourcecached.cpp b/libkdepim/kabcresourcecached.cpp
index 26648e762..d46156f6d 100644
--- a/libkdepim/kabcresourcecached.cpp
+++ b/libkdepim/kabcresourcecached.cpp
@@ -214,7 +214,11 @@ void ResourceCached::loadCache()
KABC::VCardConverter converter;
+#if defined(KABC_VCARD_ENCODING_FIX)
+ KABC::Addressee::List list = converter.parseVCardsRaw( file.readAll().data() );
+#else
KABC::Addressee::List list = converter.parseVCards( TQString::fromUtf8( file.readAll() ) );
+#endif
KABC::Addressee::List::Iterator it;
for ( it = list.begin(); it != list.end(); ++it ) {
@@ -239,8 +243,13 @@ void ResourceCached::saveCache()
KABC::Addressee::List list = mAddrMap.values();
KABC::VCardConverter converter;
+#if defined(KABC_VCARD_ENCODING_FIX)
+ TQCString vCard = converter.createVCardsRaw( list );
+ file.writeBlock( vCard, vCard.length() );
+#else
TQString vCard = converter.createVCards( list );
file.writeBlock( vCard.utf8(), vCard.utf8().length() );
+#endif
file.close();
}
@@ -259,7 +268,11 @@ void ResourceCached::cleanUpCache( const KABC::Addressee::List &addrList )
KABC::VCardConverter converter;
+#if defined(KABC_VCARD_ENCODING_FIX)
+ KABC::Addressee::List list = converter.parseVCardsRaw( file.readAll().data() );
+#else
KABC::Addressee::List list = converter.parseVCards( TQString::fromUtf8( file.readAll() ) );
+#endif
KABC::Addressee::List::Iterator cacheIt;
KABC::Addressee::List::ConstIterator it;
@@ -351,9 +364,14 @@ void ResourceCached::saveChangesCache( const TQMap<TQString, KABC::Addressee> &m
}
KABC::VCardConverter converter;
+#if defined(KABC_VCARD_ENCODING_FIX)
+ const TQCString vCards = converter.createVCardsRaw( list );
+ file.writeBlock( vCards, vCards.length() );
+#else
const TQString vCards = converter.createVCards( list );
TQCString content = vCards.utf8();
file.writeBlock( content, content.length() );
+#endif
}
}
@@ -372,7 +390,11 @@ void ResourceCached::loadChangesCache( TQMap<TQString, KABC::Addressee> &map, co
KABC::VCardConverter converter;
+#if defined(KABC_VCARD_ENCODING_FIX)
+ const KABC::Addressee::List list = converter.parseVCardsRaw( file.readAll().data() );
+#else
const KABC::Addressee::List list = converter.parseVCards( TQString::fromUtf8( file.readAll() ) );
+#endif
KABC::Addressee::List::ConstIterator it;
for ( it = list.begin(); it != list.end(); ++it )
map.insert( (*it).uid(), *it );
diff --git a/libkdepim/kaddrbook.cpp b/libkdepim/kaddrbook.cpp
index ade6ef706..e5ef47e6f 100644
--- a/libkdepim/kaddrbook.cpp
+++ b/libkdepim/kaddrbook.cpp
@@ -207,34 +207,9 @@ bool KAddrBookExternal::addVCard( const KABC::Addressee& addressee, TQWidget *pa
bool KAddrBookExternal::addAddressee( const KABC::Addressee& addr )
{
KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true );
-
-#if KDE_IS_VERSION(3,4,89)
- // This ugly hack will be removed in 4.0
- while ( !addressBook->loadingHasFinished() ) {
- TQApplication::eventLoop()->processEvents( TQEventLoop::ExcludeUserInput );
-
- // use sleep here to reduce cpu usage
- usleep( 100 );
- }
-#endif
-
- // Select a resource
- TQPtrList<KABC::Resource> kabcResources = addressBook->resources();
-
- TQPtrList<KRES::Resource> kresResources;
- TQPtrListIterator<KABC::Resource> resIt( kabcResources );
- KABC::Resource *kabcResource;
- while ( ( kabcResource = resIt.current() ) != 0 ) {
- ++resIt;
- if ( !kabcResource->readOnly() ) {
- KRES::Resource *res = static_cast<KRES::Resource*>( kabcResource );
- if ( res )
- kresResources.append( res );
- }
- }
-
- kabcResource = static_cast<KABC::Resource*>( KRES::SelectDialog::getResource( kresResources, 0 ) );
-
+ KABC::Resource *kabcResource = selectResourceForSaving( addressBook );
+ if( !kabcResource )
+ return false;
KABC::Ticket *ticket = addressBook->requestSaveTicket( kabcResource );
bool saved = false;
if ( ticket ) {
@@ -278,3 +253,33 @@ TQString KAddrBookExternal::expandDistributionList( const TQString& listName )
#endif
return TQString::null;
}
+
+KABC::Resource* KAddrBookExternal::selectResourceForSaving( KABC::AddressBook *addressBook )
+{
+#if KDE_IS_VERSION(3,4,89)
+ // This ugly hack will be removed in 4.0
+ while ( !addressBook->loadingHasFinished() ) {
+ TQApplication::eventLoop()->processEvents( TQEventLoop::ExcludeUserInput );
+
+ // use sleep here to reduce cpu usage
+ usleep( 100 );
+ }
+#endif
+
+ // Select a resource
+ TQPtrList<KABC::Resource> kabcResources = addressBook->resources();
+
+ TQPtrList<KRES::Resource> kresResources;
+ TQPtrListIterator<KABC::Resource> resIt( kabcResources );
+ KABC::Resource *kabcResource;
+ while ( ( kabcResource = resIt.current() ) != 0 ) {
+ ++resIt;
+ if ( !kabcResource->readOnly() ) {
+ KRES::Resource *res = static_cast<KRES::Resource*>( kabcResource );
+ if ( res )
+ kresResources.append( res );
+ }
+ }
+
+ return static_cast<KABC::Resource*>( KRES::SelectDialog::getResource( kresResources, 0 ) );
+}
diff --git a/libkdepim/kaddrbook.h b/libkdepim/kaddrbook.h
index dfa65823f..374753e54 100644
--- a/libkdepim/kaddrbook.h
+++ b/libkdepim/kaddrbook.h
@@ -11,6 +11,10 @@
#include <kabc/addressee.h>
#include <kdepimmacros.h>
+namespace KABC {
+ class AddressBook;
+}
+
class TQWidget;
class KDE_EXPORT KAddrBookExternal {
@@ -23,6 +27,17 @@ public:
static bool addVCard( const KABC::Addressee& addressee, TQWidget *parent );
static TQString expandDistributionList( const TQString& listName );
+
+ /**
+ * Pops up a dialog to ask the user to select a resource for saving something, and
+ * returns the selected resource or 0 on failure or if the user cancelled.
+ *
+ * The addressbook used to get the resource list from. If the addressbook was loaded
+ * async and loading is not yet finished, this method will run an eventloop until the
+ * addressbook is loaded.
+ */
+ static KABC::Resource* selectResourceForSaving( KABC::AddressBook *addressBook );
+
private:
static bool addAddressee( const KABC::Addressee& addressee );
};
diff --git a/libkdepim/kcmdesignerfields.cpp b/libkdepim/kcmdesignerfields.cpp
index 79a570ae5..330d8b84b 100644
--- a/libkdepim/kcmdesignerfields.cpp
+++ b/libkdepim/kcmdesignerfields.cpp
@@ -163,6 +163,7 @@ void KCMDesignerFields::delayedInit()
// Install a dirwatcher that will detect newly created or removed designer files
KDirWatch *dw = new KDirWatch( this );
+ KStandardDirs::makeDir(localUiDir());
dw->addDir( localUiDir(), true );
connect( dw, TQT_SIGNAL( created(const TQString&) ), TQT_SLOT( rebuildList() ) );
connect( dw, TQT_SIGNAL( deleted(const TQString&) ), TQT_SLOT( rebuildList() ) );
diff --git a/libkdepim/kdepimprotocols.h b/libkdepim/kdepimprotocols.h
new file mode 100644
index 000000000..462fafda8
--- /dev/null
+++ b/libkdepim/kdepimprotocols.h
@@ -0,0 +1,32 @@
+/*
+ This file is part of libkdepim.
+
+ Copyright (c) 2005 Rafal Rzepecki <divide@users.sourceforge.net>
+
+ 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KDEPIM_KDEPIMPROTOCOLS_H
+#define KDEPIM_KDEPIMPROTOCOLS_H
+
+/* a central place to store protocol strings to avoid knowledge duplication */
+
+#define KDEPIMPROTOCOL_CONTACT "uid:"
+#define KDEPIMPROTOCOL_EMAIL "kmail:"
+#define KDEPIMPROTOCOL_INCIDENCE "urn:x-ical"
+#define KDEPIMPROTOCOL_NEWSARTICLE "news:"
+
+#endif
diff --git a/libkdepim/kfoldertree.h b/libkdepim/kfoldertree.h
index e09cd7833..2d2805846 100644
--- a/libkdepim/kfoldertree.h
+++ b/libkdepim/kfoldertree.h
@@ -39,6 +39,7 @@ struct KPaintInfo {
{
COL_SIZE,
COL_ATTACHMENT,
+ COL_INVITATION,
COL_IMPORTANT,
COL_TODO,
COL_SPAM_HAM,
@@ -55,8 +56,9 @@ struct KPaintInfo {
showSize(false),
showAttachment(false),
+ showInvitation(false),
showImportant(false),
- showTodo( false ),
+ showTodo(false),
showSpamHam(false),
showWatchedIgnored(false),
showStatus(false),
@@ -73,6 +75,7 @@ struct KPaintInfo {
dateCol(-1),
sizeCol(-1),
attachmentCol(-1),
+ invitationCol(-1),
importantCol(-1),
todoCol(-1),
spamHamCol(-1),
@@ -84,7 +87,8 @@ struct KPaintInfo {
orderOfArrival(false),
status(false),
showCryptoIcons(false),
- showAttachmentIcon(false)
+ showAttachmentIcon(false),
+ showInvitationIcon(false)
{}
bool pixmapOn;
@@ -99,6 +103,7 @@ struct KPaintInfo {
bool showSize;
bool showAttachment;
+ bool showInvitation;
bool showImportant;
bool showTodo;
bool showSpamHam;
@@ -117,6 +122,7 @@ struct KPaintInfo {
int dateCol;
int sizeCol;
int attachmentCol;
+ int invitationCol;
int importantCol;
int todoCol;
int spamHamCol;
@@ -129,6 +135,7 @@ struct KPaintInfo {
bool status;
bool showCryptoIcons;
bool showAttachmentIcon;
+ bool showInvitationIcon;
};
//==========================================================================
diff --git a/libkdepim/kincidencechooser.cpp b/libkdepim/kincidencechooser.cpp
index 53f72c886..2cef98f3a 100644
--- a/libkdepim/kincidencechooser.cpp
+++ b/libkdepim/kincidencechooser.cpp
@@ -77,9 +77,9 @@ KIncidenceChooser::KIncidenceChooser(TQWidget *parent, char *name) :
topLayout->addWidget( new TQLabel ( i18n("Last modified:"), topFrame) ,iii,0);
mMod1lab = new TQLabel ( "Set Last modified", topFrame);
topLayout->addWidget(mMod1lab,iii,1);
- showDetails1 = new TQPushButton( i18n("Show Details"),topFrame );
- connect ( showDetails1, TQT_SIGNAL( clicked()), this, TQT_SLOT (showIncidence1() ) );
- topLayout->addWidget(showDetails1,iii,2);
+ mShowDetails1 = new TQPushButton( i18n("Show Details"),topFrame );
+ connect ( mShowDetails1, TQT_SIGNAL( clicked()), this, TQT_SLOT (showIncidence1() ) );
+ topLayout->addWidget(mShowDetails1,iii,2);
++iii;
mInc2lab = new TQLabel ( "Local incidence", topFrame);
@@ -90,19 +90,19 @@ KIncidenceChooser::KIncidenceChooser(TQWidget *parent, char *name) :
topLayout->addWidget( new TQLabel ( i18n("Last modified:"), topFrame) ,iii,0);
mMod2lab = new TQLabel ( "Set Last modified", topFrame);
topLayout->addWidget(mMod2lab,iii,1);
- showDetails2 = new TQPushButton( i18n("Show Details"), topFrame);
- connect ( showDetails2, TQT_SIGNAL( clicked()), this, TQT_SLOT (showIncidence2() ) );
- topLayout->addWidget(showDetails2,iii,2);
+ mShowDetails2 = new TQPushButton( i18n("Show Details"), topFrame);
+ connect ( mShowDetails2, TQT_SIGNAL( clicked()), this, TQT_SLOT (showIncidence2() ) );
+ topLayout->addWidget(mShowDetails2,iii,2);
++iii;
//
#if 0
// commented out for now, because the diff code has too many bugs
- diffBut = new TQPushButton( i18n("Show Differences"), topFrame );
- connect ( diffBut, TQT_SIGNAL( clicked()), this, TQT_SLOT ( showDiff() ) );
- topLayout->addMultiCellWidget(diffBut, iii,iii,0,2);
+ mDiffBut = new TQPushButton( i18n("Show Differences"), topFrame );
+ connect ( mDiffBut, TQT_SIGNAL( clicked()), this, TQT_SLOT ( showDiff() ) );
+ topLayout->addMultiCellWidget(mDiffBut, iii,iii,0,2);
++iii;
#else
- diffBut = 0;
+ mDiffBut = 0;
#endif
mBg = new TQButtonGroup ( 1, Qt::Horizontal, i18n("Sync Preferences"), topFrame);
topLayout->addMultiCellWidget(mBg, iii,iii,0,2);
@@ -116,7 +116,7 @@ KIncidenceChooser::KIncidenceChooser(TQWidget *parent, char *name) :
mTbL = 0;
mTbN = 0;
mDisplayDiff = 0;
- choosedIncidence = 0;
+ mSelIncidence = 0;
button = new TQPushButton( i18n("Apply This to All Conflicts of This Sync"), topFrame );
connect ( button, TQT_SIGNAL( clicked()), this, TQT_SLOT ( setSyncMode() ) );
topLayout->addMultiCellWidget(button, iii,iii,0,2);
@@ -142,7 +142,7 @@ void KIncidenceChooser::setIncidence( KCal::Incidence* local ,KCal::Incidence* r
KCal::Incidence* KIncidenceChooser::getIncidence( )
{
- KCal::Incidence* retval = choosedIncidence;
+ KCal::Incidence* retval = mSelIncidence;
if ( chooseMode == KIncidenceChooser::local )
retval = mInc1;
else if ( chooseMode == KIncidenceChooser::remote )
@@ -185,21 +185,21 @@ void KIncidenceChooser::setLabels()
if ( inc->type() == "Event" ) {
des->setText( i18n( "Local Event") );
sum->setText( inc->summary().left( 30 ));
- if ( diffBut )
- diffBut->setEnabled( true );
+ if ( mDiffBut )
+ mDiffBut->setEnabled( true );
}
else if ( inc->type() == "Todo" ) {
des->setText( i18n( "Local Todo") );
sum->setText( inc->summary().left( 30 ));
- if ( diffBut )
- diffBut->setEnabled( true );
+ if ( mDiffBut )
+ mDiffBut->setEnabled( true );
}
else if ( inc->type() == "Journal" ) {
des->setText( i18n( "Local Journal") );
sum->setText( inc->description().left( 30 ));
- if ( diffBut )
- diffBut->setEnabled( false );
+ if ( mDiffBut )
+ mDiffBut->setEnabled( false );
}
mMod1lab->setText( KGlobal::locale()->formatDateTime(inc->lastModified() ));
inc = mInc2;
@@ -226,10 +226,10 @@ void KIncidenceChooser::showIncidence1()
{
if ( mTbL ) {
if ( mTbL->isVisible() ) {
- showDetails1->setText( i18n("Show Details"));
+ mShowDetails1->setText( i18n("Show Details"));
mTbL->hide();
} else {
- showDetails1->setText( i18n("Hide Details"));
+ mShowDetails1->setText( i18n("Hide Details"));
mTbL->show();
mTbL->raise();
}
@@ -242,7 +242,7 @@ void KIncidenceChooser::showIncidence1()
mTbL->setMainWidget( textBrowser );
textBrowser->setText( KCal::IncidenceFormatter::extensiveDisplayString( mInc1 ) );
mTbL->setMinimumSize( 400, 400 );
- showDetails1->setText( i18n("Hide Details"));
+ mShowDetails1->setText( i18n("Hide Details"));
mTbL->show();
mTbL->raise();
}
@@ -251,9 +251,9 @@ void KIncidenceChooser::detailsDialogClosed()
{
KDialogBase* dialog = static_cast<KDialogBase *>( const_cast<TQObject *>( sender() ) );
if ( dialog == mTbL )
- showDetails1->setText( i18n( "Show details..." ) );
+ mShowDetails1->setText( i18n( "Show details..." ) );
else
- showDetails2->setText( i18n( "Show details..." ) );
+ mShowDetails2->setText( i18n( "Show details..." ) );
}
void KIncidenceChooser::showDiff()
@@ -282,10 +282,10 @@ void KIncidenceChooser::showIncidence2()
{
if ( mTbN ) {
if ( mTbN->isVisible() ) {
- showDetails2->setText( i18n("Show Details"));
+ mShowDetails2->setText( i18n("Show Details"));
mTbN->hide();
} else {
- showDetails2->setText( i18n("Hide Details"));
+ mShowDetails2->setText( i18n("Hide Details"));
mTbN->show();
mTbN->raise();
}
@@ -298,27 +298,27 @@ void KIncidenceChooser::showIncidence2()
mTbN->setMainWidget( textBrowser );
textBrowser->setText( KCal::IncidenceFormatter::extensiveDisplayString( mInc2 ) );
mTbN->setMinimumSize( 400, 400 );
- showDetails2->setText( i18n("Hide Details"));
+ mShowDetails2->setText( i18n("Hide Details"));
mTbN->show();
mTbN->raise();
}
void KIncidenceChooser::takeIncidence1()
{
- choosedIncidence = mInc1;
+ mSelIncidence = mInc1;
TQDialog::accept();
}
void KIncidenceChooser::takeIncidence2()
{
- choosedIncidence = mInc2;
+ mSelIncidence = mInc2;
TQDialog::accept();
}
void KIncidenceChooser::takeBoth()
{
- choosedIncidence = 0;
+ mSelIncidence = 0;
TQDialog::accept();
}
diff --git a/libkdepim/kincidencechooser.h b/libkdepim/kincidencechooser.h
index 8c569e33e..9d9e016ad 100644
--- a/libkdepim/kincidencechooser.h
+++ b/libkdepim/kincidencechooser.h
@@ -24,44 +24,40 @@
#ifndef _KINCIDENCECHOOSER_H
#define _KINCIDENCECHOOSER_H
+#include "calendardiffalgo.h"
+#include "htmldiffalgodisplay.h"
#include <kdialogbase.h>
-#include <tqptrlist.h>
-#include <tqmutex.h>
-#include <kdepimmacros.h>
-
-#include <libkcal/incidence.h>
-#include "htmldiffalgodisplay.h"
-#include "calendardiffalgo.h"
+namespace KCal {
+ class Incidence;
+}
+using namespace KCal;
-class TQRadioButton;
class TQButtonGroup;
-class TQVBox;
-class TQStringList;
-class TQTextBrowser;
-class KDialogBase;
/** Dialog to change the korganizer configuration.
*/
class KDE_EXPORT KIncidenceChooser : public KDialog
{
- Q_OBJECT
-public:
- enum mode { local, remote, newest, ask, both };
+ Q_OBJECT
+ public:
+ enum mode {
+ local, remote, newest, ask, both
+ };
/** Initialize dialog and pages */
- KIncidenceChooser(TQWidget *parent=0,char *name=0);
+ KIncidenceChooser( TQWidget *parent=0, char *name=0 );
~KIncidenceChooser();
//void setChooseText( TQString );
- void setIncidence( KCal::Incidence*,KCal::Incidence*);
- KCal::Incidence* getIncidence();
+ void setIncidence( KCal::Incidence *, KCal::Incidence * );
+ KCal::Incidence *getIncidence();
static int chooseMode;
-public slots:
+ public slots:
void useGlobalMode();
-protected slots:
+ protected slots:
void showIncidence1();
void showIncidence2();
void showDiff();
@@ -72,16 +68,15 @@ protected slots:
void setSyncMode();
void detailsDialogClosed();
-protected:
-private:
- KPIM::HTMLDiffAlgoDisplay* mDisplayDiff;
- KPIM::CalendarDiffAlgo* diff;
- KDialogBase* mTbL, *mTbN;
- KCal::Incidence* choosedIncidence;
- KCal::Incidence* mInc1, *mInc2;
+ private:
+ KPIM::HTMLDiffAlgoDisplay *mDisplayDiff;
+ KPIM::CalendarDiffAlgo *diff;
+ KDialogBase *mTbL, *mTbN;
+ KCal::Incidence *mSelIncidence;
+ KCal::Incidence *mInc1, *mInc2;
TQButtonGroup *mBg;
- TQPushButton *diffBut,*showDetails1,*showDetails2;
- TQLabel* mInc1lab, *mInc2lab,* mInc1Sumlab, *mInc2Sumlab,*mMod1lab,*mMod2lab;
+ TQPushButton *mDiffBut,*mShowDetails1,*mShowDetails2;
+ TQLabel *mInc1lab, *mInc2lab,* mInc1Sumlab, *mInc2Sumlab,*mMod1lab,*mMod2lab;
};
diff --git a/libkdepim/komposer/core/komposerconfig.desktop b/libkdepim/komposer/core/komposerconfig.desktop
index 9076759d5..58c8bd765 100644
--- a/libkdepim/komposer/core/komposerconfig.desktop
+++ b/libkdepim/komposer/core/komposerconfig.desktop
@@ -27,7 +27,6 @@ Comment[de]=KDE-Komposer
Comment[fr]=Komposer KDE
Comment[ga]=Komposer KDE
Comment[hi]=केडीई कम्पोज़र
-Comment[ka]=KDE კომპოზიტორი
Comment[ms]=Penggubah KDE
Comment[nds]=Nettbreef-Editor vun KDE
Comment[ne]=केडीई कम्पोजर
@@ -46,7 +45,6 @@ Keywords[da]=brevskriver
Keywords[de]=Komposer
Keywords[fy]=komposer,opstellen, opsteller
Keywords[hi]=कम्पोज़र
-Keywords[ka]=komposer,ნოტები
Keywords[nds]=Komposer
Keywords[ne]=कम्पोजर
Keywords[nl]=komposer,opstellen
diff --git a/libkdepim/komposer/core/komposereditor.desktop b/libkdepim/komposer/core/komposereditor.desktop
index 2e84bd17c..fd1c1341e 100644
--- a/libkdepim/komposer/core/komposereditor.desktop
+++ b/libkdepim/komposer/core/komposereditor.desktop
@@ -26,7 +26,6 @@ Comment[hu]=Komposer
Comment[is]=Komposer ritill
Comment[it]=Komposer editor
Comment[ja]=Komposer,エディタ
-Comment[ka]=Komposer-ის რედაქტორი
Comment[kk]=Komposer өңдегіші
Comment[km]=កម្មវិធី​និពន្ធ Komposer
Comment[ko]=Komposer 편집기
diff --git a/libkdepim/komposer/core/komposerplugin.desktop b/libkdepim/komposer/core/komposerplugin.desktop
index 08b450d6d..b398e1c67 100644
--- a/libkdepim/komposer/core/komposerplugin.desktop
+++ b/libkdepim/komposer/core/komposerplugin.desktop
@@ -29,7 +29,6 @@ Name[hu]=Komposer bővítőmodul
Name[is]=Komposer íforrit
Name[it]=Plugin Komposer
Name[ja]=Komposer プラグイン
-Name[ka]=Komposer მოდული
Name[kk]=Komposer плагин модулі
Name[km]=កម្មវិធី​ជំនួយ Komposer
Name[ko]=Komposer 플러그인
diff --git a/libkdepim/komposer/plugins/default/defaulteditor.desktop b/libkdepim/komposer/plugins/default/defaulteditor.desktop
index b0fd5a651..910f7d89c 100644
--- a/libkdepim/komposer/plugins/default/defaulteditor.desktop
+++ b/libkdepim/komposer/plugins/default/defaulteditor.desktop
@@ -38,7 +38,6 @@ Name[hu]=Komposer szerkesztő
Name[is]=Komposer ritill
Name[it]=Editor Komposer
Name[ja]=Komposer エディタ
-Name[ka]=Komposer რედაქტორი
Name[kk]=Komposer өңдегіші
Name[km]=កម្មវិធី​និពន្ធ Komposer
Name[lt]=Komposer redaktorius
@@ -84,7 +83,6 @@ Comment[hu]=A Komposer alapértelmezett szerkesztője
Comment[is]=Sjálfgefinn ritill Komposer
Comment[it]=Editor di default per Komposer
Comment[ja]=Komposer 標準エディタ
-Comment[ka]=Komposer ნაგულისხმევი რედაქტორი
Comment[kk]=Komposer әдетті өңдегіші
Comment[km]=កម្មវិធី​និពន្ធ​លំនាំដើម​របស់ Komposer
Comment[ko]=Komposer 기본 편집기
diff --git a/libkdepim/kprefsdialog.cpp b/libkdepim/kprefsdialog.cpp
index 9aef645e6..1af04fd46 100644
--- a/libkdepim/kprefsdialog.cpp
+++ b/libkdepim/kprefsdialog.cpp
@@ -376,7 +376,7 @@ KPrefsWidDate::KPrefsWidDate( KConfigSkeleton::ItemDateTime *item,
void KPrefsWidDate::readConfig()
{
- mDateEdit->setDate( mItem->value().date() );
+ mDateEdit->setDate( mItem->value().date().isValid() ? mItem->value().date() : TQDate::currentDate() );
}
void KPrefsWidDate::writeConfig()
diff --git a/libkdepim/ktimeedit.cpp b/libkdepim/ktimeedit.cpp
index 15d318418..2e82b7dfb 100644
--- a/libkdepim/ktimeedit.cpp
+++ b/libkdepim/ktimeedit.cpp
@@ -161,7 +161,7 @@ TQTime KTimeEdit::getTime() const
ok = false;
}
}
- kdDebug(5300) << "KTimeEdit::getTime(): " << time.toString() << endl;
+ // kdDebug(5300) << "KTimeEdit::getTime(): " << time.toString() << endl;
return time;
}
diff --git a/libkdepim/kvcarddrag.cpp b/libkdepim/kvcarddrag.cpp
index 2008f7a92..b8057367a 100644
--- a/libkdepim/kvcarddrag.cpp
+++ b/libkdepim/kvcarddrag.cpp
@@ -25,8 +25,11 @@
static const char vcard_mime_string[] = "text/x-vcard";
-KVCardDrag::KVCardDrag( const TQString &content, TQWidget *dragsource,
- const char *name )
+#if defined(KABC_VCARD_ENCODING_FIX)
+KVCardDrag::KVCardDrag( const TQByteArray &content, TQWidget *dragsource, const char *name )
+#else
+KVCardDrag::KVCardDrag( const TQString &content, TQWidget *dragsource, const char *name )
+#endif
: TQStoredDrag( vcard_mime_string, dragsource, name )
{
setVCard( content );
@@ -35,28 +38,60 @@ KVCardDrag::KVCardDrag( const TQString &content, TQWidget *dragsource,
KVCardDrag::KVCardDrag( TQWidget *dragsource, const char *name )
: TQStoredDrag( vcard_mime_string, dragsource, name )
{
+#if defined(KABC_VCARD_ENCODING_FIX)
+ setVCard( TQByteArray() );
+#else
setVCard( TQString::null );
+#endif
}
+#if defined(KABC_VCARD_ENCODING_FIX)
+void KVCardDrag::setVCard( const TQByteArray &content )
+{
+ setEncodedData( content );
+}
+#else
void KVCardDrag::setVCard( const TQString &content )
{
setEncodedData( content.utf8() );
}
+#endif
bool KVCardDrag::canDecode( TQMimeSource *e )
{
return e->provides( vcard_mime_string );
}
+#if defined(KABC_VCARD_ENCODING_FIX)
+bool KVCardDrag::decode( TQMimeSource *e, TQByteArray &content )
+{
+ if ( !canDecode( e ) ) {
+ return false;
+ }
+ content = e->encodedData( vcard_mime_string );
+ return true;
+}
+#else
bool KVCardDrag::decode( TQMimeSource *e, TQString &content )
{
+ if ( !canDecode( e ) ) {
+ return false;
+ }
content = TQString::fromUtf8( e->encodedData( vcard_mime_string ) );
return true;
}
+#endif
bool KVCardDrag::decode( TQMimeSource *e, KABC::Addressee::List& addressees )
{
+ if ( !canDecode( e ) ) {
+ return false;
+ }
+#if defined(KABC_VCARD_ENCODING_FIX)
+ addressees = KABC::VCardConverter().parseVCardsRaw( e->encodedData( vcard_mime_string ).data() );
+#else
addressees = KABC::VCardConverter().parseVCards( e->encodedData( vcard_mime_string ) );
+#endif
return true;
}
diff --git a/libkdepim/kvcarddrag.h b/libkdepim/kvcarddrag.h
index 55b3ef188..30d8dd742 100644
--- a/libkdepim/kvcarddrag.h
+++ b/libkdepim/kvcarddrag.h
@@ -26,6 +26,7 @@
#include <tqstring.h>
#include <kabc/addressee.h>
+#include <kabc/vcardparser.h> // for KABC_VCARD_ENCODING_FIX define
#include <kdepimmacros.h>
class KVCardDragPrivate;
@@ -49,14 +50,21 @@ class KDE_EXPORT KVCardDrag : public QStoredDrag
/**
* Constructs a vcard drag with the @p addressee.
*/
+#if defined(KABC_VCARD_ENCODING_FIX)
+ KVCardDrag( const TQByteArray &content, TQWidget *dragsource = 0, const char *name = 0 );
+#else
KVCardDrag( const TQString &content, TQWidget *dragsource = 0, const char *name = 0 );
+#endif
virtual ~KVCardDrag() {}
/**
* Sets the vcard of the drag to @p content.
*/
+#if defined(KABC_VCARD_ENCODING_FIX)
+ void setVCard( const TQByteArray &content );
+#else
void setVCard( const TQString &content );
-
+#endif
/**
* Returns true if the MIME source @p e contains a vcard object.
*/
@@ -65,7 +73,11 @@ class KDE_EXPORT KVCardDrag : public QStoredDrag
/**
* Decodes the MIME source @p e and puts the resulting vcard into @p content.
*/
+#if defined(KABC_VCARD_ENCODING_FIX)
+ static bool decode( TQMimeSource *e, TQByteArray &content );
+#else
static bool decode( TQMimeSource *e, TQString &content );
+#endif
/**
* Decodes the MIME source @p e and puts the resulting vcard into @p addresseess.
diff --git a/libkdepim/ldapclient.cpp b/libkdepim/ldapclient.cpp
index 359e03568..39d384e83 100644
--- a/libkdepim/ldapclient.cpp
+++ b/libkdepim/ldapclient.cpp
@@ -349,6 +349,22 @@ LdapSearch::LdapSearch()
TQT_SLOT(slotFileChanged(const TQString&)));
}
+void LdapSearch::readWeighForClient( LdapClient *client, KConfig *config, int clientNumber )
+{
+ const int completionWeight = config->readNumEntry( TQString( "SelectedCompletionWeight%1" ).arg( clientNumber ), -1 );
+ if ( completionWeight != -1 )
+ client->setCompletionWeight( completionWeight );
+}
+
+void LdapSearch::updateCompletionWeights()
+{
+ KConfig *config = KPIM::LdapSearch::config();
+ config->setGroup( "LDAP" );
+ for ( uint i = 0; i < mClients.size(); i++ ) {
+ readWeighForClient( mClients[i], config, i );
+ }
+}
+
void LdapSearch::readConfig()
{
cancelSearch();
@@ -371,9 +387,7 @@ void LdapSearch::readConfig()
if ( !server.host().isEmpty() ) mNoLDAPLookup = false;
ldapClient->setServer( server );
- int completionWeight = config->readNumEntry( TQString( "SelectedCompletionWeight%1" ).arg( j ), -1 );
- if ( completionWeight != -1 )
- ldapClient->setCompletionWeight( completionWeight );
+ readWeighForClient( ldapClient, config, j );
TQStringList attrs;
// note: we need "objectClass" to detect distribution lists
@@ -499,7 +513,7 @@ void LdapSearch::makeSearchData( TQStringList& ret, LdapResultList& resList )
bool wasCN = false;
bool wasDC = false;
- kdDebug(5300) << "\n\nLdapSearch::makeSearchData()\n\n" << endl;
+ //kdDebug(5300) << "\n\nLdapSearch::makeSearchData()\n\n" << endl;
LdapAttrMap::ConstIterator it2;
for ( it2 = (*it1).attrs.begin(); it2 != (*it1).attrs.end(); ++it2 ) {
@@ -508,7 +522,7 @@ void LdapSearch::makeSearchData( TQStringList& ret, LdapResultList& resList )
if( len > 0 && '\0' == val[len-1] )
--len;
const TQString tmp = TQString::fromUtf8( val, len );
- kdDebug(5300) << " key: \"" << it2.key() << "\" value: \"" << tmp << "\"" << endl;
+ //kdDebug(5300) << " key: \"" << it2.key() << "\" value: \"" << tmp << "\"" << endl;
if ( it2.key() == "cn" ) {
name = tmp;
if( mail.isEmpty() )
@@ -551,7 +565,7 @@ void LdapSearch::makeSearchData( TQStringList& ret, LdapResultList& resList )
if( mails.isEmpty()) {
if ( !mail.isEmpty() ) mails.append( mail );
if( isDistributionList ) {
- kdDebug(5300) << "\n\nLdapSearch::makeSearchData() found a list: " << name << "\n\n" << endl;
+ //kdDebug(5300) << "\n\nLdapSearch::makeSearchData() found a list: " << name << "\n\n" << endl;
ret.append( name );
// following lines commented out for bugfixing kolab issue #177:
//
@@ -568,14 +582,14 @@ void LdapSearch::makeSearchData( TQStringList& ret, LdapResultList& resList )
//mail.prepend( name );
//mail = name;
} else {
- kdDebug(5300) << "LdapSearch::makeSearchData() found BAD ENTRY: \"" << name << "\"" << endl;
+ //kdDebug(5300) << "LdapSearch::makeSearchData() found BAD ENTRY: \"" << name << "\"" << endl;
continue; // nothing, bad entry
}
} else if ( name.isEmpty() ) {
- kdDebug(5300) << "LdapSearch::makeSearchData() mail: \"" << mail << "\"" << endl;
+ //kdDebug(5300) << "LdapSearch::makeSearchData() mail: \"" << mail << "\"" << endl;
ret.append( mail );
} else {
- kdDebug(5300) << "LdapSearch::makeSearchData() name: \"" << name << "\" mail: \"" << mail << "\"" << endl;
+ //kdDebug(5300) << "LdapSearch::makeSearchData() name: \"" << name << "\" mail: \"" << mail << "\"" << endl;
ret.append( TQString( "%1 <%2>" ).arg( name ).arg( mail ) );
}
diff --git a/libkdepim/ldapclient.h b/libkdepim/ldapclient.h
index 5167660e2..cf3f55827 100644
--- a/libkdepim/ldapclient.h
+++ b/libkdepim/ldapclient.h
@@ -256,6 +256,7 @@ class KDE_EXPORT LdapSearch : public QObject
void startSearch( const TQString& txt );
void cancelSearch();
bool isAvailable() const;
+ void updateCompletionWeights();
TQValueList< LdapClient* > clients() const { return mClients; }
@@ -276,6 +277,7 @@ class KDE_EXPORT LdapSearch : public QObject
void slotFileChanged( const TQString& );
private:
+ void readWeighForClient( LdapClient *client, KConfig *config, int clientNumber );
void readConfig();
void finish();
void makeSearchData( TQStringList& ret, LdapResultList& resList );
diff --git a/libkdepim/ldapsearchdialog.cpp b/libkdepim/ldapsearchdialog.cpp
index 72011966a..a51ccfb9d 100644
--- a/libkdepim/ldapsearchdialog.cpp
+++ b/libkdepim/ldapsearchdialog.cpp
@@ -1,5 +1,5 @@
/* ldapsearchdialogimpl.cpp - LDAP access
- * Copyright (C) 2002 Klarälvdalens Datakonsult AB
+ * Copyright (C) 2002 Klar�vdalens Datakonsult AB
*
* Author: Steffen Hansen <hansen@kde.org>
*
@@ -21,6 +21,8 @@
#include "ldapsearchdialog.h"
#include "ldapclient.h"
+#include <libemailfunctions/email.h>
+
#include <tqcheckbox.h>
#include <tqgroupbox.h>
#include <tqheader.h>
@@ -94,12 +96,20 @@ static TQMap<TQString, TQString>& adrbookattr2ldap()
return keys;
}
-class ContactListItem : public QListViewItem
+namespace KPIM {
+
+class ContactListItem : public TQListViewItem
{
public:
ContactListItem( TQListView* parent, const KPIM::LdapAttrMap& attrs )
: TQListViewItem( parent ), mAttrs( attrs )
- { }
+ {
+ const KPIM::LdapAttrValue &mailAttrs = attrs[ "mail" ];
+ if ( mailAttrs.isEmpty() ) {
+ setSelectable( false );
+ setEnabled( false );
+ }
+ }
KPIM::LdapAttrMap mAttrs;
@@ -112,6 +122,8 @@ class ContactListItem : public QListViewItem
}
};
+}
+
LDAPSearchDialog::LDAPSearchDialog( TQWidget* parent, const char* name )
: KDialogBase( Plain, i18n( "Search for Addresses in Directory" ), Help | User1 |
User2 | User3 | Cancel, Default, parent, name, false, true )
@@ -248,7 +260,7 @@ void LDAPSearchDialog::restoreSettings()
KPIM::LdapClient* ldapClient = new KPIM::LdapClient( 0, this, "ldapclient" );
ldapClient->setServer( ldapServer );
-
+
TQStringList attrs;
for ( TQMap<TQString,TQString>::Iterator it = adrbookattr2ldap().begin(); it != adrbookattr2ldap().end(); ++it )
@@ -435,7 +447,7 @@ TQString LDAPSearchDialog::selectedEMails() const
if ( name.isEmpty() ) {
result << email;
} else {
- result << name + " <" + email + ">";
+ result << KPIM::quoteNameIfNecessary( name ) + " <" + email + ">";
}
}
}
diff --git a/libkdepim/ldapsearchdialog.h b/libkdepim/ldapsearchdialog.h
index 1b3a7cc0e..9b19e5246 100644
--- a/libkdepim/ldapsearchdialog.h
+++ b/libkdepim/ldapsearchdialog.h
@@ -1,5 +1,5 @@
/* ldapsearchdialogimpl.h - LDAP access
- * Copyright (C) 2002 Klarälvdalens Datakonsult AB
+ * Copyright (C) 2002 Klar�vdalens Datakonsult AB
*
* Author: Steffen Hansen <hansen@kde.org>
*
diff --git a/libkdepim/progressdialog.cpp b/libkdepim/progressdialog.cpp
index f35f23909..227e73766 100644
--- a/libkdepim/progressdialog.cpp
+++ b/libkdepim/progressdialog.cpp
@@ -224,6 +224,11 @@ void TransactionItem::setCrypto( bool on )
mSSLLabel->setState( mSSLLabel->lastState() );
}
+void TransactionItem::setTotalSteps( int totalSteps )
+{
+ mProgress->setTotalSteps( totalSteps );
+}
+
void TransactionItem::slotItemCanceled()
{
if ( mItem )
@@ -279,6 +284,8 @@ ProgressDialog::ProgressDialog( TQWidget* alignWidget, TQWidget* parent, const c
this, TQT_SLOT( slotTransactionLabel( KPIM::ProgressItem*, const TQString& ) ) );
connect ( pm, TQT_SIGNAL( progressItemUsesCrypto(KPIM::ProgressItem*, bool) ),
this, TQT_SLOT( slotTransactionUsesCrypto( KPIM::ProgressItem*, bool ) ) );
+ connect ( pm, TQT_SIGNAL( progressItemUsesBusyIndicator(KPIM::ProgressItem*, bool) ),
+ this, TQT_SLOT( slotTransactionUsesBusyIndicator( KPIM::ProgressItem*, bool ) ) );
connect ( pm, TQT_SIGNAL( showProgressDialog() ),
this, TQT_SLOT( slotShow() ) );
}
@@ -374,6 +381,17 @@ void ProgressDialog::slotTransactionUsesCrypto( ProgressItem *item,
}
}
+void ProgressDialog::slotTransactionUsesBusyIndicator( KPIM::ProgressItem *item, bool value )
+{
+ if ( mTransactionsToListviewItems.contains( item ) ) {
+ TransactionItem *ti = mTransactionsToListviewItems[ item ];
+ if ( value )
+ ti->setTotalSteps( 0 );
+ else
+ ti->setTotalSteps( 100 );
+ }
+}
+
void ProgressDialog::slotShow()
{
setVisible( true );
diff --git a/libkdepim/progressdialog.h b/libkdepim/progressdialog.h
index dc0e67949..cabcb69a2 100644
--- a/libkdepim/progressdialog.h
+++ b/libkdepim/progressdialog.h
@@ -90,6 +90,7 @@ public:
void setLabel( const TQString& );
void setStatus( const TQString& );
void setCrypto( bool );
+ void setTotalSteps( int totalSteps );
ProgressItem* item() const { return mItem; }
@@ -132,6 +133,7 @@ void slotTransactionAdded( KPIM::ProgressItem *item );
void slotTransactionStatus( KPIM::ProgressItem *item, const TQString& );
void slotTransactionLabel( KPIM::ProgressItem *item, const TQString& );
void slotTransactionUsesCrypto( KPIM::ProgressItem *item, bool );
+ void slotTransactionUsesBusyIndicator( KPIM::ProgressItem*, bool );
void slotClose();
void slotShow();
diff --git a/libkdepim/progressmanager.cpp b/libkdepim/progressmanager.cpp
index 0c73e0c55..2e5f4d6eb 100644
--- a/libkdepim/progressmanager.cpp
+++ b/libkdepim/progressmanager.cpp
@@ -41,7 +41,7 @@ ProgressItem::ProgressItem(
:mId( id ), mLabel( label ), mStatus( status ), mParent( parent ),
mCanBeCanceled( canBeCanceled ), mProgress( 0 ), mTotal( 0 ),
mCompleted( 0 ), mWaitingForKids( false ), mCanceled( false ),
- mUsesCrypto( usesCrypto )
+ mUsesCrypto( usesCrypto ), mUsesBusyIndicator( false )
{}
ProgressItem::~ProgressItem()
@@ -123,6 +123,12 @@ void ProgressItem::setUsesCrypto( bool v )
emit progressItemUsesCrypto( this, v );
}
+void ProgressItem::setUsesBusyIndicator( bool useBusyIndicator )
+{
+ mUsesBusyIndicator = useBusyIndicator;
+ emit progressItemUsesBusyIndicator( this, useBusyIndicator );
+}
+
// ======================================
ProgressManager::ProgressManager() :TQObject() {
@@ -170,6 +176,8 @@ ProgressItem* ProgressManager::createProgressItemImpl(
this, TQT_SIGNAL( progressItemLabel(KPIM::ProgressItem*, const TQString&) ) );
connect ( t, TQT_SIGNAL( progressItemUsesCrypto(KPIM::ProgressItem*, bool) ),
this, TQT_SIGNAL( progressItemUsesCrypto(KPIM::ProgressItem*, bool) ) );
+ connect ( t, TQT_SIGNAL( progressItemUsesBusyIndicator(KPIM::ProgressItem*, bool) ),
+ this, TQT_SIGNAL( progressItemUsesBusyIndicator(KPIM::ProgressItem*, bool) ) );
emit progressItemAdded( t );
} else {
@@ -212,7 +220,12 @@ ProgressItem* ProgressManager::singleItem() const
ProgressItem *item = 0;
TQDictIterator< ProgressItem > it( mTransactions );
for ( ; it.current(); ++it ) {
- if ( !(*it)->parent() ) { // if it's a top level one, only those count
+
+ // No single item for progress possible, as one of them is a busy indicator one.
+ if ( (*it)->usesBusyIndicator() )
+ return 0;
+
+ if ( !(*it)->parent() ) { // if it's a top level one, only those count
if ( item )
return 0; // we found more than one
else
diff --git a/libkdepim/progressmanager.h b/libkdepim/progressmanager.h
index b4233f8df..bf2842716 100644
--- a/libkdepim/progressmanager.h
+++ b/libkdepim/progressmanager.h
@@ -96,6 +96,18 @@ class KDE_EXPORT ProgressItem : public QObject
void setUsesCrypto( bool v );
/**
+ * @return whether this item uses a busy indicator instead of real progress display
+ */
+ bool usesBusyIndicator() const { return mUsesBusyIndicator; }
+
+ /**
+ * Sets whether this item uses a busy indicator instead of real progress for its progress bar.
+ * If it uses a busy indicator, you are still responsible for calling setProgress() from time to
+ * time to update the busy indicator.
+ */
+ void setUsesBusyIndicator( bool useBusyIndicator );
+
+ /**
* @return The current progress value of this item in percent.
*/
unsigned int progress() const { return mProgress; }
@@ -192,6 +204,15 @@ signals:
*/
void progressItemUsesCrypto( KPIM::ProgressItem*, bool );
+ /**
+ * Emitted when the busy indicator state of an item changes. Should be used
+ * by progress dialogs so that they can adjust the display of the progress bar
+ * to the new mode.
+ * @param item The updated item
+ * @param value True if the item uses a busy indicator now, false otherwise
+ */
+ void progressItemUsesBusyIndicator( KPIM::ProgressItem *item, bool value );
+
protected:
/* Only to be used by our good friend the ProgressManager */
@@ -217,6 +238,7 @@ signals:
bool mWaitingForKids;
bool mCanceled;
bool mUsesCrypto;
+ bool mUsesBusyIndicator;
};
/**
@@ -335,6 +357,9 @@ class KDE_EXPORT ProgressManager : public QObject
/**
* @return the only top level progressitem when there's only one.
* Returns 0 if there is no item, or more than one top level item.
+ * Since this is used to calculate the overall progress, it will also return
+ * 0 if there is an item which uses a busy indicator, since that will invalidate
+ * the overall progress.
*/
ProgressItem* singleItem() const;
@@ -361,6 +386,8 @@ class KDE_EXPORT ProgressManager : public QObject
void progressItemLabel( KPIM::ProgressItem*, const TQString& );
/** @see ProgressItem::progressItemUsesCrypto() */
void progressItemUsesCrypto( KPIM::ProgressItem*, bool );
+ /** @see ProgressItem::progressItemUsesBusyIndicator */
+ void progressItemUsesBusyIndicator( KPIM::ProgressItem*, bool );
/**
* Emitted when an operation requests the listeners to be shown.
diff --git a/libkdepim/statusbarprogresswidget.cpp b/libkdepim/statusbarprogresswidget.cpp
index c6fa807a2..a7b240ea0 100644
--- a/libkdepim/statusbarprogresswidget.cpp
+++ b/libkdepim/statusbarprogresswidget.cpp
@@ -105,6 +105,8 @@ StatusbarProgressWidget::StatusbarProgressWidget( ProgressDialog* progressDialog
this, TQT_SLOT( slotProgressItemAdded( KPIM::ProgressItem * ) ) );
connect ( ProgressManager::instance(), TQT_SIGNAL( progressItemCompleted( KPIM::ProgressItem * ) ),
this, TQT_SLOT( slotProgressItemCompleted( KPIM::ProgressItem * ) ) );
+ connect ( ProgressManager::instance(), TQT_SIGNAL(progressItemUsesBusyIndicator(KPIM::ProgressItem*,bool)),
+ this, TQT_SLOT( updateBusyMode() ) );
connect ( progressDialog, TQT_SIGNAL( visibilityChanged( bool )),
this, TQT_SLOT( slotProgressDialogVisible( bool ) ) );
@@ -119,9 +121,8 @@ StatusbarProgressWidget::StatusbarProgressWidget( ProgressDialog* progressDialog
// In slot..Added we can only end up in 1 or N.
// In slot..Removed we can end up in 0, 1, or we can stay in N if we were already.
-void StatusbarProgressWidget::slotProgressItemAdded( ProgressItem *item )
+void StatusbarProgressWidget::updateBusyMode()
{
- if ( item->parent() ) return; // we are only interested in top level items
connectSingleItem(); // if going to 1 item
if ( mCurrentItem ) { // Exactly one item
delete mBusyTimer;
@@ -138,6 +139,14 @@ void StatusbarProgressWidget::slotProgressItemAdded( ProgressItem *item )
}
}
+void StatusbarProgressWidget::slotProgressItemAdded( ProgressItem *item )
+{
+ if ( item->parent() )
+ return; // we are only interested in top level items
+
+ updateBusyMode();
+}
+
void StatusbarProgressWidget::slotProgressItemCompleted( ProgressItem *item )
{
if ( item->parent() ) return; // we are only interested in top level items
diff --git a/libkdepim/statusbarprogresswidget.h b/libkdepim/statusbarprogresswidget.h
index d32a37b84..a35943013 100644
--- a/libkdepim/statusbarprogresswidget.h
+++ b/libkdepim/statusbarprogresswidget.h
@@ -72,6 +72,7 @@ protected slots:
void slotProgressDialogVisible( bool );
void slotShowItemDelayed();
void slotBusyIndicator();
+ void updateBusyMode();
protected:
void setMode();
diff --git a/libkdepim/tests/Makefile.am b/libkdepim/tests/Makefile.am
index 5adc2e1c4..2e0d081ba 100644
--- a/libkdepim/tests/Makefile.am
+++ b/libkdepim/tests/Makefile.am
@@ -1,4 +1,4 @@
-AM_CPPFLAGS = -I$(top_builddir)/libkdepim -I$(top_srcdir)/libemailfunctions $(all_includes)
+AM_CPPFLAGS = -I$(top_builddir)/libkdepim -I$(top_srcdir)/libkdepim -I$(top_srcdir)/libemailfunctions $(all_includes)
AM_LDFLAGS = $(all_libraries) $(KDE_RPATH)
LDADD = ../libkdepim.la $(LIB_KDECORE)
@@ -9,8 +9,10 @@ check_PROGRAMS = testwizard testaddresseelineedit \
test_kregexp \
testdateedit \
testlinklocator \
- testdistrlist
+ testkincidencechooser
+# disabled because of X dependency
+# testdistrlist
testwizard_SOURCES = testwizard.cpp myconfig.kcfgc
testaddresseelineedit_SOURCES = testaddresseelineedit.cpp
@@ -20,9 +22,10 @@ testutf7decoder_SOURCES = testutf7decoder.cpp
test_kregexp_SOURCES = test_kregexp.cpp
testdateedit_SOURCES = testdateedit.cpp
testlinklocator_SOURCES = testlinklocator.cpp
-testdistrlist_SOURCES = testdistrlist.cpp
+#testdistrlist_SOURCES = testdistrlist.cpp
+testkincidencechooser_SOURCES = testkincidencechooser.cpp
-TESTS = testdistrlist
+#TESTS = testdistrlist
METASOURCES = AUTO
diff --git a/libkdepim/tests/testkincidencechooser.cpp b/libkdepim/tests/testkincidencechooser.cpp
new file mode 100644
index 000000000..1204f8dc2
--- /dev/null
+++ b/libkdepim/tests/testkincidencechooser.cpp
@@ -0,0 +1,45 @@
+/*
+ Copyright (C) 2009 Allen Winter <winter@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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+
+#include <libkcal/event.h>
+using namespace KCal;
+
+#include "kincidencechooser.h"
+using namespace KPIM;
+
+int main( int argc, char **argv )
+{
+ KCmdLineArgs::init( argc, argv, "testkincidencechooser", 0,
+ "KIncidenceChooserTest", "1.0",
+ "kincidencechooser test app" );
+ KApplication app;
+ KIncidenceChooser *chooser = new KIncidenceChooser();
+
+ Event event;
+ event.setSummary( i18n( "Meeting" ) );
+ event.setDescription( i18n( "Discuss foo" ) );
+ chooser->setIncidence( &event, &event );
+ chooser->resize( 600, 600 );
+ chooser->show();
+ return app.exec();
+}
diff --git a/libkdepim/tests/testutf7encoder2.cpp b/libkdepim/tests/testutf7encoder2.cpp
index 57c195662..6d67bae0a 100644
--- a/libkdepim/tests/testutf7encoder2.cpp
+++ b/libkdepim/tests/testutf7encoder2.cpp
@@ -3,7 +3,7 @@
#include <tqtextstream.h>
#include <string.h>
#include <assert.h>
-#include <iostream.h>
+#include <iostream>
int main( int argc, char * argv[] ) {
if ( argc == 1 ) {
@@ -31,10 +31,10 @@ int main( int argc, char * argv[] ) {
len = 1;
cout << (enc->fromUnicode(TQString(buffer[i]),len)).data();
}
- cout << endl;
+ std::cout << std::endl;
#else
int len = buffer.length();
- cout << (enc->fromUnicode(buffer,len)).data() << endl;;
+ std::cout << (enc->fromUnicode(buffer,len)).data() << std::endl;;
#endif // CHAR_WISE
delete enc;
#endif // else USE_STREAM
diff --git a/libkholidays/kholidays.cpp b/libkholidays/kholidays.cpp
index 694a32dd5..686b438a0 100644
--- a/libkholidays/kholidays.cpp
+++ b/libkholidays/kholidays.cpp
@@ -90,7 +90,7 @@ TQString KHolidays::location() const
TQString KHolidays::shortText( const TQDate &date )
{
TQValueList<KHoliday> lst = getHolidays( date );
- if ( !lst.isEmpty() )
+ if ( !lst.isEmpty() )
return lst.first().text;
else return TQString::null;
}
@@ -116,7 +116,7 @@ bool KHolidays::parseFile( const TQDate &date )
TQString KHolidays::getHoliday( const TQDate &date )
{
TQValueList<KHoliday> lst = getHolidays( date );
- if ( !lst.isEmpty() )
+ if ( !lst.isEmpty() )
return lst.first().text;
else return TQString::null;
}
@@ -124,6 +124,10 @@ TQString KHolidays::getHoliday( const TQDate &date )
TQValueList<KHoliday> KHolidays::getHolidays( const TQDate &date )
{
TQValueList<KHoliday> list;
+ if ( !date.isValid() ) {
+ return list;
+ }
+
if ( !parseFile( date ) ) return list;
struct holiday *hd = &holidays[date.dayOfYear()-1];
while ( hd ) {
diff --git a/libkpgp/kpgp.cpp b/libkpgp/kpgp.cpp
index ec80e6887..8a9c68989 100644
--- a/libkpgp/kpgp.cpp
+++ b/libkpgp/kpgp.cpp
@@ -1007,7 +1007,7 @@ Module::getKpgp()
{
if (!kpgpObject)
{
- kdError(5100) << "there is no instance of kpgp available" << endl;
+ kpgpObject = new Module();
}
return kpgpObject;
}
diff --git a/libkpgp/kpgpbase.cpp b/libkpgp/kpgpbase.cpp
index fa444be7f..157c73e3b 100644
--- a/libkpgp/kpgpbase.cpp
+++ b/libkpgp/kpgpbase.cpp
@@ -149,7 +149,8 @@ Base::run( const char *cmd, const char *passphrase, bool onlyReadFromPGP )
if (!onlyReadFromPGP) {
if (!input.isEmpty()) {
// write to pin[1] one line after the other to prevent dead lock
- for (unsigned int i=0; i<input.length(); i+=len2) {
+ uint input_length = input.length();
+ for (unsigned int i=0; i<input_length; i+=len2) {
len2 = 0;
// check if writing now to pin[1] will not block (5 ms timeout)
@@ -164,12 +165,12 @@ Base::run( const char *cmd, const char *passphrase, bool onlyReadFromPGP )
else if (pollin.revents & POLLOUT) {
// search end of next line
if ((len2 = input.find('\n', i)) == -1)
- len2 = input.length()-i;
+ len2 = input_length - i;
else
- len2 = len2-i+1;
+ len2 = len2 - i + 1;
//kdDebug(5100) << "Trying to write " << len2 << " bytes to pin[1] ..." << endl;
- len2 = write(pin[1], input.mid(i,len2).data(), len2);
+ len2 = write(pin[1], input.data() + i, len2);
//kdDebug(5100) << "Wrote " << len2 << " bytes to pin[1] ..." << endl;
}
}
@@ -353,7 +354,7 @@ Base::run( const char *cmd, const char *passphrase, bool onlyReadFromPGP )
if (WIFEXITED(childExitStatus) != 0) {
// Get the return code of the child
childExitStatus = WEXITSTATUS(childExitStatus);
- kdDebug(5100) << "PGP exited with exit status " << childExitStatus
+ kdDebug(5100) << "PGP exited with exit status " << childExitStatus
<< endl;
}
else {
@@ -524,6 +525,7 @@ Base::runGpg( const char *cmd, const char *passphrase, bool onlyReadFromGnuPG )
pid_t waitpidRetVal;
unsigned int input_pos = 0;
+ uint input_length = input.length();
do {
//kdDebug(5100) << "Checking if GnuPG is still running..." << endl;
@@ -585,7 +587,7 @@ Base::runGpg( const char *cmd, const char *passphrase, bool onlyReadFromGnuPG )
// disable polling of stderr
poller[STD_ERR].events = 0;
}
-
+
if (num_pollers > 2) {
if (poller[STD_IN].revents & ( POLLERR | POLLHUP ) ) {
kdDebug(5100) << "GnuPG seems to have hung up" << endl;
@@ -597,17 +599,17 @@ Base::runGpg( const char *cmd, const char *passphrase, bool onlyReadFromGnuPG )
if (!input.isEmpty()) {
// search end of next line
if ((len2 = input.find('\n', input_pos)) == -1)
- len2 = input.length()-input_pos;
+ len2 = input_length - input_pos;
else
- len2 = len2-input_pos+1;
+ len2 = len2 - input_pos + 1;
//kdDebug(5100) << "Trying to write " << len2 << " bytes to pin[1] ..." << endl;
- len2 = write(pin[1], input.mid(input_pos,len2).data(), len2);
+ len2 = write(pin[1], input.data() + input_pos, len2 );
//kdDebug(5100) << "Wrote " << len2 << " bytes to pin[1] ..." << endl;
input_pos += len2;
// We are done.
- if (input_pos >= input.length()) {
+ if (input_pos >= input_length) {
//kdDebug(5100) << "All input was written to pin[1]" << endl;
close (pin[1]);
pin[1] = -1;
@@ -635,7 +637,7 @@ Base::runGpg( const char *cmd, const char *passphrase, bool onlyReadFromGnuPG )
} while(waitpidRetVal == 0);
if( 0 <= pin[1] )
- close (pin[1]);
+ close (pin[1]);
close(pout[0]);
close(perr[0]);
@@ -646,7 +648,7 @@ Base::runGpg( const char *cmd, const char *passphrase, bool onlyReadFromGnuPG )
if (WIFEXITED(childExitStatus) != 0) {
// Get the return code of the child
childExitStatus = WEXITSTATUS(childExitStatus);
- kdDebug(5100) << "GnuPG exited with exit status " << childExitStatus
+ kdDebug(5100) << "GnuPG exited with exit status " << childExitStatus
<< endl;
}
else {
diff --git a/libkpimexchange/core/exchangedownload.cpp b/libkpimexchange/core/exchangedownload.cpp
index c8a0a2150..60879d266 100644
--- a/libkpimexchange/core/exchangedownload.cpp
+++ b/libkpimexchange/core/exchangedownload.cpp
@@ -49,7 +49,7 @@
#include <libkcal/calendarlocal.h>
extern "C" {
- #include <ical.h>
+ #include <libical/ical.h>
}
#include "exchangeclient.h"
diff --git a/libkpimexchange/core/exchangeupload.cpp b/libkpimexchange/core/exchangeupload.cpp
index bbc30906d..29a796dd8 100644
--- a/libkpimexchange/core/exchangeupload.cpp
+++ b/libkpimexchange/core/exchangeupload.cpp
@@ -33,7 +33,7 @@
#include <kio/http.h>
extern "C" {
- #include <ical.h>
+ #include <libical/ical.h>
}
#include <libkcal/event.h>
diff --git a/libkpimexchange/core/utils.cpp b/libkpimexchange/core/utils.cpp
index 61847dbdd..7e1cbadfe 100644
--- a/libkpimexchange/core/utils.cpp
+++ b/libkpimexchange/core/utils.cpp
@@ -21,7 +21,7 @@
#include <tqdatetime.h>
extern "C" {
- #include <ical.h>
+ #include <libical/ical.h>
}
#include "utils.h"
diff --git a/libkpimidentities/identity.cpp b/libkpimidentities/identity.cpp
index 19cd65935..fb2f1ac18 100644
--- a/libkpimidentities/identity.cpp
+++ b/libkpimidentities/identity.cpp
@@ -236,6 +236,7 @@ const Identity& Identity::null()
bool Identity::isNull() const {
return mIdentity.isEmpty() && mFullName.isEmpty() && mEmailAddr.isEmpty() &&
+ mEmailAliases.empty() &&
mOrganization.isEmpty() && mReplyToAddr.isEmpty() && mBcc.isEmpty() &&
mVCardFile.isEmpty() &&
mFcc.isEmpty() && mDrafts.isEmpty() && mTemplates.isEmpty() &&
@@ -251,6 +252,7 @@ bool Identity::operator==( const Identity & other ) const {
bool same = mUoid == other.mUoid &&
mIdentity == other.mIdentity && mFullName == other.mFullName &&
mEmailAddr == other.mEmailAddr && mOrganization == other.mOrganization &&
+ mEmailAliases == other.mEmailAliases &&
mReplyToAddr == other.mReplyToAddr && mBcc == other.mBcc &&
mVCardFile == other.mVCardFile &&
mFcc == other.mFcc &&
@@ -271,6 +273,7 @@ bool Identity::operator==( const Identity & other ) const {
if ( mIdentity != other.mIdentity ) kdDebug() << "mIdentity differs : " << mIdentity << " != " << other.mIdentity << endl;
if ( mFullName != other.mFullName ) kdDebug() << "mFullName differs : " << mFullName << " != " << other.mFullName << endl;
if ( mEmailAddr != other.mEmailAddr ) kdDebug() << "mEmailAddr differs : " << mEmailAddr << " != " << other.mEmailAddr << endl;
+ if ( mEmailAliases != other.mEmailAliases ) kdDebug() << "mEmailAliases differs : " << mEmailAliases.join(";") << " != " << other.mEmailAliases.join(";") << endl;
if ( mOrganization != other.mOrganization ) kdDebug() << "mOrganization differs : " << mOrganization << " != " << other.mOrganization << endl;
if ( mReplyToAddr != other.mReplyToAddr ) kdDebug() << "mReplyToAddr differs : " << mReplyToAddr << " != " << other.mReplyToAddr << endl;
if ( mBcc != other.mBcc ) kdDebug() << "mBcc differs : " << mBcc << " != " << other.mBcc << endl;
@@ -320,6 +323,7 @@ void Identity::readConfig( const KConfigBase * config )
mIdentity = config->readEntry("Identity");
mFullName = config->readEntry("Name");
mEmailAddr = config->readEntry("Email Address");
+ mEmailAliases = config->readListEntry("Email Aliases");
mVCardFile = config->readPathEntry("VCardFile");
mOrganization = config->readEntry("Organization");
mPGPSigningKey = config->readEntry("PGP Signing Key").latin1();
@@ -362,6 +366,7 @@ void Identity::writeConfig( KConfigBase * config ) const
config->writeEntry("SMIME Encryption Key", mSMIMEEncryptionKey.data());
config->writeEntry("Preferred Crypto Message Format", Kleo::cryptoMessageFormatToString( mPreferredCryptoMessageFormat ) );
config->writeEntry("Email Address", mEmailAddr);
+ config->writeEntry("Email Aliases", mEmailAliases);
config->writeEntry("Reply-To Address", mReplyToAddr);
config->writeEntry("Bcc", mBcc);
config->writePathEntry("VCardFile", mVCardFile);
@@ -385,7 +390,8 @@ TQDataStream & KPIM::operator<<( TQDataStream & stream, const KPIM::Identity & i
<< i.pgpEncryptionKey()
<< i.smimeSigningKey()
<< i.smimeEncryptionKey()
- << i.emailAddr()
+ << i.primaryEmailAddress()
+ << i.emailAliases()
<< i.replyToAddr()
<< i.bcc()
<< i.vCardFile()
@@ -411,6 +417,7 @@ TQDataStream & KPIM::operator>>( TQDataStream & stream, KPIM::Identity & i ) {
>> i.mSMIMESigningKey
>> i.mSMIMEEncryptionKey
>> i.mEmailAddr
+ >> i.mEmailAliases
>> i.mReplyToAddr
>> i.mBcc
>> i.mVCardFile
@@ -484,11 +491,26 @@ void Identity::setSMIMEEncryptionKey(const TQCString &str)
}
//-----------------------------------------------------------------------------
-void Identity::setEmailAddr(const TQString &str)
+void Identity::setPrimaryEmailAddress( const TQString & str )
{
mEmailAddr = str;
}
+void Identity::setEmailAliases( const TQStringList & list )
+{
+ mEmailAliases = list;
+}
+
+bool Identity::matchesEmailAddress( const TQString & addr ) const
+{
+ const TQString lower = addr.lower();
+ if ( lower == mEmailAddr.lower() )
+ return true;
+ for ( TQStringList::const_iterator it = mEmailAliases.begin(), end = mEmailAliases.end() ; it != end ; ++it )
+ if ( (*it).lower() == lower )
+ return true;
+ return false;
+}
//-----------------------------------------------------------------------------
void Identity::setVCardFile(const TQString &str)
diff --git a/libkpimidentities/identity.h b/libkpimidentities/identity.h
index 236a2dc68..9baba4fac 100644
--- a/libkpimidentities/identity.h
+++ b/libkpimidentities/identity.h
@@ -206,8 +206,19 @@ public:
void setPreferredCryptoMessageFormat( Kleo::CryptoMessageFormat format ) { mPreferredCryptoMessageFormat = format; }
/** email address (without the user name - only name\@host) */
- TQString emailAddr() const { return mEmailAddr; }
- void setEmailAddr(const TQString&);
+ KDE_DEPRECATED TQString emailAddr() const { return primaryEmailAddress(); }
+ KDE_DEPRECATED void setEmailAddr( const TQString & email ) { setPrimaryEmailAddress( email ); }
+
+ /** primary email address (without the user name - only name\@host).
+ The primary email address is used for all outgoing mail. */
+ TQString primaryEmailAddress() const { return mEmailAddr; }
+ void setPrimaryEmailAddress( const TQString & email );
+
+ /** email address aliases */
+ const TQStringList & emailAliases() const { return mEmailAliases; }
+ void setEmailAliases( const TQStringList & );
+
+ bool matchesEmailAddress( const TQString & addr ) const;
/** vCard to attach to outgoing emails */
TQString vCardFile() const { return mVCardFile; }
@@ -295,6 +306,7 @@ protected:
// and operator>> accordingly:
uint mUoid;
TQString mIdentity, mFullName, mEmailAddr, mOrganization;
+ TQStringList mEmailAliases;
TQString mReplyToAddr;
TQString mBcc;
TQString mVCardFile;
diff --git a/libkpimidentities/identitymanager.cpp b/libkpimidentities/identitymanager.cpp
index 4c6ed02ad..e7380ca66 100644
--- a/libkpimidentities/identitymanager.cpp
+++ b/libkpimidentities/identitymanager.cpp
@@ -211,7 +211,7 @@ void IdentityManager::writeConfig() const {
// Also write the default identity to emailsettings
KEMailSettings es;
es.setSetting( KEMailSettings::RealName, (*it).fullName() );
- es.setSetting( KEMailSettings::EmailAddress, (*it).emailAddr() );
+ es.setSetting( KEMailSettings::EmailAddress, (*it).primaryEmailAddress() );
es.setSetting( KEMailSettings::Organization, (*it).organization() );
es.setSetting( KEMailSettings::ReplyToAddress, (*it).replyToAddr() );
}
@@ -304,16 +304,14 @@ const Identity & IdentityManager::identityForUoidOrDefault( uint uoid ) const
const Identity & IdentityManager::identityForAddress( const TQString & addresses ) const
{
- TQStringList addressList = KPIM::splitEmailAddrList( addresses );
- for ( ConstIterator it = begin() ; it != end() ; ++it ) {
- for( TQStringList::ConstIterator addrIt = addressList.begin();
- addrIt != addressList.end(); ++addrIt ) {
- // I use TQString::utf8() instead of TQString::latin1() because I want
- // a TQCString and not a char*. It doesn't matter because emailAddr()
- // returns a 7-bit string.
- if( (*it).emailAddr().lower() ==
- KPIM::getEmailAddress( *addrIt ).lower() ) {
- return (*it);
+ const TQStringList addressList = KPIM::splitEmailAddrList( addresses );
+ for( TQStringList::ConstIterator addrIt = addressList.begin();
+ addrIt != addressList.end(); ++addrIt ) {
+ const TQString addr = KPIM::getEmailAddress( *addrIt ).lower();
+ for ( ConstIterator it = begin() ; it != end() ; ++it ) {
+ const Identity & id = *it;
+ if ( id.matchesEmailAddress( addr ) ) {
+ return id;
}
}
}
@@ -499,7 +497,7 @@ TQStringList KPIM::IdentityManager::allEmails() const
{
TQStringList lst;
for ( ConstIterator it = begin() ; it != end() ; ++it ) {
- lst << (*it).emailAddr();
+ lst << (*it).primaryEmailAddress();
}
return lst;
}
diff --git a/libksieve/tests/lexertest.cpp b/libksieve/tests/lexertest.cpp
index 23e0f886d..dee04bd11 100644
--- a/libksieve/tests/lexertest.cpp
+++ b/libksieve/tests/lexertest.cpp
@@ -30,6 +30,7 @@
your version.
*/
#include <config.h>
+#include <cstdlib>
#include <ksieve/lexer.h>
using KSieve::Lexer;
diff --git a/libksieve/tests/parsertest.cpp b/libksieve/tests/parsertest.cpp
index 87381a326..fdc08a978 100644
--- a/libksieve/tests/parsertest.cpp
+++ b/libksieve/tests/parsertest.cpp
@@ -30,6 +30,7 @@
your version.
*/
#include <config.h>
+#include <cstdlib>
#include <ksieve/parser.h>
using KSieve::Parser;
diff --git a/mimelib/COPYRIGHT b/mimelib/COPYRIGHT
new file mode 100644
index 000000000..75ab5778d
--- /dev/null
+++ b/mimelib/COPYRIGHT
@@ -0,0 +1,13 @@
+Copyright (c) 1996, 1997 Douglas W. Sauder
+All rights reserved.
+
+IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
diff --git a/mimelib/datetime.cpp b/mimelib/datetime.cpp
index a704e127b..64f2eef2e 100644
--- a/mimelib/datetime.cpp
+++ b/mimelib/datetime.cpp
@@ -125,7 +125,10 @@ void DwDateTime::Init()
DwUint32 t_local = my_inv_gmtime(&local);
DwUint32 t_utc = my_inv_gmtime(&utc);
sDefaultZone = (int) (t_local - t_utc)/60;
- sIsDefaultZoneSet = 1;
+
+ // do not flag this as it would never check the zone again, which
+ // would lead to wrong timediff on the DST/non-DST day change
+ //sIsDefaultZoneSet = 1;
}
// Set the time zone from the default time zone
mZone = sDefaultZone;
diff --git a/mimelib/dw_cte.cpp b/mimelib/dw_cte.cpp
index 6ebf07f50..4498597d3 100644
--- a/mimelib/dw_cte.cpp
+++ b/mimelib/dw_cte.cpp
@@ -60,7 +60,7 @@ int DwToCrLfEol(const DwString& aSrcStr, DwString& aDestStr)
char* destBuf = (char*) destStr.data();
// Encode source to destination
- size_t destLen;
+ size_t destLen = 0;
to_crlf(srcBuf, srcLen, destBuf, destSize, &destLen);
aDestStr.assign(destStr, 0, destLen);
return 0;
@@ -78,7 +78,7 @@ int DwToLfEol(const DwString& aSrcStr, DwString& aDestStr)
char* destBuf = (char*) destStr.data();
// Encode source to destination
- size_t destLen;
+ size_t destLen = 0;
to_lf(srcBuf, srcLen, destBuf, destSize, &destLen);
aDestStr.assign(destStr, 0, destLen);
return 0;
@@ -96,7 +96,7 @@ int DwToCrEol(const DwString& aSrcStr, DwString& aDestStr)
char* destBuf = (char*) destStr.data();
// Encode source to destination
- size_t destLen;
+ size_t destLen = 0;
to_cr(srcBuf, srcLen, destBuf, destSize, &destLen);
aDestStr.assign(destStr, 0, destLen);
return 0;
@@ -129,7 +129,7 @@ int DwEncodeBase64(const DwString& aSrcStr, DwString& aDestStr)
char* destBuf = (char*) destStr.data();
// Encode source to destination
- size_t destLen;
+ size_t destLen = 0;
int result =
encode_base64(srcBuf, srcLen, destBuf, destSize, &destLen);
aDestStr.assign(destStr, 0, destLen);
@@ -149,7 +149,7 @@ int DwDecodeBase64(const DwString& aSrcStr, DwString& aDestStr)
char* destBuf = (char*) destStr.data();
// Encode source to destination
- size_t destLen;
+ size_t destLen = 0;
int result =
decode_base64(srcBuf, srcLen, destBuf, destSize, &destLen);
aDestStr.assign(destStr, 0, destLen);
@@ -170,7 +170,7 @@ int DwEncodeQuotedPrintable(const DwString& aSrcStr, DwString& aDestStr)
char* destBuf = (char*) destStr.data();
// Encode source to destination
- size_t destLen;
+ size_t destLen = 0;
int result =
encode_qp(srcBuf, srcLen, destBuf, destSize, &destLen);
aDestStr.assign(destStr, 0, destLen);
@@ -190,7 +190,7 @@ int DwDecodeQuotedPrintable(const DwString& aSrcStr, DwString& aDestStr)
char* destBuf = (char*) destStr.data();
// Encode source to destination
- size_t destLen;
+ size_t destLen = 0;
int result =
decode_qp(srcBuf, srcLen, destBuf, destSize, &destLen);
aDestStr.assign(destStr, 0, destLen);
diff --git a/mimelib/dw_date.cpp b/mimelib/dw_date.cpp
index c8f89766c..e4436bbe7 100644
--- a/mimelib/dw_date.cpp
+++ b/mimelib/dw_date.cpp
@@ -246,7 +246,7 @@ int ParseRfc822Date(const char *str, struct tm *tms, int *z)
case 'O':
case 'o':
/* Oct */
- if ((str[pos+1] == 'c' || str[pos+1] == 'c')
+ if ((str[pos+1] == 'c' || str[pos+1] == 'C')
&& (str[pos+2] == 't' || str[pos+2] == 'T')) {
n = 9;
pos += 3;
@@ -713,6 +713,7 @@ int main()
// "WWW MMM dd HH:MM:SS [Z] YYYY" zone is optional
// e.g.: Fri Oct 14 09:21:49 CEST 2005
// or: Tue Mar 23 18:00:02 2004
+// also: Tue, Feb 04, 2003 00:01:20 +0000
#include <string.h>
#include <stdio.h>
@@ -733,6 +734,7 @@ int ParseDate(const char *str, struct tm *tms, int *z)
int day=1, month=0, year=1970, hour=0, minute=0, second=0, zone=0;
int i;
+ // check for week day
for (i = 0; i < 7; i++)
if ( strncmp(str, wdays[i], 3) == 0 )
break;
@@ -740,8 +742,10 @@ int ParseDate(const char *str, struct tm *tms, int *z)
if ( i == 7 )
return -1;
+ // check for month name
+ int offset = (str[3] == ',') ? 5 : 4; // allow weekday be terminated with ","
for (i = 0; i < 12; i++)
- if ( strncmp(str+4, months[i], 3) == 0 )
+ if ( strncmp(str+offset, months[i], 3) == 0 )
break;
if ( i == 12 )
@@ -749,27 +753,39 @@ int ParseDate(const char *str, struct tm *tms, int *z)
month = i;
- if ( sscanf(str+8, "%d %d:%d:%d", &day, &hour, &minute, &second) != 4 )
- return -1;
-
- if ( isdigit(str[20]) ) { // year without zone info, as in ctime()
- if ( sscanf(str+20, "%d", &year) != 1 )
- return -1;
+ // try "dd, YYYY HH:MM:SS +ZZZZ"
+ int h, m;
+ char sign;
+ if ( sscanf(str+offset+4, "%d, %d %d:%d:%d %c%2d%2d", &day, &year, &hour, &minute, &second, &sign, &h, &m) == 8 ) {
+ // ok, worked, calculate zone
+ zone = h * 60 + m;
+ if ( sign == '-' )
+ zone = -zone;
}
else {
- if ( sscanf(str+20, "%*s %d", &year) != 1 )
+ // try "dd HH:MM:SS"
+ if ( sscanf(str+8, "%d %d:%d:%d", &day, &hour, &minute, &second) != 4 )
return -1;
- if ( strncmp(str+20, "EST" , 3) == 0 ) zone = -5 * 60;
- else if ( strncmp(str+20, "EDT" , 3) == 0 ) zone = -4 * 60;
- else if ( strncmp(str+20, "CST" , 3) == 0 ) zone = -6 * 60;
- else if ( strncmp(str+20, "CDT" , 3) == 0 ) zone = -5 * 60;
- else if ( strncmp(str+20, "MST" , 3) == 0 ) zone = -7 * 60;
- else if ( strncmp(str+20, "MDT" , 3) == 0 ) zone = -6 * 60;
- else if ( strncmp(str+20, "PST" , 3) == 0 ) zone = -8 * 60;
- else if ( strncmp(str+20, "PDT" , 3) == 0 ) zone = -7 * 60;
- else if ( strncmp(str+20, "CET" , 3) == 0 ) zone = 60;
- else if ( strncmp(str+20, "CEST", 4) == 0 ) zone = 120;
+ if ( isdigit(str[20]) ) { // year without zone info, as in ctime()
+ if ( sscanf(str+20, "%d", &year) != 1 )
+ return -1;
+ }
+ else {
+ if ( sscanf(str+20, "%*s %d", &year) != 1 )
+ return -1;
+
+ if ( strncmp(str+20, "EST" , 3) == 0 ) zone = -5 * 60;
+ else if ( strncmp(str+20, "EDT" , 3) == 0 ) zone = -4 * 60;
+ else if ( strncmp(str+20, "CST" , 3) == 0 ) zone = -6 * 60;
+ else if ( strncmp(str+20, "CDT" , 3) == 0 ) zone = -5 * 60;
+ else if ( strncmp(str+20, "MST" , 3) == 0 ) zone = -7 * 60;
+ else if ( strncmp(str+20, "MDT" , 3) == 0 ) zone = -6 * 60;
+ else if ( strncmp(str+20, "PST" , 3) == 0 ) zone = -8 * 60;
+ else if ( strncmp(str+20, "PDT" , 3) == 0 ) zone = -7 * 60;
+ else if ( strncmp(str+20, "CET" , 3) == 0 ) zone = 60;
+ else if ( strncmp(str+20, "CEST", 4) == 0 ) zone = 120;
+ }
}
if ( (day < 1) || (day > 31) ||
diff --git a/mimelib/dw_mime.cpp b/mimelib/dw_mime.cpp
index 39f75f639..cca2fdede 100644
--- a/mimelib/dw_mime.cpp
+++ b/mimelib/dw_mime.cpp
@@ -215,6 +215,9 @@ int DwSubtypeStrToEnum(const DwString& aStr)
if (DwStrcasecmp(aStr, "digest") == 0) {
type = DwMime::kSubtypeDigest;
}
+ if (DwStrcasecmp(aStr, "directory") == 0) {
+ type = DwMime::kSubtypeDirectory;
+ }
else if (DwStrcasecmp(aStr, "disposition-notification") == 0 ) {
type = DwMime::kSubtypeDispositionNotification;
}
@@ -341,6 +344,9 @@ int DwSubtypeStrToEnum(const DwString& aStr)
if (DwStrcasecmp(aStr, "x-diff") == 0) {
type = DwMime::kSubtypeXDiff;
}
+ if (DwStrcasecmp(aStr, "x-vcalendar") == 0) {
+ type = DwMime::kSubtypeVCal;
+ }
break;
}
return type;
@@ -375,6 +381,9 @@ void DwSubtypeEnumToStr(int aEnum, DwString& aStr)
case DwMime::kSubtypeXVCard:
aStr = "X-VCard";
break;
+ case DwMime::kSubtypeDirectory:
+ aStr = "Directory";
+ break;
case DwMime::kSubtypeXDiff:
aStr = "X-Diff";
break;
diff --git a/mimelib/dwstring.cpp b/mimelib/dwstring.cpp
index cd3c7b1ab..749f7c8ee 100644
--- a/mimelib/dwstring.cpp
+++ b/mimelib/dwstring.cpp
@@ -399,7 +399,7 @@ DwString::DwString(const char* aCstr)
mStart = 0;
mLength = 0;
if ( aCstr ) {
- size_t len = (aCstr) ? strlen(aCstr) : 0;
+ size_t len = strlen(aCstr);
_replace(0, mLength, aCstr, len);
}
}
diff --git a/mimelib/mimelib/address.h b/mimelib/mimelib/address.h
index c384b949c..7ed56ba8c 100644
--- a/mimelib/mimelib/address.h
+++ b/mimelib/mimelib/address.h
@@ -36,7 +36,6 @@
#endif
class DwAddressList;
-class DwMailboxList;
//=============================================================================
//+ Name DwAddress -- Abstract class representing an RFC-822 address
@@ -149,7 +148,7 @@ protected:
inline DwBool DwAddress::IsValid() const
{
- return mIsValid;
+ return mIsValid != 0;
}
#endif
diff --git a/mimelib/mimelib/enum.h b/mimelib/mimelib/enum.h
index 9e2d0ee30..93cfe0106 100644
--- a/mimelib/mimelib/enum.h
+++ b/mimelib/mimelib/enum.h
@@ -78,6 +78,7 @@ enum {
kSubtypeEnriched,
kSubtypeHtml,
kSubtypeXVCard,
+ kSubtypeDirectory,
kSubtypeVCal,
kSubtypeRtf,
kSubtypeXDiff,
diff --git a/mimelib/mimelib/headers.h b/mimelib/mimelib/headers.h
index 8f802ce50..f545a3db2 100644
--- a/mimelib/mimelib/headers.h
+++ b/mimelib/mimelib/headers.h
@@ -67,7 +67,6 @@
#endif
class DwMessage;
-class DwBodyPart;
class DwField;
class DwFieldBody;
class DwDateTime;
diff --git a/mimelib/mimelib/mailbox.h b/mimelib/mimelib/mailbox.h
index d5d376f26..7e38ae4b4 100644
--- a/mimelib/mimelib/mailbox.h
+++ b/mimelib/mimelib/mailbox.h
@@ -35,7 +35,6 @@
#include <mimelib/address.h>
#endif
-class DwGroup;
//=============================================================================
//+ Name DwMailbox -- Class representing an RFC-822 mailbox
diff --git a/mimelib/mimelib/mboxlist.h b/mimelib/mimelib/mboxlist.h
index 0487d7510..723a8c55d 100644
--- a/mimelib/mimelib/mboxlist.h
+++ b/mimelib/mimelib/mboxlist.h
@@ -35,7 +35,6 @@
#include <mimelib/address.h>
#endif
-class DwGroup;
//=============================================================================
diff --git a/mimelib/mimelib/msgcmp.h b/mimelib/mimelib/msgcmp.h
index f1b284957..c9e6707ee 100644
--- a/mimelib/mimelib/msgcmp.h
+++ b/mimelib/mimelib/msgcmp.h
@@ -256,8 +256,8 @@ public:
//. Returns a object id that is unique among all DwMessageComponent
//. objects.
- const char* partId() const { return mId.c_str(); };
- void SetPartId( DwString id ) { mId = id; };
+ const char* partId() const { return mId.c_str(); }
+ void SetPartId( DwString id ) { mId = id; }
// set or get a unique string for that part
protected:
diff --git a/mimelib/mimelib/protocol.h b/mimelib/mimelib/protocol.h
index 151a68c5d..32186a82b 100644
--- a/mimelib/mimelib/protocol.h
+++ b/mimelib/mimelib/protocol.h
@@ -38,6 +38,7 @@
class DwObserver {
public:
+ virtual ~DwObserver(){}
virtual void Notify()=0;
};
diff --git a/mimelib/test_boyermor.cpp b/mimelib/test_boyermor.cpp
index 2140c4fdf..d2dcad80f 100644
--- a/mimelib/test_boyermor.cpp
+++ b/mimelib/test_boyermor.cpp
@@ -2,6 +2,7 @@
#include <mimelib/string.h>
#include <iostream>
+#include <cstdlib>
using std::cerr;
using std::cout;
using std::endl;
diff --git a/networkstatus/networkstatus.desktop b/networkstatus/networkstatus.desktop
index 9ebcffeaa..4d66b8c51 100644
--- a/networkstatus/networkstatus.desktop
+++ b/networkstatus/networkstatus.desktop
@@ -21,7 +21,6 @@ Name[hu]=Hálózati állapotjelző szolgáltatás
Name[is]=Netstöðupúki
Name[it]=Demone dello stato della rete
Name[ja]=ネットワークステータスデーモン
-Name[ka]=ქსელის მდგომარეობის დემონი
Name[kk]=Желі күйінің қызметі
Name[km]=ដេមិន​ស្ថានភាព​បណ្ដាញ
Name[ko]=네트워크 상태 데몬
@@ -67,7 +66,6 @@ Comment[hu]=Figyeli a hálózati csatolók állapotát és értesítési lehető
Comment[is]=Fylgist með stöðu netkorta og sendir tilkynningar til forrita sem nota netið.
Comment[it]=Controlla lo stato delle interfacce di rete e fornisce notifiche alle applicazioni che usano al rete.
Comment[ja]=ネットワークインターフェースの状態を追跡し、ネットワークを用いるアプリケーションに通知します
-Comment[ka]=იძიებს ქსელის ინტერფეისის სტატუსებს და უზრუნველჰყოფს ქსელის მომხმარებელი პროგრამებისათვის შეტყობინებების მიწოდებას.
Comment[kk]=Желі интерфейстерінің күйін бақылап, желіні қолданатын бағдарламаларын құлақтандыру қызметі.
Comment[km]=តាមដាន​ស្ថានភាព​របស់​ចំណុច​ប្រទាក់​បណ្ដាញ ព្រម​ទាំង​ផ្ដល់​នូវ​ការ​ជូនដំណឹង​ទៅ​កម្មវិធី ដែល​ប្រើ​បណ្ដាញ ។
Comment[lt]=Seka tinklo sąsajų būseną ir informuoja apie jas programas, naudojančias tinklą
diff --git a/patchlog.txt b/patchlog.txt
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/patchlog.txt
diff --git a/plugins/kmail/bodypartformatter/attendeeselector.cpp b/plugins/kmail/bodypartformatter/attendeeselector.cpp
index 0ea917bed..8fa677705 100644
--- a/plugins/kmail/bodypartformatter/attendeeselector.cpp
+++ b/plugins/kmail/bodypartformatter/attendeeselector.cpp
@@ -21,6 +21,7 @@
#include "ui_attendeeselector.h"
#include <libkdepim/addresseelineedit.h>
+#include <libemailfunctions/email.h>
#include <klocale.h>
#include <kpushbutton.h>
@@ -51,8 +52,15 @@ AttendeeSelector::AttendeeSelector(TQWidget * parent)
TQStringList AttendeeSelector::attendees() const
{
TQStringList rv;
- for ( uint i = 0; i < ui->attendeeList->count(); ++i )
- rv << ui->attendeeList->item( i )->text();
+ for ( uint i = 0; i < ui->attendeeList->count(); ++i ) {
+ TQString addr = ui->attendeeList->item( i )->text();
+
+ // Build a nice address for this attendee including the CN.
+ TQString tname, temail;
+ KPIM::getNameAndMail( addr, tname, temail ); // ignore return value
+ // which is always false
+ rv << temail;
+ }
return rv;
}
diff --git a/plugins/kmail/bodypartformatter/text_calendar.cpp b/plugins/kmail/bodypartformatter/text_calendar.cpp
index 2ea1cfd52..49b60f5ff 100644
--- a/plugins/kmail/bodypartformatter/text_calendar.cpp
+++ b/plugins/kmail/bodypartformatter/text_calendar.cpp
@@ -38,10 +38,14 @@
#include <interfaces/bodyparturlhandler.h>
#include <khtmlparthtmlwriter.h>
+#include <libkdepim/kfileio.h>
+
#include <libkcal/calendarlocal.h>
#include <libkcal/calendarresources.h>
+#include <libkcal/calhelper.h>
#include <libkcal/icalformat.h>
#include <libkcal/attendee.h>
+#include <libkcal/attachmenthandler.h>
#include <libkcal/incidence.h>
#include <libkcal/incidenceformatter.h>
@@ -54,6 +58,7 @@
#include <email.h>
#include <kglobal.h>
+#include <kfiledialog.h>
#include <kinputdialog.h>
#include <klocale.h>
#include <kstringhandler.h>
@@ -65,6 +70,11 @@
#include <kstandarddirs.h>
#include <kapplication.h>
#include <ktempfile.h>
+#include <kmdcodec.h>
+#include <kmimetype.h>
+#include <kpopupmenu.h>
+#include <krun.h>
+#include <kio/netaccess.h>
#include <tqurl.h>
#include <tqdir.h>
@@ -86,10 +96,10 @@ class CalendarManager
public:
CalendarManager();
~CalendarManager();
- static KCal::Calendar* calendar();
+ static Calendar* calendar();
private:
- KCal::CalendarResources* mCalendar;
+ CalendarResources* mCalendar;
static CalendarManager* mSelf;
};
@@ -130,7 +140,7 @@ CalendarManager::~CalendarManager()
mSelf = 0;
}
-KCal::Calendar* CalendarManager::calendar()
+Calendar* CalendarManager::calendar()
{
if ( !mSelf ) {
sCalendarDeleter.setObject( mSelf, new CalendarManager() );
@@ -139,12 +149,12 @@ KCal::Calendar* CalendarManager::calendar()
}
-class KMInvitationFormatterHelper : public KCal::InvitationFormatterHelper
+class KMInvitationFormatterHelper : public InvitationFormatterHelper
{
public:
KMInvitationFormatterHelper( KMail::Interface::BodyPart *bodyPart ) : mBodyPart( bodyPart ) {}
virtual TQString generateLinkURL( const TQString &id ) { return mBodyPart->makeLink( id ); }
- KCal::Calendar* calendar() const { return CalendarManager::calendar(); }
+ Calendar* calendar() const { return CalendarManager::calendar(); }
private:
KMail::Interface::BodyPart *mBodyPart;
};
@@ -153,7 +163,7 @@ class Formatter : public KMail::Interface::BodyPartFormatter
{
public:
Result format( KMail::Interface::BodyPart *bodyPart,
- KMail::HtmlWriter *writer ) const
+ KMail::HtmlWriter *writer, KMail::Callback &callback ) const
{
if ( !writer )
// Guard against crashes in createReply()
@@ -163,14 +173,15 @@ class Formatter : public KMail::Interface::BodyPartFormatter
TQString source;
/* If the bodypart does not have a charset specified, we need to fall back to
utf8, not the KMail fallback encoding, so get the contents as binary and decode
- explicitely. */
+ explicitly. */
if ( bodyPart->contentTypeParameter( "charset").isEmpty() ) {
const TQByteArray &ba = bodyPart->asBinary();
source = TQString::fromUtf8(ba);
} else {
source = bodyPart->asText();
}
- TQString html = IncidenceFormatter::formatICalInvitation( source, &cl, &helper );
+ TQString html =
+ IncidenceFormatter::formatICalInvitationNoHtml( source, &cl, &helper, callback.sender() );
if ( html.isEmpty() ) return AsIcon;
writer->queue( html );
@@ -201,6 +212,25 @@ static TQString directoryForStatus( Attendee::PartStat status )
return dir;
}
+static Incidence *icalToString( const TQString &iCal )
+{
+ CalendarLocal calendar( KPimPrefs::timezone() ) ;
+ ICalFormat format;
+ ScheduleMessage *message =
+ format.parseScheduleMessage( &calendar, iCal );
+ if ( !message )
+ //TODO: Error message?
+ return 0;
+ return dynamic_cast<Incidence*>( message->event() );
+}
+
+static ScheduleMessage *icalToMessage( const TQString &iCal )
+{
+ CalendarLocal calendar( KPimPrefs::timezone() ) ;
+ ICalFormat format;
+ return format.parseScheduleMessage( &calendar, iCal );
+}
+
class UrlHandler : public KMail::Interface::BodyPartURLHandler
{
public:
@@ -209,19 +239,6 @@ class UrlHandler : public KMail::Interface::BodyPartURLHandler
kdDebug() << "UrlHandler() (iCalendar)" << endl;
}
- Incidence* icalToString( const TQString& iCal ) const
- {
- CalendarLocal calendar( KPimPrefs::timezone() ) ;
- ICalFormat format;
- ScheduleMessage *message =
- format.parseScheduleMessage( &calendar, iCal );
- if ( !message )
- //TODO: Error message?
- return 0;
- return dynamic_cast<Incidence*>( message->event() );
- }
-
-
Attendee *findMyself( Incidence* incidence, const TQString& receiver ) const
{
Attendee::List attendees = incidence->attendees();
@@ -340,6 +357,13 @@ class UrlHandler : public KMail::Interface::BodyPartURLHandler
break;
}
+ // Set the organizer to the sender, if the ORGANIZER hasn't been set.
+ if ( incidence->organizer().isEmpty() ) {
+ TQString tname, temail;
+ KPIM::getNameAndMail( callback.sender(), tname, temail );
+ incidence->setOrganizer( Person( tname, temail ) );
+ }
+
TQString recv = to;
if ( recv.isEmpty() )
recv = incidence->organizer().fullName();
@@ -347,7 +371,7 @@ class UrlHandler : public KMail::Interface::BodyPartURLHandler
return callback.mailICal( recv, msg, subject, statusString, type != Forward );
}
- void ensureKorganizerRunning() const
+ void ensureKorganizerRunning( bool switchTo ) const
{
TQString error;
TQCString dcopService;
@@ -359,6 +383,10 @@ class UrlHandler : public KMail::Interface::BodyPartURLHandler
TQCString dummy;
if ( !kapp->dcopClient()->findObject( dcopService, dcopObjectId, "", TQByteArray(), dummy, dummy ) ) {
DCOPRef ref( dcopService, dcopService ); // talk to the KUniqueApplication or its kontact wrapper
+ if ( switchTo ) {
+ ref.call( "newInstance()" ); // activate korganizer window
+ }
+
DCOPReply reply = ref.call( "load()" );
if ( reply.isValid() && (bool)reply ) {
kdDebug() << "Loaded " << dcopService << " successfully" << endl;
@@ -390,11 +418,126 @@ class UrlHandler : public KMail::Interface::BodyPartURLHandler
// Now ensure that korganizer is running; otherwise start it, to prevent surprises
// (https://intevation.de/roundup/kolab/issue758)
- ensureKorganizerRunning();
+ ensureKorganizerRunning( false );
return true;
}
+ bool cancelPastInvites( Incidence *incidence, const TQString &path ) const
+ {
+ TQString warnStr;
+ TQDateTime now = TQDateTime::currentDateTime();
+ TQDate today = now.date();
+ Event * const event = dynamic_cast<Event *>( incidence );
+ Todo * const todo = dynamic_cast<Todo *>( incidence );
+ if ( incidence->type() == "Event" ) {
+ Q_ASSERT( event );
+ if ( !event->doesFloat() ) {
+ if ( event->dtEnd() < now ) {
+ warnStr = i18n( "\"%1\" occurred already." ).arg( event->summary() );
+ } else if ( event->dtStart() <= now && now <= event->dtEnd() ) {
+ warnStr = i18n( "\"%1\" is currently in-progress." ).arg( event->summary() );
+ }
+ } else {
+ if ( event->dtEnd().date() < today ) {
+ warnStr = i18n( "\"%1\" occurred already." ).arg( event->summary() );
+ } else if ( event->dtStart().date() <= today && today <= event->dtEnd().date() ) {
+ warnStr = i18n( "\"%1\", happening all day today, is currently in-progress." ).
+ arg( event->summary() );
+ }
+ }
+ } else if ( incidence->type() == "Todo" ) {
+ Q_ASSERT( todo );
+ if ( !todo->doesFloat() ) {
+ if ( todo->hasDueDate() ) {
+ if ( todo->dtDue() < now ) {
+ warnStr = i18n( "\"%1\" is past due." ).arg( todo->summary() );
+ } else if ( todo->hasStartDate() && todo->dtStart() <= now && now <= todo->dtDue() ) {
+ warnStr = i18n( "\"%1\" is currently in-progress." ).arg( todo->summary() );
+ }
+ } else if ( todo->hasStartDate() ) {
+ if ( todo->dtStart() < now ) {
+ warnStr = i18n( "\"%1\" has already started." ).arg( todo->summary() );
+ }
+ }
+ } else {
+ if ( todo->hasDueDate() ) {
+ if ( todo->dtDue().date() < today) {
+ warnStr = i18n( "\"%1\" is past due." ).arg( todo->summary() );
+ } else if ( todo->hasStartDate() &&
+ todo->dtStart().date() <= today && today <= todo->dtDue().date() ) {
+ warnStr = i18n( "\"%1\", happening all-day today, is currently in-progress." ).
+ arg( todo->summary() );
+ }
+ } else if ( todo->hasStartDate() ) {
+ if ( todo->dtStart().date() < today ) {
+ warnStr = i18n( "\"%1\", happening all day, has already started." ).
+ arg( todo->summary() );
+ }
+ }
+ }
+ }
+
+ if ( !warnStr.isEmpty() ) {
+ TQString queryStr;
+ Q_ASSERT( event || todo );
+ if ( path == "accept" ) {
+ if ( event ) {
+ queryStr = i18n( "Do you still want to accept the invitation?" );
+ } else if ( todo ) {
+ queryStr = i18n( "Do you still want to accept the task?" );
+ }
+ } else if ( path == "accept_conditionally" ) {
+ if ( event ) {
+ queryStr = i18n( "Do you still want to send conditional acceptance of the invitation?" );
+ } else if ( todo ) {
+ queryStr = i18n( "Do you still want to send conditional acceptance of the task?" );
+ }
+ } else if ( path == "accept_counter" ) {
+ queryStr = i18n( "Do you still want to accept the counter proposal?" );
+ } else if ( path == "counter" ) {
+ queryStr = i18n( "Do you still want to send a counter proposal?" );
+ } else if ( path == "decline" ) {
+ queryStr = i18n( "Do you still want to send a decline response?" );
+ } else if ( path == "decline_counter" ) {
+ queryStr = i18n( "Do you still want to decline the counter proposal?" );
+ } else if ( path == "reply" ) {
+ queryStr = i18n( "Do you still want to record this reponse in your calendar?" );
+ } else if ( path == "delegate" ) {
+ if ( event ) {
+ queryStr = i18n( "Do you still want to delegate this invitation?" );
+ } else if ( todo ) {
+ queryStr = i18n( "Do you still want to delegate this task?" );
+ }
+ } else if ( path == "forward" ) {
+ if ( event ) {
+ queryStr = i18n( "Do you still want to forward this invitation?" );
+ } else if ( todo ) {
+ queryStr = i18n( "Do you still want to forward this task?" );
+ }
+ } else if ( path == "check_calendar" ) {
+ queryStr = i18n( "Do you still want to check your calendar?" );
+ } else if ( path == "record" ) {
+ if ( event ) {
+ queryStr = i18n( "Do you still want to record this invitation in your calendar?" );
+ } else if ( todo ) {
+ queryStr = i18n( "Do you still want to record this task in your calendar?" );
+ }
+ } else if ( path.startsWith( "ATTACH:" ) ) {
+ return false;
+ } else {
+ queryStr = i18n( "%1?" ).arg( path );
+ }
+
+ if ( KMessageBox::warningYesNo(
+ 0,
+ i18n( "%1\n%2" ).arg( warnStr ).arg( queryStr ) ) == KMessageBox::No ) {
+ return true;
+ }
+ }
+ return false;
+ }
+
bool handleInvitation( const TQString& iCal, Attendee::PartStat status,
KMail::Callback &callback ) const
{
@@ -405,17 +548,22 @@ class UrlHandler : public KMail::Interface::BodyPartURLHandler
// Must be some error. Still return true though, since we did handle it
return true;
- // get comment for tentative acceptance
- Incidence* incidence = icalToString( iCal );
+ Incidence *incidence = icalToString( iCal );
+ // get comment for tentative acceptance
if ( callback.askForComment( status ) ) {
bool ok = false;
TQString comment = KInputDialog::getMultiLineText( i18n("Reaction to Invitation"),
i18n("Comment:"), TQString(), &ok );
if ( !ok )
return true;
- if ( !comment.isEmpty() )
- incidence->addComment( comment );
+ if ( !comment.isEmpty() ) {
+ if ( callback.outlookCompatibleInvitationReplyComments() ) {
+ incidence->setDescription( comment );
+ } else {
+ incidence->addComment( comment );
+ }
+ }
}
// First, save it for KOrganizer to handle
@@ -521,7 +669,7 @@ class UrlHandler : public KMail::Interface::BodyPartURLHandler
void showCalendar( const TQDate &date ) const
{
- ensureKorganizerRunning();
+ ensureKorganizerRunning( true );
// raise korganizer part in kontact or the korganizer app
kapp->dcopClient()->send( "korganizer", "korganizer", "newInstance()", TQByteArray() );
TQByteArray arg;
@@ -550,13 +698,17 @@ class UrlHandler : public KMail::Interface::BodyPartURLHandler
Incidence* incidence = icalToString( iCal );
if ( callback.askForComment( Attendee::Declined ) ) {
bool ok = false;
- // ### string freeze
- TQString comment = KInputDialog::getMultiLineText( i18n("Reaction to Invitation") /* i18n("Decline Counter Proposal") */,
+ TQString comment = KInputDialog::getMultiLineText( i18n("Decline Counter Proposal"),
i18n("Comment:"), TQString(), &ok );
if ( !ok )
return true;
- if ( !comment.isEmpty() )
- incidence->addComment( comment );
+ if ( !comment.isEmpty() ) {
+ if ( callback.outlookCompatibleInvitationReplyComments() ) {
+ incidence->setDescription( comment );
+ } else {
+ incidence->addComment( comment );
+ }
+ }
}
return mail( incidence, callback, Attendee::NeedsAction, Scheduler::Declinecounter,
callback.sender(), DeclineCounter );
@@ -576,17 +728,39 @@ class UrlHandler : public KMail::Interface::BodyPartURLHandler
bool handleClick( KMail::Interface::BodyPart *part,
const TQString &path, KMail::Callback& c ) const
{
+ if ( !CalHelper::hasMyWritableEventsFolders( "calendar" ) ) {
+ KMessageBox::error(
+ 0,
+ i18n( "You have no writable calendar folders for invitations, "
+ "so storing or saving a response will not be possible.\n"
+ "Please create at least 1 writable events calendar and re-sync." ) );
+ return false;
+ }
+
+
+ // If the bodypart does not have a charset specified, we need to fall back to utf8,
+ // not the KMail fallback encoding, so get the contents as binary and decode explicitly.
TQString iCal;
- /* If the bodypart does not have a charset specified, we need to fall back to
- utf8, not the KMail fallback encoding, so get the contents as binary and decode
- explicitely. */
if ( part->contentTypeParameter( "charset").isEmpty() ) {
const TQByteArray &ba = part->asBinary();
iCal = TQString::fromUtf8(ba);
} else {
iCal = part->asText();
}
+ Incidence *incidence = icalToString( iCal );
+ if ( !incidence ) {
+ KMessageBox::sorry(
+ 0,
+ i18n( "The calendar invitation stored in this email message is broken in some way. "
+ "Unable to continue." ) );
+ return false;
+ }
+
bool result = false;
+ if ( cancelPastInvites( incidence, path ) ) {
+ return result;
+ }
+
if ( path == "accept" )
result = handleInvitation( iCal, Attendee::Accepted, c );
if ( path == "accept_conditionally" )
@@ -603,7 +777,6 @@ class UrlHandler : public KMail::Interface::BodyPartURLHandler
if ( path == "delegate" )
result = handleInvitation( iCal, Attendee::Delegated, c );
if ( path == "forward" ) {
- Incidence* incidence = icalToString( iCal );
AttendeeSelector dlg;
if ( dlg.exec() == TQDialog::Rejected )
return true;
@@ -614,7 +787,7 @@ class UrlHandler : public KMail::Interface::BodyPartURLHandler
Scheduler::Request, fwdTo, Forward );
}
if ( path == "check_calendar" ) {
- Incidence* incidence = icalToString( iCal );
+ incidence = icalToString( iCal );
showCalendar( incidence->dtStart().date() );
}
if ( path == "reply" || path == "cancel" || path == "accept_counter" ) {
@@ -626,16 +799,98 @@ class UrlHandler : public KMail::Interface::BodyPartURLHandler
result = true;
}
}
- if ( result )
- c.closeIfSecondaryWindow();
+ if ( path == "record" ) {
+ incidence = icalToString( iCal );
+
+ int response =
+ KMessageBox::questionYesNoCancel(
+ 0,
+ i18n( "The organizer is not expecting a reply to this invitation "
+ "but you can send them an email message if you desire.\n\n"
+ "Would you like to send the organizer a message regarding this invitation?\n"
+ "Press the [Cancel] button to cancel the recording operation." ),
+ i18n( "Send Email to Organizer" ),
+ KGuiItem( i18n( "Do Not Send" ) ),
+ KGuiItem( i18n( "Send EMail" ) ) );
+
+ TQString summary;
+ switch( response ) {
+ case KMessageBox::Cancel:
+ break;
+ case KMessageBox::No: // means "send email"
+ summary = incidence->summary();
+ if ( !summary.isEmpty() ) {
+ summary = i18n( "Re: %1" ).arg( summary );
+ }
+
+ KApplication::kApplication()->invokeMailer( incidence->organizer().email(), summary );
+ //fall through
+ case KMessageBox::Yes: // means "do not send"
+ if ( saveFile( "Receiver Not Searched", iCal, TQString( "reply" ) ) ) {
+ if ( c.deleteInvitationAfterReply() ) {
+ ( new KMDeleteMsgCommand( c.getMsg()->getMsgSerNum() ) )->start();
+ result = true;
+ }
+ }
+ showCalendar( incidence->dtStart().date() );
+ break;
+ }
+ }
+
+ if ( path == "delete" ) {
+ ( new KMDeleteMsgCommand( c.getMsg()->getMsgSerNum() ) )->start();
+ result = true;
+ }
+
+ if ( path.startsWith( "ATTACH:" ) ) {
+ TQString name = path;
+ name.remove( TQRegExp( "^ATTACH:" ) );
+ result = AttachmentHandler::view( 0, name, icalToMessage( iCal ) );
+ }
+
+ if ( result ) {
+ // do not close the secondary window if an attachment was opened (kolab/issue4317)
+ if ( !path.startsWith( "ATTACH:" ) ) {
+ c.closeIfSecondaryWindow();
+ }
+ }
return result;
}
- bool handleContextMenuRequest( KMail::Interface::BodyPart *,
- const TQString &,
- const TQPoint & ) const
+ bool handleContextMenuRequest( KMail::Interface::BodyPart *part,
+ const TQString &path,
+ const TQPoint &point ) const
{
- return false;
+ TQString name = path;
+ if ( path.startsWith( "ATTACH:" ) ) {
+ name.remove( TQRegExp( "^ATTACH:" ) );
+ } else {
+ return false; //because it isn't an attachment inviation
+ }
+
+ TQString iCal;
+ if ( part->contentTypeParameter( "charset").isEmpty() ) {
+ const TQByteArray &ba = part->asBinary();
+ iCal = TQString::fromUtf8( ba );
+ } else {
+ iCal = part->asText();
+ }
+
+ KPopupMenu *menu = new KPopupMenu();
+ menu->insertItem( i18n( "Open Attachment" ), 0 );
+ menu->insertItem( i18n( "Save Attachment As..." ), 1 );
+
+ switch( menu->exec( point, 0 ) ) {
+ case 0: // open
+ AttachmentHandler::view( 0, name, icalToMessage( iCal ) );
+ break;
+ case 1: // save as
+ AttachmentHandler::saveAs( 0, name, icalToMessage( iCal ) );
+ break;
+ default:
+ break;
+ }
+ return true;
}
TQString statusBarMessage( KMail::Interface::BodyPart *,
@@ -643,31 +898,38 @@ class UrlHandler : public KMail::Interface::BodyPartURLHandler
{
if ( !path.isEmpty() ) {
if ( path == "accept" )
- return i18n("Accept incidence");
+ return i18n("Accept invitation");
if ( path == "accept_conditionally" )
- return i18n( "Accept incidence conditionally" );
-// ### string freeze
-// if ( path == "accept_counter" )
-// return i18n( "Accept counter proposal" );
+ return i18n( "Accept invitation conditionally" );
+ if ( path == "accept_counter" )
+ return i18n( "Accept counter proposal" );
if ( path == "counter" )
return i18n( "Create a counter proposal..." );
if ( path == "ignore" )
return i18n( "Throw mail away" );
if ( path == "decline" )
- return i18n( "Decline incidence" );
-// ### string freeze
-// if ( path == "decline_counter" )
-// return i18n( "Decline counter proposal" );
+ return i18n( "Decline invitation" );
+ if ( path == "decline_counter" )
+ return i18n( "Decline counter proposal" );
if ( path == "check_calendar" )
return i18n("Check my calendar..." );
if ( path == "reply" )
- return i18n( "Enter incidence into my calendar" );
+ return i18n( "Record response into my calendar" );
+ if ( path == "record" )
+ return i18n( "Record invitation into my calendar" );
+ if ( path == "delete" )
+ return i18n( "Move this invitation to my trash folder" );
if ( path == "delegate" )
- return i18n( "Delegate incidence" );
+ return i18n( "Delegate invitation" );
if ( path == "forward" )
- return i18n( "Forward incidence" );
+ return i18n( "Forward invitation" );
if ( path == "cancel" )
- return i18n( "Remove incidence from my calendar" );
+ return i18n( "Remove invitation from my calendar" );
+ if ( path.startsWith( "ATTACH:" ) ) {
+ TQString name = path;
+ return i18n( "Open attachment \"%1\"" ).
+ arg( name.remove( TQRegExp( "^ATTACH:" ) ) );
+ }
}
return TQString::null;
@@ -679,19 +941,20 @@ class Plugin : public KMail::Interface::BodyPartFormatterPlugin
public:
const KMail::Interface::BodyPartFormatter *bodyPartFormatter( int idx ) const
{
- if ( idx == 0 ) return new Formatter();
+ if ( idx == 0 || idx == 1 ) return new Formatter();
else return 0;
}
const char *type( int idx ) const
{
- if ( idx == 0 ) return "text";
+ if ( idx == 0 || idx == 1 ) return "text";
else return 0;
}
const char *subtype( int idx ) const
{
if ( idx == 0 ) return "calendar";
+ if ( idx == 1 ) return "x-vcalendar";
else return 0;
}
diff --git a/plugins/kmail/bodypartformatter/text_calendar.desktop b/plugins/kmail/bodypartformatter/text_calendar.desktop
index cf2443d30..1321d5835 100644
--- a/plugins/kmail/bodypartformatter/text_calendar.desktop
+++ b/plugins/kmail/bodypartformatter/text_calendar.desktop
@@ -14,7 +14,6 @@ Name[fy]=Applikaasje octetstream
Name[gl]=Aplicación Octetstream
Name[hu]=Alkalmazás-adatfolyam
Name[ja]=アプリケーション オクテット ストリーム
-Name[ka]=რვადინებიანი პროგრამა
Name[kk]=Қолданбаның бинарлы ағымы
Name[km]=Octetstream កម្មវិធី
Name[ms]=Aliran Oktet Aplikasi
@@ -55,7 +54,6 @@ Comment[hu]=Formázómodul text/calendar adatfolyamok kezeléséhez
Comment[is]=Sniðmátstól fyrir text/calendar
Comment[it]=Un plugin per formattare il corpo di text/calendar
Comment[ja]=text/calendar 用の Bodypart フォーマッタ プラグイン
-Comment[ka]=კომპონენტური დამფორმატებელი მოდული text/calendar
Comment[kk]=Text/calendar бөлімін пішімдеу модулі
Comment[km]=កម្មវិធី​ជំនួយ​កម្មវិធី​ធ្វើ​ទ្រង់ទ្រាយ​ផ្នែក​តួ សម្រាប់​អត្ថបទ/ប្រតិទិន
Comment[lt]=text/calendar formatavimo priedas
diff --git a/plugins/kmail/bodypartformatter/text_vcard.cpp b/plugins/kmail/bodypartformatter/text_vcard.cpp
index 347371d16..39a4ab28d 100644
--- a/plugins/kmail/bodypartformatter/text_vcard.cpp
+++ b/plugins/kmail/bodypartformatter/text_vcard.cpp
@@ -37,9 +37,15 @@
#include <klocale.h>
#include <kstringhandler.h>
#include <kglobalsettings.h>
+#include <kfiledialog.h>
#include <kiconloader.h>
+#include <kmessagebox.h>
+#include <ktempfile.h>
+#include <kio/netaccess.h>
-#include <kaddrbook.h>
+
+#include <libkdepim/addresseeview.h>
+#include <libkdepim/kaddrbook.h>
#include "interfaces/bodypartformatter.h"
#include "interfaces/bodypart.h"
@@ -47,6 +53,7 @@ using KMail::Interface::BodyPart;
#include "interfaces/bodyparturlhandler.h"
#include "khtmlparthtmlwriter.h"
#include <kimproxy.h>
+#include <kpopupmenu.h>
#include <kabc/vcardconverter.h>
#include <kabc/addressee.h>
@@ -67,14 +74,18 @@ namespace {
//mKIMProxy = ::KIMProxy::instance( kapp->dcopClient() );
}
- Result format( BodyPart *bodyPart, KMail::HtmlWriter *writer ) const {
+ Result format( BodyPart *bodyPart, KMail::HtmlWriter *writer, KMail::Callback & ) const {
if ( !writer ) return AsIcon;
VCardConverter vcc;
const TQString vCard = bodyPart->asText();
if ( vCard.isEmpty() ) return AsIcon;
- Addressee::List al = vcc.parseVCards( vCard );
+#if defined(KABC_VCARD_ENCODING_FIX)
+ Addressee::List al = vcc.parseVCardsRaw( vCard.utf8() );
+#else
+ Addressee::List al = vcc.parseVCards( vCard );
+#endif
if ( al.empty() ) return AsIcon;
writer->queue (
@@ -111,28 +122,126 @@ namespace {
class UrlHandler : public KMail::Interface::BodyPartURLHandler {
public:
- bool handleClick( BodyPart * bodyPart, const TQString & path,
- KMail::Callback& ) const {
+ bool handleClick( BodyPart * bodyPart, const TQString & path,
+ KMail::Callback& ) const {
- const TQString vCard = bodyPart->asText();
- if ( vCard.isEmpty() ) return true;
- VCardConverter vcc;
- Addressee::List al = vcc.parseVCards( vCard );
- int index = path.right( path.length() - path.findRev( ":" ) - 1 ).toInt();
- if ( index == -1 ) return true;
- KABC::Addressee a = al[index];
- if ( a.isEmpty() ) return true;
- KAddrBookExternal::addVCard( a, 0 );
- return true;
- }
-
- bool handleContextMenuRequest( BodyPart *, const TQString &, const TQPoint & ) const {
- return false;
- }
-
- TQString statusBarMessage( BodyPart *, const TQString & ) const {
- return i18n("Add this contact to the address book.");
- }
+ const TQString vCard = bodyPart->asText();
+ if ( vCard.isEmpty() ) return true;
+ VCardConverter vcc;
+#if defined(KABC_VCARD_ENCODING_FIX)
+ Addressee::List al = vcc.parseVCardsRaw( vCard.utf8() );
+#else
+ Addressee::List al = vcc.parseVCards( vCard );
+#endif
+ int index = path.right( path.length() - path.findRev( ":" ) - 1 ).toInt();
+ if ( index == -1 ) return true;
+ KABC::Addressee a = al[index];
+ if ( a.isEmpty() ) return true;
+ KAddrBookExternal::addVCard( a, 0 );
+ return true;
+ }
+
+ static KABC::Addressee findAddressee( BodyPart *part, const TQString &path )
+ {
+ const TQString vCard = part->asText();
+ if ( !vCard.isEmpty() ) {
+ VCardConverter vcc;
+#if defined(KABC_VCARD_ENCODING_FIX)
+ Addressee::List al = vcc.parseVCardsRaw( vCard.utf8() );
+#else
+ Addressee::List al = vcc.parseVCards( vCard );
+#endif
+ int index = path.right( path.length() - path.findRev( ":" ) - 1 ).toInt();
+ if ( index >= 0 ) {
+ return al[index];
+ }
+ }
+ return KABC::Addressee();
+ }
+
+ bool handleContextMenuRequest( KMail::Interface::BodyPart *part,
+ const TQString &path,
+ const TQPoint &point ) const
+ {
+ const TQString vCard = part->asText();
+ if ( vCard.isEmpty() ) {
+ return true;
+ }
+ KABC::Addressee a = findAddressee( part, path );
+ if ( a.isEmpty() ) {
+ return true;
+ }
+
+ KPopupMenu *menu = new KPopupMenu();
+ menu->insertItem( i18n( "View Business Card" ), 0 );
+ menu->insertItem( i18n( "Save Business Card As..." ), 1 );
+
+ switch( menu->exec( point, 0 ) ) {
+ case 0: // open
+ openVCard( a, vCard );
+ break;
+ case 1: // save as
+ saveAsVCard( a, vCard );
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ TQString statusBarMessage( BodyPart *part, const TQString &path ) const
+ {
+ KABC::Addressee a = findAddressee( part, path );
+ if ( a.realName().isEmpty() ) {
+ return i18n( "Add this contact to the address book." );
+ } else {
+ return i18n( "Add \"%1\" to the address book." ).arg( a.realName() );
+ }
+ }
+
+ bool openVCard( const KABC::Addressee &a, const TQString &vCard ) const
+ {
+ Q_UNUSED( vCard );
+ AddresseeView *view = new AddresseeView( 0 );
+ view->setVScrollBarMode( TQScrollView::Auto );
+ if ( a.isEmpty() ) {
+ view->setText( i18n( "Failed to parse the business card." ) );
+ } else {
+ view->setAddressee( a );
+ }
+ view->setMinimumSize( 300, 400 );
+ view->show();
+ return true;
+ }
+
+ bool saveAsVCard( const KABC::Addressee &a, const TQString &vCard ) const
+ {
+ TQString fileName = a.givenName() + '_' + a.familyName() + ".vcf";
+
+ // get the saveas file name
+ KURL saveAsUrl =
+ KFileDialog::getSaveURL( fileName,
+ TQString::null, 0,
+ i18n( "Save Business Card" ) );
+ if ( saveAsUrl.isEmpty() ||
+ ( TQFileInfo( saveAsUrl.path() ).exists() &&
+ ( KMessageBox::warningYesNo(
+ 0,
+ i18n( "%1 already exists. Do you want to overwrite it?").
+ arg( saveAsUrl.path() ) ) == KMessageBox::No ) ) ) {
+ return false;
+ }
+
+ // put the attachment in a temporary file and save it
+ KTempFile tmpFile;
+ tmpFile.setAutoDelete( true );
+
+ TQByteArray data = vCard.utf8();
+ tmpFile.file()->writeBlock( data.data(), data.size() );
+ tmpFile.close();
+
+ return KIO::NetAccess::upload( tmpFile.name(), saveAsUrl, 0 );
+ }
};
class Plugin : public KMail::Interface::BodyPartFormatterPlugin {
diff --git a/plugins/kmail/bodypartformatter/text_vcard.desktop b/plugins/kmail/bodypartformatter/text_vcard.desktop
index 206d8462a..87cbf490e 100644
--- a/plugins/kmail/bodypartformatter/text_vcard.desktop
+++ b/plugins/kmail/bodypartformatter/text_vcard.desktop
@@ -14,7 +14,6 @@ Name[fy]=Applikaasje octetstream
Name[gl]=Aplicación Octetstream
Name[hu]=Alkalmazás-adatfolyam
Name[ja]=アプリケーション オクテット ストリーム
-Name[ka]=რვადინებიანი პროგრამა
Name[kk]=Қолданбаның бинарлы ағымы
Name[km]=Octetstream កម្មវិធី
Name[ms]=Aliran Oktet Aplikasi
@@ -56,7 +55,6 @@ Comment[hu]=Formázómodul text/vcard adatfolyamok kezeléséhez
Comment[is]=Sniðmátstól fyrir text/vcard
Comment[it]=Un plugin per formattare il corpo di text/vcard
Comment[ja]=text/vcard 用の Bodypart フォーマッタ プラグイン
-Comment[ka]=კომპონენტური დამფორმატებელი მოდული text/vcard
Comment[kk]=Text/vcard бөлімін пішімдеу модулі
Comment[km]=កម្មវិធី​ជំនួយ​កម្មវិធី​ធ្វើ​ទ្រង់ទ្រាយ​ផ្នែក​តួ សម្រាប់​អត្ថបទ/vcard
Comment[lt]= Teksto/vcard formatavimo priedas
diff --git a/plugins/kmail/bodypartformatter/text_xdiff.cpp b/plugins/kmail/bodypartformatter/text_xdiff.cpp
index 87988840f..53bb0016f 100644
--- a/plugins/kmail/bodypartformatter/text_xdiff.cpp
+++ b/plugins/kmail/bodypartformatter/text_xdiff.cpp
@@ -59,7 +59,7 @@ namespace {
class Formatter : public KMail::Interface::BodyPartFormatter {
public:
- Result format( KMail::Interface::BodyPart *bodyPart, KMail::HtmlWriter *writer ) const {
+ Result format( KMail::Interface::BodyPart *bodyPart, KMail::HtmlWriter *writer, KMail::Callback & ) const {
if ( !writer ) return Ok;
diff --git a/plugins/kmail/bodypartformatter/text_xdiff.desktop b/plugins/kmail/bodypartformatter/text_xdiff.desktop
index a2c05f9cc..e04220538 100644
--- a/plugins/kmail/bodypartformatter/text_xdiff.desktop
+++ b/plugins/kmail/bodypartformatter/text_xdiff.desktop
@@ -14,7 +14,6 @@ Name[fy]=Applikaasje octetstream
Name[gl]=Aplicación Octetstream
Name[hu]=Alkalmazás-adatfolyam
Name[ja]=アプリケーション オクテット ストリーム
-Name[ka]=რვადინებიანი პროგრამა
Name[kk]=Қолданбаның бинарлы ағымы
Name[km]=Octetstream កម្មវិធី
Name[ms]=Aliran Oktet Aplikasi
@@ -54,7 +53,6 @@ Comment[hu]=Formázómodul text/x-diff adatok kezeléséhez
Comment[is]=Sniðmátstól fyrir text/x-diff
Comment[it]=Un plugin per formattare il corpo di text/x-diff
Comment[ja]=text/x-diff 用の bodypart フォーマッタプラグイン
-Comment[ka]=კომპონენტური დამფორმატებელი მოდული text/x-diff
Comment[kk]=Text/x-diff бөлімін пішімдеу модулі
Comment[km]=កម្មវិធី​ជំនួយ​កម្មវិធី​ធ្វើ​ទ្រង់ទ្រាយ​ផ្នែក​តួ សម្រាប់​អត្ថបទ/x-diff
Comment[lt]=text/x-diff formatavimo priedas
diff --git a/release_howto b/release_howto
new file mode 100644
index 000000000..c4bbcb456
--- /dev/null
+++ b/release_howto
@@ -0,0 +1,90 @@
+====== KDE PIM Enterprise release howto =====
+
+David Faure <faure@kde.org>, 02-Aug-2005, last update 12-Mar-2007.
+
+# First ensure that translations are uptodate, running "translate".
+# Packing kdepim doesn't pack the translations themselves, but still,
+# at release time we have to ensure they are ok.
+
+#
+
+cd kde-common/release
+mkdir clean cache dirty sources sources-old
+
+echo kdepim > modules
+
+# Now save the patch below to a file, and apply it.
+
+Index: common
+===================================================================
+--- common (revision 615014)
++++ common (working copy)
+@@ -23,6 +23,9 @@ case $package in
+ koffice-l10n)
+ version=1.3.98
+ ;;
++ kdepim)
++ version=3.5.6.enterprise.0.20070227.637543
++ ;;
+ *)
+ version=3.5.5
+ ;;
+
+Index: versions
+===================================================================
+--- versions (revision 615014)
++++ versions (working copy)
+@@ -20,6 +20,12 @@
+ DESTURL=tags/koffice/1.4.0/$1
+ subname=$1
+ ;;
++ kdepim)
++ HEADURL=branches/kdepim/enterprise/$1
++ DESTURL=tags/kdepim/enterprise.0.20070227.637543/$1
++ subname=$1
++ export UNSERMAKE=
++ ;;
+ *)
+ HEADURL=branches/KDE/3.5/$1
+ DESTURL=tags/KDE/3.5.5/$1
+
+
+### --- end of patch ---
+
+
+# Update the version number in "common" and the tagname in "versions"
+# The version number is: 0.YYYYMMDD.svnrevision
+
+
+#
+# Also update the version number in those files:
+# ./kmail/kmversion.h:#define KMAIL_VERSION "1.9.6 (enterprise 0.20070227.637543)"
+# ./kontact/src/main.cpp:static const char version[] = "1.2.4 (enterprise 0.20070227.637543)";
+# ./korganizer/version.h:static const char korgVersion[] = "3.5.6 (enterprise 0.20070227.637543)";
+
+
+./tag_all
+# tag_all checks out the enterprise branch of kdepim into a temporary tagging directory
+# and then allows to commit - to create the tag.
+# The script needs the variables SVNUSER and SVNPROTOCOL to be set.
+
+
+# If you used the "cache" feature with an older release, remove it first
+rm -rf cache/kdepim
+
+# Ready? OK, let's pack it:
+./pack kdepim
+
+# On failure it's always possible to restart from where it stopped, e.g. with
+# cd dirty ; ../dist kdepim
+# if the "dist" step failed
+# (and then ../taritup kdepim for the last step)
+# But if all goes well, "pack" will have done it all.
+
+# You can find the resulting tar.bz2 in sources/, scp it somewhere.
+
+# To make sure that snapshots display a useful version number,
+# change them after release to reflect development status in the branch.
+# ./kmail/kmversion.h:#define KMAIL_VERSION "1.9.6 (enterprise branch after 0.20070227.637543)"
+# ./kontact/src/main.cpp:static const char version[] = "1.2.4 (enterprise branch after 0.20070227.637543)";
+# ./korganizer/version.h:static const char korgVersion[] = "3.5.6 (enterprise branch after 0.20070227.637543)";
diff --git a/translate b/translate
new file mode 100644
index 000000000..0a19b1bf1
--- /dev/null
+++ b/translate
@@ -0,0 +1,83 @@
+#!/bin/sh
+
+# Update this path if necessary
+KDEL10N=$PWD/../kde-l10n
+
+export LC_ALL=C
+export CDPATH=
+
+# Fix up the script
+if ! grep -q Language-Team admin/cvs.sh; then
+ patch admin/cvs.sh < cvs.sh.diff
+fi
+
+test -L po || ( rm -f po ; ln -s ../kde-l10n/templates/messages/kdepim po )
+
+# I tried setting podir to get the output directly into kde-l10n but then
+# we run old code in cvs.sh; scripty doesn't use that anymore, but the scripts in l10n.
+# However those are harder to reduce to kdepim only, so let's keep the old way
+# of doing it: with a po subdir, like a 3rd-party app and not like a real kde module.
+#export podir="$KDEL10N/templates/messages/kdepim"
+if ! test -d "po"; then
+ echo "po doesn't exist"
+ exit 1
+fi
+
+if test -z "$XGETTEXT"; then
+ if test -f /usr/bin/kde-xgettext; then
+ xgettext=kde-xgettext
+ export XGETTEXT=kde-xgettext
+ elif test -f /opt/kde3/bin/kde-xgettext; then
+ xgettext=/opt/kde3/bin/kde-xgettext
+ export XGETTEXT=$xgettext
+ else
+ xgettext=xgettext
+ fi
+else
+ xgettext="$XGETTEXT"
+fi
+gettext_version=`$xgettext --version | grep 0.10.35`
+if test -z "$gettext_version"; then
+ echo "No xgettext installed or wrong xgettext version: "`$xgettext --version | head -n1`
+ exit 1
+fi
+
+kdepim="$PWD"
+
+# I assume kdepim is uptodate, but kde-l10n is probably not
+cd "$KDEL10N" || exit 1
+svn update
+
+cd "$kdepim"
+make -f admin/Makefile.common package-messages || exit 1
+# ? make -f admin/Makefile.common package-merge || exit 1
+
+cd "$KDEL10N" || exit 1
+
+scripts/merge_all.sh
+
+svn diff
+
+for i in `find -name kdepim`; do
+ cd $i || exit 1
+
+ for t in `svn status 2>&1 | grep '^M' | gawk '{print $2}'`; do
+ diff=`diff -u -I'^#' -I'^"POT-Creation-Date:' .svn/text-base/$t.svn-base $t`
+ if test -n "$diff"; then
+ echo "$t: changed"
+ else
+ #echo "$t: no change"
+ svn revert $t
+ fi
+ done
+ # New files are not added automatically; do those by hand.
+
+ # To see what changed in a .pot file: svn di kmail.pot | grep '^[-+][^#]'
+
+ cd "$KDEL10N"
+done
+
+scripts/check_po_files
+
+echo "Now go to $KDEL10N and commit templates/ and de/"
+
diff --git a/wizards/Makefile.am b/wizards/Makefile.am
index 0a211294c..613322330 100644
--- a/wizards/Makefile.am
+++ b/wizards/Makefile.am
@@ -4,22 +4,21 @@ INCLUDES = -I$(top_srcdir)/libkpimidentities -I$(top_srcdir)/libkcal \
-I$(top_srcdir)/kresources/kolab/shared -I$(top_srcdir) \
-I$(top_srcdir)/knotes \
-I$(top_srcdir)/certmanager/lib \
- -I$(top_builddir)/kresources/groupwise \
-I$(top_builddir)/kresources/lib \
-I$(top_srcdir)/kresources/lib \
$(all_includes)
bin_PROGRAMS = groupwarewizard egroupwarewizard sloxwizard kolabwizard \
- groupwisewizard exchangewizard scalixwizard
+ exchangewizard
kde_module_LTLIBRARIES = libegroupwarewizard.la libsloxwizard.la \
- libkolabwizard.la libgroupwisewizard.la \
- libexchangewizard.la libscalixwizard.la
+ libkolabwizard.la \
+ libexchangewizard.la
groupwarewizard_LDFLAGS = $(all_libraries) $(KDE_RPATH)
groupwarewizard_LDADD = libegroupwarewizard.la libsloxwizard.la $(LIB_KDEUI) \
- libkolabwizard.la libgroupwisewizard.la \
+ libkolabwizard.la \
libexchangewizard.la
groupwarewizard_SOURCES = groupwarewizard.cpp main.cpp overviewpage.cpp
@@ -64,22 +63,6 @@ sloxwizard_LDADD = libsloxwizard.la
sloxwizard_LDFLAGS = $(all_libraries) $(KDE_RPATH)
sloxwizard_SOURCES = sloxmain.cpp
-# GroupWise
-libgroupwisewizard_la_LDFLAGS = -avoid-version -no-undefined $(all_libraries)
-libgroupwisewizard_la_SOURCES = groupwisewizard.cpp groupwiseconfig.kcfgc \
- kmailchanges.cpp
-libgroupwisewizard_la_LIBADD = $(top_builddir)/kresources/groupwise/libkcal_groupwise.la \
- $(top_builddir)/kresources/groupwise/libkabc_groupwise.la \
- $(top_builddir)/libkdepim/libkdepim.la \
- $(top_builddir)/libkpimidentities/libkpimidentities.la
-libgroupwisewizard_la_COMPILE_FIRST = $(top_builddir)/kresources/groupwise/kabc_groupwiseprefs.h \
- $(top_builddir)/kresources/groupwise/kcal_groupwiseprefsbase.h
-
-
-groupwisewizard_LDADD = libgroupwisewizard.la
-groupwisewizard_LDFLAGS = $(all_libraries) $(KDE_RPATH)
-groupwisewizard_SOURCES = groupwisemain.cpp
-
# Exchange
libexchangewizard_la_LDFLAGS = -avoid-version -no-undefined $(all_libraries)
libexchangewizard_la_SOURCES = exchangewizard.cpp
@@ -91,25 +74,10 @@ exchangewizard_LDADD = libexchangewizard.la
exchangewizard_LDFLAGS = $(all_libraries) $(KDE_RPATH)
exchangewizard_SOURCES = exchangemain.cpp
-# Scalix
-libscalixwizard_la_LDFLAGS = -avoid-version -no-undefined $(all_libraries)
-libscalixwizard_la_LIBADD = $(top_builddir)/kresources/scalix/kcal/libkcalscalix.la \
- $(top_builddir)/kresources/scalix/kabc/libkabcscalix.la \
- $(top_builddir)/libkcal/libkcal.la \
- $(top_builddir)/libkdepim/libkdepim.la \
- $(top_builddir)/libkpimidentities/libkpimidentities.la
-
-libscalixwizard_la_SOURCES = scalixwizard.cpp kmailchanges.cpp scalixconfig.kcfgc \
- scalixkmailchanges.cpp
-
-scalixwizard_LDADD = libscalixwizard.la $(LIB_KDEUI)
-scalixwizard_LDFLAGS = $(all_libraries) $(KDE_RPATH)
-scalixwizard_SOURCES = scalixmain.cpp
-
noinst_HEADERS = egroupwarewizard.h kmailchanges.h kolabwizard.h sloxwizard.h \
- groupwisewizard.h exchangewizard.h
+ exchangewizard.h
-kde_kcfg_DATA = egroupware.kcfg slox.kcfg kolab.kcfg groupwise.kcfg scalix.kcfg
+kde_kcfg_DATA = egroupware.kcfg slox.kcfg kolab.kcfg
messages: rc.cpp
$(XGETTEXT) *.cpp -o $(podir)/kdepimwizards.pot
diff --git a/wizards/egroupwaremain.cpp b/wizards/egroupwaremain.cpp
index 86777c61d..153c2f83f 100644
--- a/wizards/egroupwaremain.cpp
+++ b/wizards/egroupwaremain.cpp
@@ -50,8 +50,8 @@ int main(int argc,char **argv)
bool verbose = false;
if ( args->isSet( "verbose" ) ) verbose = true;
-
+ args->clear();
EGroupwareWizard wizard;
- wizard.exec();
+ return wizard.exec();
}
diff --git a/wizards/exchangemain.cpp b/wizards/exchangemain.cpp
index 3b68951e5..60d58490b 100644
--- a/wizards/exchangemain.cpp
+++ b/wizards/exchangemain.cpp
@@ -50,8 +50,8 @@ int main(int argc,char **argv)
bool verbose = false;
if ( args->isSet( "verbose" ) ) verbose = true;
-
+ args->clear();
ExchangeWizard wizard;
- wizard.exec();
+ return wizard.exec();
}
diff --git a/wizards/groupwarewizard.desktop b/wizards/groupwarewizard.desktop
index ae84eb980..45fd1956e 100644
--- a/wizards/groupwarewizard.desktop
+++ b/wizards/groupwarewizard.desktop
@@ -22,7 +22,6 @@ Name[hu]=KDE csoportmunka-varázsló
Name[is]=KDE hópvinnukerfisálfur
Name[it]=Assistente configurazione di KDE Groupware
Name[ja]=KDE グループウェアウィザード
-Name[ka]=სერვერი Groupware
Name[kk]=KDE бірікен жұмыс шебері
Name[km]=អ្នក​ជំនួយការ​កម្មវិធី​ពហុ​អ្នក​ប្រើ​របស់ KDE
Name[ko]=KDE 그룹웨어 마법사
diff --git a/wizards/kmailchanges.cpp b/wizards/kmailchanges.cpp
index ca2969a51..79e06f585 100644
--- a/wizards/kmailchanges.cpp
+++ b/wizards/kmailchanges.cpp
@@ -243,10 +243,11 @@ void CreateDisconnectedImapAccount::apply()
c.setGroup( TQString("Folder-%1").arg( uid ) );
c.writeEntry( "isOpen", true );
- if ( mEnableSavePassword ) {
- c.writeEntry( "pass", KStringHandler::obscure( mPassword ) );
- c.writeEntry( "store-passwd", true );
- }
+ c.setGroup( "AccountWizard" );
+ c.writeEntry( "ShowOnStartup" , false );
+
+ c.setGroup( "Composer" );
+ c.writeEntry( "default-transport", mAccountName );
c.setGroup( TQString("Transport %1").arg( transportId ) );
c.writeEntry( "name", mAccountName );
@@ -295,7 +296,7 @@ void CreateDisconnectedImapAccount::apply()
KPIM::Identity& identity = identityManager.newFromScratch( accountName );
identity.setFullName( mRealName );
- identity.setEmailAddr( mEmail );
+ identity.setPrimaryEmailAddress( mEmail );
identityManager.commit();
}
@@ -360,6 +361,11 @@ void CreateOnlineImapAccount::apply()
c.setGroup( TQString("Folder-%1").arg( uid ) );
c.writeEntry( "isOpen", true );
+
+
+ c.setGroup( "AccountWizard" );
+ c.writeEntry( "ShowOnStartup" , false );
+
}
bool CreateImapAccount::writeToWallet(const TQString & type, int id)
diff --git a/wizards/kolabmain.cpp b/wizards/kolabmain.cpp
index 865dd9bdd..1aa817ad5 100644
--- a/wizards/kolabmain.cpp
+++ b/wizards/kolabmain.cpp
@@ -50,8 +50,8 @@ int main(int argc,char **argv)
bool verbose = false;
if ( args->isSet( "verbose" ) ) verbose = true;
-
+ args->clear();
KolabWizard wizard;
- wizard.exec();
+ return wizard.exec();
}
diff --git a/wizards/overviewpage.cpp b/wizards/overviewpage.cpp
index 657a8a0da..2ee90096b 100644
--- a/wizards/overviewpage.cpp
+++ b/wizards/overviewpage.cpp
@@ -35,7 +35,6 @@
#include "egroupwarewizard.h"
#include "kolabwizard.h"
#include "sloxwizard.h"
-#include "groupwisewizard.h"
#include "exchangewizard.h"
#include "overviewpage.h"
@@ -75,26 +74,22 @@ OverViewPage::OverViewPage( TQWidget *parent, const char *name )
layout->addMultiCellWidget( button, 5, 5, 0, 3 );
connect( button, TQT_SIGNAL( clicked() ), TQT_SLOT( showWizardSlox() ) );
- button = new TQPushButton( i18n("Novell GroupWise"), this );
- layout->addMultiCellWidget( button, 6, 6, 0, 3 );
- connect( button, TQT_SIGNAL( clicked() ), TQT_SLOT( showWizardGroupwise() ) );
-
button = new TQPushButton( i18n("Microsoft Exchange"), this );
button->hide(); // not quite ready yet
- layout->addMultiCellWidget( button, 7, 7, 0, 3 );
+ layout->addMultiCellWidget( button, 6, 6, 0, 3 );
connect( button, TQT_SIGNAL( clicked() ), TQT_SLOT( showWizardExchange() ) );
TQFrame *frame = new TQFrame( this );
frame->setFrameStyle( TQFrame::HLine | TQFrame::Sunken );
- layout->addMultiCellWidget( frame, 8, 8, 0, 3 );
+ layout->addMultiCellWidget( frame, 7, 7, 0, 3 );
TQPushButton *cancelButton = new KPushButton( KStdGuiItem::close(), this );
- layout->addWidget( cancelButton, 9, 3 );
+ layout->addWidget( cancelButton, 8, 3 );
connect( cancelButton, TQT_SIGNAL( clicked() ), this, TQT_SIGNAL( cancel() ) );
- layout->setRowStretch( 8, 1 );
+ layout->setRowStretch( 7, 1 );
KAcceleratorManager::manage( this );
}
@@ -121,12 +116,6 @@ void OverViewPage::showWizardSlox()
wizard.exec();
}
-void OverViewPage::showWizardGroupwise()
-{
- GroupwiseWizard wizard;
- wizard.exec();
-}
-
void OverViewPage::showWizardExchange()
{
ExchangeWizard wizard;
diff --git a/wizards/overviewpage.h b/wizards/overviewpage.h
index 1d93e42d3..487b14ce9 100644
--- a/wizards/overviewpage.h
+++ b/wizards/overviewpage.h
@@ -36,7 +36,6 @@ class OverViewPage : public QWidget
void showWizardEGroupware();
void showWizardKolab();
void showWizardSlox();
- void showWizardGroupwise();
void showWizardExchange();
signals: