diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | 460c52653ab0dcca6f19a4f492ed2c5e4e963ab0 (patch) | |
tree | 67208f7c145782a7e90b123b982ca78d88cc2c87 /korganizer | |
download | tdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.tar.gz tdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdepim@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'korganizer')
370 files changed, 63911 insertions, 0 deletions
diff --git a/korganizer/AUTHORS b/korganizer/AUTHORS new file mode 100644 index 000000000..3cbd7aab5 --- /dev/null +++ b/korganizer/AUTHORS @@ -0,0 +1,15 @@ +Some of the people who contributed to KOrganizer: + +Original author: Preston Brown <pbrown@kde.org> + +Current maintainer: Cornelius Schumacher <schumacher@kde.org> + +Additional contributions by: + +Fester Zigterman +Ian Dawes +Christopher Beard +Laszlo Boloni + +...and many other people, who contributed patches, bug reports, comments, +translations, encouragement and more. Thanks a lot! diff --git a/korganizer/COPYING b/korganizer/COPYING new file mode 100644 index 000000000..54754ab4b --- /dev/null +++ b/korganizer/COPYING @@ -0,0 +1,341 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/korganizer/HACKING b/korganizer/HACKING new file mode 100644 index 000000000..a8bfa7a97 --- /dev/null +++ b/korganizer/HACKING @@ -0,0 +1 @@ +See ../libkcal/HACKING diff --git a/korganizer/LICENSE b/korganizer/LICENSE new file mode 100644 index 000000000..f01f77801 --- /dev/null +++ b/korganizer/LICENSE @@ -0,0 +1,63 @@ +KOrganizer licensing policy +--------------------------- + +All files part of KOrganizer are either licensed under the LGPL or under the GPL +with the exception to link against all versions of Qt. + +Interfaces are licensed under the LGPL. These files are in the "interfaces" +subdirectory. + +The "knewstuff" subdirectory is completely licensed under the LGPL as this is +meant to become library code. + +Use the following headers to indicate the license of files belonging to +KOrganizer. Don't forget to add your copyright if appropriate. + +GPL plus Qt exception: + +/* + This file is part of KOrganizer. + + Copyright (c) 2005 xxx <xxx@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +LGPL: + +/* + This file is part of the KOrganizer interfaces. + + Copyright (c) 2005 xxx <xxx@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. +*/ diff --git a/korganizer/Makefile.am b/korganizer/Makefile.am new file mode 100644 index 000000000..aa3399386 --- /dev/null +++ b/korganizer/Makefile.am @@ -0,0 +1,208 @@ +SUBDIRS = printing . korgac pixmaps sounds plugins interfaces + +INCLUDES = \ + -I$(srcdir)/interfaces \ + -I$(top_srcdir)/libemailfunctions \ + -I$(top_srcdir)/libkpimidentities \ + -I$(top_srcdir)/libkholidays \ + -I$(top_srcdir)/mimelib \ + -I$(top_srcdir)/certmanager/lib \ + -I$(top_srcdir)/korganizer/printing \ + -I$(top_srcdir) \ + -I$(top_builddir) \ + $(all_includes) + +bin_PROGRAMS = korganizer + +korganizer_LDFLAGS = $(all_libraries) $(KDE_RPATH) +korganizer_LDADD = libkorganizer.la +korganizer_SOURCES = main.cpp korganizer.cpp koapp.cpp +korganizer_COMPILE_FIRST = koprefs_base.h + + +kde_module_LTLIBRARIES = kcm_korganizer.la libkorganizerpart.la + +kcm_korganizer_la_SOURCES = koprefsdialog.cpp +kcm_korganizer_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined +kcm_korganizer_la_LIBADD = libkorganizer.la $(top_builddir)/libkdepim/libkdepim.la \ + $(LIB_KDECORE) +kcm_korganizer_la_COMPILE_FIRST = koprefs_base.h kogroupwareprefspage.h + +libkorganizerpart_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +libkorganizerpart_la_LIBADD = libkorganizer.la +libkorganizerpart_la_SOURCES = korganizer_part.cpp +libkorganizerpart_la_COMPILE_FIRST = publishdialog_base.h koprefs_base.h + + +check_PROGRAMS = korgplugins timezone + +korgplugins_LDFLAGS = $(all_libraries) $(KDE_RPATH) +korgplugins_LDADD = libkorganizer.la $(LIB_KSYCOCA) +korgplugins_SOURCES = korgplugins.cpp +korgplugins_COMPILE_FIRST = koprefs_base.h + +timezone_LDFLAGS = $(all_libraries) $(KDE_RPATH) +timezone_LDADD = libkorganizer.la $(LIB_KSYCOCA) +timezone_SOURCES = timezone.cpp +timezone_COMPILE_FIRST = koprefs_base.h + +lib_LTLIBRARIES = libkorganizer_eventviewer.la \ + libkorganizer_calendar.la libkorganizer.la + +libkorganizer_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) -version-info 1:0 +libkorganizer_la_LIBADD = \ + $(top_builddir)/libkcal/libkcal.la \ + $(top_builddir)/libkpimidentities/libkpimidentities.la \ + $(top_builddir)/libkdepim/libkdepim.la \ + libkorganizer_eventviewer.la \ + libkorganizer_calendar.la \ + printing/libkocorehelper.la \ + printing/libkorg_stdprinting.la \ + $(top_builddir)/kdgantt/libkdgantt.la \ + $(top_builddir)/libemailfunctions/libemailfunctions.la \ + $(top_builddir)/libkholidays/libkholidays.la \ + $(top_builddir)/libkmime/libkmime.la \ + $(LIB_KPARTS) $(LIB_KFILE) $(LIB_KNEWSTUFF) \ + -lkdeprint -lkabc -lkutils + +libkorganizer_la_COMPILE_FIRST = \ + kogroupwareprefspage.ui \ + $(top_srcdir)/libkdepim/categoryselectdialog.h +libkorganizer_la_SOURCES = komessagebox.cpp \ + koagendaview.cpp koagenda.cpp koagendaitem.cpp \ + datenavigator.cpp kdatenavigator.cpp datenavigatorcontainer.cpp \ + datechecker.cpp \ + komonthview.cpp \ + searchdialog.cpp calendarview.cpp koviewmanager.cpp \ + kodialogmanager.cpp \ + archivedialog.cpp \ + kohelper.cpp \ + komailclient.cpp kotodoview.cpp kotodoviewitem.cpp \ + kolistview.cpp \ + koincidenceeditor.cpp koeventeditor.cpp kotodoeditor.cpp kojournaleditor.cpp\ + koprefs.cpp kowindowlist.cpp \ + koeditorgeneral.cpp \ + koeditorgeneralevent.cpp koeditorgeneraltodo.cpp koeditorgeneraljournal.cpp \ + koeditordetails.cpp koeditoralarms_base.ui koeditoralarms.cpp \ + koeditorrecurrence.cpp koeditorattachments.cpp \ + kogroupwareprefspage.ui koeventpopupmenu.cpp koeditorfreebusy.cpp \ + publishdialog_base.ui publishdialog.cpp \ + koeventview.cpp \ + korganizeriface.skel kcalendariface.skel \ + filtereditdialog.cpp filteredit_base.ui \ + kowhatsnextview.cpp kocounterdialog.cpp \ + kojournalview.cpp journalentry.cpp \ + kocore.cpp mailscheduler.cpp \ + kodaymatrix.cpp docprefs.cpp statusdialog.cpp\ + koglobals.cpp konewstuff.cpp \ + actionmanager.cpp resourceview.cpp \ + navigatorbar.cpp kogroupware.cpp \ + history.cpp \ + koprefs_base.kcfgc \ + koincidencetooltip.cpp aboutdata.cpp \ + importdialog.cpp \ + korganizerifaceimpl.cpp \ + freebusymanager.cpp freebusyurldialog.cpp \ + eventarchiver.cpp koidentitymanager.cpp \ + exportwebdialog.cpp kocorehelper.cpp incidencechanger.cpp \ + template_management_dialog_base.ui templatemanagementdialog.cpp \ + agendaview.cpp multiagendaview.cpp \ + timelineitem.cpp \ + kotimelineview.cpp \ + koattendeeeditor.cpp \ + timelabels.cpp + + +libkorganizer_eventviewer_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) \ + -no-undefined -version-info 1:0 +libkorganizer_eventviewer_la_LIBADD = $(LIB_KPARTS) \ + $(top_builddir)/libkcal/libkcal.la +libkorganizer_eventviewer_la_SOURCES = koeventviewer.cpp urihandler.cpp \ + kmailIface.stub koeventviewerdialog.cpp + +libkorganizer_calendar_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) \ + -no-undefined -version-info 1:0 +libkorganizer_calendar_la_LIBADD = $(LIB_KPARTS) \ + $(top_builddir)/libkdepim/libkdepim.la \ + $(top_builddir)/libkcal/libkcal.la +libkorganizer_calendar_la_SOURCES = stdcalendar.cpp + + +kmailIface_DIR = $(top_srcdir)/kmail +kmailIface_DCOPIDLNG = true + +METASOURCES = AUTO + +noinst_HEADERS = komonthview.h \ + koagendaview.h koagenda.h \ + koagendaitem.h \ + kdatenavigator.h \ + calendarview.h \ + version.h \ + searchdialog.h \ + archivedialog.h \ + komailclient.h kotodoview.h \ + kolistview.h \ + koapp.h korganizer_part.h korganizer.h \ + koprefsdialog.h koeventeditor.h \ + kotodoeditor.h koprefs.h koeventviewer.h \ + kowindowlist.h kocounterdialog.h \ + koeditorgeneralevent.h koeditorgeneraltodo.h koeditordetails.h \ + koeditorrecurrence.h koeventviewerdialog.h koeventpopupmenu.h \ + publishdialog.h koeditorfreebusy.h \ + koeventview.h statusdialog.h customlistviewitem.h \ + kohelper.h \ + navigatorbar.h kogroupware.h \ + koincidencetooltip.h korganizerifaceimpl.h \ + exportwebdialog.h templatemanagementdialog.h + +tip_DATA = tips +tipdir = $(kde_datadir)/korganizer + +kde_bin_SCRIPTS = ical2vcal + +rcdir = $(kde_datadir)/korganizer +rc_DATA = korganizerui.rc + +partdir = $(kde_datadir)/korganizer +part_DATA = korganizer_part.rc + +kde_servicetypes_DATA = dcopcalendar.desktop + +KDE_ICON = AUTO + +META_INCLUDES = $(srcdir)/interfaces/korganizer + +messages: rc.cpp + $(PREPARETIPS) > tips.cpp + $(EXTRACTRC) `find . -name "*.rc" -o -name "*.ui" -o -name "*.kcfg"` >> rc.cpp + $(XGETTEXT) `find . -name "*.cpp" -o -name "*.h"` -o $(podir)/korganizer.pot + rm -f tips.cpp + +xdg_apps_DATA = korganizer.desktop + +kde_kcfg_DATA = korganizer.kcfg + +kde_services_DATA = korganizer_configmain.desktop \ + korganizer_configtime.desktop \ + korganizer_configviews.desktop \ + korganizer_configcolors.desktop \ + korganizer_configfonts.desktop \ + korganizer_configplugins.desktop \ + korganizer_configgroupscheduling.desktop \ + korganizer_configfreebusy.desktop \ + korganizer_configdesignerfields.desktop \ + webcal.protocol + +update_DATA = korganizer.upd +updatedir = $(kde_datadir)/kconf_update + +DOXYGEN_REFERENCES=libkcal kdeui +include $(top_srcdir)/admin/Doxyfile.am + +install-data-local: + $(mkinstalldirs) $(DESTDIR)$(kde_servicesdir) + $(mkinstalldirs) $(DESTDIR)$(kde_servicesdir)/korganizer + $(INSTALL_DATA) $(srcdir)/uninstall.desktop $(DESTDIR)$(kde_servicesdir)/korganizer_configgroupautomation.desktop + $(INSTALL_DATA) $(srcdir)/uninstall.desktop $(DESTDIR)$(kde_servicesdir)/korganizer/webexport.desktop + $(INSTALL_DATA) $(srcdir)/uninstall.desktop $(DESTDIR)$(kde_servicesdir)/korganizer/holidays.desktop diff --git a/korganizer/README b/korganizer/README new file mode 100644 index 000000000..07453be9b --- /dev/null +++ b/korganizer/README @@ -0,0 +1,280 @@ + +-----------------------+ + | K O R G A N I Z E R | + +-----------------------+ + + version 3.3 pre + + http://korganizer.kde.org + +Next release: KDEPIM-3.3 (something like May 2004) + +QUICK NOTES ON WHAT'S NEW IN THE DIFFERENT VERSIONS: + +* Official 3.2 release (January 2004) + + - New Features: + - Support for multiple calendars and todo lists. Korganizer can now + transparently merge calendar data from different files or other calendar + data sources for example calendars on the web. They can conveniently + activated, deactivated, added and removed from the graphical user + interface. + - Kontact integration. KOrganizer now is fully integrated with Kontact, the + complete KDE personal information management application. Within Kontact + some additional features are available like conversion of mails to events + or todos by drag and drop. + - New storage model: The notion of an active calendar was replaced by a + persistant calendar. The user doesn't have to take care of loading or + saving the calendar. Changes are immediately saved to disk. If the + calendar is changed externally it is automatically loaded and updated in + the view. A locking mechansim handles concurrent access to the calendar. + - Undo and Redo. KOrganizer now supports unlimited undo and redo. + - Todo integration with agenda view. Todos are shown in the week and day + views. Todos can be converted to events by dragging from the todo list and + dropping on the agenda view. + - Attachements for events and todos. References to web pages, local files or + mails can be attached to events and todos. The attached data can easily be + accessed by a single click from the event and todo views as well as the + summary view or the editors. + - Quick todo entry. A special input field allows to quickly create a todo + without needing to open an editor. This is especially handy for creating + multiple todos in a row. + - Quick event entry. There are several new ways to create events from the + agenda view: Per type-ahead events can be created by selecting a time + range and then simply starting to type. An editor will be opened and the + type text will be go into the summary input line. Optionally the event + editor can be opened when the time selection is finished and in addition + to the usual menu and toolbar entries there are key bindings and a context + menu to start the editor dialog. + - Plugin for Jewish calendar dates. When enabled this plugin shows the + Jewish calendar dates for each day in the calendar view. + - Improved print support. The print dialogs were rewritten. Printing now + supports colors and overlapping events. + + - User interface polishing. The visual appearance of KOrganizer was improved + by a rewrite of the agenda view rendering and other enhancements like the + text fade-out when there isn't enough space to display the full text or the + graphical display of the completion state of todos. Many usability + improvements were incoreporated, like support for moving multi-day events in + the agenda view by dragging with the mouse, more complete and consistent key + bindings and context menus, better menu structure and more concise texts. + Some of these improvements were stimulated by external usability studies. + + - Bug fixes. Countless bug fixes went into this version, one of them being a + fix for the session management which closes the, according to Bugzilla, most + hated bug of KOrganizer 3.1. + + - Better performance. The speed of calendar loading and saving was + significantly improved and memory consumption of calendars was decreased. + + - Architecture and framework: + - KOrganizer makes use of the KDE resource framework KResources which + provides uniform management of calendar, addressbook and similar + resources including generic ways to handle locking and change + notification. This also provides a plugin interface for adding resources + which makes it possible to easily extend Korganizer for example to access + groupware servers or other ways to store calendar data. + - KOrganizer configuration is now based on KConfig XT. That means that + there is an abstract XML based description of the configuration which is + used for generating the needed code to access the configuration data and + serves as base for external configuration tools. + - Simplification of alarm daemon. KOrganizer doesn't use kalarmd anymore, + it only needs the korgac daemon which also rpovides the system tray icon + for being able to notify about alarms. Run control of the alarm daemon + also was simplified, it's now all done by the context menu of the system + tray icon and doesn't need the control center anymore. + - The configuration dialog is now based on kcontrol modules. This is a + prerequisite for integrating the configuration within Kontact. + - KMail now directly supports transfer of invitations and other calendar + attachments to KOrganizer. This supercedes the korganizerIn script + solution. + - Accessing the calendar from the command line is now exclusively handled + by a native command line application, konsolekalendar. + + +* Official 3.1 release (January 2003) + + - General: + - User-definable templates for events and todos. + - Alarms for todos. + - Automatic HTML export on save of calendar file. + - Time table print view. + - New "location" attribute for events. + - Experimental "Get Hot New Stuff" button for downloading and uploading + calendar files of common interest. + + - Views: + - New "Next 3 days" view. + - Selection of time span for a new event in day and week views. + - Direct manipulation of priority, completion status and categories of todos + by context menus. + - Deletion of individual instances of recurring events. + - Rewritten month view. + - Coloring of events in month view based on categories. + - Coloring of due and overdue todos. + - Improved "What's Next" view. + - Configurable cell height in week and day views + + - Group scheduling: + - iMIP group scheduling functions for todos. + - Publishing of Free/Busy information by iMIP conformant email. + - Improved automatisation of group scheduling. + + - Interoperability and integration + - Support for "webcal" URLs in Konqueror. + - Support for iCalendar based drag&drop. + - KOrganizer now shares the dialogs for categories with KAddressBook. + - Improved iCalendar conformance. + - Improved right-to-left languages support. + - Bug fixes for non-latin1 encodings. + + - Plugins: + - New plugin for importing birthdays from The KDE address book. + - New plugin for accessing calendar data on an Exchange server. + +* Official 3.0.3 release (August 2002) + + - Fixed problem caused by Qt 3.0.5 that made context menus in todo and list + view inaccessible. + +* Official 3.0.2 release (June 2002) + + - Bug fixes + - Respect secrecy setting in HTML export also in non-english languages. + - Insert page breaks in todo printouts when necessary. + +* Official 3.0.1 release (May 2002) + + - Lots of bug fixes including fixes to two major bugs: + - Fixed time shift problem which occurred sometimes when saving a calendar. + - Fixed memory leaks in loading and saving the calendar + +* Official 3.0 release (March 2002) + + - Bug fixes + +* Beta Release 3.0beta2 (Februrary 2002) + + - More group scheduling fixes + - Other bug fixes + +* Beta Release 3.0beta1 (December 2001) + + - Group scheduling fixes + +* Alpha Release 3.0alpha1 (October 2001) + + - Group scheduling + - Plugin interface + - Marcus Bain line + - Full port to Qt3/KDE3 + - Major code cleanup + +* Official 2.2 release (August 2001) + + - Bug fixes + +* Beta Release 2.2beta1 (June 2001) + + - Drag&Drop of attendees from kaddressbook to korganizer + +* Alpha Release 2.2alpha2 (May 2001) + + - Active remote calendar + - Sending events via KMail + - Tip of the Day + - "Percent completed" setting for todos + - Bug fixes + +* Alpha 1 release of version 2.2 (April 2001) + + This release is mainly to try out some new technologies and get some + feedback after major reorganisation of the code. + + What's new: + - Switch to iCalendar as default file format + - "What's next" view + - Journal feature + - Project view + - HTML export of month view + +* Official 2.1 release (February 2001) + + - Highlighting of working hours + - Todo and Month View can now use the full window + - ScrollBars of month view cells can now be turned off + - Better support for non-ascii charsets + +* Official 2.0 release (October 2000) + + - No more bugs to fix (sigh, I'm dreaming) + +* Beta-Release 1.94 (September 2000) + + - Even more bug fixes + +* Beta-Release 1.93 (August 2000) + + - More bug fixes + +* Beta-Release 1.92 (July 2000) + + - A couple of bug fixes + +* Beta-Release 1.91 (June 2000) + + - Full integration in KDE 2 framework + - Improved Todo-View (hierarchical todos, drag and drop, ...) + - Web Page Export + - Improved Agenda View (colored events, parallel events, ...) + - Many, many other improvements and bug fixes + +* Official 1.0 release (February 1999) + +INTRODUCTION: + +KOrganizer aims to be a complete program for organizing your +appointments, contacts, projects, etc. It is in the same spirit as +similar programs like the now ubiquitous Microsoft Outlook, Starfish +Internet Sidekick, Time & Chaos, etc. (all for the Microsoft Windows +platform, of course.) Best of all, It reads and writes the vCalendar +file format NATIVELY (please see http://www.imc.org/pdi for more +information), which is now an industry-wide personal data interchange +format. Because of this, you should be able to move from other modern +PIMs to KOrganizer with relative ease. Current users of the popular +program ical should definitely take a look at KOrganizer and compare +features. + +KOrganizer also offers full synchronization with your Palm Pilot, if you +have kpilot installed. + +To install KOrganizer, please read the file INSTALL. The process is +analogous to other KDE applications. + +Documentation is available online from the Help->Contents menu option. +While it is not complete and has not been updated in several months, +it is at least partially helpful. Anyone wishing to help on completing +or enhancing the documentation should contact me directly at the email +address given at the end of this document. + +BUGS: + +Bugs can be reported to the KDE bug tracking system (http://bugs.kde.org). +There you can also get information about the status of older bugs. +KOrganizer, as most other KDE 2 programs, offers a menu item "Report Bug" +in the Help menu for convenient reporting of bugs or feature requests. + +NEWS and TODO: + +Have a look at the KOrganizer homepage (http://korganizer.kde.org). +There you find news and a todo list for future KOrganizer development (of +course generated with KOrganizer itself). + +CONTACT INFORMATION: + +We want your suggestions and comments! + +Please mail them to the maintainer of KOrganizer: + +Cornelius Schumacher (schumacher@kde.org) + +I always welcome contributions and new members for the team. diff --git a/korganizer/aboutdata.cpp b/korganizer/aboutdata.cpp new file mode 100644 index 000000000..d2a5de359 --- /dev/null +++ b/korganizer/aboutdata.cpp @@ -0,0 +1,75 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "aboutdata.h" + +#include "version.h" + +using namespace KOrg; + +AboutData::AboutData() + : KAboutData( "korganizer", I18N_NOOP("KOrganizer"), korgVersion, + I18N_NOOP("A Personal Organizer for KDE"), + KAboutData::License_GPL, + "(c) 1997-1999 Preston Brown\n" + "(c) 2000-2004 Cornelius Schumacher\n" + "(c) 2004-2005 Reinhold Kainhofer", 0, + "http://korganizer.kde.org" ) +{ + addAuthor("Reinhold Kainhofer",I18N_NOOP("Current Maintainer"), + "reinhold@kainhofer.com"); + addAuthor("Cornelius Schumacher",I18N_NOOP("Co-Maintainer"), + "schumacher@kde.org"); + addAuthor("Preston Brown",I18N_NOOP("Original Author"), + "pbrown@kde.org"); + addCredit("Richard Apodaca"); + addCredit("Jan-Pascal van Best"); + addCredit("Laszlo Boloni"); + addCredit("Barry Benowitz"); + addCredit("Christopher Beard"); + addCredit("Ian Dawes"); + addCredit("Thomas Eitzenberger"); + addCredit("Neil Hart"); + addCredit("Declan Houlihan"); + addCredit("Hans-Jürgen Husel"); + addCredit("Tim Jansen"); + addCredit("Christian Kirsch"); + addCredit("Tobias König"); + addCredit("Martin Koller"); + addCredit("Uwe Koloska"); + addCredit("Glen Parker"); + addCredit("Dan Pilone"); + addCredit("Roman Rohr"); + addCredit("Don Sanders"); + addCredit("Bram Schoenmakers"); + addCredit("Günter Schwann"); + addCredit("Herwin Jan Steehouwer"); + addCredit("Mario Teijeiro"); + addCredit("Nick Thompson"); + addCredit("Bo Thorsen"); + addCredit("Allen Winter"); + addCredit("Larry Wright"); + addCredit("Thomas Zander"); + addCredit("Fester Zigterman"); +} diff --git a/korganizer/aboutdata.h b/korganizer/aboutdata.h new file mode 100644 index 000000000..7edfc6150 --- /dev/null +++ b/korganizer/aboutdata.h @@ -0,0 +1,40 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KORG_ABOUTDATA_H +#define KORG_ABOUTDATA_H + +#include <kaboutdata.h> +#include <kdepimmacros.h> + +namespace KOrg { + +class KDE_EXPORT AboutData : public KAboutData +{ + public: + AboutData(); +}; + +} + +#endif diff --git a/korganizer/actionmanager.cpp b/korganizer/actionmanager.cpp new file mode 100644 index 000000000..4a900abd3 --- /dev/null +++ b/korganizer/actionmanager.cpp @@ -0,0 +1,1956 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2002 Mike Pilone <mpilone@slac.com> + Copyright (c) 2002 Don Sanders <sanders@kde.org> + Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "actionmanager.h" + +#include "alarmclient.h" +#include "calendarview.h" +#include "kocore.h" +#include "kodialogmanager.h" +#include "koglobals.h" +#include "koprefs.h" +#include "koviewmanager.h" +#include "kowindowlist.h" +#include "kprocess.h" +#include "konewstuff.h" +#include "history.h" +#include "kogroupware.h" +#include "resourceview.h" +#include "importdialog.h" +#include "eventarchiver.h" +#include "stdcalendar.h" +#include "freebusymanager.h" + +#include <libkcal/calendarlocal.h> +#include <libkcal/calendarresources.h> +#include <libkcal/htmlexport.h> +#include <libkcal/htmlexportsettings.h> + +#include <libkmime/kmime_message.h> + +#include <dcopclient.h> +#include <kaction.h> +#include <kfiledialog.h> +#include <kiconloader.h> +#include <kio/netaccess.h> +#include <kkeydialog.h> +#include <kpopupmenu.h> +#include <kstandarddirs.h> +#include <ktip.h> +#include <ktempfile.h> +#include <kxmlguiclient.h> +#include <kwin.h> +#include <knotifyclient.h> +#include <kstdguiitem.h> +#include <kdeversion.h> +#include <kactionclasses.h> + +#include <qapplication.h> +#include <qcursor.h> +#include <qtimer.h> +#include <qlabel.h> + + +// FIXME: Several places in the file don't use KConfigXT yet! +KOWindowList *ActionManager::mWindowList = 0; + +ActionManager::ActionManager( KXMLGUIClient *client, CalendarView *widget, + QObject *parent, KOrg::MainWindow *mainWindow, + bool isPart ) + : QObject( parent ), KCalendarIface(), mRecent( 0 ), + mResourceButtonsAction( 0 ), mResourceViewShowAction( 0 ), mCalendar( 0 ), + mCalendarResources( 0 ), mResourceView( 0 ), mIsClosing( false ) +{ + mGUIClient = client; + mACollection = mGUIClient->actionCollection(); + mCalendarView = widget; + mIsPart = isPart; + mTempFile = 0; + mNewStuff = 0; + mHtmlExportSync = false; + mMainWindow = mainWindow; +} + +ActionManager::~ActionManager() +{ + delete mNewStuff; + + // Remove Part plugins + KOCore::self()->unloadParts( mMainWindow, mParts ); + + delete mTempFile; + + // Take this window out of the window list. + mWindowList->removeWindow( mMainWindow ); + + delete mCalendarView; + + delete mCalendar; + + kdDebug(5850) << "~ActionManager() done" << endl; +} + +// see the Note: below for why this method is necessary +void ActionManager::init() +{ + // Construct the groupware object + KOGroupware::create( mCalendarView, mCalendarResources ); + + // add this instance of the window to the static list. + if ( !mWindowList ) { + mWindowList = new KOWindowList; + // Show tip of the day, when the first calendar is shown. + if ( !mIsPart ) + QTimer::singleShot( 0, this, SLOT( showTipOnStart() ) ); + } + // Note: We need this ActionManager to be fully constructed, and + // parent() to have a valid reference to it before the following + // addWindow is called. + mWindowList->addWindow( mMainWindow ); + + initActions(); + + // set up autoSaving stuff + mAutoSaveTimer = new QTimer( this ); + connect( mAutoSaveTimer,SIGNAL( timeout() ), SLOT( checkAutoSave() ) ); + if ( KOPrefs::instance()->mAutoSave && + KOPrefs::instance()->mAutoSaveInterval > 0 ) { + mAutoSaveTimer->start( 1000 * 60 * KOPrefs::instance()->mAutoSaveInterval ); + } + + mAutoArchiveTimer = new QTimer( this ); + connect( mAutoArchiveTimer, SIGNAL( timeout() ), SLOT( slotAutoArchive() ) ); + // First auto-archive should be in 5 minutes (like in kmail). + if ( KOPrefs::instance()->mAutoArchive ) + mAutoArchiveTimer->start( 5 * 60 * 1000, true ); // singleshot + + setTitle(); + + connect( mCalendarView, SIGNAL( modifiedChanged( bool ) ), SLOT( setTitle() ) ); + connect( mCalendarView, SIGNAL( configChanged() ), SLOT( updateConfig() ) ); + + connect( mCalendarView, SIGNAL( incidenceSelected( Incidence * ) ), + this, SLOT( processIncidenceSelection( Incidence * ) ) ); + connect( mCalendarView, SIGNAL( exportHTML( HTMLExportSettings * ) ), + this, SLOT( exportHTML( HTMLExportSettings * ) ) ); + + processIncidenceSelection( 0 ); + + // Update state of paste action + mCalendarView->checkClipboard(); +} + +void ActionManager::createCalendarLocal() +{ + mCalendar = new CalendarLocal( KOPrefs::instance()->mTimeZoneId ); + mCalendarView->setCalendar( mCalendar ); + mCalendarView->readSettings(); + + initCalendar( mCalendar ); +} + +void ActionManager::createCalendarResources() +{ + mCalendarResources = KOrg::StdCalendar::self(); + + CalendarResourceManager *manager = mCalendarResources->resourceManager(); + + kdDebug(5850) << "CalendarResources used by KOrganizer:" << endl; + CalendarResourceManager::Iterator it; + for( it = manager->begin(); it != manager->end(); ++it ) { + kdDebug(5850) << " " << (*it)->resourceName() << endl; + (*it)->setResolveConflict( true ); +// (*it)->dump(); + } + + setDestinationPolicy(); + + mCalendarView->setCalendar( mCalendarResources ); + mCalendarView->readSettings(); + + ResourceViewFactory factory( mCalendarResources, mCalendarView ); + mCalendarView->addExtension( &factory ); + mResourceView = factory.resourceView(); + + connect( mCalendarResources, SIGNAL( calendarChanged() ), + mCalendarView, SLOT( slotCalendarChanged() ) ); + connect( mCalendarResources, SIGNAL( signalErrorMessage( const QString & ) ), + mCalendarView, SLOT( showErrorMessage( const QString & ) ) ); + + connect( mCalendarView, SIGNAL( configChanged() ), + SLOT( updateConfig() ) ); + + initCalendar( mCalendarResources ); +} + +void ActionManager::initCalendar( Calendar *cal ) +{ + cal->setOwner( Person( KOPrefs::instance()->fullName(), + KOPrefs::instance()->email() ) ); + // setting fullName and email do not really count as modifying the calendar + mCalendarView->setModified( false ); +} + +void ActionManager::initActions() +{ + KAction *action; + + + //*************************** FILE MENU ********************************** + + //~~~~~~~~~~~~~~~~~~~~~~~ LOADING / SAVING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + if ( mIsPart ) { + if ( mMainWindow->hasDocument() ) { + KStdAction::openNew( this, SLOT(file_new()), mACollection, "korganizer_openNew" ); + KStdAction::open( this, SLOT( file_open() ), mACollection, "korganizer_open" ); + mRecent = KStdAction::openRecent( this, SLOT( file_open( const KURL& ) ), + mACollection, "korganizer_openRecent" ); + KStdAction::revert( this,SLOT( file_revert() ), mACollection, "korganizer_revert" ); + KStdAction::saveAs( this, SLOT( file_saveas() ), mACollection, + "korganizer_saveAs" ); + KStdAction::save( this, SLOT( file_save() ), mACollection, "korganizer_save" ); + } + KStdAction::print( mCalendarView, SLOT( print() ), mACollection, "korganizer_print" ); + } else { + KStdAction::openNew( this, SLOT( file_new() ), mACollection ); + KStdAction::open( this, SLOT( file_open() ), mACollection ); + mRecent = KStdAction::openRecent( this, SLOT( file_open( const KURL& ) ), + mACollection ); + if ( mMainWindow->hasDocument() ) { + KStdAction::revert( this,SLOT( file_revert() ), mACollection ); + KStdAction::save( this, SLOT( file_save() ), mACollection ); + KStdAction::saveAs( this, SLOT( file_saveas() ), mACollection ); + } + KStdAction::print( mCalendarView, SLOT( print() ), mACollection ); + } + + + //~~~~~~~~~~~~~~~~~~~~~~~~ IMPORT / EXPORT ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + new KAction( i18n("Import &Calendar..."), 0, this, SLOT( file_merge() ), + mACollection, "import_icalendar" ); + new KAction( i18n("&Import From UNIX Ical tool"), 0, this, SLOT( file_icalimport() ), + mACollection, "import_ical" ); + new KAction( i18n("Get &Hot New Stuff..."), 0, this, + SLOT( downloadNewStuff() ), mACollection, + "downloadnewstuff" ); + + new KAction( i18n("Export &Web Page..."), "webexport", 0, + mCalendarView, SLOT( exportWeb() ), + mACollection, "export_web" ); + new KAction( i18n("&iCalendar..."), 0, + mCalendarView, SLOT( exportICalendar() ), + mACollection, "export_icalendar" ); + new KAction( i18n("&vCalendar..."), 0, + mCalendarView, SLOT( exportVCalendar() ), + mACollection, "export_vcalendar" ); + new KAction( i18n("Upload &Hot New Stuff..."), 0, this, + SLOT( uploadNewStuff() ), mACollection, + "uploadnewstuff" ); + + + + new KAction( i18n("Archive O&ld Entries..."), 0, this, SLOT( file_archive() ), + mACollection, "file_archive" ); + new KAction( i18n("delete completed to-dos", "Pur&ge Completed To-dos"), 0, + mCalendarView, SLOT( purgeCompleted() ), mACollection, + "purge_completed" ); + + + + + //************************** EDIT MENU ********************************* + KAction *pasteAction; + KOrg::History *h = mCalendarView->history(); + if ( mIsPart ) { + // edit menu + mCutAction = KStdAction::cut( mCalendarView, SLOT( edit_cut() ), + mACollection, "korganizer_cut" ); + mCopyAction = KStdAction::copy( mCalendarView, SLOT( edit_copy() ), + mACollection, "korganizer_copy" ); + pasteAction = KStdAction::paste( mCalendarView, SLOT( edit_paste() ), + mACollection, "korganizer_paste" ); + mUndoAction = KStdAction::undo( h, SLOT( undo() ), + mACollection, "korganizer_undo" ); + mRedoAction = KStdAction::redo( h, SLOT( redo() ), + mACollection, "korganizer_redo" ); + } else { + mCutAction = KStdAction::cut( mCalendarView,SLOT( edit_cut() ), + mACollection ); + mCopyAction = KStdAction::copy( mCalendarView,SLOT( edit_copy() ), + mACollection ); + pasteAction = KStdAction::paste( mCalendarView,SLOT( edit_paste() ), + mACollection ); + mUndoAction = KStdAction::undo( h, SLOT( undo() ), mACollection ); + mRedoAction = KStdAction::redo( h, SLOT( redo() ), mACollection ); + } + mDeleteAction = new KAction( i18n("&Delete"), "editdelete", 0, + mCalendarView, SLOT( appointment_delete() ), + mACollection, "edit_delete" ); + if ( mIsPart ) { + KStdAction::find( mCalendarView->dialogManager(), SLOT( showSearchDialog() ), + mACollection, "korganizer_find" ); + } else { + KStdAction::find( mCalendarView->dialogManager(), SLOT( showSearchDialog() ), + mACollection ); + } + pasteAction->setEnabled( false ); + mUndoAction->setEnabled( false ); + mRedoAction->setEnabled( false ); + connect( mCalendarView, SIGNAL( pasteEnabled( bool ) ), + pasteAction, SLOT( setEnabled( bool ) ) ); + connect( h, SIGNAL( undoAvailable( const QString & ) ), + SLOT( updateUndoAction( const QString & ) ) ); + connect( h, SIGNAL( redoAvailable( const QString & ) ), + SLOT( updateRedoAction( const QString & ) ) ); + + + + + //************************** VIEW MENU ********************************* + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ VIEWS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + new KAction( i18n("What's &Next"), + KOGlobals::self()->smallIcon( "whatsnext" ), 0, + mCalendarView->viewManager(), SLOT( showWhatsNextView() ), + mACollection, "view_whatsnext" ); + new KAction( i18n("&Day"), + KOGlobals::self()->smallIcon( "1day" ), 0, + mCalendarView->viewManager(), SLOT( showDayView() ), + mACollection, "view_day" ); + mNextXDays = new KAction( "", + KOGlobals::self()->smallIcon( "xdays" ), 0, + mCalendarView->viewManager(), + SLOT( showNextXView() ), + mACollection, "view_nextx" ); + mNextXDays->setText( i18n( "&Next Day", "Ne&xt %n Days", + KOPrefs::instance()->mNextXDays ) ); + new KAction( i18n("W&ork Week"), + KOGlobals::self()->smallIcon( "5days" ), 0, + mCalendarView->viewManager(), SLOT( showWorkWeekView() ), + mACollection, "view_workweek" ); + new KAction( i18n("&Week"), + KOGlobals::self()->smallIcon( "7days" ), 0, + mCalendarView->viewManager(), SLOT( showWeekView() ), + mACollection, "view_week" ); + new KAction( i18n("&Month"), + KOGlobals::self()->smallIcon( "month" ), 0, + mCalendarView->viewManager(), SLOT( showMonthView() ), + mACollection, "view_month" ); + new KAction( i18n("&List"), + KOGlobals::self()->smallIcon( "list" ), 0, + mCalendarView->viewManager(), SLOT( showListView() ), + mACollection, "view_list" ); + new KAction( i18n("&To-do List"), + KOGlobals::self()->smallIcon( "todo" ), 0, + mCalendarView->viewManager(), SLOT( showTodoView() ), + mACollection, "view_todo" ); + new KAction( i18n("&Journal"), + KOGlobals::self()->smallIcon( "journal" ), 0, + mCalendarView->viewManager(), SLOT( showJournalView() ), + mACollection, "view_journal" ); + new KAction( i18n("&Timeline View"), + KOGlobals::self()->smallIcon( "timeline" ), 0, + mCalendarView->viewManager(), SLOT( showTimelineView() ), + mACollection, "view_timeline" ); + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~ FILTERS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + new KAction( i18n("&Refresh"), 0, + mCalendarView, SLOT( updateView() ), + mACollection, "update" ); +// TODO: +// new KAction( i18n("Hide &Completed To-dos"), 0, +// mCalendarView, SLOT( toggleHideCompleted() ), +// mACollection, "hide_completed_todos" ); + + mFilterAction = new KSelectAction( i18n("F&ilter"), 0, + mACollection, "filter_select" ); + mFilterAction->setEditable( false ); + connect( mFilterAction, SIGNAL( activated(int) ), + mCalendarView, SLOT( filterActivated( int ) ) ); + connect( mCalendarView, SIGNAL( newFilterListSignal( const QStringList & ) ), + mFilterAction, SLOT( setItems( const QStringList & ) ) ); + connect( mCalendarView, SIGNAL( selectFilterSignal( int ) ), + mFilterAction, SLOT( setCurrentItem( int ) ) ); + connect( mCalendarView, SIGNAL( filterChanged() ), + this, SLOT( setTitle() ) ); + + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ZOOM ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // TODO: try to find / create better icons for the following 4 actions + new KAction( i18n( "Zoom In Horizontally" ), "viewmag+", 0, + mCalendarView->viewManager(), SLOT( zoomInHorizontally() ), + mACollection, "zoom_in_horizontally" ); + new KAction( i18n( "Zoom Out Horizontally" ), "viewmag-", 0, + mCalendarView->viewManager(), SLOT( zoomOutHorizontally() ), + mACollection, "zoom_out_horizontally" ); + new KAction( i18n( "Zoom In Vertically" ), "viewmag+", 0, + mCalendarView->viewManager(), SLOT( zoomInVertically() ), + mACollection, "zoom_in_vertically" ); + new KAction( i18n( "Zoom Out Vertically" ), "viewmag-", 0, + mCalendarView->viewManager(), SLOT( zoomOutVertically() ), + mACollection, "zoom_out_vertically" ); + + + + + //************************** Actions MENU ********************************* + + new KAction( i18n("Go to &Today"), "today", 0, + mCalendarView,SLOT( goToday() ), + mACollection, "go_today" ); + bool isRTL = QApplication::reverseLayout(); + action = new KAction( i18n("Go &Backward"), isRTL ? "forward" : "back", 0, + mCalendarView,SLOT( goPrevious() ), + mACollection, "go_previous" ); + + // Changing the action text by setText makes the toolbar button disappear. + // This has to be fixed first, before the connects below can be reenabled. + /* + connect( mCalendarView, SIGNAL( changeNavStringPrev( const QString & ) ), + action, SLOT( setText( const QString & ) ) ); + connect( mCalendarView, SIGNAL( changeNavStringPrev( const QString & ) ), + this, SLOT( dumpText( const QString & ) ) );*/ + + action = new KAction( i18n("Go &Forward"), isRTL ? "back" : "forward", 0, + mCalendarView,SLOT( goNext() ), + mACollection, "go_next" ); + /* + connect( mCalendarView,SIGNAL( changeNavStringNext( const QString & ) ), + action,SLOT( setText( const QString & ) ) ); + */ + + + //************************** Actions MENU ********************************* + new KAction( i18n("New E&vent..."), + KOGlobals::self()->smallIcon( "newappointment" ), 0, + mCalendarView, SLOT( newEvent() ), + mACollection, "new_event" ); + new KAction( i18n("New &To-do..."), + KOGlobals::self()->smallIcon( "newtodo" ), 0, + mCalendarView, SLOT( newTodo() ), + mACollection, "new_todo" ); + action = new KAction( i18n("New Su&b-to-do..."), 0, + mCalendarView,SLOT( newSubTodo() ), + mACollection, "new_subtodo" ); + action->setEnabled( false ); + connect( mCalendarView,SIGNAL( todoSelected( bool ) ), + action,SLOT( setEnabled( bool ) ) ); + new KAction( i18n("New &Journal..."), + KOGlobals::self()->smallIcon( "newjournal" ), 0, + mCalendarView, SLOT( newJournal() ), + mACollection, "new_journal" ); + + mShowIncidenceAction = new KAction( i18n("&Show"), 0, + mCalendarView,SLOT( showIncidence() ), + mACollection, "show_incidence" ); + mEditIncidenceAction = new KAction( i18n("&Edit..."), 0, + mCalendarView,SLOT( editIncidence() ), + mACollection, "edit_incidence" ); + mDeleteIncidenceAction = new KAction( i18n("&Delete"), Key_Delete, + mCalendarView,SLOT( deleteIncidence()), + mACollection, "delete_incidence" ); + + action = new KAction( i18n("&Make Sub-to-do Independent"), 0, + mCalendarView,SLOT( todo_unsub() ), + mACollection, "unsub_todo" ); + action->setEnabled( false ); + connect( mCalendarView,SIGNAL( subtodoSelected( bool ) ), + action,SLOT( setEnabled( bool ) ) ); +// TODO: Add item to move the incidence to different resource +// mAssignResourceAction = new KAction( i18n("Assign &Resource..."), 0, +// mCalendarView, SLOT( assignResource()), +// mACollection, "assign_resource" ); +// TODO: Add item to quickly toggle the reminder of a given incidence +// mToggleAlarmAction = new KToggleAction( i18n("&Activate Reminder"), 0, +// mCalendarView, SLOT( toggleAlarm()), +// mACollection, "activate_alarm" ); + + + + + //************************** SCHEDULE MENU ******************************** + mPublishEvent = new KAction( i18n("&Publish Item Information..."), "mail_send", 0, + mCalendarView, SLOT( schedule_publish() ), + mACollection, "schedule_publish" ); + mPublishEvent->setEnabled( false ); + + action = new KAction( i18n("Send &Invitation to Attendees"),"mail_generic",0, + mCalendarView,SLOT( schedule_request() ), + mACollection,"schedule_request" ); + action->setEnabled( false ); + connect( mCalendarView, SIGNAL( organizerEventsSelected( bool ) ), + action, SLOT( setEnabled( bool ) ) ); + + action = new KAction( i18n("Re&quest Update"), 0, + mCalendarView, SLOT( schedule_refresh() ), + mACollection, "schedule_refresh" ); + action->setEnabled( false ); + connect( mCalendarView,SIGNAL( groupEventsSelected( bool ) ), + action,SLOT( setEnabled( bool ) ) ); + + action = new KAction( i18n("Send &Cancelation to Attendees"), 0, + mCalendarView, SLOT( schedule_cancel() ), + mACollection, "schedule_cancel" ); + action->setEnabled( false ); + connect( mCalendarView,SIGNAL( organizerEventsSelected( bool ) ), + action,SLOT( setEnabled( bool ) ) ); + + action = new KAction( i18n("Send Status &Update"),"mail_reply",0, + mCalendarView,SLOT( schedule_reply() ), + mACollection,"schedule_reply" ); + action->setEnabled( false ); + connect( mCalendarView,SIGNAL( groupEventsSelected( bool ) ), + action,SLOT( setEnabled( bool ) ) ); + + action = new KAction( i18n("counter proposal","Request Chan&ge"),0, + mCalendarView,SLOT( schedule_counter() ), + mACollection, "schedule_counter" ); + action->setEnabled( false ); + connect( mCalendarView,SIGNAL( groupEventsSelected( bool ) ), + action,SLOT( setEnabled( bool ) ) ); + + mForwardEvent = new KAction( i18n("&Send as iCalendar..."), "mail_forward", 0, + mCalendarView, SLOT(schedule_forward()), + mACollection, "schedule_forward" ); + mForwardEvent->setEnabled( false ); + + action = new KAction( i18n("&Mail Free Busy Information..."), 0, + mCalendarView, SLOT( mailFreeBusy() ), + mACollection, "mail_freebusy" ); + action->setEnabled( true ); + + action = new KAction( i18n("&Upload Free Busy Information"), 0, + mCalendarView, SLOT( uploadFreeBusy() ), + mACollection, "upload_freebusy" ); + action->setEnabled( true ); + + if ( !mIsPart ) { + action = new KAction( i18n("&Addressbook"),"contents",0, + mCalendarView,SLOT( openAddressbook() ), + mACollection,"addressbook" ); + } + + + + + //************************** SETTINGS MENU ******************************** + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SIDEBAR ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + mDateNavigatorShowAction = new KToggleAction( i18n("Show Date Navigator"), 0, + this, SLOT( toggleDateNavigator() ), + mACollection, "show_datenavigator" ); + mTodoViewShowAction = new KToggleAction ( i18n("Show To-do View"), 0, + this, SLOT( toggleTodoView() ), + mACollection, "show_todoview" ); + mEventViewerShowAction = new KToggleAction ( i18n("Show Item Viewer"), 0, + this, SLOT( toggleEventViewer() ), + mACollection, "show_eventviewer" ); + KConfig *config = KOGlobals::self()->config(); + config->setGroup( "Settings" ); + mDateNavigatorShowAction->setChecked( + config->readBoolEntry( "DateNavigatorVisible", true ) ); + // if we are a kpart, then let's not show the todo in the left pane by + // default since there's also a Todo part and we'll assume they'll be + // using that as well, so let's not duplicate it (by default) here + mTodoViewShowAction->setChecked( + config->readBoolEntry( "TodoViewVisible", mIsPart ? false : true ) ); + mEventViewerShowAction->setChecked( + config->readBoolEntry( "EventViewerVisible", true ) ); + toggleDateNavigator(); + toggleTodoView(); + toggleEventViewer(); + + if ( !mMainWindow->hasDocument() ) { + mResourceViewShowAction = new KToggleAction ( i18n("Show Resource View"), 0, + this, SLOT( toggleResourceView() ), + mACollection, "show_resourceview" ); + mResourceButtonsAction = new KToggleAction( i18n("Show &Resource Buttons"), 0, + this, SLOT( toggleResourceButtons() ), + mACollection, "show_resourcebuttons" ); + mResourceViewShowAction->setChecked( + config->readBoolEntry( "ResourceViewVisible", true ) ); + mResourceButtonsAction->setChecked( + config->readBoolEntry( "ResourceButtonsVisible", true ) ); + + toggleResourceView(); + toggleResourceButtons(); + } + + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SIDEBAR ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + new KAction( i18n("Configure &Date && Time..."), 0, + this, SLOT( configureDateTime() ), + mACollection, "conf_datetime" ); +// TODO: Add an item to show the resource management dlg +// new KAction( i18n("Manage &Resources..."), 0, +// this, SLOT( manageResources() ), +// mACollection, "conf_resources" ); + new KAction( i18n("Manage View &Filters..."), "configure", 0, + mCalendarView, SLOT( editFilters() ), + mACollection, "edit_filters" ); + new KAction( i18n("Manage C&ategories..."), 0, + mCalendarView->dialogManager(), SLOT( showCategoryEditDialog() ), + mACollection, "edit_categories" ); + if ( mIsPart ) { + new KAction( i18n("&Configure Calendar..."), "configure", 0, + mCalendarView, SLOT( edit_options() ), + mACollection, "korganizer_configure" ); + KStdAction::keyBindings( this, SLOT( keyBindings() ), + mACollection, "korganizer_configure_shortcuts" ); + } else { + KStdAction::preferences( mCalendarView, SLOT( edit_options() ), + mACollection ); + KStdAction::keyBindings( this, SLOT( keyBindings() ), mACollection ); + } + + + + + //**************************** HELP MENU ********************************** + KStdAction::tipOfDay( this, SLOT( showTip() ), mACollection, + "help_tipofday" ); +// new KAction( i18n("Show Intro Page"), 0, +// mCalendarView,SLOT( showIntro() ), +// mACollection,"show_intro" ); + + + + + //************************* TOOLBAR ACTIONS ******************************* + QLabel *filterLabel = new QLabel( i18n("Filter: "), mCalendarView ); + filterLabel->hide(); + new KWidgetAction( filterLabel, i18n("Filter: "), 0, 0, 0, + mACollection, "filter_label" ); + +} + +void ActionManager::readSettings() +{ + // read settings from the KConfig, supplying reasonable + // defaults where none are to be found + + KConfig *config = KOGlobals::self()->config(); + if ( mRecent ) mRecent->loadEntries( config ); + mCalendarView->readSettings(); +} + +void ActionManager::writeSettings() +{ + kdDebug(5850) << "ActionManager::writeSettings" << endl; + + KConfig *config = KOGlobals::self()->config(); + mCalendarView->writeSettings(); + + config->setGroup( "Settings" ); + if ( mResourceButtonsAction ) { + config->writeEntry( "ResourceButtonsVisible", + mResourceButtonsAction->isChecked() ); + } + if ( mDateNavigatorShowAction ) { + config->writeEntry( "DateNavigatorVisible", + mDateNavigatorShowAction->isChecked() ); + } + if ( mTodoViewShowAction ) { + config->writeEntry( "TodoViewVisible", + mTodoViewShowAction->isChecked() ); + } + if ( mResourceViewShowAction ) { + config->writeEntry( "ResourceViewVisible", + mResourceViewShowAction->isChecked() ); + } + if ( mEventViewerShowAction ) { + config->writeEntry( "EventViewerVisible", + mEventViewerShowAction->isChecked() ); + } + + if ( mRecent ) mRecent->saveEntries( config ); + + config->sync(); + + if ( mCalendarResources ) { + mCalendarResources->resourceManager()->writeConfig(); + } +} + +void ActionManager::file_new() +{ + emit actionNew(); +} + +void ActionManager::file_open() +{ + KURL url; + QString defaultPath = locateLocal( "data","korganizer/" ); + url = KFileDialog::getOpenURL( defaultPath,i18n("*.vcs *.ics|Calendar Files"), + dialogParent() ); + + file_open( url ); +} + +void ActionManager::file_open( const KURL &url ) +{ + if ( url.isEmpty() ) return; + + // 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() ); + return; + } + + kdDebug(5850) << "ActionManager::file_open(): " << url.prettyURL() << endl; + + // Open the calendar file in the same window only if we have an empty calendar window, and not the resource calendar + if ( !mCalendarView->isModified() && mFile.isEmpty() && !mCalendarResources ) { + openURL( url ); + } else { + emit actionNew( url ); + } +} + +void ActionManager::file_icalimport() +{ + // FIXME: eventually, we will need a dialog box to select import type, etc. + // for now, hard-coded to ical file, $HOME/.calendar. + int retVal = -1; + QString progPath; + KTempFile tmpfn; + + QString homeDir = QDir::homeDirPath() + QString::fromLatin1( "/.calendar" ); + + if ( !QFile::exists( homeDir ) ) { + KMessageBox::error( dialogParent(), + i18n( "You have no ical file in your home directory.\n" + "Import cannot proceed.\n" ) ); + return; + } + + KProcess proc; + proc << "ical2vcal" << tmpfn.name(); + bool success = proc.start( KProcess::Block ); + + if ( !success ) { + kdDebug(5850) << "Error starting ical2vcal." << endl; + return; + } else { + retVal = proc.exitStatus(); + } + + kdDebug(5850) << "ical2vcal return value: " << retVal << endl; + + if ( retVal >= 0 && retVal <= 2 ) { + // now we need to MERGE what is in the iCal to the current calendar. + mCalendarView->openCalendar( tmpfn.name(),1 ); + if ( !retVal ) + KMessageBox::information( dialogParent(), + i18n( "KOrganizer successfully imported and " + "merged your .calendar file from ical " + "into the currently opened calendar." ), + "dotCalendarImportSuccess" ); + else + KMessageBox::information( dialogParent(), + i18n( "KOrganizer encountered some unknown fields while " + "parsing your .calendar ical file, and had to " + "discard them; please check to see that all " + "your relevant data was correctly imported." ), + i18n("ICal Import Successful with Warning") ); + } else if ( retVal == -1 ) { + KMessageBox::error( dialogParent(), + i18n( "KOrganizer encountered an error parsing your " + ".calendar file from ical; import has failed." ) ); + } else if ( retVal == -2 ) { + KMessageBox::error( dialogParent(), + i18n( "KOrganizer does not think that your .calendar " + "file is a valid ical calendar; import has failed." ) ); + } + tmpfn.unlink(); +} + +void ActionManager::file_merge() +{ + KURL url = KFileDialog::getOpenURL( locateLocal( "data","korganizer/" ), + i18n("*.vcs *.ics|Calendar Files"), + dialogParent() ); + if ( ! url.isEmpty() ) // isEmpty if user cancelled the dialog + importCalendar( url ); +} + +void ActionManager::file_archive() +{ + mCalendarView->archiveCalendar(); +} + +void ActionManager::file_revert() +{ + openURL( mURL ); +} + +void ActionManager::file_saveas() +{ + KURL url = getSaveURL(); + + if ( url.isEmpty() ) return; + + saveAsURL( url ); +} + +void ActionManager::file_save() +{ + if ( mMainWindow->hasDocument() ) { + if ( mURL.isEmpty() ) { + file_saveas(); + return; + } else { + saveURL(); + } + } else { + mCalendarView->calendar()->save(); + } + + // export to HTML + if ( KOPrefs::instance()->mHtmlWithSave ) { + exportHTML(); + } +} + +void ActionManager::file_close() +{ + if ( !saveModifiedURL() ) return; + + mCalendarView->closeCalendar(); + KIO::NetAccess::removeTempFile( mFile ); + mURL=""; + mFile=""; + + setTitle(); +} + +bool ActionManager::openURL( const KURL &url,bool merge ) +{ + kdDebug(5850) << "ActionManager::openURL()" << endl; + + if ( url.isEmpty() ) { + kdDebug(5850) << "ActionManager::openURL(): Error! Empty URL." << endl; + return false; + } + if ( !url.isValid() ) { + kdDebug(5850) << "ActionManager::openURL(): Error! URL is malformed." << endl; + return false; + } + + if ( url.isLocalFile() ) { + mURL = url; + mFile = url.path(); + if ( !KStandardDirs::exists( mFile ) ) { + mMainWindow->showStatusMessage( i18n("New calendar '%1'.") + .arg( url.prettyURL() ) ); + mCalendarView->setModified(); + } else { + bool success = mCalendarView->openCalendar( mFile, merge ); + if ( success ) { + showStatusMessageOpen( url, merge ); + } + } + setTitle(); + } else { + QString tmpFile; + if( KIO::NetAccess::download( url, tmpFile, view() ) ) { + kdDebug(5850) << "--- Downloaded to " << tmpFile << endl; + bool success = mCalendarView->openCalendar( tmpFile, merge ); + if ( merge ) { + KIO::NetAccess::removeTempFile( tmpFile ); + if ( success ) + showStatusMessageOpen( url, merge ); + } else { + if ( success ) { + KIO::NetAccess::removeTempFile( mFile ); + mURL = url; + mFile = tmpFile; + KConfig *config = KOGlobals::self()->config(); + config->setGroup( "General" ); + setTitle(); + kdDebug(5850) << "-- Add recent URL: " << url.prettyURL() << endl; + if ( mRecent ) mRecent->addURL( url ); + showStatusMessageOpen( url, merge ); + } + } + return success; + } else { + QString msg; + msg = i18n("Cannot download calendar from '%1'.").arg( url.prettyURL() ); + KMessageBox::error( dialogParent(), msg ); + return false; + } + } + return true; +} + +bool ActionManager::addResource( const KURL &mUrl ) +{ + CalendarResources *cr = KOrg::StdCalendar::self(); + + CalendarResourceManager *manager = cr->resourceManager(); + + ResourceCalendar *resource = 0; + + QString name; + + kdDebug(5850) << "URL: " << mUrl << endl; + if ( mUrl.isLocalFile() ) { + kdDebug(5850) << "Local Resource" << endl; + resource = manager->createResource( "file" ); + if ( resource ) + resource->setValue( "File", mUrl.path() ); + name = mUrl.path(); + } else { + kdDebug(5850) << "Remote Resource" << endl; + resource = manager->createResource( "remote" ); + if ( resource ) + resource->setValue( "DownloadURL", mUrl.url() ); + name = mUrl.prettyURL(); + resource->setReadOnly( true ); + } + + if ( resource ) { + resource->setTimeZoneId( KOPrefs::instance()->mTimeZoneId ); + resource->setResourceName( name ); + manager->add( resource ); + mMainWindow->showStatusMessage( i18n( "Added calendar resource for URL '%1'." ) + .arg( name ) ); + // we have to call resourceAdded manually, because for in-process changes + // the dcop signals are not connected, so the resource's signals would not + // be connected otherwise + if ( mCalendarResources ) + mCalendarResources->resourceAdded( resource ); + } else { + QString msg = i18n("Unable to create calendar resource '%1'.") + .arg( name ); + KMessageBox::error( dialogParent(), msg ); + } + return true; +} + + +void ActionManager::showStatusMessageOpen( const KURL &url, bool merge ) +{ + if ( merge ) { + mMainWindow->showStatusMessage( i18n("Merged calendar '%1'.") + .arg( url.prettyURL() ) ); + } else { + mMainWindow->showStatusMessage( i18n("Opened calendar '%1'.") + .arg( url.prettyURL() ) ); + } +} + +void ActionManager::closeURL() +{ + kdDebug(5850) << "ActionManager::closeURL()" << endl; + + file_close(); +} + +bool ActionManager::saveURL() +{ + QString ext; + + if ( mURL.isLocalFile() ) { + ext = mFile.right( 4 ); + } else { + ext = mURL.filename().right( 4 ); + } + + if ( ext == ".vcs" ) { + int result = KMessageBox::warningContinueCancel( + dialogParent(), + i18n( "Your calendar will be saved in iCalendar format. Use " + "'Export vCalendar' to save in vCalendar format." ), + i18n("Format Conversion"), i18n("Proceed"), "dontaskFormatConversion", + true ); + if ( result != KMessageBox::Continue ) return false; + + QString filename = mURL.fileName(); + filename.replace( filename.length() - 4, 4, ".ics" ); + mURL.setFileName( filename ); + if ( mURL.isLocalFile() ) { + mFile = mURL.path(); + } + setTitle(); + if ( mRecent ) mRecent->addURL( mURL ); + } + + if ( !mCalendarView->saveCalendar( mFile ) ) { + kdDebug(5850) << "ActionManager::saveURL(): calendar view save failed." + << endl; + return false; + } else { + mCalendarView->setModified( false ); + } + + if ( !mURL.isLocalFile() ) { + if ( !KIO::NetAccess::upload( mFile, mURL, view() ) ) { + QString msg = i18n("Cannot upload calendar to '%1'") + .arg( mURL.prettyURL() ); + KMessageBox::error( dialogParent() ,msg ); + return false; + } + } + + // keep saves on a regular interval + if ( KOPrefs::instance()->mAutoSave ) { + mAutoSaveTimer->stop(); + mAutoSaveTimer->start( 1000*60*KOPrefs::instance()->mAutoSaveInterval ); + } + + mMainWindow->showStatusMessage( i18n("Saved calendar '%1'.").arg( mURL.prettyURL() ) ); + + return true; +} + +void ActionManager::exportHTML() +{ + HTMLExportSettings settings( "KOrganizer" ); + // Manually read in the config, because parametrized kconfigxt objects don't + // seem to load the config theirselves + settings.readConfig(); + + QDate qd1; + qd1 = QDate::currentDate(); + QDate qd2; + qd2 = QDate::currentDate(); + if ( settings.monthView() ) + qd2.addMonths( 1 ); + else + qd2.addDays( 7 ); + settings.setDateStart( qd1 ); + settings.setDateEnd( qd2 ); + exportHTML( &settings ); +} + +void ActionManager::exportHTML( HTMLExportSettings *settings ) +{ + if ( !settings || settings->outputFile().isEmpty() ) + return; + settings->setEMail( KOPrefs::instance()->email() ); + settings->setName( KOPrefs::instance()->fullName() ); + + settings->setCreditName( "KOrganizer" ); + settings->setCreditURL( "http://korganizer.kde.org" ); + + KCal::HtmlExport mExport( mCalendarView->calendar(), settings ); + + QDate cdate = settings->dateStart().date(); + QDate qd2 = settings->dateEnd().date(); + while ( cdate <= qd2 ) { + QStringList holidays = KOGlobals::self()->holiday( cdate ); + if ( !holidays.isEmpty() ) { + QStringList::ConstIterator it = holidays.begin(); + for ( ; it != holidays.end(); ++it ) { + mExport.addHoliday( cdate, *it ); + } + } + cdate = cdate.addDays( 1 ); + } + + KURL dest( settings->outputFile() ); + if ( dest.isLocalFile() ) { + mExport.save( dest.path() ); + } else { + KTempFile tf; + QString tfile = tf.name(); + tf.close(); + mExport.save( tfile ); + if ( !KIO::NetAccess::upload( tfile, dest, view() ) ) { + KNotifyClient::event ( view()->winId(), + i18n("Could not upload file.") ); + } + tf.unlink(); + } +} + +bool ActionManager::saveAsURL( const KURL &url ) +{ + kdDebug(5850) << "ActionManager::saveAsURL() " << url.prettyURL() << endl; + + if ( url.isEmpty() ) { + kdDebug(5850) << "ActionManager::saveAsURL(): Empty URL." << endl; + return false; + } + if ( !url.isValid() ) { + kdDebug(5850) << "ActionManager::saveAsURL(): Malformed URL." << endl; + return false; + } + + QString fileOrig = mFile; + KURL URLOrig = mURL; + + KTempFile *tempFile = 0; + if ( url.isLocalFile() ) { + mFile = url.path(); + } else { + tempFile = new KTempFile; + mFile = tempFile->name(); + } + mURL = url; + + bool success = saveURL(); // Save local file and upload local file + if ( success ) { + delete mTempFile; + mTempFile = tempFile; + KIO::NetAccess::removeTempFile( fileOrig ); + KConfig *config = KOGlobals::self()->config(); + config->setGroup( "General" ); + setTitle(); + if ( mRecent ) mRecent->addURL( mURL ); + } else { + KMessageBox::sorry( dialogParent(), i18n("Unable to save calendar to the file %1.").arg( mFile ), i18n("Error") ); + kdDebug(5850) << "ActionManager::saveAsURL() failed" << endl; + mURL = URLOrig; + mFile = fileOrig; + delete tempFile; + } + + return success; +} + + +bool ActionManager::saveModifiedURL() +{ + kdDebug(5850) << "ActionManager::saveModifiedURL()" << endl; + + // If calendar isn't modified do nothing. + if ( !mCalendarView->isModified() ) return true; + + mHtmlExportSync = true; + if ( KOPrefs::instance()->mAutoSave && !mURL.isEmpty() ) { + // Save automatically, when auto save is enabled. + return saveURL(); + } else { + int result = KMessageBox::warningYesNoCancel( + dialogParent(), + i18n("The calendar has been modified.\nDo you want to save it?"), + QString::null, + KStdGuiItem::save(), KStdGuiItem::discard() ); + switch( result ) { + case KMessageBox::Yes: + if ( mURL.isEmpty() ) { + KURL url = getSaveURL(); + return saveAsURL( url ); + } else { + return saveURL(); + } + case KMessageBox::No: + return true; + case KMessageBox::Cancel: + default: + { + mHtmlExportSync = false; + return false; + } + } + } +} + + +KURL ActionManager::getSaveURL() +{ + KURL url = KFileDialog::getSaveURL( locateLocal( "data","korganizer/" ), + i18n("*.vcs *.ics|Calendar Files"), + dialogParent() ); + + if ( url.isEmpty() ) return url; + + QString filename = url.fileName( false ); + + QString e = filename.right( 4 ); + if ( e != ".vcs" && e != ".ics" ) { + // Default save format is iCalendar + filename += ".ics"; + } + + url.setFileName( filename ); + + kdDebug(5850) << "ActionManager::getSaveURL(): url: " << url.url() << endl; + + return url; +} + +void ActionManager::saveProperties( KConfig *config ) +{ + kdDebug(5850) << "ActionManager::saveProperties" << endl; + + config->writeEntry( "UseResourceCalendar", !mMainWindow->hasDocument() ); + if ( mMainWindow->hasDocument() ) { + config->writePathEntry( "Calendar",mURL.url() ); + } +} + +void ActionManager::readProperties( KConfig *config ) +{ + kdDebug(5850) << "ActionManager::readProperties" << endl; + + bool isResourceCalendar( + config->readBoolEntry( "UseResourceCalendar", true ) ); + QString calendarUrl = config->readPathEntry( "Calendar" ); + + if ( !isResourceCalendar && !calendarUrl.isEmpty() ) { + mMainWindow->init( true ); + KURL u( calendarUrl ); + openURL( u ); + } else { + mMainWindow->init( false ); + } +} + +void ActionManager::checkAutoSave() +{ + kdDebug(5850) << "ActionManager::checkAutoSave()" << endl; + + // Don't save if auto save interval is zero + if ( KOPrefs::instance()->mAutoSaveInterval == 0 ) return; + + // has this calendar been saved before? If yes automatically save it. + if ( KOPrefs::instance()->mAutoSave ) { + if ( mCalendarResources || ( mCalendar && !url().isEmpty() ) ) { + saveCalendar(); + } + } +} + + +// Configuration changed as a result of the options dialog. +void ActionManager::updateConfig() +{ + kdDebug(5850) << "ActionManager::updateConfig()" << endl; + + if ( KOPrefs::instance()->mAutoSave && !mAutoSaveTimer->isActive() ) { + checkAutoSave(); + if ( KOPrefs::instance()->mAutoSaveInterval > 0 ) { + mAutoSaveTimer->start( 1000 * 60 * + KOPrefs::instance()->mAutoSaveInterval ); + } + } + if ( !KOPrefs::instance()->mAutoSave ) mAutoSaveTimer->stop(); + mNextXDays->setText( i18n( "&Next Day", "&Next %n Days", + KOPrefs::instance()->mNextXDays ) ); + + KOCore::self()->reloadPlugins(); + mParts = KOCore::self()->reloadParts( mMainWindow, mParts ); + + setDestinationPolicy(); + + if ( mResourceView ) + mResourceView->updateView(); + + KOGroupware::instance()->freeBusyManager()->setBrokenUrl( false ); +} + +void ActionManager::setDestinationPolicy() +{ + if ( mCalendarResources ) { + if ( KOPrefs::instance()->mDestination == KOPrefs::askDestination ) + mCalendarResources->setAskDestinationPolicy(); + else + mCalendarResources->setStandardDestinationPolicy(); + } +} + +void ActionManager::configureDateTime() +{ + KProcess *proc = new KProcess; + *proc << "kcmshell" << "language"; + + connect( proc,SIGNAL( processExited( KProcess * ) ), + SLOT( configureDateTimeFinished( KProcess * ) ) ); + + if ( !proc->start() ) { + KMessageBox::sorry( dialogParent(), + i18n("Could not start control module for date and time format.") ); + delete proc; + } +} + +void ActionManager::showTip() +{ + KTipDialog::showTip( dialogParent(),QString::null,true ); +} + +void ActionManager::showTipOnStart() +{ + KTipDialog::showTip( dialogParent() ); +} + +KOrg::MainWindow *ActionManager::findInstance( const KURL &url ) +{ + if ( mWindowList ) { + if ( url.isEmpty() ) return mWindowList->defaultInstance(); + else return mWindowList->findInstance( url ); + } else { + return 0; + } +} + +void ActionManager::dumpText( const QString &str ) +{ + kdDebug(5850) << "ActionManager::dumpText(): " << str << endl; +} + +void ActionManager::toggleDateNavigator() +{ + bool visible = mDateNavigatorShowAction->isChecked(); + if ( mCalendarView ) mCalendarView->showDateNavigator( visible ); +} + +void ActionManager::toggleTodoView() +{ + bool visible = mTodoViewShowAction->isChecked(); + if ( mCalendarView ) mCalendarView->showTodoView( visible ); +} + +void ActionManager::toggleEventViewer() +{ + bool visible = mEventViewerShowAction->isChecked(); + if ( mCalendarView ) mCalendarView->showEventViewer( visible ); +} + +void ActionManager::toggleResourceView() +{ + bool visible = mResourceViewShowAction->isChecked(); + kdDebug(5850) << "toggleResourceView: " << endl; + if ( mResourceView ) { + if ( visible ) mResourceView->show(); + else mResourceView->hide(); + } +} + +void ActionManager::toggleResourceButtons() +{ + bool visible = mResourceButtonsAction->isChecked(); + + kdDebug(5850) << "RESOURCE VIEW " << long( mResourceView ) << endl; + + if ( mResourceView ) mResourceView->showButtons( visible ); +} + +bool ActionManager::openURL( const QString &url ) +{ + return openURL( KURL( url ) ); +} + +bool ActionManager::mergeURL( const QString &url ) +{ + return openURL( KURL( url ),true ); +} + +bool ActionManager::saveAsURL( const QString &url ) +{ + return saveAsURL( KURL( url ) ); +} + +QString ActionManager::getCurrentURLasString() const +{ + return mURL.url(); +} + +bool ActionManager::editIncidence( const QString& uid ) +{ + return mCalendarView->editIncidence( uid ); +} + +bool ActionManager::deleteIncidence( const QString& uid, bool force ) +{ + return mCalendarView->deleteIncidence( uid, force ); +} + +bool ActionManager::addIncidence( const QString& ical ) +{ + return mCalendarView->addIncidence( ical ); +} + +void ActionManager::configureDateTimeFinished( KProcess *proc ) +{ + delete proc; +} + +void ActionManager::downloadNewStuff() +{ + kdDebug(5850) << "ActionManager::downloadNewStuff()" << endl; + + if ( !mNewStuff ) mNewStuff = new KONewStuff( mCalendarView ); + mNewStuff->download(); +} + +void ActionManager::uploadNewStuff() +{ + if ( !mNewStuff ) mNewStuff = new KONewStuff( mCalendarView ); + mNewStuff->upload(); +} + +QString ActionManager::localFileName() +{ + return mFile; +} + +class ActionManager::ActionStringsVisitor : public IncidenceBase::Visitor +{ + public: + ActionStringsVisitor() : mShow( 0 ), mEdit( 0 ), mDelete( 0 ) {} + + bool act( IncidenceBase *incidence, KAction *show, KAction *edit, KAction *del ) + { + mShow = show; + mEdit = edit; + mDelete = del; + return incidence->accept( *this ); + } + + protected: + bool visit( Event * ) { + if ( mShow ) mShow->setText( i18n("&Show Event") ); + if ( mEdit ) mEdit->setText( i18n("&Edit Event...") ); + if ( mDelete ) mDelete->setText( i18n("&Delete Event") ); + return true; + } + bool visit( Todo * ) { + if ( mShow ) mShow->setText( i18n("&Show To-do") ); + if ( mEdit ) mEdit->setText( i18n("&Edit To-do...") ); + if ( mDelete ) mDelete->setText( i18n("&Delete To-do") ); + return true; + } + bool visit( Journal * ) { return assignDefaultStrings(); } + protected: + bool assignDefaultStrings() { + if ( mShow ) mShow->setText( i18n("&Show") ); + if ( mEdit ) mEdit->setText( i18n("&Edit...") ); + if ( mDelete ) mDelete->setText( i18n("&Delete") ); + return true; + } + KAction *mShow; + KAction *mEdit; + KAction *mDelete; +}; + +void ActionManager::processIncidenceSelection( Incidence *incidence ) +{ +// kdDebug(5850) << "ActionManager::processIncidenceSelection()" << endl; + + if ( !incidence ) { + enableIncidenceActions( false ); + return; + } + + enableIncidenceActions( true ); + + if ( incidence->isReadOnly() ) { + mCutAction->setEnabled( false ); + mDeleteAction->setEnabled( false ); + } + + ActionStringsVisitor v; + if ( !v.act( incidence, mShowIncidenceAction, mEditIncidenceAction, mDeleteIncidenceAction ) ) { + mShowIncidenceAction->setText( i18n("&Show") ); + mEditIncidenceAction->setText( i18n("&Edit...") ); + mDeleteIncidenceAction->setText( i18n("&Delete") ); + } +} + +void ActionManager::enableIncidenceActions( bool enabled ) +{ + mShowIncidenceAction->setEnabled( enabled ); + mEditIncidenceAction->setEnabled( enabled ); + mDeleteIncidenceAction->setEnabled( enabled ); +// mAssignResourceAction->setEnabled( enabled ); + + mCutAction->setEnabled( enabled ); + mCopyAction->setEnabled( enabled ); + mDeleteAction->setEnabled( enabled ); + mPublishEvent->setEnabled( enabled ); + mForwardEvent->setEnabled( enabled ); +} + +void ActionManager::keyBindings() +{ + KKeyDialog dlg( false, view() ); + if ( mMainWindow ) + dlg.insert( mMainWindow->getActionCollection() ); + + KOrg::Part *part; + for ( part = mParts.first(); part; part = mParts.next() ) { + dlg.insert( part->actionCollection(), part->shortInfo() ); + } + dlg.configure(); +} + +void ActionManager::loadParts() +{ + mParts = KOCore::self()->loadParts( mMainWindow ); +} + +void ActionManager::setTitle() +{ + mMainWindow->setTitle(); +} + +KCalendarIface::ResourceRequestReply ActionManager::resourceRequest( const QValueList<QPair<QDateTime, QDateTime> >&, + const QCString& resource, + const QString& vCalIn ) +{ + kdDebug(5850) << k_funcinfo << "resource=" << resource << " vCalIn=" << vCalIn << endl; + KCalendarIface::ResourceRequestReply reply; + reply.vCalOut = "VCalOut"; + return reply; +} + +void ActionManager::openEventEditor( const QString& text ) +{ + mCalendarView->newEvent( text ); +} + +void ActionManager::openEventEditor( const QString& summary, + const QString& description, + const QString& attachment ) +{ + mCalendarView->newEvent( summary, description, attachment ); +} + +void ActionManager::openEventEditor( const QString& summary, + const QString& description, + const QString& attachment, + const QStringList& attendees ) +{ + mCalendarView->newEvent( summary, description, attachment, attendees ); +} + +void ActionManager::openEventEditor( const QString & summary, + const QString & description, + const QString & uri, + const QString & file, + const QStringList & attendees, + const QString & attachmentMimetype ) +{ + int action = KOPrefs::instance()->defaultEmailAttachMethod(); + if ( attachmentMimetype != "message/rfc822" ) { + action = KOPrefs::Link; + } else if ( KOPrefs::instance()->defaultEmailAttachMethod() == KOPrefs::Ask ) { + KPopupMenu *menu = new KPopupMenu( 0 ); + menu->insertItem( i18n("Attach as &link"), KOPrefs::Link ); + menu->insertItem( i18n("Attach &inline"), KOPrefs::InlineFull ); + menu->insertItem( i18n("Attach inline &without attachments"), KOPrefs::InlineBody ); + menu->insertSeparator(); + menu->insertItem( SmallIcon("cancel"), i18n("C&ancel"), KOPrefs::Ask ); + action = menu->exec( QCursor::pos(), 0 ); + delete menu; + } + + QString attData; + KTempFile tf; + tf.setAutoDelete( true ); + switch ( action ) { + case KOPrefs::Ask: + return; + case KOPrefs::Link: + attData = uri; + break; + case KOPrefs::InlineFull: + attData = file; + break; + case KOPrefs::InlineBody: + { + QFile f( file ); + if ( !f.open( IO_ReadOnly ) ) + return; + KMime::Message *msg = new KMime::Message(); + msg->setContent( QCString( f.readAll() ) ); + QCString head = msg->head(); + msg->parse(); + if ( msg == msg->textContent() || msg->textContent() == 0 ) { // no attachments + attData = file; + } else { + if ( KMessageBox::warningContinueCancel( 0, + i18n("Removing attachments from an email might invalidate its signature."), + i18n("Remove Attachments"), KStdGuiItem::cont(), "BodyOnlyInlineAttachment" ) + != KMessageBox::Continue ) + return; + // due to kmime shortcomings in KDE3, we need to assemble the result manually + int begin = 0; + int end = head.find( '\n' ); + bool skipFolded = false; + while ( end >= 0 && end > begin ) { + if ( head.find( "Content-Type:", begin, false ) != begin && + head.find( "Content-Transfer-Encoding:", begin, false ) != begin && + !(skipFolded && (head[begin] == ' ' || head[end] == '\t')) ) { + QCString line = head.mid( begin, end - begin ); + tf.file()->writeBlock( line.data(), line.length() ); + tf.file()->writeBlock( "\n", 1 ); + skipFolded = false; + } else { + skipFolded = true; + } + + begin = end + 1; + end = head.find( '\n', begin ); + if ( end < 0 && begin < (int)head.length() ) + end = head.length() - 1; + } + QCString cte = msg->textContent()->contentTransferEncoding()->as7BitString(); + if ( !cte.stripWhiteSpace().isEmpty() ) { + tf.file()->writeBlock( cte.data(), cte.length() ); + tf.file()->writeBlock( "\n", 1 ); + } + QCString ct = msg->textContent()->contentType()->as7BitString(); + if ( !ct.stripWhiteSpace().isEmpty() ) + tf.file()->writeBlock( ct.data(), ct.length() ); + tf.file()->writeBlock( "\n", 1 ); + tf.file()->writeBlock( msg->textContent()->body() ); + attData = tf.name(); + } + tf.close(); + delete msg; + break; + } + default: + // menu could have been closed by cancel, if so, do nothing + return; + } + + mCalendarView->newEvent( summary, description, attData, attendees, attachmentMimetype, action != KOPrefs::Link ); +} + +void ActionManager::openTodoEditor( const QString& text ) +{ + mCalendarView->newTodo( text ); +} + +void ActionManager::openTodoEditor( const QString& summary, + const QString& description, + const QString& attachment ) +{ + mCalendarView->newTodo( summary, description, attachment ); +} + +void ActionManager::openTodoEditor( const QString& summary, + const QString& description, + const QString& attachment, + const QStringList& attendees ) +{ + mCalendarView->newTodo( summary, description, attachment, attendees ); +} + +void ActionManager::openTodoEditor(const QString & summary, + const QString & description, + const QString & uri, + const QString & file, + const QStringList & attendees, + const QString & attachmentMimetype) +{ + int action = KOPrefs::instance()->defaultTodoAttachMethod(); + if ( attachmentMimetype != "message/rfc822" ) { + action = KOPrefs::TodoAttachLink; + } else if ( KOPrefs::instance()->defaultTodoAttachMethod() == KOPrefs::TodoAttachAsk ) { + KPopupMenu *menu = new KPopupMenu( 0 ); + menu->insertItem( i18n("Attach as &link"), KOPrefs::TodoAttachLink ); + menu->insertItem( i18n("Attach &inline"), KOPrefs::TodoAttachInlineFull ); + menu->insertSeparator(); + menu->insertItem( SmallIcon("cancel"), i18n("C&ancel"), KOPrefs::TodoAttachAsk ); + action = menu->exec( QCursor::pos(), 0 ); + delete menu; + } + + QString attData; + switch ( action ) { + case KOPrefs::TodoAttachAsk: + return; + case KOPrefs::TodoAttachLink: + attData = uri; + break; + 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 ); +} + +void ActionManager::openJournalEditor( const QDate& date ) +{ + mCalendarView->newJournal( date ); +} + +void ActionManager::openJournalEditor( const QString& text, const QDate& date ) +{ + mCalendarView->newJournal( text, date ); +} + +void ActionManager::openJournalEditor( const QString& text ) +{ + mCalendarView->newJournal( text ); +} + +//TODO: +// void ActionManager::openJournalEditor( const QString& summary, +// const QString& description, +// const QString& attachment ) +// { +// mCalendarView->newJournal( summary, description, attachment ); +// } + + +void ActionManager::showJournalView() +{ + mCalendarView->viewManager()->showJournalView(); +} + +void ActionManager::showTodoView() +{ + mCalendarView->viewManager()->showTodoView(); +} + +void ActionManager::showEventView() +{ + mCalendarView->viewManager()->showEventView(); +} + +void ActionManager::goDate( const QDate& date ) +{ + mCalendarView->goDate( date ); +} + +void ActionManager::goDate( const QString& date ) +{ + goDate( KGlobal::locale()->readDate( date ) ); +} + +void ActionManager::showDate(const QDate & date) +{ + mCalendarView->showDate( date ); +} + + +void ActionManager::updateUndoAction( const QString &text ) +{ + if ( text.isNull() ) { + mUndoAction->setEnabled( false ); + mUndoAction->setText( i18n("Undo") ); + } else { + mUndoAction->setEnabled( true ); + if ( text.isEmpty() ) mUndoAction->setText( i18n("Undo") ); + else mUndoAction->setText( i18n("Undo (%1)").arg( text ) ); + } +} + +void ActionManager::updateRedoAction( const QString &text ) +{ + if ( text.isNull() ) { + mRedoAction->setEnabled( false ); + mRedoAction->setText( i18n( "Redo" ) ); + } else { + mRedoAction->setEnabled( true ); + if ( text.isEmpty() ) mRedoAction->setText( i18n("Redo") ); + else mRedoAction->setText( i18n( "Redo (%1)" ).arg( text ) ); + } +} + +bool ActionManager::queryClose() +{ + kdDebug(5850) << "ActionManager::queryClose()" << endl; + + bool close = true; + + if ( mCalendar && mCalendar->isModified() ) { + int res = KMessageBox::questionYesNoCancel( dialogParent(), + i18n("The calendar contains unsaved changes. Do you want to save them before exiting?"), QString::null, KStdGuiItem::save(), KStdGuiItem::discard() ); + // Exit on yes and no, don't exit on cancel. If saving fails, ask for exiting. + if ( res == KMessageBox::Yes ) { + close = saveModifiedURL(); + if ( !close ) { + int res1 = KMessageBox::questionYesNo( dialogParent(), i18n("Unable to save the calendar. Do you still want to close this window?"), QString::null, KStdGuiItem::close(), KStdGuiItem::cancel() ); + close = ( res1 == KMessageBox::Yes ); + } + } else { + close = ( res == KMessageBox::No ); + } + } else if ( mCalendarResources ) { + if ( !mIsClosing ) { + kdDebug(5850) << "!mIsClosing" << endl; + if ( !saveResourceCalendar() ) return false; + + // FIXME: Put main window into a state indicating final saving. + mIsClosing = true; +// FIXME: Close main window when save is finished +// connect( mCalendarResources, SIGNAL( calendarSaved() ), +// mMainWindow, SLOT( close() ) ); + } + if ( mCalendarResources->isSaving() ) { + kdDebug(5850) << "ActionManager::queryClose(): isSaving" << endl; + close = false; + KMessageBox::information( dialogParent(), + i18n("Unable to exit. Saving still in progress.") ); + } else { + kdDebug(5850) << "ActionManager::queryClose(): close = true" << endl; + close = true; + } + } else { + close = true; + } + + return close; +} + +void ActionManager::saveCalendar() +{ + if ( mCalendar ) { + if ( view()->isModified() ) { + if ( !url().isEmpty() ) { + saveURL(); + } else { + QString location = locateLocal( "data", "korganizer/kontact.ics" ); + saveAsURL( location ); + } + } + } else if ( mCalendarResources ) { + mCalendarResources->save(); + // FIXME: Make sure that asynchronous saves don't fail. + } +} + +bool ActionManager::saveResourceCalendar() +{ + if ( !mCalendarResources ) return false; + CalendarResourceManager *m = mCalendarResources->resourceManager(); + + CalendarResourceManager::ActiveIterator it; + for ( it = m->activeBegin(); it != m->activeEnd(); ++it ) { + if ( (*it)->readOnly() ) continue; + if ( !(*it)->save() ) { + int result = KMessageBox::warningContinueCancel( view(), + i18n( "Saving of '%1' failed. Check that the resource is " + "properly configured.\nIgnore problem and continue without " + "saving or cancel save?" ).arg( (*it)->resourceName() ), + i18n("Save Error"), KStdGuiItem::dontSave() ); + if ( result == KMessageBox::Cancel ) return false; + } + } + return true; +} + +void ActionManager::importCalendar( const KURL &url ) +{ + if ( !url.isValid() ) { + KMessageBox::error( dialogParent(), + i18n("URL '%1' is invalid.").arg( url.prettyURL() ) ); + return; + } + + ImportDialog *dialog; + dialog = new ImportDialog( url, mMainWindow->topLevelWidget() ); + connect( dialog, SIGNAL( dialogFinished( ImportDialog * ) ), + SLOT( slotImportDialogFinished( ImportDialog * ) ) ); + connect( dialog, SIGNAL( openURL( const KURL &, bool ) ), + SLOT( openURL( const KURL &, bool ) ) ); + connect( dialog, SIGNAL( newWindow( const KURL & ) ), + SIGNAL( actionNew( const KURL & ) ) ); + connect( dialog, SIGNAL( addResource( const KURL & ) ), + SLOT( addResource( const KURL & ) ) ); + + dialog->show(); +} + +void ActionManager::slotImportDialogFinished( ImportDialog *dlg ) +{ + dlg->deleteLater(); + mCalendarView->updateView(); +} + +void ActionManager::slotAutoArchivingSettingsModified() +{ + if ( KOPrefs::instance()->mAutoArchive ) + mAutoArchiveTimer->start( 4 * 60 * 60 * 1000, true ); // check again in 4 hours + else + mAutoArchiveTimer->stop(); +} + +void ActionManager::slotAutoArchive() +{ + if ( !mCalendarView->calendar() ) // can this happen? + return; + mAutoArchiveTimer->stop(); + EventArchiver archiver; + connect( &archiver, SIGNAL( eventsDeleted() ), mCalendarView, SLOT( updateView() ) ); + archiver.runAuto( mCalendarView->calendar(), mCalendarView, false /*no gui*/ ); + // restart timer with the correct delay ( especially useful for the first time ) + slotAutoArchivingSettingsModified(); +} + +void ActionManager::loadProfile( const QString & path ) +{ + KOPrefs::instance()->writeConfig(); + KConfig* const cfg = KOPrefs::instance()->config(); + + const KConfig profile( path+"/korganizerrc", /*read-only=*/false, /*useglobals=*/false ); + const QStringList groups = profile.groupList(); + for ( QStringList::ConstIterator it = groups.begin(), end = groups.end(); it != end; ++it ) + { + cfg->setGroup( *it ); + typedef QMap<QString, QString> StringMap; + const StringMap entries = profile.entryMap( *it ); + for ( StringMap::ConstIterator it2 = entries.begin(), end = entries.end(); it2 != end; ++it2 ) + { + cfg->writeEntry( it2.key(), it2.data() ); + } + } + + cfg->sync(); + KOPrefs::instance()->readConfig(); +} + +namespace { + void copyConfigEntry( KConfig* source, KConfig* dest, const QString& group, const QString& key, const QString& defaultValue=QString() ) + { + source->setGroup( group ); + dest->setGroup( group ); + dest->writeEntry( key, source->readEntry( key, defaultValue ) ); + } +} + +void ActionManager::saveToProfile( const QString & path ) const +{ + KOPrefs::instance()->writeConfig(); + KConfig* const cfg = KOPrefs::instance()->config(); + + KConfig profile( path+"/korganizerrc", /*read-only=*/false, /*useglobals=*/false ); + ::copyConfigEntry( cfg, &profile, "Views", "Agenda View Calendar Display" ); +} + +QWidget *ActionManager::dialogParent() +{ + return mCalendarView->topLevelWidget(); +} + +#include "actionmanager.moc" diff --git a/korganizer/actionmanager.h b/korganizer/actionmanager.h new file mode 100644 index 000000000..b8c9cadbc --- /dev/null +++ b/korganizer/actionmanager.h @@ -0,0 +1,422 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2002 Mike Pilone <mpilone@slac.com> + Copyright (c) 2002 Don Sanders <sanders@kde.org> + Copyright (c) 2003,2004 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KORG_ACTIONMANAGER_H +#define KORG_ACTIONMANAGER_H + +#include <qobject.h> +#include <kurl.h> +#include <korganizer/part.h> +#include <kdepimmacros.h> + +#include "kcalendariface.h" + +namespace KCal +{ + class Calendar; + class CalendarResources; + class Incidence; + class ResourceCalendar; +} +namespace KOrg +{ + class MainWindow; +} + +class KAction; +class KActionCollection; +class KRecentFilesAction; +class KSelectAction; +class KToggleAction; +class KConfig; +class KProcess; +class KTempFile; +class KXMLGUIClient; +class CalendarView; +class KOrganizer; +class KONewStuff; +class KOWindowList; +class ImportDialog; +class ResourceView; +class HTMLExportSettings; + +using namespace KCal; + +/** + The ActionManager creates all the actions in KOrganizer. This class + is shared between the main application and the part so all common + actions are in one location. + It also provides DCOP interface[s]. +*/ +class KDE_EXPORT ActionManager : public QObject, public KCalendarIface +{ + Q_OBJECT + public: + ActionManager( KXMLGUIClient *client, CalendarView *widget, + QObject *parent, KOrg::MainWindow *mainWindow, + bool isPart ); + virtual ~ActionManager(); + + /** Peform initialization that requires this* to be full constructed */ + void init(); + + CalendarView *view() const { return mCalendarView; } + + /** + Create Calendar object based on local file and set it on the view. + */ + void createCalendarLocal(); + /** + Create Calendar object based on the resource framework and set it on the + view. + */ + void createCalendarResources(); + + /** + Save calendar to disk. + */ + void saveCalendar(); + + /** + Save the resource based calendar. Return false if an error occured and the + user decidec to not ignore the error. Otherwise it returns true. + */ + bool saveResourceCalendar(); + + public slots: + /** Add a new resource */ + bool addResource( const KURL &mUrl ); + /** + Open calendar file from URL. Merge into current calendar, if \a merge is + true. + */ + bool openURL( const KURL &url, bool merge = false ); + /** Save calendar file to URL of current calendar */ + bool saveURL(); + /** Save calendar file to URL */ + bool saveAsURL( const KURL &kurl ); + /** Save calendar if it is modified by the user. Ask user what to do. */ + bool saveModifiedURL(); + + void exportHTML(); + void exportHTML( HTMLExportSettings * ); + public: + /** Get current URL */ + KURL url() const { return mURL; } + + /** Is there a instance with this URL? */ + static KOrg::MainWindow* findInstance( const KURL &url ); + /** Open calendar file from URL */ + bool openURL( const QString &url ); + /** Open calendar file from URL */ + bool mergeURL( const QString &url ); + /** Save calendar file to URL */ + bool saveAsURL( const QString &url ); + /** Close calendar file opened from URL */ + void closeURL(); + /** Get current URL as QString */ + QString getCurrentURLasString() const; + /** + Delete the incidence with the given unique id from current calendar. + @param uid UID of the incidence to delete. + @param force If true, all recurrences and sub-todos (if applicable) will be + deleted without prompting for confirmation. + */ + virtual bool deleteIncidence( const QString& uid, bool force = false ); + + bool editIncidence( const QString& uid ); + + /** + Add an incidence to the active calendar. + @param ical A calendar in iCalendar format containing the incidence. + */ + + bool addIncidence( const QString& ical ); + + //// Implementation of the DCOP interface + virtual ResourceRequestReply resourceRequest( const QValueList<QPair<QDateTime, QDateTime> >& busy, + const QCString& resource, + const QString& vCalIn ); + + void openEventEditor( const QString& ); + void openEventEditor( const QString& summary, + const QString& description, + const QString& attachment ); + void openEventEditor( const QString& summary, + const QString& description, + const QString& attachment, + const QStringList& attendees ); + void openEventEditor( const QString& summary, + const QString& description, + const QString& uri, + const QString& file, + const QStringList& attendees, + const QString& attachmentMimetype ); + + void openTodoEditor( const QString& ); + void openTodoEditor( const QString& summary, + const QString& description, + const QString& attachment ); + void openTodoEditor( const QString& summary, + const QString& description, + const QString& attachment, + const QStringList& attendees ); + void openTodoEditor( const QString& summary, + const QString& description, + const QString& uri, + const QString& file, + const QStringList& attendees, + const QString& attachmentMimetype ); + + void openJournalEditor( const QDate& date ); + void openJournalEditor( const QString& text, const QDate& date ); + void openJournalEditor( const QString& text ); + //TODO: + // void openJournalEditor( const QString& summary, + // const QString& description, + // const QString& attachment ); + + void showJournalView(); + void showTodoView(); + void showEventView(); + + void goDate( const QDate& ); + void goDate( const QString& ); + void showDate( const QDate &date ); + + QString localFileName(); + + bool queryClose(); + + void loadProfile( const QString & path ); + + void saveToProfile( const QString & path ) const; + + signals: + /** + Emitted when the "New" action is activated. + */ + void actionNew( const KURL &url = KURL() ); + + /** + When change is made to options dialog, the topwidget will catch this + and emit this signal which notifies all widgets which have registered + for notification to update their settings. + */ + void configChanged(); + + /** + Emitted when the topwidget is closing down, so that any attached + child windows can also close. + */ + void closingDown(); + + /** Indicates that a new resource was added */ + void resourceAdded( ResourceCalendar * ); + + public slots: + /** + Options dialog made a changed to the configuration. we catch this + and notify all widgets which need to update their configuration. + */ + void updateConfig(); + + void setDestinationPolicy(); + + void processIncidenceSelection( Incidence * ); + void keyBindings(); + + /** + Using the KConfig associated with the kapp variable, read in the + settings from the config file. + */ + void readSettings(); + + /** + Write current state to config file. + */ + void writeSettings(); + + /* Session management */ + void saveProperties( KConfig * ); + void readProperties( KConfig * ); + + void loadParts(); + + void importCalendar( const KURL &url ); + + protected slots: + + /** open new window */ + void file_new(); + + /** open a file, load it into the calendar. */ + void file_open(); + + /** open a file from the list of recent files. Also called from file_open() + after the URL is obtained from the user. */ + void file_open( const KURL &url ); + + /** import a calendar from another program like ical. */ + void file_icalimport(); + + /** open a calendar and add the contents to the current calendar. */ + void file_merge(); + + /** revert to saved */ + void file_revert(); + + /** delete or archive old entries in your calendar for speed/space. */ + void file_archive(); + + /** save a file with the current fileName. */ + void file_save(); + + /** save a file under a (possibly) different filename. */ + void file_saveas(); + + /** close a file, prompt for save if changes made. */ + void file_close(); + + /** Open kcontrol module for configuring date and time formats */ + void configureDateTime(); + + /** Show tip of the day */ + void showTip(); + + /** Show tip of the day */ + void showTipOnStart(); + + void downloadNewStuff(); + void uploadNewStuff(); + + void toggleResourceButtons(); + + void toggleDateNavigator(); + void toggleTodoView(); + void toggleEventViewer(); + void toggleResourceView(); + + /** called by the autoSaveTimer to automatically save the calendar */ + void checkAutoSave(); + + /** connected to CalendarView's signal which comes from the ArchiveDialog */ + void slotAutoArchivingSettingsModified(); + + /** called by the auto archive timer to automatically delete/archive events */ + void slotAutoArchive(); + + void configureDateTimeFinished(KProcess *); + + void setTitle(); + + void updateUndoAction( const QString & ); + + void updateRedoAction( const QString & ); + + void slotImportDialogFinished( ImportDialog * ); + + protected: + /** Get URL for saving. Opens FileDialog. */ + KURL getSaveURL(); + + void showStatusMessageOpen( const KURL &url, bool merge ); + + void initCalendar( Calendar *cal ); + + /** + Return widget used as parent for dialogs and message boxes. + */ + QWidget *dialogParent(); + + private slots: + void dumpText( const QString & ); // only for debugging purposes + + private: + class ActionStringsVisitor; + + /** Create all the actions. */ + void initActions(); + void enableIncidenceActions( bool enable ); + + KOrg::Part::List mParts; // List of parts loaded + KURL mURL; // URL of calendar file + QString mFile; // Local name of calendar file + QString mLastUrl; // URL of last loaded calendar. + + KTempFile *mTempFile; + QTimer *mAutoSaveTimer; // used if calendar is to be autosaved + QTimer *mAutoArchiveTimer; // used for the auto-archiving feature + + // list of all existing KOrganizer instances + static KOWindowList *mWindowList; + + // Actions + KRecentFilesAction *mRecent; + KToggleAction *mResourceButtonsAction; + + KToggleAction *mDateNavigatorShowAction; + KToggleAction *mTodoViewShowAction; + KToggleAction *mResourceViewShowAction; + KToggleAction *mEventViewerShowAction; +// KToggleAction *mToggleAlarmAction; + + KAction *mShowIncidenceAction; + KAction *mEditIncidenceAction; + KAction *mDeleteIncidenceAction; +// KAction *mAssignResourceAction; + + KAction *mCutAction; + KAction *mCopyAction; + KAction *mDeleteAction; + KAction *mNextXDays; + KAction *mPublishEvent; + KAction *mForwardEvent; + + KAction *mUndoAction; + KAction *mRedoAction; + + KSelectAction *mFilterAction; + + KXMLGUIClient *mGUIClient; + KActionCollection *mACollection; + CalendarView *mCalendarView; + KOrg::MainWindow *mMainWindow; + bool mIsPart; + + KONewStuff *mNewStuff; + bool mHtmlExportSync; + + // Either mCalendar *or* mCalendarResources is set. + Calendar *mCalendar; + CalendarResources *mCalendarResources; + + ResourceView *mResourceView; + + bool mIsClosing; +}; + +#endif diff --git a/korganizer/agendaview.cpp b/korganizer/agendaview.cpp new file mode 100644 index 000000000..c013faa82 --- /dev/null +++ b/korganizer/agendaview.cpp @@ -0,0 +1,36 @@ +/* + 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 "agendaview.h" + +#include <libkcal/calendarresources.h> + +using namespace KOrg; + +AgendaView::AgendaView(Calendar * cal, QWidget * parent, const char * name) : + KOEventView( cal, parent, name ) +{ + KCal::CalendarResources *calres = dynamic_cast<KCal::CalendarResources*>( cal ); + if ( calres ) { + connect( calres, SIGNAL(signalResourceAdded(ResourceCalendar *)), SLOT(resourcesChanged()) ); + connect( calres, SIGNAL(signalResourceModified( ResourceCalendar *)), SLOT(resourcesChanged()) ); + connect( calres, SIGNAL(signalResourceDeleted(ResourceCalendar *)), SLOT(resourcesChanged()) ); + } +} + +#include "agendaview.moc" diff --git a/korganizer/agendaview.h b/korganizer/agendaview.h new file mode 100644 index 000000000..5a1c84c6b --- /dev/null +++ b/korganizer/agendaview.h @@ -0,0 +1,43 @@ +/* + 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 KORG_AGENDAVIEW_H +#define KORG_AGENDAVIEW_H + +#include "koeventview.h" + +namespace KOrg { + +/** Base class for single/multi agenda views. */ +class AgendaView : public KOEventView +{ + Q_OBJECT + public: + AgendaView( Calendar *cal,QWidget *parent=0,const char *name=0 ); + + virtual void setTypeAheadReceiver( QObject * ) = 0; + + public slots: + virtual void finishTypeAhead() = 0; + + virtual void resourcesChanged() = 0; +}; + +} + +#endif diff --git a/korganizer/archivedialog.cpp b/korganizer/archivedialog.cpp new file mode 100644 index 000000000..89d7ecdd4 --- /dev/null +++ b/korganizer/archivedialog.cpp @@ -0,0 +1,237 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +// ArchiveDialog -- archive/delete past events. + +#include <qlabel.h> +#include <qlayout.h> +#include <qdatetime.h> +#include <qcheckbox.h> +#include <qwhatsthis.h> +#include <qhgroupbox.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kurlrequester.h> +#include <kmessagebox.h> +#include <kfiledialog.h> +#include <kurl.h> +#include <klineedit.h> +#include <kactivelabel.h> + +#include <libkdepim/kdateedit.h> + +#include "koprefs.h" + +#include "archivedialog.h" +#include "eventarchiver.h" +#include <knuminput.h> +#include <qbuttongroup.h> +#include <qradiobutton.h> +#include "archivedialog.moc" + +ArchiveDialog::ArchiveDialog(Calendar *cal,QWidget *parent, const char *name) + : KDialogBase (Plain,i18n("Archive/Delete Past Events and To-dos"), + User1|Cancel,User1,parent,name,false,true, + i18n("&Archive")) +{ + mCalendar = cal; + + QFrame *topFrame = plainPage(); + QVBoxLayout *topLayout = new QVBoxLayout(topFrame); + topLayout->setSpacing(spacingHint()); + + KActiveLabel *descLabel = new KActiveLabel( + i18n("Archiving saves old items into the given file and " + "then deletes them in the current calendar. If the archive file " + "already exists they will be added. " + "(<a href=\"whatsthis:In order to add an archive " + "to your calendar, use the "Merge Calendar" function. " + "You can view an archive by opening it in KOrganizer like any " + "other calendar. It is not saved in a special format, but as " + "vCalendar.\">How to restore</a>)"), + topFrame); + topLayout->addWidget(descLabel); + + QButtonGroup* radioBG = new QButtonGroup( this ); + radioBG->hide(); // just for the exclusive behavior + connect( radioBG, SIGNAL( clicked( int ) ), SLOT( slotActionChanged() ) ); + + QHBoxLayout *dateLayout = new QHBoxLayout(0); + mArchiveOnceRB = new QRadioButton(i18n("Archive now items older than:"),topFrame); + dateLayout->addWidget(mArchiveOnceRB); + radioBG->insert(mArchiveOnceRB); + mDateEdit = new KDateEdit(topFrame); + QWhatsThis::add(mDateEdit, + i18n("The date before which items should be archived. All older events and to-dos will " + "be saved and deleted, the newer (and events exactly on that date) will be kept.")); + dateLayout->addWidget(mDateEdit); + topLayout->addLayout(dateLayout); + + // Checkbox, numinput and combo for auto-archiving + // (similar to kmail's mExpireFolderCheckBox/mReadExpiryTimeNumInput in kmfolderdia.cpp) + QHBox* autoArchiveHBox = new QHBox(topFrame); + topLayout->addWidget(autoArchiveHBox); + mAutoArchiveRB = new QRadioButton(i18n("Automaticall&y archive items older than:"), autoArchiveHBox); + radioBG->insert(mAutoArchiveRB); + QWhatsThis::add(mAutoArchiveRB, + i18n("If this feature is enabled, KOrganizer will regularly check if events and to-dos have to be archived; " + "this means you will not need to use this dialog box again, except to change the settings.")); + + mExpiryTimeNumInput = new KIntNumInput(autoArchiveHBox); + mExpiryTimeNumInput->setRange(1, 500, 1, false); + mExpiryTimeNumInput->setEnabled(false); + mExpiryTimeNumInput->setValue(7); + QWhatsThis::add(mExpiryTimeNumInput, + i18n("The age of the events and to-dos to archive. All older items " + "will be saved and deleted, the newer will be kept.")); + + mExpiryUnitsComboBox = new QComboBox(autoArchiveHBox); + // Those items must match the "Expiry Unit" enum in the kcfg file! + mExpiryUnitsComboBox->insertItem(i18n("Day(s)")); + mExpiryUnitsComboBox->insertItem(i18n("Week(s)")); + mExpiryUnitsComboBox->insertItem(i18n("Month(s)")); + mExpiryUnitsComboBox->setEnabled(false); + + QHBoxLayout *fileLayout = new QHBoxLayout(0); + fileLayout->setSpacing(spacingHint()); + QLabel *l = new QLabel(i18n("Archive &file:"),topFrame); + fileLayout->addWidget(l); + mArchiveFile = new KURLRequester(KOPrefs::instance()->mArchiveFile,topFrame); + mArchiveFile->setMode(KFile::File); + mArchiveFile->setFilter(i18n("*.ics|iCalendar Files")); + QWhatsThis::add(mArchiveFile, + i18n("The path of the archive. The events and to-dos will be added to the " + "archive file, so any events that are already in the file " + "will not be modified or deleted. You can later load or merge the " + "file like any other calendar. It is not saved in a special " + "format, it uses the iCalendar format. ")); + l->setBuddy(mArchiveFile->lineEdit()); + fileLayout->addWidget(mArchiveFile); + topLayout->addLayout(fileLayout); + + QHGroupBox *typeBox = new QHGroupBox( i18n("Type of Items to Archive"), + topFrame); + mEvents = new QCheckBox( i18n("&Events"), typeBox ); + mTodos = new QCheckBox( i18n("&To-dos"), typeBox ); + topLayout->addWidget( typeBox ); + QWhatsThis::add( typeBox, i18n("Here you can select which items " + "should be archived. Events are archived if they " + "ended before the date given above; to-dos are archived if " + "they were finished before the date.") ); + + mDeleteCb = new QCheckBox(i18n("&Delete only, do not save"), + topFrame); + QWhatsThis::add(mDeleteCb, + i18n("Select this option to delete old events and to-dos without saving them. " + "It is not possible to recover the events later.")); + topLayout->addWidget(mDeleteCb); + connect(mDeleteCb, SIGNAL(toggled(bool)), mArchiveFile, SLOT(setDisabled(bool))); + connect(mDeleteCb, SIGNAL(toggled(bool)), this, SLOT(slotEnableUser1())); + connect(mArchiveFile->lineEdit(),SIGNAL(textChanged ( const QString & )), + this,SLOT(slotEnableUser1())); + + // Load settings from KOPrefs + mExpiryTimeNumInput->setValue( KOPrefs::instance()->mExpiryTime ); + mExpiryUnitsComboBox->setCurrentItem( KOPrefs::instance()->mExpiryUnit ); + mDeleteCb->setChecked( KOPrefs::instance()->mArchiveAction == KOPrefs::actionDelete ); + mEvents->setChecked( KOPrefs::instance()->mArchiveEvents ); + mTodos->setChecked( KOPrefs::instance()->mArchiveTodos ); + + slotEnableUser1(); + + // The focus should go to a useful field by default, not to the top richtext-label + if ( KOPrefs::instance()->mAutoArchive ) { + mAutoArchiveRB->setChecked( true ); + mAutoArchiveRB->setFocus(); + } else { + mArchiveOnceRB->setChecked( true ); + mArchiveOnceRB->setFocus(); + } + slotActionChanged(); +} + +ArchiveDialog::~ArchiveDialog() +{ +} + +void ArchiveDialog::slotEnableUser1() +{ + bool state = ( mDeleteCb->isChecked() || + !mArchiveFile->lineEdit()->text().isEmpty() ); + enableButton(KDialogBase::User1,state); +} + +void ArchiveDialog::slotActionChanged() +{ + mDateEdit->setEnabled( mArchiveOnceRB->isChecked() ); + mExpiryTimeNumInput->setEnabled( mAutoArchiveRB->isChecked() ); + mExpiryUnitsComboBox->setEnabled( mAutoArchiveRB->isChecked() ); +} + +// Archive old events +void ArchiveDialog::slotUser1() +{ + EventArchiver archiver; + connect( &archiver, SIGNAL( eventsDeleted() ), this, SLOT( slotEventsDeleted() ) ); + + KOPrefs::instance()->mAutoArchive = mAutoArchiveRB->isChecked(); + KOPrefs::instance()->mExpiryTime = mExpiryTimeNumInput->value(); + KOPrefs::instance()->mExpiryUnit = mExpiryUnitsComboBox->currentItem(); + + if (mDeleteCb->isChecked()) { + KOPrefs::instance()->mArchiveAction = KOPrefs::actionDelete; + } else { + KOPrefs::instance()->mArchiveAction = KOPrefs::actionArchive; + + // Get destination URL + KURL destUrl( mArchiveFile->url() ); + if ( !destUrl.isValid() ) { + KMessageBox::sorry(this,i18n("The archive file name is not valid.\n")); + return; + } + // Force filename to be ending with vCalendar extension + QString filename = destUrl.fileName(); + if (!filename.endsWith(".vcs") && !filename.endsWith(".ics")) { + filename.append(".ics"); + destUrl.setFileName(filename); + } + + KOPrefs::instance()->mArchiveFile = destUrl.url(); + } + if ( KOPrefs::instance()->mAutoArchive ) { + archiver.runAuto( mCalendar, this, true /*with gui*/ ); + emit autoArchivingSettingsModified(); + accept(); + } + else + archiver.runOnce( mCalendar, mDateEdit->date(), this ); +} + +void ArchiveDialog::slotEventsDeleted() +{ + emit eventsDeleted(); + if ( !KOPrefs::instance()->mAutoArchive ) + accept(); +} diff --git a/korganizer/archivedialog.h b/korganizer/archivedialog.h new file mode 100644 index 000000000..3f5c2247f --- /dev/null +++ b/korganizer/archivedialog.h @@ -0,0 +1,73 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef _ARCHIVE_DLG +#define _ARCHIVE_DLG + +#include <kdialogbase.h> + +class QRadioButton; +class QComboBox; +class KIntNumInput; +class KURLRequester; +class KDateEdit; +class QCheckBox; + +namespace KCal { +class Calendar; +} +using namespace KCal; + +class ArchiveDialog : public KDialogBase +{ + Q_OBJECT + public: + ArchiveDialog(Calendar *calendar,QWidget *parent=0, const char *name=0); + virtual ~ArchiveDialog(); + + signals: + // connected by KODialogManager to CalendarView + void eventsDeleted(); + void autoArchivingSettingsModified(); + + protected slots: + void slotEventsDeleted(); + void slotUser1(); + void slotEnableUser1(); + void slotActionChanged(); + + private: + KURLRequester *mArchiveFile; + KDateEdit *mDateEdit; + QCheckBox *mDeleteCb; + QRadioButton *mArchiveOnceRB; + QRadioButton *mAutoArchiveRB; + KIntNumInput *mExpiryTimeNumInput; + QComboBox *mExpiryUnitsComboBox; + QCheckBox *mEvents; + QCheckBox *mTodos; + + Calendar *mCalendar; +}; + +#endif diff --git a/korganizer/calendarview.cpp b/korganizer/calendarview.cpp new file mode 100644 index 000000000..75e7ee434 --- /dev/null +++ b/korganizer/calendarview.cpp @@ -0,0 +1,2291 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1997, 1998, 1999 + Preston Brown (preston.brown@yale.edu) + Fester Zigterman (F.J.F.ZigtermanRustenburg@student.utwente.nl) + Ian Dawes (iadawes@globalserve.net) + Laszlo Boloni (boloni@cs.purdue.edu) + + Copyright (c) 2000, 2001, 2002, 2003, 2004 + Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "calendarview.h" + +#ifndef KORG_NOPRINTER +#include "calprinter.h" +#endif +#include "koeventeditor.h" +#include "kotodoeditor.h" +#include "kojournaleditor.h" +#include "koprefs.h" +#include "koeventviewerdialog.h" +#include "publishdialog.h" +#include "koglobals.h" +#include "koviewmanager.h" +#include "koagendaview.h" +#include "kodialogmanager.h" +#include "statusdialog.h" +#include "datenavigatorcontainer.h" +#include "kotodoview.h" +#include "datenavigator.h" +#include "resourceview.h" +#include "navigatorbar.h" +#include "history.h" +#include "kogroupware.h" +#include "freebusymanager.h" +#include "komonthview.h" +#include "datechecker.h" +#include "komessagebox.h" +#include "exportwebdialog.h" +#include "kocorehelper.h" +#include "incidencechanger.h" +#include "kholidays.h" +#include "mailscheduler.h" +#include "komailclient.h" +#include "multiagendaview.h" + +#include <libkcal/vcaldrag.h> +#include <libkcal/icaldrag.h> +#include <libkcal/icalformat.h> +#include <libkcal/vcalformat.h> +#include <libkcal/scheduler.h> +#include <libkcal/calendarlocal.h> +#include <libkcal/journal.h> +#include <libkcal/calfilter.h> +#include <libkcal/attendee.h> +#include <libkcal/dndfactory.h> +#include <libkcal/freebusy.h> +#include <libkcal/filestorage.h> +#include <libkcal/calendarresources.h> +#include <libkcal/calendarnull.h> +#include <libkcal/htmlexportsettings.h> + +#include <kglobal.h> +#include <kdebug.h> +#include <kstandarddirs.h> +#include <kfiledialog.h> +#include <kmessagebox.h> +#include <knotifyclient.h> +#include <kconfig.h> +#include <krun.h> +#include <kdirwatch.h> + +#include <qapplication.h> +#include <qclipboard.h> +#include <qcursor.h> +#include <qmultilineedit.h> +#include <qtimer.h> +#include <qwidgetstack.h> +#include <qptrlist.h> +#include <qfile.h> +#include <qlayout.h> +#ifndef KORG_NOSPLITTER +#include <qsplitter.h> +#endif +#include <qvbox.h> +#include <qwhatsthis.h> + +#include <stdlib.h> +#include <assert.h> + +using namespace KOrg; + +CalendarView::CalendarView( QWidget *parent, const char *name ) + : CalendarViewBase( parent, name ), + mHistory( 0 ), + mCalendar( CalendarNull::self() ), + mChanger( 0 ) +{ + kdDebug(5850) << "CalendarView::CalendarView( Calendar )" << endl; + + mViewManager = new KOViewManager( this ); + mDialogManager = new KODialogManager( this ); + + mModified = false; + mReadOnly = false; + mSelectedIncidence = 0; + + mFilters.setAutoDelete( true ); + + mExtensions.setAutoDelete( true ); + + mNavigator = new DateNavigator( this ); + mDateChecker = new DateChecker( this ); + + QBoxLayout *topLayout = new QVBoxLayout( this ); + +#ifndef KORG_NOSPLITTER + // create the main layout frames. + mPanner = new QSplitter( QSplitter::Horizontal, this, + "CalendarView::Panner" ); + topLayout->addWidget( mPanner ); + + mLeftSplitter = new QSplitter( QSplitter::Vertical, mPanner, + "CalendarView::LeftFrame" ); +// mPanner->setResizeMode( mLeftSplitter, QSplitter::Stretch ); + + mDateNavigator = new DateNavigatorContainer( mLeftSplitter, + "CalendarView::DateNavigator" ); + +// mLeftSplitter->setResizeMode( mDateNavigator, QSplitter::Stretch ); + mLeftSplitter->setCollapsible( mDateNavigator, true ); + mTodoList = new KOTodoView( CalendarNull::self(), mLeftSplitter, "todolist" ); + + mEventViewer = new KOEventViewer( mLeftSplitter,"EventViewer" ); + + QVBox *rightBox = new QVBox( mPanner ); + mNavigatorBar = new NavigatorBar( rightBox ); + mRightFrame = new QWidgetStack( rightBox ); + rightBox->setStretchFactor( mRightFrame, 1 ); + + mLeftFrame = mLeftSplitter; +#else + QWidget *mainBox; + QWidget *leftFrame; + + if ( KOPrefs::instance()->mVerticalScreen ) { + mainBox = new QVBox( this ); + leftFrame = new QHBox( mainBox ); + } else { + mainBox = new QHBox( this ); + leftFrame = new QVBox( mainBox ); + } + + topLayout->addWidget( mainBox ); + + mDateNavigator = new KDateNavigator( leftFrame, true, + "CalendarView::DateNavigator", + QDate::currentDate() ); + mTodoList = new KOTodoView( CalendarNull::self(), leftFrame, "todolist" ); + + mEventViewer = new KOEventViewer ( leftFrame, "EventViewer" ); + + QWidget *rightBox = new QWidget( mainBox ); + QBoxLayout *rightLayout = new QVBoxLayout( rightBox ); + + mNavigatorBar = new NavigatorBar( QDate::currentDate(), rightBox ); + rightLayout->addWidget( mNavigatorBar ); + + mRightFrame = new QWidgetStack( rightBox ); + rightLayout->addWidget( mRightFrame ); + + mLeftFrame = leftFrame; + + if ( KOPrefs::instance()->mVerticalScreen ) { +// mTodoList->setFixedHeight( 60 ); + mTodoList->setFixedHeight( mDateNavigator->sizeHint().height() ); + } +#endif + + connect( mNavigator, SIGNAL( datesSelected( const KCal::DateList & ) ), + SLOT( showDates( const KCal::DateList & ) ) ); + connect( mNavigator, SIGNAL( datesSelected( const KCal::DateList & ) ), + mDateNavigator, SLOT( selectDates( const KCal::DateList & ) ) ); + + connect( mNavigatorBar, SIGNAL( goPrevYear() ), + mNavigator, SLOT( selectPreviousYear() ) ); + connect( mNavigatorBar, SIGNAL( goNextYear() ), + mNavigator, SLOT( selectNextYear() ) ); + connect( mNavigatorBar, SIGNAL( goPrevMonth() ), + mNavigator, SLOT( selectPreviousMonth() ) ); + connect( mNavigatorBar, SIGNAL( goNextMonth() ), + mNavigator, SLOT( selectNextMonth() ) ); + connect( mNavigatorBar, SIGNAL( goMonth(int) ), + mNavigator, SLOT( selectMonth(int) ) ); + + connect( mNavigator, SIGNAL( datesSelected( const KCal::DateList & ) ), + mNavigatorBar, SLOT( selectDates( const KCal::DateList & ) ) ); + + connect( mDateNavigator, SIGNAL( weekClicked( const QDate & ) ), + mNavigator, SLOT( selectWeek( const QDate & ) ) ); + + connect( mDateNavigator, SIGNAL( goPrevYear() ), + mNavigator, SLOT( selectPreviousYear() ) ); + connect( mDateNavigator, SIGNAL( goNextYear() ), + mNavigator, SLOT( selectNextYear() ) ); + connect( mDateNavigator, SIGNAL( goPrevMonth() ), + mNavigator, SLOT( selectPreviousMonth() ) ); + connect( mDateNavigator, SIGNAL( goNextMonth() ), + mNavigator, SLOT( selectNextMonth() ) ); + connect( mDateNavigator, SIGNAL( goMonth(int) ), + mNavigator, SLOT( selectMonth(int) ) ); + + connect( mDateNavigator, SIGNAL( goPrevious() ), + mNavigator, SLOT( selectPrevious() ) ); + connect( mDateNavigator, SIGNAL( goNext() ), + mNavigator, SLOT( selectNext() ) ); + + connect( mDateNavigator, SIGNAL( datesSelected( const KCal::DateList & ) ), + mNavigator, SLOT( selectDates( const KCal::DateList & ) ) ); + + connect( mDateNavigator, SIGNAL(incidenceDropped(Incidence*, const QDate&)), + SLOT( addIncidenceOn( Incidence *, const QDate & ) ) ); + connect( mDateNavigator, SIGNAL(incidenceDroppedMove(Incidence*,const QDate&)), + SLOT( moveIncidenceTo( Incidence *, const QDate & ) ) ); + + connect( mDateChecker, SIGNAL( dayPassed( const QDate & ) ), + mTodoList, SLOT( dayPassed( const QDate & ) ) ); + connect( mDateChecker, SIGNAL( dayPassed( const QDate & ) ), + SIGNAL( dayPassed( const QDate & ) ) ); + connect( mDateChecker, SIGNAL( dayPassed( const QDate & ) ), + mDateNavigator, SLOT( updateToday() ) ); + + connect( this, SIGNAL( configChanged() ), + mDateNavigator, SLOT( updateConfig() ) ); + + connect( this, SIGNAL( incidenceSelected(Incidence *) ), + mEventViewer, SLOT ( setIncidence (Incidence *) ) ); + + //TODO: do a pretty Summary, + QString s; + s = i18n( "<p><em>No Item Selected</em></p>" + "<p>Select an event, to-do or journal entry to view its details " + "here.</p>"); + + mEventViewer->setDefaultText( s ); + QWhatsThis::add( mEventViewer, + i18n( "View the details of events, journal entries or to-dos " + "selected in KOrganizer's main view here." ) ); + mEventViewer->setIncidence( 0 ); + + mViewManager->connectTodoView( mTodoList ); + mViewManager->connectView( mTodoList ); + + KOGlobals::self()-> + setHolidays( new KHolidays( KOPrefs::instance()->mHolidays ) ); + + connect( QApplication::clipboard(), SIGNAL( dataChanged() ), + SLOT( checkClipboard() ) ); + + connect( mTodoList, SIGNAL( incidenceSelected( Incidence * ) ), + SLOT( processTodoListSelection( Incidence * ) ) ); + disconnect( mTodoList, SIGNAL( incidenceSelected( Incidence * ) ), + this, SLOT( processMainViewSelection( Incidence * ) ) ); + + kdDebug(5850) << "CalendarView::CalendarView() done" << endl; +} + +CalendarView::~CalendarView() +{ + kdDebug(5850) << "~CalendarView()" << endl; + + mCalendar->unregisterObserver( this ); + + delete mDialogManager; + delete mViewManager; + delete mEventViewer; + kdDebug(5850) << "~CalendarView() done" << endl; +} + +void CalendarView::setCalendar( Calendar *cal ) +{ + kdDebug(5850)<<"CalendarView::setCalendar"<<endl; + mCalendar = cal; + + delete mHistory; + mHistory = new History( mCalendar ); + connect( mHistory, SIGNAL( undone() ), SLOT( updateView() ) ); + connect( mHistory, SIGNAL( redone() ), SLOT( updateView() ) ); + + if ( mChanger ) delete mChanger; + setIncidenceChanger( new IncidenceChanger( mCalendar, this ) ); + + mCalendar->registerObserver( this ); + + mDateNavigator->setCalendar( mCalendar ); + + mTodoList->setCalendar( mCalendar ); +} + +void CalendarView::setIncidenceChanger( IncidenceChangerBase *changer ) +{ + mChanger = changer; + emit newIncidenceChanger( mChanger ); + connect( mChanger, SIGNAL( incidenceAdded( Incidence* ) ), + this, SLOT( incidenceAdded( Incidence* ) ) ); + connect( mChanger, SIGNAL( incidenceChanged( Incidence*, Incidence*, int ) ), + this, SLOT( incidenceChanged( Incidence*, Incidence*, int ) ) ); + connect( mChanger, SIGNAL( incidenceChanged( Incidence*, Incidence* ) ), + this, SLOT( incidenceChanged( Incidence*, Incidence* ) ) ); + connect( mChanger, SIGNAL( incidenceToBeDeleted( Incidence * ) ), + this, SLOT( incidenceToBeDeleted( Incidence * ) ) ); + connect( mChanger, SIGNAL( incidenceDeleted( Incidence * ) ), + this, SLOT( incidenceDeleted( Incidence * ) ) ); + + connect( mChanger, SIGNAL( schedule( Scheduler::Method, Incidence*) ), + this, SLOT( schedule( Scheduler::Method, Incidence*) ) ); + + + connect( this, SIGNAL( cancelAttendees( Incidence * ) ), + mChanger, SLOT( cancelAttendees( Incidence * ) ) ); +} + +Calendar *CalendarView::calendar() +{ + if ( mCalendar ) return mCalendar; + else return CalendarNull::self(); +} + +KOIncidenceEditor *CalendarView::editorDialog( Incidence *incidence ) const +{ + if (mDialogList.find(incidence) != mDialogList.end ()) + return mDialogList[incidence]; + else return 0; +} + +QDate CalendarView::startDate() +{ + DateList dates = mNavigator->selectedDates(); + + return dates.first(); +} + +QDate CalendarView::endDate() +{ + DateList dates = mNavigator->selectedDates(); + + return dates.last(); +} + + +bool CalendarView::openCalendar(const QString& filename, bool merge) +{ + kdDebug(5850) << "CalendarView::openCalendar(): " << filename << endl; + + if (filename.isEmpty()) { + kdDebug(5850) << "CalendarView::openCalendar(): Error! Empty filename." << endl; + return false; + } + + if (!QFile::exists(filename)) { + kdDebug(5850) << "CalendarView::openCalendar(): Error! File '" << filename + << "' doesn't exist." << endl; + } + + bool loadedSuccesfully = true; + if ( !merge ) { + mCalendar->close(); + CalendarLocal *cl = dynamic_cast<CalendarLocal*>( mCalendar ); + if ( cl ) { + loadedSuccesfully = cl->load( filename ); + } else { + CalendarResources *cr = dynamic_cast<CalendarResources*>( mCalendar ); + assert( cr ); // otherwise something is majorly wrong + // openCalendar called without merge and a filename, what should we do? + return false; + } + } else { + // merge in a file + FileStorage storage( mCalendar ); + storage.setFileName( filename ); + loadedSuccesfully = storage.load(); + } + + if ( loadedSuccesfully ) { + if ( merge ) + setModified( true ); + else { + setModified( false ); + mViewManager->setDocumentId( filename ); + mTodoList->setDocumentId( filename ); + } + updateCategories(); + updateView(); + return true; + } else { + // while failing to load, the calendar object could + // have become partially populated. Clear it out. + if ( !merge ) mCalendar->close(); + + KMessageBox::error(this,i18n("Could not load calendar '%1'.").arg(filename)); + + return false; + } +} + +bool CalendarView::saveCalendar( const QString& filename ) +{ + kdDebug(5850) << "CalendarView::saveCalendar(): " << filename << endl; + + // Store back all unsaved data into calendar object + mViewManager->currentView()->flushView(); + + FileStorage storage( mCalendar ); + storage.setFileName( filename ); + storage.setSaveFormat( new ICalFormat ); + + bool success = storage.save(); + + if ( !success ) { + return false; + } + + return true; +} + +void CalendarView::closeCalendar() +{ + kdDebug(5850) << "CalendarView::closeCalendar()" << endl; + + // child windows no longer valid + emit closingDown(); + + mCalendar->close(); + setModified( false ); + updateView(); +} + +void CalendarView::archiveCalendar() +{ + mDialogManager->showArchiveDialog(); +} + + +void CalendarView::readSettings() +{ +// kdDebug(5850) << "CalendarView::readSettings()" << endl; + + QString str; + + // read settings from the KConfig, supplying reasonable + // defaults where none are to be found + + KConfig *config = KOGlobals::self()->config(); + +#ifndef KORG_NOSPLITTER + config->setGroup( "KOrganizer Geometry" ); + + QValueList<int> sizes = config->readIntListEntry( "Separator1" ); + if ( sizes.count() != 2 ) { + sizes << mDateNavigator->minimumSizeHint().width(); + sizes << 300; + } + mPanner->setSizes( sizes ); + + sizes = config->readIntListEntry( "Separator2" ); + mLeftSplitter->setSizes( sizes ); +#endif + + mEventViewer->readSettings( config ); + + mViewManager->readSettings( config ); + mTodoList->restoreLayout( config, QString( "Todo Layout" ) ); + + readFilterSettings( config ); + + config->setGroup( "Views" ); + int dateCount = config->readNumEntry( "ShownDatesCount", 7 ); + if ( dateCount == 7 ) mNavigator->selectWeek(); + else mNavigator->selectDates( mNavigator->selectedDates().first(), dateCount ); +} + + +void CalendarView::writeSettings() +{ +// kdDebug(5850) << "CalendarView::writeSettings" << endl; + + KConfig *config = KOGlobals::self()->config(); + +#ifndef KORG_NOSPLITTER + config->setGroup( "KOrganizer Geometry" ); + + QValueList<int> list = mPanner->sizes(); + config->writeEntry( "Separator1", list ); + + list = mLeftSplitter->sizes(); + config->writeEntry( "Separator2", list ); +#endif + mEventViewer->writeSettings( config ); + mViewManager->writeSettings( config ); + mTodoList->saveLayout( config, QString( "Todo Layout" ) ); + + KOPrefs::instance()->writeConfig(); + + writeFilterSettings( config ); + + config->setGroup( "Views" ); + config->writeEntry( "ShownDatesCount", mNavigator->selectedDates().count() ); + + config->sync(); +} + +void CalendarView::readFilterSettings( KConfig *config ) +{ +// kdDebug(5850) << "CalendarView::readFilterSettings()" << endl; + + mFilters.clear(); + + config->setGroup( "General" ); + // FIXME: Move the filter loading and saving to the CalFilter class in libkcal + QStringList filterList = config->readListEntry ("CalendarFilters" ); + QString currentFilter = config->readEntry( "Current Filter" ); + + QStringList::ConstIterator it = filterList.begin(); + QStringList::ConstIterator end = filterList.end(); + while( it != end ) { +// kdDebug(5850) << " filter: " << (*it) << endl; + CalFilter *filter; + filter = new CalFilter( *it ); + config->setGroup( "Filter_" + (*it) ); + filter->setCriteria( config->readNumEntry( "Criteria", 0 ) ); + filter->setCategoryList( config->readListEntry( "CategoryList" ) ); + if ( filter->criteria() & KCal::CalFilter::HideTodosWithoutAttendeeInEmailList ) + filter->setEmailList( KOPrefs::instance()->allEmails() ); + filter->setCompletedTimeSpan( config->readNumEntry( "HideTodoDays", 0 ) ); + mFilters.append( filter ); + + ++it; + } + + config->setGroup( "General" ); + int pos = filterList.findIndex( currentFilter ); + mCurrentFilter = 0; + if ( pos>=0 ) { + mCurrentFilter = mFilters.at( pos ); + } + updateFilter(); +} + +void CalendarView::writeFilterSettings( KConfig *config ) +{ +// kdDebug(5850) << "CalendarView::writeFilterSettings()" << endl; + + QStringList filterList; + + CalFilter *filter = mFilters.first(); + while( filter ) { +// kdDebug(5850) << " fn: " << filter->name() << endl; + filterList << filter->name(); + config->setGroup( "Filter_" + filter->name() ); + config->writeEntry( "Criteria", filter->criteria() ); + config->writeEntry( "CategoryList", filter->categoryList() ); + config->writeEntry( "HideTodoDays", filter->completedTimeSpan() ); + filter = mFilters.next(); + } + config->setGroup( "General" ); + config->writeEntry( "CalendarFilters", filterList ); + if ( mCurrentFilter ) { + config->writeEntry( "Current Filter", mCurrentFilter->name() ); + } else { + config->writeEntry( "Current Filter", QString::null ); + } +} + + +void CalendarView::goDate( const QDate& date ) +{ + mNavigator->selectDate( date ); +} + +void CalendarView::showDate(const QDate & date) +{ + int dateCount = mNavigator->datesCount(); + if ( dateCount == 7 ) + mNavigator->selectWeek( date ); + else + mNavigator->selectDates( date, dateCount ); +} + +void CalendarView::goToday() +{ + mNavigator->selectToday(); +} + +void CalendarView::goNext() +{ + if ( dynamic_cast<KOMonthView*>( mViewManager->currentView() ) ) + mNavigator->selectNextMonth(); + else + mNavigator->selectNext(); +} + +void CalendarView::goPrevious() +{ + if ( dynamic_cast<KOMonthView*>( mViewManager->currentView() ) ) + mNavigator->selectPreviousMonth(); + else + mNavigator->selectPrevious(); +} + +void CalendarView::updateConfig( const QCString& receiver) +{ + if ( receiver != "korganizer" ) return; + kdDebug(5850) << "CalendarView::updateConfig()" << endl; + + KOGlobals::self()-> + setHolidays( new KHolidays( KOPrefs::instance()->mHolidays ) ); + + QString tz( mCalendar->timeZoneId() ); + // Only set a new time zone if it changed. This prevents the window + // from being modified on start + if ( tz != KOPrefs::instance()->mTimeZoneId ) { + + const QString question( i18n("The timezone setting was changed. Do you want to keep the absolute time of " + "the items in your calendar, which will show them to be at a different time than " + "before, or move them to be at the old time also in the new timezone?") ); + int rc = KMessageBox::questionYesNo( this, question, + i18n("Keep Absolute Times?"), + KGuiItem(i18n("Keep Times")), + KGuiItem(i18n("Move Times")), + "calendarKeepAbsoluteTimes"); + if ( rc == KMessageBox::Yes ) { + // user wants us to shift + mCalendar->setTimeZoneIdViewOnly( KOPrefs::instance()->mTimeZoneId ); + } else { + // only set the new timezone, wihtout shifting events, they will be + // interpreted as being in the new timezone now + mCalendar->setTimeZoneId( KOPrefs::instance()->mTimeZoneId ); + } + } + 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 ); + + // To make the "fill window" configurations work + mViewManager->raiseCurrentView(); +} + + +void CalendarView::incidenceAdded( Incidence *incidence ) +{ + setModified( true ); + history()->recordAdd( incidence ); + changeIncidenceDisplay( incidence, KOGlobals::INCIDENCEADDED ); + updateUnmanagedViews(); + checkForFilteredChange( incidence ); +} + +void CalendarView::incidenceChanged( Incidence *oldIncidence, + Incidence *newIncidence ) +{ + incidenceChanged( oldIncidence, newIncidence, KOGlobals::UNKNOWN_MODIFIED ); +} + +void CalendarView::incidenceChanged( Incidence *oldIncidence, + Incidence *newIncidence, int what ) +{ + // 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 ); + } + setModified( true ); + history()->recordEdit( oldIncidence, newIncidence ); + + // 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 ) ) { + + Todo *todo = static_cast<Todo *>(newIncidence); + if ( todo->isCompleted() + || what == KOGlobals::COMPLETION_MODIFIED_WITH_RECURRENCE ) { + QString timeStr = KGlobal::locale()->formatTime( QTime::currentTime() ); + QString description = i18n( "To-do completed: %1 (%2)" ).arg( + newIncidence->summary() ).arg( timeStr ); + + Journal::List journals = calendar()->journals( QDate::currentDate() ); + Journal *journal; + + if ( journals.isEmpty() ) { + journal = new Journal(); + journal->setDtStart( QDateTime::currentDateTime() ); + + QString dateStr = KGlobal::locale()->formatDate( QDate::currentDate() ); + journal->setSummary( i18n("Journal of %1").arg( dateStr ) ); + journal->setDescription( description ); + + if ( !mChanger->addIncidence( journal, this ) ) { + KODialogManager::errorSaveIncidence( this, journal ); + delete journal; + return; + } + + } else { // journal list is not empty + journal = *(journals.at(0)); + Journal *oldJournal = journal->clone(); + journal->setDescription( journal->description().append( "\n" + description ) ); + + if ( !mChanger->changeIncidence( oldJournal, journal ) ) { + KODialogManager::errorSaveIncidence( this, journal ); + delete journal; + return; + } + } + } + } + + changeIncidenceDisplay( newIncidence, KOGlobals::INCIDENCEEDITED ); + updateUnmanagedViews(); + checkForFilteredChange( newIncidence ); +} + +void CalendarView::incidenceToBeDeleted( Incidence *incidence ) +{ + KOIncidenceEditor *tmp = editorDialog( incidence ); + if (tmp) { + kdDebug(5850) << "Incidence to be deleted and open in editor" << endl; + tmp->delayedDestruct(); + } + setModified( true ); + history()->recordDelete( incidence ); +// changeIncidenceDisplay( incidence, KOGlobals::INCIDENCEDELETED ); + updateUnmanagedViews(); +} + +void CalendarView::incidenceDeleted( Incidence *incidence ) +{ + changeIncidenceDisplay( incidence, KOGlobals::INCIDENCEDELETED ); + updateUnmanagedViews(); +} + +void CalendarView::checkForFilteredChange( Incidence *incidence ) +{ + CalFilter *filter = calendar()->filter(); + if ( filter && !filter->filterIncidence( incidence ) ) { + // Incidence is filtered and thus not shown in the view, tell the + // user so that he isn't surprised if his new event doesn't show up + KMessageBox::information( this, i18n("The item \"%1\" is filtered by " + "your current filter rules, so it will be hidden and not " + "appear in the view.").arg( incidence->summary() ), + i18n("Filter Applied"), "ChangedIncidenceFiltered" ); + } +} + +void CalendarView::startMultiModify( const QString &text ) +{ + history()->startMultiModify( text ); +} + +void CalendarView::endMultiModify() +{ + history()->endMultiModify(); +} + + +void CalendarView::changeIncidenceDisplay( Incidence *incidence, int action ) +{ + mDateNavigator->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 ); + } else { + mViewManager->currentView()->updateView(); + if ( mTodoList ) mTodoList->updateView(); + } +} + + +void CalendarView::updateView(const QDate &start, const QDate &end) +{ + mTodoList->updateView(); + mViewManager->updateView(start, end); + mDateNavigator->updateView(); +} + +void CalendarView::updateView() +{ + DateList tmpList = mNavigator->selectedDates(); + + // We assume that the navigator only selects consecutive days. + updateView( tmpList.first(), tmpList.last() ); +} + +void CalendarView::updateUnmanagedViews() +{ + mDateNavigator->updateDayMatrix(); +} + +int CalendarView::msgItemDelete( Incidence *incidence ) +{ + return KMessageBox::warningContinueCancel(this, + i18n("The item \"%1\" will be permanently deleted.").arg( incidence->summary() ), + i18n("KOrganizer Confirmation"), KGuiItem(i18n("&Delete"),"editdelete")); +} + + +void CalendarView::edit_cut() +{ + Incidence *incidence = selectedIncidence(); + + if ( !incidence || !mChanger ) { + KNotifyClient::beep(); + return; + } + mChanger->cutIncidence( incidence ); +} + +void CalendarView::edit_copy() +{ + Incidence *incidence = selectedIncidence(); + + if (!incidence) { + KNotifyClient::beep(); + return; + } + DndFactory factory( mCalendar ); + if ( !factory.copyIncidence( incidence ) ) { + KNotifyClient::beep(); + } +} + +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 + + QDate date; + // create an invalid time to check if we got a new time for the eevent + QTime time(-1,-1); + QDateTime startDT, endDT; + bool useEndTime = false; + + KOAgendaView *aView = mViewManager->agendaView(); + if (aView && aView->selectionStart().isValid()) { + date = aView->selectionStart().date(); + startDT = aView->selectionStart(); + endDT = aView->selectionEnd(); + useEndTime = !aView->selectedIsSingleCell(); + if (!aView->selectedIsAllDay()) { + time = aView->selectionStart().time(); + } + + } else { + date = mNavigator->selectedDates().first(); + } + + 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); + } + } + 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 ); + } +} + +void CalendarView::edit_options() +{ + mDialogManager->showOptionsDialog(); +} + +void CalendarView::dateTimesForNewEvent( QDateTime &startDt, QDateTime &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 ); + endDt = startDt.addSecs( addSecs ); + } + mViewManager->currentView()->eventDurationHint( startDt, endDt, allDay ); +} + +KOEventEditor *CalendarView::newEventEditor( const QDateTime &startDtParam, + const QDateTime &endDtParam, bool allDayParam) +{ + // let the current view change the default start/end datetime + bool allDay = allDayParam; + QDateTime startDt( startDtParam ), endDt( endDtParam ); + // Adjust the start/end date times (i.e. replace invalid values by defaults, + // and let the view adjust the type. + dateTimesForNewEvent( startDt, endDt, allDay ); + + KOEventEditor *eventEditor = mDialogManager->getEventEditor(); + eventEditor->newEvent(); + connectIncidenceEditor( eventEditor ); + eventEditor->setDates( startDt, endDt, allDay ); + mDialogManager->connectTypeAhead( eventEditor, dynamic_cast<KOrg::AgendaView*>(viewManager()->currentView()) ); + return eventEditor; +} + + + + +void CalendarView::newEvent() +{ + kdDebug(5850) << "CalendarView::newEvent()" << endl; + newEvent( QDateTime(), QDateTime() ); +} + +void CalendarView::newEvent( const QDate &dt ) +{ + QDateTime startDt( dt, KOPrefs::instance()->mStartTime.time() ); + return newEvent( QDateTime( dt ), QDateTime() ); +} + +void CalendarView::newEvent( const QDateTime &startDt ) +{ + return newEvent( startDt, QDateTime() ); +} + +void CalendarView::newEvent( const QDateTime &startDt, const QDateTime &endDt, + bool allDay ) +{ + KOEventEditor *eventEditor = newEventEditor( startDt, endDt, allDay ); + eventEditor->show(); +} + +void CalendarView::newEvent( const QString &summary, const QString &description, + const QStringList &attachments, const QStringList &attendees, + const QStringList &attachmentMimetypes, bool inlineAttachment ) +{ + KOEventEditor *eventEditor = newEventEditor(); + 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 + eventEditor->addAttachments( attachments, attachmentMimetypes, inlineAttachment ); + eventEditor->addAttendees( attendees ); + eventEditor->show(); +} + +void CalendarView::newTodo( const QString &summary, const QString &description, + const QStringList &attachments, const QStringList &attendees, + const QStringList &attachmentMimetypes, bool inlineAttachment ) +{ + kdDebug(5850) << k_funcinfo << endl; + KOTodoEditor *todoEditor = mDialogManager->getTodoEditor(); + connectIncidenceEditor( todoEditor ); + todoEditor->newTodo(); + todoEditor->setTexts( summary, description ); + todoEditor->addAttachments( attachments, attachmentMimetypes, inlineAttachment ); + todoEditor->addAttendees( attendees ); + todoEditor->show(); +} + +void CalendarView::newTodo() +{ + kdDebug(5850) << k_funcinfo << endl; + QDateTime dtDue; + bool allday = true; + KOTodoEditor *todoEditor = mDialogManager->getTodoEditor(); + connectIncidenceEditor( todoEditor ); + todoEditor->newTodo(); + if ( mViewManager->currentView()->isEventView() ) { + dtDue.setDate( mNavigator->selectedDates().first() ); + QDateTime dtDummy = QDateTime::currentDateTime(); + mViewManager->currentView()-> + eventDurationHint( dtDue, dtDummy, allday ); + todoEditor->setDates( dtDue, allday ); + } + todoEditor->show(); +} + +void CalendarView::newTodo( const QDate &date ) +{ + KOTodoEditor *todoEditor = mDialogManager->getTodoEditor(); + connectIncidenceEditor( todoEditor ); + todoEditor->newTodo(); + todoEditor->setDates( QDateTime( date, QTime::currentTime() ), true ); + todoEditor->show(); +} + +void CalendarView::newJournal() +{ + kdDebug(5850) << "CalendarView::newJournal()" << endl; + newJournal( QString::null, QDate() ); +} + +void CalendarView::newJournal( const QDate &date) +{ + newJournal( QString::null, date ); +} + +void CalendarView::newJournal( const QString &text, const QDate &date ) +{ + KOJournalEditor *journalEditor = mDialogManager->getJournalEditor(); + connectIncidenceEditor( journalEditor ); + journalEditor->newJournal(); + journalEditor->setTexts( text ); + if ( !date.isValid() ) { + journalEditor->setDate( mNavigator->selectedDates().first() ); + } else { + journalEditor->setDate( date ); + } + journalEditor->show(); +} + +void CalendarView::newSubTodo() +{ + Todo *todo = selectedTodo(); + if ( todo ) newSubTodo( todo ); +} + +void CalendarView::newSubTodo(Todo *parentEvent) +{ + KOTodoEditor *todoEditor = mDialogManager->getTodoEditor(); + connectIncidenceEditor( todoEditor ); + todoEditor->newTodo(); + todoEditor->setDates( QDateTime(), false, parentEvent ); + todoEditor->show(); +} + +void CalendarView::newFloatingEvent() +{ + DateList tmpList = mNavigator->selectedDates(); + QDate date = tmpList.first(); + + newEvent( QDateTime( date, QTime( 12, 0, 0 ) ), + QDateTime( date, QTime( 12, 0, 0 ) ), true ); +} + +bool CalendarView::addIncidence( const QString &ical ) +{ + kdDebug(5850) << "CalendarView::addIncidence:\n" << ical << endl; + ICalFormat format; + format.setTimeZone( mCalendar->timeZoneId(), true ); + Incidence *incidence = format.fromString( ical ); + if ( !incidence ) return false; + if ( !mChanger->addIncidence( incidence, this ) ) { + delete incidence; + return false; + } + return true; +} + +void CalendarView::appointment_show() +{ + Incidence *incidence = selectedIncidence(); + if (incidence) + showIncidence( incidence ); + else + KNotifyClient::beep(); +} + +void CalendarView::appointment_edit() +{ + Incidence *incidence = selectedIncidence(); + if (incidence) + editIncidence( incidence ); + else + KNotifyClient::beep(); +} + +void CalendarView::appointment_delete() +{ + Incidence *incidence = selectedIncidence(); + if (incidence) + deleteIncidence( incidence ); + else + KNotifyClient::beep(); +} + +void CalendarView::todo_unsub() +{ + Todo *anTodo = selectedTodo(); + if( todo_unsub (anTodo ) ) { + updateView(); + } +} + +bool CalendarView::todo_unsub( Todo *todo ) +{ + bool status= false; + if ( !todo || !todo->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; + setModified(true); + status = true; + } + if ( ! status ) { + KMessageBox::sorry( this, i18n("Unable to turn sub-to-do into a top-level " + "to-do, because it cannot be locked.") ); + } + + return status; +} + +bool CalendarView::makeSubTodosIndependents ( ) +{ + bool status = false; + Todo *anTodo = selectedTodo(); + + if( makeSubTodosIndependents( anTodo ) ) { + updateView(); + status = true; + } + return status; +} + +bool CalendarView::makeSubTodosIndependents ( Todo *todo ) +{ + if( !todo || todo->relations().isEmpty() ) return false; + + startMultiModify ( i18n( "Make sub-to-dos independent" ) ); + Incidence::List subTodos( todo->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 ); + } + } + endMultiModify(); + return true; +} + +bool CalendarView::deleteIncidence( const QString &uid, bool force ) +{ + Incidence *inc = mCalendar->incidence( uid ); + if ( inc ) { + deleteIncidence( inc, force ); + return true; + } else { + return false; + } +} + +void CalendarView::toggleAlarm( Incidence *incidence ) +{ + if ( !incidence || !mChanger ) { + kdDebug(5850) << "CalendarView::toggleAlarm() called without having a clicked item" << endl; + return; + } + Incidence*oldincidence = incidence->clone(); + if ( !mChanger->beginChange( incidence ) ) { + kdDebug(5850) << "Unable to lock incidence " << endl; + delete oldincidence; + return; + } + + Alarm::List alarms = incidence->alarms(); + Alarm::List::ConstIterator it; + for( it = alarms.begin(); it != alarms.end(); ++it ) + (*it)->toggleAlarm(); + if (alarms.isEmpty()) { + // Add an alarm if it didn't have one + Alarm*alm = incidence->newAlarm(); + alm->setEnabled(true); + } + mChanger->changeIncidence( oldincidence, incidence, KOGlobals::ALARM_MODIFIED ); + mChanger->endChange( incidence ); + delete oldincidence; + +// mClickedItem->updateIcons(); +} + +void CalendarView::dissociateOccurrence( Incidence *incidence, const QDate &date ) +{ + if ( !incidence || !mChanger ) { + kdDebug(5850) << "CalendarView::toggleAlarm() called without having a clicked item" << endl; + return; + } + if ( !mChanger->beginChange( incidence ) ) { + kdDebug(5850) << "Unable to lock incidence " << endl; + return; + } + startMultiModify( i18n("Dissociate occurrence") ); + Incidence*oldincidence = incidence->clone(); + + 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 ); + } else { + KMessageBox::sorry( this, i18n("Dissociating the occurrence failed."), + i18n("Dissociating Failed") ); + } + mChanger->endChange( incidence ); + endMultiModify(); + delete oldincidence; +} + +void CalendarView::dissociateFutureOccurrence( Incidence *incidence, const QDate &date ) +{ + if ( !incidence || !mChanger ) { + kdDebug(5850) << "CalendarView::toggleAlarm() called without having a clicked item" << endl; + return; + } + if ( !mChanger->beginChange( incidence ) ) { + kdDebug(5850) << "Unable to lock incidence " << endl; + return; + } + startMultiModify( i18n("Dissociate future occurrences") ); + Incidence*oldincidence = incidence->clone(); + + 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 ); + } else { + KMessageBox::sorry( this, i18n("Dissociating the future occurrences failed."), + i18n("Dissociating Failed") ); + } + endMultiModify(); + mChanger->endChange( incidence ); + delete oldincidence; +} + + +/*****************************************************************************/ + + +void CalendarView::schedule_publish(Incidence *incidence) +{ + if (incidence == 0) + incidence = selectedIncidence(); + + if (!incidence) { + KMessageBox::information( this, i18n("No item selected."), + "PublishNoEventSelected" ); + return; + } + + PublishDialog *publishdlg = new PublishDialog(); + if (incidence->attendeeCount()>0) { + Attendee::List attendees = incidence->attendees(); + Attendee::List::ConstIterator it; + for( it = attendees.begin(); it != attendees.end(); ++it ) { + publishdlg->addAttendee( *it ); + } + } + if ( publishdlg->exec() == QDialog::Accepted ) { + Incidence *inc = incidence->clone(); + inc->registerObserver( 0 ); + inc->clearAttendees(); + + // Send the mail + KCal::MailScheduler scheduler( mCalendar ); + if ( scheduler.publish( incidence, publishdlg->addresses() ) ) { + KMessageBox::information( this, i18n("The item information was successfully sent."), + i18n("Publishing"), "IncidencePublishSuccess" ); + } else { + KMessageBox::error( this, i18n("Unable to publish the item '%1'").arg( incidence->summary() ) ); + } + } + delete publishdlg; +} + +void CalendarView::schedule_request(Incidence *incidence) +{ + schedule(Scheduler::Request,incidence); +} + +void CalendarView::schedule_refresh(Incidence *incidence) +{ + schedule(Scheduler::Refresh,incidence); +} + +void CalendarView::schedule_cancel(Incidence *incidence) +{ + schedule(Scheduler::Cancel,incidence); +} + +void CalendarView::schedule_add(Incidence *incidence) +{ + schedule(Scheduler::Add,incidence); +} + +void CalendarView::schedule_reply(Incidence *incidence) +{ + schedule(Scheduler::Reply,incidence); +} + +void CalendarView::schedule_counter(Incidence *incidence) +{ + schedule(Scheduler::Counter,incidence); +} + +void CalendarView::schedule_declinecounter(Incidence *incidence) +{ + schedule(Scheduler::Declinecounter,incidence); +} + +void CalendarView::schedule_forward(Incidence * incidence) +{ + if (incidence == 0) + incidence = selectedIncidence(); + + if (!incidence) { + KMessageBox::information( this, i18n("No item selected."), + "ForwardNoEventSelected" ); + return; + } + + PublishDialog publishdlg; + if ( publishdlg.exec() == QDialog::Accepted ) { + QString recipients = publishdlg.addresses(); + ICalFormat format; + QString 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" ); + } else { + KMessageBox::error( this, i18n("Unable to forward the item '%1'").arg( incidence->summary() ) ); + } + } +} + +void CalendarView::mailFreeBusy( int daysToPublish ) +{ + QDateTime start = QDateTime::currentDateTime(); + QDateTime end = start.addDays(daysToPublish); + + FreeBusy *freebusy = new FreeBusy(mCalendar, start, end); + freebusy->setOrganizer( Person( KOPrefs::instance()->fullName(), + KOPrefs::instance()->email() ) ); + + kdDebug(5850) << "calendarview: schedule_publish_freebusy: startDate: " + << KGlobal::locale()->formatDateTime( start ) << " End Date: " + << KGlobal::locale()->formatDateTime( end ) << endl; + + PublishDialog *publishdlg = new PublishDialog(); + if ( publishdlg->exec() == QDialog::Accepted ) { + // Send the mail + KCal::MailScheduler scheduler( mCalendar ); + if ( scheduler.publish( freebusy, publishdlg->addresses() ) ) { + KMessageBox::information( this, i18n("The free/busy information was successfully sent."), + i18n("Sending Free/Busy"), "FreeBusyPublishSuccess" ); + } else { + KMessageBox::error( this, i18n("Unable to publish the free/busy data.") ); + } + } + delete freebusy; + delete publishdlg; +} + +void CalendarView::uploadFreeBusy() +{ + KOGroupware::instance()->freeBusyManager()->publishFreeBusy(); +} + +void CalendarView::schedule(Scheduler::Method method, Incidence *incidence) +{ + if ( !incidence ) { + incidence = selectedIncidence(); + } + + if ( !incidence ) { + KMessageBox::sorry( this, i18n("No item selected."), + "ScheduleNoEventSelected" ); + return; + } + + if( incidence->attendeeCount() == 0 && method != Scheduler::Publish ) { + KMessageBox::information( this, i18n("The item has no attendees."), + "ScheduleNoIncidences" ); + return; + } + + Incidence *inc = incidence->clone(); + inc->registerObserver( 0 ); + inc->clearAttendees(); + + // Send the mail + KCal::MailScheduler scheduler( mCalendar ); + if ( !scheduler.performTransaction( incidence, method ) ) { + KMessageBox::information( this, i18n("The groupware message for item '%1'" + "was successfully sent.\nMethod: %2") + .arg( incidence->summary() ) + .arg( Scheduler::methodName( method ) ), + i18n("Sending Free/Busy"), + "FreeBusyPublishSuccess" ); + } else { + KMessageBox::error( this, i18n("Groupware message sending failed. " + "%2 is request/reply/add/cancel/counter/etc.", + "Unable to send the item '%1'.\nMethod: %2") + .arg( incidence->summary() ) + .arg( Scheduler::methodName( method ) ) ); + } +} + +void CalendarView::openAddressbook() +{ + KRun::runCommand("kaddressbook"); +} + +void CalendarView::setModified(bool modified) +{ + if (mModified != modified) { + mModified = modified; + emit modifiedChanged(mModified); + } +} + +bool CalendarView::isReadOnly() +{ + return mReadOnly; +} + +void CalendarView::setReadOnly(bool readOnly) +{ + if (mReadOnly != readOnly) { + mReadOnly = readOnly; + emit readOnlyChanged(mReadOnly); + } +} + +bool CalendarView::isModified() +{ + return mModified; +} + +void CalendarView::print() +{ +#ifndef KORG_NOPRINTER + KOCoreHelper helper; + CalPrinter printer( this, mCalendar, &helper ); + connect( this, SIGNAL(configChanged()), &printer, SLOT(updateConfig()) ); + + KOrg::BaseView *currentView = mViewManager->currentView(); + + CalPrinterBase::PrintType printType = CalPrinterBase::Month; + if ( currentView ) printType = currentView->printType(); + + DateList tmpDateList = mNavigator->selectedDates(); + Incidence::List selectedIncidences; + if ( mViewManager->currentView() ) { + selectedIncidences = mViewManager->currentView()->selectedIncidences(); + } + printer.print( printType, tmpDateList.first(), tmpDateList.last(), selectedIncidences ); +#endif +} + +void CalendarView::exportWeb() +{ + // FIXME: Get rid of the settings object. When can I delete it??? + HTMLExportSettings *settings = new HTMLExportSettings( "KOrganizer" ); + // Manually read in the config, because parametrized kconfigxt objects don't + // seem to load the config theirselves + if ( settings ) settings->readConfig(); + ExportWebDialog *dlg = new ExportWebDialog( settings, this ); + connect( dlg, SIGNAL( exportHTML( HTMLExportSettings* ) ), + this, SIGNAL( exportHTML( HTMLExportSettings* ) ) ); + dlg->show(); +} + +void CalendarView::exportICalendar() +{ + QString 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(); +} + +void CalendarView::exportVCalendar() +{ + if (mCalendar->journals().count() > 0) { + int result = KMessageBox::warningContinueCancel(this, + i18n("The journal entries can not be exported to a vCalendar file."), + i18n("Data Loss Warning"),i18n("Proceed"),"dontaskVCalExport", + true); + if (result != KMessageBox::Continue) return; + } + + QString 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(); +} + +void CalendarView::eventUpdated(Incidence *) +{ + setModified(); + // Don't call updateView here. The code, which has caused the update of the + // event is responsible for updating the view. +// updateView(); +} + +void CalendarView::adaptNavigationUnits() +{ + if (mViewManager->currentView()->isEventView()) { + int days = mViewManager->currentView()->currentDateCount(); + if (days == 1) { + emit changeNavStringPrev(i18n("&Previous Day")); + emit changeNavStringNext(i18n("&Next Day")); + } else { + emit changeNavStringPrev(i18n("&Previous Week")); + emit changeNavStringNext(i18n("&Next Week")); + } + } +} + +void CalendarView::processMainViewSelection( Incidence *incidence ) +{ + if ( incidence ) mTodoList->clearSelection(); + processIncidenceSelection( incidence ); +} + +void CalendarView::processTodoListSelection( Incidence *incidence ) +{ + if ( incidence && mViewManager->currentView() ) { + mViewManager->currentView()->clearSelection(); + } + processIncidenceSelection( incidence ); +} + +void CalendarView::processIncidenceSelection( Incidence *incidence ) +{ + if ( incidence == mSelectedIncidence ) return; + + mSelectedIncidence = incidence; + + emit incidenceSelected( mSelectedIncidence ); + 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() ); + + if ( incidence && incidence->type() == "Todo" ) { + todo = true; + subtodo = ( incidence->relatedTo() != 0 ); + } + } + emit todoSelected( todo ); + emit subtodoSelected( subtodo ); + emit organizerEventsSelected( organizerEvents ); + emit groupEventsSelected( groupEvents ); +} + + +void CalendarView::checkClipboard() +{ +#ifndef KORG_NODND + if (ICalDrag::canDecode(QApplication::clipboard()->data())) { + kdDebug(5850) << "CalendarView::checkClipboard() true" << endl; + emit pasteEnabled(true); + } else { + kdDebug(5850) << "CalendarView::checkClipboard() false" << endl; + emit pasteEnabled(false); + } +#endif +} + +void CalendarView::showDates(const DateList &selectedDates) +{ +// kdDebug(5850) << "CalendarView::selectDates()" << endl; + + if ( mViewManager->currentView() ) { + updateView( selectedDates.first(), selectedDates.last() ); + } else { + mViewManager->showAgendaView(); + } +} + +void CalendarView::editFilters() +{ + kdDebug(5850) << "CalendarView::editFilters()" << endl; + + CalFilter *filter = mFilters.first(); + while(filter) { + kdDebug(5850) << " Filter: " << filter->name() << endl; + filter = mFilters.next(); + } + + mDialogManager->showFilterEditDialog(&mFilters); +} + +/** Filter configuration changed +*/ +void CalendarView::updateFilter() +{ + QStringList filters; + CalFilter *filter; + + int pos = mFilters.find( mCurrentFilter ); + if ( pos < 0 ) { + mCurrentFilter = 0; + } + + filters << i18n("No filter"); + for ( filter = mFilters.first(); filter; filter = mFilters.next() ) { + filters << filter->name(); + } + + emit newFilterListSignal( filters ); + // account for the additional "No filter" at the beginning! if the + // filter is not in the list, pos == -1... + emit selectFilterSignal( pos+1 ); + mCalendar->setFilter( mCurrentFilter ); + updateView(); +} + +/** A different filter was selected +*/ +void CalendarView::filterActivated( int filterNo ) +{ + CalFilter *newFilter = 0; + if ( filterNo > 0 && filterNo <= int(mFilters.count()) ) { + newFilter = mFilters.at( filterNo-1 ); + } + if ( newFilter != mCurrentFilter ) { + mCurrentFilter = newFilter; + mCalendar->setFilter( mCurrentFilter ); + updateView(); + } + emit filterChanged(); +} + +QString CalendarView::currentFilterName() const +{ + if ( mCurrentFilter) { + return mCurrentFilter->name(); + } else return i18n("No filter"); +} + +void CalendarView::takeOverEvent() +{ + Incidence *incidence = currentSelection(); + + if (!incidence) return; + + incidence->setOrganizer( Person( KOPrefs::instance()->fullName(), + KOPrefs::instance()->email() ) ); + incidence->recreate(); + incidence->setReadOnly(false); + + updateView(); +} + +void CalendarView::takeOverCalendar() +{ + Incidence::List incidences = mCalendar->rawIncidences(); + Incidence::List::Iterator it; + + for ( it = incidences.begin(); it != incidences.end(); ++it ) { + (*it)->setOrganizer( Person( KOPrefs::instance()->fullName(), + KOPrefs::instance()->email() ) ); + (*it)->recreate(); + (*it)->setReadOnly(false); + } + updateView(); +} + +void CalendarView::showIntro() +{ + kdDebug(5850) << "To be implemented." << endl; +} + +void CalendarView::showDateNavigator( bool show ) +{ + if( show ) + mDateNavigator->show(); + else + mDateNavigator->hide(); +} + +void CalendarView::showTodoView( bool show ) +{ + if( show ) + mTodoList->show(); + else + mTodoList->hide(); +} + +void CalendarView::showEventViewer( bool show ) +{ + if( show ) + mEventViewer->show(); + else + mEventViewer->hide(); +} + + +void CalendarView::addView(KOrg::BaseView *view) +{ + mViewManager->addView(view); +} + +void CalendarView::showView(KOrg::BaseView *view) +{ + mViewManager->showView(view); +} + +void CalendarView::addExtension( CalendarViewExtension::Factory *factory ) +{ + CalendarViewExtension *extension = factory->create( mLeftSplitter ); + + mExtensions.append( extension ); +} + +void CalendarView::toggleExpand() +{ + showLeftFrame( mLeftFrame->isHidden() ); +} + +void CalendarView::showLeftFrame(bool show) +{ + if (show) { + mLeftFrame->show(); + emit calendarViewExpanded( false ); + } else { + mLeftFrame->hide(); + emit calendarViewExpanded( true ); + } +} + +void CalendarView::calendarModified( bool modified, Calendar * ) +{ + setModified( modified ); +} + +Todo *CalendarView::selectedTodo() +{ + Incidence *incidence = currentSelection(); + if ( incidence && incidence->type() == "Todo" ) { + return static_cast<Todo *>( incidence ); + } + incidence = 0; + + Incidence::List selectedIncidences = mTodoList->selectedIncidences(); + if ( !selectedIncidences.isEmpty() ) incidence = selectedIncidences.first(); + if ( incidence && incidence->type() == "Todo" ) { + return static_cast<Todo *>( incidence ); + } + + return 0; +} + +void CalendarView::dialogClosing( Incidence *in ) +{ + // FIXME: this doesn't work, because if it's a new incidence, it's not locked! + mChanger->endChange( in ); + mDialogList.remove( in ); +} + +Incidence *CalendarView::currentSelection() +{ + return mViewManager->currentSelection(); +} + +Incidence* CalendarView::selectedIncidence() +{ + Incidence *incidence = currentSelection(); + if ( !incidence ) { + Incidence::List selectedIncidences = mTodoList->selectedIncidences(); + if ( !selectedIncidences.isEmpty() ) + incidence = selectedIncidences.first(); + } + return incidence; +} + +void CalendarView::showIncidence() +{ + showIncidence( selectedIncidence() ); +} + +void CalendarView::editIncidence() +{ + editIncidence( selectedIncidence() ); +} + +bool CalendarView::editIncidence( const QString& uid ) +{ + kdDebug(5850) << "CalendarView::editIncidence()" << endl; + return editIncidence( mCalendar->incidence( uid ) ); +} + +void CalendarView::deleteIncidence() +{ + deleteIncidence( selectedIncidence() ); +} + +void CalendarView::cutIncidence(Incidence *) +{ + edit_cut(); +} + +void CalendarView::copyIncidence(Incidence *) +{ + edit_copy(); +} + +void CalendarView::pasteIncidence() +{ + edit_paste(); +} + +void CalendarView::showIncidence( Incidence *incidence ) +{ + KOEventViewerDialog *eventViewer = new KOEventViewerDialog( this ); + eventViewer->setIncidence( incidence ); + eventViewer->show(); +} + +bool CalendarView::editIncidence( Incidence *incidence, bool isCounter ) +{ + kdDebug(5850) << "CalendarView::editEvent()" << endl; + + if ( !incidence || !mChanger ) { + KNotifyClient::beep(); + return false; + } + KOIncidenceEditor *tmp = editorDialog( incidence ); + if ( tmp ) { + kdDebug(5850) << "CalendarView::editIncidence() in List" << endl; + tmp->reload(); + tmp->raise(); + tmp->show(); + return true; + } + + if ( incidence->isReadOnly() ) { + showIncidence( incidence ); + return true; + } + + if ( !isCounter && !mChanger->beginChange( incidence ) ) { + warningChangeFailed( incidence ); + showIncidence( incidence ); + return false; + } + + kdDebug(5850) << "CalendarView::editIncidence() new IncidenceEditor" << endl; + KOIncidenceEditor *incidenceEditor = mDialogManager->getEditor( incidence ); + connectIncidenceEditor( incidenceEditor ); + + mDialogList.insert( incidence, incidenceEditor ); + incidenceEditor->editIncidence( incidence, mCalendar ); + incidenceEditor->show(); + return true; +} + +void CalendarView::deleteSubTodosIncidence ( Todo *todo ) +{ + if( !todo ) return; + + Incidence::List subTodos( todo->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 ); + deleteSubTodosIncidence ( aTodo ); + } + } + mChanger->deleteIncidence ( todo ); +} + +void CalendarView::deleteTodoIncidence ( Todo *todo, bool force ) +{ + if ( !todo ) return ; + + // it a simple todo, ask and delete it. + if (todo->relations().isEmpty() ) { + bool doDelete = true; + if ( !force && KOPrefs::instance()->mConfirm ) { + doDelete = ( msgItemDelete( todo ) == KMessageBox::Continue ); + } + if ( doDelete ) + mChanger->deleteIncidence( todo ); + 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")); + } + startMultiModify( i18n("Deleting sub-to-dos" ) ); + // Delete only the father + if( km == KMessageBox::Yes ) { + + makeSubTodosIndependents ( todo ); + mChanger->deleteIncidence( todo ); + } else if ( km == KMessageBox::No ) { + // Delete all + // we have to hide the delete confirmation for each itemDate + deleteSubTodosIncidence ( todo ); + } + endMultiModify(); +} + +void CalendarView::deleteIncidence(Incidence *incidence, bool force) +{ + if ( !incidence || !mChanger ) { + if ( !force ) { + KNotifyClient::beep(); + } + return; + } + if ( incidence->isReadOnly() ) { + if ( !force ) { + KMessageBox::information( this, i18n("The item \"%1\" is marked read-only " + "and cannot be deleted; it probably belongs to " + "a read-only calendar resource.") + .arg(incidence->summary()), + i18n("Removing not possible"), + "deleteReadOnlyIncidence" ); + } + return; + } + + CanDeleteIncidenceVisitor v; + + // Let the visitor do special things for special incidence types. + // e.g. todos with children cannot be deleted, so act(..) returns false + if ( !v.act( incidence, this ) ) + return; + //If it is a todo, there are specific delete function + + if ( incidence && incidence->type()=="Todo" ) { + deleteTodoIncidence( static_cast<Todo*>(incidence), force ); + return; + } + + if ( incidence->doesRecur() ) { + QDate itemDate = mViewManager->currentSelectionDate(); + kdDebug(5850) << "Recurrence-Date: " << itemDate.toString() << endl; + int km = KMessageBox::Ok; + if ( !force ) { + if ( !itemDate.isValid() ) { + kdDebug(5850) << "Date Not Valid" << endl; + km = KMessageBox::warningContinueCancel(this, + i18n("The calendar item \"%1\" recurs over multiple dates; " + "are you sure you want to delete it " + "and all its recurrences?").arg( incidence->summary() ), + i18n("KOrganizer Confirmation"), i18n("Delete All") ); + } else { + km = KOMessageBox::fourBtnMsgBox( this, QMessageBox::Warning, + i18n("The calendar item \"%1\" recurs over multiple dates. " + "Do you want to delete only the current one on %2, only all " + "future recurrences, or all its recurrences?" ) + .arg( incidence->summary() ) + .arg( KGlobal::locale()->formatDate(itemDate)), + i18n("KOrganizer Confirmation"), i18n("Delete C&urrent"), + i18n("Delete &Future"), + i18n("Delete &All")); + } + } + switch(km) { + case KMessageBox::Ok: // Continue // all + case KMessageBox::Continue: + mChanger->deleteIncidence( incidence ); + break; + + case KMessageBox::Yes: // just this one + if ( mChanger->beginChange( incidence ) ) { + Incidence *oldIncidence = incidence->clone(); + incidence->recurrence()->addExDate( itemDate ); + mChanger->changeIncidence( oldIncidence, incidence ); + mChanger->endChange( incidence ); + delete oldIncidence; + } + break; + case KMessageBox::No: // all future items + if ( mChanger->beginChange( incidence ) ) { + Incidence *oldIncidence = incidence->clone(); + Recurrence *recur = incidence->recurrence(); + recur->setEndDate( itemDate.addDays(-1) ); + mChanger->changeIncidence( oldIncidence, incidence ); + mChanger->endChange( incidence ); + delete oldIncidence; + } + break; + } + } else { + bool doDelete = true; + if ( !force && KOPrefs::instance()->mConfirm ) { + doDelete = ( msgItemDelete( incidence ) == KMessageBox::Continue ); + } + if ( doDelete ) { + mChanger->deleteIncidence( incidence ); + processIncidenceSelection( 0 ); + } + } +} + +void CalendarView::connectIncidenceEditor( KOIncidenceEditor *editor ) +{ + connect( this, SIGNAL( newIncidenceChanger( IncidenceChangerBase* ) ), + editor, SLOT( setIncidenceChanger( IncidenceChangerBase* ) ) ); + editor->setIncidenceChanger( mChanger ); +} + +bool CalendarView::purgeCompletedSubTodos( Todo* todo, bool &allPurged ) +{ + if ( !todo ) return true; + bool deleteThisTodo = true; + Incidence::List subTodos( todo->relations() ); + Incidence *aIncidence; + Todo *aTodo; + Incidence::List::Iterator it; + for ( it = subTodos.begin(); it != subTodos.end(); ++it ) { + aIncidence = *it; + if ( aIncidence && aIncidence->type()=="Todo" ) { + aTodo = static_cast<Todo*>( aIncidence ); + deleteThisTodo &= purgeCompletedSubTodos( aTodo, allPurged ); + } + } + + if ( deleteThisTodo ) { + if ( todo->isCompleted() ) { + if ( !mChanger->deleteIncidence( todo ) ) + allPurged = false; + } else { + deleteThisTodo = false; + } + } else { + if ( todo->isCompleted() ) { + allPurged = false; + } + } + return deleteThisTodo; +} + +void CalendarView::purgeCompleted() +{ + int result = KMessageBox::warningContinueCancel(this, + i18n("Delete all completed to-dos?"),i18n("Purge To-dos"),i18n("Purge")); + + if (result == KMessageBox::Continue) { + bool allDeleted = true; + startMultiModify( i18n("Purging completed to-dos") ); + Todo::List todos = calendar()->rawTodos(); + Todo::List rootTodos; + Todo::List::ConstIterator it; + for ( it = todos.begin(); it != todos.end(); ++it ) { + Todo *aTodo = *it; + if ( aTodo && !aTodo->relatedTo() ) + rootTodos.append( aTodo ); + } + // now that we have a list of all root todos, check them and their children + for ( it = rootTodos.begin(); it != rootTodos.end(); ++it ) { + purgeCompletedSubTodos( *it, allDeleted ); + } + endMultiModify(); + if ( !allDeleted ) { + KMessageBox::information( this, i18n("Unable to purge to-dos with " + "uncompleted children."), i18n("Delete To-do"), + "UncompletedChildrenPurgeTodos" ); + } + } +} + +void CalendarView::slotCalendarChanged() +{ + kdDebug(5850) << "CalendarView::slotCalendarChanged()" << endl; + + updateView(); +} + +void CalendarView::warningChangeFailed( Incidence * ) +{ + KMessageBox::sorry( this, i18n("Unable to edit item: " + "it is locked by another process.") ); +} + +void CalendarView::editCanceled( Incidence *i ) +{ + mCalendar->endChange( i ); +} + +void CalendarView::showErrorMessage( const QString &msg ) +{ + KMessageBox::error( this, msg ); +} + +void CalendarView::updateCategories() +{ + QStringList allCats( calendar()->categories() ); + allCats.sort(); + QStringList categories( KOPrefs::instance()->mCustomCategories ); + for ( QStringList::ConstIterator si = allCats.constBegin(); si != allCats.constEnd(); ++si ) { + if ( categories.find( *si ) == categories.end() ) { + categories.append( *si ); + } + } + KOPrefs::instance()->mCustomCategories = categories; + KOPrefs::instance()->writeConfig(); + // Make the category editor update the list! + emit categoriesChanged(); +} + +void CalendarView::addIncidenceOn( Incidence *incadd, const QDate &dt ) +{ + if ( !incadd || !mChanger ) { + KMessageBox::sorry(this, i18n("Unable to copy the item to %1.") + .arg( dt.toString() ), i18n("Copying Failed") ); + return; + } + Incidence *incidence = mCalendar->incidence( incadd->uid() ); + if ( !incidence ) incidence = incadd; + // Create a copy of the incidence, since the incadd doesn't belong to us. + incidence = incidence->clone(); + incidence->recreate(); + + if ( incidence->type() == "Event" ) { + Event *event = static_cast<Event*>(incidence); + + // Adjust date + QDateTime start = event->dtStart(); + QDateTime end = event->dtEnd(); + + int duration = start.daysTo( end ); + start.setDate( dt ); + end.setDate( dt.addDays( duration ) ); + + event->setDtStart( start ); + event->setDtEnd( end ); + + } else if ( incidence->type() == "Todo" ) { + Todo *todo = static_cast<Todo*>(incidence); + QDateTime due = todo->dtDue(); + due.setDate( dt ); + + todo->setDtDue( due ); + todo->setHasDueDate( true ); + } + + if ( !mChanger->addIncidence( incidence, this ) ) { + KODialogManager::errorSaveIncidence( this, incidence ); + delete incidence; + } +} + +void CalendarView::moveIncidenceTo( Incidence *incmove, const QDate &dt ) +{ + if ( !incmove || !mChanger ) { + KMessageBox::sorry( this, i18n("Unable to move the item to %1.") + .arg( dt.toString() ), i18n("Moving Failed") ); + return; + } + Incidence *incidence = mCalendar->incidence( incmove->uid() ); + if ( !incidence ) { + addIncidenceOn( incidence, dt ); + return; + } + Incidence *oldIncidence = incidence->clone(); + if ( !mChanger->beginChange( incidence ) ) { + delete oldIncidence; + return; + } + + if ( incidence->type() == "Event" ) { + Event *event = static_cast<Event*>(incidence); + + // Adjust date + QDateTime start = event->dtStart(); + QDateTime end = event->dtEnd(); + + int duration = start.daysTo( end ); + start.setDate( dt ); + end.setDate( dt.addDays( duration ) ); + + event->setDtStart( start ); + event->setDtEnd( end ); + + } else if ( incidence->type() == "Todo" ) { + Todo *todo = static_cast<Todo*>(incidence); + QDateTime due = todo->dtDue(); + due.setDate( dt ); + + todo->setDtDue( due ); + todo->setHasDueDate( true ); + } + mChanger->changeIncidence( oldIncidence, incidence ); + mChanger->endChange( incidence ); + delete oldIncidence; +} + +void CalendarView::resourcesChanged() +{ + mViewManager->resourcesChanged(); + updateView(); +} + +#include "calendarview.moc" diff --git a/korganizer/calendarview.h b/korganizer/calendarview.h new file mode 100644 index 000000000..ceb2b2d7a --- /dev/null +++ b/korganizer/calendarview.h @@ -0,0 +1,613 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2000,2001,2003,2004 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef CALENDARVIEW_H +#define CALENDARVIEW_H + +#include <qwidget.h> +#include <qptrlist.h> +#include <qmap.h> +#include <kfile.h> +#include <korganizer/koeventviewer.h> +#include <libkcal/scheduler.h> +#include <kdepimmacros.h> + +#include <korganizer/calendarviewbase.h> + +class QWidgetStack; +class QSplitter; + +class KOViewManager; +class KODialogManager; +class KOTodoView; +class KOEventEditor; +class DateNavigatorContainer; +class DateNavigator; +class KOIncidenceEditor; +class ResourceView; +class NavigatorBar; +class DateChecker; + +namespace KOrg { class History; class IncidenceChangerBase; } +class HTMLExportSettings; + +using namespace KOrg; +using namespace KCal; + +class CalendarViewExtension : public QWidget +{ + public: + CalendarViewExtension( QWidget *parent, const char *name = 0 ) + : QWidget( parent, name ) {} + + class Factory + { + public: + virtual CalendarViewExtension *create( QWidget *parent ) = 0; + }; +}; + +/** + This is the main calendar widget. It provides the different views on the + calendar data as well as the date navigator. It also handles synchronization + of the different views and controls the different dialogs like preferences, + event editor, search dialog etc. + + @short main calendar view widget + @author Cornelius Schumacher +*/ +class KDE_EXPORT CalendarView : public KOrg::CalendarViewBase, public Calendar::Observer +{ + Q_OBJECT + public: + /** + Constructs a new calendar view widget. + + @param parent parent window + @param name Qt internal widget object name + */ + CalendarView( QWidget *parent = 0, const char *name = 0 ); + virtual ~CalendarView(); + + + class CalendarViewVisitor : public IncidenceBase::Visitor + { + public: + CalendarViewVisitor() : mView( 0 ) {} + bool act( IncidenceBase *incidence, CalendarView *view ) + { + mView = view; + return incidence->accept( *this ); + } + protected: + CalendarView *mView; + }; + + class CanDeleteIncidenceVisitor : public CalendarViewVisitor + { + protected: + bool visit( Event *event ) { return mView->deleteEvent( event ); } + bool visit( Todo *todo ) { return mView->deleteTodo( todo ); } + bool visit( Journal *journal ) { return mView->deleteJournal( journal ); } + }; + + + void setCalendar( Calendar * ); + Calendar *calendar(); + + KOrg::History *history() const { return mHistory; } + + KOViewManager *viewManager() const { return mViewManager; } + KODialogManager *dialogManager() const { return mDialogManager; } + + QWidgetStack *viewStack() const { return mRightFrame; } + QWidget *leftFrame() const { return mLeftFrame; } + NavigatorBar *navigatorBar() const { return mNavigatorBar; } + DateNavigator *dateNavigator() const { return mNavigator; } + + KOIncidenceEditor *editorDialog( Incidence* ) const; + IncidenceChangerBase *incidenceChanger() const { return mChanger; } + + QDate startDate(); + QDate endDate(); + + + void addView( KOrg::BaseView * ); + void showView( KOrg::BaseView * ); + + /** + Add calendar view extension widget. CalendarView takes ownership of the + objects created by the factory. + */ + void addExtension( CalendarViewExtension::Factory * ); + + /** currentSelection() returns a pointer to the incidence selected in the current view */ + Incidence *currentSelection(); + /** Return a pointer to the incidence selected in the current view. If there + is no selection, return the selected todo from the todo list on the left */ + Incidence *selectedIncidence(); + /** Returns the name of the current filter */ + QString currentFilterName() const; + + signals: + /** when change is made to options dialog, the topwidget will catch this + * and emit this signal which notifies all widgets which have registered + * for notification to update their settings. */ + void configChanged(); + /** Emitted when the categories were updated, and thus the categories editor + * dialog needs to reload the list of categories */ + void categoriesChanged(); + /** emitted when the topwidget is closing down, so that any attached + child windows can also close. */ + void closingDown(); + /** emitted right before we die */ + void closed( QWidget * ); + + /** Emitted when state of modified flag changes */ + void modifiedChanged( bool ); + + /** Emitted when state of read-only flag changes */ + void readOnlyChanged( bool ); + + /** Emitted when the unit of navigation changes */ + void changeNavStringPrev( const QString & ); + void changeNavStringNext( const QString & ); + + /** Emitted when state of events selection has changed and user is organizer*/ + void organizerEventsSelected( bool ); + /** Emitted when state of events selection has changed and user is attendee*/ + void groupEventsSelected( bool ); + /** + Emitted when an incidence gets selected. If the selection is cleared the + signal is emitted with 0 as argument. + */ + void incidenceSelected( Incidence * ); + /** Emitted, when a todoitem is selected or deselected. + the connected slots enables/disables the corresponding menu items */ + void todoSelected( bool ); + void subtodoSelected( bool ); + + /** Emitted, when a day changed (i.e. korganizer was running at midnight). + The argument is the new date */ + void dayPassed( const QDate & ); + /** + Attendees were removed from this incidence. Only the removed attendees + are present in the incidence, so we just need to send a cancel messages + to all attendees groupware messages are enabled at all. + */ + void cancelAttendees( Incidence * ); + + + /** + Emitted, when clipboard content changes. Parameter indicates if paste + is possible or not. + */ + void pasteEnabled( bool ); + /** Send status message, which can e.g. be displayed in the status bar. */ + void statusMessage( const QString & ); + + void calendarViewExpanded( bool ); + + /** Emitted when auto-archiving options were modified */ + void autoArchivingSettingsModified(); + + void newIncidenceChanger( IncidenceChangerBase* ); + void exportHTML( HTMLExportSettings* ); + + void newFilterListSignal( const QStringList & ); + void selectFilterSignal( int ); + void filterChanged(); + + public slots: + /** options dialog made a changed to the configuration. we catch this + * and notify all widgets which need to update their configuration. */ + void updateConfig( const QCString& ); + /** Calendar configuration was changed, so refresh categories list + */ + void updateCategories(); + + + /** + Load calendar from file \a filename. If \a merge is true, load + calendar into existing one, if it is false, clear calendar, before + loading. Return true, if calendar could be successfully loaded. + */ + bool openCalendar( const QString &filename, bool merge = false ); + + /** + Save calendar data to file. Return true if calendar could be + successfully saved. + */ + bool saveCalendar( const QString &filename ); + + /** + Close calendar. Clear calendar data and reset views to display an empty + calendar. + */ + void closeCalendar(); + + /** Archive old events of calendar */ + void archiveCalendar(); + + void showIncidence(); + void editIncidence(); + bool editIncidence( const QString& uid ); + void deleteIncidence(); + + /** + Add an incidence to the active calendar. + @param ical A calendar in iCalendar format containing the incidence. The + calendar must consist of a VCALENDAR component which contains + the incidence (VEVENT, VTODO, VJOURNAL or VFREEBUSY) and + optionally a VTIMEZONE component. If there is more than one + incidence, only the first is added to KOrganizer's calendar. + */ + bool addIncidence( const QString &ical ); + + void connectIncidenceEditor( KOIncidenceEditor * ); + + /** create new event without having a date hint. Takes current date as + default hint. */ + void newEvent(); + /** create an editeventwin with supplied date/time, and if bool is true, + * make the event take all day. */ + void newEvent( const QDate &startDt ); + void newEvent( const QDateTime &startDt ); + void newEvent( const QDateTime &startDt, const QDateTime &EndDt, bool allDay = false ); + /** + Create new Event from given summary, description, attachment list and + attendees list + */ + void newEvent( const QString &summary, const QString &description = QString::null, + const QStringList &attachment = QStringList(), const QStringList &attendees = QStringList(), + const QStringList &attachmentMimetypes = QStringList(), bool inlineAttachment = false ); + void newFloatingEvent(); + + /** Create a read-only viewer dialog for the supplied incidence. It calls the correct showXXX method*/ + void showIncidence( Incidence * ); + /** Create an editor for the supplied incidence. It calls the correct editXXX method*/ + bool editIncidence( Incidence *incidence, 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 + deleted without prompting for confirmation. + */ + void deleteIncidence( Incidence *, bool force = false ); + /** + Cuts the selected incidence using the edit_cut() method + */ + void cutIncidence( Incidence * ); + /** + Copies the selected incidence using the edit_copy() method + */ + void copyIncidence( Incidence *); + /** + Pastes the curren incidence using the edit_paste() method + */ + void pasteIncidence(); + + /** Delete the supplied todo and all sub-todos */ + void deleteSubTodosIncidence ( Todo *todo ); + /** + Delete the todo incidence, and its sub-to-dos. + @param todo The todo to delete. + @param force If true, all sub-todos will be deleted without prompting for confirmation. + */ + void deleteTodoIncidence ( Todo *todo, bool force = false ); + /** Check if deleting the supplied event is allowed. */ + bool deleteEvent( Event * ) { return true; } + /** Check if deleting the todo is allowed */ + bool deleteTodo( Todo * ) {return true; } + /** Check if deleting the supplied journal is allowed. */ + bool deleteJournal( Journal * ) { return true; } + /** + Delete the incidence with the given unique ID. Returns false, if event wasn't found. + @param uid The UID of the incidence to delete. + @param force If true, all recurrences and sub-todos (if applicable) will be + deleted without prompting for confirmation. + */ + bool deleteIncidence( const QString &uid, bool force = false ); + + /** create new todo */ + void newTodo(); + /** create new todo, due on date */ + void newTodo( const QDate &date ); + /** create new todo with a parent todo */ + void newSubTodo(); + /** create new todo with a parent todo */ + void newSubTodo( Todo * ); + + void newTodo( const QString &summary, const QString &description = QString::null, + const QStringList &attachments = QStringList(), const QStringList &attendees = QStringList(), + const QStringList &attachmentMimetypes = QStringList(), bool inlineAttachment = false ); + + void newJournal(); + void newJournal( const QDate &date ); + void newJournal( const QString &text, const QDate &date = QDate() ); + + void toggleAlarm( Incidence * ); + void dissociateOccurrence( Incidence *, const QDate & ); + void dissociateFutureOccurrence( Incidence *, const QDate & ); + + + /** + Check if clipboard contains vCalendar event. The signal pasteEnabled() is + emitted as result. + */ + void checkClipboard(); + + /** + Using the KConfig associated with the kapp variable, read in the + settings from the config file. + + You have to call setCalendar before calling readSettings. + */ + void readSettings(); + + /** write current state to config file. */ + void writeSettings(); + + /** read settings for calendar filters */ + void readFilterSettings( KConfig *config ); + + /** write settings for calendar filters */ + void writeFilterSettings( KConfig *config ); + + /** passes on the message that an event has changed to the currently + * activated view so that it can make appropriate display changes. */ + void changeIncidenceDisplay( Incidence *, int ); + + void incidenceAdded( Incidence * ); + void incidenceChanged( Incidence *oldEvent, Incidence *newEvent ); + void incidenceChanged( Incidence *oldEvent, Incidence *newEvent, int what ); + void incidenceToBeDeleted( Incidence *incidence ); + void incidenceDeleted( Incidence * ); + void startMultiModify( const QString &text ); + void endMultiModify(); + + void editCanceled( Incidence * ); + + void updateView( const QDate &start, const QDate &end ); + void updateView(); + + void updateUnmanagedViews(); + + /** cut the current appointment to the clipboard */ + void edit_cut(); + + /** copy the current appointment(s) to the clipboard */ + void edit_copy(); + + /** paste the current vobject(s) in the clipboard buffer into calendar */ + void edit_paste(); + + /** edit viewing and configuration options. */ + void edit_options(); + + /** + Functions for printing, previewing a print, and setting up printing + parameters. + */ + void print(); + + /** Export as HTML file */ + void exportWeb(); + + /** Export as iCalendar file */ + void exportICalendar(); + + /** Export as vCalendar file */ + void exportVCalendar(); + + /** pop up a dialog to show an existing appointment. */ + void appointment_show(); + /** + * pop up an Appointment Dialog to edit an existing appointment. Get + * information on the appointment from the list of unique IDs that is + * currently in the View, called currIds. + */ + void appointment_edit(); + /** + * pop up dialog confirming deletion of currently selected event in the + * View. + */ + void appointment_delete(); + + /* frees a subtodo 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 ); + + /** Take ownership of selected event. */ + void takeOverEvent(); + + /** Take ownership of all events in calendar. */ + void takeOverCalendar(); + + /** query whether or not the calendar is "dirty". */ + bool isModified(); + /** set the state of calendar. Modified means "dirty", i.e. needing a save. */ + void setModified( bool modified = true ); + + /** query if the calendar is read-only. */ + bool isReadOnly(); + /** set state of calendar to read-only */ + void setReadOnly( bool readOnly = true ); + + void eventUpdated( Incidence * ); + + /* iTIP scheduling actions */ + void schedule_publish( Incidence *incidence = 0 ); + void schedule_request( Incidence *incidence = 0 ); + void schedule_refresh( Incidence *incidence = 0 ); + void schedule_cancel( Incidence *incidence = 0 ); + void schedule_add( Incidence *incidence = 0 ); + void schedule_reply( Incidence *incidence = 0 ); + void schedule_counter( Incidence *incidence = 0 ); + void schedule_declinecounter( Incidence *incidence = 0 ); + void schedule_forward( Incidence *incidence = 0 ); + void mailFreeBusy( int daysToPublish = 30 ); + void uploadFreeBusy(); + + void openAddressbook(); + + void editFilters(); + + void updateFilter(); + + void showIntro(); + + void showDateNavigator( bool ); + void showTodoView( bool ); + void showEventViewer( bool ); + + /** Move the current view date to the specified date */ + void goDate( const QDate& date ); + + /** Show the given date without changing date selection length. */ + void showDate( const QDate &date ); + + /** Move the current view date to today */ + void goToday(); + + /** Move to the next date(s) in the current view */ + void goNext(); + + /** Move to the previous date(s) in the current view */ + void goPrevious(); + + void toggleExpand(); + void showLeftFrame( bool show = true ); + + void dialogClosing( Incidence * ); + + void processMainViewSelection( Incidence * ); + void processTodoListSelection( Incidence * ); + + void processIncidenceSelection( Incidence * ); + + void purgeCompleted(); + + void slotCalendarChanged(); + + void slotAutoArchivingSettingsModified() { emit autoArchivingSettingsModified(); } + + void showErrorMessage( const QString & ); + void schedule( Scheduler::Method, Incidence *incidence ); + void addIncidenceOn( Incidence *, const QDate & ); + void moveIncidenceTo( Incidence *, const QDate & ); + void filterActivated( int filterNum ); + + void resourcesChanged(); + + protected slots: + /** Select a view or adapt the current view to display the specified dates. */ + void showDates( const KCal::DateList & ); + + public: + // show a standard warning + // returns KMsgBox::yesNoCancel() + int msgCalModified(); + + /** Adapt navigation units corresponding to step size of navigation of the + * current view. + */ + void adaptNavigationUnits(); + + //Attendee* getYourAttendee( Event *event ); + + protected: + void setIncidenceChanger( IncidenceChangerBase *changer ); + +// // returns KMsgBox::OKCancel() + int msgItemDelete( Incidence *incidence ); + + Todo *selectedTodo(); + + void warningChangeFailed( Incidence * ); + void checkForFilteredChange( Incidence *incidence ); + /** Adjust the given date/times by valid defaults (selection or configured + defaults, if invalid values are given) and allow the view to adjust the + type. */ + void dateTimesForNewEvent( QDateTime &startDt, QDateTime &endDt, bool &allDay ); + KOEventEditor *newEventEditor( const QDateTime &startDtParam = QDateTime(), + const QDateTime &endDtParam = QDateTime() , bool allDayParam = false ); + + private: + void init(); + + 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 ¬AllPurged ); + + KOrg::History *mHistory; + + QSplitter *mPanner; + QSplitter *mLeftSplitter; + QWidget *mLeftFrame; + QWidgetStack *mRightFrame; + + NavigatorBar *mNavigatorBar; + + DateNavigatorContainer *mDateNavigator; + + + QPtrList<CalendarViewExtension> mExtensions; + + Calendar *mCalendar; + + DateNavigator *mNavigator; + DateChecker *mDateChecker; + + KOEventViewer *mEventViewer; + KOViewManager *mViewManager; + KODialogManager *mDialogManager; + + // Calendar filters + QPtrList<CalFilter> mFilters; + CalFilter *mCurrentFilter; + + // various housekeeping variables. + bool mModified; // flag indicating if calendar is modified + bool mReadOnly; // flag indicating if calendar is read-only + QDate mSaveSingleDate; + + Incidence *mSelectedIncidence; + + KOTodoView *mTodoList; + QMap<Incidence*,KOIncidenceEditor*> mDialogList; + + KOrg::IncidenceChangerBase *mChanger; +}; + + + + +#endif diff --git a/korganizer/configure.in.in b/korganizer/configure.in.in new file mode 100644 index 000000000..850f2053c --- /dev/null +++ b/korganizer/configure.in.in @@ -0,0 +1,28 @@ +KDE_FIND_PATH(perl, PERL, [], + [ + AC_MSG_WARN([Couldn't find perl 5 or later. ical2vcal will not work.]) ], + [-e 'require 5.000;'] +) + +AC_SUBST(PERL) + +KDE_CHECK_STL +AC_HEADER_DIRENT +AC_HEADER_STDC +AC_CHECK_HEADERS(fcntl.h sys/time.h unistd.h sys/select.h \ + malloc.h sys/param.h libgen.h) +AC_HEADER_TIME + +AC_LANG_C +AC_C_LONG_DOUBLE +AC_TYPE_GETGROUPS + +dnl Checks for library functions. +AC_CHECK_FUNCS(socket strdup vsnprintf basename setenv unsetenv) +AC_CHECK_GETDOMAINNAME +AC_CHECK_GETHOSTNAME +AC_CHECK_USLEEP + +dnl AC_OUTPUT(korganizer/ical2vcal) + +AC_PROG_YACC diff --git a/korganizer/customlistviewitem.h b/korganizer/customlistviewitem.h new file mode 100644 index 000000000..c4ea1a97f --- /dev/null +++ b/korganizer/customlistviewitem.h @@ -0,0 +1,63 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef CUSTOMLISTVIEWITEM_H +#define CUSTOMLISTVIEWITEM_H + +#include <qmap.h> +#include <qstring.h> +#include <klistview.h> + +template<class T> +class CustomListViewItem : public KListViewItem +{ + public: + CustomListViewItem( T data, KListView *parent ) : + KListViewItem( parent ), mData( data ) { updateItem(); }; + CustomListViewItem( T data, KListView *parent, KListViewItem* after ) : + KListViewItem( parent, after ), mData( data ) { updateItem(); }; + ~CustomListViewItem() {}; + + void updateItem() {}; + + T data() const { return mData; } + + QString key(int column, bool) const + { + QMap<int,QString>::ConstIterator it = mKeyMap.find(column); + if (it == mKeyMap.end()) return text(column); + else return *it; + } + + void setSortKey(int column,const QString &key) + { + mKeyMap.insert(column,key); + } + + private: + T mData; + + QMap<int,QString> mKeyMap; +}; + +#endif diff --git a/korganizer/datechecker.cpp b/korganizer/datechecker.cpp new file mode 100644 index 000000000..43654983b --- /dev/null +++ b/korganizer/datechecker.cpp @@ -0,0 +1,97 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2002 Adriaan de Groot <groot@kde.org> + Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qtimer.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kglobal.h> + +#include "datechecker.h" + +DateChecker::DateChecker( QObject *parent, const char *name ) + : QObject( parent, name ), mUpdateTimer( 0 ) +{ + enableRollover( FollowMonth ); +} + +DateChecker::~DateChecker() +{ +} + +void DateChecker::enableRollover( RolloverType r ) +{ + switch( r ) { + case None: + if ( mUpdateTimer ) { + mUpdateTimer->stop(); + delete mUpdateTimer; + mUpdateTimer = 0; + } + break; + case FollowDay: + case FollowMonth: + if ( !mUpdateTimer ) { + mUpdateTimer = new QTimer( this, "mUpdateTimer" ); + connect( mUpdateTimer, SIGNAL( timeout() ), + SLOT( possiblyPastMidnight() ) ); + } + mUpdateTimer->start( 0, true ); + mLastDayChecked = QDate::currentDate(); + } + mUpdateRollover = r; +} + +void DateChecker::passedMidnight() +{ + QDate today = QDate::currentDate(); + + if ( today.month() != mLastDayChecked.month() ) { + if ( mUpdateRollover == FollowMonth ) { + emit monthPassed( today ); + } + } + emit dayPassed( today ); +} + +void DateChecker::possiblyPastMidnight() +{ + if ( mLastDayChecked != QDate::currentDate() ) { + passedMidnight(); + mLastDayChecked = QDate::currentDate(); + } + // Set the timer to go off 1 second after midnight + // or after 8 minutes, whichever comes first. + if ( mUpdateTimer ) { + QTime now = QTime::currentTime(); + QTime midnight = QTime( 23, 59, 59 ); + int msecsWait = QMIN( 480000, now.msecsTo( midnight ) + 2000 ); + + mUpdateTimer->stop(); + mUpdateTimer->start( msecsWait, true ); + } +} + +#include "datechecker.moc" diff --git a/korganizer/datechecker.h b/korganizer/datechecker.h new file mode 100644 index 000000000..f2d20bf3b --- /dev/null +++ b/korganizer/datechecker.h @@ -0,0 +1,86 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2002 Adriaan de Groot <groot@kde.org> + Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef DATECHECKER_H +#define DATECHECKER_H + +#include <qobject.h> +#include <qdatetime.h> + +class QTimer; + +class KCalendarSystem; + +class NavigatorBar; + +class DateChecker: public QObject +{ + Q_OBJECT + public: + DateChecker( QObject *parent = 0, const char *name = 0 ); + ~DateChecker(); + + /** + The DateChecker automatically checks for + the passage of midnight. If rollover type is + set to None, no signals are emitted and no + processing is done. With rollover set to + FollowDay, the day highlighter changes at + midnight and dayPassed() is emitted. + With FollowMonth, it has the same effect + as FollowDay but also adjusts the month that is + visible and emits monthPassed() when the month changes. + */ + enum RolloverType { None, FollowDay, FollowMonth }; + void enableRollover( RolloverType ); + + signals: + // Signals emitted at midnight carrying the new date. + void dayPassed( const QDate & ); + void monthPassed( const QDate & ); + + protected slots: + /** + Called regularly to see if we need to update the view + wrt. the today box and the month box. Only important + if you leave KOrganizer idle for long periods of time. + + Until we have a reliable way of setting QTimers to go + off at a particular wall-clock time, we need this, + which calls passedMidnight() at the right moments. + */ + void possiblyPastMidnight(); + + /** + Handles updating the view when midnight has come by due to idle time. + */ + void passedMidnight(); + + private: + QTimer *mUpdateTimer; + QDate mLastDayChecked; + RolloverType mUpdateRollover; +}; + +#endif diff --git a/korganizer/datenavigator.cpp b/korganizer/datenavigator.cpp new file mode 100644 index 000000000..56360ca2e --- /dev/null +++ b/korganizer/datenavigator.cpp @@ -0,0 +1,265 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "datenavigator.h" + +#include "koglobals.h" + +#include <kcalendarsystem.h> + +#include <kdebug.h> +#include <kglobal.h> +#include <klocale.h> + +using namespace KCal; + +DateNavigator::DateNavigator( QObject *parent, const char *name ) + : QObject( parent, name ) +{ + mSelectedDates.append( QDate::currentDate() ); +} + +DateNavigator::~DateNavigator() +{ +} + +DateList DateNavigator::selectedDates() +{ + return mSelectedDates; +} + +int DateNavigator::datesCount() const +{ + return mSelectedDates.count(); +} + +void DateNavigator::selectDates( const DateList& dateList ) +{ + if (dateList.count() > 0) { + mSelectedDates = dateList; + + emitSelected(); + } +} + +void DateNavigator::selectDate( const QDate &date ) +{ + QDate d = date; + + if ( !d.isValid() ) { + kdDebug(5850) << "DateNavigator::selectDates(QDate): an invalid date was passed as a parameter!" << endl; + d = QDate::currentDate(); + } + + mSelectedDates.clear(); + mSelectedDates.append( d ); + + emitSelected(); +} + +void DateNavigator::selectDates( int count ) +{ + selectDates( mSelectedDates.first(), count ); +} + +void DateNavigator::selectDates( const QDate &d, int count ) +{ + DateList dates; + + int i; + for( i = 0; i < count; ++i ) { + dates.append( d.addDays( i ) ); + } + + mSelectedDates = dates; + + emitSelected(); +} + +void DateNavigator::selectWeekByDay( int weekDay, const QDate &d ) +{ + int dateCount = mSelectedDates.count(); + bool weekStart = ( weekDay == KGlobal::locale()->weekStartDay() ); + if ( weekStart && dateCount == 7 ) selectWeek( d ); + else selectDates( d, dateCount ); +} + +void DateNavigator::selectWeek() +{ + selectWeek( mSelectedDates.first() ); +} + +void DateNavigator::selectWeek( const QDate &d ) +{ + int dayOfWeek = KOGlobals::self()->calendarSystem()->dayOfWeek( d ); + + int weekStart = KGlobal::locale()->weekStartDay(); + + QDate firstDate = d.addDays( weekStart - dayOfWeek ); + + if ( weekStart != 1 && dayOfWeek < weekStart ) { + firstDate = firstDate.addDays( -7 ); + } + + selectDates( firstDate, 7 ); +} + +void DateNavigator::selectWorkWeek() +{ + selectWorkWeek( mSelectedDates.first() ); +} + +void DateNavigator::selectWorkWeek( const QDate &d ) +{ + int weekStart = KGlobal::locale()->weekStartDay(); + + int dayOfWeek = KOGlobals::self()->calendarSystem()->dayOfWeek( d ); + + QDate currentDate = d.addDays( weekStart - dayOfWeek ); + + if ( weekStart != 1 && dayOfWeek < weekStart ) { + currentDate = currentDate.addDays( -7 ); + } + + mSelectedDates.clear(); + int mask = KOGlobals::self()->getWorkWeekMask(); + + for ( int i = 0; i < 7; ++i ) { + if( (1<< ((i + weekStart + 6) % 7)) & (mask) ) { + mSelectedDates.append(currentDate.addDays(i)); + } + } + + emitSelected(); +} + +void DateNavigator::selectToday() +{ + QDate d = QDate::currentDate(); + + int dateCount = mSelectedDates.count(); + + if ( dateCount == 7 ) selectWeek( d ); + else selectDates( d, dateCount ); +} + +void DateNavigator::selectPreviousYear() +{ + QDate firstSelected = mSelectedDates.first(); + int weekDay = firstSelected.dayOfWeek(); + firstSelected = KOGlobals::self()->calendarSystem()->addYears( firstSelected, -1 ); + + selectWeekByDay( weekDay, firstSelected ); +} + +void DateNavigator::selectPreviousMonth() +{ + QDate firstSelected = mSelectedDates.first(); + int weekDay = firstSelected.dayOfWeek(); + firstSelected = KOGlobals::self()->calendarSystem()->addMonths( firstSelected, -1 ); + + selectWeekByDay( weekDay, firstSelected ); +} + +void DateNavigator::selectPreviousWeek() +{ + QDate firstSelected = mSelectedDates.first(); + int weekDay = firstSelected.dayOfWeek(); + firstSelected = KOGlobals::self()->calendarSystem()->addDays( firstSelected, -7 ); + + selectWeekByDay( weekDay, firstSelected ); +} + +void DateNavigator::selectNextWeek() +{ + QDate firstSelected = mSelectedDates.first(); + int weekDay = firstSelected.dayOfWeek(); + + firstSelected = KOGlobals::self()->calendarSystem()->addDays( firstSelected, 7 ); + + selectWeekByDay( weekDay, firstSelected ); +} + +void DateNavigator::selectNextMonth() +{ + QDate firstSelected = mSelectedDates.first(); + int weekDay = firstSelected.dayOfWeek(); + + firstSelected = KOGlobals::self()->calendarSystem()->addMonths( firstSelected, 1 ); + + selectWeekByDay( weekDay, firstSelected ); +} + +void DateNavigator::selectNextYear() +{ + QDate firstSelected = mSelectedDates.first(); + int weekDay = firstSelected.dayOfWeek(); + firstSelected = KOGlobals::self()->calendarSystem()->addYears( firstSelected, 1 ); + + selectWeekByDay( weekDay, firstSelected ); +} + +void DateNavigator::selectPrevious() +{ + int offset = -7; + if ( datesCount() == 1 ) { + offset = -1; + } + + selectDates( mSelectedDates.first().addDays( offset ), datesCount() ); +} + +void DateNavigator::selectNext() +{ + int offset = 7; + if ( datesCount() == 1 ) { + offset = 1; + } + + selectDates( mSelectedDates.first().addDays( offset ), datesCount() ); +} + +void DateNavigator::selectMonth(int month) +{ + QDate 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 ); + 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; + calSys->setYMD( firstSelected, calSys->year( firstSelected ), month, day ); + + selectWeekByDay( weekDay, firstSelected ); +} + +void DateNavigator::emitSelected() +{ + emit datesSelected( mSelectedDates ); +} + +#include "datenavigator.moc" diff --git a/korganizer/datenavigator.h b/korganizer/datenavigator.h new file mode 100644 index 000000000..062f1a67d --- /dev/null +++ b/korganizer/datenavigator.h @@ -0,0 +1,86 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef DATENAVIGATOR_H +#define DATENAVIGATOR_H + +#include <libkcal/incidencebase.h> + +#include <qobject.h> + +/** + This class controls date navigation. All requests to move the views to another + date are sent to the DateNavigator. The DateNavigator processes the new + selection of dates and emits the required signals for the views. +*/ +class DateNavigator : public QObject +{ + Q_OBJECT + public: + DateNavigator( QObject *parent = 0, const char *name = 0 ); + ~DateNavigator(); + + KCal::DateList selectedDates(); + + int datesCount() const; + + public slots: + void selectDates( const KCal::DateList & ); + void selectDate( const QDate & ); + + void selectDates( int count ); + void selectDates( const QDate &, int count ); + + void selectWeek(); + void selectWeek( const QDate & ); + + void selectWorkWeek(); + void selectWorkWeek( const QDate & ); + + void selectWeekByDay( int weekDay, const QDate & ); + + void selectToday(); + + void selectPreviousYear(); + void selectPreviousMonth(); + void selectPreviousWeek(); + void selectNextWeek(); + void selectNextMonth(); + void selectNextYear(); + + void selectPrevious(); + void selectNext(); + + void selectMonth(int month); + + signals: + void datesSelected( const KCal::DateList & ); + + protected: + void emitSelected(); + + private: + KCal::DateList mSelectedDates; +}; + +#endif diff --git a/korganizer/datenavigatorcontainer.cpp b/korganizer/datenavigatorcontainer.cpp new file mode 100644 index 000000000..61be083b4 --- /dev/null +++ b/korganizer/datenavigatorcontainer.cpp @@ -0,0 +1,266 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001,2002,2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <kdebug.h> +#include <klocale.h> + +#include "koglobals.h" +#include "navigatorbar.h" +#include "kdatenavigator.h" + +#include <kcalendarsystem.h> +#include <kdialog.h> + +#include "datenavigatorcontainer.h" + +#include <qwhatsthis.h> +#include <qtimer.h> + +DateNavigatorContainer::DateNavigatorContainer( QWidget *parent, + const char *name ) + : QFrame( parent, name ), mCalendar( 0 ), + mHorizontalCount( 1 ), mVerticalCount( 1 ) +{ + mExtraViews.setAutoDelete( true ); + setFrameStyle( QFrame::Sunken | QFrame::StyledPanel ); + + mNavigatorView = new KDateNavigator( this, name ); + QWhatsThis::add( mNavigatorView, + i18n( "<qt><p>Select the dates you want to " + "display in KOrganizer's main view here. Hold down the " + "mouse button to select more than one day.</p>" + "<p>Press the top buttons to browse to the next " + "/ previous months or years.</p>" + "<p>Each line shows a week. The number in the left " + "column is the number of the week in the year. " + "Press it to select the whole week.</p>" + "</qt>" ) ); + + connectNavigatorView( mNavigatorView ); +} + +DateNavigatorContainer::~DateNavigatorContainer() +{ +} + +void DateNavigatorContainer::connectNavigatorView( KDateNavigator *v ) +{ + connect( v, SIGNAL( datesSelected( const KCal::DateList & ) ), + SIGNAL( datesSelected( const KCal::DateList & ) ) ); + connect( v, SIGNAL( incidenceDropped( Incidence *, const QDate & ) ), + SIGNAL( incidenceDropped( Incidence *, const QDate & ) ) ); + connect( v, SIGNAL( incidenceDroppedMove( Incidence *, const QDate & ) ), + SIGNAL( incidenceDroppedMove( Incidence *, const QDate & ) ) ); + connect( v, SIGNAL( weekClicked( const QDate & ) ), + SIGNAL( weekClicked( const QDate & ) ) ); + + connect( v, SIGNAL( goPrevious() ), SIGNAL( goPrevious() ) ); + connect( v, SIGNAL( goNext() ), SIGNAL( goNext() ) ); + + connect( v, SIGNAL( goNextMonth() ), SIGNAL( goNextMonth() ) ); + connect( v, SIGNAL( goPrevMonth() ), SIGNAL( goPrevMonth() ) ); + connect( v, SIGNAL( goNextYear() ), SIGNAL( goNextYear() ) ); + connect( v, SIGNAL( goPrevYear() ), SIGNAL( goPrevYear() ) ); + + connect( v, SIGNAL( goMonth( int ) ), SIGNAL( goMonth( int ) ) ); +} + +void DateNavigatorContainer::setCalendar( Calendar *cal ) +{ + mCalendar = cal; + mNavigatorView->setCalendar( cal ); + KDateNavigator *n; + for( n = mExtraViews.first(); n; n = mExtraViews.next() ) { + n->setCalendar( cal ); + } +} + +// TODO_Recurrence: let the navigators update just once, and tell them that +// if data has changed or just the selection (because then the list of dayss +// with events doesn't have to be updated if the month stayed the same +void DateNavigatorContainer::updateDayMatrix() +{ + mNavigatorView->updateDayMatrix(); + KDateNavigator *n; + for( n = mExtraViews.first(); n; n = mExtraViews.next() ) { + n->updateDayMatrix(); + } +} + +void DateNavigatorContainer::updateToday() +{ + mNavigatorView->updateToday(); + KDateNavigator *n; + for( n = mExtraViews.first(); n; n = mExtraViews.next() ) { + n->updateToday(); + } +} + +void DateNavigatorContainer::updateView() +{ + mNavigatorView->updateView(); + KDateNavigator *n; + for( n = mExtraViews.first(); n; n = mExtraViews.next() ) { + n->updateView(); + } +} + +void DateNavigatorContainer::updateConfig() +{ + mNavigatorView->updateConfig(); + KDateNavigator *n; + for( n = mExtraViews.first(); n; n = mExtraViews.next() ) { + n->updateConfig(); + } +} + +void DateNavigatorContainer::selectDates( const DateList &dateList ) +{ + if ( !dateList.isEmpty() ) { + QDate start( dateList.first() ); + QDate end( dateList.last() ); + QDate navfirst( mNavigatorView->startDate() ); + QDate navsecond; // start of the second shown month if existant + QDate navlast; + if ( !mExtraViews.isEmpty() ) { + navlast = mExtraViews.last()->endDate(); + navsecond = mExtraViews.first()->startDate(); + } else { + navlast = mNavigatorView->endDate(); + navsecond = navfirst; + } + 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 ); + } + + mNavigatorView->selectDates( dateList ); + KDateNavigator *n = mExtraViews.first(); + while ( n ) { + n->selectDates( dateList ); + n = mExtraViews.next(); + } + } +} + +void DateNavigatorContainer::setBaseDates( const QDate &start ) +{ + QDate baseDate = start; + mNavigatorView->setBaseDate( baseDate ); + for( KDateNavigator *n = mExtraViews.first(); n; n = mExtraViews.next() ) { + baseDate = KOGlobals::self()->calendarSystem()->addMonths( baseDate, 1 ); + n->setBaseDate( baseDate ); + } +} + +void DateNavigatorContainer::resizeEvent( QResizeEvent * ) +{ +#if 0 + kdDebug(5850) << "DateNavigatorContainer::resizeEvent()" << endl; + kdDebug(5850) << " CURRENT SIZE: " << size() << endl; + kdDebug(5850) << " MINIMUM SIZEHINT: " << minimumSizeHint() << endl; + kdDebug(5850) << " SIZEHINT: " << sizeHint() << endl; + kdDebug(5850) << " MINIMUM SIZE: " << minimumSize() << endl; +#endif + QTimer::singleShot( 0, this, SLOT( resizeAllContents() ) ); +} + +void DateNavigatorContainer::resizeAllContents() +{ + QSize minSize = mNavigatorView->minimumSizeHint(); + +// kdDebug(5850) << " NAVIGATORVIEW minimumSizeHint: " << minSize << endl; + + int margin = KDialog::spacingHint(); + int verticalCount = ( size().height() - margin*2 ) / minSize.height(); + int horizontalCount = ( size().width() - margin*2 ) / minSize.width(); + + if ( horizontalCount != mHorizontalCount || + verticalCount != mVerticalCount ) { + uint count = horizontalCount * verticalCount; + if ( count == 0 ) return; + + while ( count > ( mExtraViews.count() + 1 ) ) { + KDateNavigator *n = new KDateNavigator( this ); + mExtraViews.append( n ); + n->setCalendar( mCalendar ); + connectNavigatorView( n ); + } + + while ( count < ( mExtraViews.count() + 1 ) ) { + mExtraViews.removeLast(); + } + + mHorizontalCount = horizontalCount; + mVerticalCount = verticalCount; + setBaseDates( mNavigatorView->selectedDates().first() ); + selectDates( mNavigatorView->selectedDates() ); + for( KDateNavigator *n = mExtraViews.first(); n; n = mExtraViews.next() ) { + n->show(); + } + } + + int height = (size().height() - margin*2) / verticalCount; + int width = (size().width() - margin*2) / horizontalCount; + + NavigatorBar *bar = mNavigatorView->navigatorBar(); + 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 ); + } + view->setGeometry( + ( ( (KOGlobals::self()->reverseLayout())?(horizontalCount-1-x):x) * width ) + margin, + ( y * height ) + margin, width, height ); + } +} + +QSize DateNavigatorContainer::minimumSizeHint() const +{ + int margin = KDialog::spacingHint() * 2; + return mNavigatorView->minimumSizeHint() + QSize( margin, margin ); +} + +QSize DateNavigatorContainer::sizeHint() const +{ + int margin = KDialog::spacingHint() * 2; + return mNavigatorView->sizeHint() + QSize( margin, margin ); +} + +#include "datenavigatorcontainer.moc" diff --git a/korganizer/datenavigatorcontainer.h b/korganizer/datenavigatorcontainer.h new file mode 100644 index 000000000..07be7cbf0 --- /dev/null +++ b/korganizer/datenavigatorcontainer.h @@ -0,0 +1,92 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef DATENAVIGATORCONTAINER_H +#define DATENAVIGATORCONTAINER_H + +#include <qframe.h> + +class KDateNavigator; + +class DateNavigatorContainer: public QFrame +{ + Q_OBJECT + public: + DateNavigatorContainer( QWidget *parent = 0, const char *name = 0 ); + ~DateNavigatorContainer(); + + /** + Associate date navigator with a calendar. It is used by KODayMatrix. + */ + void setCalendar( Calendar * ); + + QSize minimumSizeHint() const; + QSize sizeHint() const; + + public slots: + void selectDates( const KCal::DateList & ); + void updateView(); + void updateConfig(); + void updateDayMatrix(); + void updateToday(); + + signals: + void datesSelected( const KCal::DateList & ); + void incidenceDropped( Incidence *, const QDate & ); + void incidenceDroppedMove( Incidence *, const QDate & ); + void weekClicked( const QDate &); + + void goPrevious(); + void goNext(); + + void goNextMonth(); + void goPrevMonth(); + void goNextYear(); + void goPrevYear(); + + void goMonth( int month ); + + protected: + void resizeEvent( QResizeEvent * ); + void setBaseDates( const QDate &start ); + void connectNavigatorView( KDateNavigator *v ); + protected slots: + /** Resizes all the child elements after the size of the widget + changed. This slot is called by a QTimer::singleShot from + resizeEvent. This makes the UI seem more responsive, since + the other parts of the splitter are resized earlier now */ + void resizeAllContents(); + + private: + KDateNavigator *mNavigatorView; + + KCal::Calendar *mCalendar; + + QPtrList<KDateNavigator> mExtraViews; + + int mHorizontalCount; + int mVerticalCount; +}; + +#endif diff --git a/korganizer/dcopcalendar.desktop b/korganizer/dcopcalendar.desktop new file mode 100644 index 000000000..df5c098a8 --- /dev/null +++ b/korganizer/dcopcalendar.desktop @@ -0,0 +1,58 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=DCOP/Organizer +Comment=Organizer with a DCOP interface +Comment[af]=Organiseerder met 'n DCOP koppelvlak +Comment[be]=Арганізатар з DCOP інтэрфэйсам +Comment[bg]=Организатор с поддръжка на интерфейс DCOP +Comment[br]=Deiziater gant un etrefas DCOP +Comment[bs]=Organizer sa DCOP interfejsom +Comment[ca]=Organitzador amb una interfície DCOP +Comment[cs]=Organizátor s DCOP rozhraním +Comment[cy]=Trefnydd gyda rhyngwyneb DCOP +Comment[da]=Organisator med en DCOP-grænseflade +Comment[de]=Organizer mit DCOP-Schnittstelle +Comment[el]=Organizer με περιβάλλον χρήσης DCOP +Comment[en_GB]=Organiser with a DCOP interface +Comment[eo]=Organizilo kun DCOP-interfaco +Comment[es]=Organizador con un interfaz DCOP +Comment[et]=KOrganizer DCOP-liidesega +Comment[eu]=DCOP interfazedun antolatzailea +Comment[fa]=سازماندهنده با یک واسط DCOP +Comment[fi]=Kalenteri DCOP-rajapinnalla +Comment[fr]=Organiseur avec une interface DCOP +Comment[fy]=Organizer mei in DCOP-ynterface +Comment[gl]=Organizador con interface DCOP +Comment[he]=ארגונים עם ממשק DCOP +Comment[hi]=डीकॉप इंटरफेस सहित आर्गेनाइज़र +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 +Comment[mk]=Организатор со DCOP-интерфејс +Comment[ms]=Penyusun dengan antara muka DCOP +Comment[nb]=Organizer med DCOP-grensesnitt +Comment[nds]=Mötenkalenner mit DCOP-Koppelsteed +Comment[ne]=DCOP इन्टरफेसको आयोजक +Comment[nl]=Organizer met een DCOP-interface +Comment[nn]=Organisator med eit DCOP-grensesnitt +Comment[pl]=Organizator z interfejsem DCOP +Comment[pt]=Organizador com uma interface de DCOP +Comment[pt_BR]=Organizador com uma interface DCOP +Comment[ro]=Organizator cu interfaţă DCOP +Comment[ru]=Органайзер с интерфейсом DCOP +Comment[sk]=Organizér s DCOP rozhraním +Comment[sl]=Oragnizator z vmesnikom DCOP +Comment[sr]=Организатор са DCOP интерфејсом +Comment[sr@Latn]=Organizator sa DCOP interfejsom +Comment[sv]=Filofax med DCOP-gränssnitt +Comment[ta]=DCOP முகப்பு அமைப்பாளர் +Comment[tg]=Органайзер бо интерфейси DCOP +Comment[tr]=DCOP arayüzü ile Organizer +Comment[uk]=Тижневик з інтерфейсом DCOP +Comment[zh_CN]=具有 DCOP 接口的 PDA +Comment[zh_TW]=有 DCOP 介面的 Organizer diff --git a/korganizer/docprefs.cpp b/korganizer/docprefs.cpp new file mode 100644 index 000000000..958eb236e --- /dev/null +++ b/korganizer/docprefs.cpp @@ -0,0 +1,68 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <ksimpleconfig.h> +#include <kstandarddirs.h> +#include <kdebug.h> + +#include "docprefs.h" + +KSimpleConfig *DocPrefs::mConfig = 0; + +DocPrefs::DocPrefs( const QString &type ) +{ + if ( !mConfig ) { + mConfig = new KSimpleConfig( locateLocal( "data", "korganizer/docprefs." + type + ".kconfig" ) ); + } +} + +DocPrefs::~DocPrefs() +{ + mConfig->sync(); +} + +void DocPrefs::setDoc( const QString &identifier ) +{ + mDocId = identifier; +} + +QString DocPrefs::doc() const +{ + return mDocId; +} + +bool DocPrefs::readBoolEntry( const QString &id ) const +{ + mConfig->setGroup( mDocId ); + bool result = mConfig->readBoolEntry( id, false ); +// kdDebug(5850) << "DocPrefs::readEntry(): " << id << " : " << (result ? "True" : "False" ) << endl; + return result; +} + +void DocPrefs::writeEntry( const QString &id, bool value ) +{ +// kdDebug(5850) << "DocPrefs::writeEntry(): " << id << " : " << (value ? "True" : "False" ) << endl; + mConfig->setGroup( mDocId ); + mConfig->writeEntry( id, value ); +} diff --git a/korganizer/docprefs.h b/korganizer/docprefs.h new file mode 100644 index 000000000..0c9609ed5 --- /dev/null +++ b/korganizer/docprefs.h @@ -0,0 +1,49 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef DOCPREFS_H +#define DOCPREFS_H + +#include <qstring.h> + +class KSimpleConfig; + +class DocPrefs +{ + public: + DocPrefs( const QString &type="general" ); + ~DocPrefs(); + + void setDoc( const QString &identifier ); + QString doc() const; + + bool readBoolEntry( const QString &identifier ) const; + void writeEntry( const QString &identifier, bool value ); + + private: + static KSimpleConfig *mConfig; + + QString mDocId; +}; + +#endif diff --git a/korganizer/eventarchiver.cpp b/korganizer/eventarchiver.cpp new file mode 100644 index 000000000..f4ff3cbf9 --- /dev/null +++ b/korganizer/eventarchiver.cpp @@ -0,0 +1,225 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (c) 2004 David Faure <faure@kde.org> + Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "eventarchiver.h" +#include <kglobal.h> +#include <klocale.h> +#include <ktempfile.h> +#include <kio/netaccess.h> +#include <kglobal.h> +#include <libkcal/filestorage.h> +#include <libkcal/calendarlocal.h> +#include <libkcal/calendar.h> +#include <kmessagebox.h> +#include <kdebug.h> +#include "koprefs.h" + +EventArchiver::EventArchiver( QObject* parent, const char* name ) + : QObject( parent, name ) +{ +} + +EventArchiver::~EventArchiver() +{ +} + +void EventArchiver::runOnce( Calendar* calendar, const QDate& limitDate, QWidget* widget ) +{ + run( calendar, limitDate, widget, true, true ); +} + +void EventArchiver::runAuto( Calendar* calendar, QWidget* widget, bool withGUI ) +{ + QDate limitDate( QDate::currentDate() ); + int expiryTime = KOPrefs::instance()->mExpiryTime; + switch (KOPrefs::instance()->mExpiryUnit) { + case KOPrefs::UnitDays: // Days + limitDate = limitDate.addDays( -expiryTime ); + break; + case KOPrefs::UnitWeeks: // Weeks + limitDate = limitDate.addDays( -expiryTime*7 ); + break; + case KOPrefs::UnitMonths: // Months + limitDate = limitDate.addMonths( -expiryTime ); + break; + default: + return; + } + run( calendar, limitDate, widget, withGUI, false ); +} + +void EventArchiver::run( Calendar* calendar, const QDate& limitDate, QWidget* 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( + QDate( 1769, 12, 1 ), + // #29555, also advertised by the "limitDate not included" in the class docu + limitDate.addDays( -1 ), + true ); + } + if ( KOPrefs::instance()->mArchiveTodos ) { + 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 ) ) { + todos.append( *it ); + } + } + } + + incidences = Calendar::mergeIncidenceList( events, todos, journals ); + + + 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" ); + return; + } + + + switch ( KOPrefs::instance()->mArchiveAction ) { + case KOPrefs::actionDelete: + deleteIncidences( calendar, limitDate, widget, incidences, withGUI ); + break; + case KOPrefs::actionArchive: + archiveIncidences( calendar, limitDate, widget, incidences, withGUI ); + break; + } +} + +void EventArchiver::deleteIncidences( Calendar* calendar, const QDate& limitDate, QWidget* widget, const Incidence::List& incidences, bool withGUI ) +{ + QStringList incidenceStrs; + Incidence::List::ConstIterator it; + for( it = incidences.begin(); it != incidences.end(); ++it ) { + incidenceStrs.append( (*it)->summary() ); + } + + if ( withGUI ) { + int result = KMessageBox::warningContinueCancelList( + widget, i18n("Delete all items before %1 without saving?\n" + "The following items will be deleted:") + .arg(KGlobal::locale()->formatDate(limitDate)), incidenceStrs, + i18n("Delete Old Items"),KStdGuiItem::del()); + if (result != KMessageBox::Continue) + return; + } + for( it = incidences.begin(); it != incidences.end(); ++it ) { + calendar->deleteIncidence( *it ); + } + emit eventsDeleted(); +} + +void EventArchiver::archiveIncidences( Calendar* calendar, const QDate& /*limitDate*/, QWidget* widget, const Incidence::List& incidences, bool /*withGUI*/) +{ + FileStorage storage( calendar ); + + // Save current calendar to disk + KTempFile tmpFile; + tmpFile.setAutoDelete(true); + storage.setFileName( tmpFile.name() ); + if ( !storage.save() ) { + kdDebug(5850) << "EventArchiver::archiveEvents(): Can't save calendar to temp file" << endl; + return; + } + + // Duplicate current calendar by loading in new calendar object + CalendarLocal archiveCalendar( KOPrefs::instance()->mTimeZoneId ); + + FileStorage archiveStore( &archiveCalendar ); + archiveStore.setFileName( tmpFile.name() ); + if (!archiveStore.load()) { + kdDebug(5850) << "EventArchiver::archiveEvents(): Can't load calendar from temp file" << endl; + return; + } + + // Strip active events from calendar so that only events to be archived + // remain. This is not really efficient, but there is no other easy way. + QStringList uids; + Incidence::List allIncidences = archiveCalendar.rawIncidences(); + Incidence::List::ConstIterator it; + for( it = incidences.begin(); it != incidences.end(); ++it ) { + uids << (*it)->uid(); + } + for( it = allIncidences.begin(); it != allIncidences.end(); ++it ) { + if ( !uids.contains( (*it)->uid() ) ) { + archiveCalendar.deleteIncidence( *it ); + } + } + + // Get or create the archive file + KURL archiveURL( KOPrefs::instance()->mArchiveFile ); + QString archiveFile; + + if ( KIO::NetAccess::exists( archiveURL, true, widget ) ) { + if( !KIO::NetAccess::download( archiveURL, archiveFile, widget ) ) { + kdDebug(5850) << "EventArchiver::archiveEvents(): Can't download archive file" << endl; + return; + } + // Merge with events to be archived. + archiveStore.setFileName( archiveFile ); + if ( !archiveStore.load() ) { + kdDebug(5850) << "EventArchiver::archiveEvents(): Can't merge with archive file" << endl; + return; + } + } else { + archiveFile = tmpFile.name(); + } + + // Save archive calendar + if ( !archiveStore.save() ) { + KMessageBox::error(widget,i18n("Cannot write archive file %1.").arg( archiveStore.fileName() )); + return; + } + + // Upload if necessary + KURL srcUrl; + srcUrl.setPath(archiveFile); + if (srcUrl != archiveURL) { + if ( !KIO::NetAccess::upload( archiveFile, archiveURL, widget ) ) { + KMessageBox::error(widget,i18n("Cannot write archive to final destination.")); + return; + } + } + + KIO::NetAccess::removeTempFile(archiveFile); + + // Delete archived events from calendar + for( it = incidences.begin(); it != incidences.end(); ++it ) { + calendar->deleteIncidence( *it ); + } + emit eventsDeleted(); +} + +#include "eventarchiver.moc" diff --git a/korganizer/eventarchiver.h b/korganizer/eventarchiver.h new file mode 100644 index 000000000..2826e7a92 --- /dev/null +++ b/korganizer/eventarchiver.h @@ -0,0 +1,84 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (c) 2004 David Faure <faure@kde.org> + Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef EVENTARCHIVER_H +#define EVENTARCHIVER_H + +#include <qobject.h> +#include <qdatetime.h> +#include <libkcal/event.h> + +namespace KCal { +class Calendar; +class Event; +} +using namespace KCal; + +/** + * This class handles expiring and archiving of events. + * It is used directly by the archivedialog, and it is also + * triggered by actionmanager's timer for auto-archiving. + * + * The settings are not held in this class, but directly in KOPrefs (from korganizer.kcfg) + * Be sure to set mArchiveAction and mArchiveFile before a manual archiving + * mAutoArchive is used for auto archiving. + */ +class EventArchiver : public QObject +{ + Q_OBJECT + + public: + EventArchiver( QObject* parent = 0, const char* name = 0 ); + virtual ~EventArchiver(); + + /** + * Delete or archive events once + * @param calendar the calendar to archive + * @param limitDate all events *before* the limitDate (not included) will be deleted/archived. + * @param widget parent widget for message boxes + * Confirmation and "no events to process" dialogs will be shown + */ + void runOnce( Calendar* calendar, const QDate& limitDate, QWidget* widget ); + + /** + * Delete or archive events. This is called regularly, when auto-archiving is enabled + * @param calendar the calendar to archive + * @param widget parent widget for message boxes + * @param withGUI whether this is called from the dialog, so message boxes should be shown. + * Note that error dialogs like "cannot save" are shown even if from this method, so widget + * should be set in all cases. + */ + void runAuto( Calendar* calendar, QWidget* widget, bool withGUI ); + + signals: + void eventsDeleted(); + + private: + void run( Calendar* calendar, const QDate& limitDate, QWidget* widget, bool withGUI, bool errorIfNone ); + + void deleteIncidences( Calendar* calendar, const QDate& limitDate, QWidget* widget, const Incidence::List& incidences, bool withGUI ); + void archiveIncidences( Calendar* calendar, const QDate& limitDate, QWidget* widget, const Incidence::List& incidences, bool withGUI ); +}; + +#endif /* EVENTARCHIVER_H */ diff --git a/korganizer/exportwebdialog.cpp b/korganizer/exportwebdialog.cpp new file mode 100644 index 000000000..e62b94c93 --- /dev/null +++ b/korganizer/exportwebdialog.cpp @@ -0,0 +1,257 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qlayout.h> +#include <qhgroupbox.h> +#include <qvgroupbox.h> +#include <qvbuttongroup.h> +#include <qradiobutton.h> +#include <qcheckbox.h> +#include <qlineedit.h> +#include <qhbox.h> +#include <qvbox.h> +#include <qpushbutton.h> +#include <qfiledialog.h> +#include <qtextstream.h> +#include <qlabel.h> + +#include <klocale.h> +#include <kdebug.h> +#include <kfiledialog.h> +#include <klineedit.h> +#include <kurl.h> +#include <kio/job.h> +#include <kstandarddirs.h> +#include <kconfig.h> +#include "koglobals.h" +#include <kurlrequester.h> +#include <kio/netaccess.h> +#include <knotifyclient.h> +#include <ktempfile.h> +#include <kmessagebox.h> + +#include <libkcal/calendar.h> +#include <libkcal/htmlexportsettings.h> + +#include <libkdepim/kdateedit.h> +#include <libkdepim/kdateedit.h> + +#include "koprefs.h" +#include "kocore.h" + +#include "exportwebdialog.h" +#include "exportwebdialog.moc" + + +// FIXME: The basic structure of this dialog has been copied from KPrefsDialog, +// because we want custom buttons, a Tabbed dialog, and a different +// headline... Maybe we should try to achieve the same without code +// duplication. +ExportWebDialog::ExportWebDialog( HTMLExportSettings *settings, QWidget *parent, + const char *name) + : KDialogBase( Tabbed,i18n("Export Calendar as Web Page"),Help|Default|User1|Cancel, User1, parent, name, false, false, i18n("Export") ), + KPrefsWidManager( settings ), mSettings( settings ) +{ + setupGeneralPage(); + setupEventPage(); + setupTodoPage(); +// Disabled bacause the functionality is not yet implemented. +// setupJournalPage(); +// setupFreeBusyPage(); +// setupAdvancedPage(); + + connect( this, SIGNAL( user1Clicked() ), SLOT( slotOk() ) ); + connect( this, SIGNAL( cancelClicked() ), SLOT( reject() ) ); + + readConfig(); +} + +ExportWebDialog::~ExportWebDialog() +{ +} + +void ExportWebDialog::setDefaults() +{ + setWidDefaults(); +} + +void ExportWebDialog::readConfig() +{ + readWidConfig(); + usrReadConfig(); +} + +void ExportWebDialog::writeConfig() +{ + writeWidConfig(); + usrWriteConfig(); + readConfig(); +} + +void ExportWebDialog::slotApply() +{ + writeConfig(); + emit configChanged(); +} + +void ExportWebDialog::slotOk() +{ + slotApply(); + emit exportHTML( mSettings ); + accept(); +} + +void ExportWebDialog::slotDefault() +{ + kdDebug(5850) << "KPrefsDialog::slotDefault()" << endl; + + if (KMessageBox::warningContinueCancel(this, + i18n("You are about to set all preferences to default values. All " + "custom modifications will be lost."),i18n("Setting Default Preferences"), + i18n("Reset to Defaults")) + == KMessageBox::Continue) setDefaults(); +} + + +void ExportWebDialog::setupGeneralPage() +{ + mGeneralPage = addPage( i18n("General") ); + QVBoxLayout *topLayout = new QVBoxLayout(mGeneralPage, 10); + + QGroupBox *rangeGroup = new QHGroupBox( i18n("Date Range"), mGeneralPage ); + topLayout->addWidget( rangeGroup ); + addWidDate( mSettings->dateStartItem(), rangeGroup ); + addWidDate( mSettings->dateEndItem(), rangeGroup ); + + QButtonGroup *typeGroup = new QVButtonGroup( i18n("View Type"), mGeneralPage ); + topLayout->addWidget( typeGroup ); +// addWidBool( mSettings->weekViewItem(), typeGroup ); + addWidBool( mSettings->monthViewItem(), typeGroup ); + addWidBool( mSettings->eventViewItem(), typeGroup ); + addWidBool( mSettings->todoViewItem(), typeGroup ); +// addWidBool( mSettings->journalViewItem(), typeGroup ); +// addWidBool( mSettings->freeBusyViewItem(), typeGroup ); + addWidBool( mSettings->excludePrivateItem(), typeGroup ); + addWidBool( mSettings->excludeConfidentialItem(), typeGroup ); + + QGroupBox *destGroup = new QVGroupBox(i18n("Destination"), mGeneralPage ); + topLayout->addWidget(destGroup); + KPrefsWidPath *pathWid = addWidPath( mSettings->outputFileItem(), + destGroup, "text/html", KFile::File ); + connect( pathWid->urlRequester(), SIGNAL( textChanged( const QString & ) ), + SLOT( slotTextChanged( const QString & ) ) ); + + topLayout->addStretch( 1 ); +} + +void ExportWebDialog::slotTextChanged( const QString & _text) +{ + enableButton( User1, !_text.isEmpty() ); +} + +void ExportWebDialog::setupTodoPage() +{ + mTodoPage = addPage(i18n("To-dos")); + QVBoxLayout *topLayout = new QVBoxLayout( mTodoPage, 10 ); + + QHBox *hbox = new QHBox( mTodoPage ); + topLayout->addWidget( hbox ); + addWidString( mSettings->todoListTitleItem(), hbox ); + + QVBox *vbox = new QVBox( mTodoPage ); + topLayout->addWidget( vbox ); + addWidBool( mSettings->taskDueDateItem(), vbox ); + addWidBool( mSettings->taskLocationItem(), vbox ); + addWidBool( mSettings->taskCategoriesItem(), vbox ); + addWidBool( mSettings->taskAttendeesItem(), vbox ); +// addWidBool( mSettings->taskExcludePrivateItem(), vbox ); +// addWidBool( mSettings->taskExcludeConfidentialItem(), vbox ); + + topLayout->addStretch(1); +} + +void ExportWebDialog::setupEventPage() +{ + mEventPage = addPage(i18n("Events")); + QVBoxLayout *topLayout = new QVBoxLayout( mEventPage, 10 ); + + QHBox *hbox = new QHBox( mEventPage ); + topLayout->addWidget( hbox ); + addWidString( mSettings->eventTitleItem(), hbox ); + + QVBox *vbox = new QVBox( mEventPage ); + topLayout->addWidget( vbox ); + addWidBool( mSettings->eventLocationItem(), vbox ); + addWidBool( mSettings->eventCategoriesItem(), vbox ); + addWidBool( mSettings->eventAttendeesItem(), vbox ); +// addWidBool( mSettings->eventExcludePrivateItem(), vbox ); +// addWidBool( mSettings->eventExcludeConfidentialItem(), vbox ); + + topLayout->addStretch(1); +} +/* +void ExportWebDialog::setupJournalPage() +{ + mJournalPage = addPage(i18n("Journal")); + QVBoxLayout *topLayout = new QVBoxLayout( mJournalPage, 10 ); + + QHBox *hbox = new QHBox( mJournalPage ); + topLayout->addWidget( hbox ); + addWidString( mSettings->journalTitleItem(), hbox ); + + QVBox *vbox = new QVBox( mJournalPage ); + topLayout->addWidget( vbox ); +// addWidBool( mSettings->eventExcludeConfidentialItem(), vbox ); + + topLayout->addStretch(1); +} + +void ExportWebDialog::setupFreeBusyPage() +{ + mFreeBusyPage = addPage(i18n("Free/Busy")); + QVBoxLayout *topLayout = new QVBoxLayout( mFreeBusyPage, 10 ); + + QHBox *hbox = new QHBox( mFreeBusyPage ); + topLayout->addWidget( hbox ); + addWidString( mSettings->journalTitleItem(), hbox ); + + QVBox *vbox = new QVBox( mFreeBusyPage ); + topLayout->addWidget( vbox ); +// addWidBool( mSettings->eventExcludeConfidentialItem(), vbox ); + + topLayout->addStretch(1); +} + +void ExportWebDialog::setupAdvancedPage() +{ + mAdvancedPage = addPage(i18n("Advanced")); + QVBoxLayout *topLayout = new QVBoxLayout( mAdvancedPage, 10 ); + + QVBox *vbox = new QVBox( mAdvancedPage ); + topLayout->addWidget( vbox ); +// addWidBool( mSettings->eventExcludeConfidentialItem(), vbox ); + + topLayout->addStretch(1); +} +*/ diff --git a/korganizer/exportwebdialog.h b/korganizer/exportwebdialog.h new file mode 100644 index 000000000..ead1e454c --- /dev/null +++ b/korganizer/exportwebdialog.h @@ -0,0 +1,84 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef _EXPORTWEBDIALOG_H +#define _EXPORTWEBDIALOG_H + +#include <libkdepim/kprefsdialog.h> + +class HTMLExportSettings; +using namespace KCal; + + +/** + ExportWebDialog is a class that provides the dialog and functions to export a + calendar as web page. +*/ +class ExportWebDialog : public KDialogBase, public KPrefsWidManager +{ + Q_OBJECT + public: + ExportWebDialog( HTMLExportSettings *settings, QWidget *parent = 0, + const char *name = 0 ); + virtual ~ExportWebDialog(); + + public slots: + void slotTextChanged( const QString & _text); + + protected: + void setupGeneralPage(); + void setupEventPage(); + void setupTodoPage(); +// void setupJournalPage(); +// void setupFreeBusyPage(); +// void setupAdvancedPage(); + + public slots: + void setDefaults(); + void readConfig(); + void writeConfig(); + + signals: + void configChanged(); + void exportHTML( HTMLExportSettings* ); + + protected slots: + void slotOk(); + void slotApply(); + void slotDefault(); + + protected: + virtual void usrReadConfig() {} + virtual void usrWriteConfig() {} + + private: + HTMLExportSettings* mSettings; + QFrame *mGeneralPage; + QFrame *mEventPage; + QFrame *mTodoPage; +// QFrame *mJournalPage; +// QFrame *mFreeBusyPage; +// QFrame *mAdvancedPage; +}; + +#endif // _EXPORTWEBDIALOG_H diff --git a/korganizer/filteredit_base.ui b/korganizer/filteredit_base.ui new file mode 100644 index 000000000..9eb53dbf7 --- /dev/null +++ b/korganizer/filteredit_base.ui @@ -0,0 +1,320 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>FilterEdit_base</class> +<widget class="QWidget"> + <property name="name"> + <cstring>FilterEdit_base</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>504</width> + <height>436</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QListBox" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>mRulesList</cstring> + </property> + </widget> + <widget class="QPushButton" row="1" column="0"> + <property name="name"> + <cstring>mNewButton</cstring> + </property> + <property name="text"> + <string>&New</string> + </property> + </widget> + <widget class="QPushButton" row="1" column="1"> + <property name="name"> + <cstring>mDeleteButton</cstring> + </property> + <property name="text"> + <string>&Delete</string> + </property> + </widget> + <widget class="QButtonGroup" row="0" column="2" rowspan="2" colspan="1"> + <property name="name"> + <cstring>mDetailsFrame</cstring> + </property> + <property name="title"> + <string>Filter Details</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout3</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Name:</string> + </property> + </widget> + <widget class="QLineEdit"> + <property name="name"> + <cstring>mNameLineEdit</cstring> + </property> + </widget> + </hbox> + </widget> + <widget class="QCheckBox" row="1" column="0"> + <property name="name"> + <cstring>mRecurringCheck</cstring> + </property> + <property name="text"> + <string>Hide &recurring events and to-dos</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Select this option if you do not want to show recurring events and to-dos in your views. Daily and weekly recurring items may take a lot of space, so it might be handy to hide them.</string> + </property> + </widget> + <widget class="QCheckBox" row="2" column="0"> + <property name="name"> + <cstring>mCompletedCheck</cstring> + </property> + <property name="text"> + <string>Hide co&mpleted to-dos</string> + </property> + <property name="whatsThis" stdset="0"> + <string>If this box is checked, the filter will hide all to-do items from the list, that have been completed. Optionally, only items that have been completed a given number of days are hidden.</string> + </property> + </widget> + <widget class="QLayoutWidget" row="3" column="0"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>15</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel"> + <property name="name"> + <cstring>mCompletedTimeSpanLabel</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Days after completion:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mCompletedTimeSpan</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>This option will allow you to select which completed to-dos should be hidden. When you choose <i>Immediately</i>, it will hide the to-do as soon as you check it. You can increase or decrease the number of days in the spinbox.</string> + </property> + </widget> + <widget class="KIntNumInput"> + <property name="name"> + <cstring>mCompletedTimeSpan</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="minValue"> + <number>0</number> + </property> + <property name="maxValue"> + <number>999</number> + </property> + <property name="specialValueText"> + <string>Immediately</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can give the number of days a to-do item has to be completed to be hidden from the to-do list. If you select "Immediately", all completed to-dos will be hidden. If you, for example, choose a value of 1, all to-do items will be hidden, that have been marked finished longer than 24 hours ago.</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>16</width> + <height>21</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <widget class="QCheckBox" row="4" column="0"> + <property name="name"> + <cstring>mHideInactiveTodosCheck</cstring> + </property> + <property name="text"> + <string>Hide &inactive to-dos</string> + </property> + <property name="whatsThis" stdset="0"> + <string>This option hides all to-dos from your list, where the start date has not been reached. (Note that the start date is not the due date of the to-do item.)</string> + </property> + </widget> + <widget class="QButtonGroup" row="6" column="0"> + <property name="name"> + <cstring>mCategoriesButtonGroup</cstring> + </property> + <property name="title"> + <string>Categories</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QListBox" row="2" column="0" rowspan="2" colspan="1"> + <property name="name"> + <cstring>mCatList</cstring> + </property> + <property name="selectionMode"> + <enum>NoSelection</enum> + </property> + </widget> + <spacer row="3" column="1"> + <property name="name"> + <cstring>spacer4</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>110</height> + </size> + </property> + </spacer> + <widget class="QRadioButton" row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>mCatHideCheck</cstring> + </property> + <property name="text"> + <string>Show all except selected</string> + </property> + <property name="accel"> + <string></string> + </property> + <property name="buttonGroupId"> + <number>1</number> + </property> + <property name="whatsThis" stdset="0"> + <string>When this option is enabled, this filter will show all items which do <i>not</i> contain the selected categories.</string> + </property> + </widget> + <widget class="QRadioButton" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>mCatShowCheck</cstring> + </property> + <property name="text"> + <string>Show only selected</string> + </property> + <property name="accel"> + <string></string> + </property> + <property name="buttonGroupId"> + <number>0</number> + </property> + <property name="whatsThis" stdset="0"> + <string>When this option is enabled, this filter will show all items containing at least the selected items.</string> + </property> + </widget> + <widget class="QPushButton" row="2" column="1"> + <property name="name"> + <cstring>mCatEditButton</cstring> + </property> + <property name="text"> + <string>Change...</string> + </property> + <property name="accel"> + <string></string> + </property> + </widget> + </grid> + </widget> + <widget class="QCheckBox" row="5" column="0"> + <property name="name"> + <cstring>mHideTodosNotAssignedToMeCheck</cstring> + </property> + <property name="text"> + <string>Hide to-dos not assigned to me</string> + </property> + <property name="accel"> + <string></string> + </property> + <property name="whatsThis" stdset="0"> + <string>This option hides all to-dos from your list which are assigned to someone else.<br> +Only to-dos which have least one attendee will be checked. If you are not in the list of attendees the to-do will be hidden.</string> + </property> + </widget> + </grid> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<connections> + <connection> + <sender>mCompletedCheck</sender> + <signal>toggled(bool)</signal> + <receiver>mCompletedTimeSpanLabel</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>mCompletedCheck</sender> + <signal>toggled(bool)</signal> + <receiver>mCompletedTimeSpan</receiver> + <slot>setEnabled(bool)</slot> + </connection> +</connections> +<slots> + <slot>updateFilter()</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> +</includehints> +</UI> diff --git a/korganizer/filtereditdialog.cpp b/korganizer/filtereditdialog.cpp new file mode 100644 index 000000000..72bf89023 --- /dev/null +++ b/korganizer/filtereditdialog.cpp @@ -0,0 +1,255 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.com> + Copyright (C) 2005 Thomas Zander <zander@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qpushbutton.h> +#include <qcheckbox.h> +#include <qbuttongroup.h> +#include <qlineedit.h> +#include <qradiobutton.h> +#include <qlistbox.h> +#include <qwhatsthis.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <knuminput.h> + +#include <libkcal/calfilter.h> +#include <libkdepim/categoryselectdialog.h> + +#include "koprefs.h" +#include "filteredit_base.h" + +#include "filtereditdialog.h" +#include "filtereditdialog.moc" + +FilterEditDialog::FilterEditDialog( QPtrList<CalFilter> *filters, + QWidget *parent, const char *name) + : KDialogBase( parent, name, false, i18n("Edit Calendar Filters"), + Ok | Apply | Cancel ) +{ + setMainWidget( mFilterEdit = new FilterEdit(filters, this)); + + connect(mFilterEdit, SIGNAL(dataConsistent(bool)), + SLOT(setDialogConsistent(bool))); + updateFilterList(); + connect( mFilterEdit, SIGNAL( editCategories() ), SIGNAL( editCategories() ) ); + connect( mFilterEdit, SIGNAL( filterChanged() ), SIGNAL( filterChanged() ) ); +} + +FilterEditDialog::~FilterEditDialog() +{ + delete mFilterEdit; + mFilterEdit = 0L; +} + +void FilterEditDialog::updateFilterList() +{ + mFilterEdit->updateFilterList(); +} + +void FilterEditDialog::updateCategoryConfig() +{ + mFilterEdit->updateCategoryConfig(); +} + +void FilterEditDialog::slotApply() +{ + mFilterEdit->saveChanges(); +} + +void FilterEditDialog::slotOk() +{ + slotApply(); + accept(); +} + +void FilterEditDialog::setDialogConsistent(bool consistent) { + enableButtonOK( consistent ); + enableButtonApply( consistent ); +} + +FilterEdit::FilterEdit(QPtrList<CalFilter> *filters, QWidget *parent) + : FilterEdit_base( parent), current(0), mCategorySelectDialog( 0 ) +{ + mFilters = filters; + QWhatsThis::add( mNewButton, i18n( "Press this button to define a new filter." ) ); + QWhatsThis::add( mDeleteButton, i18n( "Press this button to remove the currently active filter." ) ); + + connect( mRulesList, SIGNAL(selectionChanged()), this, SLOT(filterSelected()) ); + connect( mNewButton, SIGNAL( clicked() ), SLOT( bNewPressed() ) ); + connect( mDeleteButton, SIGNAL( clicked() ), SLOT( bDeletePressed() ) ); + connect( mNameLineEdit, SIGNAL( textChanged(const QString &) ), SLOT( updateSelectedName(const QString &) ) ); + connect( mCatEditButton, SIGNAL( clicked() ), SLOT( editCategorySelection() ) ); +} + +FilterEdit::~FilterEdit() { +} + + +void FilterEdit::updateFilterList() +{ + mRulesList->clear(); + + CalFilter *filter = mFilters->first(); + + if ( !filter ) + emit(dataConsistent(false)); + else { + while( filter ) { + mRulesList->insertItem( filter->name() ); + filter = mFilters->next(); + } + + CalFilter *f = mFilters->at( mRulesList->currentItem() ); + if ( f ) filterSelected( f ); + + emit(dataConsistent(true)); + } + + if(current == 0L && mFilters->count() > 0) + filterSelected(mFilters->at(0)); + mDeleteButton->setEnabled( mFilters->count() > 1 ); +} + +void FilterEdit::saveChanges() +{ + if(current == 0L) + return; + + current->setName(mNameLineEdit->text()); + int criteria = 0; + if ( mCompletedCheck->isChecked() ) criteria |= CalFilter::HideCompleted; + if ( mRecurringCheck->isChecked() ) criteria |= CalFilter::HideRecurring; + if ( mCatShowCheck->isChecked() ) criteria |= CalFilter::ShowCategories; + if ( mHideInactiveTodosCheck->isChecked() ) criteria |= CalFilter::HideInactiveTodos; + if ( mHideTodosNotAssignedToMeCheck->isChecked() ) + criteria |= CalFilter::HideTodosWithoutAttendeeInEmailList; + current->setCriteria( criteria ); + current->setCompletedTimeSpan( mCompletedTimeSpan->value() ); + + QStringList categoryList; + for( uint i = 0; i < mCatList->count(); ++i ) + categoryList.append( mCatList->text( i ) ); + current->setCategoryList( categoryList ); + emit filterChanged(); +} + +void FilterEdit::filterSelected() +{ + filterSelected(mFilters->at(mRulesList->currentItem())); +} + +void FilterEdit::filterSelected(CalFilter *filter) +{ + if(filter == current) return; + kdDebug(5850) << "Selected filter " << (filter!=0?filter->name():"") << endl; + saveChanges(); + + current = filter; + mNameLineEdit->blockSignals(true); + mNameLineEdit->setText(current->name()); + mNameLineEdit->blockSignals(false); + mDetailsFrame->setEnabled(current != 0L); + mCompletedCheck->setChecked( current->criteria() & CalFilter::HideCompleted ); + mCompletedTimeSpan->setValue( current->completedTimeSpan() ); + mRecurringCheck->setChecked( current->criteria() & CalFilter::HideRecurring ); + mHideInactiveTodosCheck->setChecked( current->criteria() & CalFilter::HideInactiveTodos ); + mHideTodosNotAssignedToMeCheck->setChecked( + current->criteria() & CalFilter::HideTodosWithoutAttendeeInEmailList ); + mCategoriesButtonGroup->setButton( (current->criteria() & CalFilter::ShowCategories)?0:1 ); + mCatList->clear(); + mCatList->insertStringList( current->categoryList() ); +} + +void FilterEdit::bNewPressed() { + CalFilter *newFilter = new CalFilter( i18n("New Filter %1").arg(mFilters->count()) ); + mFilters->append( newFilter ); + updateFilterList(); + mRulesList->setSelected(mRulesList->count()-1, true); + emit filterChanged(); +} + +void FilterEdit::bDeletePressed() { + if ( mRulesList->currentItem() < 0 ) return; // nothing selected + if ( mFilters->count() <= 1 ) return; // We need at least a default filter object. + + int result = KMessageBox::warningContinueCancel( this, + i18n("This item will be permanently deleted."), i18n("Delete Confirmation"), KGuiItem(i18n("Delete"),"editdelete") ); + + if ( result != KMessageBox::Continue ) + return; + + unsigned int selected = mRulesList->currentItem(); + mFilters->remove( selected ); + current = 0L; + updateFilterList(); + mRulesList->setSelected(QMIN(mRulesList->count()-1, selected), true); + emit filterChanged(); +} + +void FilterEdit::updateSelectedName(const QString &newText) { + mRulesList->blockSignals( true ); + mRulesList->changeItem(newText, mRulesList->currentItem()); + mRulesList->blockSignals( false ); + bool allOk = true; + CalFilter *filter = mFilters->first(); + while( allOk && filter ) { + if(filter->name().isEmpty()) + allOk = false; + filter = mFilters->next(); + } + emit dataConsistent(allOk); +} + +void FilterEdit::editCategorySelection() +{ + if( !current ) return; + if ( !mCategorySelectDialog ) { + mCategorySelectDialog = new KPIM::CategorySelectDialog( KOPrefs::instance(), this, "filterCatSelect" ); + connect( mCategorySelectDialog, + SIGNAL( categoriesSelected( const QStringList & ) ), + SLOT( updateCategorySelection( const QStringList & ) ) ); + connect( mCategorySelectDialog, SIGNAL( editCategories() ), + SIGNAL( editCategories() ) ); + + } + mCategorySelectDialog->setSelected( current->categoryList() ); + + mCategorySelectDialog->show(); +} + +void FilterEdit::updateCategorySelection( const QStringList &categories ) +{ + mCatList->clear(); + mCatList->insertStringList(categories); + current->setCategoryList(categories); +} + +void FilterEdit::updateCategoryConfig() +{ + if ( mCategorySelectDialog ) mCategorySelectDialog->updateCategoryConfig(); +} diff --git a/korganizer/filtereditdialog.h b/korganizer/filtereditdialog.h new file mode 100644 index 000000000..b7f061b1c --- /dev/null +++ b/korganizer/filtereditdialog.h @@ -0,0 +1,101 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001, 2002 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.com> + Copyright (C) 2005 Thomas Zander <zander@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef _FILTEREDITDIALOG_H +#define _FILTEREDITDIALOG_H + +#include <kdialogbase.h> +#include "filteredit_base.h" + +class FilterEdit; +template<class type> class QPtrList; + +namespace KPIM { class CategorySelectDialog; } +namespace KCal { class CalFilter; } + +using namespace KCal; + +/** + This is the class to add/edit a calendar filter. + + @short Creates a dialog box to create/edit a calendar filter + @author Cornelius Schumacher, Thomas Zander +*/ +class FilterEditDialog : public KDialogBase +{ + Q_OBJECT + public: + FilterEditDialog(QPtrList<CalFilter> *,QWidget *parent=0, const char *name=0); + virtual ~FilterEditDialog(); + + signals: + void filterChanged(); + void editCategories(); + + public slots: + void updateFilterList(); + void updateCategoryConfig(); + void setDialogConsistent(bool consistent); + + private: + FilterEdit *mFilterEdit; + + protected slots: + void slotApply(); + void slotOk(); +}; + +class FilterEdit : public FilterEdit_base +{ + Q_OBJECT + public: + FilterEdit(QPtrList<CalFilter> *filters, QWidget *parent); + ~FilterEdit(); + + void updateFilterList(); + void saveChanges(); + void updateCategoryConfig(); + + signals: + void dataConsistent(bool); + void filterChanged(); + void editCategories(); + + private slots: + void filterSelected(); + void bNewPressed(); + void bDeletePressed(); + void updateSelectedName(const QString &); + void updateCategorySelection(const QStringList &categories); + void editCategorySelection(); + + private: + void filterSelected(CalFilter *f); + + QPtrList<CalFilter> *mFilters; + CalFilter *current; + KPIM::CategorySelectDialog *mCategorySelectDialog; +}; + +#endif diff --git a/korganizer/freebusymanager.cpp b/korganizer/freebusymanager.cpp new file mode 100644 index 000000000..94fe320cf --- /dev/null +++ b/korganizer/freebusymanager.cpp @@ -0,0 +1,587 @@ +/* + This file is part of the Groupware/KOrganizer integration. + + Requires the Qt and KDE widget libraries, available at no cost at + http://www.trolltech.com and http://www.kde.org respectively + + Copyright (c) 2002-2004 Klar�vdalens Datakonsult AB + <info@klaralvdalens-datakonsult.se> + Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#include "freebusymanager.h" + +#include "koprefs.h" +#include "mailscheduler.h" + +#include <libkcal/incidencebase.h> +#include <libkcal/attendee.h> +#include <libkcal/freebusy.h> +#include <libkcal/journal.h> +#include <libkcal/calendarlocal.h> +#include <libkcal/icalformat.h> + +#include <kio/job.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <ktempfile.h> +#include <kio/jobclasses.h> +#include <kio/netaccess.h> +#include <kio/scheduler.h> +#include <kapplication.h> +#include <kconfig.h> +#include <klocale.h> +#include <kstandarddirs.h> +#include <kabc/stdaddressbook.h> +#include <kabc/addressee.h> + +#include <qfile.h> +#include <qbuffer.h> +#include <qregexp.h> +#include <qdir.h> + +using namespace KCal; + +FreeBusyDownloadJob::FreeBusyDownloadJob( const QString &email, const KURL &url, + FreeBusyManager *manager, + const char *name ) + : QObject( manager, name ), mManager( manager ), mEmail( email ) +{ + KIO::TransferJob *job = KIO::get( url, false, false ); + connect( job, SIGNAL( result( KIO::Job * ) ), + SLOT( slotResult( KIO::Job * ) ) ); + connect( job, SIGNAL( data( KIO::Job *, const QByteArray & ) ), + SLOT( slotData( KIO::Job *, const QByteArray & ) ) ); + KIO::Scheduler::scheduleJob( job ); +} + +FreeBusyDownloadJob::~FreeBusyDownloadJob() +{ +} + + +void FreeBusyDownloadJob::slotData( KIO::Job *, const QByteArray &data ) +{ + QByteArray tmp = data; + tmp.resize( tmp.size() + 1 ); + tmp[tmp.size()-1] = 0; + mFreeBusyData += tmp; +} + +void FreeBusyDownloadJob::slotResult( KIO::Job *job ) +{ + kdDebug(5850) << "FreeBusyDownloadJob::slotResult() " << mEmail << endl; + + if( job->error() ) { + kdDebug(5850) << "FreeBusyDownloadJob::slotResult() job error for " << mEmail << endl; + emit freeBusyDownloadError( mEmail ); + } else { + FreeBusy *fb = mManager->iCalToFreeBusy( mFreeBusyData ); + if ( fb ) { + Person p = fb->organizer(); + p.setEmail( mEmail ); + mManager->saveFreeBusy( fb, p ); + } + emit freeBusyDownloaded( fb, mEmail ); + } + deleteLater(); +} + +//// + +FreeBusyManager::FreeBusyManager( QObject *parent, const char *name ) + : QObject( parent, name ), + mCalendar( 0 ), mTimerID( 0 ), mUploadingFreeBusy( false ), + mBrokenUrl( false ) +{ +} + +void FreeBusyManager::setCalendar( KCal::Calendar *c ) +{ + mCalendar = c; + if ( mCalendar ) { + mFormat.setTimeZone( mCalendar->timeZoneId(), true ); + } +} + +KCal::FreeBusy *FreeBusyManager::ownerFreeBusy() +{ + QDateTime start = QDateTime::currentDateTime(); + QDateTime end = start.addDays( KOPrefs::instance()->mFreeBusyPublishDays ); + + FreeBusy *freebusy = new FreeBusy( mCalendar, start, end ); + freebusy->setOrganizer( Person( KOPrefs::instance()->fullName(), + KOPrefs::instance()->email() ) ); + + return freebusy; +} + +QString FreeBusyManager::ownerFreeBusyAsString() +{ + FreeBusy *freebusy = ownerFreeBusy(); + + QString result = freeBusyToIcal( freebusy ); + + delete freebusy; + + return result; +} + +QString FreeBusyManager::freeBusyToIcal( KCal::FreeBusy *freebusy ) +{ + return mFormat.createScheduleMessage( freebusy, Scheduler::Publish ); +} + +void FreeBusyManager::slotPerhapsUploadFB() +{ + // user has automatic uploading disabled, bail out + if ( !KOPrefs::instance()->freeBusyPublishAuto() || + KOPrefs::instance()->freeBusyPublishUrl().isEmpty() ) + return; + if( mTimerID != 0 ) + // A timer is already running, so we don't need to do anything + return; + + int now = static_cast<int>( QDateTime::currentDateTime().toTime_t() ); + int eta = static_cast<int>( mNextUploadTime.toTime_t() ) - now; + + if( !mUploadingFreeBusy ) { + // Not currently uploading + if( mNextUploadTime.isNull() || + QDateTime::currentDateTime() > mNextUploadTime ) { + // No uploading have been done in this session, or delay time is over + publishFreeBusy(); + return; + } + + // We're in the delay time and no timer is running. Start one + if( eta <= 0 ) { + // Sanity check failed - better do the upload + publishFreeBusy(); + return; + } + } else { + // We are currently uploading the FB list. Start the timer + if( eta <= 0 ) { + kdDebug(5850) << "This shouldn't happen! eta <= 0\n"; + eta = 10; // whatever + } + } + + // Start the timer + mTimerID = startTimer( eta * 1000 ); + + if( mTimerID == 0 ) + // startTimer failed - better do the upload + publishFreeBusy(); +} + +// This is used for delayed Free/Busy list uploading +void FreeBusyManager::timerEvent( QTimerEvent* ) +{ + publishFreeBusy(); +} + +void FreeBusyManager::setBrokenUrl( bool isBroken ) +{ + mBrokenUrl = isBroken; +} + +/*! + This method is called when the user has selected to publish its + free/busy list or when the delay have passed. +*/ +void FreeBusyManager::publishFreeBusy() +{ + // Already uploading? Skip this one then. + if ( mUploadingFreeBusy ) + return; + KURL targetURL ( KOPrefs::instance()->freeBusyPublishUrl() ); + if ( targetURL.isEmpty() ) { + KMessageBox::sorry( 0, + i18n( "<qt>No URL configured for uploading your free/busy list. Please " + "set it in KOrganizer's configuration dialog, on the \"Free/Busy\" page. " + "<br>Contact your system administrator for the exact URL and the " + "account details." + "</qt>" ), i18n("No Free/Busy Upload URL") ); + return; + } + if ( mBrokenUrl ) // Url is invalid, don't try again + return; + if ( !targetURL.isValid() ) { + KMessageBox::sorry( 0, + i18n( "<qt>The target URL '%1' provided is invalid." + "</qt>" ).arg( targetURL.prettyURL() ), i18n("Invalid URL") ); + mBrokenUrl = true; + return; + } + targetURL.setUser( KOPrefs::instance()->mFreeBusyPublishUser ); + targetURL.setPass( KOPrefs::instance()->mFreeBusyPublishPassword ); + + mUploadingFreeBusy = true; + + // If we have a timer running, it should be stopped now + if( mTimerID != 0 ) { + killTimer( mTimerID ); + mTimerID = 0; + } + + // Save the time of the next free/busy uploading + mNextUploadTime = QDateTime::currentDateTime(); + if( KOPrefs::instance()->mFreeBusyPublishDelay > 0 ) + mNextUploadTime = mNextUploadTime.addSecs( + KOPrefs::instance()->mFreeBusyPublishDelay * 60 ); + + QString messageText = ownerFreeBusyAsString(); + + // We need to massage the list a bit so that Outlook understands + // it. + messageText = messageText.replace( QRegExp( "ORGANIZER\\s*:MAILTO:" ), + "ORGANIZER:" ); + + // Create a local temp file and save the message to it + KTempFile tempFile; + QTextStream *textStream = tempFile.textStream(); + if( textStream ) { + *textStream << messageText; + tempFile.close(); + +#if 0 + QString defaultEmail = KOCore()::self()->email(); + QString emailHost = defaultEmail.mid( defaultEmail.find( '@' ) + 1 ); + + // Put target string together + KURL targetURL; + if( KOPrefs::instance()->mPublishKolab ) { + // we use Kolab + QString server; + if( KOPrefs::instance()->mPublishKolabServer == "%SERVER%" || + KOPrefs::instance()->mPublishKolabServer.isEmpty() ) + server = emailHost; + else + server = KOPrefs::instance()->mPublishKolabServer; + + targetURL.setProtocol( "webdavs" ); + targetURL.setHost( server ); + + QString fbname = KOPrefs::instance()->mPublishUserName; + int at = fbname.find('@'); + if( at > 1 && fbname.length() > (uint)at ) { + fbname = fbname.left(at); + } + targetURL.setPath( "/freebusy/" + fbname + ".ifb" ); + targetURL.setUser( KOPrefs::instance()->mPublishUserName ); + targetURL.setPass( KOPrefs::instance()->mPublishPassword ); + } else { + // we use something else + targetURL = KOPrefs::instance()->mPublishAnyURL.replace( "%SERVER%", + emailHost ); + targetURL.setUser( KOPrefs::instance()->mPublishUserName ); + targetURL.setPass( KOPrefs::instance()->mPublishPassword ); + } +#endif + + + KURL src; + src.setPath( tempFile.name() ); + + kdDebug(5850) << "FreeBusyManager::publishFreeBusy(): " << targetURL << endl; + + KIO::Job * job = KIO::file_copy( src, targetURL, -1, + true /*overwrite*/, + false /*don't resume*/, + false /*don't show progress info*/ ); + connect( job, SIGNAL( result( KIO::Job * ) ), + SLOT( slotUploadFreeBusyResult( KIO::Job * ) ) ); + } +} + +void FreeBusyManager::slotUploadFreeBusyResult(KIO::Job *_job) +{ + KIO::FileCopyJob* job = static_cast<KIO::FileCopyJob *>(_job); + if ( job->error() ) + KMessageBox::sorry( 0, + i18n( "<qt>The software could not upload your free/busy list to the " + "URL '%1'. There might be a problem with the access rights, or " + "you specified an incorrect URL. The system said: <em>%2</em>." + "<br>Please check the URL or contact your system administrator." + "</qt>" ).arg( job->destURL().prettyURL() ) + .arg( job->errorString() ) ); + // Delete temp file + KURL src = job->srcURL(); + Q_ASSERT( src.isLocalFile() ); + if( src.isLocalFile() ) + QFile::remove(src.path()); + mUploadingFreeBusy = false; +} + +bool FreeBusyManager::retrieveFreeBusy( const QString &email, bool forceDownload ) +{ + kdDebug(5850) << "FreeBusyManager::retrieveFreeBusy(): " << email << endl; + if ( email.isEmpty() ) return false; + + // Check for cached copy of free/busy list + KCal::FreeBusy *fb = loadFreeBusy( email ); + if ( fb ) { + emit freeBusyRetrieved( fb, email ); + } + + // Don't download free/busy if the user does not want it. + if( !KOPrefs::instance()->mFreeBusyRetrieveAuto && !forceDownload) { + slotFreeBusyDownloadError( email ); // fblist + return false; + } + + mRetrieveQueue.append( email ); + + if ( mRetrieveQueue.count() > 1 ) return true; + + return processRetrieveQueue(); +} + +bool FreeBusyManager::processRetrieveQueue() +{ + if ( mRetrieveQueue.isEmpty() ) return true; + + QString email = mRetrieveQueue.first(); + mRetrieveQueue.pop_front(); + + KURL sourceURL = freeBusyUrl( email ); + + kdDebug(5850) << "FreeBusyManager::processRetrieveQueue(): url: " << sourceURL + << endl; + + if ( !sourceURL.isValid() ) { + kdDebug(5850) << "Invalid FB URL\n"; + slotFreeBusyDownloadError( email ); + return false; + } + + FreeBusyDownloadJob *job = new FreeBusyDownloadJob( email, sourceURL, this, + "freebusy_download_job" ); + connect( job, SIGNAL( freeBusyDownloaded( KCal::FreeBusy *, + const QString & ) ), + SIGNAL( freeBusyRetrieved( KCal::FreeBusy *, const QString & ) ) ); + connect( job, SIGNAL( freeBusyDownloaded( KCal::FreeBusy *, + const QString & ) ), + SLOT( processRetrieveQueue() ) ); + + connect( job, SIGNAL( freeBusyDownloadError( const QString& ) ), + this, SLOT( slotFreeBusyDownloadError( const QString& ) ) ); + + return true; +} + +void FreeBusyManager::slotFreeBusyDownloadError( const QString& email ) +{ + if( KOPrefs::instance()->thatIsMe( email ) ) { + // We tried to download our own free-busy list from the net, but it failed + // so use local version instead. + // The reason we try to download even our own free-busy list is that + // this allows to avoid showing as busy the folders that are "fb relevant for nobody" + // like shared resources (meeting rooms etc.) + kdDebug(5850) << "freebusy of owner, falling back to local list" << endl; + emit freeBusyRetrieved( ownerFreeBusy(), email ); + } + +} + +void FreeBusyManager::cancelRetrieval() +{ + mRetrieveQueue.clear(); +} + +KURL FreeBusyManager::freeBusyUrl( const QString &email ) +{ + kdDebug(5850) << "FreeBusyManager::freeBusyUrl(): " << email << endl; + + // First check if there is a specific FB url for this email + QString configFile = locateLocal( "data", "korganizer/freebusyurls" ); + KConfig cfg( configFile ); + + cfg.setGroup( email ); + QString url = cfg.readEntry( "url" ); + if ( !url.isEmpty() ) { + kdDebug(5850) << "found cached url: " << url << endl; + return KURL( url ); + } + // 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; + QString pref; + 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; + cfg.setGroup( pref ); + url = cfg.readEntry ( "url" ); + if ( !url.isEmpty() ) { + kdDebug( 5850 ) << "FreeBusyManager::freeBusyUrl():" << + "Taken url from preferred email:" << url << endl; + return KURL( url ); + } + } + } + // None found. Check if we do automatic FB retrieving then + if ( !KOPrefs::instance()->mFreeBusyRetrieveAuto ) { + kdDebug( 5850 ) << "no auto retrieving" << endl; + // No, so no FB list here + return KURL(); + } + + // Sanity check: Don't download if it's not a correct email + // address (this also avoids downloading for "(empty email)"). + int emailpos = email.find( '@' ); + if( emailpos == -1 ) + return KURL(); + + // Cut off everything left of the @ sign to get the user name. + const QString emailName = email.left( emailpos ); + const QString emailHost = email.mid( emailpos + 1 ); + + // Build the URL + KURL sourceURL; + sourceURL = KOPrefs::instance()->mFreeBusyRetrieveUrl; + + if ( KOPrefs::instance()->mFreeBusyCheckHostname ) { + // 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 QString hostDomain = sourceURL.host(); + if ( hostDomain != emailHost && !hostDomain.endsWith( '.' + emailHost ) + && !emailHost.endsWith( '.' + hostDomain ) ) { + // Host names do not match + kdDebug(5850) << "Host '" << sourceURL.host() << "' doesn't match email '" + << email << '\'' << endl; + return KURL(); + } + } + + kdDebug(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 ); + + kdDebug(5850) << "Results in generated: " << sourceURL << endl; + return sourceURL; +} + +KCal::FreeBusy *FreeBusyManager::iCalToFreeBusy( const QCString &data ) +{ + kdDebug(5850) << "FreeBusyManager::iCalToFreeBusy()" << endl; + kdDebug(5850) << data << endl; + + QString freeBusyVCal = QString::fromUtf8( data ); + KCal::FreeBusy *fb = mFormat.parseFreeBusy( freeBusyVCal ); + if ( !fb ) { + kdDebug(5850) << "FreeBusyManager::iCalToFreeBusy(): Error parsing free/busy" + << endl; + kdDebug(5850) << freeBusyVCal << endl; + } + return fb; +} + +QString FreeBusyManager::freeBusyDir() +{ + return locateLocal( "data", "korganizer/freebusy" ); +} + +FreeBusy *FreeBusyManager::loadFreeBusy( const QString &email ) +{ + kdDebug(5850) << "FreeBusyManager::loadFreeBusy(): " << email << endl; + + QString fbd = freeBusyDir(); + + QFile f( fbd + "/" + email + ".ifb" ); + if ( !f.exists() ) { + kdDebug(5850) << "FreeBusyManager::loadFreeBusy() " << f.name() + << " doesn't exist." << endl; + return 0; + } + + if ( !f.open( IO_ReadOnly ) ) { + kdDebug(5850) << "FreeBusyManager::loadFreeBusy() Unable to open file " + << f.name() << endl; + return 0; + } + + QTextStream ts( &f ); + QString str = ts.read(); + + return iCalToFreeBusy( str.utf8() ); +} + +bool FreeBusyManager::saveFreeBusy( FreeBusy *freebusy, const Person &person ) +{ + kdDebug(5850) << "FreeBusyManager::saveFreeBusy(): " << person.fullName() << endl; + + QString fbd = freeBusyDir(); + + QDir freeBusyDirectory( fbd ); + if ( !freeBusyDirectory.exists() ) { + kdDebug(5850) << "Directory " << fbd << " does not exist!" << endl; + kdDebug(5850) << "Creating directory: " << fbd << endl; + + if( !freeBusyDirectory.mkdir( fbd, true ) ) { + kdDebug(5850) << "Could not create directory: " << fbd << endl; + return false; + } + } + + QString filename( fbd ); + filename += "/"; + filename += person.email(); + filename += ".ifb"; + QFile f( filename ); + + kdDebug(5850) << "FreeBusyManager::saveFreeBusy(): filename: " << filename + << endl; + + freebusy->clearAttendees(); + freebusy->setOrganizer( person ); + + QString messageText = mFormat.createScheduleMessage( freebusy, + Scheduler::Publish ); + + if ( !f.open( IO_ReadWrite ) ) { + kdDebug(5850) << "acceptFreeBusy: Can't open:" << filename << " for writing" + << endl; + return false; + } + QTextStream t( &f ); + t << messageText; + f.close(); + + return true; +} + +#include "freebusymanager.moc" diff --git a/korganizer/freebusymanager.h b/korganizer/freebusymanager.h new file mode 100644 index 000000000..c51af125b --- /dev/null +++ b/korganizer/freebusymanager.h @@ -0,0 +1,179 @@ +/* + This file is part of the Groupware/KOrganizer integration. + + Requires the Qt and KDE widget libraries, available at no cost at + http://www.trolltech.com and http://www.kde.org respectively + + Copyright (c) 2002-2004 Klarälvdalens Datakonsult AB + <info@klaralvdalens-datakonsult.se> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ +#ifndef FREEBUSYMANAGER_H +#define FREEBUSYMANAGER_H + +#include <kurl.h> +#include <libkcal/icalformat.h> +#include <libkcal/freebusycache.h> +#include <qstring.h> +#include <qobject.h> + +namespace KIO { class Job; } +namespace KCal { +class Calendar; +class FreeBusy; +} +class FreeBusyManager; + +/** + * Class for downloading FreeBusy Lists + */ +class FreeBusyDownloadJob : public QObject +{ + Q_OBJECT + public: + FreeBusyDownloadJob( const QString &email, const KURL &url, + FreeBusyManager *manager, const char *name = 0 ); + + virtual ~FreeBusyDownloadJob(); + + protected slots: + void slotResult( KIO::Job * ); + void slotData( KIO::Job *, const QByteArray &data ); + + signals: + void freeBusyDownloaded( KCal::FreeBusy *, const QString& email ); + void freeBusyDownloadError( const QString& email ); + + private: + FreeBusyManager *mManager; + QString mEmail; + + QCString mFreeBusyData; +}; + +class FreeBusyManager : public QObject, public KCal::FreeBusyCache +{ + Q_OBJECT + public: + FreeBusyManager( QObject *parent, const char *name ); + + void setCalendar( KCal::Calendar * ); + + /// KOrganizer publishes the free/busy list + void publishFreeBusy(); + + /** + KOrganizer downloads somebody else's free/busy list + The call is asynchronous, and upon download, the + receivers slot specified by member will be called. + The slot should be of type "member(const QString&, KCal::FreeBusy*)" + + Return true if a download is initiated, and false otherwise + */ + bool retrieveFreeBusy( const QString &email, bool forceDownload ); + + void cancelRetrieval(); + + KCal::FreeBusy *iCalToFreeBusy( const QCString &data ); + + /** + Load freebusy information belonging to email. + */ + KCal::FreeBusy *loadFreeBusy( const QString &email ); + /** + Store freebusy information belonging to email. + */ + bool saveFreeBusy( KCal::FreeBusy *freebusy, const KCal::Person &person ); +// bool saveFreeBusy( KCal::FreeBusy *, const QString &email ); + + /** + Return URL of freeBusy information for given email address. + */ + KURL freeBusyUrl( const QString &email ); + + /** + Return directory used for stroing free/busy information. + */ + QString freeBusyDir(); + + /** + Change the broken Url status + mBrokenUrl is used to show the 'broken url popup' only once + */ + void setBrokenUrl( bool isBroken ); + + public slots: + // When something changed in the calendar, we get this called + void slotPerhapsUploadFB(); + + signals: + /** + This signal is emitted to return results of free/busy requests. + */ + void freeBusyRetrieved( KCal::FreeBusy *, const QString &email ); + + protected: + void timerEvent( QTimerEvent* ); + + /** + Return free/busy list of calendar owner as iCalendar string. + */ + QString ownerFreeBusyAsString(); + + /** + Return free/busy list of calendar owner. + */ + KCal::FreeBusy *ownerFreeBusy(); + + /** + Convert free/busy object to iCalendar string. + */ + QString freeBusyToIcal( KCal::FreeBusy * ); + + protected slots: + bool processRetrieveQueue(); + + private slots: + void slotUploadFreeBusyResult( KIO::Job * ); + void slotFreeBusyDownloadError( const QString& email ); + + private: + KCal::Calendar *mCalendar; + KCal::ICalFormat mFormat; + + QStringList mRetrieveQueue; + + // Free/Busy uploading + QDateTime mNextUploadTime; + int mTimerID; + bool mUploadingFreeBusy; + bool mBrokenUrl; + +}; + +#endif diff --git a/korganizer/freebusyurldialog.cpp b/korganizer/freebusyurldialog.cpp new file mode 100644 index 000000000..39e4c14ed --- /dev/null +++ b/korganizer/freebusyurldialog.cpp @@ -0,0 +1,100 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "freebusyurldialog.h" + +#include <libkcal/attendee.h> +#include <libkcal/freebusyurlstore.h> + +#include <klineedit.h> +#include <klocale.h> +#include <kdebug.h> +#include <kstandarddirs.h> + +#include <qlayout.h> +#include <qlabel.h> + +FreeBusyUrlDialog::FreeBusyUrlDialog( KCal::Attendee *attendee, QWidget *parent, + const char *name ) + : KDialogBase( Plain, i18n("Edit Free/Busy Location"), Ok|Cancel, Ok, parent, + name, true, false ) +{ + QFrame *topFrame = plainPage(); + + QBoxLayout *topLayout = new QVBoxLayout( topFrame, 0, spacingHint() ); + + mWidget = new FreeBusyUrlWidget( attendee, topFrame ); + topLayout->addWidget( mWidget ); + + mWidget->loadConfig(); +} + +void FreeBusyUrlDialog::slotOk() +{ + mWidget->saveConfig(); + accept(); +} + + +FreeBusyUrlWidget::FreeBusyUrlWidget( KCal::Attendee *attendee, QWidget *parent, + const char *name ) + : QWidget( parent, name ), mAttendee( attendee ) +{ + QBoxLayout *topLayout = new QVBoxLayout( this ); + topLayout->setSpacing( KDialog::spacingHint() ); + + QLabel *label = new QLabel( + i18n("Location of Free/Busy information for %1 <%2>:") + .arg( mAttendee->name() ).arg( mAttendee->email() ), this ); + topLayout->addWidget( label ); + + mUrlEdit = new KLineEdit( this ); + topLayout->addWidget( mUrlEdit ); +} + +FreeBusyUrlWidget::~FreeBusyUrlWidget() +{ +} + +void FreeBusyUrlWidget::loadConfig() +{ + kdDebug(5850) << "FreeBusyUrlWidget::loadConfig()" << endl; + + QString url = KCal::FreeBusyUrlStore::self()->readUrl( mAttendee->email() ); + + mUrlEdit->setText( url ); +} + +void FreeBusyUrlWidget::saveConfig() +{ + kdDebug(5850) << "FreeBusyUrlWidget::saveConfig()" << endl; + + QString url = mUrlEdit->text(); + + KCal::FreeBusyUrlStore::self()->writeUrl( mAttendee->email(), url ); + + KCal::FreeBusyUrlStore::self()->sync(); +} + +#include "freebusyurldialog.moc" diff --git a/korganizer/freebusyurldialog.h b/korganizer/freebusyurldialog.h new file mode 100644 index 000000000..db5cff6c0 --- /dev/null +++ b/korganizer/freebusyurldialog.h @@ -0,0 +1,66 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef FREEBUSYURLCONFIG_H +#define FREEBUSYURLCONFIG_H + +#include <kdialogbase.h> + +class FreeBusyUrlWidget; +class KLineEdit; + +namespace KCal { +class Attendee; +} + +class FreeBusyUrlDialog : public KDialogBase +{ + Q_OBJECT + public: + FreeBusyUrlDialog( KCal::Attendee *, QWidget *parent = 0, + const char *name = 0 ); + + public slots: + void slotOk(); + + private: + FreeBusyUrlWidget *mWidget; +}; + +class FreeBusyUrlWidget : public QWidget +{ + Q_OBJECT + public: + FreeBusyUrlWidget( KCal::Attendee *, QWidget *parent = 0, + const char *name = 0 ); + ~FreeBusyUrlWidget(); + + void loadConfig(); + void saveConfig(); + + private: + KLineEdit *mUrlEdit; + KCal::Attendee *mAttendee; +}; + +#endif diff --git a/korganizer/hi128-app-korganizer.png b/korganizer/hi128-app-korganizer.png Binary files differnew file mode 100644 index 000000000..894a7eb1c --- /dev/null +++ b/korganizer/hi128-app-korganizer.png diff --git a/korganizer/hi16-app-korganizer.png b/korganizer/hi16-app-korganizer.png Binary files differnew file mode 100644 index 000000000..fb840c531 --- /dev/null +++ b/korganizer/hi16-app-korganizer.png diff --git a/korganizer/hi32-app-korganizer.png b/korganizer/hi32-app-korganizer.png Binary files differnew file mode 100644 index 000000000..3add587e5 --- /dev/null +++ b/korganizer/hi32-app-korganizer.png diff --git a/korganizer/hi48-app-korganizer.png b/korganizer/hi48-app-korganizer.png Binary files differnew file mode 100644 index 000000000..5056ac6b8 --- /dev/null +++ b/korganizer/hi48-app-korganizer.png diff --git a/korganizer/hi64-app-korganizer.png b/korganizer/hi64-app-korganizer.png Binary files differnew file mode 100644 index 000000000..fbeb65f61 --- /dev/null +++ b/korganizer/hi64-app-korganizer.png diff --git a/korganizer/history.cpp b/korganizer/history.cpp new file mode 100644 index 000000000..5afc325e7 --- /dev/null +++ b/korganizer/history.cpp @@ -0,0 +1,295 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "history.h" + +#include <libkcal/calendar.h> +#include <libkcal/incidence.h> + +#include <klocale.h> +#include <kdebug.h> + +using namespace KCal; +using namespace KOrg; + +History::History( KCal::Calendar *calendar ) + : mCalendar( calendar ), mCurrentMultiEntry( 0 ), + mUndoEntry( mEntries ), mRedoEntry( mEntries ) +{ + mEntries.setAutoDelete( true ); +} + +void History::undo() +{ + if ( mCurrentMultiEntry ) mCurrentMultiEntry = 0; + Entry *entry = mUndoEntry.current(); + if ( !entry ) return; + + entry->undo(); + emit undone(); + + emit redoAvailable( entry->text() ); + + mRedoEntry = mUndoEntry; + --mUndoEntry; + + entry = mUndoEntry.current(); + if ( entry ) emit undoAvailable( entry->text() ); + else emit undoAvailable( QString::null ); +} + +void History::redo() +{ + if ( mCurrentMultiEntry ) mCurrentMultiEntry = 0; + Entry *entry = mRedoEntry.current(); + if ( !entry ) return; + + emit undoAvailable( entry->text() ); + + entry->redo(); + emit redone(); + + mUndoEntry = mRedoEntry; + ++mRedoEntry; + + entry = mRedoEntry.current(); + if ( entry ) emit redoAvailable( entry->text() ); + else emit redoAvailable( QString::null ); +} + +void History::truncate() +{ + while ( mUndoEntry.current() != mEntries.last() ) { + mEntries.removeLast(); + } + mRedoEntry = QPtrList<Entry>( mEntries ); + emit redoAvailable( QString::null ); +} + +void History::recordDelete( Incidence *incidence ) +{ + Entry *entry = new EntryDelete( mCalendar, incidence ); + if (mCurrentMultiEntry) { + mCurrentMultiEntry->appendEntry( entry ); + } else { + truncate(); + mEntries.append( entry ); + mUndoEntry.toLast(); + mRedoEntry = QPtrList<Entry>( mEntries ); + emit undoAvailable( entry->text() ); + } +} + +void History::recordAdd( Incidence *incidence ) +{ + Entry *entry = new EntryAdd( mCalendar, incidence ); + if (mCurrentMultiEntry) { + mCurrentMultiEntry->appendEntry( entry ); + } else { + truncate(); + mEntries.append( entry ); + mUndoEntry.toLast(); + mRedoEntry = QPtrList<Entry>( mEntries ); + emit undoAvailable( entry->text() ); + } +} + +void History::recordEdit( Incidence *oldIncidence, Incidence *newIncidence ) +{ + Entry *entry = new EntryEdit( mCalendar, oldIncidence, newIncidence ); + if (mCurrentMultiEntry) { + mCurrentMultiEntry->appendEntry( entry ); + } else { + truncate(); + mEntries.append( entry ); + mUndoEntry.toLast(); + mRedoEntry = QPtrList<Entry>( mEntries ); + emit undoAvailable( entry->text() ); + } +} + +void History::startMultiModify( const QString &description ) +{ + if ( mCurrentMultiEntry ) { + endMultiModify(); + } + mCurrentMultiEntry = new MultiEntry( mCalendar, description ); + truncate(); + mEntries.append( mCurrentMultiEntry ); + mUndoEntry.toLast(); + mRedoEntry = QPtrList<Entry>( mEntries ); + emit undoAvailable( mCurrentMultiEntry->text() ); +} + +void History::endMultiModify() +{ + mCurrentMultiEntry = 0; +} + + +History::Entry::Entry( KCal::Calendar *calendar ) + : mCalendar( calendar ) +{ +} + +History::Entry::~Entry() +{ +} + +History::EntryDelete::EntryDelete( Calendar *calendar, Incidence *incidence ) + : Entry( calendar ), mIncidence( incidence->clone() ) +{ +} + +History::EntryDelete::~EntryDelete() +{ + delete mIncidence; +} + +void History::EntryDelete::undo() +{ + // TODO: Use the proper resource instead of asking! + mCalendar->addIncidence( mIncidence->clone() ); +} + +void History::EntryDelete::redo() +{ + Incidence *incidence = mCalendar->incidence( mIncidence->uid() ); + mCalendar->deleteIncidence( incidence ); +} + +QString History::EntryDelete::text() +{ + return i18n("Delete %1").arg(mIncidence->type()); +} + + +History::EntryAdd::EntryAdd( Calendar *calendar, Incidence *incidence ) + : Entry( calendar ), mIncidence( incidence->clone() ) +{ +} + +History::EntryAdd::~EntryAdd() +{ + delete mIncidence; +} + +void History::EntryAdd::undo() +{ + Incidence *incidence = mCalendar->incidence( mIncidence->uid() ); + if ( incidence ) + mCalendar->deleteIncidence( incidence ); +} + +void History::EntryAdd::redo() +{ + // TODO: User the proper resource instead of asking again + mCalendar->addIncidence( mIncidence->clone() ); +} + +QString History::EntryAdd::text() +{ + return i18n("Add %1").arg(mIncidence->type()); +} + + +History::EntryEdit::EntryEdit( Calendar *calendar, Incidence *oldIncidence, + Incidence *newIncidence ) + : Entry( calendar ), mOldIncidence( oldIncidence->clone() ), + mNewIncidence( newIncidence->clone() ) +{ +} + +History::EntryEdit::~EntryEdit() +{ + delete mOldIncidence; + delete mNewIncidence; +} + +void History::EntryEdit::undo() +{ + Incidence *incidence = mCalendar->incidence( mNewIncidence->uid() ); + if ( incidence ) + mCalendar->deleteIncidence( incidence ); + // TODO: Use the proper resource instead of asking again + mCalendar->addIncidence( mOldIncidence->clone() ); +} + +void History::EntryEdit::redo() +{ + Incidence *incidence = mCalendar->incidence( mOldIncidence->uid() ); + if ( incidence ) + mCalendar->deleteIncidence( incidence ); + // TODO: Use the proper resource instead of asking again + mCalendar->addIncidence( mNewIncidence->clone() ); +} + +QString History::EntryEdit::text() +{ + return i18n("Edit %1").arg(mNewIncidence->type()); +} + +History::MultiEntry::MultiEntry( Calendar *calendar, const QString &text ) + : Entry( calendar ), mText( text ) +{ + mEntries.setAutoDelete( true ); +} + +History::MultiEntry::~MultiEntry() +{ +} + +void History::MultiEntry::appendEntry( Entry* entry ) +{ + mEntries.append( entry ); +} + +void History::MultiEntry::undo() +{ + QPtrListIterator<Entry> it( mEntries ); + it.toLast(); + Entry *entry; + while ( (entry = it.current()) != 0 ) { + --it; + entry->undo(); + } +} + +void History::MultiEntry::redo() +{ + QPtrListIterator<Entry> it( mEntries ); + Entry *entry; + while ( (entry = it.current()) != 0 ) { + ++it; + entry->redo(); + } +} + +QString History::MultiEntry::text() +{ + return mText; +} + +#include "history.moc" diff --git a/korganizer/history.h b/korganizer/history.h new file mode 100644 index 000000000..a6d6a9f6f --- /dev/null +++ b/korganizer/history.h @@ -0,0 +1,156 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KORG_HISTORY_H +#define KORG_HISTORY_H + +#include <qobject.h> +#include <qptrlist.h> + +namespace KCal { + +class Calendar; +class Incidence; + +} + +namespace KOrg { + +class History : public QObject +{ + Q_OBJECT + public: + History( KCal::Calendar * ); + + void recordDelete( KCal::Incidence * ); + void recordAdd( KCal::Incidence * ); + void recordEdit( KCal::Incidence *oldIncidence, + KCal::Incidence *newIncidence ); + void startMultiModify( const QString &description ); + void endMultiModify(); + + public slots: + void undo(); + void redo(); + + signals: + void undone(); + void redone(); + + void undoAvailable( const QString & ); + void redoAvailable( const QString & ); + + protected: + void truncate(); + + private: + + class Entry + { + public: + Entry( KCal::Calendar * ); + virtual ~Entry(); + + virtual void undo() = 0; + virtual void redo() = 0; + + virtual QString text() = 0; + + protected: + KCal::Calendar *mCalendar; + }; + + class EntryDelete : public Entry + { + public: + EntryDelete( KCal::Calendar *, KCal::Incidence * ); + ~EntryDelete(); + + void undo(); + void redo(); + + QString text(); + + private: + KCal::Incidence *mIncidence; + }; + + class EntryAdd : public Entry + { + public: + EntryAdd( KCal::Calendar *, KCal::Incidence * ); + ~EntryAdd(); + + void undo(); + void redo(); + + QString text(); + + private: + KCal::Incidence *mIncidence; + }; + + class EntryEdit : public Entry + { + public: + EntryEdit( KCal::Calendar *calendar, KCal::Incidence *oldIncidence, + KCal::Incidence *newIncidence ); + ~EntryEdit(); + + void undo(); + void redo(); + + QString text(); + + private: + KCal::Incidence *mOldIncidence; + KCal::Incidence *mNewIncidence; + }; + + class MultiEntry : public Entry + { + public: + MultiEntry( KCal::Calendar *calendar, const QString &text ); + ~MultiEntry(); + + void appendEntry( Entry* entry ); + void undo(); + void redo(); + + QString text(); + + private: + QPtrList<Entry> mEntries; + QString mText; + }; + + KCal::Calendar *mCalendar; + MultiEntry *mCurrentMultiEntry; + + QPtrList<Entry> mEntries; + QPtrListIterator<Entry> mUndoEntry; + QPtrListIterator<Entry> mRedoEntry; +}; + +} +#endif diff --git a/korganizer/ical2vcal.in b/korganizer/ical2vcal.in new file mode 100755 index 000000000..c83f60104 --- /dev/null +++ b/korganizer/ical2vcal.in @@ -0,0 +1,454 @@ +#! @PERL@ +# THE ABOVE LINE SHOULD POINT TO YOUR PERL EXECUTABLE! +# ical2vcal +# (c) 1998 Preston Brown +# Part of the KOrganizer Project +# +# This utility will read ~/.calendar in the ical format as input, and output +# a file in the versit vCalendar format with a .vcs extension. +# +# This code is covered by the GNU Public License. Please see the file +# COPYING for more information. +# +# MINIMAL ERROR CHECKING! HIGHLY PRIMITIVE! YOU HAVE BEEN WARNED! + +# open the calendar. +$home = $ENV{"HOME"}; +$pcount = 0; + +$exitstatus = 0; + +$filename = "$home/.calendar"; + +if (defined($ARGV[0]) && defined($ARGV[1])) { + $filename = $ARGV[0]; + $outfilename = $ARGV[1]; +} elsif (defined($ARGV[0])) { + $outfilename = $ARGV[0]; +} else { + exit -1; +} + +if (!open(ICALFILE, $filename)) { + exit -1; +} +if (!open(VCALFILE, ">$outfilename")) { + exit -1; +} + +$line = <ICALFILE>; + +&write_header; + +if ($line =~ /Calendar(\s+)\[v/) { + while ($line = &getLine) { + if (($line =~ /^Appt/) || ($line =~ /^Note/)) { + &process_appointment; + &write_appointment; + } else { + # silently skip line + } + } +} else { + # not a ical file?! + exit -2; +} + +close(ICALFILE); +close(VCALFILE); + +sub getLine +{ + $_ = <ICALFILE>; + if (!defined($_)) { + &write_footer; + exit $exitstatus; + } + s/\\\[/\(/g; + s/\\\]/\)/g; + $pcount += tr/\[//; + $pcount -= tr/\]//; + return $_; +} + +sub process_appointment +{ + undef(%curappt); + + # this is a count of the total # of parentheses. + while ($pcount) { + $line = &getLine; + + # check to see if more is left to be processed. + if ($pcount > 0) { + # process the line. + + if ($line =~ /^Start/) { + # start time (minutes since midnight) + $_ = $line; + ($totalmin) = /\[(\d+)\]/; + $min = $totalmin % 60; + $hour = int ($totalmin / 60); + $curappt{"starthour"} = $hour; + $curappt{"startmin"} = $min; + + } elsif ($line =~ /^Length/) { + # time length (minutes) + $_ = $line; + ($lengthmin) = /\[(\d+)\]/; + $min = $lengthmin % 60; + $hour = int ($lengthmin / 60); + $curappt{"endhour"} = $hour; + $curappt{"endmin"} = $min; + } elsif ($line =~ /^Uid/) { + # unique identifier + $_ = $line; + ($uid) = /\[(.+)\]/; + $curappt{"uid"} = $uid ; + } elsif ($line =~ /^Owner/) { + # appointment's owner + $_ = $line; + ($attendee) = /\[(\w+)\]/; + $curappt{"attendee"} = $attendee; + } elsif ($line =~ /^Contents/) { + # description + $description = ""; + $_ = $line; + # special case where it's all in one place: + if (/\[(.*)\]/) { + $summary = $1; + } else { + ($summary) = /\[(.*)/; + $_ = &getLine; + while (!(/\]$/)) { + chop; + $description = $description . " " . $_; + $_ = &getLine; + } + /(.*)\]$/; + $description = $description . $1; + } + $curappt{"summary"} = $summary; + if (length($description) > 0) { + $summary = $summary . "..."; + $curappt{"description"} = $description; + } + } elsif ($line =~ /^Text/) { + $description = ""; + $_ = $line; + if (/\[\d+\s+\[(.*)\]\]/) { + $summary = $1; + } else { + ($summary) = /\[\d+\s+\[(.*)$/; + $_ = &getLine; + while (!(/\]$/)) { + chop; + $description = $description . " " . $_; + $_ = &getLine; + } + /^(.*)\]\]/; + $description = $description . $1; + } + $curappt{"summary"} = $summary; + if (length($description) > 0) { + $summary = $summary . "..."; + $curappt{"description"} = $description; + } + } elsif ($line =~ /^Alarms/) { + $_ = $line; + ($alarm) = /(\d+)\]/; + $curappt{"alarmtime"} = $alarm; + } elsif ($line =~ /^Todo/) { + $curappt{"todo"} = 1; + } elsif ($line =~ /^Dates/) { + # dates to occur on + &process_dates; + } elsif ($line =~ /^\]/) { + # do nothing + } elsif ($line =~ /^Hilite/) { + # do nothing + } elsif ($line =~ /^Remind/) { + # do nothing + } elsif ($line =~ /^Done/) { + $curappt{"done"}=1; + } else { + # do nothing + ; + } + + } # if $pcount > 0 + + } # while pcount + + if (defined($curappt{"starthour"})) { + # fix up end time, just peg it at the end of the day + $endhour = $curappt{"starthour"} + $curappt{"endhour"}; + $endmin = $curappt{"startmin"} + $curappt{"endmin"}; + $endhour = $endhour + int ($endmin / 60); + $endmin = $endmin % 60; + $curappt{"endhour"} = $endhour; + $curappt{"endmin"} = $endmin; + if ($endhour >= 24) { + $curappt{"endhour"} = 23; + $curappt{"endmin"} = 55; + } + } +} + +sub output +{ + $outline = shift(@_); + print VCALFILE $outline; + print VCALFILE "\n"; +# print($outline); +# print("\n"); +} + +sub write_header +{ + output("BEGIN:VCALENDAR"); + output("PRODID:-//K Desktop Environment//NONSGML KOrganizer//EN"); + output("VERSION:1.0"); +} + +sub write_footer +{ + output("END:VCALENDAR"); +} + +sub write_appointment +{ + if (defined($curappt{"tossme"})) { + return; + } + + if (defined($curappt{"todo"})) { + output("BEGIN:VTODO"); + } else { + output("BEGIN:VEVENT"); + } + $tmpstr = &date_to_str($curappt{"startyear"}, + $curappt{"startmonth"}, + $curappt{"startday"}); + if (defined($curappt{"starthour"})) { + $tmpstr = $tmpstr . &time_to_str($curappt{"starthour"}, + $curappt{"startmin"}); + } else { + $tmpstr = $tmpstr . &time_to_str("0","0"); + } + output("DCREATED:" . $tmpstr); + output("UID:" . $curappt{"uid"}); + output("SEQUENCE:0"); + output("LAST-MODIFIED:$tmpstr"); + output("DTSTART:$tmpstr"); + if (defined($curappt{"starthour"})) { + $tmpstr = &date_to_str($curappt{"startyear"}, + $curappt{"startmonth"}, + $curappt{"startday"}) . + &time_to_str($curappt{"endhour"}, + $curappt{"endmin"}); + } + output("DTEND:$tmpstr"); + if (defined($curappt{"summary"})) { + $summary = $curappt{"summary"}; + output("SUMMARY:$summary"); + } + if (defined($curappt{"description"})) { + $description = $curappt{"description"}; + output("DESCRIPTION:$description"); + } + if (defined($curappt{"attendee"})) { + $attendee = "ATTENDEE;ROLE=OWNER:" . $curappt{"attendee"}; + output($attendee); + } + + if (defined($curappt{"alarm"})) { + + } + + if (defined($curappt{"repeats"})) { + # wow what a mess + $rule = "RRULE:"; + if ($curappt{"repeats"} eq "DAILY") { + $rule = $rule . "D" . $curappt{"period"}; + } elsif ($curappt{"repeats"} eq "WEEKLY") { + $rule = $rule . "W1" . " "; + $rule = $rule . $curappt{"weekdays"}; + + } elsif ($curappt{"repeats"} eq "MONTHLY") { + $rule = $rule . "MD" . $curappt{"period"}; + $rule = $rule . " " . $curappt{"startday"}; + } + if ($curappt{"endrepeat"} && ($curappt{"endrepeat"} =~ /T/)) { + $rule = $rule . " " . $curappt{"endrepeat"}; + } elsif ($curappt{"endrepeat"}) { + $rule = $rule . " \#" . $curappt{"endrepeat"}; + } else { + $rule = $rule . " \#0"; + } + output($rule); + } + if (defined($curappt{"exceptions"})) { + $exceptions = "EXDATE:" . $curappt{"exceptions"}; + chop($exceptions); + output($exceptions); + } + if (defined($curappt{"todo"})) { + if (defined($curappt{"done"})) { + output("STATUS:COMPLETED"); + } else { + output("STATUS:NEEDS ACTION"); + } + } + output("CLASS:PUBLIC"); + output("PRIORITY:0"); + output("TRANSP:0"); + output("RELATED-TO:0"); + if (defined($curappt{"todo"})) { + output("END:VTODO\n"); + } else { + output("END:VEVENT\n"); + } +} + +sub date_to_str +{ + $year = shift(@_); + $month = shift(@_); + $day = shift(@_); + my($datestr); + $datestr = sprintf("%04d%02d%02d",$year,$month,$day); + return $datestr; +} + +sub time_to_str +{ + $hour = shift(@_); + $min = shift(@_); + my($timestr); + + $timestr = sprintf("T%02d%02d00",$hour,$min); + return $timestr; +} + +sub process_dates +{ + # first, test for single + $_ = $line; + if (/\[Single/) { + &repeat_none; + } elsif (/\[Days/) { + &repeat_daily; + } elsif (/\[WeekDays/) { + &repeat_weekly; + } elsif (/\[Months/) { + &repeat_monthly; + } elsif (/\[ComplexMonths/) { + $exitstatus = 1; + #printf("WARNING: complex repeating month entry detected, we don't support.\n"); + #printf("converting to a single occurrence on the original start date.\n"); + $line = &getLine; + &repeat_none; + } elsif (/\[Empty/) { + # silently toss + $curappt{"tossme"} = "TRUE"; + } else { + $exitstatus = 1; + #print "didn't understand line: $_"; + } + while ($line = &getLine) { + if ($line =~ /^\]/) { + return; + } elsif ($line =~ /^Finish/) { + ($day, $month, $year) = /(\d+)\/(\d+)\/(\d+)/; + $curappt{"endrepeat"} = &date_to_str($year, $month, $day); + $curappt{"endrepeat"} = $curappt{"endrepeat"} . &time_to_str("0","0"); + } elsif ($line =~ /^Deleted/) { + ($day, $month, $year) = /(\d+)\/(\d+)\/(\d+)/; + if (defined($curappt{"exceptions"})) { + $curappt{"exceptions"} = $curappt{"exceptions"} . + &date_to_str($year, $month, $day) . ";"; + } else { + $curappt{"exceptions"} = &date_to_str($year, $month, $day) . + ";"; + } + } else { + $exitstatus = 1; + #print "trashed line: $line"; + } + } +} + +sub repeat_none +{ + # just a one time shot + ($day, $month, $year) = /(\d+)\/(\d+)\/(\d+)/; + $curappt{"startmonth"} = $month; + $curappt{"startday"} = $day; + $curappt{"startyear"} = $year; +} + +sub repeat_daily +{ + # repeats on a daily basis + $curappt{"repeats"} = "DAILY"; + ($skip) = /(\d+)$/; + $curappt{"period"} = $skip; + $line = &getLine; + ($day, $month, $year) = /(\d+)\/(\d+)\/(\d+)/; + $curappt{"startmonth"} = $month; + $curappt{"startday"} = $day; + $curappt{"startyear"} = $year; +} + +sub repeat_weekly +{ + # repeats on a weekly basis, a few days a week + $curappt{"repeats"} = "WEEKLY"; + $startofdates = index($_,"WeekDays") + length("WeekDays"); + $endofdates = index($_,"Months"); + $datestr = substr($_,$startofdates,($endofdates-$startofdates)); + $datestr =~ s/^\s+//; + @days = split(/\s+/,$datestr); + $datestr = ""; + foreach $date (@days) { + if ($date == 1) { + $datestr = $datestr . "SU "; + } elsif ($date == 2) { + $datestr = $datestr . "MO "; + } elsif ($date == 3) { + $datestr = $datestr . "TU "; + } elsif ($date == 4) { + $datestr = $datestr . "WE "; + } elsif ($date == 5) { + $datestr = $datestr . "TH "; + } elsif ($date == 6) { + $datestr = $datestr . "FR "; + } elsif ($date == 7) { + $datestr = $datestr . "SA "; + } + } + # remove one trailing whitespace + chop($datestr); + $curappt{"weekdays"} = $datestr; + $line = &getLine; + ($day, $month, $year) = /(\d+)\/(\d+)\/(\d+)/; + $curappt{"startmonth"} = $month; + $curappt{"startday"} = $day; + $curappt{"startyear"} = $year; +} + +sub repeat_monthly +{ + # repeats on a daily basis + $curappt{"repeats"} = "MONTHLY"; + ($skip) = /(\d+)$/; + $curappt{"period"} = $skip; + $line = &getLine; + ($day, $month, $year) = /(\d+)\/(\d+)\/(\d+)/; + $curappt{"startmonth"} = $month; + $curappt{"startday"} = $day; + $curappt{"startyear"} = $year; +} + + diff --git a/korganizer/importdialog.cpp b/korganizer/importdialog.cpp new file mode 100644 index 000000000..a07d0ef1c --- /dev/null +++ b/korganizer/importdialog.cpp @@ -0,0 +1,92 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2003,2004 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "importdialog.h" + +#include "koprefs.h" +#include "stdcalendar.h" + +#include <klocale.h> + +#include <qlabel.h> +#include <qlayout.h> +#include <qradiobutton.h> +#include <qbuttongroup.h> + +using namespace KCal; + +ImportDialog::ImportDialog( const KURL &url, QWidget *parent ) + : KDialogBase( Plain, i18n("Import Calendar"), Ok | Cancel, Ok, parent, + 0, true, true ), + mUrl( url ) +{ + QFrame *topFrame = plainPage(); + QVBoxLayout *topLayout = new QVBoxLayout( topFrame, 0, spacingHint() ); + + QString txt = i18n("Import calendar at '%1' into KOrganizer.") + .arg( mUrl.prettyURL() ); + + topLayout->addWidget( new QLabel( txt, topFrame ) ); + + QButtonGroup *radioBox = new QButtonGroup( 1, Horizontal, topFrame ); + radioBox->setFlat( true ); + topLayout->addWidget( radioBox ); + + mAddButton = new QRadioButton( i18n("Add as new calendar"), radioBox ); + + mMergeButton = new QRadioButton( i18n("Merge into existing calendar"), + radioBox ); + + mOpenButton = new QRadioButton( i18n("Open in separate window"), radioBox ); + + mAddButton->setChecked( true ); +} + +ImportDialog::~ImportDialog() +{ +} + +void ImportDialog::slotOk() +{ + kdDebug(5850) << "Adding resource for url '" << mUrl << "'" << endl; + + if ( mAddButton->isChecked() ) { + emit addResource( mUrl ); + } 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() ) { + // emit a signal to the action manager to open mUrl in a separate window + emit newWindow( mUrl ); + } else { + kdError() << "ImportDialog: internal error." << endl; + } + + emit dialogFinished( this ); + accept(); +} + + +#include "importdialog.moc" diff --git a/korganizer/importdialog.h b/korganizer/importdialog.h new file mode 100644 index 000000000..a62ffb3e7 --- /dev/null +++ b/korganizer/importdialog.h @@ -0,0 +1,59 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2003,2004 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef IMPORTDIALOG_H +#define IMPORTDIALOG_H + +#include <kdialogbase.h> + +#include <kurl.h> + + +class QRadioButton; + +class ImportDialog : public KDialogBase +{ + Q_OBJECT + public: + ImportDialog( const KURL &url, QWidget *parent ); + ~ImportDialog(); + + public slots: + void slotOk(); + + signals: + void dialogFinished( ImportDialog * ); + void openURL( const KURL &, bool ); + void newWindow( const KURL & ); + void addResource( const KURL & ); + + private: + KURL mUrl; + + QRadioButton *mAddButton; + QRadioButton *mMergeButton; + QRadioButton *mOpenButton; +}; + +#endif diff --git a/korganizer/incidencechanger.cpp b/korganizer/incidencechanger.cpp new file mode 100644 index 000000000..d440f0842 --- /dev/null +++ b/korganizer/incidencechanger.cpp @@ -0,0 +1,354 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "incidencechanger.h" +#include "koprefs.h" +#include "kogroupware.h" +#include "mailscheduler.h" + +#include <libkcal/freebusy.h> +#include <libkcal/dndfactory.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <klocale.h> + + + +bool IncidenceChanger::beginChange( Incidence * incidence ) +{ + if ( !incidence ) return false; +kdDebug(5850)<<"IncidenceChanger::beginChange for incidence \""<<incidence->summary()<<"\""<<endl; + return mCalendar->beginChange( incidence ); +} + +bool IncidenceChanger::sendGroupwareMessage( Incidence *incidence, KCal::Scheduler::Method method, bool deleting ) +{ + 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 true; +} + +void IncidenceChanger::cancelAttendees( Incidence *incidence ) +{ + if ( KOPrefs::instance()->mUseGroupwareCommunication ) { + if ( KMessageBox::questionYesNo( 0, i18n("Some attendees were removed " + "from the incidence. Shall cancel messages be sent to these attendees?"), + i18n( "Attendees Removed" ), i18n("Send Messages"), i18n("Do Not Send") ) == KMessageBox::Yes ) { + // don't use KOGroupware::sendICalMessage here, because that asks just + // a very general question "Other people are involved, send message to + // 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 + // anyway + KCal::MailScheduler scheduler( mCalendar ); + scheduler.performTransaction( incidence, Scheduler::Cancel ); + } + } +} + +bool IncidenceChanger::endChange( Incidence *incidence ) +{ + // 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 ); +} + +bool IncidenceChanger::deleteIncidence( Incidence *incidence ) +{ + if ( !incidence ) return true; +kdDebug(5850)<<"IncidenceChanger::deleteIncidence for incidence \""<<incidence->summary()<<"\""<<endl; + bool doDelete = sendGroupwareMessage( incidence, KCal::Scheduler::Cancel ); + if( doDelete ) { + // @TODO: let Calendar::deleteIncidence do the locking... + Incidence* tmp = incidence->clone(); + emit incidenceToBeDeleted( incidence ); + doDelete = mCalendar->deleteIncidence( incidence ); + if ( !KOPrefs::instance()->thatIsMe( tmp->organizer().email() ) ) { + const QStringList myEmails = KOPrefs::instance()->allEmails(); + bool notifyOrganizer = false; + for ( QStringList::ConstIterator it = myEmails.begin(); it != myEmails.end(); ++it ) { + QString email = *it; + Attendee *me = tmp->attendeeByMail(email); + if ( me ) { + if ( me->status() == KCal::Attendee::Accepted || me->status() == KCal::Attendee::Delegated ) + notifyOrganizer = true; + Attendee *newMe = new Attendee( *me ); + newMe->setStatus( KCal::Attendee::Declined ); + tmp->clearAttendees(); + tmp->addAttendee( newMe ); + break; + } + } + + if ( notifyOrganizer ) { + KCal::MailScheduler scheduler( mCalendar ); + scheduler.performTransaction( tmp, Scheduler::Reply ); + } + } + emit incidenceDeleted( incidence ); + } + return doDelete; +} + +bool IncidenceChanger::cutIncidence( Incidence *incidence ) +{ + 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 ); + } + return doDelete; +} + +class IncidenceChanger::ComparisonVisitor : public IncidenceBase::Visitor +{ + public: + ComparisonVisitor() {} + bool act( IncidenceBase *incidence, IncidenceBase *inc2 ) + { + mIncidence2 = inc2; + if ( incidence ) + return incidence->accept( *this ); + else + return (inc2 == 0); + } + protected: + bool visit( Event *event ) + { + Event *ev2 = dynamic_cast<Event*>(mIncidence2); + if ( event && ev2 ) { + return *event == *ev2; + } else { + // either both 0, or return false; + return ( ev2 == event ); + } + } + bool visit( Todo *todo ) + { + Todo *to2 = dynamic_cast<Todo*>( mIncidence2 ); + if ( todo && to2 ) { + return *todo == *to2; + } else { + // either both 0, or return false; + return ( todo == to2 ); + } + } + bool visit( Journal *journal ) + { + Journal *j2 = dynamic_cast<Journal*>( mIncidence2 ); + if ( journal && j2 ) { + return *journal == *j2; + } else { + // either both 0, or return false; + return ( journal == j2 ); + } + } + bool visit( FreeBusy *fb ) + { + FreeBusy *fb2 = dynamic_cast<FreeBusy*>( mIncidence2 ); + if ( fb && fb2 ) { + return *fb == *fb2; + } else { + // either both 0, or return false; + return ( fb2 == fb ); + } + } + + protected: + IncidenceBase *mIncidence2; +}; + +class IncidenceChanger::AssignmentVisitor : public IncidenceBase::Visitor +{ + public: + AssignmentVisitor() {} + bool act( IncidenceBase *incidence, IncidenceBase *inc2 ) + { + mIncidence2 = inc2; + if ( incidence ) + return incidence->accept( *this ); + else + return false; + } + protected: + bool visit( Event *event ) + { + Event *ev2 = dynamic_cast<Event*>( mIncidence2 ); + if ( event && ev2 ) { + *event = *ev2; + return true; + } else { + return false; + } + } + bool visit( Todo *todo ) + { + Todo *to2 = dynamic_cast<Todo*>( mIncidence2 ); + if ( todo && to2 ) { + *todo = *to2; + return true; + } else { + return false; + } + } + bool visit( Journal *journal ) + { + Journal *j2 = dynamic_cast<Journal*>(mIncidence2); + if ( journal && j2 ) { + *journal = *j2; + return true; + } else { + return false; + } + } + bool visit( FreeBusy *fb ) + { + FreeBusy *fb2 = dynamic_cast<FreeBusy*>( mIncidence2 ); + if ( fb && fb2 ) { + *fb = *fb2; + return true; + } else { + return false; + } + } + + protected: + IncidenceBase *mIncidence2; +}; + +bool IncidenceChanger::incidencesEqual( Incidence *inc1, Incidence *inc2 ) +{ + ComparisonVisitor v; + return ( v.act( inc1, inc2 ) ); +} + +bool IncidenceChanger::assignIncidence( Incidence *inc1, Incidence *inc2 ) +{ + AssignmentVisitor v; + return v.act( inc1, inc2 ); +} + +bool IncidenceChanger::myAttendeeStatusChanged( Incidence *oldInc, Incidence *newInc ) +{ + Attendee *oldMe = oldInc->attendeeByMails( KOPrefs::instance()->allEmails() ); + Attendee *newMe = newInc->attendeeByMails( KOPrefs::instance()->allEmails() ); + if ( oldMe && newMe && ( oldMe->status() != newMe->status() ) ) + return true; + + return false; +} + +bool IncidenceChanger::changeIncidence( Incidence *oldinc, Incidence *newinc, + int action ) +{ +kdDebug(5850)<<"IncidenceChanger::changeIncidence for incidence \""<<newinc->summary()<<"\" ( old one was \""<<oldinc->summary()<<"\")"<<endl; + 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 ); + int revision = newinc->revision(); + newinc->setRevision( revision + 1 ); + // FIXME: Use a generic method for this! Ideally, have an interface class + // for group cheduling. 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 + if ( action<0 ) { + emit incidenceChanged( oldinc, newinc ); + } else { + emit incidenceChanged( oldinc, newinc, action ); + } + revert = false; + } + + if ( revert ) { + assignIncidence( newinc, oldinc ); + return false; + } + } + return true; +} + +bool IncidenceChanger::addIncidence( Incidence *incidence, QWidget *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; + } + } + // 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); + QWidget *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 ( !success ) { + KMessageBox::sorry( parent, i18n("Unable to save %1 \"%2\".") + .arg( i18n( incidence->type() ) ) + .arg( incidence->summary() ) ); + return false; + } + emit incidenceAdded( incidence ); + return true; +} + +#include "incidencechanger.moc" +#include "incidencechangerbase.moc" diff --git a/korganizer/incidencechanger.h b/korganizer/incidencechanger.h new file mode 100644 index 000000000..0b1ed4cb2 --- /dev/null +++ b/korganizer/incidencechanger.h @@ -0,0 +1,58 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef INCIDENCECHANGER_H +#define INCIDENCECHANGER_H + +#include "korganizer/incidencechangerbase.h" + +class IncidenceChanger : public KOrg::IncidenceChangerBase +{ +Q_OBJECT +public: + IncidenceChanger( Calendar*cal, QObject *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, QWidget *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; +}; + +#endif diff --git a/korganizer/interfaces/Makefile.am b/korganizer/interfaces/Makefile.am new file mode 100644 index 000000000..ed117460f --- /dev/null +++ b/korganizer/interfaces/Makefile.am @@ -0,0 +1 @@ +SUBDIRS=calendar korganizer diff --git a/korganizer/interfaces/calendar/Makefile.am b/korganizer/interfaces/calendar/Makefile.am new file mode 100644 index 000000000..d39a76a99 --- /dev/null +++ b/korganizer/interfaces/calendar/Makefile.am @@ -0,0 +1,6 @@ + +calinclude_HEADERS = plugin.h calendardecoration.h +calincludedir = $(includedir)/calendar + +servicetypedir = $(kde_servicetypesdir) +servicetype_DATA = calendarplugin.desktop calendardecoration.desktop diff --git a/korganizer/interfaces/calendar/calendardecoration.desktop b/korganizer/interfaces/calendar/calendardecoration.desktop new file mode 100644 index 000000000..e9763878e --- /dev/null +++ b/korganizer/interfaces/calendar/calendardecoration.desktop @@ -0,0 +1,66 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=Calendar/Decoration +Comment=Calendar Decoration Plugin +Comment[af]=Kalender Versiering Inplak +Comment[bg]=Приставка за декорация на календара +Comment[br]=Lugent kinkladur an deiziadur +Comment[bs]=Dodatak za ukrašavanje kalendara +Comment[ca]=Endollable de decoració del calendari +Comment[cs]=Modul dekorace kalendáře +Comment[cy]=Ategyn Addurniad Calendr +Comment[da]=Calendar-dekorations-plugin +Comment[de]=Dekoration für den Kalender +Comment[el]=Πρόσθετο διακόσμησης ημερολογίου +Comment[eo]=Kalendarornama kromaĵo +Comment[es]=Plugin de decoración de calendario +Comment[et]=Kalendri dekoratsiooni plugin +Comment[eu]=Egutegi apainketa plugin-a +Comment[fa]=وصلۀ تزئین تقویم +Comment[fi]=Kalenteritekstin koristeluliitännäinen +Comment[fr]=Module de décoration d'agenda +Comment[fy]=Agindadekoraasjeplugin +Comment[gl]=Extensión para a Decoración do Calendario +Comment[he]=תוסף קישוטי לוח שנה +Comment[hi]=कैलेन्डर सजावट प्लगइन +Comment[hr]=Dodatak za dekoraciju kalendara +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 +Comment[lv]=Kalendāra Dekorāciju Iespraudnis +Comment[mk]=Приклучок за декорација на календар +Comment[ms]=Plugin Hiasan Kalendar +Comment[mt]=Plagin ta' dekorazzjoni tal-kalendarju +Comment[nb]=Calendar dekorasjonsprogramtillegg +Comment[nds]=Dekoratschoon för den Kalenner +Comment[ne]=क्यालेन्डर सजावट प्लगइन +Comment[nl]=Agendadecoratieplugin +Comment[nn]=Tilleggsmodul for kalenderpynt +Comment[nso]=Plugin ya Kgabiso ya Tshupamabaka +Comment[pl]=Wtyczka do dekoracji kalendarza +Comment[pt]='Plugin' de Decoração do Calendário +Comment[pt_BR]=Plug-in para Decoração do Calendário +Comment[ro]=Modul decorare calendar +Comment[ru]=Оформление календаря +Comment[se]=Kaleandarčiŋaid lassemoduvla +Comment[sk]=Modul pre skrášlenie kalendára +Comment[sl]=Vstavek besedilnega okrasa za Koledar +Comment[sr]=Прикључак за декорацију календара +Comment[sr@Latn]=Priključak za dekoraciju kalendara +Comment[sv]=Insticksprogram för kalenderdekoration +Comment[ta]=நாள்காட்டி அலங்கார சொருகுப்பொருள் +Comment[tg]=Модул барои ороиш додани тақвимот +Comment[th]=โปรแกรมเสริมตกแต่งบันทึกประจำวัน +Comment[tr]=Takvim Dekorasyon Eklentisi +Comment[uk]=Втулок прикрас календаря +Comment[ven]=Pulagini yo khavhisiwaho ya khalenda +Comment[vi]=Plugin phối trí lịch +Comment[xh]=Ikhalenda Yohombiso lwe Plugin +Comment[zh_CN]=日历装饰插件 +Comment[zh_TW]=行事曆文字裝飾外掛程式 +Comment[zu]=Ikhalenda Yeplagi Yokuhlobisa diff --git a/korganizer/interfaces/calendar/calendardecoration.h b/korganizer/interfaces/calendar/calendardecoration.h new file mode 100644 index 000000000..a6f487b7b --- /dev/null +++ b/korganizer/interfaces/calendar/calendardecoration.h @@ -0,0 +1,84 @@ +/* + This file is part of the KOrganizer interfaces. + + Copyright (c) 2001,2003 Cornelius Schumacher <schumacher@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef KORG_CALENDARDECORATION_H +#define KORG_CALENDARDECORATION_H + +#include <qstring.h> +#include <qdatetime.h> +#include <qpixmap.h> + +#include <klibloader.h> + +#include "plugin.h" + +namespace KOrg { + +/** + This class provides the interface for a date dependent decoration. + + It provides entities like texts and pictures for a given date. Implementations + can implement all functions or only a subset. +*/ +class CalendarDecoration : public Plugin +{ + public: + static int interfaceVersion() { return 2; } + static QString serviceType() { return "Calendar/Decoration"; } + + typedef QPtrList<CalendarDecoration> List; + + CalendarDecoration() {} + virtual ~CalendarDecoration() {} + + /** + Return a short text for a given date, ususally only a few words. + */ + virtual QString shortText( const QDate & ) { return QString::null; } + /** + Return along text for a given date. This text can be of any length, but + usually it will have one or a few paragraphs. + */ + virtual QString longText( const QDate & ) { return QString::null; } + + /** + Return a small pixmap. The size should be something like 30x30 pixels. + */ + virtual QPixmap smallPixmap( const QDate &) { return QPixmap(); } + /** + Return a large pixmap. The size should be something like 300x300 pixels. + */ + virtual QPixmap largePixmap( const QDate &) { return QPixmap(); } + + /** + Return a small widget. It should have the size of a pushbutton. + */ + virtual QWidget *smallWidget( QWidget *, const QDate & ) { return 0; } +}; + +class CalendarDecorationFactory : public PluginFactory +{ + public: + virtual CalendarDecoration *create() = 0; +}; + +} + +#endif diff --git a/korganizer/interfaces/calendar/calendarplugin.desktop b/korganizer/interfaces/calendar/calendarplugin.desktop new file mode 100644 index 000000000..765fced76 --- /dev/null +++ b/korganizer/interfaces/calendar/calendarplugin.desktop @@ -0,0 +1,74 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=Calendar/Plugin +Comment=Calendar Plugin +Comment[af]=Kalender Inplak +Comment[az]=Təqvim Əlavəsi +Comment[be]=Дапаўненне "Календар" +Comment[bg]=Приставка за календар +Comment[br]=Lugent an deiziadur +Comment[bs]=Dodatak za kalendar +Comment[ca]=Endollable calendari +Comment[cs]=Kalendářový modul +Comment[cy]=Ategyn Calendr +Comment[da]=Calendar-plugin +Comment[de]=Kalender-Modul +Comment[el]=Πρόσθετο ημερολογίου +Comment[eo]=Kalendaro-kromaĵo +Comment[es]=Plugin de calendario +Comment[et]=Kalendriplugin +Comment[eu]=Egutegi plugin-a +Comment[fa]=وصلۀ تقویم +Comment[fi]=Kalenteriliitännäinen +Comment[fr]=Module d'agenda +Comment[fy]=Agindaplugin +Comment[gl]=Extensión de Calendario +Comment[he]=תוסף לוח שנה +Comment[hi]=कैलेन्डर प्लगइन +Comment[hr]=Kalendar dodatak +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]=달력 플러그인 +Comment[lt]=iCalendar priedas +Comment[lv]=Kalendāra Iespraudnis +Comment[mk]=Приклучок за календар +Comment[ms]=Plugin Kalendar +Comment[mt]=Plagin tal-kalendarju +Comment[nb]=Calendar-programtillegg +Comment[nds]=Kalenner-Moduul +Comment[ne]=क्यालेन्डर प्लगइन +Comment[nl]=Agendaplugin +Comment[nn]=Kalendermodul +Comment[nso]=Plugin ya Tshupamabaka +Comment[pl]=Wtyczka do kalendarza +Comment[pt]='Plugin' de Calendário +Comment[pt_BR]=Plug-in de Calendário +Comment[ro]=Modul calendar +Comment[ru]=Модуль календаря +Comment[se]=Kaleandarlassemoduvla +Comment[sk]=Modul Calendar +Comment[sl]=Vstavek za Koledar +Comment[sr]=Прикључак за календар +Comment[sr@Latn]=Priključak za kalendar +Comment[sv]=Insticksprogram för kalender +Comment[ta]=நாள்காட்டி சொருகுப்பொருள் +Comment[tg]=Модул барои тақвимот +Comment[th]=โปรแกรมเสริมบันทึกประจำวัน +Comment[tr]=Takvim Eklentisi +Comment[uk]=Втулок календаря +Comment[uz]=Kalendar plagini +Comment[uz@cyrillic]=Календар плагини +Comment[ven]=U pulaga ha khalenda +Comment[vi]=Plugin lịch +Comment[xh]=Ikhalenda ye Plugin +Comment[zh_CN]=日历插件 +Comment[zh_TW]=行事曆外掛程式 +Comment[zu]=Iplagi Yekhalanda + +[PropertyDef::X-KDE-KOrganizer-HasSettings] +Type=bool diff --git a/korganizer/interfaces/calendar/plugin.h b/korganizer/interfaces/calendar/plugin.h new file mode 100644 index 000000000..478b86468 --- /dev/null +++ b/korganizer/interfaces/calendar/plugin.h @@ -0,0 +1,58 @@ +/* + This file is part of the KOrganizer interfaces. + + Copyright (c) 2001,2003 Cornelius Schumacher <schumacher@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef KORG_PLUGIN_H +#define KORG_PLUGIN_H + +#include <klocale.h> +#include <klibloader.h> + +namespace KOrg { + +class Plugin +{ + public: + static int interfaceVersion() { return 2; } + static QString serviceType() { return "Calendar/Plugin"; } + + Plugin() {} + virtual ~Plugin() {} + + virtual QString info() = 0; + + virtual void configure( QWidget * ) {} +}; + +class PluginFactory : public KLibFactory +{ + public: + virtual Plugin *create() = 0; + + protected: + virtual QObject *createObject( QObject *, const char *,const char *, + const QStringList & ) + { + return 0; + } +}; + +} + +#endif diff --git a/korganizer/interfaces/korganizer/Makefile.am b/korganizer/interfaces/korganizer/Makefile.am new file mode 100644 index 000000000..1833d0b75 --- /dev/null +++ b/korganizer/interfaces/korganizer/Makefile.am @@ -0,0 +1,6 @@ + +korginclude_HEADERS = part.h baseview.h calendarviewbase.h mainwindow.h corehelper.h printplugin.h +korgincludedir = $(includedir)/korganizer + +servicetypedir = $(kde_servicetypesdir) +servicetype_DATA = korganizerpart.desktop korgprintplugin.desktop diff --git a/korganizer/interfaces/korganizer/baseview.h b/korganizer/interfaces/korganizer/baseview.h new file mode 100644 index 000000000..abaa85917 --- /dev/null +++ b/korganizer/interfaces/korganizer/baseview.h @@ -0,0 +1,254 @@ +/* + 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> + + 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 KORG_BASEVIEW_H +#define KORG_BASEVIEW_H + +#include <qwidget.h> +#include <qptrlist.h> +#include <qvaluelist.h> + +#include <klocale.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <kdepimmacros.h> +#include "korganizer/incidencechangerbase.h" + +#include "printplugin.h" + +#include <libkcal/event.h> + +using namespace KCal; + +namespace KCal { class Calendar; } + +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. + + @short Base class for calendar views + @author Preston Brown, Cornelius Schumacher + @see KOTodoView, KOEventView, KOListView, KOAgendaView, KOMonthView +*/ +class KDE_EXPORT BaseView : public QWidget +{ + Q_OBJECT + public: + /** + Constructs a view. + + @param cal Pointer to the calendar object from which events + will be retrieved for display. + @param parent parent widget. + @param name name of this widget. + */ + BaseView( Calendar *cal, QWidget *parent = 0, + const char *name = 0 ) + : QWidget( parent, name ), mCalendar( cal ), mChanger( 0 ) {} + + /** + Destructor. Views will do view-specific cleanups here. + */ + virtual ~BaseView() {} + + virtual void setCalendar( Calendar *cal ) { mCalendar = cal; } + /** + Return calendar object of this view. + */ + virtual Calendar *calendar() { return mCalendar; } + + /** + @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 + more than one. + */ + virtual Incidence::List selectedIncidences() = 0; + + /** + @return a list of the dates of selected events. Most views can probably only + select a single event at a time, but some may be able to select + more than one. + */ + virtual DateList selectedDates() = 0; + + virtual CalPrinterBase::PrintType printType() + { + return CalPrinterBase::Month; + } + + /** + Return number of currently shown dates. A return value of 0 means no idea. + */ + virtual int currentDateCount() = 0; + + /** Return if this view is a view for displaying events. */ + virtual bool isEventView() { return false; } + + public slots: + /** + Show incidences for the given date range. The date range actually shown may be + different from the requested range, depending on the particular requirements + of the view. + + @param start Start of date range. + @param end End of date range. + */ + virtual void showDates( const QDate &start, const QDate &end ) = 0; + + /** + Show given incidences. Depending on the actual view it might not be possible to + show all given events. + + @param incidenceList a list of incidences to show. + */ + virtual void showIncidences( const Incidence::List &incidenceList ) = 0; + + /** + Updates the current display to reflect changes that may have happened + in the calendar since the last display refresh. + */ + virtual void updateView() = 0; + virtual void dayPassed( const QDate & ) { updateView(); } + + /** + Assign a new incidence change helper object. + */ + virtual void setIncidenceChanger( IncidenceChangerBase *changer ) { mChanger = changer; } + + /** + Write all unsaved data back to calendar store. + */ + virtual void flushView() {} + + /** + Updates the current display to reflect the changes to one particular incidence. + */ + virtual void changeIncidenceDisplay( Incidence *, int ) = 0; + + /** + Re-reads the KOrganizer configuration and picks up relevant + changes which are applicable to the view. + */ + virtual void updateConfig() {} + + /** + Clear selection. The incidenceSelected signal is not emitted. + */ + virtual void clearSelection() {} + + /** + Set the default start/end date/time for new events. Return true if anything was changed + */ + virtual bool eventDurationHint(QDateTime &/*startDt*/, QDateTime &/*endDt*/, bool &/*allDay*/) { return false; } + + signals: + void incidenceSelected( Incidence * ); + + /** + * instructs the receiver to show the incidence in read-only mode. + */ + void showIncidenceSignal(Incidence *); + + /** + * 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 *); + + /** + * instructs the receiver to delete the Incidence in some manner; some + * possibilities include automatically, with a confirmation dialog + * box, etc. Doesn't make sense to connect to more than one receiver. + */ + void deleteIncidenceSignal(Incidence *); + + /** + * instructs the receiver to cut the Incidence + */ + void cutIncidenceSignal(Incidence *); + + /** + * instructs the receiver to copy the incidence + */ + void copyIncidenceSignal(Incidence *); + + /** + * instructs the receiver to paste the incidence + */ + void pasteIncidenceSignal(); + + /** + * instructs the receiver to toggle the alarms of the Incidence. + */ + void toggleAlarmSignal(Incidence *); + /** Dissociate from a recurring incidence the occurrence on the given + date to a new incidence */ + void dissociateOccurrenceSignal( Incidence *, const QDate & ); + /** Dissociate from a recurring incidence all occurrences after the given + date to a new incidence */ + void dissociateFutureOccurrenceSignal( Incidence *, const QDate & ); + + void startMultiModify( const QString & ); + void endMultiModify(); + + /** + * instructs the receiver to create a new event. Doesn't make + * sense to connect to more than one receiver. + */ + void newEventSignal(); + /** + * 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 QDate & ); + /** + * 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 QDateTime & ); + /** + * 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 QDateTime &, const QDateTime & ); + + void newTodoSignal( const QDate & ); + void newSubTodoSignal( Todo * ); + + void newJournalSignal( const QDate & ); + + private: + Calendar *mCalendar; + protected: + IncidenceChangerBase *mChanger; +}; + +} + +#endif diff --git a/korganizer/interfaces/korganizer/calendarviewbase.h b/korganizer/interfaces/korganizer/calendarviewbase.h new file mode 100644 index 000000000..fe0cd4961 --- /dev/null +++ b/korganizer/interfaces/korganizer/calendarviewbase.h @@ -0,0 +1,63 @@ +/* + This file is part of the KOrganizer interfaces. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-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 + 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 KORG_CALENDARVIEWBASE_H +#define KORG_CALENDARVIEWBASE_H + +#include <qwidget.h> + +#include <libkcal/calendar.h> + +#include <korganizer/baseview.h> + +namespace KOrg { + +/** + @short interface for main calendar view widget + @author Cornelius Schumacher +*/ +class CalendarViewBase : public QWidget +{ + public: + CalendarViewBase( QWidget *parent, const char *name ) + : QWidget( parent, name ) {} + virtual ~CalendarViewBase() {} + + virtual KCal::Calendar *calendar() = 0; + + virtual QDate startDate() = 0; + virtual QDate endDate() = 0; + + virtual Incidence *currentSelection() = 0; + + virtual void addView( KOrg::BaseView * ) = 0; + + /** changes the view to be the currently selected view */ + virtual void showView( KOrg::BaseView * ) = 0; + + public slots: + virtual void updateView() = 0; + virtual void updateCategories() = 0; +}; + +} + +#endif diff --git a/korganizer/interfaces/korganizer/corehelper.h b/korganizer/interfaces/korganizer/corehelper.h new file mode 100644 index 000000000..2ab839065 --- /dev/null +++ b/korganizer/interfaces/korganizer/corehelper.h @@ -0,0 +1,52 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KORG_COREHELPER_H +#define KORG_COREHELPER_H + +#include <qstring.h> +#include <qdatetime.h> +#include <qcolor.h> +#include "printplugin.h" + +class KCalendarSytstem; + +namespace KOrg { + +class CoreHelper +{ + public: + CoreHelper() {} + virtual ~CoreHelper() {} + + virtual QColor defaultEventColor() = 0; + virtual QColor textColor( const QColor &bgColor ) = 0; + virtual QColor categoryColor( const QStringList &cats ) = 0; + virtual QString holidayString( const QDate &dt ) = 0; + virtual QTime dayStart() = 0; + virtual const KCalendarSystem *calendarSystem() = 0; + virtual KOrg::PrintPlugin::List loadPrintPlugins() = 0; + virtual bool isWorkingDay( const QDate &dt ) = 0; +}; + +} +#endif diff --git a/korganizer/interfaces/korganizer/incidencechangerbase.h b/korganizer/interfaces/korganizer/incidencechangerbase.h new file mode 100644 index 000000000..9aeaf2438 --- /dev/null +++ b/korganizer/interfaces/korganizer/incidencechangerbase.h @@ -0,0 +1,77 @@ +/* + This file is part of the KOrganizer interfaces. + + 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 + 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 KORG_INCIDENCECHANGERBASE_H +#define KORG_INCIDENCECHANGERBASE_H + +#include <libkcal/scheduler.h> +#include <qobject.h> + +class QWidget; +namespace KCal { +class Calendar; +class Incidence; +} +using namespace KCal; + +namespace KOrg { + +class IncidenceChangerBase : public QObject +{ +Q_OBJECT +public: + IncidenceChangerBase( Calendar*cal, QObject *parent = 0 ) : + QObject( parent ), mCalendar( cal ) {} + virtual ~IncidenceChangerBase() {} + + virtual bool sendGroupwareMessage( Incidence *incidence, + KCal::Scheduler::Method method, bool deleting = false ) = 0; + + virtual bool beginChange( Incidence * incidence ) = 0; + virtual bool endChange( Incidence *incidence ) = 0; + + virtual bool addIncidence( Incidence *incidence, QWidget *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; + +/* + 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 incidenceToBeDeleted( Incidence * ); + void incidenceDeleted( Incidence * ); + + void schedule( Scheduler::Method method, Incidence *incidence ); +protected: + Calendar *mCalendar; +}; + + + + +} + +#endif diff --git a/korganizer/interfaces/korganizer/korganizerpart.desktop b/korganizer/interfaces/korganizer/korganizerpart.desktop new file mode 100644 index 000000000..7cb419dea --- /dev/null +++ b/korganizer/interfaces/korganizer/korganizerpart.desktop @@ -0,0 +1,66 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=KOrganizer/Part +Comment=KOrganizer Part +Comment[af]=Korganizer Deel +Comment[be]=Частка "K Арганізатар" +Comment[bg]=Модул KOrganizer +Comment[br]=Perzh KOrganizer +Comment[bs]=KOrganizer dio +Comment[ca]=Part de KOrganizer +Comment[cy]=KTrefnydd Part +Comment[da]=KOrganizer-del +Comment[de]=KOrganizer-Komponente +Comment[eo]=Organizilo-parto +Comment[es]=Parte de KOrganizer +Comment[et]=KOrganizeri komponent +Comment[eu]=KOrganizer zatia +Comment[fa]=بخش KOrganizer +Comment[fr]=Composant KOrganizer +Comment[gl]=Parte de KOrganizer +Comment[he]=רכיב KOrganizer +Comment[hi]=के-आर्गेनाइज़र हिस्सा +Comment[hr]=KOrganizer komponenta +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 +Comment[lv]=KOrganizer Daļa +Comment[mk]=Дел од КОрганизатор +Comment[ms]=Bahagian KOrganizer +Comment[mt]=Parti ta' KOrganizer +Comment[nb]=KOrganizerdel +Comment[nds]=KOrganizer-Komponent +Comment[ne]=केडीई आयोजक भाग +Comment[nn]=KOrganizer-del +Comment[nso]=Seripa sa KMokopanyi +Comment[pl]=Moduł KOrganizera +Comment[pt]=Componente do KOrganizer +Comment[pt_BR]=Componente do KOrganizer +Comment[ro]=Componentă KOrganizer +Comment[ru]=Компонент органайзера +Comment[se]=KOrganizer-oassi +Comment[sk]=Part KOrganizer +Comment[sl]=Del KOrganizerja +Comment[sr]=Део KOrganizer-а +Comment[sr@Latn]=Deo KOrganizer-a +Comment[sv]=Korganizer-del +Comment[ta]=கேஅமைப்பாளர் பகுதி +Comment[tg]=Қисмати органайзер +Comment[tr]=KOrganizer Parçası +Comment[uk]=Складова KOrganizer +Comment[ven]=Tshipida tsha mudzudzanyi wa K +Comment[xh]=Indawana yeKOrganizer +Comment[zh_CN]=KOrganizer 部件 +Comment[zh_TW]=KOrganizer 組件 +Comment[zu]=KUmgqugquzeleli Wengxenye + +[PropertyDef::X-KDE-KOrganizer-HasSettings] +Type=bool + +[PropertyDef::X-KDE-PluginInterfaceVersion] +Type=int diff --git a/korganizer/interfaces/korganizer/korgprintplugin.desktop b/korganizer/interfaces/korganizer/korgprintplugin.desktop new file mode 100644 index 000000000..ffa520d36 --- /dev/null +++ b/korganizer/interfaces/korganizer/korgprintplugin.desktop @@ -0,0 +1,66 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=KOrganizer/PrintPlugin +Comment=KOrganizer Part +Comment[af]=Korganizer Deel +Comment[be]=Частка "K Арганізатар" +Comment[bg]=Модул KOrganizer +Comment[br]=Perzh KOrganizer +Comment[bs]=KOrganizer dio +Comment[ca]=Part de KOrganizer +Comment[cy]=KTrefnydd Part +Comment[da]=KOrganizer-del +Comment[de]=KOrganizer-Komponente +Comment[eo]=Organizilo-parto +Comment[es]=Parte de KOrganizer +Comment[et]=KOrganizeri komponent +Comment[eu]=KOrganizer zatia +Comment[fa]=بخش KOrganizer +Comment[fr]=Composant KOrganizer +Comment[gl]=Parte de KOrganizer +Comment[he]=רכיב KOrganizer +Comment[hi]=के-आर्गेनाइज़र हिस्सा +Comment[hr]=KOrganizer komponenta +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 +Comment[lv]=KOrganizer Daļa +Comment[mk]=Дел од КОрганизатор +Comment[ms]=Bahagian KOrganizer +Comment[mt]=Parti ta' KOrganizer +Comment[nb]=KOrganizerdel +Comment[nds]=KOrganizer-Komponent +Comment[ne]=केडीई आयोजक भाग +Comment[nn]=KOrganizer-del +Comment[nso]=Seripa sa KMokopanyi +Comment[pl]=Moduł KOrganizera +Comment[pt]=Componente do KOrganizer +Comment[pt_BR]=Componente do KOrganizer +Comment[ro]=Componentă KOrganizer +Comment[ru]=Компонент органайзера +Comment[se]=KOrganizer-oassi +Comment[sk]=Part KOrganizer +Comment[sl]=Del KOrganizerja +Comment[sr]=Део KOrganizer-а +Comment[sr@Latn]=Deo KOrganizer-a +Comment[sv]=Korganizer-del +Comment[ta]=கேஅமைப்பாளர் பகுதி +Comment[tg]=Қисмати органайзер +Comment[tr]=KOrganizer Parçası +Comment[uk]=Складова KOrganizer +Comment[ven]=Tshipida tsha mudzudzanyi wa K +Comment[xh]=Indawana yeKOrganizer +Comment[zh_CN]=KOrganizer 部件 +Comment[zh_TW]=KOrganizer 組件 +Comment[zu]=KUmgqugquzeleli Wengxenye + +[PropertyDef::X-KDE-KOrganizer-HasSettings] +Type=bool + +[PropertyDef::X-KDE-PluginInterfaceVersion] +Type=int diff --git a/korganizer/interfaces/korganizer/mainwindow.h b/korganizer/interfaces/korganizer/mainwindow.h new file mode 100644 index 000000000..cbfb7915c --- /dev/null +++ b/korganizer/interfaces/korganizer/mainwindow.h @@ -0,0 +1,99 @@ +/* + This file is part of the KOrganizer interfaces. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef KORG_MAINWINDOW_H +#define KORG_MAINWINDOW_H + +#include <kxmlguiclient.h> + +#include <qwidget.h> + +class KActionCollection; +class KAction; + +class ActionManager; + +namespace KOrg { + +class CalendarViewBase; + +/** + @short interface for korganizer main window + @author Cornelius Schumacher +*/ +class MainWindow +{ + public: + MainWindow() : mDocument( true ) {} + virtual ~MainWindow() {} + + virtual void init( bool hasDocument ) { Q_UNUSED( hasDocument ); } + + virtual CalendarViewBase *view() const = 0; + + /** Load calendar file from URL. Merge into current calendar, if \a merge is true. */ + virtual bool openURL( const KURL &url, bool merge = false ) = 0; + /** Save calendar file to URL of current calendar */ + virtual bool saveURL() = 0; + /** Save calendar file to URL */ + virtual bool saveAsURL( const KURL &kurl ) = 0; + + /** Get current URL */ + virtual KURL getCurrentURL() const = 0; + + /** + Return XML GUI factory of this main window. + */ + virtual KXMLGUIFactory *mainGuiFactory() = 0; + /** + Return XML GUI client of this main window. + */ + virtual KXMLGUIClient *mainGuiClient() = 0; + /** + Return widget whcih represents this main window. + */ + virtual QWidget *topLevelWidget() = 0; + /** + Return ActionManager of this main window. + */ + virtual ActionManager *actionManager() = 0; + /** + Return actionCollection of this main window. + */ + virtual KActionCollection *getActionCollection() const = 0; + /** + Show status mesage in status bar. + */ + virtual void showStatusMessage( const QString &message ) = 0; + + /** + Set window title. + */ + virtual void setTitle() = 0; + + void setHasDocument( bool d ) { mDocument = d; } + bool hasDocument() const { return mDocument; } + + private: + bool mDocument; +}; + +} + +#endif diff --git a/korganizer/interfaces/korganizer/part.h b/korganizer/interfaces/korganizer/part.h new file mode 100644 index 000000000..5db429298 --- /dev/null +++ b/korganizer/interfaces/korganizer/part.h @@ -0,0 +1,71 @@ +/* + This file is part of the KOrganizer interfaces. + + Copyright (c) 2001,2003 Cornelius Schumacher <schumacher@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef KORG_PART_H +#define KORG_PART_H + +#include <qstring.h> + +#include <klibloader.h> +#include <kparts/part.h> + +#include <korganizer/mainwindow.h> + +namespace KOrg { + +class Part : public KParts::Part +{ + public: + static int interfaceVersion() { return 2; } + static QString serviceType() { return "KOrganizer/Part"; } + + typedef QPtrList<Part> List; + + Part( MainWindow *parent, const char *name ) + : KParts::Part( parent?(parent->topLevelWidget()):0, name ), mMainWindow( parent ) {} + + virtual ~Part() {} + + virtual QString info() = 0; + /** short name of the part, used as category in the keybindings dialog */ + virtual QString shortInfo() = 0; + + MainWindow *mainWindow() { return mMainWindow; } + + private: + MainWindow *mMainWindow; +}; + +class PartFactory : public KLibFactory +{ + public: + virtual Part *create( MainWindow *parent, const char *name = 0 ) = 0; + + protected: + virtual QObject *createObject( QObject *, const char *,const char *, + const QStringList & ) + { + return 0; + } +}; + +} + +#endif diff --git a/korganizer/interfaces/korganizer/printplugin.h b/korganizer/interfaces/korganizer/printplugin.h new file mode 100644 index 000000000..0a7abd44c --- /dev/null +++ b/korganizer/interfaces/korganizer/printplugin.h @@ -0,0 +1,172 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2003 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 + 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 PRINTPLUGINBASE_H +#define PRINTPLUGINBASE_H + +#ifndef KORG_NOPRINTER + +#include <qdatetime.h> +#include <kprinter.h> +#include <calendar/plugin.h> +#include <libkcal/incidence.h> + +namespace KCal { +class Calendar; +} + +namespace KOrg { +class CoreHelper; + +/** + Base class of KOrganizer printer class. +*/ +class CalPrinterBase +{ + public: + enum PrintType { Incidence = 100, Day=200, Week=300, Month=400, Todolist=1000, Journallist=2000 }; +}; + +/** + Base class for KOrganizer printing classes. Each sub class represents one + calendar print format. +*/ +class PrintPlugin : public KOrg::Plugin +{ + public: + PrintPlugin() : KOrg::Plugin(), mConfigWidget(0), mCoreHelper(0), mPrinter(0), + mCalendar(0), mConfig(0) {} + virtual ~PrintPlugin() {} + + typedef QPtrList<PrintPlugin> List; + static int interfaceVersion() { return 2; } + static QString serviceType() { return "KOrganizer/PrintPlugin"; } + + virtual void setKOrgCoreHelper( KOrg::CoreHelper*helper ) { mCoreHelper = helper; } + virtual void setConfig( KConfig *cfg ) { mConfig = cfg; } + virtual void setCalendar( KCal::Calendar *cal ) { mCalendar = cal; } + virtual void setSelectedIncidences( KCal::Incidence::List inc ) { mSelectedIncidences = inc; } + virtual KCal::Incidence::List selectedIncidences() const { return mSelectedIncidences; } + + + /** + Returns short description of print format. + */ + virtual QString description() = 0; + /** + Returns long description of print format. + */ + virtual QString info() = 0; + + /** + Returns the sort ID of the plugin. This value will be used to identify + the config widget in the widget stack, and to sort the plugin name in the + print style selection list. + If another plugin uses the same ID or a value of -1 is returned, a unique + (negative) ID will be automatically generated and thus the position of + the plugin in the selection list is undefined. + */ + virtual int sortID() { return -1; } + + /** + Returns true if the plugin should be enabled; false otherwise. + */ + virtual bool enabled() { return false; } + + QWidget *configWidget( QWidget *w ) + { + if ( !mConfigWidget ) { + mConfigWidget = createConfigWidget( w ); + setSettingsWidget(); + } + return mConfigWidget; + } + /* Create the config widget. setSettingsWidget will be automatically + called on it */ + virtual QWidget *createConfigWidget( QWidget * ) = 0; + + /** + Actually do the printing. + */ + virtual void doPrint( KPrinter *printer ) = 0; + + /** + Orientation of printout. Default is Portrait. If your plugin wants + to use some other orientation as default (e.g. depending on some + config settings), implement this function in your subclass and + return the desired orientation. + */ + virtual KPrinter::Orientation defaultOrientation() { return KPrinter::Portrait; } + + /** + Load complete config. + */ + virtual void doLoadConfig() {}; + /** + Save complete config. + */ + virtual void doSaveConfig() {}; + + + public: + /** + Read settings from configuration widget and apply them to current object. + */ + virtual void readSettingsWidget() {} + /** + Set configuration widget to reflect settings of current object. + */ + virtual void setSettingsWidget() {} + + /** + Set date range which should be printed. + */ + virtual void setDateRange( const QDate &from, const QDate &to ) + { + mFromDate = from; + mToDate = to; + } + + protected: + QDate mFromDate; + QDate mToDate; + + protected: + QWidget *mConfigWidget; + KOrg::CoreHelper *mCoreHelper; + /** The printer object. This will only be available in the doPrint method + of the selected plugin */ + KPrinter *mPrinter; + KCal::Calendar *mCalendar; + KCal::Incidence::List mSelectedIncidences; + KConfig *mConfig; +}; + +class PrintPluginFactory : public PluginFactory +{ + public: + virtual PrintPlugin *create() = 0; +}; + +} + +#endif + +#endif diff --git a/korganizer/journalentry.cpp b/korganizer/journalentry.cpp new file mode 100644 index 000000000..3c680c654 --- /dev/null +++ b/korganizer/journalentry.cpp @@ -0,0 +1,414 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +// +// Journal Entry + +#include <qlabel.h> +#include <qlayout.h> +#include <qcheckbox.h> +#include <qwhatsthis.h> +#include <qtooltip.h> +#include <qtoolbutton.h> + +#include <kdebug.h> +#include <kdialog.h> +#include <kglobal.h> +#include <klocale.h> +#include <ktextedit.h> +#include <ktimeedit.h> +#include <klineedit.h> +#include <kactivelabel.h> +#include <kstdguiitem.h> +#include <kmessagebox.h> + +#include <libkcal/journal.h> +#include <libkcal/calendar.h> + +#include "kodialogmanager.h" +#include "incidencechanger.h" +#include "koglobals.h" + +#include "journalentry.h" +#include "journalentry.moc" +#ifndef KORG_NOPRINTER +#include "kocorehelper.h" +#include "calprinter.h" +#endif + +class JournalTitleLable : public KActiveLabel +{ +public: + JournalTitleLable( QWidget *parent, const char *name=0 ) : KActiveLabel( parent, name ) {} + + void openLink( const QString &/*link*/ ) {} +}; + + +JournalDateEntry::JournalDateEntry( Calendar *calendar, QWidget *parent ) : + QVBox( parent ), mCalendar( calendar ) +{ +//kdDebug(5850)<<"JournalEntry::JournalEntry, parent="<<parent<<endl; + mChanger = 0; + + mTitle = new JournalTitleLable( this ); + mTitle->setMargin(2); + mTitle->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ); + connect( mTitle, SIGNAL( linkClicked( const QString & ) ), + this, SLOT( emitNewJournal() ) ); +} + +JournalDateEntry::~JournalDateEntry() +{ +} + +void JournalDateEntry::setDate(const QDate &date) +{ + QString dtstring = QString( "<qt><center><b><i>%1</i></b> " ) + .arg( KGlobal::locale()->formatDate(date) ); + + dtstring += " <font size=\"-1\"><a href=\"#\">" + + i18n("[Add Journal Entry]") + + "</a></font></center></qt>"; + + mTitle->setText( dtstring ); + mDate = date; + emit setDateSignal( date ); +} + +void JournalDateEntry::clear() +{ + QValueList<JournalEntry*> values( mEntries.values() ); + + QValueList<JournalEntry*>::Iterator it = values.begin(); + for ( ; it != values.end(); ++it ) { + delete (*it); + } + mEntries.clear(); +} + +// should only be called by the KOJournalView now. +void JournalDateEntry::addJournal( Journal *j ) +{ + QMap<Journal*,JournalEntry*>::Iterator pos = mEntries.find( j ); + if ( pos != mEntries.end() ) return; + + JournalEntry *entry = new JournalEntry( j, this ); + entry->show(); + entry->setDate( mDate ); + entry->setIncidenceChanger( mChanger ); + + mEntries.insert( j, entry ); + connect( this, SIGNAL( setIncidenceChangerSignal( IncidenceChangerBase * ) ), + entry, SLOT( setIncidenceChanger( IncidenceChangerBase * ) ) ); + connect( this, SIGNAL( setDateSignal( const QDate & ) ), + entry, SLOT( setDate( const QDate & ) ) ); + connect( this, SIGNAL( flushEntries() ), + entry, SLOT( flushEntry() ) ); + connect( entry, SIGNAL( deleteIncidence( Incidence* ) ), + this, SIGNAL( deleteIncidence( Incidence* ) ) ); + connect( entry, SIGNAL( editIncidence( Incidence* ) ), + this, SIGNAL( editIncidence( Incidence* ) ) ); +} + +Journal::List JournalDateEntry::journals() const +{ + QValueList<Journal*> jList( mEntries.keys() ); + Journal::List l; + QValueList<Journal*>::Iterator it = jList.begin(); + for ( ; it != jList.end(); ++it ) { + l.append( *it ); + } + return l; +} + +void JournalDateEntry::setIncidenceChanger( IncidenceChangerBase *changer ) +{ + mChanger = changer; + emit setIncidenceChangerSignal( changer ); +} + +void JournalDateEntry::emitNewJournal() +{ + emit newJournal( mDate ); +} + +void JournalDateEntry::journalEdited( Journal *journal ) +{ + QMap<Journal*,JournalEntry*>::Iterator pos = mEntries.find( journal ); + if ( pos == mEntries.end() ) return; + + pos.data()->setJournal( journal ); + +} + +void JournalDateEntry::journalDeleted( Journal *journal ) +{ + QMap<Journal*,JournalEntry*>::Iterator pos = mEntries.find( journal ); + if ( pos == mEntries.end() ) return; + + delete pos.data(); +} + + + + + +JournalEntry::JournalEntry( Journal* j, QWidget *parent ) : + QWidget( parent ), mJournal( j ) +{ +//kdDebug(5850)<<"JournalEntry::JournalEntry, parent="<<parent<<endl; + mDirty = false; + mWriteInProgress = false; + mChanger = 0; + mReadOnly = false; + + mLayout = new QGridLayout( this ); + mLayout->setSpacing( KDialog::spacingHint() ); + mLayout->setMargin( KDialog::marginHint() ); + + QString whatsThis = i18n("Sets the Title of this journal entry."); + + mTitleLabel = new QLabel( i18n("&Title: "), this ); + mLayout->addWidget( mTitleLabel, 0, 0 ); + mTitleEdit = new KLineEdit( this ); + mLayout->addWidget( mTitleEdit, 0, 1 ); + mTitleLabel->setBuddy( mTitleEdit ); + + QWhatsThis::add( mTitleLabel, whatsThis ); + QWhatsThis::add( mTitleEdit, whatsThis ); + + mTimeCheck = new QCheckBox( i18n("Ti&me: "), this ); + mLayout->addWidget( mTimeCheck, 0, 2 ); + mTimeEdit = new KTimeEdit( this ); + mLayout->addWidget( mTimeEdit, 0, 3 ); + connect( mTimeCheck, SIGNAL(toggled(bool)), + this, SLOT(timeCheckBoxToggled(bool)) ); + QWhatsThis::add( mTimeCheck, i18n("Determines whether this journal entry has " + "a time associated with it") ); + QWhatsThis::add( mTimeEdit, i18n( "Sets the time associated with this journal " + "entry" ) ); + + mDeleteButton = new QToolButton( this, "deleteButton" ); + QPixmap pix = KOGlobals::self()->smallIcon( "editdelete" ); + mDeleteButton->setPixmap( pix ); + mDeleteButton->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); + QToolTip::add( mDeleteButton, i18n("Delete this journal entry") ); + QWhatsThis::add( mDeleteButton, i18n("Delete this journal entry") ); + mLayout->addWidget( mDeleteButton, 0, 4 ); + connect( mDeleteButton, SIGNAL(pressed()), this, SLOT(deleteItem()) ); + + mEditButton = new QToolButton( this, "editButton" ); + mEditButton->setPixmap( KOGlobals::self()->smallIcon( "edit" ) ); + mEditButton->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); + QToolTip::add( mEditButton, i18n("Edit this journal entry") ); + QWhatsThis::add( mEditButton, i18n("Opens an editor dialog for this journal entry") ); + mLayout->addWidget( mEditButton, 0, 5 ); + connect( mEditButton, SIGNAL(clicked()), this, SLOT( editItem() ) ); + +#ifndef KORG_NOPRINTER + mPrintButton = new QToolButton( this, "printButton" ); + mPrintButton->setPixmap( KOGlobals::self()->smallIcon( "printer1" ) ); + mPrintButton->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); + QToolTip::add( mPrintButton, i18n("Print this journal entry") ); + QWhatsThis::add( mPrintButton, i18n("Opens the print dialog for this journal entry") ); + mLayout->addWidget( mPrintButton, 0, 6 ); + connect( mPrintButton, SIGNAL(clicked()), this, SLOT( printItem() ) ); +#endif + mEditor = new KTextEdit(this); + mLayout->addMultiCellWidget( mEditor, 1, 2, 0, 6 ); + + connect( mTitleEdit, SIGNAL(textChanged( const QString& )), SLOT(setDirty()) ); + connect( mTimeCheck, SIGNAL(toggled(bool)), SLOT(setDirty()) ); + connect( mTimeEdit, SIGNAL(timeChanged(QTime)), SLOT(setDirty()) ); + connect( mEditor, SIGNAL(textChanged()), SLOT(setDirty()) ); + + mEditor->installEventFilter(this); + + readJournal( mJournal ); + mDirty = false; +} + +JournalEntry::~JournalEntry() +{ + writeJournal(); +} + +void JournalEntry::deleteItem() +{ +/* KMessageBox::ButtonCode *code = KMessageBox::warningContinueCancel(this, + i18n("The journal \"%1\" on %2 will be permanently deleted.") + .arg( mJournal->summary() ) + .arg( mJournal->dtStartStr() ), + i18n("KOrganizer Confirmation"), KStdGuiItem::del() ); + if ( code == KMessageBox::Yes ) {*/ + if ( mJournal ) + emit deleteIncidence( mJournal ); +// } +} + +void JournalEntry::editItem() +{ + writeJournal(); + if ( mJournal ) + emit editIncidence( mJournal ); +} + +void JournalEntry::printItem() +{ +#ifndef KORG_NOPRINTER + writeJournal(); + if ( mJournal ) { + KOCoreHelper helper; + CalPrinter printer( this, 0, &helper ); + connect( this, SIGNAL(configChanged()), &printer, SLOT(updateConfig()) ); + + Incidence::List selectedIncidences; + selectedIncidences.append( mJournal ); + + printer.print( KOrg::CalPrinterBase::Incidence, + QDate(), QDate(), selectedIncidences ); + } +#endif +} + +void JournalEntry::setReadOnly( bool readonly ) +{ + mReadOnly = readonly; + mTitleEdit->setReadOnly( mReadOnly ); + mEditor->setReadOnly( mReadOnly ); + mTimeCheck->setEnabled( !mReadOnly ); + mTimeEdit->setEnabled( !mReadOnly && mTimeCheck->isChecked() ); + mDeleteButton->setEnabled( !mReadOnly ); +} + + +void JournalEntry::setDate(const QDate &date) +{ + writeJournal(); + mDate = date; +} + +void JournalEntry::setJournal(Journal *journal) +{ + if ( !mWriteInProgress ) + writeJournal(); + if ( !journal ) return; + + mJournal = journal; + readJournal( journal ); + + mDirty = false; +} + +void JournalEntry::setDirty() +{ + mDirty = true; + kdDebug(5850) << "JournalEntry::setDirty()" << endl; +} + +bool JournalEntry::eventFilter( QObject *o, QEvent *e ) +{ +// kdDebug(5850) << "JournalEntry::event received " << e->type() << endl; + + if ( e->type() == QEvent::FocusOut || e->type() == QEvent::Hide || + e->type() == QEvent::Close ) { + writeJournal(); + } + return QWidget::eventFilter( o, e ); // standard event processing +} + + +void JournalEntry::readJournal( Journal *j ) +{ + mJournal = j; + mTitleEdit->setText( mJournal->summary() ); + bool hasTime = !mJournal->doesFloat(); + mTimeCheck->setChecked( hasTime ); + mTimeEdit->setEnabled( hasTime ); + if ( hasTime ) { + mTimeEdit->setTime( mJournal->dtStart().time() ); + } + mEditor->setText( mJournal->description() ); + setReadOnly( mJournal->isReadOnly() ); +} + +void JournalEntry::writeJournalPrivate( Journal *j ) +{ + j->setSummary( mTitleEdit->text() ); + bool hasTime = mTimeCheck->isChecked(); + QTime tm( mTimeEdit->getTime() ); + j->setDtStart( QDateTime( mDate, hasTime?tm:QTime(0,0,0) ) ); + j->setFloats( !hasTime ); + j->setDescription( mEditor->text() ); +} + +void JournalEntry::writeJournal() +{ +// kdDebug(5850) << "JournalEntry::writeJournal()" << endl; + + if ( mReadOnly || !mDirty || !mChanger ) { + kdDebug(5850)<<"Journal either read-only, unchanged or no changer object available"<<endl; + return; + } + bool newJournal = false; + mWriteInProgress = true; + + Journal *oldJournal = 0; + + if ( !mJournal ) { + newJournal = true; + mJournal = new Journal; + writeJournalPrivate( mJournal ); + if ( !mChanger->addIncidence( mJournal, this ) ) { + KODialogManager::errorSaveIncidence( this, mJournal ); + delete mJournal; + mJournal = 0; + } + } else { + oldJournal = mJournal->clone(); + if ( mChanger->beginChange( mJournal ) ) { + writeJournalPrivate( mJournal ); + mChanger->changeIncidence( oldJournal, mJournal, KOGlobals::DESCRIPTION_MODIFIED ); + mChanger->endChange( mJournal ); + } + delete oldJournal; + } + mDirty = false; + mWriteInProgress = false; +} + +void JournalEntry::flushEntry() +{ + if (!mDirty) return; + + writeJournal(); +} + +void JournalEntry::timeCheckBoxToggled(bool on) +{ + mTimeEdit->setEnabled(on); + if(on) + mTimeEdit->setFocus(); +} diff --git a/korganizer/journalentry.h b/korganizer/journalentry.h new file mode 100644 index 000000000..761e77e58 --- /dev/null +++ b/korganizer/journalentry.h @@ -0,0 +1,155 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef JOURNALENTRY_H +#define JOURNALENTRY_H +// +// Widget showing one Journal entry + +#include <qvbox.h> + +class QLabel; +class KActiveLabel; +class QCheckBox; +class QGridLayout; +class KLineEdit; +class KTextEdit; +class KTimeEdit; +class QButton; +namespace KOrg { +class IncidenceChangerBase; +} +using namespace KOrg; +namespace KCal { + class Calendar; + class Journal; +} +using namespace KCal; + +class JournalEntry : public QWidget { + Q_OBJECT + public: + typedef ListBase<JournalEntry> List; + + JournalEntry( Journal* j, QWidget *parent ); + virtual ~JournalEntry(); + + void setJournal(Journal *); + Journal *journal() const { return mJournal; } + + QDate date() const { return mDate; } + + void clear(); + void readJournal( Journal *j ); + + bool isReadOnly() const { return mReadOnly; } + void setReadOnly( bool readonly ); + + protected slots: + void setDirty(); + void deleteItem(); + void editItem(); + void printItem(); + void timeCheckBoxToggled(bool on); + public slots: + void setIncidenceChanger( IncidenceChangerBase *changer ) { mChanger = changer; } + void setDate(const QDate &); + void flushEntry(); + + signals: + void deleteIncidence( Incidence * ); + void editIncidence( Incidence * ); + + protected: + void clearFields(); + bool eventFilter( QObject *o, QEvent *e ); + + void writeJournal(); + + private: + void writeJournalPrivate( Journal *j ); + + Journal *mJournal; + QDate mDate; + bool mReadOnly; + + QLabel *mTitleLabel; + KLineEdit *mTitleEdit; + KTextEdit *mEditor; + QCheckBox *mTimeCheck; + KTimeEdit *mTimeEdit; + QButton *mDeleteButton; + QButton *mEditButton; + QButton *mPrintButton; + + QGridLayout *mLayout; + + bool mDirty; + bool mWriteInProgress; + IncidenceChangerBase *mChanger; +}; + + +class JournalDateEntry : public QVBox { + Q_OBJECT + public: + typedef ListBase<JournalDateEntry> List; + + JournalDateEntry( Calendar *, QWidget *parent ); + virtual ~JournalDateEntry(); + + void addJournal( Journal * ); + Journal::List journals() const; + + void setDate( const QDate & ); + QDate date() const { return mDate; } + + void clear(); + + + signals: + void setIncidenceChangerSignal( IncidenceChangerBase *changer ); + void setDateSignal( const QDate & ); + void flushEntries(); + void editIncidence( Incidence * ); + void deleteIncidence( Incidence * ); + void newJournal( const QDate & ); + + public slots: + void emitNewJournal(); + void setIncidenceChanger( IncidenceChangerBase *changer ); + void journalEdited( Journal* ); + void journalDeleted( Journal* ); + + private: + Calendar *mCalendar; + QDate mDate; + QMap<Journal*,JournalEntry*> mEntries; + + KActiveLabel *mTitle; + QWidget *mAddBar; + IncidenceChangerBase *mChanger; +}; + + +#endif diff --git a/korganizer/kcalendariface.h b/korganizer/kcalendariface.h new file mode 100644 index 000000000..c84281d7f --- /dev/null +++ b/korganizer/kcalendariface.h @@ -0,0 +1,122 @@ +/* + This file is a generic DCOP interface, shared between KDE applications. + Copyright (c) 2003 David Faure <faure@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 KCALENDARIFACE_H +#define KCALENDARIFACE_H + +/** @file +* This file is a generic DCOP interface, shared between KDE applications. +* It handles Calendar requests. +*/ + +#include <dcopobject.h> +#include <qdatetime.h> +#include <qdatastream.h> +#include <qstringlist.h> +// yes, this is this very header - but it tells dcopidl to include it +// in _stub.cpp and _skel.cpp files, to get the definition of the structs. +#include "kcalendariface.h" + +typedef QPair<QDateTime, QDateTime> QDateTimePair; + +/** Interface class for calendar requests. */ +class KCalendarIface : public DCOPObject +{ + K_DCOP + public: + KCalendarIface() : DCOPObject("CalendarIface") {} + + k_dcop: + + /** This is a struct. + * + */ + struct ResourceRequestReply { + bool vCalInOK; + QString vCalOut; + bool vCalOutOK; bool isFree; + QDateTime start; QDateTime end; + }; + virtual KCalendarIface::ResourceRequestReply resourceRequest( + const QValueList< QDateTimePair >& busy, + const QCString& resource, + const QString& vCalIn ) = 0; + + virtual void openEventEditor( const QString& text ) = 0; + virtual void openEventEditor( const QString& summary, + const QString& description, + const QString& attachment ) = 0; + virtual void openEventEditor( const QString& summary, + const QString& description, + const QString& attachment, + const QStringList& attendees ) = 0; + virtual void openEventEditor( const QString& summary, + const QString& description, + const QString& uri, + const QString& file, + const QStringList& attendees, + const QString& attachmentMimetype ) = 0; + + virtual void openTodoEditor( const QString& text ) = 0; + virtual void openTodoEditor( const QString& summary, + const QString& description, + const QString& attachment ) = 0; + virtual void openTodoEditor( const QString& summary, + const QString& description, + const QString& attachment, + const QStringList& attendees ) = 0; + virtual void openTodoEditor( const QString& summary, + const QString& description, + const QString& uri, + const QString& file, + const QStringList& attendees, + const QString& attachmentMimetype ) = 0; + + virtual void openJournalEditor( const QDate& date ) = 0; + virtual void openJournalEditor( const QString& text, + const QDate& date ) = 0; + virtual void openJournalEditor( const QString& text ) = 0; + //TODO: + // virtual void openJournalEditor( const QString& summary, + // const QString& description, + // const QString& attachment ) = 0; + + virtual void showJournalView() = 0; + virtual void showTodoView() = 0; + virtual void showEventView() = 0; + + virtual void goDate( const QDate& date ) = 0; + virtual void goDate( const QString& date ) = 0; + + virtual void showDate( const QDate &date ) = 0; +}; + +inline QDataStream& operator<<( QDataStream& str, const KCalendarIface::ResourceRequestReply& reply ) +{ + str << reply.vCalInOK << reply.vCalOut << reply.vCalOutOK << reply.isFree << reply.start << reply.end; + return str; +} + +inline QDataStream& operator>>( QDataStream& str, KCalendarIface::ResourceRequestReply& reply ) +{ + str >> reply.vCalInOK >> reply.vCalOut >> reply.vCalOutOK >> reply.isFree >> reply.start >> reply.end; + return str; +} + +#endif diff --git a/korganizer/kdatenavigator.cpp b/korganizer/kdatenavigator.cpp new file mode 100644 index 000000000..900a7b24e --- /dev/null +++ b/korganizer/kdatenavigator.cpp @@ -0,0 +1,279 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001,2002,2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qstring.h> +#include <qkeycode.h> +#include <qlayout.h> +#include <qtimer.h> +#include <qframe.h> +#include <qlabel.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kglobal.h> +#include <kglobalsettings.h> + +#include "koglobals.h" +#include "koprefs.h" +#include "kodaymatrix.h" + +#include <kcalendarsystem.h> + +#include "navigatorbar.h" + +#include "kdatenavigator.h" + +KDateNavigator::KDateNavigator( QWidget *parent, const char *name ) + : QFrame( parent, name ), mBaseDate( 1970, 1, 1 ) +{ + QGridLayout* topLayout = new QGridLayout( this, 8, 8 ); + + mNavigatorBar = new NavigatorBar( this ); + topLayout->addMultiCellWidget( mNavigatorBar, 0, 0, 0, 7 ); + + connect( mNavigatorBar, SIGNAL( goPrevYear() ), SIGNAL( goPrevYear() ) ); + connect( mNavigatorBar, SIGNAL( goPrevMonth() ), SIGNAL( goPrevMonth() ) ); + connect( mNavigatorBar, SIGNAL( goNextMonth() ), SIGNAL( goNextMonth() ) ); + connect( mNavigatorBar, SIGNAL( goNextYear() ), SIGNAL( goNextYear() ) ); + connect( mNavigatorBar, SIGNAL( goMonth( int ) ), SIGNAL( goMonth( int ) ) ); + + int i; + QString generalFont = KGlobalSettings::generalFont().family(); + + // Set up the heading fields. + for( i = 0; i < 7; i++ ) { + mHeadings[i] = new QLabel( this ); + mHeadings[i]->setFont( QFont( generalFont, 10, QFont::Bold ) ); + mHeadings[i]->setAlignment( AlignCenter ); + + topLayout->addWidget( mHeadings[i], 1, i + 1 ); + } + + // Create the weeknumber labels + for( i = 0; i < 6; i++ ) { + mWeeknos[i] = new QLabel( this ); + mWeeknos[i]->setAlignment( AlignCenter ); + mWeeknos[i]->setFont( QFont( generalFont, 10 ) ); + mWeeknos[i]->installEventFilter( this ); + + topLayout->addWidget( mWeeknos[i], i + 2, 0 ); + } + + mDayMatrix = new KODayMatrix( this, "KDateNavigator::dayMatrix" ); + + connect( mDayMatrix, SIGNAL( selected( const KCal::DateList & ) ), + SIGNAL( datesSelected( const KCal::DateList & ) ) ); + + connect( mDayMatrix, SIGNAL( incidenceDropped( Incidence *, const QDate & ) ), + SIGNAL( incidenceDropped( Incidence *, const QDate & ) ) ); + connect( mDayMatrix, SIGNAL( incidenceDroppedMove( Incidence * , const QDate & ) ), + SIGNAL( incidenceDroppedMove( Incidence *, const QDate & ) ) ); + + + topLayout->addMultiCellWidget( mDayMatrix, 2, 7, 1, 7 ); + + // read settings from configuration file. + updateConfig(); +} + +KDateNavigator::~KDateNavigator() +{ +} + +void KDateNavigator::setCalendar( Calendar *cal ) +{ + mDayMatrix->setCalendar( cal ); +} + +void KDateNavigator::setBaseDate( const QDate &date ) +{ + if ( date != mBaseDate ) { + mBaseDate = date; + + updateDates(); + updateView(); + + // Use the base date to show the monthname and year in the header + KCal::DateList dates; + dates.append( date ); + mNavigatorBar->selectDates( dates ); + + repaint(); + mDayMatrix->repaint(); + } +} + +QSizePolicy KDateNavigator::sizePolicy () const +{ + return QSizePolicy( QSizePolicy::MinimumExpanding, + QSizePolicy::MinimumExpanding ); +} + +void KDateNavigator::updateToday() +{ + mDayMatrix->recalculateToday(); + mDayMatrix->repaint(); +} +QDate KDateNavigator::startDate() const +{ + // Find the first day of the week of the current month. + QDate dayone( mBaseDate.year(), mBaseDate.month(), mBaseDate.day() ); + int d2 = KOGlobals::self()->calendarSystem()->day( dayone ); + //int di = d1 - d2 + 1; + dayone = dayone.addDays( -d2 + 1 ); + + + const KCalendarSystem *calsys = KOGlobals::self()->calendarSystem(); + int m_fstDayOfWkCalsys = calsys->dayOfWeek( dayone ); + int weekstart = KGlobal::locale()->weekStartDay(); + + // If month begins on Monday and Monday is first day of week, + // month should begin on second line. Sunday doesn't have this problem. + int nextLine = m_fstDayOfWkCalsys <= weekstart ? 7 : 0; + + // update the matrix dates + int index = weekstart - m_fstDayOfWkCalsys - nextLine; + + dayone = dayone.addDays( index ); + + return dayone; +} +QDate KDateNavigator::endDate() const +{ + return startDate().addDays( 6*7 ); +} + +void KDateNavigator::updateDates() +{ +// kdDebug(5850) << "KDateNavigator::updateDates(), this=" << this << endl; + QDate dayone = startDate(); + + mDayMatrix->updateView( dayone ); + + const KCalendarSystem *calsys = KOGlobals::self()->calendarSystem(); + + // set the week numbers. + for( int i = 0; i < 6; i++ ) { + // Use QDate's weekNumber method to determine the week number! + QDate dtStart = mDayMatrix->getDate( i * 7 ); + QDate dtEnd = mDayMatrix->getDate( ( i + 1 ) * 7 - 1 ); + int weeknumstart = calsys->weekNumber( dtStart ); + int weeknumend = calsys->weekNumber( dtEnd ); + QString weeknum; + + if ( weeknumstart != weeknumend ) { + weeknum = i18n("start/end week number of line in date picker", "%1/%2") + .arg( weeknumstart ).arg( weeknumend ); + } else { + weeknum.setNum( weeknumstart ); + } + mWeeknos[i]->setText( weeknum ); + } + +// each updateDates is followed by an updateView -> repaint is issued there ! +// mDayMatrix->repaint(); +} + +void KDateNavigator::updateDayMatrix() +{ + mDayMatrix->updateView(); + mDayMatrix->repaint(); +} + + +void KDateNavigator::updateView() +{ +// kdDebug(5850) << "KDateNavigator::updateView(), view " << this << endl; + + updateDayMatrix(); + repaint(); +} + +void KDateNavigator::updateConfig() +{ + int day; + int weekstart = KGlobal::locale()->weekStartDay(); + for( int i = 0; i < 7; i++ ) { + day = weekstart + i <= 7 ? weekstart + i : ( weekstart + i ) % 7; + QString dayName = KOGlobals::self()->calendarSystem()->weekDayName( day, + true ); + if ( KOPrefs::instance()->mCompactDialogs ) dayName = dayName.left( 1 ); + mHeadings[i]->setText( dayName ); + } + + // FIXME: Use actual config setting here +// setShowWeekNums( true ); +} + +void KDateNavigator::setShowWeekNums( bool enabled ) +{ + for( int i = 0; i < 6; i++ ) { + if( enabled ) + mWeeknos[i]->show(); + else + mWeeknos[i]->hide(); + } +} + +void KDateNavigator::selectDates( const DateList &dateList ) +{ + if ( dateList.count() > 0 ) { + mSelectedDates = dateList; + + updateDates(); + + mDayMatrix->setSelectedDaysFrom( *( dateList.begin() ), + *( --dateList.end() ) ); + + updateView(); + } +} + +void KDateNavigator::wheelEvent ( QWheelEvent *e ) +{ + if( e->delta() > 0 ) emit goPrevious(); + else emit goNext(); + + e->accept(); +} + +bool KDateNavigator::eventFilter ( QObject *o, QEvent *e ) +{ + if ( e->type() == QEvent::MouseButtonPress ) { + int i; + for( i = 0; i < 6; ++i ) { + if ( o == mWeeknos[ i ] ) { + QDate weekstart = mDayMatrix->getDate( i * 7 ); + emit weekClicked( weekstart ); + break; + } + } + return true; + } else { + return false; + } +} + +#include "kdatenavigator.moc" diff --git a/korganizer/kdatenavigator.h b/korganizer/kdatenavigator.h new file mode 100644 index 000000000..873c4cd3e --- /dev/null +++ b/korganizer/kdatenavigator.h @@ -0,0 +1,115 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001,2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KDATENAVIGATOR_H +#define KDATENAVIGATOR_H + +#include <qframe.h> +#include <qdatetime.h> + +#include <libkcal/incidencebase.h> + +class QPushButton; +class QLabel; + +namespace KCal { +class Calendar; +class Incidence; +} +class NavigatorBar; +using namespace KCal; + +class KODayMatrix; + +class KDateNavigator: public QFrame +{ + Q_OBJECT + public: + KDateNavigator( QWidget *parent = 0, const char *name = 0 ); + ~KDateNavigator(); + + /** + Associate date navigator with a calendar. It is used by KODayMatrix. + */ + void setCalendar( Calendar * ); + + void setBaseDate( const QDate & ); + + KCal::DateList selectedDates() const { return mSelectedDates; } + + QSizePolicy sizePolicy () const; + + NavigatorBar *navigatorBar() const { return mNavigatorBar; } + QDate startDate() const; + QDate endDate() const; + + public slots: + void selectDates( const KCal::DateList & ); + void updateView(); + void updateConfig(); + void updateDayMatrix(); + void updateToday(); + + signals: + void datesSelected( const KCal::DateList & ); + void incidenceDropped( Incidence *, const QDate & ); + void incidenceDroppedMove( Incidence *, const QDate & ); + void weekClicked( const QDate &); + + void goPrevious(); + void goNext(); + + void goNextMonth(); + void goPrevMonth(); + void goNextYear(); + void goPrevYear(); + + void goMonth( int month ); + + protected: + void updateDates(); + + void wheelEvent( QWheelEvent * ); + + bool eventFilter( QObject *,QEvent * ); + + void setShowWeekNums( bool enabled ); + + private: + NavigatorBar *mNavigatorBar; + + QLabel *mHeadings[ 7 ]; + QLabel *mWeeknos[ 7 ]; + + KODayMatrix *mDayMatrix; + + KCal::DateList mSelectedDates; + QDate mBaseDate; + + // Disabling copy constructor and assignment operator + KDateNavigator( const KDateNavigator & ); + KDateNavigator &operator=( const KDateNavigator & ); +}; + +#endif diff --git a/korganizer/koagenda.cpp b/korganizer/koagenda.cpp new file mode 100644 index 000000000..b63f13030 --- /dev/null +++ b/korganizer/koagenda.cpp @@ -0,0 +1,1999 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com> + + Marcus Bains line. + Copyright (c) 2001 Ali Rahimi + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#include <assert.h> + +#include <qintdict.h> +#include <qdatetime.h> +#include <qapplication.h> +#include <qpopupmenu.h> +#include <qcursor.h> +#include <qpainter.h> +#include <qlabel.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kglobal.h> +#include <kmessagebox.h> + +#include "koagendaitem.h" +#include "koprefs.h" +#include "koglobals.h" +#include "komessagebox.h" +#include "incidencechanger.h" +#include "kohelper.h" + +#include "koagenda.h" +#include "koagenda.moc" +#include <korganizer/baseview.h> + +#include <libkcal/event.h> +#include <libkcal/todo.h> +#include <libkcal/dndfactory.h> +#include <libkcal/icaldrag.h> +#include <libkcal/vcaldrag.h> +#include <libkcal/calendar.h> +#include <libkcal/calendarresources.h> +#include <math.h> + +//////////////////////////////////////////////////////////////////////////// +MarcusBains::MarcusBains(KOAgenda *_agenda,const char *name) + : QFrame(_agenda->viewport(),name), agenda(_agenda) +{ + setLineWidth(0); + setMargin(0); + setBackgroundColor(Qt::red); + minutes = new QTimer(this); + connect(minutes, SIGNAL(timeout()), this, SLOT(updateLocation())); + minutes->start(0, true); + + mTimeBox = new QLabel(this); + mTimeBox->setAlignment(Qt::AlignRight | Qt::AlignBottom); + QPalette pal = mTimeBox->palette(); + pal.setColor(QColorGroup::Foreground, Qt::red); + mTimeBox->setPalette(pal); + mTimeBox->setAutoMask(true); + + agenda->addChild(mTimeBox); + + oldToday = -1; +} + +MarcusBains::~MarcusBains() +{ + delete minutes; +} + +int MarcusBains::todayColumn() +{ + QDate currentDate = QDate::currentDate(); + + DateList dateList = agenda->dateList(); + DateList::ConstIterator it; + int col = 0; + for(it = dateList.begin(); it != dateList.end(); ++it) { + if((*it) == currentDate) + return KOGlobals::self()->reverseLayout() ? + agenda->columns() - 1 - col : col; + ++col; + } + + return -1; +} + +void MarcusBains::updateLocation(bool recalculate) +{ + QTime tim = QTime::currentTime(); + if((tim.hour() == 0) && (oldTime.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 x = int( agenda->gridSpacingX() * today ); + bool disabled = !(KOPrefs::instance()->mMarcusBainsEnabled); + + oldTime = tim; + oldToday = today; + + if(disabled || (today<0)) { + hide(); + mTimeBox->hide(); + return; + } else { + show(); + mTimeBox->show(); + } + + if ( recalculate ) setFixedSize( int( agenda->gridSpacingX() ), 1 ); + agenda->moveChild( this, x, y ); + raise(); + + if(recalculate) + mTimeBox->setFont(KOPrefs::instance()->mMarcusBainsFont); + + mTimeBox->setText(KGlobal::locale()->formatTime(tim, KOPrefs::instance()->mMarcusBainsShowSeconds)); + mTimeBox->adjustSize(); + if (y-mTimeBox->height()>=0) y-=mTimeBox->height(); else y++; + if (x-mTimeBox->width()+agenda->gridSpacingX() > 0) + x += int( agenda->gridSpacingX() - mTimeBox->width() - 1 ); + else x++; + agenda->moveChild(mTimeBox,x,y); + mTimeBox->raise(); + mTimeBox->setAutoMask(true); + + minutes->start(1000,true); +} + + +//////////////////////////////////////////////////////////////////////////// + + +/* + Create an agenda widget with rows rows and columns columns. +*/ +KOAgenda::KOAgenda( int columns, int rows, int rowSize, QWidget *parent, + const char *name, WFlags f ) + : QScrollView( parent, name, f ), mChanger( 0 ) +{ + mColumns = columns; + mRows = rows; + mGridSpacingY = rowSize; + mAllDayMode = false; + + init(); + + viewport()->setMouseTracking(true); +} + +/* + Create an agenda widget with columns columns and one row. This is used for + all-day events. +*/ +KOAgenda::KOAgenda( int columns, QWidget *parent, const char *name, WFlags f ) + : QScrollView( parent, name, f ) +{ + mColumns = columns; + mRows = 1; + mGridSpacingY = 24; + mAllDayMode = true; + setVScrollBarMode( AlwaysOff ); + + init(); +} + + +KOAgenda::~KOAgenda() +{ + delete mMarcusBains; +} + + +Incidence *KOAgenda::selectedIncidence() const +{ + return ( mSelectedItem ? mSelectedItem->incidence() : 0 ); +} + + +QDate KOAgenda::selectedIncidenceDate() const +{ + return ( mSelectedItem ? mSelectedItem->itemDate() : QDate() ); +} + +const QString KOAgenda::lastSelectedUid() const +{ + return mSelectedUid; +} + + +void KOAgenda::init() +{ + mGridSpacingX = 100; + + mResizeBorderWidth = 8; + mScrollBorderWidth = 8; + mScrollDelay = 30; + mScrollOffset = 10; + + enableClipper( true ); + + // Grab key strokes for keyboard navigation of agenda. Seems to have no + // effect. Has to be fixed. + setFocusPolicy( WheelFocus ); + + connect( &mScrollUpTimer, SIGNAL( timeout() ), SLOT( scrollUp() ) ); + connect( &mScrollDownTimer, SIGNAL( timeout() ), SLOT( scrollDown() ) ); + + mStartCell = QPoint( 0, 0 ); + mEndCell = QPoint( 0, 0 ); + + mHasSelection = false; + mSelectionStartPoint = QPoint( 0, 0 ); + mSelectionStartCell = QPoint( 0, 0 ); + mSelectionEndCell = QPoint( 0, 0 ); + + mOldLowerScrollValue = -1; + mOldUpperScrollValue = -1; + + mClickedItem = 0; + + mActionItem = 0; + mActionType = NOP; + mItemMoved = false; + + mSelectedItem = 0; + mSelectedUid = QString::null; + + setAcceptDrops( true ); + installEventFilter( this ); + mItems.setAutoDelete( true ); + mItemsToDelete.setAutoDelete( true ); + + resizeContents( int( mGridSpacingX * mColumns ), + int( mGridSpacingY * mRows ) ); + + viewport()->update(); + viewport()->setBackgroundMode( NoBackground ); + viewport()->setFocusPolicy( WheelFocus ); + + setMinimumSize( 30, int( mGridSpacingY + 1 ) ); +// setMaximumHeight(mGridSpacingY * mRows + 5); + + // Disable horizontal scrollbar. This is a hack. The geometry should be + // controlled in a way that the contents horizontally always fits. Then it is + // not necessary to turn off the scrollbar. + setHScrollBarMode( AlwaysOff ); + + setStartTime( KOPrefs::instance()->mDayBegins.time() ); + + calculateWorkingHours(); + + connect( verticalScrollBar(), SIGNAL( valueChanged( int ) ), + SLOT( checkScrollBoundaries( int ) ) ); + + // Create the Marcus Bains line. + if( mAllDayMode ) { + mMarcusBains = 0; + } else { + mMarcusBains = new MarcusBains( this ); + addChild( mMarcusBains ); + } + + mTypeAhead = false; + mTypeAheadReceiver = 0; + + mReturnPressed = false; +} + + +void KOAgenda::clear() +{ +// kdDebug(5850) << "KOAgenda::clear()" << endl; + + KOAgendaItem *item; + for ( item = mItems.first(); item != 0; item = mItems.next() ) { + removeChild( item ); + } + mItems.clear(); + mItemsToDelete.clear(); + + mSelectedItem = 0; + + clearSelection(); +} + + +void KOAgenda::clearSelection() +{ + mHasSelection = false; + mActionType = NOP; + updateContents(); +} + +void KOAgenda::marcus_bains() +{ + if(mMarcusBains) mMarcusBains->updateLocation(true); +} + + +void KOAgenda::changeColumns(int columns) +{ + if (columns == 0) { + kdDebug(5850) << "KOAgenda::changeColumns() called with argument 0" << endl; + return; + } + + clear(); + mColumns = columns; +// setMinimumSize(mColumns * 10, mGridSpacingY + 1); +// init(); +// update(); + + QResizeEvent event( size(), size() ); + + QApplication::sendEvent( this, &event ); +} + +/* + This is the eventFilter function, which gets all events from the KOAgendaItems + contained in the agenda. It has to handle moving and resizing for all items. +*/ +bool KOAgenda::eventFilter ( QObject *object, QEvent *event ) +{ +// kdDebug(5850) << "KOAgenda::eventFilter() " << int( event->type() ) << endl; + + switch( event->type() ) { + case QEvent::MouseButtonPress: + case QEvent::MouseButtonDblClick: + case QEvent::MouseButtonRelease: + case QEvent::MouseMove: + return eventFilter_mouse( object, static_cast<QMouseEvent *>( event ) ); +#ifndef QT_NO_WHEELEVENT + case QEvent::Wheel: + return eventFilter_wheel( object, static_cast<QWheelEvent *>( event ) ); +#endif + case QEvent::KeyPress: + case QEvent::KeyRelease: + return eventFilter_key( object, static_cast<QKeyEvent *>( event ) ); + + case ( QEvent::Leave ): + if ( !mActionItem ) + setCursor( arrowCursor ); + if ( object == viewport() ) + emit leaveAgenda(); + return true; + + case QEvent::Enter: + emit enterAgenda(); + return QScrollView::eventFilter( object, event ); + +#ifndef KORG_NODND + case QEvent::DragEnter: + case QEvent::DragMove: + case QEvent::DragLeave: + case QEvent::Drop: + // case QEvent::DragResponse: + return eventFilter_drag(object, static_cast<QDropEvent*>(event)); +#endif + + default: + return QScrollView::eventFilter( object, event ); + } +} + +bool KOAgenda::eventFilter_drag( QObject *object, QDropEvent *de ) +{ +#ifndef KORG_NODND + QPoint viewportPos; + if ( object != viewport() && object != this ) { + viewportPos = static_cast<QWidget *>( object )->mapToParent( de->pos() ); + } else { + viewportPos = de->pos(); + } + + switch ( de->type() ) { + case QEvent::DragEnter: + case QEvent::DragMove: + if ( ICalDrag::canDecode( de ) || VCalDrag::canDecode( de ) ) { + + DndFactory factory( mCalendar ); + Todo *todo = factory.createDropTodo( de ); + if ( todo ) { + de->accept(); + delete todo; + } else { + de->ignore(); + } + return true; + } else return false; + break; + case QEvent::DragLeave: + return false; + break; + case QEvent::Drop: + { + if ( !ICalDrag::canDecode( de ) && !VCalDrag::canDecode( de ) ) { + return false; + } + + DndFactory factory( mCalendar ); + Todo *todo = factory.createDropTodo( de ); + + if ( todo ) { + de->acceptAction(); + QPoint pos; + // FIXME: This is a bad hack, as the viewportToContents seems to be off by + // 2000 (which is the left upper corner of the viewport). It works correctly + // for agendaItems. + if ( object == this ) { + pos = viewportPos + QPoint( contentsX(), contentsY() ); + } else { + pos = viewportToContents( viewportPos ); + } + QPoint gpos = contentsToGrid( pos ); + emit droppedToDo( todo, gpos, mAllDayMode ); + return true; + } + } + break; + + case QEvent::DragResponse: + default: + break; + } +#endif + + return false; +} + +bool KOAgenda::eventFilter_key( QObject *, QKeyEvent *ke ) +{ + // kdDebug(5850) << "KOAgenda::eventFilter_key() " << ke->type() << endl; + + // If Return is pressed bring up an editor for the current selected time span. + if ( ke->key() == Key_Return ) { + if ( ke->type() == QEvent::KeyPress ) mReturnPressed = true; + else if ( ke->type() == QEvent::KeyRelease ) { + if ( mReturnPressed ) { + emitNewEventForSelection(); + mReturnPressed = false; + return true; + } else { + mReturnPressed = false; + } + } + } + + // Ignore all input that does not produce any output + if ( ke->text().isEmpty() ) return false; + + if ( ke->type() == QEvent::KeyPress || ke->type() == QEvent::KeyRelease ) { + switch ( ke->key() ) { + case Key_Escape: + case Key_Return: + case Key_Enter: + case Key_Tab: + case Key_Backtab: + case Key_Left: + case Key_Right: + case Key_Up: + case Key_Down: + case Key_Backspace: + case Key_Delete: + case Key_Prior: + case Key_Next: + case Key_Home: + case Key_End: + case Key_Control: + case Key_Meta: + case Key_Alt: + break; + default: + mTypeAheadEvents.append( new QKeyEvent( ke->type(), ke->key(), + ke->ascii(), ke->state(), + ke->text(), ke->isAutoRepeat(), + ke->count() ) ); + if ( !mTypeAhead ) { + mTypeAhead = true; + emitNewEventForSelection(); + } + return true; + } + } + return false; +} + +void KOAgenda::emitNewEventForSelection() +{ + emit newEventSignal(); +} + +void KOAgenda::finishTypeAhead() +{ +// kdDebug(5850) << "KOAgenda::finishTypeAhead()" << endl; + if ( typeAheadReceiver() ) { + for( QEvent *e = mTypeAheadEvents.first(); e; + e = mTypeAheadEvents.next() ) { +// kdDebug(5850) << "sendEvent() " << int( typeAheadReceiver() ) << endl; + QApplication::sendEvent( typeAheadReceiver(), e ); + } + } + mTypeAheadEvents.clear(); + mTypeAhead = false; +} +#ifndef QT_NO_WHEELEVENT +bool KOAgenda::eventFilter_wheel ( QObject *object, QWheelEvent *e ) +{ + QPoint viewportPos; + bool accepted=false; + if ( ( e->state() & ShiftButton) == ShiftButton ) { + if ( object != viewport() ) { + viewportPos = ( (QWidget *) object )->mapToParent( e->pos() ); + } else { + viewportPos = e->pos(); + } + //kdDebug(5850)<< "KOAgenda::eventFilter_wheel: type:"<< + // e->type()<<" delta: "<< e->delta()<< endl; + emit zoomView( -e->delta() , + contentsToGrid( viewportToContents( viewportPos ) ), + Qt::Horizontal ); + accepted=true; + } + + if ( ( e->state() & ControlButton ) == ControlButton ){ + if ( object != viewport() ) { + viewportPos = ( (QWidget *)object )->mapToParent( e->pos() ); + } else { + viewportPos = e->pos(); + } + emit zoomView( -e->delta() , + contentsToGrid( viewportToContents( viewportPos ) ), + Qt::Vertical ); + emit mousePosSignal(gridToContents(contentsToGrid(viewportToContents( viewportPos )))); + accepted=true; + } + if (accepted ) e->accept(); + return accepted; +} +#endif +bool KOAgenda::eventFilter_mouse(QObject *object, QMouseEvent *me) +{ + QPoint viewportPos; + if (object != viewport()) { + viewportPos = ((QWidget *)object)->mapToParent(me->pos()); + } else { + viewportPos = me->pos(); + } + + switch (me->type()) { + case QEvent::MouseButtonPress: +// 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(), + mClickedItem->itemDate() ); + } + } else { + KOAgendaItem* item = dynamic_cast<KOAgendaItem *>(object); + if (item) { + Incidence *incidence = item->incidence(); + if ( incidence->isReadOnly() ) { + mActionItem = 0; + } else { + mActionItem = item; + startItemAction(viewportPos); + } + // Warning: do selectItem() as late as possible, since all + // sorts of things happen during this call. Some can lead to + // this filter being run again and mActionItem being set to + // null. + selectItem( item ); + } + } + } else { + if (me->button() == RightButton) + { + // if mouse pointer is not in selection, select the cell below the cursor + QPoint gpos = contentsToGrid( viewportToContents( viewportPos ) ); + if ( !ptInSelection( gpos ) ) { + mSelectionStartCell = gpos; + mSelectionEndCell = gpos; + mHasSelection = true; + emit newStartSelectSignal(); + emit newTimeSpanSignal( mSelectionStartCell, mSelectionEndCell ); + updateContents(); + } + showNewEventPopupSignal(); + } + else + { + // if mouse pointer is in selection, don't change selection + QPoint gpos = contentsToGrid( viewportToContents( viewportPos ) ); + if ( !ptInSelection( gpos ) ) { + selectItem(0); + mActionItem = 0; + setCursor(arrowCursor); + startSelectAction(viewportPos); + } + } + } + break; + + case QEvent::MouseButtonRelease: + if (mActionItem) { + endItemAction(); + } else if ( mActionType == SELECT ) { + endSelectAction( viewportPos ); + } + // This nasty gridToContents(contentsToGrid(..)) is needed to + // avoid an offset of a few pixels. Don't ask me why... + emit mousePosSignal( gridToContents(contentsToGrid( + viewportToContents( viewportPos ) ) )); + break; + + case QEvent::MouseMove: { + // This nasty gridToContents(contentsToGrid(..)) is needed to + // avoid an offset of a few pixels. Don't ask me why... + QPoint indicatorPos = gridToContents(contentsToGrid( + viewportToContents( viewportPos ))); + if (object != viewport()) { + KOAgendaItem *moveItem = dynamic_cast<KOAgendaItem *>(object); + if (moveItem && !moveItem->incidence()->isReadOnly() ) { + if (!mActionItem) + setNoActionCursor(moveItem,viewportPos); + else { + performItemAction(viewportPos); + + if ( mActionType == MOVE ) { + // show cursor at the current begin of the item + KOAgendaItem *firstItem = mActionItem->firstMultiItem(); + if (!firstItem) firstItem = mActionItem; + indicatorPos = gridToContents( QPoint( firstItem->cellXLeft(), + firstItem->cellYTop() ) ); + + } else if ( mActionType == RESIZEBOTTOM ) { + // RESIZETOP is handled correctly, only resizebottom works differently + indicatorPos = gridToContents( QPoint( mActionItem->cellXLeft(), + mActionItem->cellYBottom()+1 ) ); + } + + } // 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( QPoint(mEndCell.x(), mEndCell.y()+1) ); + else + indicatorPos = gridToContents( mEndCell ); + } + } + emit mousePosSignal( indicatorPos ); + break; } + + case QEvent::MouseButtonDblClick: + if (object == viewport()) { + selectItem(0); + emit newEventSignal(); + } else { + KOAgendaItem *doubleClickedItem = dynamic_cast<KOAgendaItem *>(object); + if (doubleClickedItem) { + selectItem(doubleClickedItem); + emit editIncidenceSignal(doubleClickedItem->incidence()); + } + } + break; + + default: + break; + } + + return true; +} + +bool KOAgenda::ptInSelection( QPoint gpos ) const +{ + if ( !mHasSelection ) { + return false; + } else if ( gpos.x()<mSelectionStartCell.x() || gpos.x()>mSelectionEndCell.x() ) { + return false; + } else if ( (gpos.x()==mSelectionStartCell.x()) && (gpos.y()<mSelectionStartCell.y()) ) { + return false; + } else if ( (gpos.x()==mSelectionEndCell.x()) && (gpos.y()>mSelectionEndCell.y()) ) { + return false; + } + return true; +} + +void KOAgenda::startSelectAction( const QPoint &viewportPos ) +{ + emit newStartSelectSignal(); + + mActionType = SELECT; + mSelectionStartPoint = viewportPos; + mHasSelection = true; + + QPoint pos = viewportToContents( viewportPos ); + QPoint gpos = contentsToGrid( pos ); + + // Store new selection + mStartCell = gpos; + mEndCell = gpos; + mSelectionStartCell = gpos; + mSelectionEndCell = gpos; + + updateContents(); +} + +void KOAgenda::performSelectAction(const QPoint& viewportPos) +{ + QPoint pos = viewportToContents( viewportPos ); + QPoint gpos = contentsToGrid( pos ); + + QPoint clipperPos = clipper()-> + mapFromGlobal(viewport()->mapToGlobal(viewportPos)); + + // Scroll if cursor was moved to upper or lower end of agenda. + if (clipperPos.y() < mScrollBorderWidth) { + mScrollUpTimer.start(mScrollDelay); + } else if (visibleHeight() - clipperPos.y() < + mScrollBorderWidth) { + mScrollDownTimer.start(mScrollDelay); + } else { + mScrollUpTimer.stop(); + mScrollDownTimer.stop(); + } + + if ( gpos != mEndCell ) { + mEndCell = gpos; + if ( mStartCell.x()>mEndCell.x() || + ( mStartCell.x()==mEndCell.x() && mStartCell.y()>mEndCell.y() ) ) { + // backward selection + mSelectionStartCell = mEndCell; + mSelectionEndCell = mStartCell; + } else { + mSelectionStartCell = mStartCell; + mSelectionEndCell = mEndCell; + } + + updateContents(); + } +} + +void KOAgenda::endSelectAction( const QPoint ¤tPos ) +{ + mScrollUpTimer.stop(); + mScrollDownTimer.stop(); + + mActionType = NOP; + + emit newTimeSpanSignal( mSelectionStartCell, mSelectionEndCell ); + + if ( KOPrefs::instance()->mSelectionStartsEditor ) { + if ( ( mSelectionStartPoint - currentPos ).manhattanLength() > + QApplication::startDragDistance() ) { + emitNewEventForSelection(); + } + } +} + +KOAgenda::MouseActionType KOAgenda::isInResizeArea( bool horizontal, + const QPoint &pos, KOAgendaItem*item ) +{ + if (!item) return NOP; + QPoint gridpos = contentsToGrid( pos ); + QPoint contpos = gridToContents( gridpos + + QPoint( (KOGlobals::self()->reverseLayout())?1:0, 0 ) ); + +//kdDebug(5850)<<"contpos="<<contpos<<", pos="<<pos<<", gpos="<<gpos<<endl; +//kdDebug(5850)<<"clXLeft="<<clXLeft<<", clXRight="<<clXRight<<endl; + + if ( horizontal ) { + int clXLeft = item->cellXLeft(); + int clXRight = item->cellXRight(); + if ( KOGlobals::self()->reverseLayout() ) { + int tmp = clXLeft; + clXLeft = clXRight; + clXRight = tmp; + } + int gridDistanceX = int( pos.x() - contpos.x() ); + if (gridDistanceX < mResizeBorderWidth && clXLeft == gridpos.x() ) { + if ( KOGlobals::self()->reverseLayout() ) return RESIZERIGHT; + else return RESIZELEFT; + } else if ((mGridSpacingX - gridDistanceX) < mResizeBorderWidth && + clXRight == gridpos.x() ) { + if ( KOGlobals::self()->reverseLayout() ) return RESIZELEFT; + else return RESIZERIGHT; + } else { + return MOVE; + } + } else { + int gridDistanceY = int( pos.y() - contpos.y() ); + if (gridDistanceY < mResizeBorderWidth && + item->cellYTop() == gridpos.y() && + !item->firstMultiItem() ) { + return RESIZETOP; + } else if ((mGridSpacingY - gridDistanceY) < mResizeBorderWidth && + item->cellYBottom() == gridpos.y() && + !item->lastMultiItem() ) { + return RESIZEBOTTOM; + } else { + return MOVE; + } + } +} + +void KOAgenda::startItemAction(const QPoint& viewportPos) +{ + QPoint pos = viewportToContents( viewportPos ); + mStartCell = contentsToGrid( pos ); + mEndCell = mStartCell; + + bool noResize = ( mActionItem->incidence()->type() == "Todo"); + + mActionType = MOVE; + if ( !noResize ) { + mActionType = isInResizeArea( mAllDayMode, pos, mActionItem ); + } + + + mActionItem->startMove(); + setActionCursor( mActionType, true ); +} + +void KOAgenda::performItemAction(const QPoint& viewportPos) +{ +// kdDebug(5850) << "viewportPos: " << viewportPos.x() << "," << viewportPos.y() << endl; +// QPoint point = viewport()->mapToGlobal(viewportPos); +// kdDebug(5850) << "Global: " << point.x() << "," << point.y() << endl; +// point = clipper()->mapFromGlobal(point); +// kdDebug(5850) << "clipper: " << point.x() << "," << point.y() << endl; +// kdDebug(5850) << "visible height: " << visibleHeight() << endl; + QPoint pos = viewportToContents( viewportPos ); +// kdDebug(5850) << "contents: " << x << "," << y << "\n" << endl; + QPoint gpos = contentsToGrid( pos ); + QPoint clipperPos = clipper()-> + mapFromGlobal(viewport()->mapToGlobal(viewportPos)); + + // Cursor left active agenda area. + // This starts a drag. + if ( clipperPos.y() < 0 || clipperPos.y() > visibleHeight() || + clipperPos.x() < 0 || clipperPos.x() > visibleWidth() ) { + if ( mActionType == MOVE ) { + mScrollUpTimer.stop(); + mScrollDownTimer.stop(); + mActionItem->resetMove(); + placeSubCells( mActionItem ); + emit startDragSignal( mActionItem->incidence() ); + setCursor( arrowCursor ); + mActionItem = 0; + mActionType = NOP; + mItemMoved = false; + if ( mItemMoved && mChanger ) + mChanger->endChange( mActionItem->incidence() ); + return; + } + } else { + setActionCursor( mActionType ); + } + + // Scroll if item was moved to upper or lower end of agenda. + if (clipperPos.y() < mScrollBorderWidth) { + mScrollUpTimer.start(mScrollDelay); + } else if (visibleHeight() - clipperPos.y() < + mScrollBorderWidth) { + mScrollDownTimer.start(mScrollDelay); + } else { + mScrollUpTimer.stop(); + mScrollDownTimer.stop(); + } + + // Move or resize item if necessary + if ( mEndCell != gpos ) { + if ( !mItemMoved ) { + if ( !mChanger || !mChanger->beginChange( mActionItem->incidence() ) ) { + KMessageBox::information( this, i18n("Unable to lock item for " + "modification. You cannot make any changes."), + i18n("Locking Failed"), "AgendaLockingFailed" ); + mScrollUpTimer.stop(); + mScrollDownTimer.stop(); + mActionItem->resetMove(); + placeSubCells( mActionItem ); + setCursor( arrowCursor ); + mActionItem = 0; + mActionType = NOP; + mItemMoved = false; + return; + } + mItemMoved = true; + } + mActionItem->raise(); + if (mActionType == MOVE) { + // Move all items belonging to a multi item + KOAgendaItem *firstItem = mActionItem->firstMultiItem(); + if (!firstItem) firstItem = mActionItem; + KOAgendaItem *lastItem = mActionItem->lastMultiItem(); + if (!lastItem) lastItem = mActionItem; + QPoint deltapos = gpos - mEndCell; + KOAgendaItem *moveItem = firstItem; + while (moveItem) { + bool changed=false; + if ( deltapos.x()!=0 ) { + moveItem->moveRelative( deltapos.x(), 0 ); + changed=true; + } + // in agenda's all day view don't try to move multi items, since there are none + if ( moveItem==firstItem && !mAllDayMode ) { // is the first item + int newY = deltapos.y() + moveItem->cellYTop(); + // If event start moved earlier than 0:00, it starts the previous day + if ( newY<0 ) { + moveItem->expandTop( -moveItem->cellYTop() ); + // prepend a new item at ( x-1, rows()+newY to rows() ) + KOAgendaItem *newFirst = firstItem->prevMoveItem(); + // cell's y values are first and last cell of the bar, so if newY=-1, they need to be the same + if (newFirst) { + newFirst->setCellXY(moveItem->cellXLeft()-1, rows()+newY, rows()-1); + mItems.append( newFirst ); + moveItem->resize( int( mGridSpacingX * newFirst->cellWidth() ), + int( mGridSpacingY * newFirst->cellHeight() )); + QPoint cpos = gridToContents( QPoint( newFirst->cellXLeft(), newFirst->cellYTop() ) ); + addChild( newFirst, cpos.x(), cpos.y() ); + } else { + newFirst = insertItem( moveItem->incidence(), moveItem->itemDate(), + moveItem->cellXLeft()-1, rows()+newY, rows()-1 ) ; + } + if (newFirst) newFirst->show(); + moveItem->prependMoveItem(newFirst); + firstItem=newFirst; + } else if ( newY>=rows() ) { + // If event start is moved past 24:00, it starts the next day + // erase current item (i.e. remove it from the multiItem list) + firstItem = moveItem->nextMultiItem(); + moveItem->hide(); + mItems.take( mItems.find( moveItem ) ); + removeChild( moveItem ); + mActionItem->removeMoveItem(moveItem); + moveItem=firstItem; + // adjust next day's item + if (moveItem) moveItem->expandTop( rows()-newY ); + } else { + moveItem->expandTop(deltapos.y()); + } + changed=true; + } + if ( !moveItem->lastMultiItem() && !mAllDayMode ) { // is the last item + int newY = deltapos.y()+moveItem->cellYBottom(); + if (newY<0) { + // erase current item + lastItem = moveItem->prevMultiItem(); + moveItem->hide(); + mItems.take( mItems.find(moveItem) ); + removeChild( moveItem ); + moveItem->removeMoveItem( moveItem ); + moveItem = lastItem; + moveItem->expandBottom(newY+1); + } else if (newY>=rows()) { + moveItem->expandBottom( rows()-moveItem->cellYBottom()-1 ); + // append item at ( x+1, 0 to newY-rows() ) + KOAgendaItem *newLast = lastItem->nextMoveItem(); + if (newLast) { + newLast->setCellXY( moveItem->cellXLeft()+1, 0, newY-rows()-1 ); + mItems.append(newLast); + moveItem->resize( int( mGridSpacingX * newLast->cellWidth() ), + int( mGridSpacingY * newLast->cellHeight() )); + QPoint cpos = gridToContents( QPoint( newLast->cellXLeft(), newLast->cellYTop() ) ) ; + addChild( newLast, cpos.x(), cpos.y() ); + } else { + newLast = insertItem( moveItem->incidence(), moveItem->itemDate(), + moveItem->cellXLeft()+1, 0, newY-rows()-1 ) ; + } + moveItem->appendMoveItem( newLast ); + newLast->show(); + lastItem = newLast; + } else { + moveItem->expandBottom( deltapos.y() ); + } + changed=true; + } + if (changed) { + adjustItemPosition( moveItem ); + } + moveItem = moveItem->nextMultiItem(); + } + } else if (mActionType == RESIZETOP) { + if (mEndCell.y() <= mActionItem->cellYBottom()) { + mActionItem->expandTop(gpos.y() - mEndCell.y()); + adjustItemPosition( mActionItem ); + } + } else if (mActionType == RESIZEBOTTOM) { + if (mEndCell.y() >= mActionItem->cellYTop()) { + mActionItem->expandBottom(gpos.y() - mEndCell.y()); + adjustItemPosition( mActionItem ); + } + } else if (mActionType == RESIZELEFT) { + if (mEndCell.x() <= mActionItem->cellXRight()) { + mActionItem->expandLeft( gpos.x() - mEndCell.x() ); + adjustItemPosition( mActionItem ); + } + } else if (mActionType == RESIZERIGHT) { + if (mEndCell.x() >= mActionItem->cellXLeft()) { + mActionItem->expandRight(gpos.x() - mEndCell.x()); + adjustItemPosition( mActionItem ); + } + } + mEndCell = gpos; + } +} + +void KOAgenda::endItemAction() +{ +// kdDebug(5850) << "KOAgenda::endItemAction() " << endl; + mActionType = NOP; + mScrollUpTimer.stop(); + mScrollDownTimer.stop(); + setCursor( arrowCursor ); + bool multiModify = false; + // FIXME: do the cloning here... + Incidence* inc = mActionItem->incidence(); + + if ( mItemMoved ) { + bool modify = true; + if ( mActionItem->incidence()->doesRecur() ) { + int res = KOMessageBox::fourBtnMsgBox( this, QMessageBox::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; + 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(); + Incidence* 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 ); + mChanger->addIncidence( newInc, this ); + emit enableAgendaUpdate( true ); + 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(); + Incidence* newInc = mCalendar->dissociateOccurrence( + oldInc, mActionItem->itemDate(), false ); + if ( newInc ) { + emit enableAgendaUpdate( false ); + mActionItem->dissociateFromMultiItem(); + mActionItem->setIncidence( newInc ); + mChanger->addIncidence( newInc, this ); + emit enableAgendaUpdate( true ); + 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 ); + } + } + + if ( modify ) { + mActionItem->endMove(); + KOAgendaItem *placeItem = mActionItem->firstMultiItem(); + if ( !placeItem ) { + placeItem = mActionItem; + } + + KOAgendaItem *modif = placeItem; + + QPtrList<KOAgendaItem> oldconflictItems = placeItem->conflictItems(); + KOAgendaItem *item; + for ( item = oldconflictItems.first(); item != 0; + item = oldconflictItems.next() ) { + placeSubCells( item ); + } + while ( placeItem ) { + placeSubCells( placeItem ); + placeItem = placeItem->nextMultiItem(); + } + + // Notify about change + // the agenda view will apply the changes to the actual Incidence*! + emit itemModified( modif ); + } + // FIXME: If the change failed, we need to update the view! + mChanger->endChange( inc ); + } + + mActionItem = 0; + mItemMoved = false; + + if ( multiModify ) emit endMultiModify(); + + kdDebug(5850) << "KOAgenda::endItemAction() done" << endl; +} + +void KOAgenda::setActionCursor( int actionType, bool acting ) +{ + switch ( actionType ) { + case MOVE: + if (acting) setCursor( sizeAllCursor ); + else setCursor( arrowCursor ); + break; + case RESIZETOP: + case RESIZEBOTTOM: + setCursor( sizeVerCursor ); + break; + case RESIZELEFT: + case RESIZERIGHT: + setCursor( sizeHorCursor ); + break; + default: + setCursor( arrowCursor ); + } +} + +void KOAgenda::setNoActionCursor( KOAgendaItem *moveItem, const QPoint& viewportPos ) +{ +// kdDebug(5850) << "viewportPos: " << viewportPos.x() << "," << viewportPos.y() << endl; +// QPoint point = viewport()->mapToGlobal(viewportPos); +// kdDebug(5850) << "Global: " << point.x() << "," << point.y() << endl; +// point = clipper()->mapFromGlobal(point); +// kdDebug(5850) << "clipper: " << point.x() << "," << point.y() << endl; + + QPoint pos = viewportToContents( viewportPos ); + bool noResize = (moveItem && moveItem->incidence() && + moveItem->incidence()->type() == "Todo"); + + KOAgenda::MouseActionType resizeType = MOVE; + if ( !noResize ) resizeType = isInResizeArea( mAllDayMode, pos , moveItem); + setActionCursor( resizeType ); +} + + +/** calculate the width of the column subcells of the given item +*/ +double KOAgenda::calcSubCellWidth( KOAgendaItem *item ) +{ + QPoint pt, pt1; + pt = gridToContents( QPoint( item->cellXLeft(), item->cellYTop() ) ); + pt1 = gridToContents( QPoint( item->cellXLeft(), item->cellYTop() ) + + QPoint( 1, 1 ) ); + pt1 -= pt; + int maxSubCells = item->subCells(); + double newSubCellWidth; + if ( mAllDayMode ) { + newSubCellWidth = double( pt1.y() ) / maxSubCells; + } else { + newSubCellWidth = double( pt1.x() ) / maxSubCells; + } + return newSubCellWidth; +} + +void KOAgenda::adjustItemPosition( KOAgendaItem *item ) +{ + if (!item) return; + item->resize( int( mGridSpacingX * item->cellWidth() ), + int( mGridSpacingY * item->cellHeight() ) ); + int clXLeft = item->cellXLeft(); + if ( KOGlobals::self()->reverseLayout() ) + clXLeft = item->cellXRight() + 1; + QPoint cpos = gridToContents( QPoint( clXLeft, item->cellYTop() ) ); + moveChild( item, cpos.x(), cpos.y() ); +} + +void KOAgenda::placeAgendaItem( KOAgendaItem *item, double subCellWidth ) +{ +// kdDebug(5850) << "KOAgenda::placeAgendaItem(): " << item->incidence()->summary() +// << " subCellWidth: " << subCellWidth << endl; + + // "left" upper corner, no subcells yet, RTL layouts have right/left switched, widths are negative then + QPoint pt = gridToContents( QPoint( item->cellXLeft(), item->cellYTop() ) ); + // right lower corner + QPoint pt1 = gridToContents( QPoint( item->cellXLeft() + item->cellWidth(), + item->cellYBottom()+1 ) ); + + double subCellPos = item->subCell() * subCellWidth; + + // we need to add 0.01 to make sure we don't loose one pixed due to + // numerics (i.e. if it would be x.9998, we want the integer, not rounded down. + double delta=0.01; + if (subCellWidth<0) delta=-delta; + int height, width, xpos, ypos; + if (mAllDayMode) { + width = pt1.x()-pt.x(); + height = int( subCellPos + subCellWidth + delta ) - int( subCellPos ); + xpos = pt.x(); + ypos = pt.y() + int( subCellPos ); + } else { + width = int( subCellPos + subCellWidth + delta ) - int( subCellPos ); + height = pt1.y()-pt.y(); + xpos = pt.x() + int( subCellPos ); + ypos = pt.y(); + } + if ( KOGlobals::self()->reverseLayout() ) { // RTL language/layout + xpos += width; + width = -width; + } + if ( height<0 ) { // BTT (bottom-to-top) layout ?!? + ypos += height; + height = -height; + } + item->resize( width, height ); + moveChild( item, xpos, ypos ); +} + +/* + Place item in cell and take care that multiple items using the same cell do + not overlap. This method is not yet optimal. It doesn't use the maximum space + it can get in all cases. + At the moment the method has a bug: When an item is placed only the sub cell + widths of the items are changed, which are within the Y region the item to + place spans. When the sub cell width change of one of this items affects a + cell, where other items are, which do not overlap in Y with the item to place, + the display gets corrupted, although the corruption looks quite nice. +*/ +void KOAgenda::placeSubCells( KOAgendaItem *placeItem ) +{ +#if 0 + kdDebug(5850) << "KOAgenda::placeSubCells()" << endl; + if ( placeItem ) { + Incidence *event = placeItem->incidence(); + if ( !event ) { + kdDebug(5850) << " event is 0" << endl; + } else { + kdDebug(5850) << " event: " << event->summary() << endl; + } + } else { + kdDebug(5850) << " placeItem is 0" << endl; + } + kdDebug(5850) << "KOAgenda::placeSubCells()..." << endl; +#endif + + QPtrList<KOrg::CellItem> cells; + KOAgendaItem *item; + for ( item = mItems.first(); item != 0; item = mItems.next() ) { + cells.append( item ); + } + + QPtrList<KOrg::CellItem> items = KOrg::CellItem::placeItem( cells, + placeItem ); + + placeItem->setConflictItems( QPtrList<KOAgendaItem>() ); + double newSubCellWidth = calcSubCellWidth( placeItem ); + KOrg::CellItem *i; + for ( i = items.first(); i; i = items.next() ) { + item = static_cast<KOAgendaItem *>( i ); + placeAgendaItem( item, newSubCellWidth ); + item->addConflictItem( placeItem ); + placeItem->addConflictItem( item ); + } + if ( items.isEmpty() ) { + placeAgendaItem( placeItem, newSubCellWidth ); + } + placeItem->update(); +} + +int KOAgenda::columnWidth( int column ) +{ + int start = gridToContents( QPoint( column, 0 ) ).x(); + if (KOGlobals::self()->reverseLayout() ) + column--; + else + column++; + int end = gridToContents( QPoint( column, 0 ) ).x(); + return end - start; +} +/* + Draw grid in the background of the agenda. +*/ +void KOAgenda::drawContents(QPainter* p, int cx, int cy, int cw, int ch) +{ + QPixmap db(cw, ch); + db.fill(KOPrefs::instance()->mAgendaBgColor); + QPainter dbp(&db); + dbp.translate(-cx,-cy); + +// kdDebug(5850) << "KOAgenda::drawContents()" << endl; + double lGridSpacingY = mGridSpacingY*2; + + // Highlight working hours + if (mWorkingHoursEnable) { + QPoint pt1( cx, mWorkingHoursYTop ); + QPoint pt2( cx+cw, mWorkingHoursYBottom ); + if ( pt2.x() >= pt1.x() /*&& pt2.y() >= pt1.y()*/) { + int gxStart = contentsToGrid( pt1 ).x(); + int gxEnd = contentsToGrid( pt2 ).x(); + // correct start/end for rtl layouts + if ( gxStart > gxEnd ) { + int tmp = gxStart; + gxStart = gxEnd; + gxEnd = tmp; + } + int xoffset = ( KOGlobals::self()->reverseLayout()?1:0 ); + while( gxStart <= gxEnd ) { + int xStart = gridToContents( QPoint( gxStart+xoffset, 0 ) ).x(); + int xWidth = columnWidth( gxStart ) + 1; + if ( pt2.y() < pt1.y() ) { + // overnight working hours + if ( ( (gxStart==0) && !mHolidayMask->at(mHolidayMask->count()-1) ) || + ( (gxStart>0) && (gxStart<int(mHolidayMask->count())) && (!mHolidayMask->at(gxStart-1) ) ) ) { + if ( pt2.y() > cy ) { + dbp.fillRect( xStart, cy, xWidth, pt2.y() - cy + 1, + KOPrefs::instance()->mWorkingHoursColor); + } + } + if ( (gxStart < int(mHolidayMask->count()-1)) && (!mHolidayMask->at(gxStart)) ) { + if ( pt1.y() < cy + ch - 1 ) { + dbp.fillRect( xStart, pt1.y(), xWidth, cy + ch - pt1.y() + 1, + KOPrefs::instance()->mWorkingHoursColor); + } + } + } else { + // last entry in holiday mask denotes the previous day not visible (needed for overnight shifts) + if ( gxStart < int(mHolidayMask->count()-1) && !mHolidayMask->at(gxStart)) { + dbp.fillRect( xStart, pt1.y(), xWidth, pt2.y() - pt1.y() + 1, + KOPrefs::instance()->mWorkingHoursColor ); + } + } + ++gxStart; + } + } + } + + // draw selection + if ( mHasSelection ) { + QPoint pt, pt1; + + if ( mSelectionEndCell.x() > mSelectionStartCell.x() ) { // multi day selection + // draw start day + pt = gridToContents( mSelectionStartCell ); + pt1 = gridToContents( QPoint( mSelectionStartCell.x() + 1, mRows + 1 ) ); + dbp.fillRect( QRect( pt, pt1 ), KOPrefs::instance()->mHighlightColor ); + // draw all other days between the start day and the day of the selection end + for ( int c = mSelectionStartCell.x() + 1; c < mSelectionEndCell.x(); ++c ) { + pt = gridToContents( QPoint( c, 0 ) ); + pt1 = gridToContents( QPoint( c + 1, mRows + 1 ) ); + dbp.fillRect( QRect( pt, pt1 ), KOPrefs::instance()->mHighlightColor ); + } + // draw end day + pt = gridToContents( QPoint( mSelectionEndCell.x(), 0 ) ); + pt1 = gridToContents( mSelectionEndCell + QPoint(1,1) ); + dbp.fillRect( QRect( pt, pt1), KOPrefs::instance()->mHighlightColor ); + } else { // single day selection + pt = gridToContents( mSelectionStartCell ); + pt1 = gridToContents( mSelectionEndCell + QPoint(1,1) ); + dbp.fillRect( QRect( pt, pt1 ), KOPrefs::instance()->mHighlightColor ); + } + } + + QPen hourPen( KOPrefs::instance()->mAgendaBgColor.dark( 150 ) ); + QPen halfHourPen( KOPrefs::instance()->mAgendaBgColor.dark( 125 ) ); + dbp.setPen( hourPen ); + + // Draw vertical lines of grid, start with the last line not yet visible + // kdDebug(5850) << "drawContents cx: " << cx << " cy: " << cy << " cw: " << cw << " ch: " << ch << endl; + double x = ( int( cx / mGridSpacingX ) ) * mGridSpacingX; + while (x < cx + cw) { + dbp.drawLine( int( x ), cy, int( x ), cy + ch ); + x+=mGridSpacingX; + } + + // Draw horizontal lines of grid + double y = ( int( cy / (2*lGridSpacingY) ) ) * 2 * lGridSpacingY; + while (y < cy + ch) { +// kdDebug(5850) << " y: " << y << endl; + dbp.drawLine( cx, int( y ), cx + cw, int( y ) ); + y += 2 * lGridSpacingY; + } + y = ( 2 * int( cy / (2*lGridSpacingY) ) + 1) * lGridSpacingY; + dbp.setPen( halfHourPen ); + while (y < cy + ch) { +// kdDebug(5850) << " y: " << y << endl; + dbp.drawLine( cx, int( y ), cx + cw, int( y ) ); + y+=2*lGridSpacingY; + } + p->drawPixmap(cx,cy, db); +} + +/* + Convert srcollview contents coordinates to agenda grid coordinates. +*/ +QPoint KOAgenda::contentsToGrid ( const QPoint &pos ) const +{ + int gx = int( KOGlobals::self()->reverseLayout() ? + mColumns - pos.x()/mGridSpacingX : pos.x()/mGridSpacingX ); + int gy = int( pos.y()/mGridSpacingY ); + return QPoint( gx, gy ); +} + +/* + Convert agenda grid coordinates to scrollview contents coordinates. +*/ +QPoint KOAgenda::gridToContents( const QPoint &gpos ) const +{ + int x = int( KOGlobals::self()->reverseLayout() ? + (mColumns - gpos.x())*mGridSpacingX : gpos.x()*mGridSpacingX ); + int y = int( gpos.y()*mGridSpacingY ); + return QPoint( x, y ); +} + + +/* + Return Y coordinate corresponding to time. Coordinates are rounded to fit into + the grid. +*/ +int KOAgenda::timeToY(const QTime &time) +{ +// kdDebug(5850) << "Time: " << time.toString() << endl; + int minutesPerCell = 24 * 60 / mRows; +// kdDebug(5850) << "minutesPerCell: " << minutesPerCell << endl; + int timeMinutes = time.hour() * 60 + time.minute(); +// kdDebug(5850) << "timeMinutes: " << timeMinutes << endl; + int Y = (timeMinutes + (minutesPerCell / 2)) / minutesPerCell; +// kdDebug(5850) << "y: " << Y << endl; +// kdDebug(5850) << "\n" << endl; + return Y; +} + + +/* + Return time corresponding to cell y coordinate. Coordinates are rounded to + fit into the grid. +*/ +QTime KOAgenda::gyToTime(int gy) +{ +// kdDebug(5850) << "gyToTime: " << gy << endl; + int secondsPerCell = 24 * 60 * 60/ mRows; + + int timeSeconds = secondsPerCell * gy; + + QTime time( 0, 0, 0 ); + if ( timeSeconds < 24 * 60 * 60 ) { + time = time.addSecs(timeSeconds); + } else { + time.setHMS( 23, 59, 59 ); + } +// kdDebug(5850) << " gyToTime: " << time.toString() << endl; + + return time; +} + +QMemArray<int> KOAgenda::minContentsY() +{ + QMemArray<int> minArray; + minArray.fill( timeToY( QTime(23, 59) ), mSelectedDates.count() ); + for ( KOAgendaItem *item = mItems.first(); + item != 0; item = mItems.next() ) { + int ymin = item->cellYTop(); + int index = item->cellXLeft(); + if ( index>=0 && index<(int)(mSelectedDates.count()) ) { + if ( ymin < minArray[index] && mItemsToDelete.findRef( item ) == -1 ) + minArray[index] = ymin; + } + } + + return minArray; +} + +QMemArray<int> KOAgenda::maxContentsY() +{ + QMemArray<int> maxArray; + maxArray.fill( timeToY( QTime(0, 0) ), mSelectedDates.count() ); + for ( KOAgendaItem *item = mItems.first(); + item != 0; item = mItems.next() ) { + int ymax = item->cellYBottom(); + int index = item->cellXLeft(); + if ( index>=0 && index<(int)(mSelectedDates.count()) ) { + if ( ymax > maxArray[index] && mItemsToDelete.findRef( item ) == -1 ) + maxArray[index] = ymax; + } + } + + return maxArray; +} + +void KOAgenda::setStartTime( const QTime &startHour ) +{ + double startPos = ( startHour.hour()/24. + startHour.minute()/1440. + + startHour.second()/86400. ) * mRows * gridSpacingY(); + setContentsPos( 0, int( startPos ) ); +} + + +/* + Insert KOAgendaItem into agenda. +*/ +KOAgendaItem *KOAgenda::insertItem( Incidence *incidence, const QDate &qd, int X, + int YTop, int YBottom ) +{ +#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() ); + connect( agendaItem, SIGNAL( removeAgendaItem( KOAgendaItem * ) ), + SLOT( removeAgendaItem( KOAgendaItem * ) ) ); + connect( agendaItem, SIGNAL( showAgendaItem( KOAgendaItem * ) ), + SLOT( showAgendaItem( KOAgendaItem * ) ) ); + + if ( YBottom <= YTop ) { + kdDebug(5850) << "KOAgenda::insertItem(): Text: " << agendaItem->text() << " YSize<0" << endl; + YBottom = YTop; + } + + agendaItem->resize( int( ( X + 1 ) * mGridSpacingX ) - + int( X * mGridSpacingX ), + int( YTop * mGridSpacingY ) - + int( ( YBottom + 1 ) * mGridSpacingY ) ); + agendaItem->setCellXY( X, YTop, YBottom ); + agendaItem->setCellXRight( X ); + agendaItem->setResourceColor( KOHelper::resourceColor( mCalendar, incidence ) ); + agendaItem->installEventFilter( this ); + + addChild( agendaItem, int( X * mGridSpacingX ), int( YTop * mGridSpacingY ) ); + mItems.append( agendaItem ); + + placeSubCells( agendaItem ); + + agendaItem->show(); + + marcus_bains(); + + return agendaItem; +} + +/* + Insert all-day KOAgendaItem into agenda. +*/ +KOAgendaItem *KOAgenda::insertAllDayItem( Incidence *event, const QDate &qd, + int XBegin, int XEnd ) +{ + if ( !mAllDayMode ) { + kdDebug(5850) << "KOAgenda: calling insertAllDayItem in non all-day mode is illegal." << endl; + return 0; + } + + mActionType = NOP; + + KOAgendaItem *agendaItem = new KOAgendaItem( event, qd, viewport() ); + connect( agendaItem, SIGNAL( removeAgendaItem( KOAgendaItem* ) ), + SLOT( removeAgendaItem( KOAgendaItem* ) ) ); + connect( agendaItem, SIGNAL( showAgendaItem( KOAgendaItem* ) ), + SLOT( showAgendaItem( KOAgendaItem* ) ) ); + + agendaItem->setCellXY( XBegin, 0, 0 ); + agendaItem->setCellXRight( XEnd ); + + double startIt = mGridSpacingX * ( agendaItem->cellXLeft() ); + double endIt = mGridSpacingX * ( agendaItem->cellWidth() + + agendaItem->cellXLeft() ); + + agendaItem->resize( int( endIt ) - int( startIt ), int( mGridSpacingY ) ); + + agendaItem->installEventFilter( this ); + agendaItem->setResourceColor( KOHelper::resourceColor( mCalendar, event ) ); + addChild( agendaItem, int( XBegin * mGridSpacingX ), 0 ); + mItems.append( agendaItem ); + + placeSubCells( agendaItem ); + + agendaItem->show(); + + return agendaItem; +} + + +void KOAgenda::insertMultiItem (Event *event,const QDate &qd,int XBegin,int XEnd, + int YTop,int YBottom) +{ + if (mAllDayMode) { + kdDebug(5850) << "KOAgenda: calling insertMultiItem in all-day mode is illegal." << endl; + return; + } + mActionType = NOP; + + int cellX,cellYTop,cellYBottom; + QString newtext; + int width = XEnd - XBegin + 1; + int count = 0; + KOAgendaItem *current = 0; + QPtrList<KOAgendaItem> multiItems; + 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; + newtext = QString("(%1/%2): ").arg( count ).arg( width ); + newtext.append( event->summary() ); + + current = insertItem( event, qd, cellX, cellYTop, cellYBottom ); + 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; + } + + marcus_bains(); +} + +void KOAgenda::removeIncidence( Incidence *incidence ) +{ + // First find all items to be deleted and store them + // in its own list. Otherwise removeAgendaItem will reset + // the current position and mess this up. + QPtrList<KOAgendaItem> itemsToRemove; + + KOAgendaItem *item = mItems.first(); + while ( item ) { + if ( item->incidence() == incidence ) { + itemsToRemove.append( item ); + } + item = mItems.next(); + } + item = itemsToRemove.first(); + while ( item ) { + removeAgendaItem( item ); + item = itemsToRemove.next(); + } +} + +void KOAgenda::showAgendaItem( KOAgendaItem *agendaItem ) +{ + if ( !agendaItem ) return; + agendaItem->hide(); + addChild( agendaItem ); + if ( !mItems.containsRef( agendaItem ) ) + mItems.append( agendaItem ); + placeSubCells( agendaItem ); + + agendaItem->show(); +} + +bool KOAgenda::removeAgendaItem( KOAgendaItem *item ) +{ + // we found the item. Let's remove it and update the conflicts + bool taken = false; + KOAgendaItem *thisItem = item; + QPtrList<KOAgendaItem> conflictItems = thisItem->conflictItems(); + removeChild( thisItem ); + int pos = mItems.find( thisItem ); + if ( pos>=0 ) { + mItems.take( pos ); + taken = true; + } + + KOAgendaItem *confitem; + for ( confitem = conflictItems.first(); confitem != 0; + confitem = conflictItems.next() ) { + // the item itself is also in its own conflictItems list! + if ( confitem != thisItem ) placeSubCells(confitem); + + } + mItemsToDelete.append( thisItem ); + QTimer::singleShot( 0, this, SLOT( deleteItemsToDelete() ) ); + return taken; +} + +void KOAgenda::deleteItemsToDelete() +{ + mItemsToDelete.clear(); +} + +/*QSizePolicy KOAgenda::sizePolicy() const +{ + // Thought this would make the all-day event agenda minimum size and the + // normal agenda take the remaining space. But it doesnt work. The QSplitter + // dont seem to think that an Expanding widget needs more space than a + // Preferred one. + // But it doesnt hurt, so it stays. + if (mAllDayMode) { + return QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred); + } else { + return QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); + } +} +*/ + +/* + Overridden from QScrollView to provide proper resizing of KOAgendaItems. +*/ +void KOAgenda::resizeEvent ( QResizeEvent *ev ) +{ +// kdDebug(5850) << "KOAgenda::resizeEvent" << endl; + + QSize newSize( ev->size() ); + if (mAllDayMode) { + mGridSpacingX = double( newSize.width() - 2 * frameWidth() ) / (double)mColumns; + mGridSpacingY = newSize.height() - 2 * frameWidth(); + } else { + int scrollbarWidth = vScrollBarMode() != AlwaysOff ? verticalScrollBar()->width() : 0; + mGridSpacingX = double( newSize.width() - scrollbarWidth - 2 * frameWidth()) / double(mColumns); + // make sure that there are not more than 24 per day + mGridSpacingY = double(newSize.height() - 2 * frameWidth()) / double(mRows); + if ( mGridSpacingY < mDesiredGridSpacingY ) + mGridSpacingY = mDesiredGridSpacingY; + } + calculateWorkingHours(); + QTimer::singleShot( 0, this, SLOT( resizeAllContents() ) ); + emit gridSpacingYChanged( mGridSpacingY * 4 ); + QScrollView::resizeEvent(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 ); + } + } + checkScrollBoundaries(); + marcus_bains(); +} + + +void KOAgenda::scrollUp() +{ + scrollBy(0,-mScrollOffset); +} + + +void KOAgenda::scrollDown() +{ + scrollBy(0,mScrollOffset); +} + + +/* + Calculates the minimum width +*/ +int KOAgenda::minimumWidth() const +{ + // FIXME:: develop a way to dynamically determine the minimum width + int min = 100; + + return min; +} + +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; + + //can be two doubles equal?, it's better to compare them with an epsilon + if ( fabs( oldGridSpacingY - mGridSpacingY ) > 0.1 ) + resizeContents( int( mGridSpacingX * mColumns ), + int( mGridSpacingY * mRows ) ); + + calculateWorkingHours(); + + marcus_bains(); +} + +void KOAgenda::checkScrollBoundaries() +{ + // Invalidate old values to force update + mOldLowerScrollValue = -1; + mOldUpperScrollValue = -1; + + checkScrollBoundaries(verticalScrollBar()->value()); +} + +void KOAgenda::checkScrollBoundaries( int v ) +{ + int yMin = int( (v) / mGridSpacingY ); + int yMax = int( ( v + visibleHeight() ) / mGridSpacingY ); + +// kdDebug(5850) << "--- yMin: " << yMin << " yMax: " << yMax << endl; + + if ( yMin != mOldLowerScrollValue ) { + mOldLowerScrollValue = yMin; + emit lowerYChanged(yMin); + } + if ( yMax != mOldUpperScrollValue ) { + mOldUpperScrollValue = yMax; + emit upperYChanged(yMax); + } +} + +int KOAgenda::visibleContentsYMin() +{ + int v = verticalScrollBar()->value(); + return int( v / mGridSpacingY ); +} + +int KOAgenda::visibleContentsYMax() +{ + int v = verticalScrollBar()->value(); + return int( ( v + visibleHeight() ) / mGridSpacingY ); +} + +void KOAgenda::deselectItem() +{ + if (mSelectedItem.isNull()) return; + mSelectedItem->select(false); + mSelectedItem = 0; +} + +void KOAgenda::selectItem(KOAgendaItem *item) +{ + if ((KOAgendaItem *)mSelectedItem == item) return; + deselectItem(); + if (item == 0) { + emit incidenceSelected( 0 ); + return; + } + mSelectedItem = item; + mSelectedItem->select(); + assert( mSelectedItem->incidence() ); + mSelectedUid = mSelectedItem->incidence()->uid(); + emit incidenceSelected( mSelectedItem->incidence() ); +} + +void KOAgenda::selectItemByUID( const QString& uid ) +{ + KOAgendaItem *item; + for ( item = mItems.first(); item != 0; item = mItems.next() ) { + if( item->incidence() && item->incidence()->uid() == uid ) { + selectItem( item ); + break; + } + } +} + +// This function seems never be called. +void KOAgenda::keyPressEvent( QKeyEvent *kev ) +{ + switch(kev->key()) { + case Key_PageDown: + verticalScrollBar()->addPage(); + break; + case Key_PageUp: + verticalScrollBar()->subtractPage(); + break; + case Key_Down: + verticalScrollBar()->addLine(); + break; + case Key_Up: + verticalScrollBar()->subtractLine(); + break; + default: + ; + } +} + +void KOAgenda::calculateWorkingHours() +{ + mWorkingHoursEnable = !mAllDayMode; + + QTime tmp = KOPrefs::instance()->mWorkingHoursStart.time(); + mWorkingHoursYTop = int( 4 * mGridSpacingY * + ( tmp.hour() + tmp.minute() / 60. + + tmp.second() / 3600. ) ); + tmp = KOPrefs::instance()->mWorkingHoursEnd.time(); + mWorkingHoursYBottom = int( 4 * mGridSpacingY * + ( tmp.hour() + tmp.minute() / 60. + + tmp.second() / 3600. ) - 1 ); +} + + +DateList KOAgenda::dateList() const +{ + return mSelectedDates; +} + +void KOAgenda::setDateList(const DateList &selectedDates) +{ + mSelectedDates = selectedDates; + marcus_bains(); +} + +void KOAgenda::setHolidayMask(QMemArray<bool> *mask) +{ + mHolidayMask = mask; + +} + +void KOAgenda::contentsMousePressEvent ( QMouseEvent *event ) +{ + kdDebug(5850) << "KOagenda::contentsMousePressEvent(): type: " << event->type() << endl; + QScrollView::contentsMousePressEvent(event); +} + +void KOAgenda::setTypeAheadReceiver( QObject *o ) +{ + mTypeAheadReceiver = o; +} + +QObject *KOAgenda::typeAheadReceiver() const +{ + return mTypeAheadReceiver; +} diff --git a/korganizer/koagenda.h b/korganizer/koagenda.h new file mode 100644 index 000000000..cec1b74d8 --- /dev/null +++ b/korganizer/koagenda.h @@ -0,0 +1,378 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOAGENDA_H +#define KOAGENDA_H + +#include <qscrollview.h> +#include <qtimer.h> +#include <qguardedptr.h> +#include <libkcal/incidencebase.h> + + +class QPopupMenu; +class QTime; +class QLabel; +class KConfig; +class KOAgenda; +class KOAgendaItem; + +using namespace KOrg; +namespace KOrg { +class IncidenceChangerBase; +} + +using namespace KCal; +namespace KCal { +class Event; +class Todo; +class Calendar; +} + +class MarcusBains : public QFrame { + Q_OBJECT + public: + MarcusBains( KOAgenda *agenda = 0, const char *name = 0 ); + virtual ~MarcusBains(); + + public slots: + void updateLocation( bool recalculate = false ); + + private: + int todayColumn(); + QTimer *minutes; + QLabel *mTimeBox; + KOAgenda *agenda; + QTime oldTime; + int oldToday; +}; + + +class KOAgenda : public QScrollView +{ + Q_OBJECT + public: + KOAgenda ( int columns, int rows, int columnSize, QWidget *parent=0, + const char *name = 0, WFlags f = 0 ); + KOAgenda ( int columns, QWidget *parent = 0, + const char *name = 0, WFlags f = 0 ); + virtual ~KOAgenda(); + + Incidence *selectedIncidence() const; + QDate selectedIncidenceDate() const; + /** + * Returns the uid of the last incidence that was selected. This + * persists across reloads and clear, so that if the same uid + * reappears, it can be reselected. */ + const QString lastSelectedUid() const; + + virtual bool eventFilter ( QObject *, QEvent * ); + + QPoint contentsToGrid ( const QPoint &pos ) const; + QPoint gridToContents ( const QPoint &gpos ) const; + + int timeToY ( const QTime &time ); + QTime gyToTime ( int y ); + + QMemArray<int> minContentsY(); + QMemArray<int> maxContentsY(); + + int visibleContentsYMin(); + int visibleContentsYMax(); + + void setStartTime( const QTime &startHour ); + + KOAgendaItem *insertItem ( Incidence *incidence, const QDate &qd, int X, int YTop, + int YBottom ); + KOAgendaItem *insertAllDayItem ( Incidence *event, const QDate &qd, int XBegin, + int XEnd ); + void insertMultiItem ( Event *event, const QDate &qd, int XBegin, int XEnd, + int YTop, int YBottom ); + + /** remove an event and all its multi-items from the agenda. + * This function removes the items from the view, but doesn't delete them immediately. + * Instead, they are queued in mItemsToDelete and later deleted by + * the slot deleteItemsToDelete() (called by QTimer::singleShot ) */ + void removeIncidence( Incidence *incidence ); + + void changeColumns( int columns ); + + int columns() { return mColumns; } + int rows() { return mRows; } + + double gridSpacingX() const { return mGridSpacingX; } + double gridSpacingY() const { return mGridSpacingY; } + +// virtual QSizePolicy sizePolicy() const; + + void clear(); + + /** Calculates the minimum width */ + virtual int minimumWidth() const; + /** Update configuration from preference settings */ + void updateConfig(); + + void checkScrollBoundaries(); + + void setHolidayMask( QMemArray<bool> * ); + + void setDateList( const DateList &selectedDates ); + DateList dateList() const; + + void setTypeAheadReceiver( QObject * ); + QObject *typeAheadReceiver() const; + void finishTypeAhead(); + + void setCalendar( Calendar*cal ) { mCalendar = cal; } + void setIncidenceChanger( IncidenceChangerBase *changer ) { mChanger = changer; } + + public slots: + void scrollUp(); + void scrollDown(); + + void checkScrollBoundaries( int ); + + /** Deselect selected items. This function does not emit any signals. */ + void deselectItem(); + + void clearSelection(); + + /** + Select item. If the argument is 0, the currently selected item gets + deselected. This function emits the itemSelected(bool) signal to inform + about selection/deselection of events. + */ + void selectItem( KOAgendaItem * ); + /** + Select the item associated with a given uid. Linear search, use carefully. + */ + void selectItemByUID( const QString& uid ); + bool removeAgendaItem( KOAgendaItem *item ); + void showAgendaItem( KOAgendaItem *item ); + + signals: + void newEventSignal(); + void newTimeSpanSignal( const QPoint &, const QPoint & ); + void newStartSelectSignal(); + + void showIncidenceSignal( Incidence * ); + void editIncidenceSignal( Incidence * ); + void deleteIncidenceSignal( Incidence * ); + void showIncidencePopupSignal( Incidence *, const QDate &); + void showNewEventPopupSignal(); + + void itemModified( KOAgendaItem *item ); + void incidenceSelected( Incidence * ); + void startMultiModify( const QString & ); + void endMultiModify(); + + void lowerYChanged( int ); + void upperYChanged( int ); + + void startDragSignal(Incidence *); + void droppedToDo( Todo*todo, const QPoint &gpos, bool allDay ); + + void enableAgendaUpdate( bool enable ); + void zoomView( const int delta, const QPoint &pos, const Qt::Orientation ); + + void mousePosSignal(const QPoint &pos); + void enterAgenda(); + void leaveAgenda(); + + void gridSpacingYChanged( double ); + + private: + enum MouseActionType { NOP, MOVE, SELECT, + RESIZETOP, RESIZEBOTTOM, RESIZELEFT, RESIZERIGHT }; + + protected: + void drawContents( QPainter *p, int cx, int cy, int cw, int ch ); + int columnWidth( int column ); + virtual void resizeEvent ( QResizeEvent * ); + + /** Handles mouse events. Called from eventFilter */ + virtual bool eventFilter_mouse ( QObject *, QMouseEvent * ); +#ifndef QT_NO_WHEELEVENT + /** Handles mousewheel events. Called from eventFilter */ + virtual bool eventFilter_wheel ( QObject *, QWheelEvent * ); +#endif + /** Handles key events. Called from eventFilter */ + virtual bool eventFilter_key ( QObject *, QKeyEvent * ); + + /** Handles drag and drop events. Called from eventFilter */ + virtual bool eventFilter_drag( QObject *, QDropEvent * ); + + /** returns RESIZELEFT if pos is near the lower edge of the action item, + RESIZERIGHT if pos is near the higher edge, and MOVE otherwise. + If --reverse is used, RESIZELEFT still means resizing the beginning of + the event, although that means moving to the right! + horizontal is the same as mAllDayAgenda. + */ + MouseActionType isInResizeArea( bool horizontal, const QPoint &pos, KOAgendaItem *item ); + /** Return whether the cell specified by the grid point belongs to the current select + */ + bool ptInSelection( QPoint gpos ) const; + + + /** Start selecting time span. */ + void startSelectAction( const QPoint &viewportPos ); + + /** Select time span. */ + void performSelectAction( const QPoint &viewportPos ); + + /** Emd selecting time span. */ + void endSelectAction( const QPoint &viewportPos ); + + /** Start moving/resizing agenda item */ + void startItemAction(const QPoint& viewportPos); + + /** Move/resize agenda item */ + void performItemAction(const QPoint& viewportPos); + + /** End moving/resizing agenda item */ + void endItemAction(); + + /** Set cursor, when no item action is in progress */ + void setNoActionCursor( KOAgendaItem *moveItem, const QPoint &viewportPos ); + /** Sets the cursor according to the given action type. If acting==true, + the corresponding action is running (i.e. the item is really moved). If + acting==false the cursor should just indicate that the corresponding action + is possible */ + void setActionCursor( int actionType, bool acting=false ); + + /** calculate the width of the column subcells of the given item */ + double calcSubCellWidth( KOAgendaItem *item ); + /** Move and resize the given item to the correct position */ + void placeAgendaItem( KOAgendaItem *item, double subCellWidth ); + /** Place agenda item in agenda and adjust other cells if necessary */ + void placeSubCells( KOAgendaItem *placeItem ); + /** Place the agenda item at the correct position (ignoring conflicting items) */ + void adjustItemPosition( KOAgendaItem *item ); + + /** Process the keyevent, including the ignored keyevents of eventwidgets. + * Implements pgup/pgdn and cursor key navigation in the view. + */ + void keyPressEvent( QKeyEvent * ); + + void calculateWorkingHours(); + + virtual void contentsMousePressEvent ( QMouseEvent * ); + + void emitNewEventForSelection(); + + protected slots: + /** delete the items that are queued for deletion */ + void deleteItemsToDelete(); + /** Resizes all the child elements after the size of the agenda + changed. This is needed because Qt seems to have a bug when + the resizeEvent of one of the widgets in a splitter takes a + lot of time / does a lot of resizes.... see bug 80114 */ + void resizeAllContents(); + + private: + void init(); + void marcus_bains(); + bool mAllDayMode; + + // We need the calendar for drag'n'drop and for paint the ResourceColor + Calendar *mCalendar; + + // Width and height of agenda cells. mDesiredGridSpacingY is the height + // set in the config. The actual height might be larger since otherwise + // more than 24 hours might be displayed. + double mGridSpacingX; + double mGridSpacingY; + double mDesiredGridSpacingY; + + // size of border, where mouse action will resize the KOAgendaItem + int mResizeBorderWidth; + + // size of border, where mouse mve will cause a scroll of the agenda + int mScrollBorderWidth; + int mScrollDelay; + int mScrollOffset; + + QTimer mScrollUpTimer; + QTimer mScrollDownTimer; + + // Number of Columns/Rows of agenda grid + int mColumns; + int mRows; + + // Cells to store Move and Resize coordiantes while performing the action + QPoint mStartCell; + QPoint mEndCell; + + // Working Hour coordiantes + bool mWorkingHoursEnable; + QMemArray<bool> *mHolidayMask; + int mWorkingHoursYTop; + int mWorkingHoursYBottom; + + // Selection + bool mHasSelection; + QPoint mSelectionStartPoint; + QPoint mSelectionStartCell; + QPoint mSelectionEndCell; + + // List of dates to be displayed + DateList mSelectedDates; + + // The KOAgendaItem, which has been right-clicked last + QGuardedPtr<KOAgendaItem> mClickedItem; + + // The KOAgendaItem, which is being moved/resized + QGuardedPtr<KOAgendaItem> mActionItem; + + // Currently selected item + QGuardedPtr<KOAgendaItem> mSelectedItem; + // Uid of the last selected item. Used for reselecting in situations + // where the selected item points to a no longer valid incidence, for + // example during resource reload. + QString mSelectedUid; + + // The Marcus Bains Line widget. + MarcusBains *mMarcusBains; + + MouseActionType mActionType; + + bool mItemMoved; + + // List of all Items contained in agenda + QPtrList<KOAgendaItem> mItems; + QPtrList<KOAgendaItem> mItemsToDelete; + + QPopupMenu *mItemPopup; // Right mouse button popup menu for KOAgendaItems + + int mOldLowerScrollValue; + int mOldUpperScrollValue; + + bool mTypeAhead; + QObject *mTypeAheadReceiver; + QPtrList<QEvent> mTypeAheadEvents; + + bool mReturnPressed; + KOrg::IncidenceChangerBase *mChanger; +}; + +#endif // KOAGENDA_H diff --git a/korganizer/koagendaitem.cpp b/korganizer/koagendaitem.cpp new file mode 100644 index 000000000..34d851a7f --- /dev/null +++ b/korganizer/koagendaitem.cpp @@ -0,0 +1,975 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2000,2001,2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qtooltip.h> +#include <qdragobject.h> +#include <qpainter.h> + +#include <kiconloader.h> +#include <kdebug.h> +#include <klocale.h> +#include <kwordwrap.h> +#include <kmessagebox.h> + +#include <libkcal/icaldrag.h> +#include <libkcal/vcaldrag.h> +#include <libkdepim/kvcarddrag.h> +#include <libemailfunctions/email.h> +#ifndef KORG_NOKABC +#include <kabc/addressee.h> +#include <kabc/vcardconverter.h> +#endif + +#include "koprefs.h" +#include "koglobals.h" + +#include "koincidencetooltip.h" +#include "koagendaitem.h" +#include "koagendaitem.moc" + +//-------------------------------------------------------------------------- + +QToolTipGroup *KOAgendaItem::mToolTipGroup = 0; + +QPixmap *KOAgendaItem::alarmPxmp = 0; +QPixmap *KOAgendaItem::recurPxmp = 0; +QPixmap *KOAgendaItem::readonlyPxmp = 0; +QPixmap *KOAgendaItem::replyPxmp = 0; +QPixmap *KOAgendaItem::groupPxmp = 0; +QPixmap *KOAgendaItem::groupPxmpTentative = 0; +QPixmap *KOAgendaItem::organizerPxmp = 0; + +//-------------------------------------------------------------------------- + +KOAgendaItem::KOAgendaItem( Incidence *incidence, const QDate &qd, QWidget *parent, + const char *name, WFlags f ) : + QWidget( parent, name, f ), mIncidence( incidence ), mDate( qd ), + mLabelText( mIncidence->summary() ), mIconAlarm( false ), + mIconRecur( false ), mIconReadonly( false ), mIconReply( false ), + mIconGroup( false ), mIconGroupTentative( false ), mIconOrganizer( false ), + mMultiItemInfo( 0 ), mStartMoveInfo( 0 ) +{ + setBackgroundMode( Qt::NoBackground ); + + setCellXY( 0, 0, 1 ); + setCellXRight( 0 ); + setMouseTracking( true ); + mResourceColor = QColor(); + updateIcons(); + + // select() does nothing, if state hasn't change, so preset mSelected. + mSelected = true; + select( false ); + + KOIncidenceToolTip::add( this, incidence, toolTipGroup() ); + setAcceptDrops( true ); +} + +void KOAgendaItem::updateIcons() +{ + if ( !mIncidence ) return; + mIconReadonly = mIncidence->isReadOnly(); + mIconRecur = mIncidence->doesRecur(); + mIconAlarm = mIncidence->isAlarmEnabled(); + if ( mIncidence->attendeeCount() > 0 ) { + if ( KOPrefs::instance()->thatIsMe( mIncidence->organizer().email() ) ) { + mIconReply = false; + mIconGroup = false; + mIconGroupTentative = false; + mIconOrganizer = true; + } else { + Attendee *me = mIncidence->attendeeByMails( KOPrefs::instance()->allEmails() ); + if ( me ) { + if ( me->status() == Attendee::NeedsAction && me->RSVP() ) { + mIconReply = true; + mIconGroup = false; + mIconGroupTentative = false; + mIconOrganizer = false; + } else if ( me->status() == Attendee::Tentative ) { + mIconReply = false; + mIconGroup = false; + mIconGroupTentative = true; + mIconOrganizer = false; + } else { + mIconReply = false; + mIconGroup = true; + mIconGroupTentative = false; + mIconOrganizer = false; + } + } else { + mIconReply = false; + mIconGroup = true; + mIconGroupTentative = false; + mIconOrganizer = false; + } + } + } + update(); +} + + +void KOAgendaItem::select( bool selected ) +{ + if ( mSelected == selected ) return; + mSelected = selected; + + update(); +} + +bool KOAgendaItem::dissociateFromMultiItem() +{ + if ( !isMultiItem() ) return false; + KOAgendaItem *firstItem = firstMultiItem(); + if ( firstItem == this ) firstItem = nextMultiItem(); + KOAgendaItem *lastItem = lastMultiItem(); + if ( lastItem == this ) lastItem = prevMultiItem(); + + KOAgendaItem *prevItem = prevMultiItem(); + KOAgendaItem *nextItem = nextMultiItem(); + + if ( prevItem ) { + prevItem->setMultiItem( firstItem, + prevItem->prevMultiItem(), + nextItem, lastItem ); + } + if ( nextItem ) { + nextItem->setMultiItem( firstItem, prevItem, + nextItem->prevMultiItem(), + lastItem ); + } + delete mMultiItemInfo; + mMultiItemInfo = 0; + return true; +} + +bool KOAgendaItem::setIncidence( Incidence *i ) +{ + mIncidence = i; + updateIcons(); + return true; +} + + +/* + Return height of item in units of agenda cells +*/ +int KOAgendaItem::cellHeight() const +{ + return mCellYBottom - mCellYTop + 1; +} + +/* + Return height of item in units of agenda cells +*/ +int KOAgendaItem::cellWidth() const +{ + return mCellXRight - mCellXLeft + 1; +} + +void KOAgendaItem::setItemDate( const QDate &qd ) +{ + mDate = qd; +} + +void KOAgendaItem::setCellXY( int X, int YTop, int YBottom ) +{ + mCellXLeft = X; + mCellYTop = YTop; + mCellYBottom = YBottom; +} + +void KOAgendaItem::setCellXRight( int xright ) +{ + mCellXRight = xright; +} + +void KOAgendaItem::setCellX( int XLeft, int XRight ) +{ + mCellXLeft = XLeft; + mCellXRight = XRight; +} + +void KOAgendaItem::setCellY( int YTop, int YBottom ) +{ + mCellYTop = YTop; + mCellYBottom = YBottom; +} + +void KOAgendaItem::setMultiItem(KOAgendaItem *first, KOAgendaItem *prev, + KOAgendaItem *next, KOAgendaItem *last) +{ + if (!mMultiItemInfo) mMultiItemInfo=new MultiItemInfo; + mMultiItemInfo->mFirstMultiItem = first; + mMultiItemInfo->mPrevMultiItem = prev; + mMultiItemInfo->mNextMultiItem = next; + mMultiItemInfo->mLastMultiItem = last; +} +bool KOAgendaItem::isMultiItem() +{ + return mMultiItemInfo; +} +KOAgendaItem* KOAgendaItem::prependMoveItem(KOAgendaItem* e) +{ + if (!e) return e; + + KOAgendaItem*first=0, *last=0; + if (isMultiItem()) { + first=mMultiItemInfo->mFirstMultiItem; + last=mMultiItemInfo->mLastMultiItem; + } + if (!first) first=this; + if (!last) last=this; + + e->setMultiItem(0, 0, first, last); + first->setMultiItem(e, e, first->nextMultiItem(), first->lastMultiItem() ); + + KOAgendaItem*tmp=first->nextMultiItem(); + while (tmp) { + tmp->setMultiItem( e, tmp->prevMultiItem(), tmp->nextMultiItem(), tmp->lastMultiItem() ); + tmp = tmp->nextMultiItem(); + } + + if ( mStartMoveInfo && !e->moveInfo() ) { + e->mStartMoveInfo=new MultiItemInfo( *mStartMoveInfo ); +// e->moveInfo()->mFirstMultiItem = moveInfo()->mFirstMultiItem; +// e->moveInfo()->mLastMultiItem = moveInfo()->mLastMultiItem; + e->moveInfo()->mPrevMultiItem = 0; + e->moveInfo()->mNextMultiItem = first; + } + + if (first && first->moveInfo()) { + first->moveInfo()->mPrevMultiItem = e; + } + return e; +} + +KOAgendaItem* KOAgendaItem::appendMoveItem(KOAgendaItem* e) +{ + if (!e) return e; + + KOAgendaItem*first=0, *last=0; + if (isMultiItem()) { + first=mMultiItemInfo->mFirstMultiItem; + last=mMultiItemInfo->mLastMultiItem; + } + if (!first) first=this; + if (!last) last=this; + + e->setMultiItem( first, last, 0, 0 ); + KOAgendaItem*tmp=first; + + while (tmp) { + tmp->setMultiItem(tmp->firstMultiItem(), tmp->prevMultiItem(), tmp->nextMultiItem(), e); + tmp = tmp->nextMultiItem(); + } + last->setMultiItem( last->firstMultiItem(), last->prevMultiItem(), e, e); + + if ( mStartMoveInfo && !e->moveInfo() ) { + e->mStartMoveInfo=new MultiItemInfo( *mStartMoveInfo ); +// e->moveInfo()->mFirstMultiItem = moveInfo()->mFirstMultiItem; +// e->moveInfo()->mLastMultiItem = moveInfo()->mLastMultiItem; + e->moveInfo()->mPrevMultiItem = last; + e->moveInfo()->mNextMultiItem = 0; + } + if (last && last->moveInfo()) { + last->moveInfo()->mNextMultiItem = e; + } + return e; +} + +KOAgendaItem* KOAgendaItem::removeMoveItem(KOAgendaItem* e) +{ + if (isMultiItem()) { + KOAgendaItem *first = mMultiItemInfo->mFirstMultiItem; + KOAgendaItem *next, *prev; + KOAgendaItem *last = mMultiItemInfo->mLastMultiItem; + if (!first) first = this; + if (!last) last = this; + if ( first==e ) { + first = first->nextMultiItem(); + first->setMultiItem( 0, 0, first->nextMultiItem(), first->lastMultiItem() ); + } + if ( last==e ) { + last=last->prevMultiItem(); + last->setMultiItem( last->firstMultiItem(), last->prevMultiItem(), 0, 0 ); + } + + KOAgendaItem *tmp = first; + if ( first==last ) { + delete mMultiItemInfo; + tmp = 0; + mMultiItemInfo = 0; + } + while ( tmp ) { + next = tmp->nextMultiItem(); + prev = tmp->prevMultiItem(); + if ( e==next ) { + next = next->nextMultiItem(); + } + if ( e==prev ) { + prev = prev->prevMultiItem(); + } + tmp->setMultiItem((tmp==first)?0:first, (tmp==prev)?0:prev, (tmp==next)?0:next, (tmp==last)?0:last); + tmp = tmp->nextMultiItem(); + } + } + + return e; +} + + +void KOAgendaItem::startMove() +{ + KOAgendaItem* first = this; + if ( isMultiItem() && mMultiItemInfo->mFirstMultiItem ) { + first=mMultiItemInfo->mFirstMultiItem; + } + first->startMovePrivate(); +} + +void KOAgendaItem::startMovePrivate() +{ + mStartMoveInfo = new MultiItemInfo; + mStartMoveInfo->mStartCellXLeft = mCellXLeft; + mStartMoveInfo->mStartCellXRight = mCellXRight; + mStartMoveInfo->mStartCellYTop = mCellYTop; + mStartMoveInfo->mStartCellYBottom = mCellYBottom; + if (mMultiItemInfo) { + mStartMoveInfo->mFirstMultiItem = mMultiItemInfo->mFirstMultiItem; + mStartMoveInfo->mLastMultiItem = mMultiItemInfo->mLastMultiItem; + mStartMoveInfo->mPrevMultiItem = mMultiItemInfo->mPrevMultiItem; + mStartMoveInfo->mNextMultiItem = mMultiItemInfo->mNextMultiItem; + } else { + mStartMoveInfo->mFirstMultiItem = 0; + mStartMoveInfo->mLastMultiItem = 0; + mStartMoveInfo->mPrevMultiItem = 0; + mStartMoveInfo->mNextMultiItem = 0; + } + if ( isMultiItem() && mMultiItemInfo->mNextMultiItem ) + { + mMultiItemInfo->mNextMultiItem->startMovePrivate(); + } +} + +void KOAgendaItem::resetMove() +{ + if ( mStartMoveInfo ) { + if ( mStartMoveInfo->mFirstMultiItem ) { + mStartMoveInfo->mFirstMultiItem->resetMovePrivate(); + } else { + resetMovePrivate(); + } + } +} + +void KOAgendaItem::resetMovePrivate() +{ + if (mStartMoveInfo) { + mCellXLeft = mStartMoveInfo->mStartCellXLeft; + mCellXRight = mStartMoveInfo->mStartCellXRight; + mCellYTop = mStartMoveInfo->mStartCellYTop; + mCellYBottom = mStartMoveInfo->mStartCellYBottom; + + // if we don't have mMultiItemInfo, the item didn't span two days before, + // and wasn't moved over midnight, either, so we don't have to reset + // anything. Otherwise, restore from mMoveItemInfo + if ( mMultiItemInfo ) { + // It was already a multi-day info + mMultiItemInfo->mFirstMultiItem = mStartMoveInfo->mFirstMultiItem; + mMultiItemInfo->mPrevMultiItem = mStartMoveInfo->mPrevMultiItem; + mMultiItemInfo->mNextMultiItem = mStartMoveInfo->mNextMultiItem; + mMultiItemInfo->mLastMultiItem = mStartMoveInfo->mLastMultiItem; + + if ( !mStartMoveInfo->mFirstMultiItem ) { + // This was the first multi-item when the move started, delete all previous + KOAgendaItem*toDel=mStartMoveInfo->mPrevMultiItem; + KOAgendaItem*nowDel=0L; + while (toDel) { + nowDel=toDel; + if (nowDel->moveInfo()) { + toDel=nowDel->moveInfo()->mPrevMultiItem; + } + emit removeAgendaItem( nowDel ); + } + mMultiItemInfo->mFirstMultiItem = 0L; + mMultiItemInfo->mPrevMultiItem = 0L; + } + if ( !mStartMoveInfo->mLastMultiItem ) { + // This was the last multi-item when the move started, delete all next + KOAgendaItem*toDel=mStartMoveInfo->mNextMultiItem; + KOAgendaItem*nowDel=0L; + while (toDel) { + nowDel=toDel; + if (nowDel->moveInfo()) { + toDel=nowDel->moveInfo()->mNextMultiItem; + } + emit removeAgendaItem( nowDel ); + } + mMultiItemInfo->mLastMultiItem = 0L; + mMultiItemInfo->mNextMultiItem = 0L; + } + + if ( mStartMoveInfo->mFirstMultiItem==0 && mStartMoveInfo->mLastMultiItem==0 ) { + // it was a single-day event before we started the move. + delete mMultiItemInfo; + mMultiItemInfo = 0; + } + } + delete mStartMoveInfo; + mStartMoveInfo = 0; + } + emit showAgendaItem( this ); + if ( nextMultiItem() ) { + nextMultiItem()->resetMovePrivate(); + } +} + +void KOAgendaItem::endMove() +{ + KOAgendaItem*first=firstMultiItem(); + if (!first) first=this; + first->endMovePrivate(); +} + +void KOAgendaItem::endMovePrivate() +{ + if ( mStartMoveInfo ) { + // if first, delete all previous + if ( !firstMultiItem() || firstMultiItem()==this ) { + KOAgendaItem*toDel=mStartMoveInfo->mPrevMultiItem; + KOAgendaItem*nowDel = 0; + while (toDel) { + nowDel=toDel; + if (nowDel->moveInfo()) { + toDel=nowDel->moveInfo()->mPrevMultiItem; + } + emit removeAgendaItem( nowDel ); + } + } + // if last, delete all next + if ( !lastMultiItem() || lastMultiItem()==this ) { + KOAgendaItem*toDel=mStartMoveInfo->mNextMultiItem; + KOAgendaItem*nowDel = 0; + while (toDel) { + nowDel=toDel; + if (nowDel->moveInfo()) { + toDel=nowDel->moveInfo()->mNextMultiItem; + } + emit removeAgendaItem( nowDel ); + } + } + // also delete the moving info + delete mStartMoveInfo; + mStartMoveInfo=0; + if ( nextMultiItem() ) + nextMultiItem()->endMovePrivate(); + } +} + +void KOAgendaItem::moveRelative(int dx, int dy) +{ + int newXLeft = cellXLeft() + dx; + int newXRight = cellXRight() + dx; + int newYTop = cellYTop() + dy; + int newYBottom = cellYBottom() + dy; + setCellXY(newXLeft,newYTop,newYBottom); + setCellXRight(newXRight); +} + +void KOAgendaItem::expandTop(int dy) +{ + int newYTop = cellYTop() + dy; + int newYBottom = cellYBottom(); + if (newYTop > newYBottom) newYTop = newYBottom; + setCellY(newYTop, newYBottom); +} + +void KOAgendaItem::expandBottom(int dy) +{ + int newYTop = cellYTop(); + int newYBottom = cellYBottom() + dy; + if (newYBottom < newYTop) newYBottom = newYTop; + setCellY(newYTop, newYBottom); +} + +void KOAgendaItem::expandLeft(int dx) +{ + int newXLeft = cellXLeft() + dx; + int newXRight = cellXRight(); + if ( newXLeft > newXRight ) newXLeft = newXRight; + setCellX( newXLeft, newXRight ); +} + +void KOAgendaItem::expandRight(int dx) +{ + int newXLeft = cellXLeft(); + int newXRight = cellXRight() + dx; + if ( newXRight < newXLeft ) newXRight = newXLeft; + setCellX( newXLeft, newXRight ); +} + +QToolTipGroup *KOAgendaItem::toolTipGroup() +{ + if (!mToolTipGroup) mToolTipGroup = new QToolTipGroup(0); + return mToolTipGroup; +} + +void KOAgendaItem::dragEnterEvent( QDragEnterEvent *e ) +{ +#ifndef KORG_NODND + if ( ICalDrag::canDecode( e ) || VCalDrag::canDecode( e ) ) { + e->ignore(); + return; + } + if ( KVCardDrag::canDecode( e ) || QTextDrag::canDecode( e ) ) + e->accept(); + else + e->ignore(); +#endif +} + +void KOAgendaItem::addAttendee( const QString &newAttendee ) +{ + kdDebug(5850) << " Email: " << newAttendee << endl; + QString name, email; + KPIM::getNameAndMail( newAttendee, name, email ); + if ( !( name.isEmpty() && email.isEmpty() ) ) { + mIncidence->addAttendee(new Attendee(name,email)); + KMessageBox::information( this, i18n("Attendee \"%1\" added to the calendar item \"%2\"").arg(KPIM::normalizedAddress(name, email, QString())).arg(text()), i18n("Attendee added"), "AttendeeDroppedAdded" ); + } + +} + +void KOAgendaItem::dropEvent( QDropEvent *e ) +{ + // TODO: Organize this better: First check for attachment (not only file, also any other url!), then if it's a vcard, otherwise check for attendees, then if the data is binary, add a binary attachment. +#ifndef KORG_NODND + QString text; + + bool decoded = QTextDrag::decode( e, text ); + if( decoded && text.startsWith( "file:" ) ) { + mIncidence->addAttachment( new Attachment( text ) ); + return; + } + +#ifndef KORG_NOKABC + QString 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 ) { + QString em( (*it).fullEmail() ); + if (em.isEmpty()) { + em=(*it).realName(); + } + addAttendee( em ); + } +#else + if( decoded ) { + kdDebug(5850) << "Dropped : " << text << endl; + + QStringList emails = QStringList::split( ",", text ); + for( QStringList::ConstIterator it = emails.begin(); it != emails.end(); + ++it ) { + addAttendee( *it ); + } + } +#endif // KORG_NOKABC + +#endif // KORG_NODND +} + + +QPtrList<KOAgendaItem> KOAgendaItem::conflictItems() +{ + return mConflictItems; +} + +void KOAgendaItem::setConflictItems( QPtrList<KOAgendaItem> ci ) +{ + mConflictItems = ci; + KOAgendaItem *item; + for ( item = mConflictItems.first(); item != 0; + item = mConflictItems.next() ) { + item->addConflictItem( this ); + } +} + +void KOAgendaItem::addConflictItem( KOAgendaItem *ci ) +{ + if ( mConflictItems.find( ci ) < 0 ) mConflictItems.append( ci ); +} + +QString KOAgendaItem::label() const +{ + return mLabelText; +} + +bool KOAgendaItem::overlaps( KOrg::CellItem *o ) const +{ + KOAgendaItem *other = static_cast<KOAgendaItem *>( o ); + + if ( cellXLeft() <= other->cellXRight() && + cellXRight() >= other->cellXLeft() ) { + if ( ( cellYTop() <= other->cellYBottom() ) && + ( cellYBottom() >= other->cellYTop() ) ) { + return true; + } + } + + return false; +} + +void KOAgendaItem::paintFrame( QPainter *p, const QColor &color ) +{ + QColor oldpen(p->pen().color()); + p->setPen( color ); + p->drawRect( 0, 0, width(), height() ); + p->drawRect( 1, 1, width() - 2, height() - 2 ); + p->setPen( oldpen ); +} + +static void conditionalPaint( QPainter *p, bool cond, int &x, int ft, + const QPixmap &pxmp ) +{ + if ( !cond ) return; + + p->drawPixmap( x, ft, pxmp ); + x += pxmp.width() + ft; +} + +void KOAgendaItem::paintEventIcon( QPainter *p, int &x, int ft ) +{ + if ( !mIncidence ) return; + static const QPixmap eventPxmp = + KOGlobals::self()->smallIcon( "appointment" ); + if ( mIncidence->type() != "Event" ) + return; + conditionalPaint( p, true, x, ft, eventPxmp ); +} + +void KOAgendaItem::paintTodoIcon( QPainter *p, int &x, int ft ) +{ + if ( !mIncidence ) return; + static const QPixmap todoPxmp = + KOGlobals::self()->smallIcon( "todo" ); + static const QPixmap completedPxmp = + KOGlobals::self()->smallIcon( "checkedbox" ); + if ( mIncidence->type() != "Todo" ) + return; + bool b = ( static_cast<Todo *>( mIncidence ) )->isCompleted(); + conditionalPaint( p, !b, x, ft, todoPxmp ); + conditionalPaint( p, b, x, ft, completedPxmp ); +} + +void KOAgendaItem::paintAlarmIcon( QPainter *p, int &x, int ft ) +{ + if (!mIconAlarm) return; + int y = ft; + // if we can't fit it all, bottom align it, more or less, so + // it can be guessed better, visually + if ( visibleRect().height() - ft < alarmPxmp->height() ) + y -= ( alarmPxmp->height() - visibleRect().height() - ft ); + p->drawPixmap( x, y, *alarmPxmp ); + x += alarmPxmp->width() + ft; +} + +void KOAgendaItem::paintIcons( QPainter *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 ); + conditionalPaint( p, mIconReply, x, ft, *replyPxmp ); + conditionalPaint( p, mIconGroup, x, ft, *groupPxmp ); + conditionalPaint( p, mIconGroupTentative, x, ft, *groupPxmpTentative ); + conditionalPaint( p, mIconOrganizer, x, ft, *organizerPxmp ); +} + +void KOAgendaItem::paintEvent( QPaintEvent *ev ) +{ + //HACK + // to reproduce a crash: + // 1. start Kontact with the Calendar as the initial module + // 2. immediately select the summary (which must include appt and to-do) + // causes a crash for me every time in this method unless we make + // the following check + if ( !mIncidence )return; + + QRect visRect = visibleRect(); + // when scrolling horizontally in the side-by-side view, the repainted area is clipped + // to the newly visible area, which is a problem since the content changes when visRect + // changes, so repaint the full item in that case + if ( ev->rect() != visRect && visRect.isValid() && ev->rect().isValid() ) { + repaint( visRect ); + return; + } + + QPainter p( this ); + const int ft = 2; // frame thickness for layout, see paintFrame() + const int margin = 1 + ft; // frame + space between frame and content + + // General idea is to always show the icons (even in the all-day events). + // This creates a consistent fealing for the user when the view mode + // changes and therefore the available width changes. + // Also look at #17984 + + if ( !alarmPxmp ) { + alarmPxmp = new QPixmap( KOGlobals::self()->smallIcon("bell") ); + recurPxmp = new QPixmap( KOGlobals::self()->smallIcon("recur") ); + readonlyPxmp = new QPixmap( KOGlobals::self()->smallIcon("readonlyevent") ); + replyPxmp = new QPixmap( KOGlobals::self()->smallIcon("mail_reply") ); + groupPxmp = new QPixmap( KOGlobals::self()->smallIcon("groupevent") ); + groupPxmpTentative = new QPixmap( KOGlobals::self()->smallIcon("groupeventtentative") ); + organizerPxmp = new QPixmap( KOGlobals::self()->smallIcon("organizer") ); + } + + QColor bgColor; + if ( mIncidence->type() == "Todo" ) { + if ( static_cast<Todo*>(mIncidence)->isOverdue() ) + bgColor = KOPrefs::instance()->todoOverdueColor(); + else if ( static_cast<Todo*>(mIncidence)->dtDue().date() == + QDateTime::currentDateTime().date() ) + bgColor = KOPrefs::instance()->todoDueTodayColor(); + } + + QColor categoryColor; + QStringList categories = mIncidence->categories(); + QString cat = categories.first(); + if (cat.isEmpty()) + categoryColor = KOPrefs::instance()->mEventColor; + else + categoryColor = *(KOPrefs::instance()->categoryColor(cat)); + + QColor resourceColor = mResourceColor; + if ( !resourceColor.isValid() ) + resourceColor = categoryColor; + + if (!KOPrefs::instance()->hasCategoryColor(cat)) + categoryColor = resourceColor; + + QColor frameColor; + if ( KOPrefs::instance()->agendaViewColors() == KOPrefs::ResourceOnly || + KOPrefs::instance()->agendaViewColors() == KOPrefs::CategoryInsideResourceOutside ) { + frameColor = bgColor.isValid() ? bgColor : resourceColor; + } else { + frameColor = bgColor.isValid() ? bgColor : categoryColor; + } + + if ( !bgColor.isValid() ) { + if ( KOPrefs::instance()->agendaViewColors() == KOPrefs::ResourceOnly || + KOPrefs::instance()->agendaViewColors() == KOPrefs::ResourceInsideCategoryOutside ) { + bgColor = resourceColor; + } else { + bgColor = categoryColor; + } + } + + if ( mSelected ) { + frameColor = QColor( 85 + frameColor.red() * 2/3, + 85 + frameColor.green() * 2/3, + 85 + frameColor.blue() * 2/3 ); + } else { + frameColor = frameColor.dark( 115 ); + } + QColor textColor = getTextColor(bgColor); + p.setPen( textColor ); + p.setBackgroundColor( bgColor ); + p.setFont(KOPrefs::instance()->mAgendaViewFont); + QFontMetrics fm = p.fontMetrics(); + + int singleLineHeight = fm.boundingRect( mLabelText ).height(); + + p.eraseRect( 0, 0, width(), height() ); + paintFrame( &p, frameColor ); + + // calculate the height of the full version (case 4) to test whether it is + // possible + + QString shortH; + QString longH; + if ( !isMultiItem() ) { + shortH = KGlobal::locale()->formatTime(mIncidence->dtStart().time()); + if (mIncidence->type() != "Todo") + longH = i18n("%1 - %2").arg(shortH) + .arg(KGlobal::locale()->formatTime(mIncidence->dtEnd().time())); + else + longH = shortH; + } else if ( !mMultiItemInfo->mFirstMultiItem ) { + shortH = KGlobal::locale()->formatTime(mIncidence->dtStart().time()); + longH = shortH; + } else { + shortH = KGlobal::locale()->formatTime(mIncidence->dtEnd().time()); + longH = i18n("- %1").arg(shortH); + } + + KWordWrap *ww = KWordWrap::formatText( fm, + QRect(0, 0, width() - (2 * margin), -1), + 0, + mLabelText ); + int th = ww->boundingRect().height(); + delete ww; + + int hlHeight = QMAX(fm.boundingRect(longH).height(), + QMAX(alarmPxmp->height(), QMAX(recurPxmp->height(), + QMAX(readonlyPxmp->height(), QMAX(replyPxmp->height(), + QMAX(groupPxmp->height(), organizerPxmp->height())))))); + + bool completelyRenderable = th < (height() - 2 * ft - 2 - hlHeight); + + // case 1: do not draw text when not even a single line fits + // Don't do this any more, always try to print out the text. Even if + // it's just a few pixel, one can still guess the whole text from just four pixels' height! + if ( //( singleLineHeight > height()-4 ) || // ignore margin, be gentle.. Even ignore 2 pixel outside the item + ( width() < 16 ) ) { + int x = margin; + paintTodoIcon( &p, x, ft ); + return; + } + + // case 2: draw a single line when no more space + if ( (2 * singleLineHeight) > (height() - 2 * margin) ) { + int x = margin, txtWidth; + + if ( mIncidence->doesFloat() ) { + x += visRect.left(); + paintIcons( &p, x, ft ); + txtWidth = visRect.right() - margin - x; + } + else { + paintIcons( &p, x, ft ); + txtWidth = width() - margin - x; + } + + int y = ((height() - 2 * ft - singleLineHeight) / 2) + fm.ascent(); + KWordWrap::drawFadeoutText( &p, x, y, + txtWidth, mLabelText ); + return; + } + + // case 3: enough for 2-5 lines, but not for the header. + // Also used for the middle days in multi-events + if ( ((!completelyRenderable) && ((height() - (2 * margin)) <= (5 * singleLineHeight)) ) || + (isMultiItem() && mMultiItemInfo->mNextMultiItem && mMultiItemInfo->mFirstMultiItem) ) { + int x = margin, txtWidth; + + if ( mIncidence->doesFloat() ) { + x += visRect.left(); + paintIcons( &p, x, ft ); + txtWidth = visRect.right() - margin - x; + } + else { + paintIcons( &p, x, ft ); + txtWidth = width() - margin - x; + } + + ww = KWordWrap::formatText( fm, + QRect( 0, 0, txtWidth, + (height() - (2 * margin)) ), + 0, + mLabelText ); + + //kdDebug() << "SIZES for " << mLabelText << ": " << width() << " :: " << txtWidth << endl; + ww->drawText( &p, x, margin, Qt::AlignHCenter | KWordWrap::FadeOut ); + delete ww; + return; + } + + // case 4: paint everything, with header: + // consists of (vertically) ft + headline&icons + ft + text + margin + int y = 2 * ft + hlHeight; + if ( completelyRenderable ) + y += (height() - (2 * ft) - margin - hlHeight - th) / 2; + + int x = margin, txtWidth, hTxtWidth, eventX; + + if ( mIncidence->doesFloat() ) { + shortH = longH = ""; + + if ( (mIncidence->type() != "Todo") && + (mIncidence->dtStart() != mIncidence->dtEnd()) ) { // multi days + shortH = longH = + i18n("%1 - %2") + .arg(KGlobal::locale()->formatDate(mIncidence->dtStart().date())) + .arg(KGlobal::locale()->formatDate(mIncidence->dtEnd().date())); + + // paint headline + p.fillRect( 0, 0, width(), (ft/2) + margin + hlHeight, + QBrush( frameColor ) ); + } + + x += visRect.left(); + eventX = x; + txtWidth = visRect.right() - margin - x; + paintIcons( &p, x, ft ); + hTxtWidth = visRect.right() - margin - x; + } + else { + // paint headline + p.fillRect( 0, 0, width(), (ft/2) + margin + hlHeight, + QBrush( frameColor ) ); + + txtWidth = width() - margin - x; + eventX = x; + paintIcons( &p, x, ft ); + hTxtWidth = width() - margin - x; + } + + QString headline; + int hw = fm.boundingRect( longH ).width(); + if ( hw > hTxtWidth ) { + headline = shortH; + hw = fm.boundingRect( shortH ).width(); + if ( hw < txtWidth ) + x += (hTxtWidth - hw) / 2; + } else { + headline = longH; + x += (hTxtWidth - hw) / 2; + } + p.setBackgroundColor( frameColor ); + p.setPen( getTextColor( frameColor ) ); + KWordWrap::drawFadeoutText( &p, x, ft + fm.ascent(), hTxtWidth, headline ); + + // draw event text + ww = KWordWrap::formatText( fm, + QRect( 0, 0, txtWidth, height() - margin - y ), + 0, + mLabelText ); + + p.setBackgroundColor( bgColor ); + p.setPen( textColor ); + QString ws = ww->wrappedString(); + if ( ws.left( ws.length()-1 ).find( '\n' ) >= 0 ) + ww->drawText( &p, eventX, y, + Qt::AlignAuto | KWordWrap::FadeOut ); + else + ww->drawText( &p, eventX + (txtWidth-ww->boundingRect().width()-2*margin)/2, + y, Qt::AlignHCenter | KWordWrap::FadeOut ); + delete ww; +} + diff --git a/korganizer/koagendaitem.h b/korganizer/koagendaitem.h new file mode 100644 index 000000000..2595e9c98 --- /dev/null +++ b/korganizer/koagendaitem.h @@ -0,0 +1,208 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2000,2001,2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOAGENDAITEM_H +#define KOAGENDAITEM_H + +#include "cellitem.h" + +#include <qdatetime.h> + +class QToolTipGroup; +class QDragEnterEvent; +class QDropEvent; + +namespace KCal { +class Incidence; +} +using namespace KCal; +class KOAgendaItem; + +struct MultiItemInfo +{ + int mStartCellXLeft, mStartCellXRight; + int mStartCellYTop, mStartCellYBottom; + KOAgendaItem *mFirstMultiItem; + KOAgendaItem *mPrevMultiItem; + KOAgendaItem *mNextMultiItem; + KOAgendaItem *mLastMultiItem; +}; + +/* + The KOAgendaItem has to make sure that it receives all mouse events, which are + to be used for dragging and resizing. That means it has to be installed as + eventfiler for its children, if it has children, and it has to pass mouse + events from the cildren to itself. See eventFilter(). + + + Some comments on the movement of multi-day items: + Basically, the agenda items are arranged in two implicit double-linked lists. + The mMultiItemInfo works like before to describe the currently viewed + multi-item. + When moving, new events might need to be added to the beginning or the end of + the multi-item sequence, or events might need to be hidden. I cannot just + delete this items, since I have to restore/show them if the move is reset + (i.e. if a drag started). So internally, I keep another doubly-linked list + which is longer than the one defined by mMultiItemInfo, but includes the + multi-item sequence, too. + + The mStartMoveInfo stores the first and last item of the multi-item sequence + when the move started. The prev and next members of mStartMoveInfo are used + for that longer sequence including all (shown and hidden) items. +*/ +class KOAgendaItem : public QWidget, public KOrg::CellItem +{ + Q_OBJECT + public: + KOAgendaItem(Incidence *incidence, const QDate &qd, QWidget *parent, const char *name=0, + WFlags f=0 ); + + int cellXLeft() const { return mCellXLeft; } + int cellXRight() const { return mCellXRight; } + int cellYTop() const { return mCellYTop; } + int cellYBottom() const { return mCellYBottom; } + int cellHeight() const; + int cellWidth() const; + + void setCellXY(int X, int YTop, int YBottom); + void setCellY(int YTop, int YBottom); + void setCellX(int XLeft, int XRight); + void setCellXRight(int xright); + + /** Start movement */ + void startMove(); + /** Reset to original values */ + void resetMove(); + /** End the movement (i.e. clean up) */ + void endMove(); + + void moveRelative(int dx,int dy); + void expandTop(int dy); + void expandBottom(int dy); + void expandLeft(int dx); + void expandRight(int dx); + + bool isMultiItem(); + KOAgendaItem *prevMoveItem() const { return (mStartMoveInfo)?(mStartMoveInfo->mPrevMultiItem):0; } + KOAgendaItem *nextMoveItem() const { return (mStartMoveInfo)?(mStartMoveInfo->mNextMultiItem):0; } + MultiItemInfo *moveInfo() const { return mStartMoveInfo; } + void setMultiItem(KOAgendaItem *first,KOAgendaItem *prev, + KOAgendaItem *next, KOAgendaItem *last); + KOAgendaItem *prependMoveItem(KOAgendaItem*); + KOAgendaItem *appendMoveItem(KOAgendaItem*); + KOAgendaItem *removeMoveItem(KOAgendaItem*); + KOAgendaItem *firstMultiItem() const { return (mMultiItemInfo)?(mMultiItemInfo->mFirstMultiItem):0; } + KOAgendaItem *prevMultiItem() const { return (mMultiItemInfo)?(mMultiItemInfo->mPrevMultiItem):0; } + KOAgendaItem *nextMultiItem() const { return (mMultiItemInfo)?(mMultiItemInfo->mNextMultiItem):0; } + KOAgendaItem *lastMultiItem() const { return (mMultiItemInfo)?(mMultiItemInfo->mLastMultiItem):0; } + + bool dissociateFromMultiItem(); + + bool setIncidence( Incidence * ); + Incidence *incidence() const { return mIncidence; } + QDate itemDate() { return mDate; } + + /** Update the date of this item's occurrence (not in the event) */ + void setItemDate( const QDate &qd ); + + void setText ( const QString & text ) { mLabelText = text; } + QString text () { return mLabelText; } + + static QToolTipGroup *toolTipGroup(); + + QPtrList<KOAgendaItem> conflictItems(); + void setConflictItems(QPtrList<KOAgendaItem>); + void addConflictItem(KOAgendaItem *ci); + + QString label() const; + + bool overlaps( KOrg::CellItem * ) const; + + void setResourceColor( const QColor& color ) { mResourceColor = color; } + QColor resourceColor() {return mResourceColor;} + signals: + void removeAgendaItem( KOAgendaItem* ); + void showAgendaItem( KOAgendaItem* ); + + public slots: + void updateIcons(); + void select(bool=true); + void addAttendee( const QString & ); + + protected: + void dragEnterEvent(QDragEnterEvent *e); + void dropEvent(QDropEvent *e); + void paintEvent(QPaintEvent *e); + void paintFrame(QPainter *p, const QColor &color); + void paintEventIcon(QPainter *p, int &x, int ft); + void paintTodoIcon(QPainter *p, int &x, int ft); + void paintAlarmIcon(QPainter *p, int &x, int ft); + + // paint all visible icons + void paintIcons(QPainter *p, int &x, int ft); + + /** private movement functions. startMove needs to be called of only one of + * the multitems. it will then loop through the whole series using + * startMovePrivate. Same for resetMove and endMove */ + void startMovePrivate(); + void resetMovePrivate(); + void endMovePrivate(); + + + 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 + + Incidence *mIncidence; // corresponding event or todo + QDate mDate; //date this events occurs (for recurrence) + QString mLabelText; + bool mIconAlarm, mIconRecur, mIconReadonly; + bool mIconReply, mIconGroup, mIconGroupTentative; + bool mIconOrganizer; + + // Multi item pointers + MultiItemInfo* mMultiItemInfo; + protected: + // Variables to remember start position + MultiItemInfo* mStartMoveInfo; + //Color of the resource + QColor mResourceColor; + private: + static QToolTipGroup *mToolTipGroup; + + bool mSelected; + QPtrList<KOAgendaItem> mConflictItems; + + static QPixmap *alarmPxmp; + static QPixmap *recurPxmp; + static QPixmap *readonlyPxmp; + static QPixmap *replyPxmp; + static QPixmap *groupPxmp; + static QPixmap *groupPxmpTentative; + static QPixmap *organizerPxmp; +}; + +#endif diff --git a/korganizer/koagendaview.cpp b/korganizer/koagendaview.cpp new file mode 100644 index 000000000..a526760e5 --- /dev/null +++ b/korganizer/koagendaview.cpp @@ -0,0 +1,1618 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qhbox.h> +#include <qvbox.h> +#include <qlabel.h> +#include <qframe.h> +#include <qlayout.h> +#ifndef KORG_NOSPLITTER +#include <qsplitter.h> +#endif +#include <qfont.h> +#include <qfontmetrics.h> +#include <qpopupmenu.h> +#include <qtooltip.h> +#include <qpainter.h> +#include <qpushbutton.h> +#include <qcursor.h> +#include <qbitarray.h> + +#include <kapplication.h> +#include <kdebug.h> +#include <kstandarddirs.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kconfig.h> +#include <kglobal.h> +#include <kglobalsettings.h> +#include <kholidays.h> + +#include <libkcal/calendar.h> +#include <libkcal/icaldrag.h> +#include <libkcal/dndfactory.h> +#include <libkcal/calfilter.h> + +#include <kcalendarsystem.h> + +#include "koglobals.h" +#ifndef KORG_NOPLUGINS +#include "kocore.h" +#endif +#include "koprefs.h" +#include "koagenda.h" +#include "koagendaitem.h" +#include "timelabels.h" + +#include "koincidencetooltip.h" +#include "kogroupware.h" +#include "kodialogmanager.h" +#include "koeventpopupmenu.h" + +#include "koagendaview.h" +#include "koagendaview.moc" + +using namespace KOrg; + + +EventIndicator::EventIndicator(Location loc,QWidget *parent,const char *name) + : QFrame(parent,name) +{ + mColumns = 1; + mEnabled.resize( mColumns ); + mLocation = loc; + + if (mLocation == Top) mPixmap = KOGlobals::self()->smallIcon("upindicator"); + else mPixmap = KOGlobals::self()->smallIcon("downindicator"); + + setMinimumHeight(mPixmap.height()); +} + +EventIndicator::~EventIndicator() +{ +} + +void EventIndicator::drawContents(QPainter *p) +{ +// kdDebug(5850) << "======== top: " << contentsRect().top() << " bottom " +// << contentsRect().bottom() << " left " << contentsRect().left() +// << " right " << contentsRect().right() << endl; + + int i; + for(i=0;i<mColumns;++i) { + if (mEnabled[i]) { + int cellWidth = contentsRect().right()/mColumns; + int xOffset = KOGlobals::self()->reverseLayout() ? + (mColumns - 1 - i)*cellWidth + cellWidth/2 -mPixmap.width()/2 : + i*cellWidth + cellWidth/2 -mPixmap.width()/2; + p->drawPixmap(QPoint(xOffset,0),mPixmap); + } + } +} + +void EventIndicator::changeColumns(int columns) +{ + mColumns = columns; + mEnabled.resize(mColumns); + + update(); +} + +void EventIndicator::enableColumn(int column, bool enable) +{ + mEnabled[column] = enable; +} + + +#include <libkcal/incidence.h> + +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// + + +KOAlternateLabel::KOAlternateLabel(const QString &shortlabel, const QString &longlabel, + const QString &extensivelabel, QWidget *parent, const char *name ) + : QLabel(parent, name), mTextTypeFixed(false), mShortText(shortlabel), + mLongText(longlabel), mExtensiveText(extensivelabel) +{ + setSizePolicy(QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed )); + if (mExtensiveText.isEmpty()) mExtensiveText = mLongText; + squeezeTextToLabel(); +} + +KOAlternateLabel::~KOAlternateLabel() +{ +} + +void KOAlternateLabel::useShortText() +{ + mTextTypeFixed = true; + QLabel::setText( mShortText ); + QToolTip::remove( this ); + QToolTip::add( this, mExtensiveText ); +} + +void KOAlternateLabel::useLongText() +{ + mTextTypeFixed = true; + QLabel::setText( mLongText ); + QToolTip::remove( this ); + QToolTip::add( this, mExtensiveText ); +} + +void KOAlternateLabel::useExtensiveText() +{ + mTextTypeFixed = true; + QLabel::setText( mExtensiveText ); + QToolTip::remove( this ); + QToolTip::hide(); +} + +void KOAlternateLabel::useDefaultText() +{ + mTextTypeFixed = false; + squeezeTextToLabel(); +} + +void KOAlternateLabel::squeezeTextToLabel() +{ + if (mTextTypeFixed) return; + + QFontMetrics fm(fontMetrics()); + int labelWidth = size().width(); + int textWidth = fm.width(mLongText); + int longTextWidth = fm.width(mExtensiveText); + if (longTextWidth <= labelWidth) { + QLabel::setText( mExtensiveText ); + QToolTip::remove( this ); + QToolTip::hide(); + } else if (textWidth <= labelWidth) { + QLabel::setText( mLongText ); + QToolTip::remove( this ); + QToolTip::add( this, mExtensiveText ); + } else { + QLabel::setText( mShortText ); + QToolTip::remove( this ); + QToolTip::add( this, mExtensiveText ); + } +} + +void KOAlternateLabel::resizeEvent( QResizeEvent * ) +{ + squeezeTextToLabel(); +} + +QSize KOAlternateLabel::minimumSizeHint() const +{ + QSize sh = QLabel::minimumSizeHint(); + sh.setWidth(-1); + return sh; +} + +void KOAlternateLabel::setText( const QString &text ) { + mLongText = text; + squeezeTextToLabel(); +} + + +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// + +KOAgendaView::KOAgendaView(Calendar *cal,QWidget *parent,const char *name, bool isSideBySide ) : + KOrg::AgendaView (cal,parent,name), mExpandButton( 0 ), mAllowAgendaUpdate( true ), + mUpdateItem( 0 ), + mResource( 0 ), + mIsSideBySide( isSideBySide ), + mPendingChanges( true ) +{ + mSelectedDates.append(QDate::currentDate()); + + mLayoutDayLabels = 0; + mDayLabelsFrame = 0; + mDayLabels = 0; + + bool isRTL = KOGlobals::self()->reverseLayout(); + + if ( KOPrefs::instance()->compactDialogs() ) { + if ( KOPrefs::instance()->mVerticalScreen ) { + mExpandedPixmap = KOGlobals::self()->smallIcon( "1downarrow" ); + mNotExpandedPixmap = KOGlobals::self()->smallIcon( "1uparrow" ); + } else { + mExpandedPixmap = KOGlobals::self()->smallIcon( isRTL ? "1leftarrow" : "1rightarrow" ); + mNotExpandedPixmap = KOGlobals::self()->smallIcon( isRTL ? "1rightarrow" : "1leftarrow" ); + } + } + + QBoxLayout *topLayout = new QVBoxLayout(this); + + // Create day name labels for agenda columns + mDayLabelsFrame = new QHBox(this); + topLayout->addWidget(mDayLabelsFrame); + + // Create agenda splitter +#ifndef KORG_NOSPLITTER + mSplitterAgenda = new QSplitter(Vertical,this); + topLayout->addWidget(mSplitterAgenda); + +#if KDE_IS_VERSION( 3, 1, 93 ) + mSplitterAgenda->setOpaqueResize( KGlobalSettings::opaqueResize() ); +#else + mSplitterAgenda->setOpaqueResize(); +#endif + + mAllDayFrame = new QHBox(mSplitterAgenda); + + QWidget *agendaFrame = new QWidget(mSplitterAgenda); +#else + QVBox *mainBox = new QVBox( this ); + topLayout->addWidget( mainBox ); + + mAllDayFrame = new QHBox(mainBox); + + QWidget *agendaFrame = new QWidget(mainBox); +#endif + + // Create all-day agenda widget + mDummyAllDayLeft = new QVBox( mAllDayFrame ); + if ( isSideBySide ) + mDummyAllDayLeft->hide(); + + if ( KOPrefs::instance()->compactDialogs() ) { + mExpandButton = new QPushButton(mDummyAllDayLeft); + mExpandButton->setPixmap( mNotExpandedPixmap ); + mExpandButton->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, + QSizePolicy::Fixed ) ); + connect( mExpandButton, SIGNAL( clicked() ), SIGNAL( toggleExpand() ) ); + } else { + QLabel *label = new QLabel( i18n("All Day"), mDummyAllDayLeft ); + label->setAlignment( Qt::AlignRight | Qt::AlignVCenter | Qt::WordBreak ); + } + + mAllDayAgenda = new KOAgenda(1,mAllDayFrame); + QWidget *dummyAllDayRight = new QWidget(mAllDayFrame); + + // Create agenda frame + QGridLayout *agendaLayout = new QGridLayout(agendaFrame,3,3); +// QHBox *agendaFrame = new QHBox(splitterAgenda); + + // create event indicator bars + mEventIndicatorTop = new EventIndicator(EventIndicator::Top,agendaFrame); + agendaLayout->addWidget(mEventIndicatorTop,0,1); + mEventIndicatorBottom = new EventIndicator(EventIndicator::Bottom, + agendaFrame); + agendaLayout->addWidget(mEventIndicatorBottom,2,1); + QWidget *dummyAgendaRight = new QWidget(agendaFrame); + agendaLayout->addWidget(dummyAgendaRight,0,2); + + // Create time labels + mTimeLabels = new TimeLabels(24,agendaFrame); + agendaLayout->addWidget(mTimeLabels,1,0); + + // Create agenda + mAgenda = new KOAgenda(1,96,KOPrefs::instance()->mHourSize,agendaFrame); + agendaLayout->addMultiCellWidget(mAgenda,1,1,1,2); + agendaLayout->setColStretch(1,1); + + // Create event context menu for agenda + mAgendaPopup = eventPopup(); + + // Create event context menu for all day agenda + mAllDayAgendaPopup = eventPopup(); + + // make connections between dependent widgets + mTimeLabels->setAgenda(mAgenda); + if ( isSideBySide ) + mTimeLabels->hide(); + + // Update widgets to reflect user preferences +// updateConfig(); + + createDayLabels(); + + if ( !isSideBySide ) { + // these blank widgets make the All Day Event box line up with the agenda + dummyAllDayRight->setFixedWidth(mAgenda->verticalScrollBar()->width()); + dummyAgendaRight->setFixedWidth(mAgenda->verticalScrollBar()->width()); + } + + updateTimeBarWidth(); + + // Scrolling + connect(mAgenda->verticalScrollBar(),SIGNAL(valueChanged(int)), + mTimeLabels, SLOT(positionChanged())); + + connect( mAgenda, + SIGNAL( zoomView( const int, const QPoint & ,const Qt::Orientation ) ), + SLOT( zoomView( const int, const QPoint &, const Qt::Orientation ) ) ); + + connect(mTimeLabels->verticalScrollBar(),SIGNAL(valueChanged(int)), + SLOT(setContentsPos(int))); + + // Create Events, depends on type of agenda + connect( mAgenda, SIGNAL(newTimeSpanSignal(const QPoint &, const QPoint &)), + SLOT(newTimeSpanSelected(const QPoint &, const QPoint &))); + connect( mAllDayAgenda, SIGNAL(newTimeSpanSignal(const QPoint &, const QPoint &)), + SLOT(newTimeSpanSelectedAllDay(const QPoint &, const QPoint &))); + + // event indicator update + connect( mAgenda, SIGNAL(lowerYChanged(int)), + SLOT(updateEventIndicatorTop(int))); + connect( mAgenda, SIGNAL(upperYChanged(int)), + SLOT(updateEventIndicatorBottom(int))); + + connectAgenda( mAgenda, mAgendaPopup, mAllDayAgenda ); + connectAgenda( mAllDayAgenda, mAllDayAgendaPopup, mAgenda); + + if ( cal ) + cal->registerObserver( this ); +} + + +KOAgendaView::~KOAgendaView() +{ + if ( calendar() ) + calendar()->unregisterObserver( this ); + delete mAgendaPopup; + delete mAllDayAgendaPopup; +} + +void KOAgendaView::connectAgenda( KOAgenda *agenda, QPopupMenu *popup, + KOAgenda *otherAgenda ) +{ + connect( agenda, SIGNAL( showIncidencePopupSignal( Incidence *, const QDate & ) ), + popup, SLOT( showIncidencePopup( Incidence *, const QDate & ) ) ); + + connect( agenda, SIGNAL( showNewEventPopupSignal() ), + SLOT( showNewEventPopup() ) ); + + agenda->setCalendar( calendar() ); + + // Create/Show/Edit/Delete Event + connect( agenda, SIGNAL( newEventSignal() ), SIGNAL( newEventSignal() ) ); + + connect( agenda, SIGNAL( newStartSelectSignal() ), + otherAgenda, SLOT( clearSelection() ) ); + connect( agenda, SIGNAL( newStartSelectSignal() ), + SIGNAL( timeSpanSelectionChanged()) ); + + connect( agenda, SIGNAL( editIncidenceSignal( Incidence * ) ), + SIGNAL( editIncidenceSignal( Incidence * ) ) ); + connect( agenda, SIGNAL( showIncidenceSignal( Incidence * ) ), + SIGNAL( showIncidenceSignal( Incidence * ) ) ); + connect( agenda, SIGNAL( deleteIncidenceSignal( Incidence * ) ), + SIGNAL( deleteIncidenceSignal( Incidence * ) ) ); + + connect( agenda, SIGNAL( startMultiModify( const QString & ) ), + SIGNAL( startMultiModify( const QString & ) ) ); + connect( agenda, SIGNAL( endMultiModify() ), + SIGNAL( endMultiModify() ) ); + + connect( agenda, SIGNAL( itemModified( KOAgendaItem * ) ), + SLOT( updateEventDates( KOAgendaItem * ) ) ); + connect( agenda, SIGNAL( enableAgendaUpdate( bool ) ), + SLOT( enableAgendaUpdate( bool ) ) ); + + // drag signals + connect( agenda, SIGNAL( startDragSignal( Incidence * ) ), + SLOT( startDrag( Incidence * ) ) ); + + // synchronize selections + connect( agenda, SIGNAL( incidenceSelected( Incidence * ) ), + otherAgenda, SLOT( deselectItem() ) ); + connect( agenda, SIGNAL( incidenceSelected( Incidence * ) ), + SIGNAL( incidenceSelected( Incidence * ) ) ); + + // rescheduling of todos by d'n'd + connect( agenda, SIGNAL( droppedToDo( Todo *, const QPoint &, bool ) ), + SLOT( slotTodoDropped( Todo *, const QPoint &, bool ) ) ); + +} + +void KOAgendaView::zoomInVertically( ) +{ + if ( !mIsSideBySide ) + KOPrefs::instance()->mHourSize++; + mAgenda->updateConfig(); + mAgenda->checkScrollBoundaries(); + + mTimeLabels->updateConfig(); + mTimeLabels->positionChanged(); + mTimeLabels->repaint(); + + updateView(); +} + +void KOAgendaView::zoomOutVertically( ) +{ + + if ( KOPrefs::instance()->mHourSize > 4 || mIsSideBySide ) { + + if ( !mIsSideBySide ) + KOPrefs::instance()->mHourSize--; + mAgenda->updateConfig(); + mAgenda->checkScrollBoundaries(); + + mTimeLabels->updateConfig(); + mTimeLabels->positionChanged(); + mTimeLabels->repaint(); + + updateView(); + } +} + +void KOAgendaView::zoomInHorizontally( const QDate &date) +{ + QDate begin; + QDate newBegin; + QDate dateToZoom = date; + int ndays,count; + + begin = mSelectedDates.first(); + ndays = begin.daysTo( mSelectedDates.last() ); + + // zoom with Action and are there a selected Incidence?, Yes, I zoom in to it. + if ( ! dateToZoom.isValid () ) + dateToZoom=mAgenda->selectedIncidenceDate(); + + if( !dateToZoom.isValid() ) { + if ( ndays > 1 ) { + newBegin=begin.addDays(1); + count = ndays-1; + emit zoomViewHorizontally ( newBegin , count ); + } + } else { + if ( ndays <= 2 ) { + newBegin = dateToZoom; + count = 1; + } else { + newBegin = dateToZoom.addDays( -ndays/2 +1 ); + count = ndays -1 ; + } + emit zoomViewHorizontally ( newBegin , count ); + } +} + +void KOAgendaView::zoomOutHorizontally( const QDate &date ) +{ + QDate begin; + QDate newBegin; + QDate dateToZoom = date; + int ndays,count; + + begin = mSelectedDates.first(); + ndays = begin.daysTo( mSelectedDates.last() ); + + // zoom with Action and are there a selected Incidence?, Yes, I zoom out to it. + if ( ! dateToZoom.isValid () ) + dateToZoom=mAgenda->selectedIncidenceDate(); + + if ( !dateToZoom.isValid() ) { + newBegin = begin.addDays(-1); + count = ndays+3 ; + } else { + newBegin = dateToZoom.addDays( -ndays/2-1 ); + count = ndays+3; + } + + if ( abs( count ) >= 31 ) + kdDebug(5850) << "change to the mounth view?"<<endl; + else + //We want to center the date + emit zoomViewHorizontally( newBegin, count ); +} + +void KOAgendaView::zoomView( const int delta, const QPoint &pos, + const Qt::Orientation orient ) +{ + static QDate zoomDate; + static QTimer *t = new QTimer( this ); + + + //Zoom to the selected incidence, on the other way + // zoom to the date on screen after the first mousewheel move. + if ( orient == Qt::Horizontal ) { + QDate date=mAgenda->selectedIncidenceDate(); + if ( date.isValid() ) + zoomDate=date; + else{ + if ( !t->isActive() ) { + zoomDate= mSelectedDates[pos.x()]; + } + t->start ( 1000,true ); + } + if ( delta > 0 ) + zoomOutHorizontally( zoomDate ); + else + zoomInHorizontally( zoomDate ); + } else { + // Vertical zoom + QPoint posConstentsOld = mAgenda->gridToContents(pos); + if ( delta > 0 ) { + zoomOutVertically(); + } else { + zoomInVertically(); + } + QPoint posConstentsNew = mAgenda->gridToContents(pos); + mAgenda->scrollBy( 0, posConstentsNew.y() - posConstentsOld.y() ); + } +} + +void KOAgendaView::createDayLabels() +{ +// 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) + delete mDayLabels; + + mDayLabels = new QFrame (mDayLabelsFrame); + mLayoutDayLabels = new QHBoxLayout(mDayLabels); + if ( !mIsSideBySide ) + mLayoutDayLabels->addSpacing(mTimeLabels->width()); + + const KCalendarSystem*calsys=KOGlobals::self()->calendarSystem(); + + DateList::ConstIterator dit; + for( dit = mSelectedDates.begin(); dit != mSelectedDates.end(); ++dit ) { + QDate date = *dit; + QBoxLayout *dayLayout = new QVBoxLayout(mLayoutDayLabels); + mLayoutDayLabels->setStretchFactor(dayLayout, 1); +// dayLayout->setMinimumWidth(1); + + int dW = calsys->dayOfWeek(date); + QString veryLongStr = KGlobal::locale()->formatDate( date ); + QString longstr = i18n( "short_weekday date (e.g. Mon 13)","%1 %2" ) + .arg( calsys->weekDayName( dW, true ) ) + .arg( calsys->day(date) ); + QString shortstr = QString::number(calsys->day(date)); + + KOAlternateLabel *dayLabel = new KOAlternateLabel(shortstr, + longstr, veryLongStr, mDayLabels); + dayLabel->setMinimumWidth(1); + dayLabel->setAlignment(QLabel::AlignHCenter); + if (date == QDate::currentDate()) { + QFont font = dayLabel->font(); + font.setBold(true); + dayLabel->setFont(font); + } + dayLayout->addWidget(dayLabel); + + // if a holiday region is selected, show the holiday name + QStringList texts = KOGlobals::self()->holiday( date ); + QStringList::ConstIterator textit = texts.begin(); + for ( ; textit != texts.end(); ++textit ) { + // use a KOAlternateLabel so when the text doesn't fit any more a tooltip is used + KOAlternateLabel*label = new KOAlternateLabel( (*textit), (*textit), QString::null, mDayLabels ); + label->setMinimumWidth(1); + label->setAlignment(AlignCenter); + dayLayout->addWidget(label); + } + +#ifndef KORG_NOPLUGINS + CalendarDecoration::List cds = KOCore::self()->calendarDecorations(); + CalendarDecoration *it; + for(it = cds.first(); it; it = cds.next()) { + QString text = it->shortText( date ); + if ( !text.isEmpty() ) { + // use a KOAlternateLabel so when the text doesn't fit any more a tooltip is used + KOAlternateLabel*label = new KOAlternateLabel( text, text, QString::null, mDayLabels ); + label->setMinimumWidth(1); + label->setAlignment(AlignCenter); + dayLayout->addWidget(label); + } + } + + for(it = cds.first(); it; it = cds.next()) { + QWidget *wid = it->smallWidget(mDayLabels,date); + if ( wid ) { +// wid->setHeight(20); + dayLayout->addWidget(wid); + } + } +#endif + } + + if ( !mIsSideBySide ) + mLayoutDayLabels->addSpacing(mAgenda->verticalScrollBar()->width()); + mDayLabels->show(); +} + +void KOAgendaView::enableAgendaUpdate( bool enable ) +{ + mAllowAgendaUpdate = enable; +} + +int KOAgendaView::maxDatesHint() +{ + // Not sure about the max number of events, so return 0 for now. + return 0; +} + +int KOAgendaView::currentDateCount() +{ + return mSelectedDates.count(); +} + +Incidence::List KOAgendaView::selectedIncidences() +{ + Incidence::List selected; + Incidence *incidence; + + incidence = mAgenda->selectedIncidence(); + if (incidence) selected.append(incidence); + + incidence = mAllDayAgenda->selectedIncidence(); + if (incidence) selected.append(incidence); + + return selected; +} + +DateList KOAgendaView::selectedDates() +{ + DateList selected; + QDate qd; + + qd = mAgenda->selectedIncidenceDate(); + if (qd.isValid()) selected.append(qd); + + qd = mAllDayAgenda->selectedIncidenceDate(); + if (qd.isValid()) selected.append(qd); + + return selected; +} + +bool KOAgendaView::eventDurationHint( QDateTime &startDt, QDateTime &endDt, + bool &allDay ) +{ + if ( selectionStart().isValid() ) { + QDateTime start = selectionStart(); + QDateTime end = selectionEnd(); + + if ( start.secsTo( end ) == 15*60 ) { + // One cell in the agenda view selected, e.g. + // because of a double-click, => Use the default duration + QTime defaultDuration( KOPrefs::instance()->mDefaultDuration.time() ); + int addSecs = ( defaultDuration.hour()*3600 ) + + ( defaultDuration.minute()*60 ); + end = start.addSecs( addSecs ); + } + + startDt = start; + endDt = end; + allDay = selectedIsAllDay(); + return true; + } + return false; +} + +/** returns if only a single cell is selected, or a range of cells */ +bool KOAgendaView::selectedIsSingleCell() +{ + if ( !selectionStart().isValid() || !selectionEnd().isValid() ) return false; + + if (selectedIsAllDay()) { + int days = selectionStart().daysTo(selectionEnd()); + return ( days < 1 ); + } else { + int secs = selectionStart().secsTo(selectionEnd()); + return ( secs <= 24*60*60/mAgenda->rows() ); + } +} + + +void KOAgendaView::updateView() +{ +// kdDebug(5850) << "KOAgendaView::updateView()" << endl; + fillAgenda(); +} + + +/* + Update configuration settings for the agenda view. This method is not + complete. +*/ +void KOAgendaView::updateConfig() +{ +// kdDebug(5850) << "KOAgendaView::updateConfig()" << endl; + + // update config for children + mTimeLabels->updateConfig(); + mAgenda->updateConfig(); + mAllDayAgenda->updateConfig(); + + // widget synchronization + // FIXME: find a better way, maybe signal/slot + mTimeLabels->positionChanged(); + + // for some reason, this needs to be called explicitly + mTimeLabels->repaint(); + + updateTimeBarWidth(); + + // ToolTips displaying summary of events + KOAgendaItem::toolTipGroup()->setEnabled(KOPrefs::instance() + ->mEnableToolTips); + + setHolidayMasks(); + + createDayLabels(); + + updateView(); +} + +void KOAgendaView::updateTimeBarWidth() +{ + int width; + + width = mDummyAllDayLeft->fontMetrics().width( i18n("All Day") ); + width = QMAX( width, mTimeLabels->width() ); + + mDummyAllDayLeft->setFixedWidth( width ); + mTimeLabels->setFixedWidth( width ); +} + + +void KOAgendaView::updateEventDates( KOAgendaItem *item ) +{ + kdDebug(5850) << "KOAgendaView::updateEventDates(): " << item->text() << endl; + + QDateTime 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 + // for doesRecur(), because we only move the start day by the number of days the + // agenda item was really moved. Smart, isn't it?) + QDate thisDate; + if ( item->cellXLeft() < 0 ) { + thisDate = ( mSelectedDates.first() ).addDays( item->cellXLeft() ); + } else { + thisDate = mSelectedDates[ item->cellXLeft() ]; + } + QDate oldThisDate( item->itemDate() ); + int daysOffset = oldThisDate.daysTo( thisDate ); + int daysLength = 0; + +// startDt.setDate( startDate ); + + Incidence *incidence = item->incidence(); + if ( !incidence ) return; + if ( !mChanger || !mChanger->beginChange(incidence) ) return; + Incidence *oldIncidence = incidence->clone(); + + QTime startTime(0,0,0), endTime(0,0,0); + if ( incidence->doesFloat() ) { + daysLength = item->cellWidth() - 1; + } else { + startTime = mAgenda->gyToTime( item->cellYTop() ); + if ( item->lastMultiItem() ) { + endTime = mAgenda->gyToTime( item->lastMultiItem()->cellYBottom() + 1 ); + daysLength = item->lastMultiItem()->cellXLeft() - item->cellXLeft(); + } else { + endTime = mAgenda->gyToTime( item->cellYBottom() + 1 ); + } + } + +// kdDebug(5850) << "KOAgendaView::updateEventDates(): now setting dates" << endl; + // FIXME: use a visitor here + if ( incidence->type() == "Event" ) { + startDt = incidence->dtStart(); + startDt = startDt.addDays( daysOffset ); + startDt.setTime( startTime ); + endDt = startDt.addDays( daysLength ); + endDt.setTime( endTime ); + Event*ev = static_cast<Event*>(incidence); + if( incidence->dtStart() == startDt && ev->dtEnd() == endDt ) { + // No change + delete oldIncidence; + return; + } + incidence->setDtStart( startDt ); + ev->setDtEnd( endDt ); + } else if ( incidence->type() == "Todo" ) { + Todo *td = static_cast<Todo*>(incidence); + startDt = td->hasStartDate() ? td->dtStart() : td->dtDue(); + startDt = thisDate.addDays( td->dtDue().daysTo( startDt ) ); + startDt.setTime( startTime ); + endDt.setDate( thisDate ); + endDt.setTime( endTime ); + + if( td->dtDue() == endDt ) { + // No change + delete oldIncidence; + return; + } + } + // FIXME: Adjusting the recurrence should really go to CalendarView so this + // 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 ) { + switch ( recur->recurrenceType() ) { + case Recurrence::rYearlyPos: { + int freq = recur->frequency(); + int duration = recur->duration(); + QDate endDt( recur->endDate() ); + bool negative = false; + + QPtrList<Recurrence::rMonthPos> monthPos( recur->yearMonthPositions() ); + if ( monthPos.first() ) { + negative = monthPos.first()->negative; + } + QBitArray days( 7 ); + int pos = 0; + days.fill( false ); + days.setBit( thisDate.dayOfWeek() - 1 ); + if ( negative ) { + pos = - ( thisDate.daysInMonth() - thisDate.day() - 1 ) / 7 - 1; + } else { + pos = ( thisDate.day()-1 ) / 7 + 1; + } + // Terrible hack: to change the month days, I have to unset the recurrence, and set all days manually again + recur->unsetRecurs(); + if ( duration != 0 ) { + recur->setYearly( Recurrence::rYearlyPos, freq, duration ); + } else { + recur->setYearly( Recurrence::rYearlyPos, freq, endDt ); + } + recur->addYearlyMonthPos( pos, days ); + recur->addYearlyNum( thisDate.month() ); + + break; } + case Recurrence::rYearlyDay: { + int freq = recur->frequency(); + int duration = recur->duration(); + QDate endDt( recur->endDate() ); + // Terrible hack: to change the month days, I have to unset the recurrence, and set all days manually again + recur->unsetRecurs(); + if ( duration == 0 ) { // end by date + recur->setYearly( Recurrence::rYearlyDay, freq, endDt ); + } else { + recur->setYearly( Recurrence::rYearlyDay, freq, duration ); + } + recur->addYearlyNum( thisDate.dayOfYear() ); + break; } + case Recurrence::rYearlyMonth: { + int freq = recur->frequency(); + int duration = recur->duration(); + QDate endDt( recur->endDate() ); + // Terrible hack: to change the month days, I have to unset the recurrence, and set all days manually again + recur->unsetRecurs(); + if ( duration != 0 ) { + recur->setYearlyByDate( thisDate.day(), recur->feb29YearlyType(), freq, duration ); + } else { + recur->setYearlyByDate( thisDate.day(), recur->feb29YearlyType(), freq, endDt ); + } + recur->addYearlyNum( thisDate.month() ); + break; } + case Recurrence::rMonthlyPos: { + int freq = recur->frequency(); + int duration = recur->duration(); + QDate endDt( recur->endDate() ); + QPtrList<Recurrence::rMonthPos> monthPos( recur->monthPositions() ); + if ( !monthPos.isEmpty() ) { + // FIXME: How shall I adapt the day x of week Y if we move the date across month borders??? + // for now, just use the date of the moved item and assume the recurrence only occurs on that day. + // That's fine for korganizer, but might mess up other organizers. + QBitArray rDays( 7 ); + rDays = monthPos.first()->rDays; + bool negative = monthPos.first()->negative; + int newPos; + rDays.fill( false ); + rDays.setBit( thisDate.dayOfWeek() - 1 ); + if ( negative ) { + newPos = - ( thisDate.daysInMonth() - thisDate.day() - 1 ) / 7 - 1; + } else { + newPos = ( thisDate.day()-1 ) / 7 + 1; + } + + // Terrible hack: to change the month days, I have to unset the recurrence, and set all days manually again + recur->unsetRecurs(); + if ( duration == 0 ) { // end by date + recur->setMonthly( Recurrence::rMonthlyPos, freq, endDt ); + } else { + recur->setMonthly( Recurrence::rMonthlyPos, freq, duration ); + } + recur->addMonthlyPos( newPos, rDays ); + } + break;} + case Recurrence::rMonthlyDay: { + int freq = recur->frequency(); + int duration = recur->duration(); + QDate endDt( recur->endDate() ); + QPtrList<int> monthDays( recur->monthDays() ); + // Terrible hack: to change the month days, I have to unset the recurrence, and set all days manually again + recur->unsetRecurs(); + if ( duration == 0 ) { // end by date + recur->setMonthly( Recurrence::rMonthlyDay, freq, endDt ); + } else { + recur->setMonthly( Recurrence::rMonthlyDay, freq, duration ); + } + // FIXME: How shall I adapt the n-th day if we move the date across month borders??? + // for now, just use the date of the moved item and assume the recurrence only occurs on that day. + // That's fine for korganizer, but might mess up other organizers. + recur->addMonthlyDay( thisDate.day() ); + + break;} + case Recurrence::rWeekly: { + QBitArray days(7), oldDays( recur->days() ); + int offset = daysOffset % 7; + if ( offset<0 ) offset = (offset+7) % 7; + // rotate the days + for (int d=0; d<7; d++ ) { + days.setBit( (d+offset) % 7, oldDays.at(d) ); + } + if ( recur->duration() == 0 ) { // end by date + recur->setWeekly( recur->frequency(), days, recur->endDate(), recur->weekStart() ); + } else { // duration or no end + recur->setWeekly( recur->frequency(), days, recur->duration(), recur->weekStart() ); + } + break;} + // nothing to be done for the following: + case Recurrence::rDaily: + case Recurrence::rHourly: + case Recurrence::rMinutely: + case Recurrence::rNone: + default: + break; + } + if ( recur->duration()==0 ) { // end by date + recur->setEndDate( recur->endDate().addDays( daysOffset ) ); + } + KMessageBox::information( this, i18n("A recurring calendar item was moved " + "to a different day. The recurrence settings " + "have been updated with that move. Please check " + "them in the editor."), + i18n("Recurrence Moved"), + "RecurrenceMoveInAgendaWarning" ); + }*/ + + // FIXME: use a visitor here + if ( incidence->type() == "Event" ) { + incidence->setDtStart( startDt ); + (static_cast<Event*>( incidence ) )->setDtEnd( endDt ); + } else if ( incidence->type() == "Todo" ) { + Todo *td = static_cast<Todo*>( incidence ); + if ( td->hasStartDate() ) + td->setDtStart( startDt ); + td->setDtDue( endDt ); + } + + item->setItemDate( startDt.date() ); + + KOIncidenceToolTip::remove( item ); + KOIncidenceToolTip::add( item, incidence, KOAgendaItem::toolTipGroup() ); + + mChanger->changeIncidence( oldIncidence, incidence ); + mChanger->endChange(incidence); + delete oldIncidence; + + // 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 + enableAgendaUpdate( false ); + // We need to do this in a timer to make sure we are not deleting the item + // we are currently working on, which would lead to crashes + // Only the actually moved agenda item is already at the correct position and mustn't be + // recreated. All others have to!!! + if ( incidence->doesRecur() ) { + mUpdateItem = incidence; + QTimer::singleShot( 0, this, SLOT( doUpdateItem() ) ); + } + + enableAgendaUpdate( true ); + +// kdDebug(5850) << "KOAgendaView::updateEventDates() done " << endl; +} + +void KOAgendaView::doUpdateItem() +{ + if ( mUpdateItem ) { + changeIncidenceDisplay( mUpdateItem, KOGlobals::INCIDENCEEDITED ); + mUpdateItem = 0; + } +} + + + +void KOAgendaView::showDates( const QDate &start, const QDate &end ) +{ +// kdDebug(5850) << "KOAgendaView::selectDates" << endl; + if ( !mSelectedDates.isEmpty() && mSelectedDates.first() == start + && mSelectedDates.last() == end && !mPendingChanges ) + return; + + mSelectedDates.clear(); + + QDate d = start; + while (d <= end) { + mSelectedDates.append(d); + d = d.addDays( 1 ); + } + + // and update the view + fillAgenda(); +} + + +void KOAgendaView::showIncidences( const Incidence::List & ) +{ + kdDebug(5850) << "KOAgendaView::showIncidences( const Incidence::List & ) is not yet implemented" << endl; +} + +void KOAgendaView::insertIncidence( Incidence *incidence, const QDate &curDate, + int curCol ) +{ + 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 ); + + if ( curCol < 0 ) { + curCol = mSelectedDates.findIndex( curDate ); + } + // The date for the event is not displayed, just ignore it + if ( curCol < 0 || curCol > int( mSelectedDates.size() ) ) + return; + + int beginX; + int endX; + if ( event ) { + beginX = curDate.daysTo( incidence->dtStart().date() ) + curCol; + endX = curDate.daysTo( event->dateEnd() ) + curCol; + } 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; + } 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 ); + } + } + } else if ( event && event->isMultiDay() ) { + int startY = mAgenda->timeToY( event->dtStart().time() ); + QTime endtime( event->dtEnd().time() ); + if ( endtime == QTime( 0, 0, 0 ) ) endtime = QTime( 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 == curCol ) { + mMaxY[curCol] = mAgenda->timeToY( QTime(23,59) ); + if ( startY < mMinY[curCol] ) mMinY[curCol] = startY; + } else if ( endX == curCol ) { + mMinY[curCol] = mAgenda->timeToY( QTime(0,0) ); + if ( endY > mMaxY[curCol] ) mMaxY[curCol] = endY; + } else { + mMinY[curCol] = mAgenda->timeToY( QTime(0,0) ); + mMaxY[curCol] = mAgenda->timeToY( QTime(23,59) ); + } + } else { + int startY = 0, endY = 0; + if ( event ) { + startY = mAgenda->timeToY( incidence->dtStart().time() ); + QTime endtime( event->dtEnd().time() ); + if ( endtime == QTime( 0, 0, 0 ) ) endtime = QTime( 23, 59, 59 ); + endY = mAgenda->timeToY( endtime ) - 1; + } + if ( todo ) { + QTime t = todo->dtDue().time(); + endY = mAgenda->timeToY( t ) - 1; + startY = mAgenda->timeToY( t.addSecs( -1800 ) ); + } + 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; + } +} + +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; + + QDate f = mSelectedDates.first(); + QDate l = mSelectedDates.last(); + QDate startDt = incidence->dtStart().date(); + + if ( incidence->doesRecur() ) { + DateList::ConstIterator dit; + QDate curDate; + for( dit = mSelectedDates.begin(); dit != mSelectedDates.end(); ++dit ) { + curDate = *dit; +// FIXME: This breaks with recurring multi-day events! + if ( incidence->recursOn( curDate ) ) { + insertIncidence( incidence, curDate ); + } + } + return; + } + + QDate endDt; + if ( incidence->type() == "Event" ) + endDt = (static_cast<Event *>(incidence))->dateEnd(); + if ( todo ) { + endDt = todo->isOverdue() ? QDate::currentDate() + : todo->dtDue().date(); + + if ( endDt >= f && endDt <= l ) { + insertIncidence( incidence, endDt ); + return; + } + } + + if ( startDt >= f && startDt <= l ) { + insertIncidence( incidence, startDt ); + } +} + +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 ); + break; + } + case KOGlobals::INCIDENCEEDITED: { + if ( !mAllowAgendaUpdate ) { + updateEventIndicators(); + } else { + removeIncidence( incidence ); + updateEventIndicators(); + changeIncidenceDisplayAdded( incidence ); + } + break; + } + case KOGlobals::INCIDENCEDELETED: { + mAgenda->removeIncidence( incidence ); + mAllDayAgenda->removeIncidence( incidence ); + updateEventIndicators(); + break; + } + default: + updateView(); + } +} + +void KOAgendaView::fillAgenda( const QDate & ) +{ + fillAgenda(); +} + +void KOAgendaView::fillAgenda() +{ + mPendingChanges = false; + + /* Remember the uids of the selected items. In case one of the + * items was deleted and re-added, we want to reselect it. */ + const QString &selectedAgendaUid = mAgenda->lastSelectedUid(); + const QString &selectedAllDayAgendaUid = mAllDayAgenda->lastSelectedUid(); + + enableAgendaUpdate( true ); + clearView(); + + mAllDayAgenda->changeColumns(mSelectedDates.count()); + mAgenda->changeColumns(mSelectedDates.count()); + mEventIndicatorTop->changeColumns(mSelectedDates.count()); + mEventIndicatorBottom->changeColumns(mSelectedDates.count()); + + createDayLabels(); + setHolidayMasks(); + + mMinY.resize(mSelectedDates.count()); + mMaxY.resize(mSelectedDates.count()); + + Event::List dayEvents; + + // 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); + + QDate today = QDate::currentDate(); + + bool somethingReselected = false; + DateList::ConstIterator dit; + int curCol = 0; + for( dit = mSelectedDates.begin(); dit != mSelectedDates.end(); ++dit ) { + QDate 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(QTime(23,59)) + 1; + mMaxY[curCol] = mAgenda->timeToY(QTime(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 (numEvent == 0) kdDebug(5850) << " No events" << endl; + + + // ---------- [display Todos -------------- + if ( KOPrefs::instance()->showAllDayTodo() ) { + unsigned int numTodo; + for (numTodo = 0; numTodo < todos.count(); ++numTodo) { + Todo *todo = *todos.at(numTodo); + + if ( ! todo->hasDueDate() ) continue; // todo shall not be displayed if it has no date + + if ( !filterByResource( todo ) ) continue; + + // 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(); + + 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; + + mAllDayAgenda->insertAllDayItem(todo, currentDate, curCol, curCol); + } else { + //kdDebug(5850) << "todo with time:" << todo->dtDueStr() << ";" << todo->summary() << endl; + + int endY = mAgenda->timeToY(todo->dtDue().time()) - 1; + int startY = endY - 1; + + mAgenda->insertItem(todo,currentDate,curCol,startY,endY); + + if (startY < mMinY[curCol]) mMinY[curCol] = startY; + if (endY > mMaxY[curCol]) mMaxY[curCol] = endY; + } + } + } + } + // ---------- display Todos] -------------- + + ++curCol; + } + + mAgenda->checkScrollBoundaries(); + updateEventIndicators(); + +// mAgenda->viewport()->update(); +// mAllDayAgenda->viewport()->update(); + +// make invalid + deleteSelectedDateTime(); + + if( !somethingReselected ) { + emit incidenceSelected( 0 ); + } + +// kdDebug(5850) << "Fill Agenda done" << endl; +} + +void KOAgendaView::clearView() +{ +// kdDebug(5850) << "ClearView" << endl; + mAllDayAgenda->clear(); + mAgenda->clear(); +} + +CalPrinterBase::PrintType KOAgendaView::printType() +{ + if ( currentDateCount() == 1 ) return CalPrinterBase::Day; + else return CalPrinterBase::Week; +} + +void KOAgendaView::updateEventIndicatorTop( int newY ) +{ + uint i; + for( i = 0; i < mMinY.size(); ++i ) { + mEventIndicatorTop->enableColumn( i, newY >= mMinY[i] ); + } + mEventIndicatorTop->update(); +} + +void KOAgendaView::updateEventIndicatorBottom( int newY ) +{ + uint i; + for( i = 0; i < mMaxY.size(); ++i ) { + mEventIndicatorBottom->enableColumn( i, newY <= mMaxY[i] ); + } + mEventIndicatorBottom->update(); +} + +void KOAgendaView::slotTodoDropped( Todo *todo, const QPoint &gpos, bool allDay ) +{ + if ( gpos.x()<0 || gpos.y()<0 ) return; + QDate day = mSelectedDates[gpos.x()]; + QTime time = mAgenda->gyToTime( gpos.y() ); + QDateTime newTime( day, time ); + + if ( todo ) { + Todo *existingTodo = calendar()->todo( todo->uid() ); + if ( existingTodo ) { + kdDebug(5850) << "Drop existing Todo" << endl; + Todo *oldTodo = existingTodo->clone(); + if ( mChanger && mChanger->beginChange( existingTodo ) ) { + existingTodo->setDtDue( newTime ); + existingTodo->setFloats( allDay ); + existingTodo->setHasDueDate( true ); + mChanger->changeIncidence( oldTodo, existingTodo ); + mChanger->endChange( existingTodo ); + } else { + KMessageBox::sorry( this, i18n("Unable to modify this to-do, " + "because it cannot be locked.") ); + } + delete oldTodo; + } else { + kdDebug(5850) << "Drop new Todo" << endl; + todo->setDtDue( newTime ); + todo->setFloats( allDay ); + todo->setHasDueDate( true ); + if ( !mChanger->addIncidence( todo, this ) ) { + KODialogManager::errorSaveIncidence( this, todo ); + } + } + } +} + +void KOAgendaView::startDrag( Incidence *incidence ) +{ +#ifndef KORG_NODND + DndFactory factory( calendar() ); + ICalDrag *vd = factory.createDrag( incidence, this ); + if ( vd->drag() ) { + kdDebug(5850) << "KOAgendaView::startDrag(): Delete drag source" << endl; + } +#endif +} + +void KOAgendaView::readSettings() +{ + readSettings(KOGlobals::self()->config()); +} + +void KOAgendaView::readSettings(KConfig *config) +{ +// kdDebug(5850) << "KOAgendaView::readSettings()" << endl; + + config->setGroup("Views"); + +#ifndef KORG_NOSPLITTER + QValueList<int> sizes = config->readIntListEntry("Separator AgendaView"); + if (sizes.count() == 2) { + mSplitterAgenda->setSizes(sizes); + } +#endif + + updateConfig(); +} + +void KOAgendaView::writeSettings(KConfig *config) +{ +// kdDebug(5850) << "KOAgendaView::writeSettings()" << endl; + + config->setGroup("Views"); + +#ifndef KORG_NOSPLITTER + QValueList<int> list = mSplitterAgenda->sizes(); + config->writeEntry("Separator AgendaView",list); +#endif +} + +void KOAgendaView::setHolidayMasks() +{ + mHolidayMask.resize( mSelectedDates.count() + 1 ); + + for( uint i = 0; i < mSelectedDates.count(); ++i ) { + mHolidayMask[i] = !KOGlobals::self()->isWorkDay( mSelectedDates[ i ] ); + } + + // Store the information about the day before the visible area (needed for + // overnight working hours) in the last bit of the mask: + bool showDay = !KOGlobals::self()->isWorkDay( mSelectedDates[ 0 ].addDays( -1 ) ); + mHolidayMask[ mSelectedDates.count() ] = showDay; + + mAgenda->setHolidayMask( &mHolidayMask ); + mAllDayAgenda->setHolidayMask( &mHolidayMask ); +} + +void KOAgendaView::setContentsPos( int y ) +{ + mAgenda->setContentsPos( 0, y ); +} + +void KOAgendaView::setExpandedButton( bool expanded ) +{ + if ( !mExpandButton ) return; + + if ( expanded ) { + mExpandButton->setPixmap( mExpandedPixmap ); + } else { + mExpandButton->setPixmap( mNotExpandedPixmap ); + } +} + +void KOAgendaView::clearSelection() +{ + mAgenda->deselectItem(); + mAllDayAgenda->deselectItem(); +} + +void KOAgendaView::newTimeSpanSelectedAllDay( const QPoint &start, const QPoint &end ) +{ + newTimeSpanSelected( start, end ); + mTimeSpanInAllDay = true; +} + +void KOAgendaView::newTimeSpanSelected( const QPoint &start, const QPoint &end ) +{ + if (!mSelectedDates.count()) return; + + mTimeSpanInAllDay = false; + + QDate dayStart = mSelectedDates[ kClamp( start.x(), 0, (int)mSelectedDates.size() - 1 ) ]; + QDate dayEnd = mSelectedDates[ kClamp( end.x(), 0, (int)mSelectedDates.size() - 1 ) ]; + + QTime timeStart = mAgenda->gyToTime(start.y()); + QTime timeEnd = mAgenda->gyToTime( end.y() + 1 ); + + QDateTime dtStart(dayStart,timeStart); + QDateTime dtEnd(dayEnd,timeEnd); + + mTimeSpanBegin = dtStart; + mTimeSpanEnd = dtEnd; +} + +void KOAgendaView::deleteSelectedDateTime() +{ + mTimeSpanBegin.setDate(QDate()); + mTimeSpanEnd.setDate(QDate()); + mTimeSpanInAllDay = false; +} + +void KOAgendaView::setTypeAheadReceiver( QObject *o ) +{ + mAgenda->setTypeAheadReceiver( o ); + mAllDayAgenda->setTypeAheadReceiver( o ); +} + +void KOAgendaView::finishTypeAhead() +{ + mAgenda->finishTypeAhead(); + mAllDayAgenda->finishTypeAhead(); +} + +void KOAgendaView::removeIncidence( Incidence *incidence ) +{ + mAgenda->removeIncidence( incidence ); + mAllDayAgenda->removeIncidence( incidence ); +} + +void KOAgendaView::updateEventIndicators() +{ + mMinY = mAgenda->minContentsY(); + mMaxY = mAgenda->maxContentsY(); + + mAgenda->checkScrollBoundaries(); + updateEventIndicatorTop( mAgenda->visibleContentsYMin() ); + updateEventIndicatorBottom( mAgenda->visibleContentsYMax() ); +} + +void KOAgendaView::setIncidenceChanger( IncidenceChangerBase *changer ) +{ + mChanger = changer; + mAgenda->setIncidenceChanger( changer ); + mAllDayAgenda->setIncidenceChanger( changer ); +} + +void KOAgendaView::clearTimeSpanSelection() +{ + mAgenda->clearSelection(); + mAllDayAgenda->clearSelection(); + deleteSelectedDateTime(); +} + +void KOAgendaView::setResource(KCal::ResourceCalendar * res, const QString & subResource) +{ + mResource = res; + mSubResource = subResource; +} + +bool KOAgendaView::filterByResource(Incidence * incidence) +{ + if ( !mResource ) + return true; + CalendarResources *calRes = dynamic_cast<CalendarResources*>( calendar() ); + if ( !calRes ) + return true; + if ( calRes->resource( incidence ) != mResource ) + return false; + if ( !mSubResource.isEmpty() ) { + if ( mResource->subresourceIdentifier( incidence ) != mSubResource ) + return false; + } + return true; +} + +void KOAgendaView::resourcesChanged() +{ + mPendingChanges = true; +} + +void KOAgendaView::calendarIncidenceAdded(Incidence * incidence) +{ + Q_UNUSED( incidence ); + mPendingChanges = true; +} + +void KOAgendaView::calendarIncidenceChanged(Incidence * incidence) +{ + Q_UNUSED( incidence ); + mPendingChanges = true; +} + +void KOAgendaView::calendarIncidenceRemoved(Incidence * incidence) +{ + Q_UNUSED( incidence ); + mPendingChanges = true; +} diff --git a/korganizer/koagendaview.h b/korganizer/koagendaview.h new file mode 100644 index 000000000..6fc673307 --- /dev/null +++ b/korganizer/koagendaview.h @@ -0,0 +1,295 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2000,2001,2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOAGENDAVIEW_H +#define KOAGENDAVIEW_H + +#include <qscrollview.h> +#include <qlabel.h> + +#include <libkcal/calendar.h> + +#include "calprinter.h" + +#include "agendaview.h" + +class QHBox; +class QPushButton; +class QBoxLayout; + +class KOAgenda; +class KOAgendaItem; +class TimeLabels; +class KConfig; + +namespace KCal { + class ResourceCalendar; +} + +namespace KOrg { + class IncidenceChangerBase; +} + +class EventIndicator : public QFrame +{ + Q_OBJECT + public: + enum Location { Top, Bottom }; + EventIndicator( Location loc = Top, QWidget *parent = 0, + const char *name = 0 ); + virtual ~EventIndicator(); + + void changeColumns( int columns ); + + void enableColumn( int column, bool enable ); + + protected: + void drawContents( QPainter * ); + + private: + int mColumns; + Location mLocation; + QPixmap mPixmap; + QMemArray<bool> mEnabled; +}; + +class KOAlternateLabel : public QLabel +{ + Q_OBJECT + public: + KOAlternateLabel( const QString &shortlabel, const QString &longlabel, + const QString &extensivelabel = QString::null, + QWidget *parent = 0, const char *name = 0 ); + ~KOAlternateLabel(); + + virtual QSize minimumSizeHint() const; + + public slots: + void setText( const QString & ); + void useShortText(); + void useLongText(); + void useExtensiveText(); + void useDefaultText(); + + protected: + virtual void resizeEvent( QResizeEvent * ); + virtual void squeezeTextToLabel(); + bool mTextTypeFixed; + QString mShortText, mLongText, mExtensiveText; +}; + +/** + KOAgendaView is the agenda-like view used to display events in a single one or + multi-day view. +*/ +class KOAgendaView : public KOrg::AgendaView, public KCal::Calendar::Observer +{ + Q_OBJECT + public: + KOAgendaView( Calendar *cal, QWidget *parent = 0, const char *name = 0, bool isSideBySide = false ); + virtual ~KOAgendaView(); + + + + /** Returns maximum number of days supported by the koagendaview */ + virtual int maxDatesHint(); + + /** Returns number of currently shown dates. */ + virtual int currentDateCount(); + + /** returns the currently selected events */ + virtual Incidence::List selectedIncidences(); + + /** returns the currently selected events */ + virtual DateList selectedDates(); + + /** return the default start/end date/time for new events */ + virtual bool eventDurationHint(QDateTime &startDt, QDateTime &endDt, bool &allDay); + + /** Remove all events from view */ + void clearView(); + + KOrg::CalPrinterBase::PrintType printType(); + + /** start-datetime of selection */ + QDateTime selectionStart() { return mTimeSpanBegin; } + /** end-datetime of selection */ + QDateTime selectionEnd() { return mTimeSpanEnd; } + /** returns true if selection is for whole day */ + bool selectedIsAllDay() { return mTimeSpanInAllDay; } + /** make selected start/end invalid */ + void deleteSelectedDateTime(); + /** returns if only a single cell is selected, or a range of cells */ + bool selectedIsSingleCell(); + + void setTypeAheadReceiver( QObject * ); + + /** Show only incidences from the given resource. */ + void setResource( KCal::ResourceCalendar *res, const QString &subResource = QString::null ); + + KOAgenda* agenda() const { return mAgenda; } + QSplitter* splitter() const { return mSplitterAgenda; } + + /* reimplmented from KCal::Calendar::Observer */ + void calendarIncidenceAdded( Incidence *incidence ); + void calendarIncidenceChanged( Incidence *incidence ); + void calendarIncidenceRemoved( Incidence *incidence ); + + public slots: + virtual void updateView(); + virtual void updateConfig(); + virtual void showDates( const QDate &start, const QDate &end ); + virtual void showIncidences( const Incidence::List &incidenceList ); + + void insertIncidence( Incidence *incidence, const QDate &curDate, int curCol = -1 ); + void changeIncidenceDisplayAdded( Incidence *incidence ); + void changeIncidenceDisplay( Incidence *incidence, int mode ); + + void clearSelection(); + + void startDrag( Incidence * ); + + void readSettings(); + void readSettings( KConfig * ); + void writeSettings( KConfig * ); + + void setContentsPos( int y ); + + void setExpandedButton( bool expanded ); + + void finishTypeAhead(); + + /** reschedule the todo to the given x- and y- coordinates. Third parameter determines all-day (no time specified) */ + void slotTodoDropped( Todo *, const QPoint &, bool ); + + void enableAgendaUpdate( bool enable ); + void setIncidenceChanger( KOrg::IncidenceChangerBase *changer ); + + void zoomInHorizontally( const QDate& date=QDate() ); + void zoomOutHorizontally( const QDate& date=QDate() ); + + void zoomInVertically( ); + void zoomOutVertically( ); + + void zoomView( const int delta, const QPoint &pos, + const Qt::Orientation orient=Qt::Horizontal ); + + void clearTimeSpanSelection(); + + void resourcesChanged(); + + signals: + void toggleExpand(); + void zoomViewHorizontally(const QDate &, int count ); + + void timeSpanSelectionChanged(); + + protected: + /** Fill agenda beginning with date startDate */ + void fillAgenda( const QDate &startDate ); + + /** Fill agenda using the current set value for the start date */ + void fillAgenda(); + + void connectAgenda( KOAgenda*agenda, QPopupMenu*popup, KOAgenda* otherAgenda ); + + /** Create labels for the selected dates. */ + void createDayLabels(); + + /** + Set the masks on the agenda widgets indicating, which days are holidays. + */ + void setHolidayMasks(); + + void removeIncidence( Incidence * ); + /** + Updates the event indicators after a certain incidence was modified or + removed. + */ + void updateEventIndicators(); + + void updateTimeBarWidth(); + + protected slots: + /** Update event belonging to agenda item */ + void updateEventDates( KOAgendaItem *item ); + /** update just the display of the given incidence, called by a single-shot timer */ + void doUpdateItem(); + + void updateEventIndicatorTop( int newY ); + void updateEventIndicatorBottom( int newY ); + + /** Updates data for selected timespan */ + void newTimeSpanSelected( const QPoint &start, const QPoint &end ); + /** Updates data for selected timespan for all day event*/ + void newTimeSpanSelectedAllDay( const QPoint &start, const QPoint &end ); + + private: + bool filterByResource( Incidence *incidence ); + + private: + // view widgets + QFrame *mDayLabels; + QHBox *mDayLabelsFrame; + QBoxLayout *mLayoutDayLabels; + QFrame *mAllDayFrame; + KOAgenda *mAllDayAgenda; + KOAgenda *mAgenda; + TimeLabels *mTimeLabels; + QWidget *mDummyAllDayLeft; + QSplitter *mSplitterAgenda; + QPushButton *mExpandButton; + + DateList mSelectedDates; // List of dates to be displayed + int mViewType; + + KOEventPopupMenu *mAgendaPopup; + KOEventPopupMenu *mAllDayAgendaPopup; + + EventIndicator *mEventIndicatorTop; + EventIndicator *mEventIndicatorBottom; + + QMemArray<int> mMinY; + QMemArray<int> mMaxY; + + QMemArray<bool> mHolidayMask; + + QPixmap mExpandedPixmap; + QPixmap mNotExpandedPixmap; + + QDateTime mTimeSpanBegin; + QDateTime mTimeSpanEnd; + bool mTimeSpanInAllDay; + bool mAllowAgendaUpdate; + + Incidence *mUpdateItem; + + KCal::ResourceCalendar *mResource; + QString mSubResource; + + bool mIsSideBySide; + bool mPendingChanges; +}; + +#endif diff --git a/korganizer/koapp.cpp b/korganizer/koapp.cpp new file mode 100644 index 000000000..66bb39556 --- /dev/null +++ b/korganizer/koapp.cpp @@ -0,0 +1,157 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1999 Preston Brown <pbrown@kde.org> + Copyright (c) 2000,2001,2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <stdlib.h> +#include <iostream> + +#include <kglobal.h> +#include <kcmdlineargs.h> +#include <kconfig.h> +#include <kdebug.h> +#include <klocale.h> +#include <kwin.h> +#include <kurl.h> + +#include <libkcal/calformat.h> +#include <libkcal/calendarresources.h> + +#include "korganizer.h" +#include "koprefs.h" +#include "version.h" +#include "alarmclient.h" +#include "koglobals.h" +#include "actionmanager.h" +#include "importdialog.h" +#include "kocore.h" +#include "calendarview.h" +#include "stdcalendar.h" + +#include "koapp.h" +#include <kstartupinfo.h> + +using namespace std; + +KOrganizerApp::KOrganizerApp() : KUniqueApplication() +{ + QString prodId = "-//K Desktop Environment//NONSGML KOrganizer %1//EN"; + CalFormat::setApplication( "KOrganizer", prodId.arg( korgVersion ) ); +} + +KOrganizerApp::~KOrganizerApp() +{ +} + +int KOrganizerApp::newInstance() +{ + kdDebug(5850) << "KOApp::newInstance()" << endl; + static bool first = true; + if ( isRestored() && first ) { + KOrg::MainWindow *korg = ActionManager::findInstance( KURL() ); + if ( korg ) { + KOrg::StdCalendar::self()->load(); + korg->view()->updateCategories(); + korg->view()->updateView(); + } + first = false; + return 0; + } + first = false; + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + KOGlobals::self()->alarmClient()->startDaemon(); + + // No filenames given => all other args are meaningless, show main Window + if ( args->count() <= 0 ) { + processCalendar( KURL() ); + return 0; + } + + // If filenames wer given as arguments, load them as calendars, one per window. + if ( args->isSet( "open" ) ) { + for( int i = 0; i < args->count(); ++i ) { + processCalendar( args->url( i ) ); + } + } else { + // Import, merge, or ask => we need the resource calendar window anyway. + processCalendar( KURL() ); + KOrg::MainWindow *korg = ActionManager::findInstance( KURL() ); + if ( !korg ) { + kdError() << "Unable to find default calendar resources view." << endl; + return -1; + } + // Check for import, merge or ask + if ( args->isSet( "import" ) ) { + for( int i = 0; i < args->count(); ++i ) { + korg->actionManager()->addResource( args->url( i ) ); + } + } else if ( args->isSet( "merge" ) ) { + for( int i = 0; i < args->count(); ++i ) { + korg->actionManager()->mergeURL( args->url( i ).url() ); + } + } else { + for( int i = 0; i < args->count(); ++i ) { + korg->actionManager()->importCalendar( args->url( i ) ); + } + } + } + + kdDebug(5850) << "KOApp::newInstance() done" << endl; + + return 0; +} + + +void KOrganizerApp::processCalendar( const KURL &url ) +{ + KOrg::MainWindow *korg = ActionManager::findInstance( url ); + if ( !korg ) { + bool hasDocument = !url.isEmpty(); + korg = new KOrganizer( "KOrganizer MainWindow" ); + korg->init( hasDocument ); + korg->topLevelWidget()->show(); + + kdDebug(5850) << "KOrganizerApp::processCalendar(): '" << url.url() + << "'" << endl; + + if ( hasDocument ) + korg->openURL( url ); + else { + KOrg::StdCalendar::self()->load(); + korg->view()->updateCategories(); + korg->view()->updateView(); + } + } else { + korg->topLevelWidget()->show(); + } + + // Handle window activation +#if defined Q_WS_X11 && ! defined K_WS_QTONLY + KStartupInfo::setNewStartupId( korg->topLevelWidget(), startupId() ); +#endif +} + +#include "koapp.moc" diff --git a/korganizer/koapp.h b/korganizer/koapp.h new file mode 100644 index 000000000..776f15728 --- /dev/null +++ b/korganizer/koapp.h @@ -0,0 +1,51 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1999 Preston Brown <pbrown@kde.org> + Copyright (c) 2000,2001,2003 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KORGANIZERAPP_H +#define KORGANIZERAPP_H + +#include <kuniqueapplication.h> + +class KOrganizerApp : public KUniqueApplication +{ + Q_OBJECT + public: + KOrganizerApp(); + ~KOrganizerApp(); + + /** + Create new instance of KOrganizer. If there is already running a + KOrganizer only an additional main window is opened. + */ + int newInstance(); + + private: + /** + Process calendar from URL \arg url. If url is empty open the default + calendar based on the resource framework. + */ + void processCalendar( const KURL &url ); +}; + +#endif diff --git a/korganizer/koattendeeeditor.cpp b/korganizer/koattendeeeditor.cpp new file mode 100644 index 000000000..c6a255e9c --- /dev/null +++ b/korganizer/koattendeeeditor.cpp @@ -0,0 +1,457 @@ +/* + Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com> + 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 "koattendeeeditor.h" +#include "koprefs.h" +#include "koglobals.h" + +#ifndef KORG_NOKABC +#include <kabc/addresseedialog.h> +#include <libkdepim/addressesdialog.h> +#include <libkdepim/addresseelineedit.h> +#endif + +#include <libkcal/incidence.h> + +#include <libemailfunctions/email.h> + +#include <kiconloader.h> +#include <klocale.h> + +#include <qcheckbox.h> +#include <qcombobox.h> +#include <qhbox.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qpushbutton.h> +#include <qwhatsthis.h> + +using namespace KCal; + +KOAttendeeEditor::KOAttendeeEditor( QWidget * parent, const char *name ) : + QWidget( parent, name ), + mDisableItemUpdate( true ) +{ +} + +void KOAttendeeEditor::initOrganizerWidgets(QWidget * parent, QBoxLayout * layout) +{ + mOrganizerHBox = new QHBox( parent ); + layout->addWidget( mOrganizerHBox ); + // If creating a new event, then the user is the organizer -> show the + // identity combo + // readEvent will delete it and set another label text instead, if the user + // isn't the organizer. + // Note that the i18n text below is duplicated in readEvent + QString whatsThis = i18n("Sets the identity corresponding to " + "the organizer of this to-do or event. " + "Identities can be set in the 'Personal' " + "section of the KOrganizer configuration, or in the " + "'Security & Privacy'->'Password & User Account' " + "section of the KDE Control Center. In addition, " + "identities are gathered from your KMail settings " + "and from your address book. If you choose " + "to set it globally for KDE in the Control Center, " + "be sure to check 'Use email settings from " + "Control Center' in the 'Personal' section of the " + "KOrganizer configuration."); + mOrganizerLabel = new QLabel( i18n( "Identity as organizer:" ), + mOrganizerHBox ); + mOrganizerCombo = new QComboBox( mOrganizerHBox ); + QWhatsThis::add( mOrganizerLabel, whatsThis ); + QWhatsThis::add( mOrganizerCombo, whatsThis ); + fillOrganizerCombo(); + mOrganizerHBox->setStretchFactor( mOrganizerCombo, 100 ); +} + +void KOAttendeeEditor::initEditWidgets(QWidget * parent, QBoxLayout * layout) +{ + QGridLayout *topLayout = new QGridLayout(); + layout->addLayout( topLayout ); + + QString whatsThis = i18n("Edits the name of the attendee selected in the list " + "above, or adds a new attendee if there are no attendees" + "in the list."); + QLabel *attendeeLabel = new QLabel( parent ); + QWhatsThis::add( attendeeLabel, whatsThis ); + attendeeLabel->setText( i18n("Na&me:") ); + topLayout->addWidget( attendeeLabel, 0, 0 ); + + mNameEdit = new KPIM::AddresseeLineEdit( parent ); + QWhatsThis::add( mNameEdit, whatsThis ); + mNameEdit->setClickMessage( i18n("Click to add a new attendee") ); + attendeeLabel->setBuddy( mNameEdit ); + mNameEdit->installEventFilter( this ); + connect( mNameEdit, SIGNAL( textChanged( const QString & ) ), + SLOT( updateAttendee() ) ); + topLayout->addMultiCellWidget( mNameEdit, 0, 0, 1, 2 ); + + whatsThis = i18n("Edits the role of the attendee selected " + "in the list above."); + QLabel *attendeeRoleLabel = new QLabel( parent ); + QWhatsThis::add( attendeeRoleLabel, whatsThis ); + attendeeRoleLabel->setText( i18n("Ro&le:") ); + topLayout->addWidget( attendeeRoleLabel, 1, 0 ); + + mRoleCombo = new QComboBox( false, parent ); + QWhatsThis::add( mRoleCombo, whatsThis ); + mRoleCombo->insertStringList( Attendee::roleList() ); + attendeeRoleLabel->setBuddy( mRoleCombo ); + connect( mRoleCombo, SIGNAL( activated( int ) ), + SLOT( updateAttendee() ) ); + topLayout->addWidget( mRoleCombo, 1, 1 ); + + mDelegateLabel = new QLabel( parent ); + topLayout->addWidget( mDelegateLabel, 1, 2 ); + + whatsThis = i18n("Edits the current attendance status of the attendee " + "selected in the list above."); + QLabel *statusLabel = new QLabel( parent ); + QWhatsThis::add( statusLabel, whatsThis ); + statusLabel->setText( i18n("Stat&us:") ); + topLayout->addWidget( statusLabel, 2, 0 ); + + mStatusCombo = new QComboBox( false, parent ); + QWhatsThis::add( mStatusCombo, whatsThis ); +// mStatusCombo->insertStringList( Attendee::statusList() ); + mStatusCombo->insertItem( SmallIcon( "help" ), Attendee::statusName( Attendee::NeedsAction ) ); + mStatusCombo->insertItem( KOGlobals::self()->smallIcon( "ok" ), Attendee::statusName( Attendee::Accepted ) ); + mStatusCombo->insertItem( KOGlobals::self()->smallIcon( "no" ), Attendee::statusName( Attendee::Declined ) ); + mStatusCombo->insertItem( KOGlobals::self()->smallIcon( "apply" ), Attendee::statusName( Attendee::Tentative ) ); + mStatusCombo->insertItem( KOGlobals::self()->smallIcon( "mail_forward" ), Attendee::statusName( Attendee::Delegated ) ); + mStatusCombo->insertItem( Attendee::statusName( Attendee::Completed ) ); + mStatusCombo->insertItem( KOGlobals::self()->smallIcon( "help" ), Attendee::statusName( Attendee::InProcess ) ); + + statusLabel->setBuddy( mStatusCombo ); + connect( mStatusCombo, SIGNAL( activated( int ) ), + SLOT( updateAttendee() ) ); + topLayout->addWidget( mStatusCombo, 2, 1 ); + + topLayout->setColStretch( 2, 1 ); + + mRsvpButton = new QCheckBox( parent ); + QWhatsThis::add( mRsvpButton, + i18n("Edits whether to send an email to the attendee " + "selected in the list above to request " + "a response concerning attendance.") ); + mRsvpButton->setText( i18n("Re&quest response") ); + connect( mRsvpButton, SIGNAL( clicked() ), SLOT( updateAttendee() ) ); + topLayout->addWidget( mRsvpButton, 2, 2 ); + + QWidget *buttonBox = new QWidget( parent ); + QVBoxLayout *buttonLayout = new QVBoxLayout( buttonBox ); + + mAddButton = new QPushButton( i18n("&New"), buttonBox ); + QWhatsThis::add( mAddButton, + i18n("Adds a new attendee to the list. Once the " + "attendee is added, you will be able to " + "edit the attendee's name, role, attendance " + "status, and whether or not the attendee is required " + "to respond to the invitation. To select an attendee " + "from your addressbook, click the 'Select Addressee' " + "button instead.") ); + buttonLayout->addWidget( mAddButton ); + connect( mAddButton, SIGNAL( clicked() ), SLOT( addNewAttendee() ) ); + + mRemoveButton = new QPushButton( i18n("&Remove"), buttonBox ); + QWhatsThis::add( mRemoveButton, + i18n("Removes the attendee selected in " + "the list above.") ); + buttonLayout->addWidget( mRemoveButton ); + + mAddressBookButton = new QPushButton( i18n("Select Addressee..."), + buttonBox ); + QWhatsThis::add( mAddressBookButton, + i18n("Opens your address book, allowing you to select " + "new attendees from it.") ); + buttonLayout->addWidget( mAddressBookButton ); + connect( mAddressBookButton, SIGNAL( clicked() ), SLOT( openAddressBook() ) ); + + topLayout->addMultiCellWidget( buttonBox, 0, 3, 3, 3 ); + +#ifdef KORG_NOKABC + mAddressBookButton->hide(); +#endif +} + +void KOAttendeeEditor::openAddressBook() +{ +#ifndef KORG_NOKABC + KPIM::AddressesDialog *dia = new KPIM::AddressesDialog( this, "adddialog" ); + dia->setShowCC( false ); + dia->setShowBCC( false ); + if ( dia->exec() ) { + KABC::Addressee::List aList = dia->allToAddressesNoDuplicates(); + for ( KABC::Addressee::List::iterator itr = aList.begin(); + itr != aList.end(); ++itr ) { + insertAttendeeFromAddressee( (*itr) ); + } + } + 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 +} + +void KOAttendeeEditor::insertAttendeeFromAddressee(const KABC::Addressee &a, const Attendee * at) +{ + bool myself = KOPrefs::instance()->thatIsMe( a.preferredEmail() ); + bool sameAsOrganizer = mOrganizerCombo && + KPIM::compareEmail( a.preferredEmail(), mOrganizerCombo->currentText(), false ); + KCal::Attendee::PartStat partStat = at? at->status() : KCal::Attendee::NeedsAction; + bool rsvp = at? at->RSVP() : true; + + if ( myself && sameAsOrganizer ) { + partStat = KCal::Attendee::Accepted; + rsvp = false; + } + Attendee *newAt = new Attendee( a.realName(), + a.preferredEmail(), + !myself, partStat, + at ? at->role() : Attendee::ReqParticipant, + a.uid() ); + newAt->setRSVP( rsvp ); + insertAttendee( newAt, true ); +} + +void KOAttendeeEditor::fillOrganizerCombo() +{ + Q_ASSERT( mOrganizerCombo ); + // Get all emails from KOPrefs (coming from various places), + // and insert them - removing duplicates + const QStringList lst = KOPrefs::instance()->fullEmails(); + QStringList uniqueList; + for( QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it ) { + if ( uniqueList.find( *it ) == uniqueList.end() ) + uniqueList << *it; + } + mOrganizerCombo->insertStringList( uniqueList ); +} + +void KOAttendeeEditor::addNewAttendee() +{ + Attendee *a = new Attendee( i18n("Firstname Lastname"), + i18n("name") + "@example.net", true ); + insertAttendee( a, false ); + mnewAttendees.append(a); + updateAttendeeInput(); + // We don't want the hint again + mNameEdit->setClickMessage( "" ); + mNameEdit->setFocus(); + QTimer::singleShot( 0, mNameEdit, SLOT( selectAll() ) ); +} + +void KOAttendeeEditor::readEvent(KCal::Incidence * incidence) +{ + mdelAttendees.clear(); + mnewAttendees.clear(); + if ( KOPrefs::instance()->thatIsMe( incidence->organizer().email() ) ) { + if ( !mOrganizerCombo ) { + mOrganizerCombo = new QComboBox( mOrganizerHBox ); + fillOrganizerCombo(); + } + mOrganizerLabel->setText( i18n( "Identity as organizer:" ) ); + + int found = -1; + QString fullOrganizer = incidence->organizer().fullName(); + for ( int i = 0 ; i < mOrganizerCombo->count(); ++i ) { + if ( mOrganizerCombo->text( i ) == fullOrganizer ) { + found = i; + mOrganizerCombo->setCurrentItem( i ); + break; + } + } + if ( found < 0 ) { + mOrganizerCombo->insertItem( fullOrganizer, 0 ); + mOrganizerCombo->setCurrentItem( 0 ); + } + } else { // someone else is the organizer + if ( mOrganizerCombo ) { + delete mOrganizerCombo; + mOrganizerCombo = 0; + } + mOrganizerLabel->setText( i18n( "Organizer: %1" ).arg( incidence->organizer().fullName() ) ); + } + + Attendee::List al = incidence->attendees(); + Attendee::List::ConstIterator it; + for( it = al.begin(); it != al.end(); ++it ) + insertAttendee( new Attendee( **it ), true ); +} + +void KOAttendeeEditor::writeEvent(KCal::Incidence * incidence) +{ + if ( mOrganizerCombo ) { + // TODO: Don't take a string and split it up... Is there a better way? + incidence->setOrganizer( mOrganizerCombo->currentText() ); + } +} + +void KOAttendeeEditor::setEnableAttendeeInput(bool enabled) +{ + //mNameEdit->setEnabled( enabled ); + mRoleCombo->setEnabled( enabled ); + mStatusCombo->setEnabled( enabled ); + mRsvpButton->setEnabled( enabled ); + + mRemoveButton->setEnabled( enabled ); +} + +void KOAttendeeEditor::clearAttendeeInput() +{ + mNameEdit->setText(""); + mUid = QString::null; + mRoleCombo->setCurrentItem(0); + mStatusCombo->setCurrentItem(0); + mRsvpButton->setChecked(true); + setEnableAttendeeInput( false ); + mDelegateLabel->setText( QString() ); +} + +void KOAttendeeEditor::updateAttendee() +{ + Attendee *a = currentAttendee(); + if ( !a || mDisableItemUpdate ) + return; + + QString name; + QString email; + KPIM::getNameAndMail(mNameEdit->text(), name, email); + + bool iAmTheOrganizer = mOrganizerCombo && + KOPrefs::instance()->thatIsMe( mOrganizerCombo->currentText() ); + if ( iAmTheOrganizer ) { + bool myself = + KPIM::compareEmail( email, mOrganizerCombo->currentText(), false ); + 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 ) { + // this was me, but is no longer, reset + mStatusCombo->setCurrentItem( KCal::Attendee::NeedsAction ); + mRsvpButton->setChecked( true ); + mRsvpButton->setEnabled( true ); + } + } + a->setName( name ); + a->setUid( mUid ); + a->setEmail( email ); + a->setRole( Attendee::Role( mRoleCombo->currentItem() ) ); + a->setStatus( Attendee::PartStat( mStatusCombo->currentItem() ) ); + a->setRSVP( mRsvpButton->isChecked() ); + + updateCurrentItem(); +} + +void KOAttendeeEditor::fillAttendeeInput( KCal::Attendee *a ) +{ + mDisableItemUpdate = true; + + QString name = a->name(); + if (!a->email().isEmpty()) { + name = KPIM::quoteNameIfNecessary( name ); + name += " <" + a->email() + ">"; + } + mNameEdit->setText(name); + mUid = a->uid(); + mRoleCombo->setCurrentItem(a->role()); + mStatusCombo->setCurrentItem(a->status()); + mRsvpButton->setChecked(a->RSVP()); + + mDisableItemUpdate = false; + setEnableAttendeeInput( true ); + + if ( a->status() == Attendee::Delegated ) { + if ( !a->delegate().isEmpty() ) + mDelegateLabel->setText( i18n( "Delegated to %1" ).arg( a->delegate() ) ); + else if ( !a->delegator().isEmpty() ) + mDelegateLabel->setText( i18n( "Delegated from %1" ).arg( a->delegator() ) ); + else + mDelegateLabel->setText( i18n( "Not delegated" ) ); + } +} + +void KOAttendeeEditor::updateAttendeeInput() +{ + setEnableAttendeeInput(!mNameEdit->text().isEmpty()); + Attendee* a = currentAttendee(); + if ( a ) { + fillAttendeeInput( a ); + } else { + clearAttendeeInput(); + } +} + +void KOAttendeeEditor::cancelAttendeeEvent( KCal::Incidence *incidence ) +{ + incidence->clearAttendees(); + 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 (!isNewAttendee) { + incidence->addAttendee(new Attendee(*att)); + } + } + mdelAttendees.clear(); +} + +void KOAttendeeEditor::acceptForMe() +{ + changeStatusForMe( Attendee::Accepted ); +} + +void KOAttendeeEditor::declineForMe() +{ + changeStatusForMe( Attendee::Declined ); +} + +bool KOAttendeeEditor::eventFilter(QObject *watched, QEvent *ev) +{ + if ( watched && watched == mNameEdit && ev->type() == QEvent::FocusIn && + currentAttendee() == 0 ) { + addNewAttendee(); + } + + return QWidget::eventFilter( watched, ev ); +} + +#include "koattendeeeditor.moc" diff --git a/korganizer/koattendeeeditor.h b/korganizer/koattendeeeditor.h new file mode 100644 index 000000000..d7eb8cbdc --- /dev/null +++ b/korganizer/koattendeeeditor.h @@ -0,0 +1,124 @@ +/* + Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com> + 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 KOATTENDEEEDITOR_H +#define KOATTENDEEEDITOR_H + +#include <qwidget.h> +#include <libkcal/attendee.h> + +class QBoxLayout; +class QComboBox; +class QCheckBox; +class QLabel; +class QPushButton; +class QHBox; + +namespace KPIM { + class AddresseeLineEdit; +} + +namespace KABC { + class Addressee; +} + +namespace KCal { + class Incidence; +} + +/** + Common base class for attendee editor and free busy view. +*/ +class KOAttendeeEditor : public QWidget +{ + Q_OBJECT + public: + KOAttendeeEditor( QWidget *parent, const char *name = 0 ); + + virtual void insertAttendee( KCal::Attendee* attendee, bool fetchFB = true ) = 0; + + virtual void readEvent( KCal::Incidence *incidence ); + virtual void writeEvent( KCal::Incidence *incidence ); + + /** return a clone of the event with attendees to be canceld*/ + void cancelAttendeeEvent( KCal::Incidence *incidence ); + + public slots: + void acceptForMe(); + void declineForMe(); + + signals: + void updateAttendeeSummary( int count ); + + protected: + void initOrganizerWidgets( QWidget *parent, QBoxLayout *layout ); + void initEditWidgets( QWidget *parent, QBoxLayout *layout ); + + /** Reads values from a KABC::Addressee and inserts a new Attendee + * item into the listview with those items. Used when adding attendees + * from the addressbook and expanding distribution lists. + * The optional Attendee parameter can be used to pass in default values + * to be used by the new Attendee. */ + void insertAttendeeFromAddressee( const KABC::Addressee &a, const KCal::Attendee* at=0 ); + + void fillOrganizerCombo(); + + virtual KCal::Attendee* currentAttendee() const = 0; + virtual void updateCurrentItem() = 0; + + virtual void changeStatusForMe( KCal::Attendee::PartStat status ) = 0; + + virtual bool eventFilter( QObject *, QEvent *); + + protected slots: + void addNewAttendee(); + void openAddressBook(); + + void setEnableAttendeeInput( bool enabled ); + void updateAttendeeInput(); + void clearAttendeeInput(); + void fillAttendeeInput( KCal::Attendee *a ); + void updateAttendee(); + + protected: + KPIM::AddresseeLineEdit *mNameEdit; + QString mUid; + QComboBox* mRoleCombo; + QCheckBox* mRsvpButton; + QComboBox* mStatusCombo; + + QHBox* mOrganizerHBox; + QComboBox *mOrganizerCombo; // either we organize it (combo shown) + QLabel *mOrganizerLabel; // or someone else does (just a label is shown) + + QLabel* mDelegateLabel; + + QPushButton* mAddButton; + QPushButton* mRemoveButton; + QPushButton* mAddressBookButton; + + QPtrList<KCal::Attendee> mdelAttendees; + QPtrList<KCal::Attendee> mnewAttendees; + + private: + bool mDisableItemUpdate; +}; + +#endif diff --git a/korganizer/kocore.cpp b/korganizer/kocore.cpp new file mode 100644 index 000000000..6aca769b5 --- /dev/null +++ b/korganizer/kocore.cpp @@ -0,0 +1,386 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001,2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "kocore.h" + +#include "koprefs.h" +#include "koglobals.h" +#include "koidentitymanager.h" + +#include <calendar/plugin.h> +#include <korganizer/part.h> + +#include <klibloader.h> +#include <kdebug.h> +#include <kconfig.h> +#include <kxmlguifactory.h> +#include <kstandarddirs.h> +#include <klocale.h> + +#include <qwidget.h> + +KOCore *KOCore::mSelf = 0; + +KOCore *KOCore::self() +{ + if ( !mSelf ) { + mSelf = new KOCore; + } + + return mSelf; +} + +KOCore::KOCore() + : mCalendarDecorationsLoaded( false ), mIdentityManager( 0 ) +{ +} + +KOCore::~KOCore() +{ + mSelf = 0; +} + +KTrader::OfferList KOCore::availablePlugins( const QString &type, int version ) +{ + QString constraint; + if ( version >= 0 ) { + constraint = QString("[X-KDE-PluginInterfaceVersion] == %1") + .arg( QString::number( version ) ); + } + + return KTrader::self()->query( type, constraint ); +} + +KTrader::OfferList KOCore::availablePlugins() +{ + return availablePlugins( KOrg::Plugin::serviceType(), + KOrg::Plugin::interfaceVersion() ); +} + +KTrader::OfferList KOCore::availableCalendarDecorations() +{ + return availablePlugins( KOrg::CalendarDecoration::serviceType(), + KOrg::CalendarDecoration::interfaceVersion() ); +} + +KTrader::OfferList KOCore::availableParts() +{ + return availablePlugins( KOrg::Part::serviceType(), + KOrg::Part::interfaceVersion() ); +} + +KTrader::OfferList KOCore::availablePrintPlugins() +{ + return availablePlugins( KOrg::PrintPlugin::serviceType(), + KOrg::PrintPlugin::interfaceVersion() ); +} + +KOrg::Plugin *KOCore::loadPlugin( KService::Ptr service ) +{ + kdDebug(5850) << "loadPlugin: library: " << service->library() << endl; + + if ( !service->hasServiceType( KOrg::Plugin::serviceType() ) ) { + return 0; + } + + KLibFactory *factory = KLibLoader::self()->factory( + service->library().latin1() ); + + if ( !factory ) { + kdDebug(5850) << "KOCore::loadPlugin(): Factory creation failed" << endl; + return 0; + } + + KOrg::PluginFactory *pluginFactory = + static_cast<KOrg::PluginFactory *>( factory ); + + if ( !pluginFactory ) { + kdDebug(5850) << "KOCore::loadPlugin(): Cast to KOrg::PluginFactory failed" << endl; + return 0; + } + + return pluginFactory->create(); +} + +KOrg::Plugin *KOCore::loadPlugin( const QString &name ) +{ + KTrader::OfferList list = availablePlugins(); + KTrader::OfferList::ConstIterator it; + for( it = list.begin(); it != list.end(); ++it ) { + if ( (*it)->desktopEntryName() == name ) { + return loadPlugin( *it ); + } + } + return 0; +} + +KOrg::CalendarDecoration *KOCore::loadCalendarDecoration(KService::Ptr service) +{ + kdDebug(5850) << "loadCalendarDecoration: library: " << service->library() << endl; + + KLibFactory *factory = KLibLoader::self()->factory(service->library().latin1()); + + if (!factory) { + kdDebug(5850) << "KOCore::loadCalendarDecoration(): Factory creation failed" << endl; + return 0; + } + + KOrg::CalendarDecorationFactory *pluginFactory = + static_cast<KOrg::CalendarDecorationFactory *>(factory); + + if (!pluginFactory) { + kdDebug(5850) << "KOCore::loadCalendarDecoration(): Cast failed" << endl; + return 0; + } + + return pluginFactory->create(); +} + +KOrg::CalendarDecoration *KOCore::loadCalendarDecoration( const QString &name ) +{ + KTrader::OfferList list = availableCalendarDecorations(); + KTrader::OfferList::ConstIterator it; + for( it = list.begin(); it != list.end(); ++it ) { + if ( (*it)->desktopEntryName() == name ) { + return loadCalendarDecoration( *it ); + } + } + return 0; +} + +KOrg::Part *KOCore::loadPart( KService::Ptr service, KOrg::MainWindow *parent ) +{ + kdDebug(5850) << "loadPart: library: " << service->library() << endl; + + if ( !service->hasServiceType( KOrg::Part::serviceType() ) ) { + return 0; + } + + KLibFactory *factory = KLibLoader::self()->factory( + service->library().latin1() ); + + if ( !factory ) { + kdDebug(5850) << "KOCore::loadPart(): Factory creation failed" << endl; + return 0; + } + + KOrg::PartFactory *pluginFactory = + static_cast<KOrg::PartFactory *>( factory ); + + if ( !pluginFactory ) { + kdDebug(5850) << "KOCore::loadPart(): Cast failed" << endl; + return 0; + } + + return pluginFactory->create( parent ); +} + +KOrg::PrintPlugin *KOCore::loadPrintPlugin( KService::Ptr service ) +{ + kdDebug(5850) << "loadPart: print plugin in library: " << service->library() << endl; + + if ( !service->hasServiceType( KOrg::PrintPlugin::serviceType() ) ) { + return 0; + } + + KLibFactory *factory = KLibLoader::self()->factory( + service->library().latin1() ); + + if ( !factory ) { + kdDebug(5850) << "KOCore::loadPrintPlugin(): Factory creation failed" << endl; + return 0; + } + + KOrg::PrintPluginFactory *pluginFactory = + static_cast<KOrg::PrintPluginFactory *>( factory ); + + if ( !pluginFactory ) { + kdDebug(5850) << "KOCore::loadPrintPlugins(): Cast failed" << endl; + return 0; + } + + return pluginFactory->create(); +} + +void KOCore::addXMLGUIClient( QWidget *wdg, KXMLGUIClient *guiclient ) +{ + mXMLGUIClients.insert( wdg, guiclient ); +} + +void KOCore::removeXMLGUIClient( QWidget *wdg ) +{ + mXMLGUIClients.remove( wdg ); +} + +KXMLGUIClient* KOCore::xmlguiClient( QWidget *wdg ) const +{ + QWidget *topLevel = wdg->topLevelWidget(); + QMap<QWidget*, KXMLGUIClient*>::ConstIterator it = mXMLGUIClients.find( topLevel ); + if ( it != mXMLGUIClients.end() ) + return it.data(); + + return 0; +} + +KOrg::Part *KOCore::loadPart( const QString &name, KOrg::MainWindow *parent ) +{ + KTrader::OfferList list = availableParts(); + KTrader::OfferList::ConstIterator it; + for( it = list.begin(); it != list.end(); ++it ) { + if ( (*it)->desktopEntryName() == name ) { + return loadPart( *it, parent ); + } + } + return 0; +} + +KOrg::PrintPlugin *KOCore::loadPrintPlugin( const QString &name ) +{ + KTrader::OfferList list = availablePrintPlugins(); + KTrader::OfferList::ConstIterator it; + for( it = list.begin(); it != list.end(); ++it ) { + if ( (*it)->desktopEntryName() == name ) { + return loadPrintPlugin( *it ); + } + } + return 0; +} + +KOrg::CalendarDecoration::List KOCore::calendarDecorations() +{ + if ( !mCalendarDecorationsLoaded ) { + QStringList selectedPlugins = KOPrefs::instance()->mSelectedPlugins; + + mCalendarDecorations.clear(); + KTrader::OfferList plugins = availableCalendarDecorations(); + KTrader::OfferList::ConstIterator it; + for( it = plugins.begin(); it != plugins.end(); ++it ) { + if ( (*it)->hasServiceType("Calendar/Decoration") ) { + QString name = (*it)->desktopEntryName(); + if ( selectedPlugins.find( name ) != selectedPlugins.end() ) { + KOrg::CalendarDecoration *d = loadCalendarDecoration(*it); + mCalendarDecorations.append( d ); + } + } + } + mCalendarDecorationsLoaded = true; + } + + return mCalendarDecorations; +} + +KOrg::Part::List KOCore::loadParts( KOrg::MainWindow *parent ) +{ + KOrg::Part::List parts; + + QStringList selectedPlugins = KOPrefs::instance()->mSelectedPlugins; + + KTrader::OfferList plugins = availableParts(); + KTrader::OfferList::ConstIterator it; + for( it = plugins.begin(); it != plugins.end(); ++it ) { + if ( selectedPlugins.find( (*it)->desktopEntryName() ) != + selectedPlugins.end() ) { + KOrg::Part *part = loadPart( *it, parent ); + if ( part ) { + if ( !parent->mainGuiClient() ) { + kdError() << "KOCore::loadParts(): parent has no mainGuiClient." + << endl; + } else { + parent->mainGuiClient()->insertChildClient( part ); + parts.append( part ); + } + } + } + } + return parts; +} + +KOrg::PrintPlugin::List KOCore::loadPrintPlugins() +{ + KOrg::PrintPlugin::List loadedPlugins; + + QStringList selectedPlugins = KOPrefs::instance()->mSelectedPlugins; + + KTrader::OfferList plugins = availablePrintPlugins(); + KTrader::OfferList::ConstIterator it; + for( it = plugins.begin(); it != plugins.end(); ++it ) { + if ( selectedPlugins.find( (*it)->desktopEntryName() ) != + selectedPlugins.end() ) { + KOrg::PrintPlugin *part = loadPrintPlugin( *it ); + if ( part ) loadedPlugins.append( part ); + } + } + return loadedPlugins; +} + +void KOCore::unloadPlugins() +{ + KOrg::CalendarDecoration *plugin; + for( plugin = mCalendarDecorations.first(); plugin; + plugin = mCalendarDecorations.next() ) { + delete plugin; + } + mCalendarDecorations.clear(); + mCalendarDecorationsLoaded = false; +} + +void KOCore::unloadParts( KOrg::MainWindow *parent, KOrg::Part::List &parts ) +{ + KOrg::Part *part; + for( part = parts.first(); part; part = parts.next() ) { + parent->mainGuiClient()->removeChildClient( part ); + delete part; + } + parts.clear(); +} + +KOrg::Part::List KOCore::reloadParts( KOrg::MainWindow *parent, + KOrg::Part::List &parts ) +{ + KXMLGUIFactory *factory = parent->mainGuiClient()->factory(); + factory->removeClient( parent->mainGuiClient() ); + + unloadParts( parent, parts ); + KOrg::Part::List list = loadParts( parent ); + + factory->addClient( parent->mainGuiClient() ); + + return list; +} + +void KOCore::reloadPlugins() +{ + mCalendarDecorationsLoaded = false; +// Plugins should be unloaded, but e.g. komonthview keeps using the old ones + unloadPlugins(); + calendarDecorations(); +} + +KPIM::IdentityManager* KOCore::identityManager() +{ + if ( !mIdentityManager ) + mIdentityManager = new KOrg::IdentityManager; + return mIdentityManager; +} diff --git a/korganizer/kocore.h b/korganizer/kocore.h new file mode 100644 index 000000000..0cfa7011e --- /dev/null +++ b/korganizer/kocore.h @@ -0,0 +1,104 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001,2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOCORE_H +#define KOCORE_H + +#include <calendar/calendardecoration.h> +#include <korganizer/part.h> +#include <korganizer/printplugin.h> + +#include <kdepimmacros.h> +#include <ktrader.h> + +namespace KPIM { class IdentityManager; } + +class KDE_EXPORT KOCore +{ + public: + ~KOCore(); + + static KOCore *self(); + + KTrader::OfferList availablePlugins(); + KTrader::OfferList availableCalendarDecorations(); + KTrader::OfferList availableParts(); + KTrader::OfferList availablePrintPlugins(); + + KOrg::Plugin *loadPlugin( KService::Ptr service ); + KOrg::Plugin *loadPlugin( const QString & ); + + KOrg::CalendarDecoration *loadCalendarDecoration( KService::Ptr service ); + KOrg::CalendarDecoration *loadCalendarDecoration( const QString & ); + + KOrg::Part *loadPart( KService::Ptr, KOrg::MainWindow *parent ); + KOrg::Part *loadPart( const QString &, KOrg::MainWindow *parent ); + + KOrg::PrintPlugin *loadPrintPlugin( KService::Ptr service ); + KOrg::PrintPlugin *loadPrintPlugin( const QString & ); + + KOrg::CalendarDecoration::List calendarDecorations(); + KOrg::PrintPlugin::List loadPrintPlugins(); + KOrg::Part::List loadParts( KOrg::MainWindow *parent ); + + void addXMLGUIClient( QWidget*, KXMLGUIClient *guiclient ); + void removeXMLGUIClient( QWidget* ); + KXMLGUIClient *xmlguiClient( QWidget* ) const; + + /** + Unload the parts in &p parts for this main window. Clears + parts. + */ + void unloadParts( KOrg::MainWindow *parent, KOrg::Part::List &parts ); + void unloadPlugins(); + + void reloadPlugins(); + + /** + Unloads the parts from the main window. Loads the parts that + are listed in KOPrefs and returns a list of these parts. + */ + KOrg::Part::List reloadParts( KOrg::MainWindow *parent, + KOrg::Part::List &parts ); + + KPIM::IdentityManager* identityManager(); + + protected: + KOCore(); + + KTrader::OfferList availablePlugins( const QString &type, + int pluginInterfaceVersion = -1 ); + + private: + static KOCore *mSelf; + + KOrg::CalendarDecoration::List mCalendarDecorations; + bool mCalendarDecorationsLoaded; + + QMap<QWidget*, KXMLGUIClient*> mXMLGUIClients; + + KPIM::IdentityManager *mIdentityManager; +}; + +#endif diff --git a/korganizer/kocorehelper.cpp b/korganizer/kocorehelper.cpp new file mode 100644 index 000000000..40f557263 --- /dev/null +++ b/korganizer/kocorehelper.cpp @@ -0,0 +1,44 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "kocorehelper.h" +#include "kocore.h" +#include "koglobals.h" + + +QColor KOCoreHelper::categoryColor( const QStringList &categories ) +{ + // FIXME: Correctly treat events with multiple categories + QString cat = categories.first(); + QColor bgColor; + if (cat.isEmpty()) + bgColor = defaultEventColor(); + else + bgColor = *( KOPrefs::instance()->categoryColor( cat ) ); + return bgColor; +} + +QString KOCoreHelper::holidayString( const QDate &dt ) +{ + return KOGlobals::self()->holiday( dt ).join( i18n("delimiter for joining holiday names", ", " ) ); +} diff --git a/korganizer/kocorehelper.h b/korganizer/kocorehelper.h new file mode 100644 index 000000000..62a7d8a49 --- /dev/null +++ b/korganizer/kocorehelper.h @@ -0,0 +1,53 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1999 Preston Brown <pbrown@kde.org> + Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef _KOCOREHELPER_H +#define _KOCOREHELPER_H + + +#include "korganizer/corehelper.h" +#include "koprefs.h" +#include "koglobals.h" +#include "kocore.h" + +class KCalendarSystem; + +class KOCoreHelper : public KOrg::CoreHelper +{ + public: + KOCoreHelper() {} + virtual ~KOCoreHelper() {} + + virtual QColor defaultEventColor() { return KOPrefs::instance()->mEventColor; } + virtual QColor textColor( const QColor &bgColor ) { return getTextColor( bgColor ); } + virtual QColor categoryColor( const QStringList &cats ); + virtual QString holidayString( const QDate &dt ); + virtual QTime dayStart() { return KOPrefs::instance()->mDayBegins.time(); } + virtual const KCalendarSystem *calendarSystem() { return KOGlobals::self()->calendarSystem(); } + virtual KOrg::PrintPlugin::List loadPrintPlugins() { return KOCore::self()->loadPrintPlugins(); } + virtual bool isWorkingDay( const QDate &dt ) { return KOGlobals::self()->isWorkDay( dt ); } +}; + +#endif diff --git a/korganizer/kocounterdialog.cpp b/korganizer/kocounterdialog.cpp new file mode 100644 index 000000000..f3c0a2e4f --- /dev/null +++ b/korganizer/kocounterdialog.cpp @@ -0,0 +1,67 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + + +#include <klocale.h> + +#include <libkcal/event.h> +#include <libkcal/todo.h> +#include "koeventviewer.h" + +#include "kocounterdialog.h" +#include "kocounterdialog.moc" + +KOCounterDialog::KOCounterDialog( QWidget *parent, const char *name ) + : KDialogBase( parent, name, false, i18n("Counter-Event Viewer"), + User1 | User2, User1, false, i18n("Decline"), i18n("Accept") ) +{ + mEventViewer = new KOEventViewer( this ); + setMainWidget( mEventViewer ); + + connect( this, SIGNAL( user1Clicked() ), SLOT( slotCancel() ) ); + connect( this, SIGNAL( user2Clicked() ), SLOT( slotOk( ) ) ); + + // FIXME: Set a sensible size (based on the content?). + setMinimumSize( 300, 200 ); + resize( 320, 300 ); +} + +KOCounterDialog::~KOCounterDialog() +{ +} + +void KOCounterDialog::setIncidence( Incidence *incidence ) +{ + mEventViewer->setIncidence( incidence ); +} + +void KOCounterDialog::addIncidence( Incidence *incidence ) +{ + mEventViewer->appendIncidence( incidence ); +} + +void KOCounterDialog::addText( const QString &text ) +{ + mEventViewer->addText( text ); +} diff --git a/korganizer/kocounterdialog.h b/korganizer/kocounterdialog.h new file mode 100644 index 000000000..9bc5d28d3 --- /dev/null +++ b/korganizer/kocounterdialog.h @@ -0,0 +1,55 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2000, 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOCOUNTERDIALOG_H +#define KOCOUNTERDIALOG_H + +#include <kdialogbase.h> + +namespace KCal { +class Event; +class Todo; +} +using namespace KCal; + +class KOEventViewer; + +/** + Viewer dialog for counter events. +*/ +class KOCounterDialog : public KDialogBase +{ + Q_OBJECT + public: + KOCounterDialog(QWidget *parent = 0, const char *name = 0 ); + virtual ~KOCounterDialog(); + + void setIncidence( Incidence *incidence ); + void addIncidence( Incidence *incidence ); + void addText( const QString &text ); + + private: + KOEventViewer *mEventViewer; +}; + +#endif diff --git a/korganizer/kodaymatrix.cpp b/korganizer/kodaymatrix.cpp new file mode 100644 index 000000000..b749b2227 --- /dev/null +++ b/korganizer/kodaymatrix.cpp @@ -0,0 +1,704 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001 Eitzenberger Thomas <thomas.eitzenberger@siemens.at> + Parts of the source code have been copied from kdpdatebutton.cpp + + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qevent.h> +#include <qpainter.h> +#include <qptrlist.h> + +#include <kglobal.h> +#include <kdebug.h> +#include <klocale.h> +#include <kiconloader.h> + +#include <libkcal/vcaldrag.h> +#include <libkcal/icaldrag.h> +#include <libkcal/dndfactory.h> +#include <libkcal/calendarresources.h> +#include <libkcal/resourcecalendar.h> + +#include <kcalendarsystem.h> + +#include "koprefs.h" +#include "koglobals.h" +#include "kodialogmanager.h" + +#include "kodaymatrix.h" +#include "kodaymatrix.moc" + +#ifndef NODND +#include <qcursor.h> +#include <kpopupmenu.h> +#include <X11/Xlib.h> +#undef FocusIn +#undef KeyPress +#undef None +#undef Status +#endif + +// ============================================================================ +// D Y N A M I C T I P +// ============================================================================ + +DynamicTip::DynamicTip( QWidget * parent ) + : QToolTip( parent ) +{ + mMatrix = static_cast<KODayMatrix *>( parent ); +} + + +void DynamicTip::maybeTip( const QPoint &pos ) +{ + //calculate which cell of the matrix the mouse is in + QRect sz = mMatrix->frameRect(); + int dheight = sz.height() * 7 / 42; + int dwidth = sz.width() / 7; + int row = pos.y() / dheight; + int col = pos.x() / dwidth; + + QRect rct( col * dwidth, row * dheight, dwidth, dheight ); + +// kdDebug(5850) << "DynamicTip::maybeTip matrix cell index [" << +// col << "][" << row << "] => " <<(col+row*7) << endl; + + //show holiday names only + QString str = mMatrix->getHolidayLabel( col + row * 7 ); + if ( str.isEmpty() ) return; + tip( rct, str ); +} + + +// ============================================================================ +// K O D A Y M A T R I X +// ============================================================================ + +const int KODayMatrix::NOSELECTION = -1000; +const int KODayMatrix::NUMDAYS = 42; + +KODayMatrix::KODayMatrix( QWidget *parent, const char *name ) + : QFrame( parent, name ), mCalendar( 0 ), mStartDate(), mPendingChanges( false ) +{ + // initialize dynamic arrays + mDays = new QDate[ NUMDAYS ]; + mDayLabels = new QString[ NUMDAYS ]; + mEvents = new int[ NUMDAYS ]; + mToolTip = new DynamicTip( this ); + + mTodayMarginWidth = 2; + mSelEnd = mSelStart = NOSELECTION; + setBackgroundMode( NoBackground ); + recalculateToday(); +} + +void KODayMatrix::setCalendar( Calendar *cal ) +{ + if ( mCalendar ) { + mCalendar->unregisterObserver( this ); + mCalendar->disconnect( this ); + } + + mCalendar = cal; + mCalendar->registerObserver( this ); + CalendarResources *calres = dynamic_cast<CalendarResources*>( cal ); + if ( calres ) { + connect( calres, SIGNAL(signalResourceAdded(ResourceCalendar *)), SLOT(resourcesChanged()) ); + connect( calres, SIGNAL(signalResourceModified( ResourceCalendar *)), SLOT(resourcesChanged()) ); + connect( calres, SIGNAL(signalResourceDeleted(ResourceCalendar *)), SLOT(resourcesChanged()) ); + } + + setAcceptDrops( mCalendar ); + + updateEvents(); +} + +QColor KODayMatrix::getShadedColor( const QColor &color ) +{ + QColor shaded; + int h = 0; + int s = 0; + int v = 0; + color.hsv( &h, &s, &v ); + s = s / 4; + v = 192 + v / 4; + shaded.setHsv( h, s, v ); + + return shaded; +} + +KODayMatrix::~KODayMatrix() +{ + if ( mCalendar ) + mCalendar->unregisterObserver( this ); + delete [] mDays; + delete [] mDayLabels; + delete [] mEvents; + delete mToolTip; +} + +void KODayMatrix::addSelectedDaysTo( DateList &selDays ) +{ + kdDebug(5850) << "KODayMatrix::addSelectedDaysTo() - " << "mSelStart:" << mSelStart << endl; + + if ( mSelStart == NOSELECTION ) { + return; + } + + // cope with selection being out of matrix limits at top (< 0) + int i0 = mSelStart; + if ( i0 < 0 ) { + for ( int i = i0; i < 0; i++ ) { + selDays.append( mDays[ 0 ].addDays( i ) ); + } + i0 = 0; + } + + // cope with selection being out of matrix limits at bottom (> NUMDAYS-1) + if ( mSelEnd > NUMDAYS-1 ) { + for ( int i = i0; i <= NUMDAYS - 1; i++ ) { + selDays.append( mDays[ i ] ); + } + for ( int i = NUMDAYS; i < mSelEnd; i++ ) { + selDays.append( mDays[ 0 ].addDays( i ) ); + } + } else { + // apply normal routine to selection being entirely within matrix limits + for ( int i = i0; i <= mSelEnd; i++ ) { + selDays.append( mDays[ i ] ); + } + } +} + +void KODayMatrix::setSelectedDaysFrom( const QDate &start, const QDate &end ) +{ + if ( mStartDate.isValid() ) { + mSelStart = mStartDate.daysTo( start ); + mSelEnd = mStartDate.daysTo( end ); + } +} + +void KODayMatrix::clearSelection() +{ + mSelEnd = mSelStart = NOSELECTION; +} + +void KODayMatrix::recalculateToday() +{ + if ( !mStartDate.isValid() ) return; + mToday = -1; + for ( int i = 0; i < NUMDAYS; i++ ) { + mDays[ i ] = mStartDate.addDays( i ); + mDayLabels[ i ] = QString::number( KOGlobals::self()->calendarSystem()->day( mDays[i] )); + + // if today is in the currently displayed month, hilight today + if ( mDays[ i ].year() == QDate::currentDate().year() && + mDays[ i ].month() == QDate::currentDate().month() && + mDays[ i ].day() == QDate::currentDate().day() ) { + mToday = i; + } + } + // kdDegug(5850) << "Today is visible at "<< today << "." << endl; +} + +/* slot */ void KODayMatrix::updateView() +{ + updateView( mStartDate ); +} + +void KODayMatrix::updateView( const QDate &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; + + // if a new startdate is to be set then apply Cornelius's calculation + // of the first day to be shown + if ( actdate != mStartDate ) { + // reset index of selection according to shift of starting date from startdate to actdate + if ( mSelStart != NOSELECTION ) { + int tmp = actdate.daysTo( mStartDate ); + //kdDebug(5850) << "Shift of Selection1: " << mSelStart << " - " << mSelEnd << " -> " << tmp << "(" << offset << ")" << endl; + // shift selection if new one would be visible at least partly ! + + if ( mSelStart + tmp < NUMDAYS && mSelEnd + tmp >= 0 ) { + // nested if is required for next X display pushed from a different month - correction required + // otherwise, for month forward and backward, it must be avoided + if( mSelStart > NUMDAYS || mSelStart < 0 ) + mSelStart = mSelStart + tmp; + if( mSelEnd > NUMDAYS || mSelEnd < 0 ) + mSelEnd = mSelEnd + tmp; + } + } + + mStartDate = actdate; + daychanged = true; + } + + if ( daychanged ) { + recalculateToday(); + } + + // the calendar hasn't changed in the meantime and the selected range is still the same + // so we can safe the expensive updateEvents() call + if ( !daychanged && !mPendingChanges ) + return; + + // TODO_Recurrence: If we just change the selection, but not the data, there's + // no need to update the whole list of events... This is just a waste of + // computational power (and it takes forever!) + updateEvents(); + for( int i = 0; i < NUMDAYS; i++ ) { + //if it is a holy day then draw it red. Sundays are consider holidays, too + QStringList holidays = KOGlobals::self()->holiday( mDays[ i ] ); + QString holiStr = QString::null; + + if ( ( KOGlobals::self()->calendarSystem()->dayOfWeek( mDays[ i ] ) == + KOGlobals::self()->calendarSystem()->weekDayOfPray() ) || + !holidays.isEmpty() ) { + if ( !holidays.isEmpty() ) holiStr = holidays.join( i18n("delimiter for joining holiday names", ", " ) ); + if ( holiStr.isNull() ) holiStr = ""; + } + mHolidays[ i ] = holiStr; + } +} + +void KODayMatrix::updateEvents() +{ + kdDebug( 5850 ) << k_funcinfo << endl; + if ( !mCalendar ) return; + + for( int i = 0; i < NUMDAYS; i++ ) { + // if events are set for the day then remember to draw it bold + Event::List eventlist = mCalendar->events( mDays[ i ] ); + int numEvents = eventlist.count(); + Event::List::ConstIterator it; + for( it = eventlist.begin(); it != eventlist.end(); ++it ) { + Event *event = *it; + ushort recurType = event->recurrenceType(); + if ( ( recurType == Recurrence::rDaily && + !KOPrefs::instance()->mDailyRecur ) || + ( recurType == Recurrence::rWeekly && + !KOPrefs::instance()->mWeeklyRecur ) ) { + numEvents--; + } + } + mEvents[ i ] = numEvents; + } + + mPendingChanges = false; +} + +const QDate& KODayMatrix::getDate( int offset ) +{ + if ( offset < 0 || offset > NUMDAYS - 1 ) { + kdDebug(5850) << "Wrong offset (" << offset << ") in KODayMatrix::getDate(int)" << endl; + return mDays[ 0 ]; + } + return mDays[ offset ]; +} + +QString KODayMatrix::getHolidayLabel( int offset ) +{ + if ( offset < 0 || offset > NUMDAYS - 1 ) { + kdDebug(5850) << "Wrong offset (" << offset << ") in KODayMatrix::getHolidayLabel(int)" << endl; + return 0; + } + return mHolidays[ offset ]; +} + +int KODayMatrix::getDayIndexFrom( int x, int y ) +{ + return 7 * ( y / mDaySize.height() ) + + ( KOGlobals::self()->reverseLayout() ? + 6 - x / mDaySize.width() : x / mDaySize.width() ); +} + +void KODayMatrix::calendarIncidenceAdded(Incidence * incidence) +{ + mPendingChanges = true; +} + +void KODayMatrix::calendarIncidenceChanged(Incidence * incidence) +{ + mPendingChanges = true; +} + +void KODayMatrix::calendarIncidenceRemoved(Incidence * incidence) +{ + mPendingChanges = true; +} + +void KODayMatrix::resourcesChanged() +{ + mPendingChanges = true; +} + + +// ---------------------------------------------------------------------------- +// M O U S E E V E N T H A N D L I N G +// ---------------------------------------------------------------------------- + +void KODayMatrix::mousePressEvent( QMouseEvent *e ) +{ + mSelStart = getDayIndexFrom(e->x(), e->y()); + if (mSelStart > NUMDAYS-1) mSelStart=NUMDAYS-1; + mSelInit = mSelStart; +} + +void KODayMatrix::mouseReleaseEvent( QMouseEvent *e ) +{ + int tmp = getDayIndexFrom(e->x(), e->y()); + if (tmp > NUMDAYS-1) tmp=NUMDAYS-1; + + if (mSelInit > tmp) { + mSelEnd = mSelInit; + if (tmp != mSelStart) { + mSelStart = tmp; + repaint(); + } + } else { + mSelStart = mSelInit; + + //repaint only if selection has changed + if (tmp != mSelEnd) { + mSelEnd = tmp; + repaint(); + } + } + + DateList daylist; + if ( mSelStart < 0 ) mSelStart = 0; + for ( int i = mSelStart; i <= mSelEnd; ++i ) { + daylist.append( mDays[i] ); + } + emit selected((const DateList)daylist); +} + +void KODayMatrix::mouseMoveEvent( QMouseEvent *e ) +{ + int tmp = getDayIndexFrom(e->x(), e->y()); + if (tmp > NUMDAYS-1) tmp=NUMDAYS-1; + + if (mSelInit > tmp) { + mSelEnd = mSelInit; + if (tmp != mSelStart) { + mSelStart = tmp; + repaint(); + } + } else { + mSelStart = mSelInit; + + //repaint only if selection has changed + if (tmp != mSelEnd) { + mSelEnd = tmp; + repaint(); + } + } +} + +// ---------------------------------------------------------------------------- +// D R A G ' N D R O P H A N D L I N G +// ---------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Drag and Drop handling -- based on the Troll Tech dirview example + +enum { + DRAG_COPY = 0, + DRAG_MOVE = 1, + DRAG_CANCEL = 2 +}; + +void KODayMatrix::dragEnterEvent( QDragEnterEvent *e ) +{ +#ifndef KORG_NODND + if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) ) { + e->ignore(); + return; + } + + // some visual feedback +// oldPalette = palette(); +// setPalette(my_HilitePalette); +// update(); +#endif +} + +void KODayMatrix::dragMoveEvent( QDragMoveEvent *e ) +{ +#ifndef KORG_NODND + if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) ) { + e->ignore(); + return; + } + + e->accept(); +#endif +} + +void KODayMatrix::dragLeaveEvent( QDragLeaveEvent * /*dl*/ ) +{ +#ifndef KORG_NODND +// setPalette(oldPalette); +// update(); +#endif +} + +void KODayMatrix::dropEvent( QDropEvent *e ) +{ +#ifndef KORG_NODND + kdDebug(5850) << "KODayMatrix::dropEvent(e) begin" << endl; + + if ( !mCalendar || + ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) ) ) { + e->ignore(); + return; + } + + DndFactory factory( mCalendar ); + Event *event = factory.createDrop( e ); + Todo *todo = factory.createDropTodo( e ); + if ( !event && !todo ) { + e->ignore(); + return; + } + + Todo *existingTodo = 0; + Event *existingEvent = 0; + + // Find the incidence in the calendar, then we don't need the drag object any more + if ( event ) existingEvent = mCalendar->event( event->uid() ); + if ( todo ) existingTodo = mCalendar->todo( todo->uid() ); + + int action = DRAG_CANCEL; + + int root_x, root_y, win_x, win_y; + uint keybstate; + Window rootw, childw; + XQueryPointer( qt_xdisplay(), qt_xrootwin(), &rootw, &childw, + &root_x, &root_y, &win_x, &win_y, &keybstate ); + + if ( keybstate & ControlMask ) { + action = DRAG_COPY; + } else if ( keybstate & ShiftMask ) { + action = DRAG_MOVE; + } else { + KPopupMenu *menu = new KPopupMenu( this ); + if ( existingEvent || existingTodo ) { + menu->insertItem( i18n("Move"), DRAG_MOVE, 0 ); + if (existingEvent) + menu->insertItem( KOGlobals::self()->smallIcon("editcopy"), i18n("Copy"), DRAG_COPY, 1 ); + } else { + menu->insertItem( i18n("Add"), DRAG_MOVE, 0 ); + } + menu->insertSeparator(); + menu->insertItem( KOGlobals::self()->smallIcon("cancel"), i18n("Cancel"), DRAG_CANCEL, 3 ); + action = menu->exec( QCursor::pos(), 0 ); + } + + if ( action == DRAG_COPY || action == DRAG_MOVE ) { + e->accept(); + int idx = getDayIndexFrom( e->pos().x(), e->pos().y() ); + + if ( action == DRAG_COPY ) { + if ( event ) emit incidenceDropped( event, mDays[idx] ); + if ( todo ) emit incidenceDropped( todo, mDays[idx] ); + } else if ( action == DRAG_MOVE ) { + if ( event ) emit incidenceDroppedMove( event, mDays[idx] ); + if ( todo ) emit incidenceDroppedMove( todo, mDays[idx] ); + } + } + delete event; + delete todo; +#endif +} + +// ---------------------------------------------------------------------------- +// P A I N T E V E N T H A N D L I N G +// ---------------------------------------------------------------------------- + +void KODayMatrix::paintEvent( QPaintEvent * ) +{ +// kdDebug(5850) << "KODayMatrix::paintEvent() BEGIN" << endl; + + QPainter p; + QRect sz = frameRect(); + QPixmap pm( sz.size() ); + int dheight = mDaySize.height(); + int dwidth = mDaySize.width(); + int row,col; + int selw, selh; + bool isRTL = KOGlobals::self()->reverseLayout(); + + QColorGroup cg = palette().active(); + + p.begin( &pm, this ); + pm.fill( cg.base() ); + + // draw topleft frame + p.setPen( cg.mid() ); + p.drawRect(0, 0, sz.width()-1, sz.height()-1); + // don't paint over borders + p.translate(1,1); + + // draw selected days with highlighted background color + if (mSelStart != NOSELECTION) { + + row = mSelStart/7; + // fix larger selections starting in the previous month + if ( row < 0 && mSelEnd > 0 ) row = 0; + col = mSelStart -row*7; + QColor selcol = KOPrefs::instance()->mHighlightColor; + + if ( row < 6 && row >= 0 ) { + if (row == mSelEnd/7) { + // Single row selection + p.fillRect(isRTL ? (7 - (mSelEnd-mSelStart+1) - col)*dwidth : col*dwidth, + row*dheight, (mSelEnd-mSelStart+1)*dwidth, dheight, selcol); + } else { + // draw first row to the right + p.fillRect(isRTL ? 0 : col*dwidth, row*dheight, (7-col)*dwidth, + dheight, selcol); + // draw full block till last line + selh = mSelEnd/7-row; + if ( selh + row >= 6 ) selh = 6-row; + if ( selh > 1 ) { + p.fillRect(0, (row+1)*dheight, 7*dwidth, (selh-1)*dheight,selcol); + } + // draw last block from left to mSelEnd + if ( mSelEnd/7 < 6 ) { + selw = mSelEnd-7*(mSelEnd/7)+1; + p.fillRect(isRTL ? (7-selw)*dwidth : 0, (row+selh)*dheight, + selw*dwidth, dheight, selcol); + } + } + } + } + + // iterate over all days in the matrix and draw the day label in appropriate colors + QColor textColor = cg.text(); + QColor textColorShaded = getShadedColor( textColor ); + QColor actcol = textColorShaded; + p.setPen(actcol); + QPen tmppen; + for ( int i = 0; i < NUMDAYS; ++i ) { + row = i/7; + col = isRTL ? 6-(i-row*7) : i-row*7; + + // if it is the first day of a month switch color from normal to shaded and vice versa + if ( KOGlobals::self()->calendarSystem()->day( mDays[i] ) == 1) { + if (actcol == textColorShaded) { + actcol = textColor; + } else { + actcol = textColorShaded; + } + p.setPen(actcol); + } + + //Reset pen color after selected days block + if (i == mSelEnd+1) { + p.setPen(actcol); + } + + bool holiday = ! KOGlobals::self()->isWorkDay( mDays[ i ] ); + + QColor holidayColorShaded = getShadedColor( KOPrefs::instance()->mHolidayColor ); + // if today then draw rectangle around day + if (mToday == i) { + tmppen = p.pen(); + QPen mTodayPen(p.pen()); + + mTodayPen.setWidth(mTodayMarginWidth); + //draw red rectangle for holidays + if (holiday) { + if (actcol == textColor) { + mTodayPen.setColor(KOPrefs::instance()->mHolidayColor); + } else { + mTodayPen.setColor(holidayColorShaded); + } + } + //draw gray rectangle for today if in selection + if (i >= mSelStart && i <= mSelEnd) { + QColor grey("grey"); + mTodayPen.setColor(grey); + } + p.setPen(mTodayPen); + p.drawRect(col*dwidth, row*dheight, dwidth, dheight); + p.setPen(tmppen); + } + + // if any events are on that day then draw it using a bold font + if (mEvents[i] > 0) { + QFont myFont = font(); + myFont.setBold(true); + p.setFont(myFont); + } + + // if it is a holiday then use the default holiday color + if (holiday) { + if (actcol == textColor) { + p.setPen(KOPrefs::instance()->mHolidayColor); + } else { + p.setPen(holidayColorShaded); + } + } + + // draw selected days with special color + // DO NOT specially highlight holidays in selection ! + if (i >= mSelStart && i <= mSelEnd) { + p.setPen( QColor( "white" ) ); + } + + p.drawText(col*dwidth, row*dheight, dwidth, dheight, + Qt::AlignHCenter | Qt::AlignVCenter, mDayLabels[i]); + + // reset color to actual color + if (holiday) { + p.setPen(actcol); + } + // reset bold font to plain font + if (mEvents[i] > 0) { + QFont myFont = font(); + myFont.setBold(false); + p.setFont(myFont); + } + } + p.end(); + bitBlt( this, 0, 0, &pm ); +} + +// ---------------------------------------------------------------------------- +// R E SI Z E E V E N T H A N D L I N G +// ---------------------------------------------------------------------------- + +void KODayMatrix::resizeEvent( QResizeEvent * ) +{ + QRect sz = frameRect(); + mDaySize.setHeight( sz.height() * 7 / NUMDAYS ); + mDaySize.setWidth( sz.width() / 7 ); +} diff --git a/korganizer/kodaymatrix.h b/korganizer/kodaymatrix.h new file mode 100644 index 000000000..a76e61874 --- /dev/null +++ b/korganizer/kodaymatrix.h @@ -0,0 +1,318 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001 Eitzenberger Thomas <thomas.eitzenberger@siemens.at> + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KODAYMATRIX_H +#define KODAYMATRIX_H + +#include <libkcal/incidencebase.h> +#include <libkcal/calendar.h> + +#include <qframe.h> +#include <qcolor.h> +#include <qtooltip.h> +#include <qmap.h> + +class QDragEnterEvent; +class QDragMoveEvent; +class QDragLeaveEvent; +class QDropEvent; + +class KODayMatrix; + +namespace KCal { +class Incidence; +class Calendar; +} +using namespace KCal; + + +/** + * small helper class to dynamically show tooltips inside the day matrix. + * This class asks the day matrix object for a appropriate label which + * is in our special case the name of the holiday or null if this day is no holiday. + */ +class DynamicTip : public QToolTip +{ + public: + /** + * Constructor that expects a KODayMatrix object as parent. + * + * @param parent the parent KODayMatrix control. + */ + DynamicTip( QWidget *parent ); + + protected: + /** + * Qt's callback to ask the object to provide an approrpiate text for the + * tooltip to be shown. + * + * @param pos coordinates of the mouse. + */ + void maybeTip( const QPoint &pos ); + + private: + /** the parent control this tooltip is designed for. */ + KODayMatrix *mMatrix; +}; + +/** + * Replacement for kdpdatebuton.cpp that used 42 widgets for the day matrix to be displayed. + * Cornelius thought this was a waste of memory and a lot of overhead. + * In addition the selection was not very intuitive so I decided to rewrite it using a QFrame + * that draws the labels and allows for dragging selection while maintaining nearly full + * compatibility in behavior with its predecessor. + * + * The following functionality has been changed: + * + * o when shifting events in the agenda view from one day to another the day matrix is updated now + * o dragging an event to the matrix will MOVE not COPY the event to the new date. + * o no support for Ctrl+click to create groups of dates + * (This has not really been supported in the predecessor. It was not very intuitive nor was it + * user friendly.) + * This feature has been replaced with dragging a selection on the matrix. The matrix will + * automatically choose the appropriate selection (e.g. you are not any longer able to select + * two distinct groups of date selections as in the old class) + * o now that you can select more then a week it can happen that not all selected days are + * displayed in the matrix. However this is preferred to the alternative which would mean to + * adjust the selection and leave some days undisplayed while scrolling through the months + * + * @short day matrix widget of the KDateNavigator + * + * @author Eitzenberger Thomas + */ +class KODayMatrix: public QFrame, public KCal::Calendar::Observer +{ + Q_OBJECT + public: + /** constructor to create a day matrix widget. + * + * @param parent widget that is the parent of the day matrix. + * Normally this should be a KDateNavigator + * @param name name of the widget + */ + KODayMatrix( QWidget *parent, const char *name ); + + /** destructor that deallocates all dynamically allocated private members. + */ + ~KODayMatrix(); + + /** + 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. + */ + void setCalendar( Calendar * ); + + /** updates the day matrix to start with the given date. Does all the necessary + * checks for holidays or events on a day and stores them for display later on. + * Does NOT update the view visually. Call repaint() for this. + * + * @param actdate recalculates the day matrix to show NUMDAYS starting from this + * date. + */ + void updateView( const QDate &actdate ); + + /** + Update event states of dates. Depending of the preferences days with + events are highlighted in some way. + */ + void updateEvents(); + + /** returns the QDate object associated with day indexed by the + * supplied offset. + */ + const QDate& getDate( int offset ); + + /** returns the official name of this holy day or 0 if there is no label + * for this day. + */ + QString getHolidayLabel( int offset ); + + /** adds all actual selected days from mSelStart to mSelEnd to the supplied + * DateList. + */ + void addSelectedDaysTo( DateList & ); + + /** sets the actual to be displayed selection in the day matrix starting from + * start and ending with end. Theview must be manually updated by calling + * repaint. (?) + */ + void setSelectedDaysFrom( const QDate &start, const QDate &end ); + + /** + Clear all selections. + */ + void clearSelection(); + + /** Is today visible in the view? Keep this in sync with + * the values today (below) can take. + */ + bool isTodayVisible() const { return mToday >= 0; } + + /** If today is visible, then we can find out if today is + * near the beginning or the end of the month. + * This is dependent on today remaining the index + * in the array of visible dates and going from + * top left (0) to bottom right (41). + */ + bool isBeginningOfMonth() const { return mToday <= 8; } + bool isEndOfMonth() const { return mToday >= 27; } + + /* reimplmented from KCal::Calendar::Observer */ + void calendarIncidenceAdded( Incidence *incidence ); + void calendarIncidenceChanged( Incidence *incidence ); + void calendarIncidenceRemoved( Incidence *incidence ); + + public slots: + /** Recalculates all the flags of the days in the matrix like holidays or events + * on a day (Actually calls above method with the actual startdate). + */ + void updateView(); + + /** + * Calculate which square in the matrix should be + * hilighted to indicate it's today. + */ + void recalculateToday(); + + /** + * Handle resource changes. + */ + void resourcesChanged(); + + signals: + /** emitted if the user selects a block of days with the mouse by dragging a rectangle + * inside the matrix + * + * @param daylist list of days that have been selected by the user + */ + void selected( const KCal::DateList &daylist ); + + /** emitted if the user has dropped an incidence (event or todo) inside the matrix + * + * @param incidence the dropped calendar incidence + * @param dt QDate that has been selected + */ + void incidenceDropped( Incidence *incidence, const QDate &dt ); + /** emitted if the user has dropped an event inside the matrix and chose to move it instead of copy + * + * @param oldincidence the new calendar incidence + * @param dt QDate that has been selected + */ + void incidenceDroppedMove( Incidence *oldincidence, const QDate &dt ); + + protected: + void paintEvent( QPaintEvent *ev ); + + void mousePressEvent( QMouseEvent *e ); + + void mouseReleaseEvent( QMouseEvent *e ); + + void mouseMoveEvent( QMouseEvent *e ); + + void dragEnterEvent( QDragEnterEvent * ); + + void dragMoveEvent( QDragMoveEvent * ); + + void dragLeaveEvent( QDragLeaveEvent * ); + + void dropEvent( QDropEvent * ); + + void resizeEvent( QResizeEvent * ); + + private: + /** returns the index of the day located at the matrix's widget (x,y) position. + * + * @param x horizontal coordinate + * @param y vertical coordinate + */ + int getDayIndexFrom( int x, int y ); + + /** calculates a "shaded" color from the supplied color object. + * (Copied from Cornelius's kdpdatebutton.cpp) + * + * @param color source based on which a shaded color should be calculated. + */ + QColor getShadedColor( const QColor &color ); + + /** number of days to be displayed. For now there is no support for any other number then 42. + so change it at your own risk :o) */ + static const int NUMDAYS; + + /** calendar instance to be queried for holidays, events, ... */ + Calendar *mCalendar; + + /** starting date of the matrix */ + QDate mStartDate; + + /** array of day labels to optimeize drawing performance. */ + QString *mDayLabels; + + /** array of days displayed to reduce memory consumption by + subsequently calling QDate::addDays(). */ + QDate *mDays; + + /** array of storing the number of events on a given day. + * used for drawing a bold font if there is at least one event on that day. + */ + int *mEvents; + + /** stores holiday names of the days shown in the matrix. */ + QMap<int,QString> mHolidays; + + /** index of today or -1 if today is not visible in the matrix. */ + int mToday; + + /** index of day where dragged selection was initiated. + used to detect "negative" timely selections */ + int mSelInit; + + /** if mSelStart has this value it indicates that there is no + actual selection in the matrix. */ + static const int NOSELECTION; + + /** index of first selected day. */ + int mSelStart; + + /** index of last selected day. */ + int mSelEnd; + + /** dynamic tooltip to handle mouse dependent tips for each day in the matrix. */ + DynamicTip* mToolTip; + + /** default width of the frame drawn around today if it is visible in the matrix. */ + int mTodayMarginWidth; + + /** stores actual size of each day in the widget so that I don't need to ask this data + * on every repaint. + */ + QRect mDaySize; + + /** + * Indicate pending calendar changes. + */ + bool mPendingChanges; +}; + +#endif diff --git a/korganizer/kodialogmanager.cpp b/korganizer/kodialogmanager.cpp new file mode 100644 index 000000000..908b74913 --- /dev/null +++ b/korganizer/kodialogmanager.cpp @@ -0,0 +1,288 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <kcmultidialog.h> +#include <ksettings/dialog.h> +#include <kwin.h> + +#include <libkdepim/categoryeditdialog.h> + +#include "calendarview.h" +#include "koprefsdialog.h" +#include "koprefs.h" +#include "koeventeditor.h" +#include "kotodoeditor.h" +#include "kojournaleditor.h" +#include "searchdialog.h" +#include "filtereditdialog.h" +#ifndef KORG_NOARCHIVE +#include "archivedialog.h" +#endif +#include "koviewmanager.h" +#include "koagendaview.h" +#include "koglobals.h" + +#include "kodialogmanager.h" +#include "kodialogmanager.moc" + + +// FIXME: Handle KOEventViewerDialogs in dialog manager. Pass +// KOPrefs::mCompactDialog. + +class KODialogManager::DialogManagerVisitor : public IncidenceBase::Visitor +{ + public: + DialogManagerVisitor() : mDialogManager( 0 ) {} + + bool act( IncidenceBase *incidence, KODialogManager *manager ) + { + mDialogManager = manager; + return incidence->accept( *this ); + } + + protected: + KODialogManager *mDialogManager; +}; + +class KODialogManager::EditorDialogVisitor : + public KODialogManager::DialogManagerVisitor +{ + public: + EditorDialogVisitor() : DialogManagerVisitor(), mEditor( 0 ) {} + KOIncidenceEditor *editor() const { return mEditor; } + protected: + bool visit( Event * ) { mEditor = mDialogManager->getEventEditor(); return mEditor; } + bool visit( Todo * ) { mEditor = mDialogManager->getTodoEditor(); return mEditor; } + bool visit( Journal * ) { mEditor = mDialogManager->getJournalEditor(); return mEditor; } + protected: + KOIncidenceEditor *mEditor; +}; + + +KODialogManager::KODialogManager( CalendarView *mainView ) : + QObject(), mMainView( mainView ) +{ + mOptionsDialog = 0; + mSearchDialog = 0; + mArchiveDialog = 0; + mFilterEditDialog = 0; + + mCategoryEditDialog = new KPIM::CategoryEditDialog( KOPrefs::instance(), mMainView ); + // don't set any specific parent for the dialog, as its kept around and reused + // in different cases where it should have different parents + KWin::setMainWindow( mCategoryEditDialog, 0 ); + connect( mainView, SIGNAL( categoriesChanged() ), + mCategoryEditDialog, SLOT( reload() ) ); + KOGlobals::fitDialogToScreen( mCategoryEditDialog ); +} + +KODialogManager::~KODialogManager() +{ + delete mOptionsDialog; + delete mSearchDialog; +#ifndef KORG_NOARCHIVE + delete mArchiveDialog; +#endif + delete mFilterEditDialog; +} + +void KODialogManager::errorSaveIncidence( QWidget *parent, Incidence *incidence ) +{ + KMessageBox::sorry( parent, i18n("Unable to save %1 \"%2\".") + .arg( i18n( incidence->type() ) ) + .arg( incidence->summary() ) ); +} + +void KODialogManager::showOptionsDialog() +{ + if (!mOptionsDialog) { +#if 0 + mOptionsDialog = new KConfigureDialog(); +// mOptionsDialog = new KConfigureDialog( KConfigureDialog::Configurable ); +// mOptionsDialog = new KConfigureDialog( mMainView ); + connect( mOptionsDialog->dialog(), + SIGNAL( configCommitted( const QCString & ) ), + mMainView, SLOT( updateConfig() ) ); +#else + mOptionsDialog = new KCMultiDialog( mMainView, "KorganizerPreferences" ); + connect( mOptionsDialog, SIGNAL( configCommitted( const QCString & ) ), + mMainView, SLOT( updateConfig( const QCString& ) ) ); +#if 0 + connect( mOptionsDialog, SIGNAL( applyClicked() ), + mMainView, SLOT( updateConfig() ) ); + connect( mOptionsDialog, SIGNAL( okClicked() ), + mMainView, SLOT( updateConfig() ) ); + // @TODO Find a way to do this with KCMultiDialog + connect(mCategoryEditDialog,SIGNAL(categoryConfigChanged()), + mOptionsDialog,SLOT(updateCategories())); +#endif + + QStringList modules; + + modules.append( "korganizer_configmain.desktop" ); + modules.append( "korganizer_configtime.desktop" ); + modules.append( "korganizer_configviews.desktop" ); + modules.append( "korganizer_configfonts.desktop" ); + modules.append( "korganizer_configcolors.desktop" ); + modules.append( "korganizer_configgroupscheduling.desktop" ); + modules.append( "korganizer_configgroupautomation.desktop" ); + modules.append( "korganizer_configfreebusy.desktop" ); + modules.append( "korganizer_configplugins.desktop" ); + modules.append( "korganizer_configdesignerfields.desktop" ); + + // add them all + QStringList::iterator mit; + for ( mit = modules.begin(); mit != modules.end(); ++mit ) + mOptionsDialog->addModule( *mit ); +#endif + } + + mOptionsDialog->show(); + mOptionsDialog->raise(); +} + +void KODialogManager::showCategoryEditDialog() +{ + mCategoryEditDialog->show(); +} + +void KODialogManager::showSearchDialog() +{ + if (!mSearchDialog) { + mSearchDialog = new SearchDialog(mMainView->calendar(),mMainView); + connect(mSearchDialog,SIGNAL(showIncidenceSignal(Incidence *)), + mMainView,SLOT(showIncidence(Incidence *))); + connect(mSearchDialog,SIGNAL(editIncidenceSignal(Incidence *)), + mMainView,SLOT(editIncidence(Incidence *))); + connect(mSearchDialog,SIGNAL(deleteIncidenceSignal(Incidence *)), + mMainView, SLOT(deleteIncidence(Incidence *))); + connect(mMainView,SIGNAL(closingDown()),mSearchDialog,SLOT(reject())); + } + // make sure the widget is on top again + mSearchDialog->show(); + mSearchDialog->raise(); +} + +void KODialogManager::showArchiveDialog() +{ +#ifndef KORG_NOARCHIVE + if (!mArchiveDialog) { + mArchiveDialog = new ArchiveDialog(mMainView->calendar(),mMainView); + connect(mArchiveDialog,SIGNAL(eventsDeleted()), + mMainView,SLOT(updateView())); + connect(mArchiveDialog,SIGNAL(autoArchivingSettingsModified()), + mMainView,SLOT(slotAutoArchivingSettingsModified())); + } + mArchiveDialog->show(); + mArchiveDialog->raise(); + + // Workaround. + QApplication::restoreOverrideCursor(); +#endif +} + +void KODialogManager::showFilterEditDialog( QPtrList<CalFilter> *filters ) +{ + if ( !mFilterEditDialog ) { + mFilterEditDialog = new FilterEditDialog( filters, mMainView ); + connect( mFilterEditDialog, SIGNAL( filterChanged() ), + mMainView, SLOT( updateFilter() ) ); + connect( mFilterEditDialog, SIGNAL( editCategories() ), + mCategoryEditDialog, SLOT( show() ) ); + connect( mCategoryEditDialog, SIGNAL( categoryConfigChanged() ), + mFilterEditDialog, SLOT( updateCategoryConfig() ) ); + } + mFilterEditDialog->show(); + mFilterEditDialog->raise(); +} + +KOIncidenceEditor *KODialogManager::getEditor( Incidence *incidence ) +{ + if ( !incidence ) return 0; + EditorDialogVisitor v; + if ( v.act( incidence, this ) ) { + return v.editor(); + } else + return 0; +} + +KOEventEditor *KODialogManager::getEventEditor() +{ + KOEventEditor *eventEditor = new KOEventEditor( mMainView->calendar(), + mMainView ); + connectEditor( eventEditor ); + return eventEditor; +} + +void KODialogManager::connectTypeAhead( KOEventEditor *editor, + KOrg::AgendaView *agenda ) +{ + if ( editor && agenda ) { + agenda->setTypeAheadReceiver( editor->typeAheadReceiver() ); + connect( editor, SIGNAL( focusReceivedSignal() ), + agenda, SLOT( finishTypeAhead() ) ); + } +} + +void KODialogManager::connectEditor( KOIncidenceEditor*editor ) +{ + connect( editor, SIGNAL( deleteIncidenceSignal( Incidence * ) ), + mMainView, SLOT( deleteIncidence( Incidence * ) ) ); + + connect( mCategoryEditDialog, SIGNAL( categoryConfigChanged() ), + editor, SIGNAL( updateCategoryConfig() ) ); + connect( editor, SIGNAL( editCategories() ), + mCategoryEditDialog, SLOT( show() ) ); + + connect( editor, SIGNAL( dialogClose( Incidence * ) ), + mMainView, SLOT( dialogClosing( Incidence * ) ) ); + connect( editor, SIGNAL( editCanceled( Incidence * ) ), + mMainView, SLOT( editCanceled( Incidence * ) ) ); + connect( mMainView, SIGNAL( closingDown() ), editor, SLOT( reject() ) ); + + connect( editor, SIGNAL( deleteAttendee( Incidence * ) ), + mMainView, SIGNAL( cancelAttendees( Incidence * ) ) ); +} + +KOTodoEditor *KODialogManager::getTodoEditor() +{ + kdDebug(5850) << k_funcinfo << endl; + KOTodoEditor *todoEditor = new KOTodoEditor( mMainView->calendar(), mMainView ); + connectEditor( todoEditor ); + return todoEditor; +} + +KOJournalEditor *KODialogManager::getJournalEditor() +{ + KOJournalEditor *journalEditor = new KOJournalEditor( mMainView->calendar(), mMainView ); + connectEditor( journalEditor ); + return journalEditor; +} + +void KODialogManager::updateSearchDialog() +{ + if (mSearchDialog) mSearchDialog->updateView(); +} + diff --git a/korganizer/kodialogmanager.h b/korganizer/kodialogmanager.h new file mode 100644 index 000000000..50c52412f --- /dev/null +++ b/korganizer/kodialogmanager.h @@ -0,0 +1,95 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001,2004 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KODIALOGMANAGER_H +#define KODIALOGMANAGER_H + +#include <qobject.h> +#include <qptrlist.h> + +namespace KCal{class CalFilter; } +class CalendarView; +class KCMultiDialog; +class KConfigureDialog; +namespace KPIM { class CategoryEditDialog; } +class KOIncidenceEditor; +class KOEventEditor; +class KOTodoEditor; +class KOJournalEditor; +class SearchDialog; +class ArchiveDialog; +class FilterEditDialog; +namespace KOrg { class AgendaView; } + +using namespace KCal; + +/** + This class manages the dialogs used by the calendar view. It owns the objects + and handles creation and selection. +*/ +class KODialogManager : public QObject +{ + Q_OBJECT + public: + KODialogManager( CalendarView * ); + virtual ~KODialogManager(); + + /** Get the appropriate editor for the given incidence */ + KOIncidenceEditor *getEditor( Incidence * ); + /** Get an editor dialog for an Event. */ + KOEventEditor *getEventEditor(); + /** Get an editor dialog for a Todo. */ + KOTodoEditor *getTodoEditor(); + /** Get an editor dialog for a Journal. */ + KOJournalEditor *getJournalEditor(); + void connectEditor( KOIncidenceEditor*editor ); + + void updateSearchDialog(); + + void connectTypeAhead( KOEventEditor *editor, KOrg::AgendaView *agenda ); + + static void errorSaveIncidence( QWidget *parent, Incidence *incidence ); + + public slots: + void showOptionsDialog(); + void showCategoryEditDialog(); + void showSearchDialog(); + void showArchiveDialog(); + void showFilterEditDialog(QPtrList<CalFilter> *filters); + + private: + class DialogManagerVisitor; + class EditorDialogVisitor; + + CalendarView *mMainView; + + KCMultiDialog *mOptionsDialog; +// KConfigureDialog *mOptionsDialog; + KPIM::CategoryEditDialog *mCategoryEditDialog; + SearchDialog *mSearchDialog; + ArchiveDialog *mArchiveDialog; + FilterEditDialog *mFilterEditDialog; +}; + +#endif diff --git a/korganizer/koeditoralarms.cpp b/korganizer/koeditoralarms.cpp new file mode 100644 index 000000000..e14581e4d --- /dev/null +++ b/korganizer/koeditoralarms.cpp @@ -0,0 +1,388 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "koeditoralarms_base.h" +#include "koeditoralarms.h" + +#include <qlayout.h> +#include <qlistview.h> +#include <qpushbutton.h> +#include <qspinbox.h> +#include <qcombobox.h> +#include <qcheckbox.h> +#include <qbuttongroup.h> +#include <qtextedit.h> +#include <qwidgetstack.h> + +#include <kurlrequester.h> +#include <klocale.h> +#include <kdebug.h> + +#include <libkcal/alarm.h> +#include <libkcal/incidence.h> + +#include <libemailfunctions/email.h> + +class AlarmListViewItem : public QListViewItem +{ + public: + AlarmListViewItem( QListView *parent, KCal::Alarm *alarm ); + virtual ~AlarmListViewItem(); + KCal::Alarm *alarm() const { return mAlarm; } + void construct(); + enum AlarmViewColumns { ColAlarmType=0, ColAlarmOffset, ColAlarmRepeat }; + protected: + KCal::Alarm *mAlarm; +}; + +AlarmListViewItem::AlarmListViewItem( QListView *parent, KCal::Alarm *alarm ) + : QListViewItem( parent ) +{ + if ( alarm ) { + mAlarm = new KCal::Alarm( *alarm ); + } else { + mAlarm = new KCal::Alarm( 0 ); + } + construct(); +} + +AlarmListViewItem::~AlarmListViewItem() +{ + delete mAlarm; +} + +void AlarmListViewItem::construct() +{ + if ( mAlarm ) { + // Alarm type: + QString type; + switch ( mAlarm->type() ) { + case KCal::Alarm::Display: + type = i18n("Reminder Dialog"); + break; + case KCal::Alarm::Procedure: + type = i18n("Program"); + break; + case KCal::Alarm::Email: + type = i18n("Email"); + break; + case KCal::Alarm::Audio: + type = i18n("Audio"); + break; + default: + type = i18n("Unknown"); + break; + } + setText( ColAlarmType, type ); + + // Alarm offset: + QString offsetstr; + 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"); + offset = -offset; + } else { + 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"); + offset = -offset; + } else { + offsetstr = i18n("N days/hours/minutes before/after the start/end", "%1 after the end"); + } + } + + offset = offset / 60; // make minutes + int useoffset = offset; + + if ( offset % (24*60) == 0 && offset>0 ) { // divides evenly into days? + useoffset = offset / (24*60); + offsetstr = offsetstr.arg( i18n("1 day", "%n days", useoffset ) ); + } else if (offset % 60 == 0 && offset>0 ) { // divides evenly into hours? + useoffset = offset / 60; + offsetstr = offsetstr.arg( i18n("1 hour", "%n hours", useoffset ) ); + } else { + useoffset = offset; + offsetstr = offsetstr.arg( i18n("1 minute", "%n minutes", useoffset ) ); + } + setText( ColAlarmOffset, offsetstr ); + + // Alarm repeat + if ( mAlarm->repeatCount()>0 ) { + setText( ColAlarmRepeat, i18n("Yes") ); + } else { + setText( ColAlarmRepeat, i18n("No") ); + } + } +} + + +KOEditorAlarms::KOEditorAlarms( KCal::Alarm::List *alarms, QWidget *parent, + const char *name ) + : KDialogBase( parent, name, true, i18n("Edit Reminders"), Ok | Cancel ), mAlarms( alarms ),mCurrentItem(0L) +{ + setMainWidget( mWidget = new KOEditorAlarms_base( this ) ); + mWidget->mAlarmList->setColumnWidthMode( 0, QListView::Maximum ); + mWidget->mAlarmList->setColumnWidthMode( 1, QListView::Maximum ); + connect( mWidget->mAlarmList, SIGNAL( selectionChanged( QListViewItem * ) ), + SLOT( selectionChanged( QListViewItem * ) ) ); + connect( mWidget->mAddButton, SIGNAL( clicked() ), SLOT( slotAdd() ) ); + connect( mWidget->mRemoveButton, SIGNAL( clicked() ), SLOT( slotRemove() ) ); + connect( mWidget->mDuplicateButton, SIGNAL( clicked() ), SLOT( slotDuplicate() ) ); + + connect( mWidget->mAlarmOffset, SIGNAL( valueChanged( int ) ), SLOT( changed() ) ); + connect( mWidget->mOffsetUnit, SIGNAL( activated( int ) ), SLOT( changed() ) ); + connect( mWidget->mBeforeAfter, SIGNAL( activated( int ) ), SLOT( changed() ) ); + connect( mWidget->mRepeats, SIGNAL( toggled( bool ) ), SLOT( changed() ) ); + connect( mWidget->mRepeatCount, SIGNAL( valueChanged( int ) ), SLOT( changed() ) ); + connect( mWidget->mRepeatInterval, SIGNAL( valueChanged( int ) ), SLOT( changed() ) ); + connect( mWidget->mAlarmType, SIGNAL(clicked(int)), SLOT( changed() ) ); + connect( mWidget->mDisplayText, SIGNAL( textChanged() ), SLOT( changed() ) ); + connect( mWidget->mSoundFile, SIGNAL( textChanged( const QString & ) ), SLOT( changed() ) ); + connect( mWidget->mApplication, SIGNAL( textChanged( const QString & ) ), SLOT( changed() ) ); + connect( mWidget->mAppArguments, SIGNAL( textChanged( const QString & ) ), SLOT( changed() ) ); + connect( mWidget->mEmailAddress, SIGNAL( textChanged( const QString & ) ), SLOT( changed() ) ); + connect( mWidget->mEmailText, SIGNAL( textChanged() ), SLOT( changed() ) ); + + init(); +} + +KOEditorAlarms::~KOEditorAlarms() +{ +} + +void KOEditorAlarms::changed() +{ + if ( !mInitializing && mCurrentItem ) { + writeAlarm( mCurrentItem->alarm() ); + mCurrentItem->construct(); + } +} + +void KOEditorAlarms::readAlarm( KCal::Alarm *alarm ) +{ + if ( !alarm ) return; + + mInitializing = true; + + // Offsets + int offset; + int beforeafterpos = 0; + if ( alarm->hasEndOffset() ) { + beforeafterpos = 2; + offset = alarm->endOffset().asSeconds(); + } else { + // TODO: Also allow alarms at fixed times, not relative to start/end + offset = alarm->startOffset().asSeconds(); + } + // Negative offset means before the start/end... + if ( offset < 0 ) { + offset = -offset; + } else { + ++beforeafterpos; + } + mWidget->mBeforeAfter->setCurrentItem( beforeafterpos ); + + offset = offset / 60; // make minutes + int useoffset = offset; + + if ( offset % (24*60) == 0 && offset>0 ) { // divides evenly into days? + useoffset = offset / (24*60); + mWidget->mOffsetUnit->setCurrentItem( 2 ); + } else if (offset % 60 == 0 && offset>0 ) { // divides evenly into hours? + useoffset = offset / 60; + mWidget->mOffsetUnit->setCurrentItem( 1 ); + } else { + useoffset = offset; + mWidget->mOffsetUnit->setCurrentItem( 0 ); + } + mWidget->mAlarmOffset->setValue( useoffset ); + + + // Repeating + mWidget->mRepeats->setChecked( alarm->repeatCount()>0 ); + if ( alarm->repeatCount()>0 ) { + mWidget->mRepeatCount->setValue( alarm->repeatCount() ); + mWidget->mRepeatInterval->setValue( alarm->snoozeTime() ); + } + + switch ( alarm->type() ) { + case KCal::Alarm::Audio: + mWidget->mAlarmType->setButton( 1 ); + mWidget->mSoundFile->setURL( alarm->audioFile() ); + break; + case KCal::Alarm::Procedure: + mWidget->mAlarmType->setButton( 2 ); + mWidget->mApplication->setURL( alarm->programFile() ); + mWidget->mAppArguments->setText( alarm->programArguments() ); + break; + case KCal::Alarm::Email: { + mWidget->mAlarmType->setButton( 3 ); + QValueList<KCal::Person> addresses = alarm->mailAddresses(); + QStringList add; + for ( QValueList<KCal::Person>::ConstIterator it = addresses.begin(); + it != addresses.end(); ++it ) { + add << (*it).fullName(); + } + mWidget->mEmailAddress->setText( add.join(", ") ); + mWidget->mEmailText->setText( alarm->mailText() ); + break;} + case KCal::Alarm::Display: + case KCal::Alarm::Invalid: + default: + mWidget->mAlarmType->setButton( 0 ); + mWidget->mDisplayText->setText( alarm->text() ); + break; + } + + mWidget->mTypeStack->raiseWidget( mWidget->mAlarmType->selectedId() ); + + mInitializing = false; +} + +void KOEditorAlarms::writeAlarm( KCal::Alarm *alarm ) +{ + // Offsets + int offset = mWidget->mAlarmOffset->value()*60; // minutes + int offsetunit = mWidget->mOffsetUnit->currentItem(); + if ( offsetunit >= 1 ) offset *= 60; // hours + if ( offsetunit >= 2 ) offset *= 24; // days + if ( offsetunit >= 3 ) offset *= 7; // weeks + + int beforeafterpos = mWidget->mBeforeAfter->currentItem(); + if ( beforeafterpos % 2 == 0 ) { // before -> negative + offset = -offset; + } + + // TODO: Add possibility to specify a given time for the reminder + if ( beforeafterpos / 2 == 0 ) { // start offset + alarm->setStartOffset( KCal::Duration( offset ) ); + } else { + alarm->setEndOffset( KCal::Duration( offset ) ); + } + + // Repeating + if ( mWidget->mRepeats->isChecked() ) { + alarm->setRepeatCount( mWidget->mRepeatCount->value() ); + alarm->setSnoozeTime( mWidget->mRepeatInterval->value() ); + } else { + alarm->setRepeatCount( 0 ); + } + + switch ( mWidget->mAlarmType->selectedId() ) { + case 1: // Audio + alarm->setAudioAlarm( mWidget->mSoundFile->url() ); + break; + case 2: // Procedure + alarm->setProcedureAlarm( mWidget->mApplication->url(), mWidget->mAppArguments->text() ); + break; + case 3: { // Email + QStringList addresses = KPIM::splitEmailAddrList( mWidget->mEmailAddress->text() ); + QValueList<KCal::Person> add; + for ( QStringList::Iterator it = addresses.begin(); it != addresses.end(); + ++it ) { + add << KCal::Person( *it ); + } + // TODO: Add a subject line and possibilities for attachments + alarm->setEmailAlarm( QString::null, mWidget->mEmailText->text(), + add ); + break; } + case 0: // Display + default: + alarm->setDisplayAlarm( mWidget->mDisplayText->text() ); + break; + } +} + +void KOEditorAlarms::selectionChanged( QListViewItem *listviewitem ) +{ + AlarmListViewItem *item = dynamic_cast<AlarmListViewItem*>(listviewitem); + mCurrentItem = item; + mWidget->mTimeGroup->setEnabled( item ); + mWidget->mTypeGroup->setEnabled( item ); + if ( item ) { + readAlarm( item->alarm() ); + } +} + +void KOEditorAlarms::slotOk() +{ + // copy the mAlarms list + if ( mAlarms ) { + mAlarms->clear(); + QListViewItemIterator it( mWidget->mAlarmList ); + while ( it.current() ) { + AlarmListViewItem *item = dynamic_cast<AlarmListViewItem*>(*it); + if ( item ) { + mAlarms->append( new KCal::Alarm( *(item->alarm()) ) ); + } + ++it; + } + } + accept(); +} + +void KOEditorAlarms::slotAdd() +{ + mCurrentItem = new AlarmListViewItem( mWidget->mAlarmList, 0 ); + mWidget->mAlarmList->setCurrentItem( mCurrentItem ); +// selectionChanged( mCurrentItem ); +} + +void KOEditorAlarms::slotDuplicate() +{ + if ( mCurrentItem ) { + mCurrentItem = new AlarmListViewItem( mWidget->mAlarmList, mCurrentItem->alarm() ); + mWidget->mAlarmList->setCurrentItem( mCurrentItem ); +// selectionChanged( mCurrentItem ); + } +} + +void KOEditorAlarms::slotRemove() +{ + if ( mCurrentItem ) { + delete mCurrentItem; + mCurrentItem = dynamic_cast<AlarmListViewItem*>( mWidget->mAlarmList->currentItem() ); + mWidget->mAlarmList->setSelected( mCurrentItem, true ); + + } +} + +void KOEditorAlarms::init() +{ + mInitializing = true; + KCal::Alarm::List::ConstIterator it; + for ( it = mAlarms->begin(); it != mAlarms->end(); ++it ) { + new AlarmListViewItem( mWidget->mAlarmList, *it ); + } + mWidget->mAlarmList->setSelected( mWidget->mAlarmList->firstChild(), true ); + mInitializing = false; +} + +#include "koeditoralarms.moc" diff --git a/korganizer/koeditoralarms.h b/korganizer/koeditoralarms.h new file mode 100644 index 000000000..04af51b48 --- /dev/null +++ b/korganizer/koeditoralarms.h @@ -0,0 +1,60 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOEDITORALARMS_H +#define KOEDITORALARMS_H + +#include <kdialogbase.h> +#include <libkcal/alarm.h> + +class KOEditorAlarms_base; + +class AlarmListViewItem; + +class KOEditorAlarms : public KDialogBase +{ + Q_OBJECT + public: + KOEditorAlarms( KCal::Alarm::List *alarms, QWidget *parent = 0, + const char *name = 0 ); + ~KOEditorAlarms(); + + protected slots: + void slotOk(); + void slotAdd(); + void slotDuplicate(); + void slotRemove(); + void changed(); + void selectionChanged( QListViewItem *listviewitem ); + protected: + void init(); + void readAlarm( KCal::Alarm *alarm ); + void writeAlarm( KCal::Alarm *alarm ); + private: + KCal::Alarm::List *mAlarms; + KOEditorAlarms_base *mWidget; + bool mInitializing; + AlarmListViewItem *mCurrentItem; +}; + +#endif diff --git a/korganizer/koeditoralarms_base.ui b/korganizer/koeditoralarms_base.ui new file mode 100644 index 000000000..68e8d5bc9 --- /dev/null +++ b/korganizer/koeditoralarms_base.ui @@ -0,0 +1,669 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>KOEditorAlarms_base</class> +<widget class="QWidget"> + <property name="name"> + <cstring>KOEditorAlarms_base</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>500</width> + <height>300</height> + </rect> + </property> + <property name="caption"> + <string>Alarms</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QGroupBox" row="1" column="0"> + <property name="name"> + <cstring>mTimeGroup</cstring> + </property> + <property name="title"> + <string>Time Offset</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout3</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QSpinBox"> + <property name="name"> + <cstring>mAlarmOffset</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QComboBox"> + <item> + <property name="text"> + <string>minute(s)</string> + </property> + </item> + <item> + <property name="text"> + <string>hour(s)</string> + </property> + </item> + <item> + <property name="text"> + <string>day(s)</string> + </property> + </item> + <property name="name"> + <cstring>mOffsetUnit</cstring> + </property> + </widget> + <widget class="QComboBox"> + <item> + <property name="text"> + <string>before the start</string> + </property> + </item> + <item> + <property name="text"> + <string>after the start</string> + </property> + </item> + <item> + <property name="text"> + <string>before the end</string> + </property> + </item> + <item> + <property name="text"> + <string>after the end</string> + </property> + </item> + <property name="name"> + <cstring>mBeforeAfter</cstring> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout8</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="1"> + <property name="name"> + <cstring>mHowOftenLabel</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&How often:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mRepeatCount</cstring> + </property> + </widget> + <widget class="QSpinBox" row="0" column="2"> + <property name="name"> + <cstring>mRepeatCount</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="suffix"> + <string> time(s)</string> + </property> + <property name="maxValue"> + <number>500</number> + </property> + <property name="minValue"> + <number>1</number> + </property> + </widget> + <widget class="QLabel" row="1" column="1"> + <property name="name"> + <cstring>mIntervalLabel</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>&Interval:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mRepeatInterval</cstring> + </property> + </widget> + <widget class="QCheckBox" row="0" column="0"> + <property name="name"> + <cstring>mRepeats</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Repeat:</string> + </property> + </widget> + <widget class="QSpinBox" row="1" column="2"> + <property name="name"> + <cstring>mRepeatInterval</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="prefix"> + <string>every </string> + </property> + <property name="suffix"> + <string> minute(s)</string> + </property> + <property name="maxValue"> + <number>999</number> + </property> + <property name="minValue"> + <number>1</number> + </property> + </widget> + </grid> + </widget> + </vbox> + </widget> + <widget class="QGroupBox" row="2" column="0"> + <property name="name"> + <cstring>mTypeGroup</cstring> + </property> + <property name="title"> + <string>Type</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>mAlarmType</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <property name="title"> + <string></string> + </property> + <property name="flat"> + <bool>true</bool> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QRadioButton"> + <property name="name"> + <cstring>mTypeDisplayRadio</cstring> + </property> + <property name="text"> + <string>&Reminder Dialog</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>mTypeSoundRadio</cstring> + </property> + <property name="text"> + <string>A&udio</string> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>mTypeAppRadio</cstring> + </property> + <property name="text"> + <string>Program</string> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>mTypeEmailRadio</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Email</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>41</height> + </size> + </property> + </spacer> + </vbox> + </widget> + <widget class="Line"> + <property name="name"> + <cstring>line1</cstring> + </property> + <property name="frameShape"> + <enum>VLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + </widget> + <widget class="QWidgetStack"> + <property name="name"> + <cstring>mTypeStack</cstring> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>WStackPage</cstring> + </property> + <attribute name="id"> + <number>0</number> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>mDisplayTextLabel</cstring> + </property> + <property name="text"> + <string>Reminder Dialog &text:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mDisplayText</cstring> + </property> + </widget> + <widget class="QTextEdit"> + <property name="name"> + <cstring>mDisplayText</cstring> + </property> + </widget> + </vbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>WStackPage</cstring> + </property> + <attribute name="id"> + <number>1</number> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>mSoundFileLabel</cstring> + </property> + <property name="text"> + <string>Audio &file:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mSoundFile</cstring> + </property> + </widget> + <widget class="KURLRequester"> + <property name="name"> + <cstring>mSoundFile</cstring> + </property> + <property name="filter"> + <string>audio/x-wav audio/x-mp3 application/ogg</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>61</height> + </size> + </property> + </spacer> + </vbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>WStackPage</cstring> + </property> + <attribute name="id"> + <number>2</number> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>mApplicationLabel</cstring> + </property> + <property name="text"> + <string>&Program file:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mApplication</cstring> + </property> + </widget> + <widget class="KURLRequester"> + <property name="name"> + <cstring>mApplication</cstring> + </property> + <property name="filter"> + <string>*.*|All files</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>mAppArgumentsLabel</cstring> + </property> + <property name="text"> + <string>Program ar&guments:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mAppArguments</cstring> + </property> + </widget> + <widget class="QLineEdit"> + <property name="name"> + <cstring>mAppArguments</cstring> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3_2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + </vbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>WStackPage</cstring> + </property> + <attribute name="id"> + <number>3</number> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QLabel" row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>mEmailTextLabel</cstring> + </property> + <property name="text"> + <string>Email &message text:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mEmailText</cstring> + </property> + </widget> + <widget class="QTextEdit" row="2" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>mEmailText</cstring> + </property> + </widget> + <widget class="KPIM::AddresseeLineEdit" row="0" column="1"> + <property name="name"> + <cstring>mEmailAddress</cstring> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>mEmailToLabel</cstring> + </property> + <property name="text"> + <string>Email &address(es):</string> + </property> + <property name="buddy" stdset="0"> + <cstring>unnamed</cstring> + </property> + </widget> + </grid> + </widget> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout7</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton" row="2" column="1"> + <property name="name"> + <cstring>mRemoveButton</cstring> + </property> + <property name="text"> + <string>&Remove...</string> + </property> + </widget> + <widget class="QPushButton" row="0" column="1"> + <property name="name"> + <cstring>mAddButton</cstring> + </property> + <property name="text"> + <string>&Add</string> + </property> + </widget> + <widget class="QPushButton" row="1" column="1"> + <property name="name"> + <cstring>mDuplicateButton</cstring> + </property> + <property name="text"> + <string>D&uplicate</string> + </property> + </widget> + <spacer row="3" column="1"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>60</height> + </size> + </property> + </spacer> + <widget class="QListView" row="0" column="0" rowspan="4" colspan="1"> + <column> + <property name="text"> + <string>Type</string> + </property> + <property name="clickable"> + <bool>false</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Time Offset</string> + </property> + <property name="clickable"> + <bool>false</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Repeat</string> + </property> + <property name="clickable"> + <bool>false</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>mAlarmList</cstring> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + <property name="resizeMode"> + <enum>AllColumns</enum> + </property> + </widget> + </grid> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<connections> + <connection> + <sender>mAlarmType</sender> + <signal>clicked(int)</signal> + <receiver>mTypeStack</receiver> + <slot>raiseWidget(int)</slot> + </connection> + <connection> + <sender>mRepeats</sender> + <signal>toggled(bool)</signal> + <receiver>mIntervalLabel</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>mRepeats</sender> + <signal>toggled(bool)</signal> + <receiver>mRepeatInterval</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>mRepeats</sender> + <signal>toggled(bool)</signal> + <receiver>mHowOftenLabel</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>mRepeats</sender> + <signal>toggled(bool)</signal> + <receiver>mRepeatCount</receiver> + <slot>setEnabled(bool)</slot> + </connection> +</connections> +<includes> + <include location="global" impldecl="in declaration">addresseelineedit.h</include> +</includes> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>libkdepim/addresseelineedit.h</includehint> +</includehints> +</UI> diff --git a/korganizer/koeditorattachments.cpp b/korganizer/koeditorattachments.cpp new file mode 100644 index 000000000..51dd63044 --- /dev/null +++ b/korganizer/koeditorattachments.cpp @@ -0,0 +1,501 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (c) 2005 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "koeditorattachments.h" + +#include <libkcal/incidence.h> +#include <libkdepim/kpimurlrequesterdlg.h> +#include <libkdepim/kfileio.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> +#include <ktempdir.h> +#include <kio/netaccess.h> +#include <kmimetype.h> +#include <kiconloader.h> +#include <kfiledialog.h> +#include <kstdaction.h> +#include <kactioncollection.h> +#include <kpopupmenu.h> + +#include <qfile.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qlistview.h> +#include <qpushbutton.h> +#include <qdragobject.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qapplication.h> +#include <qclipboard.h> + +#include <cassert> +#include <set> + +class AttachmentListItem : public KIconViewItem +{ + public: + AttachmentListItem( KCal::Attachment*att, QIconView *parent ) : + KIconViewItem( parent ) + { + if ( att ) { + mAttachment = new KCal::Attachment( *att ); + } else { + mAttachment = new KCal::Attachment( QString::null ); + } + readAttachment(); + setDragEnabled( true ); + } + ~AttachmentListItem() { delete mAttachment; } + KCal::Attachment *attachment() const { return mAttachment; } + + void setUri( const QString &uri ) + { + mAttachment->setUri( uri ); + readAttachment(); + } + void setData( const char *base64 ) + { + mAttachment->setData( base64 ); + readAttachment(); + } + void setMimeType( const QString &mime ) + { + mAttachment->setMimeType( mime ); + readAttachment(); + } + void setLabel( const QString &label ) + { + mAttachment->setLabel( label ); + readAttachment(); + } + + void readAttachment() + { + if ( mAttachment->isUri() ) + setText( mAttachment->uri() ); + else { + if ( mAttachment->label().isEmpty() ) + setText( i18n("[Binary data]") ); + else + setText( mAttachment->label() ); + } + KMimeType::Ptr mt = KMimeType::mimeType( mAttachment->mimeType() ); + if ( mt ) { + const QString iconName( mt->icon( QString(), false ) ); + QPixmap pix = KGlobal::iconLoader( )->loadIcon( iconName, KIcon::Small ); + if ( pix.isNull() ) + pix = KGlobal::iconLoader( )->loadIcon( "unknown", KIcon::Small ); + if ( !pix.isNull() ) + setPixmap( pix ); + } + } + + private: + KCal::Attachment *mAttachment; +}; + +class AttachmentIconView : public KIconView +{ + friend class KOEditorAttachments; + public: + AttachmentIconView( KOEditorAttachments* parent=0 ) + :KIconView( parent ), + mParent( parent ) + { + setAcceptDrops( true ); + setSelectionMode( QIconView::Extended ); + setMode( KIconView::Select ); + setItemTextPos( QIconView::Right ); + setArrangement( QIconView::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: + QDragObject * dragObject() + { + KURL::List urls; + for ( QIconViewItem *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 ); + QByteArray encoded; + encoded.duplicate( att->data(), strlen(att->data()) ); + QByteArray decoded; + KCodecs::base64Decode( encoded, decoded ); + const QString 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( QDropEvent* event ) + { + mParent->handlePasteOrDrop( event ); + } + private: + std::set<KTempDir*> mTempDirs; + KOEditorAttachments* mParent; +}; + +KOEditorAttachments::KOEditorAttachments( int spacing, QWidget *parent, + const char *name ) + : QWidget( parent, name ) +{ + QBoxLayout *topLayout = new QHBoxLayout( this ); + topLayout->setSpacing( spacing ); + + QLabel *label = new QLabel( i18n("Attachments:"), this ); + topLayout->addWidget( label ); + + mAttachments = new AttachmentIconView( this ); + QWhatsThis::add( mAttachments, + i18n("Displays a list of current items (files, mail, etc.) " + "that have been associated with this event or to-do. ") ); + topLayout->addWidget( mAttachments ); + connect( mAttachments, SIGNAL( doubleClicked( QIconViewItem * ) ), + SLOT( showAttachment( QIconViewItem * ) ) ); + connect( mAttachments, SIGNAL(selectionChanged()), + SLOT(selectionChanged()) ); + connect( mAttachments, SIGNAL(contextMenuRequested(QIconViewItem*,const QPoint&)), + SLOT(contextMenu(QIconViewItem*,const QPoint&)) ); + + mAddMenu = new KPopupMenu( this ); + mContextMenu = new KPopupMenu( this ); + + KActionCollection* ac = new KActionCollection( this, this ); + + mOpenAction = new KAction( i18n("View"), 0, this, SLOT(slotShow()), ac ); + mOpenAction->plug( mContextMenu ); + mContextMenu->insertSeparator(); + + mCopyAction = KStdAction::copy(this, SLOT(slotCopy( ) ), ac ); + mCopyAction->plug( mContextMenu ); + mCutAction = KStdAction::cut(this, SLOT(slotCut( ) ), ac ); + mCutAction->plug( mContextMenu ); + KAction *action = KStdAction::paste(this, SLOT(slotPaste( ) ), ac ); + action->plug( mContextMenu ); + + action = new KAction( i18n("&Attach File..."), 0, this, 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, 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 ); + + QPushButton *addButton = new QPushButton( this ); + addButton->setIconSet( SmallIconSet( "add" ) ); + addButton->setPopup( mAddMenu ); + topLayout->addWidget( addButton ); + + mRemoveBtn = new QPushButton( this ); + mRemoveBtn->setIconSet( SmallIconSet( "remove" ) ); + QToolTip::add( mRemoveBtn, i18n("&Remove") ); + QWhatsThis::add( mRemoveBtn, + i18n("Removes the attachment selected in the list above " + "from this event or to-do.") ); + topLayout->addWidget( mRemoveBtn ); + connect( mRemoveBtn, SIGNAL( clicked() ), SLOT( slotRemove() ) ); + + selectionChanged(); + setAcceptDrops( true ); +} + +KOEditorAttachments::~KOEditorAttachments() +{ +} + +bool KOEditorAttachments::hasAttachments() +{ + return mAttachments->count() != 0; +} + +void KOEditorAttachments::dragEnterEvent( QDragEnterEvent* event ) +{ + event->accept( KURLDrag::canDecode( event ) | QTextDrag::canDecode( event ) ); +} + +void KOEditorAttachments::handlePasteOrDrop( QMimeSource* source ) +{ + KURL::List urls; + QString 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(), QString::null, asUri ); + } + } else if ( QTextDrag::decode( source, text ) ) { + QStringList lst = QStringList::split( '\n', text ); + for ( QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it ) { + addAttachment( (*it) ); + } + } +} + +void KOEditorAttachments::dropEvent( QDropEvent* event ) +{ + handlePasteOrDrop( event ); +} + +void KOEditorAttachments::showAttachment( QIconViewItem *item ) +{ + AttachmentListItem *attitem = static_cast<AttachmentListItem*>(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; + QByteArray encoded; + encoded.duplicate( att->data(), strlen(att->data()) ); + QByteArray decoded; + KCodecs::base64Decode( encoded, decoded ); + f.file()->writeBlock( decoded ); + f.file()->close(); + KRun::runURL( f.name(), att->mimeType(), true, false ); + } +} + +void KOEditorAttachments::slotAdd() +{ + KURL uri = KPimURLRequesterDlg::getURL( QString::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 ); + } +} + +void KOEditorAttachments::slotAddData() +{ + KURL uri = KFileDialog::getOpenFileName( QString(), QString(), this, i18n("Add Attachment") ); + if ( !uri.isEmpty() ) { + addAttachment( uri, QString::null, false ); + } +} + +void KOEditorAttachments::slotEdit() +{ + QIconViewItem *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( QString::null, i18n( + "File to be attached:"), this, i18n("Add Attachment") ); + if ( !uri.isEmpty() ) { + QString tmpFile; + if ( KIO::NetAccess::download( uri, tmpFile, this ) ) { + QFile f( tmpFile ); + if ( !f.open( IO_ReadOnly ) ) + return; + QByteArray data = f.readAll(); + f.close(); + attitem->setData( KCodecs::base64Encode( data ) ); + attitem->setMimeType( KIO::NetAccess::mimetype( uri, this ) ); + QString label = uri.fileName(); + if ( label.isEmpty() ) + label = uri.prettyURL(); + attitem->setLabel( label ); + KIO::NetAccess::removeTempFile( tmpFile ); + } + } + } +} + +void KOEditorAttachments::slotRemove() +{ + QValueList<QIconViewItem*> selected; + for ( QIconViewItem *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; + + for ( QValueList<QIconViewItem*>::iterator it( selected.begin() ), end( selected.end() ); it != end ; ++it ) { + delete *it; + } +} + +void KOEditorAttachments::slotShow() +{ + for ( QIconViewItem *it = mAttachments->firstItem(); it; it = it->nextItem() ) { + if ( !it->isSelected() ) + continue; + showAttachment( it ); + } +} + +void KOEditorAttachments::setDefaults() +{ + mAttachments->clear(); +} + +void KOEditorAttachments::addAttachment( const KURL &uri, + const QString &mimeType, bool asUri ) +{ + AttachmentListItem *item = new AttachmentListItem( 0, mAttachments ); + if ( asUri ) { + item->setUri( uri.url() ); + if ( !mimeType.isEmpty() ) item->setMimeType( mimeType ); + } else { + QString tmpFile; + if ( KIO::NetAccess::download( uri, tmpFile, this ) ) { + QFile f( tmpFile ); + if ( !f.open( IO_ReadOnly ) ) + return; + QByteArray data = f.readAll(); + f.close(); + item->setData( KCodecs::base64Encode( data ) ); + if ( !mimeType.isEmpty() ) + item->setMimeType( mimeType ); + else + item->setMimeType( KIO::NetAccess::mimetype( uri, this ) ); + QString label = uri.fileName(); + if ( label.isEmpty() ) + label = uri.prettyURL(); + item->setLabel( label ); + KIO::NetAccess::removeTempFile( tmpFile ); + } + } +} + + +void KOEditorAttachments::addAttachment( KCal::Attachment *attachment ) +{ + new AttachmentListItem( attachment, mAttachments ); +} + +void KOEditorAttachments::readIncidence( KCal::Incidence *i ) +{ + mAttachments->clear(); + + KCal::Attachment::List attachments = i->attachments(); + KCal::Attachment::List::ConstIterator it; + for( it = attachments.begin(); it != attachments.end(); ++it ) { + addAttachment( (*it) ); + } + if ( mAttachments->count() > 0 ) { + QTimer::singleShot( 0, mAttachments, SLOT(arrangeItemsInGrid()) ); + } +} + +void KOEditorAttachments::writeIncidence( KCal::Incidence *i ) +{ + i->clearAttachments(); + + QIconViewItem *item; + AttachmentListItem *attitem; + for( item = mAttachments->firstItem(); item; item = item->nextItem() ) { + attitem = static_cast<AttachmentListItem*>(item); + if ( attitem ) + i->addAttachment( new KCal::Attachment( *(attitem->attachment() ) ) ); + } +} + + +void KOEditorAttachments::slotCopy() +{ + QApplication::clipboard()->setData( mAttachments->dragObject(), QClipboard::Clipboard ); +} + +void KOEditorAttachments::slotCut() +{ + slotCopy(); + slotRemove(); +} + +void KOEditorAttachments::slotPaste() +{ + handlePasteOrDrop( QApplication::clipboard()->data() ); +} + +void KOEditorAttachments::selectionChanged() +{ + bool selected = false; + for ( QIconViewItem *item = mAttachments->firstItem(); item; item = item->nextItem() ) { + if ( item->isSelected() ) { + selected = true; + break; + } + } + mRemoveBtn->setEnabled( selected ); +} + +void KOEditorAttachments::contextMenu(QIconViewItem * item, const QPoint & pos) +{ + const bool enable = item != 0; + mOpenAction->setEnabled( enable ); + mCopyAction->setEnabled( enable ); + mCutAction->setEnabled( enable ); + mContextMenu->exec( pos ); +} + +#include "koeditorattachments.moc" diff --git a/korganizer/koeditorattachments.h b/korganizer/koeditorattachments.h new file mode 100644 index 000000000..813124a22 --- /dev/null +++ b/korganizer/koeditorattachments.h @@ -0,0 +1,91 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (c) 2005 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOEDITORATTACHMENTS_H +#define KOEDITORATTACHMENTS_H + +#include <qwidget.h> +#include <kurl.h> + +namespace KCal { +class Incidence; +class Attachment; +} + +class QIconViewItem; +class AttachmentIconView; +class QMimeSource; +class QPushButton; +class QPopupMenu; +class KAction; + +class KOEditorAttachments : public QWidget +{ + Q_OBJECT + public: + KOEditorAttachments( int spacing = 8, QWidget *parent = 0, + const char *name = 0 ); + ~KOEditorAttachments(); + + void addAttachment( const KURL &uri, + const QString &mimeType = QString::null, bool asUri = true ); + void addAttachment( KCal::Attachment *attachment ); + + /** Set widgets to default values */ + void setDefaults(); + /** Read event object and setup widgets accordingly */ + void readIncidence( KCal::Incidence * ); + /** Write event settings to event object */ + void writeIncidence( KCal::Incidence * ); + + bool hasAttachments(); + + protected slots: + void showAttachment( QIconViewItem *item ); + void slotAdd(); + void slotAddData(); + void slotEdit(); + void slotRemove(); + void slotShow(); + void dragEnterEvent( QDragEnterEvent *event ); + void dropEvent( QDropEvent *event ); + void slotCopy(); + void slotCut(); + void slotPaste(); + void selectionChanged(); + void contextMenu( QIconViewItem* item, const QPoint &pos ); + signals: + void openURL( const KURL &url ); + + private: + friend class AttachmentIconView; + void handlePasteOrDrop( QMimeSource* source ); + + AttachmentIconView *mAttachments; + QPushButton *mRemoveBtn; + QPopupMenu *mContextMenu, *mAddMenu; + KAction *mOpenAction, *mCopyAction, *mCutAction; +}; + +#endif diff --git a/korganizer/koeditordetails.cpp b/korganizer/koeditordetails.cpp new file mode 100644 index 000000000..2485fc96a --- /dev/null +++ b/korganizer/koeditordetails.cpp @@ -0,0 +1,372 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "koeditordetails.h" + +#include <qbuttongroup.h> +#include <qcheckbox.h> +#include <qcombobox.h> +#include <qdatetime.h> +#include <qdragobject.h> +#include <qfiledialog.h> +#include <qgroupbox.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qlineedit.h> +#include <qpushbutton.h> +#include <qradiobutton.h> +#include <qregexp.h> +#include <qtooltip.h> +#include <qvbox.h> +#include <qvgroupbox.h> +#include <qwhatsthis.h> +#include <qwidgetstack.h> +#include <qvaluevector.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kmessagebox.h> +#ifndef KORG_NOKABC +#include <kabc/addresseedialog.h> +#include <kabc/vcardconverter.h> +#include <libkdepim/addressesdialog.h> +#include <libkdepim/addresseelineedit.h> +#include <libkdepim/distributionlist.h> +#include <kabc/stdaddressbook.h> +#endif +#include <libkdepim/kvcarddrag.h> +#include <libemailfunctions/email.h> + +#include <libkcal/incidence.h> + +#include "koprefs.h" +#include "koglobals.h" + +#include "koeditorfreebusy.h" + +#include "kocore.h" + +template <> +CustomListViewItem<KCal::Attendee *>::~CustomListViewItem() +{ + delete mData; +} + +template <> +void CustomListViewItem<KCal::Attendee *>::updateItem() +{ + setText(0,mData->name()); + setText(1,mData->email()); + setText(2,mData->roleStr()); + setText(3,mData->statusStr()); + if (mData->RSVP() && !mData->email().isEmpty()) + setPixmap(4,KOGlobals::self()->smallIcon("mailappt")); + else + setPixmap(4,KOGlobals::self()->smallIcon("nomailappt")); + setText(5, mData->delegate()); + setText(6, mData->delegator()); +} + +KOAttendeeListView::KOAttendeeListView ( QWidget *parent, const char *name ) + : KListView(parent, name) +{ + setAcceptDrops( true ); + setAllColumnsShowFocus( true ); + setSorting( -1 ); +} + +/** KOAttendeeListView is a child class of KListView which supports + * dropping of attendees (e.g. from kaddressbook) onto it. If an attendeee + * was dropped, the signal dropped(Attendee*) is emitted. Valid drop classes + * are KVCardDrag and QTextDrag. + */ +KOAttendeeListView::~KOAttendeeListView() +{ +} + +void KOAttendeeListView::contentsDragEnterEvent( QDragEnterEvent *e ) +{ + dragEnterEvent(e); +} + +void KOAttendeeListView::contentsDragMoveEvent( QDragMoveEvent *e ) +{ +#ifndef KORG_NODND + if ( KVCardDrag::canDecode( e ) || QTextDrag::canDecode( e ) ) { + e->accept(); + } else { + e->ignore(); + } +#endif +} + +void KOAttendeeListView::dragEnterEvent( QDragEnterEvent *e ) +{ +#ifndef KORG_NODND + if ( KVCardDrag::canDecode( e ) || QTextDrag::canDecode( e ) ) { + e->accept(); + } else { + e->ignore(); + } +#endif +} + +void KOAttendeeListView::addAttendee( const QString &newAttendee ) +{ + kdDebug(5850) << " Email: " << newAttendee << endl; + QString name; + QString email; + KPIM::getNameAndMail( newAttendee, name, email ); + emit dropped( new Attendee( name, email, true ) ); +} + +void KOAttendeeListView::contentsDropEvent( QDropEvent *e ) +{ + dropEvent(e); +} + +void KOAttendeeListView::dropEvent( QDropEvent *e ) +{ +#ifndef KORG_NODND + QString text; + QString vcards; + +#ifndef KORG_NOKABC + if ( KVCardDrag::decode( e, vcards ) ) { + KABC::VCardConverter converter; + + KABC::Addressee::List list = converter.parseVCards( vcards ); + KABC::Addressee::List::Iterator it; + for ( it = list.begin(); it != list.end(); ++it ) { + QString em( (*it).fullEmail() ); + if (em.isEmpty()) { + em=(*it).realName(); + } + addAttendee( em ); + } + } else +#endif // KORG_NOKABC + if (QTextDrag::decode(e,text)) { + kdDebug(5850) << "Dropped : " << text << endl; + QStringList emails = QStringList::split(",",text); + for(QStringList::ConstIterator it = emails.begin();it!=emails.end();++it) { + addAttendee(*it); + } + } +#endif //KORG_NODND +} + + +KOEditorDetails::KOEditorDetails( int spacing, QWidget *parent, + const char *name ) + : KOAttendeeEditor( parent, name), mDisableItemUpdate( false ) +{ + QBoxLayout *topLayout = new QVBoxLayout( this ); + topLayout->setSpacing( spacing ); + + initOrganizerWidgets( this, topLayout ); + + mListView = new KOAttendeeListView( this, "mListView" ); + QWhatsThis::add( mListView, + i18n("Displays information about current attendees. " + "To edit an attendee, select it in this list " + "and modify the values in the area below. " + "Clicking on a column title will sort the list " + "according to that column. The RSVP column " + "indicates whether or not a response is requested " + "from the attendee.") ); + mListView->addColumn( i18n("Name"), 200 ); + mListView->addColumn( i18n("Email"), 200 ); + mListView->addColumn( i18n("Role"), 80 ); + mListView->addColumn( i18n("Status"), 100 ); + mListView->addColumn( i18n("RSVP"), 55 ); + mListView->addColumn( i18n("Delegated to"), 120 ); + mListView->addColumn( i18n("Delegated from" ), 120 ); + mListView->setResizeMode( QListView::LastColumn ); + if ( KOPrefs::instance()->mCompactDialogs ) { + mListView->setFixedHeight( 78 ); + } + + connect( mListView, SIGNAL( selectionChanged( QListViewItem * ) ), + SLOT( updateAttendeeInput() ) ); +#ifndef KORG_NODND + connect( mListView, SIGNAL( dropped( Attendee * ) ), + SLOT( slotInsertAttendee( Attendee * ) ) ); +#endif + topLayout->addWidget( mListView ); + + initEditWidgets( this, topLayout ); + + connect( mRemoveButton, SIGNAL(clicked()), SLOT(removeAttendee()) ); + + updateAttendeeInput(); +} + +KOEditorDetails::~KOEditorDetails() +{ +} + +bool KOEditorDetails::hasAttendees() +{ + return mListView->childCount() > 0; +} + +void KOEditorDetails::removeAttendee() +{ + AttendeeListItem *aItem = + 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 ); + + delete aItem; + + updateAttendeeInput(); + emit updateAttendeeSummary( mListView->childCount() ); +} + + +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() ) ); + mListView->setSelected( item, true ); + emit updateAttendeeSummary( mListView->childCount() ); +} + +void KOEditorDetails::setDefaults() +{ + mRsvpButton->setChecked( true ); +} + +void KOEditorDetails::readEvent( Incidence *event ) +{ + mListView->clear(); + KOAttendeeEditor::readEvent( event ); + + mListView->setSelected( mListView->firstChild(), true ); + + emit updateAttendeeSummary( mListView->childCount() ); +} + +void KOEditorDetails::writeEvent(Incidence *event) +{ + event->clearAttendees(); + QValueVector<QListViewItem*> toBeDeleted; + QListViewItem *item; + AttendeeListItem *a; + for (item = mListView->firstChild(); item; + item = item->nextSibling()) { + a = (AttendeeListItem *)item; + Attendee *attendee = a->data(); + Q_ASSERT( attendee ); + /* Check if the attendee is a distribution list and expand it */ + if ( attendee->email().isEmpty() ) { + KPIM::DistributionList list = + KPIM::DistributionList::findByName( KABC::StdAddressBook::self(), attendee->name() ); + if ( !list.isEmpty() ) { + toBeDeleted.push_back( item ); // remove it once we are done expanding + KPIM::DistributionList::Entry::List entries = list.entries( KABC::StdAddressBook::self() ); + KPIM::DistributionList::Entry::List::Iterator it( entries.begin() ); + while ( it != entries.end() ) { + KPIM::DistributionList::Entry &e = ( *it ); + ++it; + // this calls insertAttendee, which appends + insertAttendeeFromAddressee( e.addressee, attendee ); + // TODO: duplicate check, in case it was already added manually + } + } + } else { + bool skip = false; + if ( attendee->email().endsWith( "example.net" ) ) { + if ( KMessageBox::warningYesNo( this, i18n("%1 does not look like a valid email address. " + "Are you sure you want to invite this participant?").arg( attendee->email() ), + i18n("Invalid email address") ) != KMessageBox::Yes ) { + skip = true; + } + } + if ( !skip ) { + event->addAttendee( new Attendee( *attendee ) ); + } + } + } + + KOAttendeeEditor::writeEvent( event ); + + // cleanup + QValueVector<QListViewItem*>::iterator it; + for( it = toBeDeleted.begin(); it != toBeDeleted.end(); ++it ) { + delete *it; + } +} + +bool KOEditorDetails::validateInput() +{ + return true; +} + +KCal::Attendee * KOEditorDetails::currentAttendee() const +{ + QListViewItem *item = mListView->selectedItem(); + AttendeeListItem *aItem = static_cast<AttendeeListItem *>( item ); + if ( !aItem ) + return 0; + return aItem->data(); +} + +void KOEditorDetails::updateCurrentItem() +{ + AttendeeListItem *item = static_cast<AttendeeListItem*>( mListView->selectedItem() ); + if ( item ) + item->updateItem(); +} + +void KOEditorDetails::slotInsertAttendee(Attendee * a) +{ + insertAttendee( a ); +} + +void KOEditorDetails::changeStatusForMe(Attendee::PartStat status) +{ + const QStringList myEmails = KOPrefs::instance()->allEmails(); + for ( QListViewItemIterator it( mListView ); it.current(); ++it ) { + AttendeeListItem *item = static_cast<AttendeeListItem*>( it.current() ); + for ( QStringList::ConstIterator it2( myEmails.begin() ), end( myEmails.end() ); it2 != end; ++it2 ) { + if ( item->data()->email() == *it2 ) { + item->data()->setStatus( status ); + item->updateItem(); + } + } + } +} + +#include "koeditordetails.moc" diff --git a/korganizer/koeditordetails.h b/korganizer/koeditordetails.h new file mode 100644 index 000000000..1929a49ab --- /dev/null +++ b/korganizer/koeditordetails.h @@ -0,0 +1,117 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef _KOEDITORDETAILS_H +#define _KOEDITORDETAILS_H + +#include <klistview.h> +#include "customlistviewitem.h" +#include "koattendeeeditor.h" + +#include <libkcal/attendee.h> + +class QPushButton; +class QCheckBox; +class QLineEdit; +class QLabel; +class QComboBox; +class QHBox; +class KDateEdit; +class KOEditorFreeBusy; + +namespace KCal { +class Attendee; +class Incidence; +} +using namespace KCal; + +namespace KPIM { +class AddresseeLineEdit; +} + +typedef CustomListViewItem<KCal::Attendee *> AttendeeListItem; + + +/** KOAttendeeListView is a child class of KListView which supports + * dropping of attendees (e.g. from kaddressbook) onto it. If an attendeee + * was dropped, the signal dropped(Attendee*) is emitted. Valid drop classes + * are KVCardDrag and QTextDrag. + */ +class KOAttendeeListView : public KListView +{ +Q_OBJECT +public: + KOAttendeeListView (QWidget *parent=0, const char *name=0); + virtual ~KOAttendeeListView(); + virtual void addAttendee( const QString& newAttendee ); +public slots: + virtual void contentsDragEnterEvent( QDragEnterEvent *e ); + virtual void dragEnterEvent( QDragEnterEvent *e ); + virtual void contentsDropEvent( QDropEvent *e ); + virtual void dropEvent( QDropEvent *e ); + virtual void contentsDragMoveEvent(QDragMoveEvent *e); +signals: + void dropped(Attendee*); +}; + + +class KOEditorDetails : public KOAttendeeEditor +{ + Q_OBJECT + public: + KOEditorDetails (int spacing = 8,QWidget* parent = 0, const char* name = 0); + virtual ~KOEditorDetails(); + + /** Set widgets to default values */ + void setDefaults(); + /** Read event object and setup widgets accordingly */ + void readEvent(Incidence *); + /** Write event settings to event object */ + void writeEvent(Incidence *); + + /** Check if the input is valid. */ + bool validateInput(); + + /** Returns whether at least one attendee was added */ + bool hasAttendees(); + + void insertAttendee( Attendee*, bool goodEmailAddress = true ); + + protected slots: + void removeAttendee(); + void slotInsertAttendee( Attendee *a ); + + protected: + void changeStatusForMe( Attendee::PartStat status ); + + KCal::Attendee* currentAttendee() const; + void updateCurrentItem(); + + private: + bool mDisableItemUpdate; + + KListView *mListView; +// KOEditorFreeBusy *mFreeBusy; +}; + +#endif diff --git a/korganizer/koeditorfreebusy.cpp b/korganizer/koeditorfreebusy.cpp new file mode 100644 index 000000000..3849bc5d0 --- /dev/null +++ b/korganizer/koeditorfreebusy.cpp @@ -0,0 +1,931 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001,2004 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qtooltip.h> +#include <qlayout.h> +#include <qlabel.h> +#include <qcombobox.h> +#include <qpushbutton.h> +#include <qvaluevector.h> +#include <qwhatsthis.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kmessagebox.h> + +#ifndef KORG_NOKABC +#include <kabc/addresseedialog.h> +#include <kabc/vcardconverter.h> +#include <libkdepim/addressesdialog.h> +#include <libkdepim/addresseelineedit.h> +#include <libkdepim/distributionlist.h> +#include <kabc/stdaddressbook.h> +#endif + +#include <libkcal/event.h> +#include <libkcal/freebusy.h> + +#include <libemailfunctions/email.h> + +#include <kdgantt/KDGanttView.h> +#include <kdgantt/KDGanttViewTaskItem.h> +#include <kdgantt/KDGanttViewSubwidgets.h> + +#include "koprefs.h" +#include "koglobals.h" +#include "kogroupware.h" +#include "freebusymanager.h" +#include "freebusyurldialog.h" + +#include "koeditorfreebusy.h" + +// The FreeBusyItem is the whole line for a given attendee. +// Individual "busy" periods are created as sub-items of this item. +// +// We can't use the CustomListViewItem base class, since we need a +// different inheritance hierarchy for supporting the Gantt view. +class FreeBusyItem : public KDGanttViewTaskItem +{ + public: + FreeBusyItem( Attendee *attendee, KDGanttView *parent ) : + KDGanttViewTaskItem( parent, parent->lastItem() ), mAttendee( attendee ), mTimerID( 0 ), + mIsDownloading( false ) + { + Q_ASSERT( attendee ); + updateItem(); + setFreeBusyPeriods( 0 ); + setDisplaySubitemsAsGroup( true ); + if ( listView () ) + listView ()->setRootIsDecorated( false ); + } + ~FreeBusyItem() {} + + void updateItem(); + + Attendee *attendee() const { return mAttendee; } + void setFreeBusy( KCal::FreeBusy *fb ) { mFreeBusy = fb; } + KCal::FreeBusy* freeBusy() const { return mFreeBusy; } + + void setFreeBusyPeriods( FreeBusy *fb ); + + QString key( int column, bool ) const + { + QMap<int,QString>::ConstIterator it = mKeyMap.find( column ); + if ( it == mKeyMap.end() ) return listViewText( column ); + else return *it; + } + + void setSortKey( int column, const QString &key ) + { + mKeyMap.insert( column, key ); + } + + QString email() const { return mAttendee->email(); } + void setUpdateTimerID( int id ) { mTimerID = id; } + int updateTimerID() const { return mTimerID; } + + void startDownload( bool forceDownload ) { + mIsDownloading = true; + FreeBusyManager *m = KOGroupware::instance()->freeBusyManager(); + if ( !m->retrieveFreeBusy( attendee()->email(), forceDownload ) ) + mIsDownloading = false; + } + void setIsDownloading( bool d ) { mIsDownloading = d; } + bool isDownloading() const { return mIsDownloading; } + + private: + Attendee *mAttendee; + KCal::FreeBusy *mFreeBusy; + + QMap<int,QString> mKeyMap; + + // This is used for the update timer + int mTimerID; + + // Only run one download job at a time + bool mIsDownloading; +}; + +void FreeBusyItem::updateItem() +{ + setListViewText( 0, mAttendee->fullName() ); + switch ( mAttendee->status() ) { + case Attendee::Accepted: + setPixmap( 0, KOGlobals::self()->smallIcon( "ok" ) ); + break; + case Attendee::Declined: + setPixmap( 0, KOGlobals::self()->smallIcon( "no" ) ); + break; + case Attendee::NeedsAction: + case Attendee::InProcess: + setPixmap( 0, KOGlobals::self()->smallIcon( "help" ) ); + break; + case Attendee::Tentative: + setPixmap( 0, KOGlobals::self()->smallIcon( "apply" ) ); + break; + case Attendee::Delegated: + setPixmap( 0, KOGlobals::self()->smallIcon( "mail_forward" ) ); + break; + default: + setPixmap( 0, QPixmap() ); + } +} + + +// Set the free/busy periods for this attendee +void FreeBusyItem::setFreeBusyPeriods( FreeBusy* fb ) +{ + if( fb ) { + // Clean out the old entries + for( KDGanttViewItem* it = firstChild(); it; it = firstChild() ) + delete it; + + // Evaluate free/busy information + QValueList<KCal::Period> busyPeriods = fb->busyPeriods(); + for( QValueList<KCal::Period>::Iterator it = busyPeriods.begin(); + it != busyPeriods.end(); ++it ) { + KDGanttViewTaskItem* newSubItem = new KDGanttViewTaskItem( this ); + newSubItem->setStartTime( (*it).start() ); + newSubItem->setEndTime( (*it).end() ); + newSubItem->setColors( Qt::red, Qt::red, Qt::red ); + QString 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 ); + } + setFreeBusy( fb ); + setShowNoInformation( false ); + } else { + // No free/busy information + //debug only start + // int ii ; + // QDateTime cur = QDateTime::currentDateTime(); + // for( ii = 0; ii < 10 ;++ii ) { + // KDGanttViewTaskItem* newSubItem = new KDGanttViewTaskItem( this ); + // cur = cur.addSecs( 7200 ); + // newSubItem->setStartTime( cur ); + // cur = cur.addSecs( 7200 ); + // newSubItem->setEndTime( cur ); + // newSubItem->setColors( Qt::red, Qt::red, Qt::red ); + // } + //debug only end + setFreeBusy( 0 ); + setShowNoInformation( true ); + } + + // We are no longer downloading + mIsDownloading = false; +} + +//// + +KOEditorFreeBusy::KOEditorFreeBusy( int spacing, QWidget *parent, + const char *name ) + : KOAttendeeEditor( parent, name ) +{ + QVBoxLayout *topLayout = new QVBoxLayout( this ); + topLayout->setSpacing( spacing ); + + initOrganizerWidgets( this, topLayout ); + + // Label for status summary information + // Uses the tooltip palette to highlight it + mIsOrganizer = false; // Will be set later. This is just valgrind silencing + mStatusSummaryLabel = new QLabel( this ); + mStatusSummaryLabel->setPalette( QToolTip::palette() ); + mStatusSummaryLabel->setFrameStyle( QFrame::Plain | QFrame::Box ); + mStatusSummaryLabel->setLineWidth( 1 ); + mStatusSummaryLabel->hide(); // Will be unhidden later if you are organizer + topLayout->addWidget( mStatusSummaryLabel ); + + // The control panel for the gantt widget + QBoxLayout *controlLayout = new QHBoxLayout( topLayout ); + + QString whatsThis = i18n("Sets the zoom level on the Gantt chart. " + "'Hour' shows a range of several hours, " + "'Day' shows a range of a few days, " + "'Week' shows a range of a few months, " + "and 'Month' shows a range of a few years, " + "while 'Automatic' selects the range most " + "appropriate for the current event or to-do."); + QLabel *label = new QLabel( i18n( "Scale: " ), this ); + QWhatsThis::add( label, whatsThis ); + controlLayout->addWidget( label ); + + scaleCombo = new QComboBox( this ); + QWhatsThis::add( scaleCombo, whatsThis ); + scaleCombo->insertItem( i18n( "Hour" ) ); + scaleCombo->insertItem( i18n( "Day" ) ); + scaleCombo->insertItem( i18n( "Week" ) ); + scaleCombo->insertItem( i18n( "Month" ) ); + scaleCombo->insertItem( i18n( "Automatic" ) ); + scaleCombo->setCurrentItem( 0 ); // start with "hour" + connect( scaleCombo, SIGNAL( activated( int ) ), + SLOT( slotScaleChanged( int ) ) ); + controlLayout->addWidget( scaleCombo ); + + QPushButton *button = new QPushButton( i18n( "Center on Start" ), this ); + QWhatsThis::add( button, + i18n("Centers the Gantt chart on the start time " + "and day of this event.") ); + connect( button, SIGNAL( clicked() ), SLOT( slotCenterOnStart() ) ); + controlLayout->addWidget( button ); + + controlLayout->addStretch( 1 ); + + button = new QPushButton( i18n( "Pick Date" ), this ); + QWhatsThis::add( button, + i18n("Moves the event to a date and time when all the " + "attendees are free.") ); + connect( button, SIGNAL( clicked() ), SLOT( slotPickDate() ) ); + controlLayout->addWidget( button ); + + controlLayout->addStretch( 1 ); + + button = new QPushButton( i18n("Reload"), this ); + QWhatsThis::add( button, + i18n("Reloads Free/Busy data for all attendees from " + "the corresponding servers.") ); + controlLayout->addWidget( button ); + connect( button, SIGNAL( clicked() ), SLOT( manualReload() ) ); + + mGanttView = new KDGanttView( this, "mGanttView" ); + QWhatsThis::add( mGanttView, + i18n("Shows the free/busy status of all attendees. " + "Double-clicking on an attendees entry in the " + "list will allow you to enter the location of their " + "Free/Busy Information.") ); + topLayout->addWidget( mGanttView ); + // Remove the predefined "Task Name" column + mGanttView->removeColumn( 0 ); + mGanttView->addColumn( i18n("Attendee") ); + if ( KOPrefs::instance()->mCompactDialogs ) { + mGanttView->setFixedHeight( 78 ); + } + mGanttView->setHeaderVisible( true ); + mGanttView->setScale( KDGanttView::Hour ); + mGanttView->setShowHeaderPopupMenu( false, false, false, false, false, false ); + // Initially, show 15 days back and forth + // set start to even hours, i.e. to 12:AM 0 Min 0 Sec + QDateTime horizonStart = QDateTime( QDateTime::currentDateTime() + .addDays( -15 ).date() ); + QDateTime horizonEnd = QDateTime::currentDateTime().addDays( 15 ); + mGanttView->setHorizonStart( horizonStart ); + mGanttView->setHorizonEnd( horizonEnd ); + mGanttView->setCalendarMode( true ); + //mGanttView->setDisplaySubitemsAsGroup( true ); + mGanttView->setShowLegendButton( false ); + // Initially, center to current date + mGanttView->centerTimelineAfterShow( QDateTime::currentDateTime() ); + if ( KGlobal::locale()->use12Clock() ) + mGanttView->setHourFormat( KDGanttView::Hour_12 ); + else + mGanttView->setHourFormat( KDGanttView::Hour_24_FourDigit ); + + // mEventRectangle is the colored rectangle representing the event being modified + mEventRectangle = new KDIntervalColorRectangle( mGanttView ); + mEventRectangle->setColor( Qt::magenta ); + mGanttView->addIntervalBackgroundColor( mEventRectangle ); + + connect( mGanttView, SIGNAL ( timeIntervalSelected( const QDateTime &, + const QDateTime & ) ), + mGanttView, SLOT( zoomToSelection( const QDateTime &, + const QDateTime & ) ) ); + connect( mGanttView, SIGNAL( lvItemDoubleClicked( KDGanttViewItem * ) ), + SLOT( editFreeBusyUrl( KDGanttViewItem * ) ) ); + connect( mGanttView, SIGNAL( intervalColorRectangleMoved( const QDateTime&, const QDateTime& ) ), + this, SLOT( slotIntervalColorRectangleMoved( const QDateTime&, const QDateTime& ) ) ); + + connect( mGanttView, SIGNAL(lvSelectionChanged(KDGanttViewItem*)), + this, SLOT(updateAttendeeInput()) ); + connect( mGanttView, SIGNAL(lvItemLeftClicked(KDGanttViewItem*)), + this, SLOT(showAttendeeStatusMenu()) ); + connect( mGanttView, SIGNAL(lvItemRightClicked(KDGanttViewItem*)), + this, SLOT(showAttendeeStatusMenu()) ); + connect( mGanttView, SIGNAL(lvMouseButtonClicked(int, KDGanttViewItem*, const QPoint&, int)), + this, SLOT(listViewClicked(int, KDGanttViewItem*)) ); + + FreeBusyManager *m = KOGroupware::instance()->freeBusyManager(); + connect( m, SIGNAL( freeBusyRetrieved( KCal::FreeBusy *, const QString & ) ), + SLOT( slotInsertFreeBusy( KCal::FreeBusy *, const QString & ) ) ); + + connect( &mReloadTimer, SIGNAL( timeout() ), SLOT( autoReload() ) ); + + initEditWidgets( this, topLayout ); + connect( mRemoveButton, SIGNAL(clicked()), + SLOT(removeAttendee()) ); + + slotOrganizerChanged( mOrganizerCombo->currentText() ); + connect( mOrganizerCombo, SIGNAL( activated(const QString&) ), + this, SLOT( slotOrganizerChanged(const QString&) ) ); + + //suppress the buggy consequences of clicks on the time header widget + mGanttView->timeHeaderWidget()->installEventFilter( this ); +} + +KOEditorFreeBusy::~KOEditorFreeBusy() +{ +} + +void KOEditorFreeBusy::removeAttendee( Attendee *attendee ) +{ + FreeBusyItem *anItem = + static_cast<FreeBusyItem *>( mGanttView->firstChild() ); + while( anItem ) { + if( anItem->attendee() == attendee ) { + if ( anItem->updateTimerID() != 0 ) + killTimer( anItem->updateTimerID() ); + delete anItem; + updateStatusSummary(); + break; + } + anItem = static_cast<FreeBusyItem *>( anItem->nextSibling() ); + } +} + +void KOEditorFreeBusy::insertAttendee( Attendee *attendee, bool readFBList ) +{ + FreeBusyItem* item = new FreeBusyItem( attendee, mGanttView ); + if ( readFBList ) + updateFreeBusyData( item ); + else { + clearSelection(); + mGanttView->setSelected( item, true ); + } + updateStatusSummary(); + emit updateAttendeeSummary( mGanttView->childCount() ); +} + +void KOEditorFreeBusy::clearAttendees() +{ + mGanttView->clear(); +} + + +void KOEditorFreeBusy::setUpdateEnabled( bool enabled ) +{ + mGanttView->setUpdateEnabled( enabled ); +} + +bool KOEditorFreeBusy::updateEnabled() const +{ + return mGanttView->getUpdateEnabled(); +} + + +void KOEditorFreeBusy::readEvent( Event *event ) +{ + bool block = updateEnabled(); + setUpdateEnabled( false ); + clearAttendees(); + + setDateTimes( event->dtStart(), event->dtEnd() ); + mIsOrganizer = KOPrefs::instance()->thatIsMe( event->organizer().email() ); + updateStatusSummary(); + clearSelection(); + KOAttendeeEditor::readEvent( event ); + + setUpdateEnabled( block ); + emit updateAttendeeSummary( mGanttView->childCount() ); +} + +void KOEditorFreeBusy::slotIntervalColorRectangleMoved( const QDateTime& start, const QDateTime& end ) +{ + kdDebug() << k_funcinfo << "slotIntervalColorRectangleMoved " << start << "," << end << endl; + mDtStart = start; + mDtEnd = end; + emit dateTimesChanged( start, end ); +} + +void KOEditorFreeBusy::setDateTimes( const QDateTime &start, const QDateTime &end ) +{ + slotUpdateGanttView( start, end ); +} + +void KOEditorFreeBusy::slotScaleChanged( int newScale ) +{ + // The +1 is for the Minute scale which we don't offer in the combo box. + KDGanttView::Scale scale = static_cast<KDGanttView::Scale>( newScale+1 ); + mGanttView->setScale( scale ); + slotCenterOnStart(); +} + +void KOEditorFreeBusy::slotCenterOnStart() +{ + mGanttView->centerTimeline( mDtStart ); +} + +void KOEditorFreeBusy::slotZoomToTime() +{ + mGanttView->zoomToFit(); +} + +void KOEditorFreeBusy::updateFreeBusyData( FreeBusyItem* item ) +{ + if ( item->isDownloading() ) + // This item is already in the process of fetching the FB list + return; + + if ( item->updateTimerID() != 0 ) + // An update timer is already running. Reset it + killTimer( item->updateTimerID() ); + + // This item does not have a download running, and no timer is set + // Do the download in five seconds + item->setUpdateTimerID( startTimer( 5000 ) ); +} + +void KOEditorFreeBusy::timerEvent( QTimerEvent* event ) +{ + killTimer( event->timerId() ); + FreeBusyItem *item = static_cast<FreeBusyItem *>( mGanttView->firstChild() ); + while( item ) { + if( item->updateTimerID() == event->timerId() ) { + item->setUpdateTimerID( 0 ); + item->startDownload( mForceDownload ); + return; + } + item = static_cast<FreeBusyItem *>( item->nextSibling() ); + } +} + +// Set the Free Busy list for everyone having this email address +// If fb == 0, this disabled the free busy list for them +void KOEditorFreeBusy::slotInsertFreeBusy( KCal::FreeBusy *fb, + const QString &email ) +{ + kdDebug(5850) << "KOEditorFreeBusy::slotInsertFreeBusy() " << email << endl; + + if( fb ) + fb->sortList(); + bool block = mGanttView->getUpdateEnabled(); + mGanttView->setUpdateEnabled( false ); + for( KDGanttViewItem *it = mGanttView->firstChild(); it; + it = it->nextSibling() ) { + FreeBusyItem *item = static_cast<FreeBusyItem *>( it ); + if( item->email() == email ) + item->setFreeBusyPeriods( fb ); + } + mGanttView->setUpdateEnabled( block ); +} + + +/*! + Centers the Gantt view to the date/time passed in. +*/ + +void KOEditorFreeBusy::slotUpdateGanttView( const QDateTime &dtFrom, const QDateTime &dtTo ) +{ + mDtStart = dtFrom; + mDtEnd = dtTo; + bool block = mGanttView->getUpdateEnabled( ); + mGanttView->setUpdateEnabled( false ); + QDateTime horizonStart = QDateTime( dtFrom.addDays( -15 ).date() ); + mGanttView->setHorizonStart( horizonStart ); + mGanttView->setHorizonEnd( dtTo.addDays( 15 ) ); + mEventRectangle->setDateTimes( dtFrom, dtTo ); + mGanttView->setUpdateEnabled( block ); + mGanttView->centerTimelineAfterShow( dtFrom ); +} + + +/*! + This slot is called when the user clicks the "Pick a date" button. +*/ +void KOEditorFreeBusy::slotPickDate() +{ + QDateTime start = mDtStart; + QDateTime end = mDtEnd; + bool success = findFreeSlot( start, end ); + + if( success ) { + if ( start == mDtStart && end == mDtEnd ) { + KMessageBox::information( this, + i18n( "The meeting already has suitable start/end times." ), QString::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() ), QString::null, + "MeetingMovedFreeBusy" ); + } + } else + KMessageBox::sorry( this, i18n( "No suitable date found." ) ); +} + + +/*! + Finds a free slot in the future which has at least the same size as + the initial slot. +*/ +bool KOEditorFreeBusy::findFreeSlot( QDateTime &dtFrom, QDateTime &dtTo ) +{ + if( tryDate( dtFrom, dtTo ) ) + // Current time is acceptable + return true; + + QDateTime tryFrom = dtFrom; + QDateTime tryTo = dtTo; + + // Make sure that we never suggest a date in the past, even if the + // user originally scheduled the meeting to be in the past. + if( tryFrom < QDateTime::currentDateTime() ) { + // The slot to look for is at least partially in the past. + int secs = tryFrom.secsTo( tryTo ); + tryFrom = QDateTime::currentDateTime(); + tryTo = tryFrom.addSecs( secs ); + } + + bool found = false; + while( !found ) { + found = tryDate( tryFrom, tryTo ); + // PENDING(kalle) Make the interval configurable + if( !found && dtFrom.daysTo( tryFrom ) > 365 ) + break; // don't look more than one year in the future + } + + dtFrom = tryFrom; + dtTo = tryTo; + + return found; +} + + +/*! + Checks whether the slot specified by (tryFrom, tryTo) is free + for all participants. If yes, return true. If at least one + participant is found for which this slot is occupied, this method + returns false, and (tryFrom, tryTo) contain the next free slot for + that participant. In other words, the returned slot does not have to + be free for everybody else. +*/ +bool KOEditorFreeBusy::tryDate( QDateTime& tryFrom, QDateTime& tryTo ) +{ + FreeBusyItem* currentItem = static_cast<FreeBusyItem*>( mGanttView->firstChild() ); + while( currentItem ) { + if( !tryDate( currentItem, tryFrom, tryTo ) ) { + // kdDebug(5850) << "++++date is not OK, new suggestion: " << tryFrom.toString() << " to " << tryTo.toString() << endl; + return false; + } + + currentItem = static_cast<FreeBusyItem*>( currentItem->nextSibling() ); + } + + return true; +} + +/*! + Checks whether the slot specified by (tryFrom, tryTo) is available + for the participant specified with attendee. If yes, return true. If + not, return false and change (tryFrom, tryTo) to contain the next + possible slot for this participant (not necessarily a slot that is + available for all participants). +*/ +bool KOEditorFreeBusy::tryDate( FreeBusyItem *attendee, + QDateTime &tryFrom, QDateTime &tryTo ) +{ + // If we don't have any free/busy information, assume the + // participant is free. Otherwise a participant without available + // information would block the whole allocation. + KCal::FreeBusy *fb = attendee->freeBusy(); + if( !fb ) + return true; + + QValueList<KCal::Period> busyPeriods = fb->busyPeriods(); + for( QValueList<KCal::Period>::Iterator it = busyPeriods.begin(); + it != busyPeriods.end(); ++it ) { + if( (*it).end() <= tryFrom || // busy period ends before try period + (*it).start() >= tryTo ) // busy period starts after try period + continue; + else { + // the current busy period blocks the try period, try + // after the end of the current busy period + int secsDuration = tryFrom.secsTo( tryTo ); + tryFrom = (*it).end(); + tryTo = tryFrom.addSecs( secsDuration ); + // try again with the new try period + tryDate( attendee, tryFrom, tryTo ); + // we had to change the date at least once + return false; + } + } + + return true; +} + +void KOEditorFreeBusy::updateStatusSummary() +{ + FreeBusyItem *aItem = + static_cast<FreeBusyItem *>( mGanttView->firstChild() ); + int total = 0; + int accepted = 0; + int tentative = 0; + int declined = 0; + while( aItem ) { + ++total; + switch( aItem->attendee()->status() ) { + case Attendee::Accepted: + ++accepted; + break; + case Attendee::Tentative: + ++tentative; + break; + case Attendee::Declined: + ++declined; + break; + case Attendee::NeedsAction: + case Attendee::Delegated: + case Attendee::Completed: + case Attendee::InProcess: + /* just to shut up the compiler */ + break; + } + aItem = static_cast<FreeBusyItem *>( aItem->nextSibling() ); + } + if( total > 1 && mIsOrganizer ) { + mStatusSummaryLabel->show(); + mStatusSummaryLabel->setText( + i18n( "Of the %1 participants, %2 have accepted, %3" + " have tentatively accepted, and %4 have declined.") + .arg( total ).arg( accepted ).arg( tentative ).arg( declined ) ); + } else { + mStatusSummaryLabel->hide(); + } + mStatusSummaryLabel->adjustSize(); +} + +void KOEditorFreeBusy::triggerReload() +{ + mReloadTimer.start( 1000, true ); +} + +void KOEditorFreeBusy::cancelReload() +{ + mReloadTimer.stop(); +} + +void KOEditorFreeBusy::manualReload() +{ + mForceDownload = true; + reload(); +} + +void KOEditorFreeBusy::autoReload() +{ + mForceDownload = false; + reload(); +} + +void KOEditorFreeBusy::reload() +{ + kdDebug(5850) << "KOEditorFreeBusy::reload()" << endl; + + FreeBusyItem *item = static_cast<FreeBusyItem *>( mGanttView->firstChild() ); + while( item ) { + if ( mForceDownload ) + item->startDownload( mForceDownload ); + else + updateFreeBusyData( item ); + + item = static_cast<FreeBusyItem *>( item->nextSibling() ); + } +} + +void KOEditorFreeBusy::editFreeBusyUrl( KDGanttViewItem *i ) +{ + FreeBusyItem *item = static_cast<FreeBusyItem *>( i ); + if ( !item ) return; + + Attendee *attendee = item->attendee(); + + FreeBusyUrlDialog dialog( attendee, this ); + dialog.exec(); +} + +void KOEditorFreeBusy::writeEvent(KCal::Event * event) +{ + event->clearAttendees(); + QValueVector<FreeBusyItem*> toBeDeleted; + for ( FreeBusyItem *item = static_cast<FreeBusyItem *>( mGanttView->firstChild() ); item; + item = static_cast<FreeBusyItem*>( item->nextSibling() ) ) + { + Attendee *attendee = item->attendee(); + Q_ASSERT( attendee ); + /* Check if the attendee is a distribution list and expand it */ + if ( attendee->email().isEmpty() ) { + KPIM::DistributionList list = + KPIM::DistributionList::findByName( KABC::StdAddressBook::self(), attendee->name() ); + if ( !list.isEmpty() ) { + toBeDeleted.push_back( item ); // remove it once we are done expanding + KPIM::DistributionList::Entry::List entries = list.entries( KABC::StdAddressBook::self() ); + KPIM::DistributionList::Entry::List::Iterator it( entries.begin() ); + while ( it != entries.end() ) { + KPIM::DistributionList::Entry &e = ( *it ); + ++it; + // this calls insertAttendee, which appends + insertAttendeeFromAddressee( e.addressee, attendee ); + // TODO: duplicate check, in case it was already added manually + } + } + } else { + bool skip = false; + if ( attendee->email().endsWith( "example.net" ) ) { + if ( KMessageBox::warningYesNo( this, i18n("%1 does not look like a valid email address. " + "Are you sure you want to invite this participant?").arg( attendee->email() ), + i18n("Invalid email address") ) != KMessageBox::Yes ) { + skip = true; + } + } + if ( !skip ) { + event->addAttendee( new Attendee( *attendee ) ); + } + } + } + + KOAttendeeEditor::writeEvent( event ); + + // cleanup + QValueVector<FreeBusyItem*>::iterator it; + for( it = toBeDeleted.begin(); it != toBeDeleted.end(); ++it ) { + delete *it; + } +} + +KCal::Attendee * KOEditorFreeBusy::currentAttendee() const +{ + KDGanttViewItem *item = mGanttView->selectedItem(); + FreeBusyItem *aItem = static_cast<FreeBusyItem*>( item ); + if ( !aItem ) + return 0; + return aItem->attendee(); +} + +void KOEditorFreeBusy::updateCurrentItem() +{ + FreeBusyItem* item = static_cast<FreeBusyItem*>( mGanttView->selectedItem() ); + if ( item ) { + item->updateItem(); + updateFreeBusyData( item ); + updateStatusSummary(); + } +} + +void KOEditorFreeBusy::removeAttendee() +{ + FreeBusyItem *item = static_cast<FreeBusyItem*>( mGanttView->selectedItem() ); + if ( !item ) + return; + + Attendee *delA = new Attendee( item->attendee()->name(), item->attendee()->email(), + item->attendee()->RSVP(), item->attendee()->status(), + item->attendee()->role(), item->attendee()->uid() ); + mdelAttendees.append( delA ); + delete item; + + updateStatusSummary(); + updateAttendeeInput(); + emit updateAttendeeSummary( mGanttView->childCount() ); +} + +void KOEditorFreeBusy::clearSelection() const +{ + KDGanttViewItem *item = mGanttView->selectedItem(); + if ( item ) + mGanttView->setSelected( item, false ); + mGanttView->repaint(); + item->repaint(); +} + +void KOEditorFreeBusy::changeStatusForMe(KCal::Attendee::PartStat status) +{ + const QStringList myEmails = KOPrefs::instance()->allEmails(); + for ( FreeBusyItem *item = static_cast<FreeBusyItem *>( mGanttView->firstChild() ); item; + item = static_cast<FreeBusyItem*>( item->nextSibling() ) ) + { + for ( QStringList::ConstIterator it2( myEmails.begin() ), end( myEmails.end() ); it2 != end; ++it2 ) { + if ( item->attendee()->email() == *it2 ) { + item->attendee()->setStatus( status ); + item->updateItem(); + } + } + } +} + +void KOEditorFreeBusy::showAttendeeStatusMenu() +{ + if ( mGanttView->mapFromGlobal( QCursor::pos() ).x() > 22 ) + return; + QPopupMenu popup; + popup.insertItem( SmallIcon( "help" ), Attendee::statusName( Attendee::NeedsAction ), Attendee::NeedsAction ); + popup.insertItem( KOGlobals::self()->smallIcon( "ok" ), Attendee::statusName( Attendee::Accepted ), Attendee::Accepted ); + popup.insertItem( KOGlobals::self()->smallIcon( "no" ), Attendee::statusName( Attendee::Declined ), Attendee::Declined ); + popup.insertItem( KOGlobals::self()->smallIcon( "apply" ), Attendee::statusName( Attendee::Tentative ), Attendee::Tentative ); + popup.insertItem( KOGlobals::self()->smallIcon( "mail_forward" ), Attendee::statusName( Attendee::Delegated ), Attendee::Delegated ); + popup.insertItem( Attendee::statusName( Attendee::Completed ), Attendee::Completed ); + popup.insertItem( KOGlobals::self()->smallIcon( "help" ), Attendee::statusName( Attendee::InProcess ), Attendee::InProcess ); + popup.setItemChecked( currentAttendee()->status(), true ); + int status = popup.exec( QCursor::pos() ); + if ( status >= 0 ) { + currentAttendee()->setStatus( (Attendee::PartStat)status ); + updateCurrentItem(); + updateAttendeeInput(); + } +} + +void KOEditorFreeBusy::listViewClicked(int button, KDGanttViewItem * item) +{ + if ( button == Qt::LeftButton && item == 0 ) + addNewAttendee(); +} + +void KOEditorFreeBusy::slotOrganizerChanged(const QString & newOrganizer) +{ + if (newOrganizer==mCurrentOrganizer) return; + + QString name; + QString email; + bool success = KPIM::getNameAndMail( newOrganizer, name, email ); + + if (!success) return; +// + + Attendee *currentOrganizerAttendee = 0; + Attendee *newOrganizerAttendee = 0; + + FreeBusyItem *anItem = + static_cast<FreeBusyItem *>( mGanttView->firstChild() ); + while( anItem ) { + Attendee *attendee = anItem->attendee(); + if( attendee->fullName() == mCurrentOrganizer ) + currentOrganizerAttendee = attendee; + + if( attendee->fullName() == newOrganizer ) + newOrganizerAttendee = attendee; + + anItem = static_cast<FreeBusyItem *>( anItem->nextSibling() ); + } + + int answer = KMessageBox::No; + + if (currentOrganizerAttendee) { + answer = KMessageBox::questionYesNo( this, i18n("You are changing the organiser of " + "this event, who is also attending, " + "do you want to change that attendee " + "as well?") ); + } else { + answer = KMessageBox::Yes; + } + + if (answer==KMessageBox::Yes) { + if (currentOrganizerAttendee) { + removeAttendee( currentOrganizerAttendee ); + } + + if (!newOrganizerAttendee) { + Attendee *a = new Attendee( name, email, true ); + insertAttendee( a, false ); + updateAttendee(); + } + } + + mCurrentOrganizer = newOrganizer; +} + +bool KOEditorFreeBusy::eventFilter( QObject *watched, QEvent *event ) +{ + if ( watched == mGanttView->timeHeaderWidget() && + event->type() >= QEvent::MouseButtonPress && event->type() <= QEvent::MouseMove ) { + return true; + } else { + return KOAttendeeEditor::eventFilter( watched, event ); + } +} + +#include "koeditorfreebusy.moc" diff --git a/korganizer/koeditorfreebusy.h b/korganizer/koeditorfreebusy.h new file mode 100644 index 000000000..9ff3af21c --- /dev/null +++ b/korganizer/koeditorfreebusy.h @@ -0,0 +1,127 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2000,2001,2004 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOEDITORFREEBUSY_H +#define KOEDITORFREEBUSY_H + +#include "koattendeeeditor.h" + +#include <qwidget.h> +#include <qdatetime.h> +#include <qtimer.h> + +class KDIntervalColorRectangle; +class QLabel; +class KDGanttView; +class KDGanttViewItem; +class FreeBusyItem; + +namespace KCal { + class FreeBusy; + class Attendee; +} + + +class KOEditorFreeBusy : public KOAttendeeEditor +{ + Q_OBJECT + public: + KOEditorFreeBusy( int spacing = 8, QWidget *parent = 0, + const char *name = 0 ); + virtual ~KOEditorFreeBusy(); + + void setUpdateEnabled( bool enabled ); + bool updateEnabled() const; + + void insertAttendee( KCal::Attendee *, bool readFBList = true ); + void removeAttendee( KCal::Attendee * ); + void clearAttendees(); + + void readEvent( KCal::Event * ); + void writeEvent( KCal::Event *event ); + + void triggerReload(); + void cancelReload(); + + signals: + void dateTimesChanged( const QDateTime &, const QDateTime & ); + + public slots: + void slotInsertFreeBusy( KCal::FreeBusy *fb, const QString &email ); + + void setDateTimes( const QDateTime &, const QDateTime & ); + + void editFreeBusyUrl( KDGanttViewItem *item ); + + protected slots: + void slotUpdateGanttView( const QDateTime &, const QDateTime & ); + void slotScaleChanged( int ); + void slotCenterOnStart() ; + void slotZoomToTime(); + void slotPickDate(); + void showAttendeeStatusMenu(); + + // Force the download of FB informations + void manualReload(); + // Only download FB if the auto-download option is set in config + void autoReload(); + void slotIntervalColorRectangleMoved( const QDateTime& start, const QDateTime& end ); + + void removeAttendee(); + void listViewClicked( int button, KDGanttViewItem* item ); + + protected: + void timerEvent( QTimerEvent* ); + KCal::Attendee* currentAttendee() const; + void updateCurrentItem(); + void clearSelection() const; + void changeStatusForMe( KCal::Attendee::PartStat status ); + virtual bool eventFilter( QObject *watched, QEvent *event ); + + private slots: + void slotOrganizerChanged( const QString &newOrganizer ); + private: + void updateFreeBusyData( FreeBusyItem * ); + + bool findFreeSlot( QDateTime &dtFrom, QDateTime &dtTo ); + bool tryDate( QDateTime &tryFrom, QDateTime &tryTo ); + bool tryDate( FreeBusyItem *attendee, + QDateTime &tryFrom, QDateTime &tryTo ); + void updateStatusSummary(); + void reload(); + KDGanttView *mGanttView; + KDIntervalColorRectangle* mEventRectangle; + QLabel *mStatusSummaryLabel; + bool mIsOrganizer; + QComboBox *scaleCombo; + + QDateTime mDtStart, mDtEnd; + + QTimer mReloadTimer; + + bool mForceDownload; + + QString mCurrentOrganizer; +}; + +#endif diff --git a/korganizer/koeditorgeneral.cpp b/korganizer/koeditorgeneral.cpp new file mode 100644 index 000000000..8b93c2ef0 --- /dev/null +++ b/korganizer/koeditorgeneral.cpp @@ -0,0 +1,497 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + + +#include <qwidget.h> +#include <qtooltip.h> +#include <qlayout.h> +#include <qvbox.h> +#include <qhbox.h> +#include <qbuttongroup.h> +#include <qvgroupbox.h> +#include <qwidgetstack.h> +#include <qdatetime.h> +#include <qlineedit.h> +#include <qlabel.h> +#include <qcheckbox.h> +#include <qpushbutton.h> +#include <qcombobox.h> +#include <qspinbox.h> +#include <qwhatsthis.h> + +#include <kglobal.h> +#include <kdialog.h> +#include <kdebug.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kmessagebox.h> +#include <kfiledialog.h> +#include <ksqueezedtextlabel.h> +#include <kstandarddirs.h> +#include <ktextedit.h> +#include <krestrictedline.h> + +#include <libkcal/todo.h> +#include <libkcal/event.h> + +#include <libkdepim/kdateedit.h> +#include <libkdepim/categoryselectdialog.h> + +#include "koprefs.h" +#include "koglobals.h" + +#include "koeditorgeneral.h" +#include "koeditoralarms.h" +#include "koeditorattachments.h" +#include "koeditorgeneral.moc" +#include "kohelper.h" + +KOEditorGeneral::KOEditorGeneral(QObject* parent, const char* name) : + QObject( parent, name ), mAttachments(0) +{ + mAlarmList.setAutoDelete( true ); +} + +KOEditorGeneral::~KOEditorGeneral() +{ +} + + +FocusLineEdit::FocusLineEdit( QWidget *parent ) + : QLineEdit( parent ), mSkipFirst( true ) +{ +} + +void FocusLineEdit::focusInEvent ( QFocusEvent *e ) +{ + if ( !mSkipFirst ) { + emit focusReceivedSignal(); + } else { + mSkipFirst = false; + } + QLineEdit::focusInEvent( e ); +} + + +void KOEditorGeneral::initHeader( QWidget *parent,QBoxLayout *topLayout) +{ + QGridLayout *headerLayout = new QGridLayout(); + headerLayout->setSpacing( topLayout->spacing() ); + topLayout->addLayout( headerLayout ); + +#if 0 + mOwnerLabel = new QLabel(i18n("Owner:"),parent); + headerLayout->addMultiCellWidget(mOwnerLabel,0,0,0,1); +#endif + + QString whatsThis = i18n("Sets the Title of this event or to-do."); + QLabel *summaryLabel = new QLabel( i18n("T&itle:"), parent ); + QWhatsThis::add( summaryLabel, whatsThis ); + QFont f = summaryLabel->font(); + f.setBold( true ); + summaryLabel->setFont(f); + headerLayout->addWidget(summaryLabel,1,0); + + mSummaryEdit = new FocusLineEdit( parent ); + QWhatsThis::add( mSummaryEdit, whatsThis ); + connect( mSummaryEdit, SIGNAL( focusReceivedSignal() ), + SIGNAL( focusReceivedSignal() ) ); + headerLayout->addWidget(mSummaryEdit,1,1); + summaryLabel->setBuddy( mSummaryEdit ); + + mAttendeeSummaryLabel = new QLabel( parent ); + updateAttendeeSummary( 0 ); + headerLayout->addWidget( mAttendeeSummaryLabel, 1, 2 ); + + whatsThis = i18n("Sets where the event or to-do will take place."); + QLabel *locationLabel = new QLabel( i18n("&Location:"), parent ); + QWhatsThis::add( locationLabel, whatsThis ); + headerLayout->addWidget(locationLabel,2,0); + + mLocationEdit = new QLineEdit( parent ); + QWhatsThis::add( mLocationEdit, whatsThis ); + headerLayout->addMultiCellWidget( mLocationEdit, 2, 2, 1, 2 ); + locationLabel->setBuddy( mLocationEdit ); + + QBoxLayout *thirdLineLayout = new QHBoxLayout(); + headerLayout->addMultiCellLayout( thirdLineLayout, 3, 3, 0, 2 ); + + mResourceLabel = new QLabel( parent ); + mResourceLabel->hide(); + thirdLineLayout->addWidget( mResourceLabel ); + + whatsThis = i18n("Allows you to select the categories that this event or to-do belongs to."); + QLabel *categoriesLabel = new QLabel( i18n("Categories:"), parent ); + QWhatsThis::add( categoriesLabel, whatsThis ); + thirdLineLayout->addWidget( categoriesLabel ); + mCategoriesLabel = new KSqueezedTextLabel( parent ); + QWhatsThis::add( mCategoriesLabel, whatsThis ); + mCategoriesLabel->setFrameStyle(QFrame::Panel|QFrame::Sunken); + thirdLineLayout->addWidget( mCategoriesLabel ); + + mCategoriesButton = new QPushButton( parent ); + mCategoriesButton->setText(i18n("&Select...")); + QWhatsThis::add( mCategoriesButton, whatsThis ); + connect(mCategoriesButton,SIGNAL(clicked()),SLOT(selectCategories())); + thirdLineLayout->addWidget( mCategoriesButton ); +} + +void KOEditorGeneral::initSecrecy(QWidget *parent, QBoxLayout *topLayout) +{ + QBoxLayout *secrecyLayout = new QHBoxLayout( topLayout ); + + QLabel *secrecyLabel = new QLabel(i18n("Acc&ess:"),parent); + QString whatsThis = i18n("Sets whether the access to this event or to-do " + "is restricted. Please note that KOrganizer " + "currently does not use this setting, so the " + "implementation of the restrictions will depend " + "on the groupware server. This means that events " + "or to-dos marked as private or confidential may " + "be visible to others."); + QWhatsThis::add( secrecyLabel, whatsThis ); + secrecyLayout->addWidget(secrecyLabel); + + mSecrecyCombo = new QComboBox(parent); + QWhatsThis::add( mSecrecyCombo, whatsThis ); + mSecrecyCombo->insertStringList(Incidence::secrecyList()); + secrecyLayout->addWidget(mSecrecyCombo); + secrecyLabel->setBuddy( mSecrecyCombo ); +} + +void KOEditorGeneral::initDescription(QWidget *parent,QBoxLayout *topLayout) +{ + mDescriptionEdit = new KTextEdit(parent); + QWhatsThis::add( mDescriptionEdit, + i18n("Sets the description for this event or to-do. This " + "will be displayed in a reminder if one is set, " + "as well as in a tooltip when you hover over the " + "event.") ); + mDescriptionEdit->append(""); + mDescriptionEdit->setReadOnly(false); + mDescriptionEdit->setOverwriteMode(false); + mDescriptionEdit->setWordWrap( KTextEdit::WidgetWidth ); + mDescriptionEdit->setTabChangesFocus( true );; + topLayout->addWidget(mDescriptionEdit, 4); +} + +void KOEditorGeneral::initAlarm(QWidget *parent,QBoxLayout *topLayout) +{ + QBoxLayout *alarmLayout = new QHBoxLayout(topLayout); + + mAlarmBell = new QLabel(parent); + mAlarmBell->setPixmap(KOGlobals::self()->smallIcon("bell")); + alarmLayout->addWidget( mAlarmBell ); + + + mAlarmStack = new QWidgetStack( parent ); + alarmLayout->addWidget( mAlarmStack ); + + mAlarmInfoLabel = new QLabel( i18n("No reminders configured"), mAlarmStack ); + mAlarmStack->addWidget( mAlarmInfoLabel, AdvancedAlarmLabel ); + + QHBox *simpleAlarmBox = new QHBox( mAlarmStack ); + mAlarmStack->addWidget( simpleAlarmBox, SimpleAlarmPage ); + + mAlarmButton = new QCheckBox(i18n("&Reminder:"), simpleAlarmBox ); + QWhatsThis::add( mAlarmButton, + i18n("Activates a reminder for this event or to-do.") ); + + QString whatsThis = i18n("Sets how long before the event occurs " + "the reminder will be triggered."); + mAlarmTimeEdit = new QSpinBox( 0, 99999, 1, simpleAlarmBox, "alarmTimeEdit" ); + mAlarmTimeEdit->setValue( 0 ); + QWhatsThis::add( mAlarmTimeEdit, whatsThis ); + + mAlarmIncrCombo = new QComboBox( false, simpleAlarmBox ); + QWhatsThis::add( mAlarmIncrCombo, whatsThis ); + mAlarmIncrCombo->insertItem( i18n("minute(s)") ); + mAlarmIncrCombo->insertItem( i18n("hour(s)") ); + mAlarmIncrCombo->insertItem( i18n("day(s)") ); +// mAlarmIncrCombo->setMinimumHeight(20); + connect(mAlarmButton, SIGNAL(toggled(bool)), mAlarmTimeEdit, SLOT(setEnabled(bool))); + connect(mAlarmButton, SIGNAL(toggled(bool)), mAlarmIncrCombo, SLOT(setEnabled(bool))); + mAlarmTimeEdit->setEnabled( false ); + mAlarmIncrCombo->setEnabled( false ); + + mAlarmEditButton = new QPushButton( i18n("Advanced"), parent ); + mAlarmEditButton->setEnabled( false ); + alarmLayout->addWidget( mAlarmEditButton ); + connect( mAlarmButton, SIGNAL(toggled(bool)), mAlarmEditButton, SLOT(setEnabled( bool))); + connect( mAlarmEditButton, SIGNAL( clicked() ), + SLOT( editAlarms() ) ); + +} + +void KOEditorGeneral::initAttachments(QWidget *parent,QBoxLayout *topLayout) +{ + mAttachments = new KOEditorAttachments( KDialog::spacingHint(), parent ); + connect( mAttachments, SIGNAL( openURL( const KURL & ) ) , + this, SIGNAL( openURL( const KURL & ) ) ); + topLayout->addWidget( mAttachments, 1 ); +} + +void KOEditorGeneral::addAttachments( const QStringList &attachments, + const QStringList &mimeTypes, + bool inlineAttachments ) +{ + QStringList::ConstIterator it; + uint i = 0; + for ( it = attachments.begin(); it != attachments.end(); ++it, ++i ) { + QString mimeType; + if ( mimeTypes.count() > i ) + mimeType = mimeTypes[ i ]; + mAttachments->addAttachment( *it, mimeType, !inlineAttachments ); + } +} + +void KOEditorGeneral::selectCategories() +{ + KPIM::CategorySelectDialog *categoryDialog = new KPIM::CategorySelectDialog( KOPrefs::instance(), mCategoriesButton ); + KOGlobals::fitDialogToScreen( categoryDialog ); + categoryDialog->setSelected( mCategories ); + + connect(categoryDialog, SIGNAL(editCategories()), this, SIGNAL(openCategoryDialog())); + connect(this, SIGNAL(updateCategoryConfig()), categoryDialog, SLOT(updateCategoryConfig())); + + if ( categoryDialog->exec() ) { + setCategories( categoryDialog->selectedCategories() ); + } + delete categoryDialog; +} + + +void KOEditorGeneral::editAlarms() +{ + if ( mAlarmStack->id( mAlarmStack->visibleWidget() ) == SimpleAlarmPage ) { + mAlarmList.clear(); + Alarm *al = alarmFromSimplePage(); + if ( al ) { + mAlarmList.append( al ); + } + } + + KOEditorAlarms *dlg = new KOEditorAlarms( &mAlarmList, mAlarmEditButton ); + if ( dlg->exec() != KDialogBase::Cancel ) { + updateAlarmWidgets(); + } +} + + +void KOEditorGeneral::enableAlarm( bool enable ) +{ + mAlarmStack->setEnabled( enable ); + mAlarmEditButton->setEnabled( enable ); +} + + +void KOEditorGeneral::toggleAlarm( bool on ) +{ + mAlarmButton->setChecked( on ); +} + +void KOEditorGeneral::setCategories( const QStringList &categories ) +{ + mCategoriesLabel->setText( categories.join(",") ); + mCategories = categories; +} + +void KOEditorGeneral::setDefaults(bool /*allDay*/) +{ +#if 0 + mOwnerLabel->setText(i18n("Owner: ") + KOPrefs::instance()->fullName()); +#endif + + mAlarmList.clear(); + updateDefaultAlarmTime(); + updateAlarmWidgets(); + + 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]; + } + mAlarmTimeEdit->setValue(alarmTime); +} + +void KOEditorGeneral::updateAlarmWidgets() +{ + if ( mAlarmList.isEmpty() ) { + mAlarmStack->raiseWidget( SimpleAlarmPage ); + mAlarmButton->setChecked( false ); + 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... + + 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(); + + offset = offset / -60; // make minutes + int useoffset = offset; + 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? + useoffset = offset / 60; + mAlarmIncrCombo->setCurrentItem(1); + } + mAlarmTimeEdit->setValue( useoffset ); + } else { + mAlarmStack->raiseWidget( AdvancedAlarmLabel ); + mAlarmInfoLabel->setText( i18n("1 advanced reminder configured") ); + mAlarmEditButton->setEnabled( true ); + } + } +} + +void KOEditorGeneral::readIncidence(Incidence *event, Calendar *calendar) +{ + mSummaryEdit->setText(event->summary()); + mLocationEdit->setText(event->location()); + + mDescriptionEdit->setText(event->description()); + +#if 0 + // organizer information + mOwnerLabel->setText(i18n("Owner: ") + event->organizer().fullName() ); +#endif + + mSecrecyCombo->setCurrentItem(event->secrecy()); + + // set up alarm stuff + mAlarmList.clear(); + Alarm::List::ConstIterator it; + Alarm::List alarms = event->alarms(); + for( it = alarms.begin(); it != alarms.end(); ++it ) { + Alarm *al = new Alarm( *(*it) ); + al->setParent( 0 ); + mAlarmList.append( al ); + } + updateDefaultAlarmTime(); + updateAlarmWidgets(); + + setCategories(event->categories()); + + mAttachments->readIncidence( event ); + + QString resLabel = KOHelper::resourceLabel( calendar, event ); + if ( !resLabel.isEmpty() ) { + mResourceLabel->setText( i18n( "Calendar: %1" ).arg( resLabel ) ); + mResourceLabel->show(); + } +} + +Alarm *KOEditorGeneral::alarmFromSimplePage() const +{ + if ( mAlarmButton->isChecked() ) { + Alarm *alarm = new Alarm( 0 ); + alarm->setDisplayAlarm(""); + alarm->setEnabled(true); + QString tmpStr = mAlarmTimeEdit->text(); + int j = mAlarmTimeEdit->value() * -60; + if (mAlarmIncrCombo->currentItem() == 1) + j = j * 60; + else if (mAlarmIncrCombo->currentItem() == 2) + j = j * (60 * 24); + alarm->setStartOffset( j ); + return alarm; + } else { + return 0; + } +} +void KOEditorGeneral::writeIncidence(Incidence *event) +{ +// kdDebug(5850) << "KOEditorGeneral::writeEvent()" << endl; + + event->setSummary(mSummaryEdit->text()); + event->setLocation(mLocationEdit->text()); + event->setDescription(mDescriptionEdit->text()); + event->setCategories(mCategories); + event->setSecrecy(mSecrecyCombo->currentItem()); + + // alarm stuff + event->clearAlarms(); + if ( mAlarmStack->id( mAlarmStack->visibleWidget() ) == SimpleAlarmPage ) { + Alarm *al = alarmFromSimplePage(); + if ( al ) { + al->setParent( event ); + event->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 ); + } + } + mAttachments->writeIncidence( event ); +} + +void KOEditorGeneral::setSummary( const QString &text ) +{ + mSummaryEdit->setText( text ); +} + +void KOEditorGeneral::setDescription( const QString &text ) +{ + mDescriptionEdit->setText( text ); +} + +QObject *KOEditorGeneral::typeAheadReceiver() const +{ + return mSummaryEdit; +} + +void KOEditorGeneral::updateAttendeeSummary(int count) +{ + if ( count <= 0 ) + mAttendeeSummaryLabel->setText( "No attendees" ); + else + mAttendeeSummaryLabel->setText( i18n( "One attendee", "%n attendees", count ) ); +} diff --git a/korganizer/koeditorgeneral.h b/korganizer/koeditorgeneral.h new file mode 100644 index 000000000..b369c2389 --- /dev/null +++ b/korganizer/koeditorgeneral.h @@ -0,0 +1,143 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOEDITORGENERAL_H +#define KOEDITORGENERAL_H + +#include <libkcal/alarm.h> +#include <qlineedit.h> + +class QWidget; +class QBoxLayout; +class QLineEdit; +class QLabel; +class QCheckBox; +class QWidgetStack; +class QSpinBox; +class QPushButton; +class QComboBox; +class KTextEdit; +class KSqueezedTextLabel; +class KURL; +class KOEditorAttachments; + +namespace KCal { +class Incidence; +class Calendar; +} +using namespace KCal; + +class FocusLineEdit : public QLineEdit +{ + Q_OBJECT + public: + FocusLineEdit( QWidget *parent ); + + signals: + void focusReceivedSignal(); + + protected: + void focusInEvent ( QFocusEvent *e ); + + private: + bool mSkipFirst; +}; + +class KOEditorGeneral : public QObject +{ + Q_OBJECT + public: + KOEditorGeneral (QObject* parent=0,const char* name=0); + virtual ~KOEditorGeneral(); + + void initHeader( QWidget *parent,QBoxLayout *topLayout ); + void initDescription(QWidget *,QBoxLayout *); + void initSecrecy(QWidget *,QBoxLayout *); + void initAlarm(QWidget *,QBoxLayout *); + void initAttachments(QWidget *,QBoxLayout *); + + /** 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 *); + + /** Check if the input is valid. */ + bool validateInput() { return true; } + + void enableAlarm( bool enable ); + void toggleAlarm( bool on ); + + void setSummary( const QString & ); + void setDescription( const QString & ); + + QObject *typeAheadReceiver() const; + + public slots: + void setCategories(const QStringList &categories); + void selectCategories(); + void addAttachments( const QStringList &attachments, + const QStringList& mimeTypes = QStringList(), + bool inlineAttachment = false ); + + + protected slots: + void editAlarms(); + void updateAlarmWidgets(); + void updateDefaultAlarmTime(); + void updateAttendeeSummary( int count ); + + signals: + void openCategoryDialog(); + void updateCategoryConfig(); + void focusReceivedSignal(); + void openURL( const KURL & ); + protected: + Alarm *alarmFromSimplePage() const; + + QLineEdit *mSummaryEdit; + QLineEdit *mLocationEdit; + QLabel *mAttendeeSummaryLabel; + QLabel *mAlarmBell; + QWidgetStack *mAlarmStack; + QLabel *mAlarmInfoLabel; + QCheckBox *mAlarmButton; + QSpinBox *mAlarmTimeEdit; + QComboBox *mAlarmIncrCombo; + QPushButton *mAlarmEditButton; + KTextEdit *mDescriptionEdit; + QLabel *mOwnerLabel; + QComboBox *mSecrecyCombo; + QPushButton *mCategoriesButton; + KSqueezedTextLabel *mCategoriesLabel; + KOEditorAttachments *mAttachments; + QLabel *mResourceLabel; + + enum AlarmStackPages { SimpleAlarmPage, AdvancedAlarmLabel }; + + private: + QStringList mCategories; + KCal::Alarm::List mAlarmList; +}; + +#endif diff --git a/korganizer/koeditorgeneralevent.cpp b/korganizer/koeditorgeneralevent.cpp new file mode 100644 index 000000000..e9bc44d6d --- /dev/null +++ b/korganizer/koeditorgeneralevent.cpp @@ -0,0 +1,524 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qtooltip.h> +#include <qlayout.h> +#include <qvbox.h> +#include <qbuttongroup.h> +#include <qvgroupbox.h> +#include <qwidgetstack.h> +#include <qspinbox.h> +#include <qdatetime.h> +#include <qlabel.h> +#include <qcheckbox.h> +#include <qcombobox.h> +#include <qpushbutton.h> +#include <qwhatsthis.h> + +#include <kdebug.h> +#include <kglobal.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kmessagebox.h> +#include <kfiledialog.h> +#include <kstandarddirs.h> +#include <ktextedit.h> + +#include <libkcal/event.h> +#include <libkcal/incidenceformatter.h> + +#include "ktimeedit.h" +#include <libkdepim/kdateedit.h> + +#include "koprefs.h" + +#include "koeditorgeneralevent.h" +#include "koeditorgeneralevent.moc" + +KOEditorGeneralEvent::KOEditorGeneralEvent(QObject* parent, + const char* name) : + KOEditorGeneral( parent, name) +{ + connect( this, SIGNAL( dateTimesChanged( const QDateTime &, const QDateTime & )), + SLOT( setDuration() ) ); + connect( this, SIGNAL( dateTimesChanged( const QDateTime &, const QDateTime & )), + SLOT( emitDateTimeStr() )); +} + +KOEditorGeneralEvent::~KOEditorGeneralEvent() +{ +} + +void KOEditorGeneralEvent::finishSetup() +{ + QWidget::setTabOrder( mSummaryEdit, mLocationEdit ); + QWidget::setTabOrder( mLocationEdit, mStartDateEdit ); + QWidget::setTabOrder( mStartDateEdit, mStartTimeEdit ); + QWidget::setTabOrder( mStartTimeEdit, mEndDateEdit ); + QWidget::setTabOrder( mEndDateEdit, mEndTimeEdit ); + QWidget::setTabOrder( mEndTimeEdit, mAlldayEventCheckbox ); + QWidget::setTabOrder( mAlldayEventCheckbox, mAlarmButton ); + QWidget::setTabOrder( mAlarmButton, mAlarmTimeEdit ); + QWidget::setTabOrder( mAlarmTimeEdit, mAlarmIncrCombo ); +// QWidget::setTabOrder( mAlarmIncrCombo, mAlarmSoundButton ); + QWidget::setTabOrder( mAlarmIncrCombo, mAlarmEditButton ); +// QWidget::setTabOrder( mAlarmSoundButton, mAlarmProgramButton ); +// QWidget::setTabOrder( mAlarmProgramButton, mFreeTimeCombo ); + QWidget::setTabOrder( mAlarmEditButton, mFreeTimeCombo ); + QWidget::setTabOrder( mFreeTimeCombo, mDescriptionEdit ); + QWidget::setTabOrder( mDescriptionEdit, mCategoriesButton ); + QWidget::setTabOrder( mCategoriesButton, mSecrecyCombo ); +// QWidget::setTabOrder( mSecrecyCombo, mDescriptionEdit ); + + mSummaryEdit->setFocus(); +} + +void KOEditorGeneralEvent::initTime(QWidget *parent,QBoxLayout *topLayout) +{ + QBoxLayout *timeLayout = new QVBoxLayout(topLayout); + + QGroupBox *timeGroupBox = new QGroupBox(1,QGroupBox::Horizontal, + i18n("Date && Time"),parent); + QWhatsThis::add( timeGroupBox, + i18n("Sets options related to the date and time of the " + "event or to-do.") ); + timeLayout->addWidget(timeGroupBox); + + QFrame *timeBoxFrame = new QFrame(timeGroupBox); + + QGridLayout *layoutTimeBox = new QGridLayout( timeBoxFrame ); + layoutTimeBox->setSpacing(topLayout->spacing()); + layoutTimeBox->setColStretch( 3, 1 ); + + mStartDateLabel = new QLabel(i18n("&Start:"),timeBoxFrame); + layoutTimeBox->addWidget(mStartDateLabel,0,0); + + mStartDateEdit = new KDateEdit(timeBoxFrame); + layoutTimeBox->addWidget(mStartDateEdit,0,1); + mStartDateLabel->setBuddy( mStartDateEdit ); + + mStartTimeEdit = new KTimeEdit(timeBoxFrame); + layoutTimeBox->addWidget(mStartTimeEdit,0,2); + + + mEndDateLabel = new QLabel(i18n("&End:"),timeBoxFrame); + layoutTimeBox->addWidget(mEndDateLabel,1,0); + + mEndDateEdit = new KDateEdit(timeBoxFrame); + layoutTimeBox->addWidget(mEndDateEdit,1,1); + mEndDateLabel->setBuddy( mEndDateEdit ); + + mEndTimeEdit = new KTimeEdit(timeBoxFrame); + layoutTimeBox->addWidget(mEndTimeEdit,1,2); + + mAlldayEventCheckbox = new QCheckBox(i18n("All-&day"),timeBoxFrame); + layoutTimeBox->addWidget( mAlldayEventCheckbox, 0, 3 ); + connect(mAlldayEventCheckbox, SIGNAL(toggled(bool)),SLOT(associateTime(bool))); + + mDurationLabel = new QLabel( timeBoxFrame ); + layoutTimeBox->addWidget( mDurationLabel, 1, 3 ); + + // time widgets are checked if they contain a valid time + connect(mStartTimeEdit, SIGNAL(timeChanged(QTime)), + this, SLOT(startTimeChanged(QTime))); + connect(mEndTimeEdit, SIGNAL(timeChanged(QTime)), + this, SLOT(endTimeChanged(QTime))); + + // date widgets are checked if they contain a valid date + connect(mStartDateEdit, SIGNAL(dateChanged(const QDate&)), + this, SLOT(startDateChanged(const QDate&))); + connect(mEndDateEdit, SIGNAL(dateChanged(const QDate&)), + this, SLOT(endDateChanged(const QDate&))); + + QBoxLayout *recLayout = new QHBoxLayout(); + layoutTimeBox->addMultiCellLayout( recLayout, 2, 2, 1, 4 ); + mRecurrenceSummary = new QLabel( QString(), timeBoxFrame ); + recLayout->addWidget( mRecurrenceSummary ); + QPushButton *recEditButton = new QPushButton( i18n("Edit..."), timeBoxFrame ); + recLayout->addWidget( recEditButton ); + connect( recEditButton, SIGNAL(clicked()), SIGNAL(editRecurrence()) ); + recLayout->addStretch( 1 ); + + QLabel *label = new QLabel( i18n("Reminder:"), timeBoxFrame ); + layoutTimeBox->addWidget( label, 3, 0 ); + QBoxLayout *alarmLineLayout = new QHBoxLayout(); + layoutTimeBox->addMultiCellLayout( alarmLineLayout, 3, 3, 1, 4 ); + initAlarm( timeBoxFrame, alarmLineLayout ); + alarmLineLayout->addStretch( 1 ); + + QBoxLayout *secLayout = new QHBoxLayout(); + layoutTimeBox->addLayout( secLayout, 0, 4 ); + initSecrecy( timeBoxFrame, secLayout ); + + QBoxLayout *classLayout = new QHBoxLayout(); + layoutTimeBox->addLayout( classLayout, 1, 4 ); + initClass( timeBoxFrame, classLayout ); +} + +void KOEditorGeneralEvent::initClass(QWidget *parent,QBoxLayout *topLayout) +{ + QBoxLayout *classLayout = new QHBoxLayout(topLayout); + + QLabel *freeTimeLabel = new QLabel(i18n("S&how time as:"),parent); + QString whatsThis = i18n("Sets how this time will appear on your Free/Busy " + "information."); + QWhatsThis::add( freeTimeLabel, whatsThis ); + classLayout->addWidget(freeTimeLabel); + + mFreeTimeCombo = new QComboBox(false, parent); + QWhatsThis::add( mFreeTimeCombo, whatsThis ); + mFreeTimeCombo->insertItem(i18n("Busy")); + mFreeTimeCombo->insertItem(i18n("Free")); + classLayout->addWidget(mFreeTimeCombo); + freeTimeLabel->setBuddy( mFreeTimeCombo ); +} + +void KOEditorGeneralEvent::initInvitationBar(QWidget * parent, QBoxLayout * layout) +{ + QBoxLayout *topLayout = new QHBoxLayout( layout ); + mInvitationBar = new QFrame( parent ); + mInvitationBar->setPaletteBackgroundColor( KGlobalSettings::alternateBackgroundColor() ); + topLayout->addWidget( mInvitationBar ); + + QBoxLayout *barLayout = new QHBoxLayout( mInvitationBar ); + barLayout->setSpacing( layout->spacing() ); + QLabel *label = new QLabel( i18n("You have not yet definitely responded to this invitation." ), mInvitationBar ); + barLayout->addWidget( label ); + barLayout->addStretch( 1 ); + QPushButton *button = new QPushButton( i18n("Accept"), mInvitationBar ); + connect( button, SIGNAL(clicked()), SIGNAL(acceptInvitation()) ); + connect( button, SIGNAL(clicked()), mInvitationBar, SLOT(hide()) ); + barLayout->addWidget( button ); + button = new QPushButton( i18n("Decline"), mInvitationBar ); + connect( button, SIGNAL(clicked()), SIGNAL(declineInvitation()) ); + connect( button, SIGNAL(clicked()), mInvitationBar, SLOT(hide()) ); + barLayout->addWidget( button ); + + mInvitationBar->hide(); +} + +void KOEditorGeneralEvent::timeStuffDisable(bool disable) +{ + mStartTimeEdit->setEnabled( !disable ); + mEndTimeEdit->setEnabled( !disable ); + + setDuration(); + emitDateTimeStr(); +} + +void KOEditorGeneralEvent::associateTime(bool time) +{ + timeStuffDisable(time); + //if(alarmButton->isChecked()) alarmStuffDisable(noTime); + allDayChanged(time); +} + +void KOEditorGeneralEvent::setDateTimes( const QDateTime &start, const QDateTime &end ) +{ +// kdDebug(5850) << "KOEditorGeneralEvent::setDateTimes(): Start DateTime: " << start.toString() << endl; + + mStartDateEdit->setDate(start.date()); + // KTimeEdit seems to emit some signals when setTime() is called. + mStartTimeEdit->blockSignals( true ); + mStartTimeEdit->setTime(start.time()); + mStartTimeEdit->blockSignals( false ); + mEndDateEdit->setDate(end.date()); + mEndTimeEdit->setTime(end.time()); + + mCurrStartDateTime = start; + mCurrEndDateTime = end; + + setDuration(); + emitDateTimeStr(); +} + +void KOEditorGeneralEvent::startTimeChanged( QTime newtime ) +{ + kdDebug(5850) << "KOEditorGeneralEvent::startTimeChanged() " << newtime.toString() << endl; + + int secsep = mCurrStartDateTime.secsTo(mCurrEndDateTime); + + mCurrStartDateTime.setTime(newtime); + + // adjust end time so that the event has the same duration as before. + mCurrEndDateTime = mCurrStartDateTime.addSecs(secsep); + mEndTimeEdit->setTime(mCurrEndDateTime.time()); + mEndDateEdit->setDate(mCurrEndDateTime.date()); + + emit dateTimesChanged(mCurrStartDateTime,mCurrEndDateTime); +} + +void KOEditorGeneralEvent::endTimeChanged( QTime newtime ) +{ +// kdDebug(5850) << "KOEditorGeneralEvent::endTimeChanged " << newtime.toString() << endl; + + QDateTime newdt(mCurrEndDateTime.date(), newtime); + mCurrEndDateTime = newdt; + + emit dateTimesChanged(mCurrStartDateTime,mCurrEndDateTime); +} + +void KOEditorGeneralEvent::startDateChanged( const QDate &newdate ) +{ + if ( !newdate.isValid() ) + return; + + int daysep = mCurrStartDateTime.daysTo(mCurrEndDateTime); + + mCurrStartDateTime.setDate(newdate); + + // adjust end date so that the event has the same duration as before + mCurrEndDateTime.setDate(mCurrStartDateTime.date().addDays(daysep)); + mEndDateEdit->setDate(mCurrEndDateTime.date()); + + emit dateTimesChanged(mCurrStartDateTime,mCurrEndDateTime); +} + +void KOEditorGeneralEvent::endDateChanged( const QDate &newdate ) +{ + if ( !newdate.isValid() ) + return; + + QDateTime newdt(newdate, mCurrEndDateTime.time()); + mCurrEndDateTime = newdt; + + emit dateTimesChanged(mCurrStartDateTime,mCurrEndDateTime); +} + +void KOEditorGeneralEvent::setDefaults( const QDateTime &from, + const QDateTime &to, bool allDay) +{ + KOEditorGeneral::setDefaults(allDay); + + mAlldayEventCheckbox->setChecked(allDay); + timeStuffDisable(allDay); + + setDateTimes(from,to); +} + +void KOEditorGeneralEvent::readEvent( Event *event, Calendar *calendar, bool tmpl ) +{ + QString tmpStr; + + mAlldayEventCheckbox->setChecked(event->doesFloat()); + timeStuffDisable(event->doesFloat()); + + if ( !tmpl ) { + // the rest is for the events only + setDateTimes(event->dtStart(),event->dtEnd()); + } + + switch( event->transparency() ) { + case Event::Transparent: + mFreeTimeCombo->setCurrentItem(1); + break; + case Event::Opaque: + mFreeTimeCombo->setCurrentItem(0); + break; + } + + mRecurrenceSummary->setText( IncidenceFormatter::recurrenceString( event ) ); + + Attendee *me = event->attendeeByMails( KOPrefs::instance()->allEmails() ); + if ( me && (me->status() == Attendee::NeedsAction || me->status() == Attendee::Tentative || + me->status() == Attendee::InProcess) ) { + mInvitationBar->show(); + } else { + mInvitationBar->hide(); + } + + readIncidence(event, calendar); +} + +void KOEditorGeneralEvent::writeEvent(Event *event) +{ +// kdDebug(5850) << "KOEditorGeneralEvent::writeEvent()" << endl; + + writeIncidence(event); + + QDate tmpDate; + QTime tmpTime; + QDateTime tmpDT; + + // temp. until something better happens. + QString tmpStr; + + if (mAlldayEventCheckbox->isChecked()) { + event->setFloats(true); + // need to change this. + tmpDate = mStartDateEdit->date(); + tmpTime.setHMS(0,0,0); + tmpDT.setDate(tmpDate); + tmpDT.setTime(tmpTime); + event->setDtStart(tmpDT); + + tmpDate = mEndDateEdit->date(); + tmpTime.setHMS(0,0,0); + tmpDT.setDate(tmpDate); + tmpDT.setTime(tmpTime); + event->setDtEnd(tmpDT); + } else { + event->setFloats(false); + + // set date/time end + tmpDate = mEndDateEdit->date(); + tmpTime = mEndTimeEdit->getTime(); + tmpDT.setDate(tmpDate); + tmpDT.setTime(tmpTime); + event->setDtEnd(tmpDT); + + // set date/time start + tmpDate = mStartDateEdit->date(); + tmpTime = mStartTimeEdit->getTime(); + tmpDT.setDate(tmpDate); + tmpDT.setTime(tmpTime); + event->setDtStart(tmpDT); + } // check for float + + event->setTransparency(mFreeTimeCombo->currentItem() > 0 + ? KCal::Event::Transparent + : KCal::Event::Opaque); + +// kdDebug(5850) << "KOEditorGeneralEvent::writeEvent() done" << endl; +} + +void KOEditorGeneralEvent::setDuration() +{ + QString tmpStr, catStr; + int hourdiff, minutediff; + // end<date is an accepted temporary state while typing, but don't show + // any duration if this happens + if(mCurrEndDateTime >= mCurrStartDateTime) { + + if (mAlldayEventCheckbox->isChecked()) { + int daydiff = mCurrStartDateTime.date().daysTo(mCurrEndDateTime.date()) + 1; + tmpStr = i18n("Duration: "); + tmpStr.append(i18n("1 Day","%n Days",daydiff)); + } else { + hourdiff = mCurrStartDateTime.date().daysTo(mCurrEndDateTime.date()) * 24; + hourdiff += mCurrEndDateTime.time().hour() - + mCurrStartDateTime.time().hour(); + minutediff = mCurrEndDateTime.time().minute() - + mCurrStartDateTime.time().minute(); + // If minutediff is negative, "borrow" 60 minutes from hourdiff + if (minutediff < 0 && hourdiff > 0) { + hourdiff -= 1; + minutediff += 60; + } + if (hourdiff || minutediff){ + tmpStr = i18n("Duration: "); + if (hourdiff){ + catStr = i18n("1 hour","%n hours",hourdiff); + tmpStr.append(catStr); + } + if (hourdiff && minutediff){ + tmpStr += i18n(", "); + } + if (minutediff){ + catStr = i18n("1 minute","%n minutes",minutediff); + tmpStr += catStr; + } + } else tmpStr = ""; + } + } + mDurationLabel->setText(tmpStr); + QWhatsThis::add( mDurationLabel, + i18n("Shows the duration of the event or to-do with the " + "current start and end dates and times.") ); +} + +void KOEditorGeneralEvent::emitDateTimeStr() +{ + KLocale *l = KGlobal::locale(); + + QString from,to; + if (mAlldayEventCheckbox->isChecked()) { + from = l->formatDate(mCurrStartDateTime.date()); + to = l->formatDate(mCurrEndDateTime.date()); + } else { + from = l->formatDateTime(mCurrStartDateTime); + to = l->formatDateTime(mCurrEndDateTime); + } + + QString str = i18n("From: %1 To: %2 %3").arg(from).arg(to) + .arg(mDurationLabel->text()); + + emit dateTimeStrChanged(str); +} + +bool KOEditorGeneralEvent::validateInput() +{ +// kdDebug(5850) << "KOEditorGeneralEvent::validateInput()" << endl; + + if (!mAlldayEventCheckbox->isChecked()) { + if (!mStartTimeEdit->inputIsValid()) { + KMessageBox::sorry( 0, + i18n("Please specify a valid start time, for example '%1'.") + .arg( KGlobal::locale()->formatTime( QTime::currentTime() ) ) ); + return false; + } + + if (!mEndTimeEdit->inputIsValid()) { + KMessageBox::sorry( 0, + i18n("Please specify a valid end time, for example '%1'.") + .arg( KGlobal::locale()->formatTime( QTime::currentTime() ) ) ); + return false; + } + } + + if (!mStartDateEdit->date().isValid()) { + KMessageBox::sorry( 0, + i18n("Please specify a valid start date, for example '%1'.") + .arg( KGlobal::locale()->formatDate( QDate::currentDate() ) ) ); + return false; + } + + if (!mEndDateEdit->date().isValid()) { + KMessageBox::sorry( 0, + i18n("Please specify a valid end date, for example '%1'.") + .arg( KGlobal::locale()->formatDate( QDate::currentDate() ) ) ); + return false; + } + + QDateTime startDt,endDt; + startDt.setDate(mStartDateEdit->date()); + endDt.setDate(mEndDateEdit->date()); + if (!mAlldayEventCheckbox->isChecked()) { + startDt.setTime(mStartTimeEdit->getTime()); + endDt.setTime(mEndTimeEdit->getTime()); + } + + 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 QString & summary) +{ + mRecurrenceSummary->setText( summary ); +} diff --git a/korganizer/koeditorgeneralevent.h b/korganizer/koeditorgeneralevent.h new file mode 100644 index 000000000..67fc51e4d --- /dev/null +++ b/korganizer/koeditorgeneralevent.h @@ -0,0 +1,113 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef _KOEDITORGENERALEVENT_H +#define _KOEDITORGENERALEVENT_H + +#include "koeditorgeneral.h" +#include <qdatetime.h> + +class QLabel; +class KDateEdit; +class KTimeEdit; +class QCheckBox; +class QComboBox; +class QBoxLayout; + +namespace KCal { +class Event; +} +using namespace KCal; + +class KOEditorGeneralEvent : public KOEditorGeneral +{ + Q_OBJECT + public: + KOEditorGeneralEvent (QObject* parent=0,const char* name=0); + virtual ~KOEditorGeneralEvent(); + + void initTime(QWidget *,QBoxLayout *); + void initClass(QWidget *,QBoxLayout *); + void initInvitationBar( QWidget* parent, QBoxLayout *layout ); + + void finishSetup(); + + /** Set widgets to default values */ + void setDefaults( const QDateTime &from, const QDateTime &to, bool allDay ); + /** + 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 ); + /** Write event settings to event object */ + void writeEvent( Event * ); + + /** Check if the input is valid. */ + bool validateInput(); + + void updateRecurrenceSummary( const QString &summary ); + + QFrame* invitationBar() const { return mInvitationBar; } + + public slots: + void setDateTimes( const QDateTime &start, const QDateTime &end ); + void setDuration(); + + protected slots: + void timeStuffDisable( bool disable ); + void associateTime( bool time ); + + void startTimeChanged( QTime ); + void startDateChanged( const QDate& ); + void endTimeChanged( QTime ); + void endDateChanged( const QDate& ); + + void emitDateTimeStr(); + + signals: + void allDayChanged(bool); + void dateTimeStrChanged( const QString & ); + void dateTimesChanged( const QDateTime &start, const QDateTime &end ); + void editRecurrence(); + void acceptInvitation(); + void declineInvitation(); + + private: + QLabel *mStartDateLabel; + QLabel *mEndDateLabel; + KDateEdit *mStartDateEdit; + KDateEdit *mEndDateEdit; + KTimeEdit *mStartTimeEdit; + KTimeEdit *mEndTimeEdit; + QLabel *mDurationLabel; + QCheckBox *mAlldayEventCheckbox; + QComboBox *mFreeTimeCombo; + QLabel *mRecurrenceSummary; + QFrame *mInvitationBar; + + // current start and end date and time + QDateTime mCurrStartDateTime; + QDateTime mCurrEndDateTime; +}; + +#endif diff --git a/korganizer/koeditorgeneraljournal.cpp b/korganizer/koeditorgeneraljournal.cpp new file mode 100644 index 000000000..500c389bd --- /dev/null +++ b/korganizer/koeditorgeneraljournal.cpp @@ -0,0 +1,205 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.com> + large parts of code taken from KOEditorGeneralJournal.cpp: + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "koeditorgeneraljournal.h" +#include "koeditorgeneral.h" + +#include <libkcal/journal.h> + +#include <ktextedit.h> +#include <kdateedit.h> +#include <ktimeedit.h> +//#include <klineedit.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kdebug.h> + +#include <qgroupbox.h> +#include <qdatetime.h> +#include <qcheckbox.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qwhatsthis.h> + + +KOEditorGeneralJournal::KOEditorGeneralJournal( QObject *parent, + const char *name ) + : QObject( parent, name ) +{ +} + +KOEditorGeneralJournal::~KOEditorGeneralJournal() +{ +} + +void KOEditorGeneralJournal::initTitle( QWidget *parent, QBoxLayout *topLayout ) +{ + QHBoxLayout *hbox = new QHBoxLayout( topLayout ); + + QString whatsThis = i18n("Sets the title of this journal."); + QLabel *summaryLabel = new QLabel( i18n("T&itle:"), parent ); + QWhatsThis::add( summaryLabel, whatsThis ); + QFont f = summaryLabel->font(); + f.setBold( true ); + summaryLabel->setFont( f ); + hbox->addWidget( summaryLabel ); + + mSummaryEdit = new FocusLineEdit( parent ); + QWhatsThis::add( mSummaryEdit, whatsThis ); + summaryLabel->setBuddy( mSummaryEdit ); + hbox->addWidget( mSummaryEdit ); +} + + +void KOEditorGeneralJournal::initDate( QWidget *parent, QBoxLayout *topLayout ) +{ +// QBoxLayout *dateLayout = new QVBoxLayout(topLayout); + QBoxLayout *dateLayout = new QHBoxLayout( topLayout ); + + mDateLabel = new QLabel( i18n("&Date:"), parent); + dateLayout->addWidget( mDateLabel ); + + mDateEdit = new KDateEdit( parent ); + dateLayout->addWidget( mDateEdit ); + mDateLabel->setBuddy( mDateEdit ); + + dateLayout->addStretch(); + + mTimeCheckBox = new QCheckBox( i18n("&Time: "), parent ); + dateLayout->addWidget( mTimeCheckBox ); + + mTimeEdit = new KTimeEdit( parent ); + dateLayout->addWidget( mTimeEdit ); + connect( mTimeCheckBox, SIGNAL(toggled(bool)), + mTimeEdit, SLOT(setEnabled(bool)) ); + + dateLayout->addStretch(); + setTime( QTime( -1, -1, -1 ) ); +} + +void KOEditorGeneralJournal::setDate( const QDate &date ) +{ +// kdDebug(5850) << "KOEditorGeneralJournal::setDate(): Date: " << date.toString() << endl; + + mDateEdit->setDate( date ); +} + +void KOEditorGeneralJournal::setTime( const QTime &time ) +{ +kdDebug()<<"KOEditorGeneralJournal::setTime, time="<<time.toString()<<endl; + bool validTime = time.isValid(); + mTimeCheckBox->setChecked( validTime ); + mTimeEdit->setEnabled( validTime ); + if ( validTime ) { +kdDebug()<<"KOEditorGeneralJournal::setTime, time is valid"<<endl; + mTimeEdit->setTime( time ); + } +} + +void KOEditorGeneralJournal::initDescription( QWidget *parent, QBoxLayout *topLayout ) +{ + mDescriptionEdit = new KTextEdit( parent ); + mDescriptionEdit->append(""); + mDescriptionEdit->setReadOnly( false ); + mDescriptionEdit->setOverwriteMode( false ); + mDescriptionEdit->setWordWrap( KTextEdit::WidgetWidth ); + mDescriptionEdit->setTabChangesFocus( true ); + topLayout->addWidget( mDescriptionEdit ); +} + +void KOEditorGeneralJournal::setDefaults( const QDate &date ) +{ + setDate( date ); +} + +void KOEditorGeneralJournal::readJournal( Journal *journal, bool tmpl ) +{ + setSummary( journal->summary() ); + if ( !tmpl ) { + setDate( journal->dtStart().date() ); + if ( !journal->doesFloat() ) { +kdDebug()<<"KOEditorGeneralJournal::readJournal, does not float, time="<<(journal->dtStart().time().toString())<<endl; + setTime( journal->dtStart().time() ); + } else { +kdDebug()<<"KOEditorGeneralJournal::readJournal, does float"<<endl; + setTime( QTime( -1, -1, -1 ) ); + } + } + setDescription( journal->description() ); +} + +void KOEditorGeneralJournal::writeJournal( Journal *journal ) +{ +// kdDebug(5850) << "KOEditorGeneralJournal::writeIncidence()" << endl; + journal->setSummary( mSummaryEdit->text() ); + journal->setDescription( mDescriptionEdit->text() ); + + QDateTime tmpDT( mDateEdit->date(), QTime(0,0,0) ); + bool hasTime = mTimeCheckBox->isChecked(); + journal->setFloats( !hasTime ); + if ( hasTime ) { + tmpDT.setTime( mTimeEdit->getTime() ); + } + journal->setDtStart(tmpDT); + +// kdDebug(5850) << "KOEditorGeneralJournal::writeJournal() done" << endl; +} + + +void KOEditorGeneralJournal::setDescription( const QString &text ) +{ + mDescriptionEdit->setText( text ); +} + +void KOEditorGeneralJournal::setSummary( const QString &text ) +{ + mSummaryEdit->setText( text ); +} + +void KOEditorGeneralJournal::finishSetup() +{ + QWidget::setTabOrder( mSummaryEdit, mDateEdit ); + QWidget::setTabOrder( mDateEdit, mTimeCheckBox ); + QWidget::setTabOrder( mTimeCheckBox, mTimeEdit ); + QWidget::setTabOrder( mTimeEdit, mDescriptionEdit ); + mSummaryEdit->setFocus(); +} + +bool KOEditorGeneralJournal::validateInput() +{ +// kdDebug(5850) << "KOEditorGeneralJournal::validateInput()" << endl; + + if (!mDateEdit->date().isValid()) { + KMessageBox::sorry( 0, + i18n("Please specify a valid date, for example '%1'.") + .arg( KGlobal::locale()->formatDate( QDate::currentDate() ) ) ); + return false; + } + + return true; +} + +#include "koeditorgeneraljournal.moc" diff --git a/korganizer/koeditorgeneraljournal.h b/korganizer/koeditorgeneraljournal.h new file mode 100644 index 000000000..38fe4e525 --- /dev/null +++ b/korganizer/koeditorgeneraljournal.h @@ -0,0 +1,83 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOEDITORGENERALJOURNAL_H +#define KOEDITORGENERALJOURNAL_H + +#include <qobject.h> +#include <qdatetime.h> + +class KDateEdit; +class KTimeEdit; +class KTextEdit; +class QLineEdit; +class QLabel; +class QBoxLayout; +class QCheckBox; +class QWidget; + +namespace KCal { +class Incidence; +class Journal; +} +using namespace KCal; + +class KOEditorGeneralJournal : public QObject +{ + Q_OBJECT + public: + KOEditorGeneralJournal ( QObject* parent=0, const char* name=0 ); + virtual ~KOEditorGeneralJournal(); + + void initDate( QWidget *, QBoxLayout * ); + void initDescription( QWidget *, QBoxLayout * ); + void initTitle( QWidget *parent, QBoxLayout *topLayout ); + + /** Set widgets to default values */ + void setDefaults( const QDate &date ); + void setDate( const QDate &date ); + void setTime( const QTime &time ); + /** Read journal object and setup widgets accordingly */ + void readJournal( Journal *, bool tmpl = false ); + /** Write journal settings to event object */ + void writeJournal( Journal * ); + + /** Check if the input is valid. */ + bool validateInput(); + + void setDescription( const QString &text ); + void setSummary( const QString &text ); + void finishSetup(); + + protected: + QLineEdit *mSummaryEdit; + QLabel *mSummaryLabel; + KTextEdit *mDescriptionEdit; + QLabel *mDateLabel; + KDateEdit *mDateEdit; + QCheckBox *mTimeCheckBox; + KTimeEdit *mTimeEdit; +}; + +#endif diff --git a/korganizer/koeditorgeneraltodo.cpp b/korganizer/koeditorgeneraltodo.cpp new file mode 100644 index 000000000..89deed4f2 --- /dev/null +++ b/korganizer/koeditorgeneraltodo.cpp @@ -0,0 +1,571 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qtooltip.h> +#include <qfiledialog.h> +#include <qlayout.h> +#include <qvbox.h> +#include <qbuttongroup.h> +#include <qvgroupbox.h> +#include <qwidgetstack.h> +#include <qdatetime.h> +#include <qcheckbox.h> +#include <qlabel.h> +#include <qspinbox.h> +#include <qpushbutton.h> +#include <qwhatsthis.h> + +#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/todo.h> + +#include <libkdepim/kdateedit.h> + +#include "koprefs.h" +#include "koglobals.h" +#include "ktimeedit.h" + +#include "koeditorgeneraltodo.h" +#include "koeditorgeneraltodo.moc" + +KOEditorGeneralTodo::KOEditorGeneralTodo(QObject* parent, + const char* name) + : KOEditorGeneral( parent, name) +{ +} + +KOEditorGeneralTodo::~KOEditorGeneralTodo() +{ +} + +void KOEditorGeneralTodo::finishSetup() +{ + QWidget::setTabOrder( mSummaryEdit, mLocationEdit ); + QWidget::setTabOrder( mLocationEdit, mStartCheck ); + QWidget::setTabOrder( mStartCheck, mStartDateEdit ); + QWidget::setTabOrder( mStartDateEdit, mStartTimeEdit ); + QWidget::setTabOrder( mStartTimeEdit, mDueCheck ); + QWidget::setTabOrder( mDueCheck, mDueDateEdit ); + QWidget::setTabOrder( mDueDateEdit, mDueTimeEdit ); + QWidget::setTabOrder( mDueTimeEdit, mTimeButton ); + QWidget::setTabOrder( mTimeButton, mCompletedCombo ); + QWidget::setTabOrder( mCompletedCombo, mPriorityCombo ); + QWidget::setTabOrder( mPriorityCombo, mAlarmButton ); + QWidget::setTabOrder( mAlarmButton, mAlarmTimeEdit ); + QWidget::setTabOrder( mAlarmTimeEdit, mAlarmIncrCombo ); +// QWidget::setTabOrder( mAlarmIncrCombo, mAlarmSoundButton ); + QWidget::setTabOrder( mAlarmIncrCombo, mAlarmEditButton ); +// QWidget::setTabOrder( mAlarmSoundButton, mAlarmProgramButton ); +// QWidget::setTabOrder( mAlarmProgramButton, mDescriptionEdit ); + QWidget::setTabOrder( mAlarmEditButton, mDescriptionEdit ); + QWidget::setTabOrder( mDescriptionEdit, mCategoriesButton ); + QWidget::setTabOrder( mCategoriesButton, mSecrecyCombo ); +// QWidget::setTabOrder( mSecrecyCombo, mDescriptionEdit ); + + mSummaryEdit->setFocus(); +} + +void KOEditorGeneralTodo::initTime(QWidget *parent,QBoxLayout *topLayout) +{ + kdDebug(5850) << k_funcinfo << endl; + QBoxLayout *timeLayout = new QVBoxLayout(topLayout); + + QGroupBox *timeGroupBox = new QGroupBox(1,QGroupBox::Horizontal, + i18n("Date && Time"),parent); + timeLayout->addWidget(timeGroupBox); + + QFrame *timeBoxFrame = new QFrame(timeGroupBox); + QWhatsThis::add( timeBoxFrame, + i18n("Sets options for due and start dates and times " + "for this to-do.") ); + + QGridLayout *layoutTimeBox = new QGridLayout(timeBoxFrame,1,1); + layoutTimeBox->setSpacing(topLayout->spacing()); + + + QString whatsThis = i18n("Sets the start date for this to-do"); + mStartCheck = new QCheckBox(i18n("Sta&rt:"),timeBoxFrame); + QWhatsThis::add( mStartCheck, whatsThis ); + layoutTimeBox->addWidget(mStartCheck,0,0); + connect(mStartCheck,SIGNAL(toggled(bool)),SLOT(enableStartEdit(bool))); + connect(mStartCheck,SIGNAL(toggled(bool)),SLOT(startDateModified())); + + mStartDateEdit = new KDateEdit(timeBoxFrame); + QWhatsThis::add( mStartDateEdit, whatsThis ); + layoutTimeBox->addWidget(mStartDateEdit,0,1); + connect(mStartDateEdit,SIGNAL(dateChanged(const QDate&)),SLOT(startDateModified())); + + mStartTimeEdit = new KTimeEdit(timeBoxFrame); + QWhatsThis::add( mStartTimeEdit, + i18n("Sets the start time for this to-do.") ); + layoutTimeBox->addWidget(mStartTimeEdit,0,2); + connect(mStartTimeEdit,SIGNAL(timeChanged(QTime)),SLOT(startDateModified())); + + whatsThis = i18n("Sets the due date for this to-do."); + mDueCheck = new QCheckBox(i18n("&Due:"),timeBoxFrame); + QWhatsThis::add( mDueCheck, whatsThis ); + layoutTimeBox->addWidget(mDueCheck,1,0); + connect(mDueCheck,SIGNAL(toggled(bool)),SLOT(enableDueEdit(bool))); + connect(mDueCheck,SIGNAL(toggled(bool)),SLOT(showAlarm())); + connect(mDueCheck,SIGNAL(toggled(bool)),SIGNAL(dueDateEditToggle(bool))); + connect(mDueCheck,SIGNAL(toggled(bool)),SLOT(dateChanged())); + + mDueDateEdit = new KDateEdit(timeBoxFrame); + QWhatsThis::add( mDueDateEdit, whatsThis ); + layoutTimeBox->addWidget(mDueDateEdit,1,1); + connect(mDueDateEdit,SIGNAL(dateChanged(const QDate&)),SLOT(dateChanged())); + + mDueTimeEdit = new KTimeEdit(timeBoxFrame); + QWhatsThis::add( mDueTimeEdit, + i18n("Sets the due time for this to-do.") ); + layoutTimeBox->addWidget(mDueTimeEdit,1,2); + connect(mDueTimeEdit,SIGNAL(timeChanged( QTime )),SLOT(dateChanged())); + + mTimeButton = new QCheckBox(i18n("Ti&me associated"),timeBoxFrame); + QWhatsThis::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); + + connect(mTimeButton,SIGNAL(toggled(bool)),SLOT(enableTimeEdits(bool))); + connect(mTimeButton,SIGNAL(toggled(bool)),SLOT(dateChanged())); + + // some more layouting + layoutTimeBox->setColStretch(3,1); + + QBoxLayout *secLayout = new QHBoxLayout(); + layoutTimeBox->addLayout( secLayout, 0, 4 ); + initSecrecy( timeBoxFrame, secLayout ); +} + + +void KOEditorGeneralTodo::initCompletion(QWidget *parent, QBoxLayout *topLayout) +{ + QString whatsThis = i18n("Sets the current completion status of this to-do " + "as a percentage."); + mCompletedCombo = new QComboBox(parent); + QWhatsThis::add( mCompletedCombo, whatsThis ); + for (int i = 0; i <= 100; i+=10) { + // xgettext:no-c-format + QString label = i18n("Percent complete", "%1 %").arg (i); + mCompletedCombo->insertItem(label); + } + connect(mCompletedCombo,SIGNAL(activated(int)),SLOT(completedChanged(int))); + topLayout->addWidget(mCompletedCombo); + + mCompletedLabel = new QLabel(i18n("co&mpleted"),parent); + topLayout->addWidget(mCompletedLabel); + mCompletedLabel->setBuddy( mCompletedCombo ); + mCompletionDateEdit = new KDateEdit( parent ); + mCompletionDateEdit->hide(); + topLayout->addWidget( mCompletionDateEdit ); + mCompletionTimeEdit = new KTimeEdit( parent, QTime() ); + mCompletionTimeEdit->hide(); + topLayout->addWidget( mCompletionTimeEdit ); +} + +void KOEditorGeneralTodo::initPriority(QWidget *parent, QBoxLayout *topLayout) +{ + QString 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."); + QLabel *priorityLabel = new QLabel(i18n("&Priority:"),parent); + topLayout->addWidget(priorityLabel); + + mPriorityCombo = new QComboBox(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); + priorityLabel->setBuddy( mPriorityCombo ); +} + +void KOEditorGeneralTodo::initStatus(QWidget *parent,QBoxLayout *topLayout) +{ + QBoxLayout *statusLayout = new QHBoxLayout(topLayout); + + initCompletion( parent, statusLayout ); + + statusLayout->addStretch( 1 ); + + initPriority( parent, statusLayout ); +} + +void KOEditorGeneralTodo::setDefaults( const QDateTime &due, bool allDay ) +{ + kdDebug(5850) << k_funcinfo << due <<endl; + KOEditorGeneral::setDefaults(allDay); + + mTimeButton->setChecked( !allDay ); + mTimeButton->setEnabled( mTimeButton->isChecked() /* i.e. !allDay */ ); + + enableTimeEdits( !allDay ); + + mDueCheck->setChecked( due.isValid() ); + enableDueEdit( due.isValid() ); + + mStartCheck->setChecked(false); + enableStartEdit(false); + + if ( due.isValid() ) { + mDueDateEdit->setDate( due.date() ); + mDueTimeEdit->setTime( due.time() ); + } else { + // Make it due tomorrow. + mDueDateEdit->setDate( QDate::currentDate().addDays(1) ); + mDueTimeEdit->setTime( QTime::currentTime() ); + } + + if ( !due.isValid() || (QDateTime::currentDateTime() < due) ) { + mStartDateEdit->setDate( QDate::currentDate() ); + mStartTimeEdit->setTime( QTime::currentTime() ); + } else { + mStartDateEdit->setDate( due.date().addDays( -1 ) ); + mStartTimeEdit->setTime( due.time() ); + } + mStartDateModified = false; + + mPriorityCombo->setCurrentItem(5); + + mCompletedCombo->setCurrentItem(0); +} + +void KOEditorGeneralTodo::readTodo(Todo *todo, Calendar *calendar) +{ + KOEditorGeneral::readIncidence(todo, calendar); + + QDateTime dueDT; + + if (todo->hasDueDate()) { + enableAlarm( true ); + dueDT = todo->dtDue(); + mDueDateEdit->setDate(todo->dtDue().date()); + mDueTimeEdit->setTime(todo->dtDue().time()); + mDueCheck->setChecked(true); + } else { + enableAlarm( false ); + mDueDateEdit->setEnabled(false); + mDueTimeEdit->setEnabled(false); + mDueDateEdit->setDate(QDate::currentDate()); + mDueTimeEdit->setTime(QTime::currentTime()); + mDueCheck->setChecked(false); + } + + if (todo->hasStartDate()) { + mStartDateEdit->setDate(todo->dtStart().date()); + mStartTimeEdit->setTime(todo->dtStart().time()); + mStartCheck->setChecked(true); + } else { + mStartDateEdit->setEnabled(false); + mStartTimeEdit->setEnabled(false); + mStartDateEdit->setDate(QDate::currentDate()); + mStartTimeEdit->setTime(QTime::currentTime()); + mStartCheck->setChecked(false); + } + + mTimeButton->setChecked( !todo->doesFloat() ); + + mAlreadyComplete = false; + mCompletedCombo->setCurrentItem(todo->percentComplete() / 10); + if (todo->isCompleted() && todo->hasCompletedDate()) { + mCompleted = todo->completed(); + mAlreadyComplete = true; + } + setCompletedDate(); + + mPriorityCombo->setCurrentItem( todo->priority() ); + mStartDateModified = false; +} + +void KOEditorGeneralTodo::writeTodo(Todo *todo) +{ + KOEditorGeneral::writeIncidence(todo); + + // temp. until something better happens. + QString tmpStr; + + todo->setHasDueDate(mDueCheck->isChecked()); + todo->setHasStartDate(mStartCheck->isChecked()); + + QDate tmpSDate, tmpDDate; + QTime tmpSTime, tmpDTime; + QDateTime tmpStartDT, tmpDueDT; + if ( mTimeButton->isChecked() ) { + todo->setFloats(false); + + // set due date/time + tmpDDate = mDueDateEdit->date(); + tmpDTime = mDueTimeEdit->getTime(); + tmpDueDT.setDate(tmpDDate); + tmpDueDT.setTime(tmpDTime); + + // set start date/time + if ( mStartCheck->isChecked() ) { + tmpSDate = mStartDateEdit->date(); + tmpSTime = mStartTimeEdit->getTime(); + tmpStartDT.setDate(tmpSDate); + tmpStartDT.setTime(tmpSTime); + } else { + tmpStartDT = tmpDueDT; + } + } else { + todo->setFloats(true); + + // need to change this. + tmpDDate = mDueDateEdit->date(); + tmpDTime.setHMS(0,0,0); + tmpDueDT.setDate(tmpDDate); + tmpDueDT.setTime(tmpDTime); + + if ( mStartCheck->isChecked() ) { + tmpSDate = mStartDateEdit->date(); + tmpSTime.setHMS(0,0,0); + tmpStartDT.setDate(tmpSDate); + tmpStartDT.setTime(tmpSTime); + } else { + tmpStartDT = tmpDueDT; + } + } + + // TODO: Don't use the due date for the recurrence, but the start date (cf. rfc 2445) + if ( todo->doesRecur() && !mStartDateModified ) { + todo->setDtDue( tmpDueDT ); + } else { + todo->setDtDue( tmpDueDT, true ); + todo->setDtStart( tmpStartDT ); + todo->setDtRecurrence( tmpDueDT ); + } + + todo->setPriority( mPriorityCombo->currentItem() ); + + // set completion state + todo->setPercentComplete(mCompletedCombo->currentItem() * 10); + + if (mCompletedCombo->currentItem() == 10 && mCompleted.isValid()) { + QDateTime completed( mCompletionDateEdit->date(), + mCompletionTimeEdit->getTime() ); + int difference = mCompleted.secsTo( completed ); + if ( (difference < 60) && (difference > -60) && + (completed.time().minute() == mCompleted.time().minute() ) ) { + // completion time wasn't changed substantially (only the seconds + // truncated, but that's an effect done by KTimeEdit automatically). + completed = mCompleted; + } + todo->setCompleted( completed ); + } +} + +void KOEditorGeneralTodo::enableDueEdit(bool enable) +{ + mDueDateEdit->setEnabled( enable ); + + if(mDueCheck->isChecked() || mStartCheck->isChecked()) { + mTimeButton->setEnabled(true); + } else { + mTimeButton->setEnabled(false); + } + + if (enable) { + mDueTimeEdit->setEnabled( mTimeButton->isChecked() ); + } else { + mDueTimeEdit->setEnabled( false ); + } +} + +void KOEditorGeneralTodo::enableStartEdit( bool enable ) +{ + mStartDateEdit->setEnabled( enable ); + + if(mDueCheck->isChecked() || mStartCheck->isChecked()) { + mTimeButton->setEnabled(true); + } + else { + mTimeButton->setEnabled(false); + mTimeButton->setChecked(false); + } + + if (enable) { + mStartTimeEdit->setEnabled( mTimeButton->isChecked() ); + } else { + mStartTimeEdit->setEnabled( false ); + } +} + +void KOEditorGeneralTodo::enableTimeEdits(bool enable) +{ + if(mStartCheck->isChecked()) { + mStartTimeEdit->setEnabled( enable ); + } + if(mDueCheck->isChecked()) { + mDueTimeEdit->setEnabled( enable ); + } +} + +void KOEditorGeneralTodo::showAlarm() +{ + enableAlarm( mDueCheck->isChecked() ); +} + +bool KOEditorGeneralTodo::validateInput() +{ + if (mDueCheck->isChecked()) { + if (!mDueDateEdit->date().isValid()) { + KMessageBox::sorry(0,i18n("Please specify a valid due date.")); + return false; + } + if (mTimeButton->isChecked()) { + if (!mDueTimeEdit->inputIsValid()) { + KMessageBox::sorry(0,i18n("Please specify a valid due time.")); + return false; + } + } + } + + if (mStartCheck->isChecked()) { + if (!mStartDateEdit->date().isValid()) { + KMessageBox::sorry(0,i18n("Please specify a valid start date.")); + return false; + } + if (mTimeButton->isChecked()) { + if (!mStartTimeEdit->inputIsValid()) { + KMessageBox::sorry(0,i18n("Please specify a valid start time.")); + return false; + } + } + } + + if (mStartCheck->isChecked() && mDueCheck->isChecked()) { + QDateTime startDate; + QDateTime dueDate; + startDate.setDate(mStartDateEdit->date()); + dueDate.setDate(mDueDateEdit->date()); + if (mTimeButton->isChecked()) { + startDate.setTime(mStartTimeEdit->getTime()); + dueDate.setTime(mDueTimeEdit->getTime()); + } + if (startDate > dueDate) { + KMessageBox::sorry(0, + i18n("The start date cannot be after the due date.")); + return false; + } + } + + return KOEditorGeneral::validateInput(); +} + +void KOEditorGeneralTodo::completedChanged(int index) +{ + if (index == 10) { + mCompleted = QDateTime::currentDateTime(); + } + setCompletedDate(); +} + +void KOEditorGeneralTodo::dateChanged() +{ + KLocale *l = KGlobal::locale(); + QString dateTimeStr = ""; + + if ( mStartCheck->isChecked() ) { + dateTimeStr += i18n("Start: %1").arg( + l->formatDate( mStartDateEdit->date() ) ); + if ( mTimeButton->isChecked() ) + dateTimeStr += QString(" %1").arg( + l->formatTime( mStartTimeEdit->getTime() ) ); + } + + if ( mDueCheck->isChecked() ) { + dateTimeStr += i18n(" Due: %1").arg( + l->formatDate( mDueDateEdit->date() ) ); + if ( mTimeButton->isChecked() ) + dateTimeStr += QString(" %1").arg( + l->formatTime( mDueTimeEdit->getTime() ) ); + } + + emit dateTimeStrChanged( dateTimeStr ); + QDateTime endDt( mDueDateEdit->date(), mDueTimeEdit->getTime() ); + emit signalDateTimeChanged( endDt, endDt ); +} + +void KOEditorGeneralTodo::startDateModified() +{ + mStartDateModified = true; + dateChanged(); +} + +void KOEditorGeneralTodo::setCompletedDate() +{ + if (mCompletedCombo->currentItem() == 10 && mCompleted.isValid()) { + mCompletedLabel->setText(i18n("co&mpleted on")); +// .arg(KGlobal::locale()->formatDateTime(mCompleted))); + mCompletionDateEdit->show(); + mCompletionTimeEdit->show(); + mCompletionDateEdit->setDate( mCompleted.date() ); + mCompletionTimeEdit->setTime( mCompleted.time() ); + } else { + mCompletedLabel->setText(i18n("co&mpleted")); + mCompletionDateEdit->hide(); + mCompletionTimeEdit->hide(); + } +} + +void KOEditorGeneralTodo::modified (Todo* todo, int modification) +{ + switch (modification) { + case KOGlobals::PRIORITY_MODIFIED: + mPriorityCombo->setCurrentItem( todo->priority() ); + break; + case KOGlobals::COMPLETION_MODIFIED: + mCompletedCombo->setCurrentItem(todo->percentComplete() / 10); + if (todo->isCompleted() && todo->hasCompletedDate()) { + mCompleted = todo->completed(); + } + setCompletedDate(); + break; + case KOGlobals::CATEGORY_MODIFIED: + setCategories( todo->categories() ); + break; + case KOGlobals::UNKNOWN_MODIFIED: // fall through + default: + readTodo( todo, 0 ); + break; + } +} diff --git a/korganizer/koeditorgeneraltodo.h b/korganizer/koeditorgeneraltodo.h new file mode 100644 index 000000000..d3e051866 --- /dev/null +++ b/korganizer/koeditorgeneraltodo.h @@ -0,0 +1,109 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef _KOEDITORGENERALTODO_H +#define _KOEDITORGENERALTODO_H + +#include "koeditorgeneral.h" +#include <qdatetime.h> + +class KRestrictedLine; + +class KDateEdit; +class KTimeEdit; + +namespace KCal { +class Todo; +} +using namespace KCal; + +class KOEditorGeneralTodo : public KOEditorGeneral +{ + Q_OBJECT + public: + KOEditorGeneralTodo (QObject* parent=0,const char* name=0); + virtual ~KOEditorGeneralTodo(); + + void initTime(QWidget *, QBoxLayout *); + void initStatus(QWidget *, QBoxLayout *); + void initCompletion(QWidget *, QBoxLayout *); + void initPriority(QWidget *, QBoxLayout *); + + void finishSetup(); + + /** Set widgets to default values */ + void setDefaults( const QDateTime &due, bool allDay ); + /** Read todo object and setup widgets accordingly */ + void readTodo(Todo *todo, Calendar *calendar); + /** Write todo settings to event object */ + void writeTodo(Todo *); + + /** Check if the input is valid. */ + bool validateInput(); + + /** The todo has been modified externally */ + void modified (Todo*, int); + + signals: + void dueDateEditToggle( bool ); + void dateTimeStrChanged( const QString & ); + void signalDateTimeChanged( const QDateTime &, const QDateTime & ); + + protected slots: + void completedChanged(int); + void dateChanged(); + void startDateModified(); + + void enableDueEdit( bool enable ); + void enableStartEdit( bool enable ); + void enableTimeEdits( bool enable ); + void showAlarm(); + + protected: + void setCompletedDate(); + + private: + bool mAlreadyComplete; + bool mStartDateModified; + + KDateEdit *mStartDateEdit; + KTimeEdit *mStartTimeEdit; + QCheckBox *mTimeButton; + QCheckBox *mDueCheck; + KDateEdit *mDueDateEdit; + KTimeEdit *mDueTimeEdit; + QComboBox *mCompletedCombo; + QLabel *mCompletedLabel; + QLabel *mPriorityLabel; + QComboBox *mPriorityCombo; + + KDateEdit *mCompletionDateEdit; + KTimeEdit *mCompletionTimeEdit; + + QCheckBox *mStartCheck; + + QDateTime mCompleted; +}; + + +#endif diff --git a/korganizer/koeditorrecurrence.cpp b/korganizer/koeditorrecurrence.cpp new file mode 100644 index 000000000..48471c421 --- /dev/null +++ b/korganizer/koeditorrecurrence.cpp @@ -0,0 +1,1447 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2000-2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qtooltip.h> +#include <qfiledialog.h> +#include <qlayout.h> +#include <qvbox.h> +#include <qbuttongroup.h> +#include <qvgroupbox.h> +#include <qwidgetstack.h> +#include <qdatetime.h> +#include <qlistbox.h> +#include <qspinbox.h> +#include <qcheckbox.h> +#include <qgroupbox.h> +#include <qwidgetstack.h> +#include <qradiobutton.h> +#include <qlabel.h> +#include <qpushbutton.h> +#include <qwhatsthis.h> + +#include <kdialog.h> +#include <kglobal.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kdebug.h> +#include <knumvalidator.h> +#include <kcalendarsystem.h> +#include <kmessagebox.h> + +#include <libkdepim/kdateedit.h> +#include <libkcal/todo.h> + +#include "koprefs.h" +#include "koglobals.h" + +#include "koeditorrecurrence.h" +#include "koeditorrecurrence.moc" + +/////////////////////////// RecurBase /////////////////////////////// + +RecurBase::RecurBase( QWidget *parent, const char *name ) : + QWidget( parent, name ) +{ + mFrequencyEdit = new QSpinBox( 1, 9999, 1, this ); + mFrequencyEdit->setValue( 1 ); +} + +QWidget *RecurBase::frequencyEdit() +{ + return mFrequencyEdit; +} + +void RecurBase::setFrequency( int f ) +{ + if ( f < 1 ) f = 1; + + mFrequencyEdit->setValue( f ); +} + +int RecurBase::frequency() +{ + return mFrequencyEdit->value(); +} + +QComboBox *RecurBase::createWeekCountCombo( QWidget *parent, const char *name ) +{ + QComboBox *combo = new QComboBox( parent, name ); + QWhatsThis::add( combo, + i18n("The number of the week from the beginning " + "of the month on which this event or to-do " + "should recur.") ); + if ( !combo ) return 0; + combo->insertItem( i18n("1st") ); + combo->insertItem( i18n("2nd") ); + combo->insertItem( i18n("3rd") ); + combo->insertItem( i18n("4th") ); + combo->insertItem( i18n("5th") ); + combo->insertItem( i18n("Last") ); + combo->insertItem( i18n("2nd Last") ); + combo->insertItem( i18n("3rd Last") ); + combo->insertItem( i18n("4th Last") ); + combo->insertItem( i18n("5th Last") ); + return combo; +} + +QComboBox *RecurBase::createWeekdayCombo( QWidget *parent, const char *name ) +{ + QComboBox *combo = new QComboBox( parent, name ); + QWhatsThis::add( combo, + i18n("The weekday on which this event or to-do " + "should recur.") ); + if ( !combo ) return 0; + const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem(); + for( int i = 1; i <= 7; ++i ) { + combo->insertItem( calSys->weekDayName( i ) ); + } + return combo; +} + +QComboBox *RecurBase::createMonthNameCombo( QWidget *parent, const char *name ) +{ + QComboBox *combo = new QComboBox( parent, name ); + QWhatsThis::add( combo, + i18n("The month during which this event or to-do " + "should recur.") ); + if ( !combo ) return 0; + const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem(); + for( int i = 1; i <= 12; ++i ) { + // use an arbitrary year, we just need the month name... + QDate dt( 2005, i, 1 ); + combo->insertItem( calSys->monthName( dt ) ); + } + return combo; +} + +QBoxLayout *RecurBase::createFrequencySpinBar( QWidget *parent, QLayout *layout, + QString everyText, QString unitText ) +{ + QBoxLayout *freqLayout = new QHBoxLayout( layout ); + + QString whatsThis = i18n("Sets how often this event or to-do should recur."); + QLabel *preLabel = new QLabel( everyText, parent ); + QWhatsThis::add( preLabel, whatsThis ); + freqLayout->addWidget( preLabel ); + + freqLayout->addWidget( frequencyEdit() ); + preLabel->setBuddy( frequencyEdit() ); + QWhatsThis::add( preLabel->buddy(), whatsThis ); + + QLabel *postLabel = new QLabel( unitText, parent ); + QWhatsThis::add( postLabel, whatsThis ); + freqLayout->addWidget( postLabel ); + freqLayout->addStretch(); + return freqLayout; +} + +/////////////////////////// RecurDaily /////////////////////////////// + +RecurDaily::RecurDaily( QWidget *parent, const char *name ) : + RecurBase( parent, name ) +{ + QBoxLayout *topLayout = new QVBoxLayout( this ); + topLayout->setSpacing( KDialog::spacingHint() ); + + createFrequencySpinBar( this, topLayout, i18n("&Recur every"), i18n("day(s)") ); +} + + +/////////////////////////// RecurWeekly /////////////////////////////// + +RecurWeekly::RecurWeekly( QWidget *parent, const char *name ) : + RecurBase( parent, name ) +{ + QBoxLayout *topLayout = new QVBoxLayout( this ); + topLayout->setSpacing( KDialog::spacingHint() ); + +// topLayout->addStretch( 1 ); + + createFrequencySpinBar( this, topLayout, i18n("&Recur every"), i18n("week(s) on:") ); + + QHBox *dayBox = new QHBox( this ); + topLayout->addWidget( dayBox, 1, AlignVCenter ); + // Respect start of week setting + int weekStart=KGlobal::locale()->weekStartDay(); + for ( int i = 0; i < 7; ++i ) { + // i is the nr of the combobox, not the day of week! + // label=(i+weekStart+6)%7 + 1; + // index in CheckBox array(=day): label-1 + const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem(); + QString weekDayName = calSys->weekDayName( + (i + weekStart + 6)%7 + 1, true ); + if ( KOPrefs::instance()->mCompactDialogs ) { + weekDayName = weekDayName.left( 1 ); + } + mDayBoxes[ (i + weekStart + 6)%7 ] = new QCheckBox( weekDayName, dayBox ); + QWhatsThis::add( mDayBoxes[ (i + weekStart + 6)%7 ], + i18n("Day of the week on which this event or to-do " + "should recur.") ); + } + + topLayout->addStretch( 1 ); +} + +void RecurWeekly::setDays( const QBitArray &days ) +{ + for ( int i = 0; i < 7; ++i ) { + mDayBoxes[ i ]->setChecked( days.testBit( i ) ); + } +} + +QBitArray RecurWeekly::days() +{ + QBitArray days( 7 ); + + for ( int i = 0; i < 7; ++i ) { + days.setBit( i, mDayBoxes[ i ]->isChecked() ); + } + + return days; +} + +/////////////////////////// RecurMonthly /////////////////////////////// + +RecurMonthly::RecurMonthly( QWidget *parent, const char *name ) : + RecurBase( parent, name ) +{ + QBoxLayout *topLayout = new QVBoxLayout( this ); + topLayout->setSpacing( KDialog::spacingHint() ); + + createFrequencySpinBar( this, topLayout, i18n("&Recur every"), i18n("month(s)") ); + + QButtonGroup *buttonGroup = new QButtonGroup( this ); + buttonGroup->setFrameStyle( QFrame::NoFrame ); + topLayout->addWidget( buttonGroup, 1, AlignVCenter ); + + QGridLayout *buttonLayout = new QGridLayout( buttonGroup, 3, 2 ); + buttonLayout->setSpacing( KDialog::spacingHint() ); + + + QString recurOnText; + if ( !KOPrefs::instance()->mCompactDialogs ) { + recurOnText = i18n("&Recur on the"); + } + + mByDayRadio = new QRadioButton( recurOnText, buttonGroup ); + QWhatsThis::add( mByDayRadio, + i18n("Sets a specific day of the month on which " + "this event or to-do should recur.") ); + + buttonLayout->addWidget( mByDayRadio, 0, 0 ); + + QString whatsThis = i18n("The day of the month on which this event or to-do " + "should recur."); + mByDayCombo = new QComboBox( buttonGroup ); + QWhatsThis::add( mByDayCombo, whatsThis ); + mByDayCombo->setSizeLimit( 7 ); + mByDayCombo->insertItem( i18n("1st") ); + mByDayCombo->insertItem( i18n("2nd") ); + mByDayCombo->insertItem( i18n("3rd") ); + mByDayCombo->insertItem( i18n("4th") ); + mByDayCombo->insertItem( i18n("5th") ); + mByDayCombo->insertItem( i18n("6th") ); + mByDayCombo->insertItem( i18n("7th") ); + mByDayCombo->insertItem( i18n("8th") ); + mByDayCombo->insertItem( i18n("9th") ); + mByDayCombo->insertItem( i18n("10th") ); + mByDayCombo->insertItem( i18n("11th") ); + mByDayCombo->insertItem( i18n("12th") ); + mByDayCombo->insertItem( i18n("13th") ); + mByDayCombo->insertItem( i18n("14th") ); + mByDayCombo->insertItem( i18n("15th") ); + mByDayCombo->insertItem( i18n("16th") ); + mByDayCombo->insertItem( i18n("17th") ); + mByDayCombo->insertItem( i18n("18th") ); + mByDayCombo->insertItem( i18n("19th") ); + mByDayCombo->insertItem( i18n("20th") ); + mByDayCombo->insertItem( i18n("21st") ); + mByDayCombo->insertItem( i18n("22nd") ); + mByDayCombo->insertItem( i18n("23rd") ); + mByDayCombo->insertItem( i18n("24th") ); + mByDayCombo->insertItem( i18n("25th") ); + mByDayCombo->insertItem( i18n("26th") ); + mByDayCombo->insertItem( i18n("27th") ); + mByDayCombo->insertItem( i18n("28th") ); + mByDayCombo->insertItem( i18n("29th") ); + mByDayCombo->insertItem( i18n("30th") ); + mByDayCombo->insertItem( i18n("31st") ); + mByDayCombo->insertItem( i18n("Last") ); + mByDayCombo->insertItem( i18n("2nd Last") ); + mByDayCombo->insertItem( i18n("3rd Last") ); + mByDayCombo->insertItem( i18n("4th Last") ); + mByDayCombo->insertItem( i18n("5th Last") ); + // FIXME: After the string freeze is over, insert all possible values, not + // just the ones we already have translated: +/* mByDayCombo->insertItem( i18n("6th Last") ); + mByDayCombo->insertItem( i18n("7th Last") ); + mByDayCombo->insertItem( i18n("8th Last") ); + mByDayCombo->insertItem( i18n("9th Last") ); + mByDayCombo->insertItem( i18n("10th Last") ); + mByDayCombo->insertItem( i18n("11th Last") ); + mByDayCombo->insertItem( i18n("12th Last") ); + mByDayCombo->insertItem( i18n("13th Last") ); + mByDayCombo->insertItem( i18n("14th Last") ); + mByDayCombo->insertItem( i18n("15th Last") ); + mByDayCombo->insertItem( i18n("16th Last") ); + mByDayCombo->insertItem( i18n("17th Last") ); + mByDayCombo->insertItem( i18n("18th Last") ); + mByDayCombo->insertItem( i18n("19th Last") ); + mByDayCombo->insertItem( i18n("20th Last") ); + mByDayCombo->insertItem( i18n("21st Last") ); + mByDayCombo->insertItem( i18n("22nd Last") ); + mByDayCombo->insertItem( i18n("23rd Last") ); + mByDayCombo->insertItem( i18n("24th Last") ); + mByDayCombo->insertItem( i18n("25th Last") ); + mByDayCombo->insertItem( i18n("26th Last") ); + mByDayCombo->insertItem( i18n("27th Last") ); + mByDayCombo->insertItem( i18n("28th Last") ); + mByDayCombo->insertItem( i18n("29th Last") ); + mByDayCombo->insertItem( i18n("30th Last") ); + mByDayCombo->insertItem( i18n("31st Last") );*/ + buttonLayout->addWidget( mByDayCombo, 0, 1 ); + + QLabel *byDayLabel = new QLabel( i18n("day"), buttonGroup ); + QWhatsThis::add( byDayLabel, whatsThis ); + buttonLayout->addWidget( byDayLabel, 0, 2 ); + + + mByPosRadio = new QRadioButton( recurOnText, buttonGroup); + QWhatsThis::add( mByPosRadio, + i18n("Sets a weekday and specific week in the month " + "on which this event or to-do should recur") ); + buttonLayout->addWidget( mByPosRadio, 1, 0 ); + + mByPosCountCombo = createWeekCountCombo( buttonGroup ); + buttonLayout->addWidget( mByPosCountCombo, 1, 1 ); + + mByPosWeekdayCombo = createWeekdayCombo( buttonGroup ); + buttonLayout->addWidget( mByPosWeekdayCombo, 1, 2 ); +} + +void RecurMonthly::setByDay( int day ) +{ + mByDayRadio->setChecked( true ); + // Days from the end are after the ones from the begin, so correct for the + // negative sign and add 30 (index starting at 0) + if ( day > 0 && day <= 31 ) + mByDayCombo->setCurrentItem( day-1 ); + else if ( day < 0 ) + mByDayCombo->setCurrentItem( 31 - 1 - day ); +} + +void RecurMonthly::setByPos( int count, int weekday ) +{ + mByPosRadio->setChecked( true ); + if (count>0) + mByPosCountCombo->setCurrentItem( count - 1 ); + else + // negative weeks means counted from the end of month + mByPosCountCombo->setCurrentItem( -count + 4 ); + mByPosWeekdayCombo->setCurrentItem( weekday - 1 ); +} + +bool RecurMonthly::byDay() +{ + return mByDayRadio->isChecked(); +} + +bool RecurMonthly::byPos() +{ + return mByPosRadio->isChecked(); +} + +int RecurMonthly::day() +{ + int day = mByDayCombo->currentItem(); + if ( day >= 31 ) day = 31-day-1; + else ++day; + return day; +} + +int RecurMonthly::count() +{ + int pos=mByPosCountCombo->currentItem(); + if (pos<=4) // positive count + return pos+1; + else + return -pos+4; +} + +int RecurMonthly::weekday() +{ + return mByPosWeekdayCombo->currentItem() + 1; +} + +/////////////////////////// RecurYearly /////////////////////////////// + +RecurYearly::RecurYearly( QWidget *parent, const char *name ) : + RecurBase( parent, name ) +{ + QBoxLayout *topLayout = new QVBoxLayout( this ); + topLayout->setSpacing( KDialog::spacingHint() ); + + createFrequencySpinBar( this, topLayout, i18n("&Recur every"), i18n("year(s)") ); + + + QButtonGroup *buttonGroup = new QButtonGroup( this ); + buttonGroup->setFrameStyle( QFrame::NoFrame ); + topLayout->addWidget( buttonGroup, 1, AlignVCenter ); + + QBoxLayout *buttonLayout = new QVBoxLayout( buttonGroup ); + + + /* YearlyMonth (day n of Month Y) */ + QBoxLayout *monthLayout = new QHBoxLayout( buttonLayout ); + QString recurInMonthText( + i18n("part before XXX of 'Recur on day XXX of month YYY'", + "&Recur on day ")); + if ( KOPrefs::instance()->mCompactDialogs ) { + recurInMonthText = i18n("&Day "); + } + mByMonthRadio = new QRadioButton( recurInMonthText, buttonGroup ); + QWhatsThis::add( mByMonthRadio, + i18n("Sets a specific day in a specific month on which " + "this event or to-do should recur.") ); + monthLayout->addWidget( mByMonthRadio ); + mByMonthSpin = new QSpinBox( 1, 31, 1, buttonGroup ); + QWhatsThis::add( mByMonthSpin, + i18n("The day of the month on which this event or to-do " + "should recur.") ); + monthLayout->addWidget( mByMonthSpin ); + QLabel *ofLabel = new QLabel( + i18n("part between XXX and YYY of 'Recur on day XXX of month YYY'", " &of "), + buttonGroup ); + //What do I do here? I'm not sure if this label should have What's This in it... - Antonio + monthLayout->addWidget( ofLabel ); + + mByMonthCombo = createMonthNameCombo( buttonGroup ); + monthLayout->addWidget( mByMonthCombo ); + ofLabel->setBuddy( mByMonthCombo ); + + monthLayout->addStretch( 1 ); + + + /* YearlyPos (weekday X of week N of month Y) */ + QBoxLayout *posLayout = new QHBoxLayout( buttonLayout ); + QString recurOnPosText( i18n("Part before XXX in 'Recur on NNN. WEEKDAY of MONTH', short version", "&On" ) ); + if ( !KOPrefs::instance()->mCompactDialogs ) { + recurOnPosText = i18n("Part before XXX in 'Recur on NNN. WEEKDAY of MONTH'", "&On the" ); + } + mByPosRadio = new QRadioButton( recurOnPosText, buttonGroup ); + QWhatsThis::add( mByPosRadio, + i18n("Sets a specific day in a specific week of a specific " + "month on which this event or to-do should recur.") ); + posLayout->addWidget( mByPosRadio ); + + mByPosDayCombo = createWeekCountCombo( buttonGroup ); + posLayout->addWidget( mByPosDayCombo ); + + mByPosWeekdayCombo = createWeekdayCombo( buttonGroup ); + posLayout->addWidget( mByPosWeekdayCombo ); + + ofLabel = new QLabel( + i18n("part between WEEKDAY and MONTH in 'Recur on NNN. WEEKDAY of MONTH'", " o&f "), + buttonGroup ); + posLayout->addWidget( ofLabel ); + + mByPosMonthCombo = createMonthNameCombo( buttonGroup ); + posLayout->addWidget( mByPosMonthCombo ); + ofLabel->setBuddy( mByPosMonthCombo ); + + posLayout->addStretch( 1 ); + + + /* YearlyDay (day N of the year) */ + QBoxLayout *dayLayout = new QHBoxLayout( buttonLayout ); + QString recurOnDayText; + if ( KOPrefs::instance()->mCompactDialogs ) { + recurOnDayText = i18n("Day #"); + } else { + recurOnDayText = i18n("Recur on &day #"); + } + QString whatsThis = i18n("Sets a specific day within the year on which this " + "event or to-do should recur."); + mByDayRadio = new QRadioButton( recurOnDayText, buttonGroup ); + QWhatsThis::add( mByDayRadio, whatsThis ); + dayLayout->addWidget( mByDayRadio ); + + mByDaySpin = new QSpinBox( 1, 366, 1, buttonGroup ); + QWhatsThis::add( mByDaySpin, whatsThis ); + + dayLayout->addWidget( mByDaySpin ); + + QString ofTheYear( i18n("part after NNN of 'Recur on day #NNN of the year'", " of the &year")); + if ( KOPrefs::instance()->mCompactDialogs ) { + ofTheYear = i18n("part after NNN of 'Recur on day #NNN of the year', short version", + " of the year"); + } + ofLabel = new QLabel( ofTheYear, buttonGroup ); + QWhatsThis::add( ofLabel, whatsThis ); + dayLayout->addWidget( ofLabel ); + ofLabel->setBuddy( mByDaySpin ); + + dayLayout->addStretch( 1 ); +} + +void RecurYearly::setByDay( int day ) +{ + mByDayRadio->setChecked( true ); + mByDaySpin->setValue( day ); +} + +void RecurYearly::setByPos( int count, int weekday, int month ) +{ + mByPosRadio->setChecked( true ); + if ( count > 0 ) + mByPosDayCombo->setCurrentItem( count - 1 ); + else + mByPosDayCombo->setCurrentItem( -count + 4 ); + mByPosWeekdayCombo->setCurrentItem( weekday - 1 ); + mByPosMonthCombo->setCurrentItem( month-1 ); +} + +void RecurYearly::setByMonth( int day, int month ) +{ + mByMonthRadio->setChecked( true ); + mByMonthSpin->setValue( day ); + mByMonthCombo->setCurrentItem( month - 1 ); +} + +RecurYearly::YearlyType RecurYearly::getType() +{ + if ( mByMonthRadio->isChecked() ) return byMonth; + if ( mByPosRadio->isChecked() ) return byPos; + if ( mByDayRadio->isChecked() ) return byDay; + return byMonth; +} + +int RecurYearly::monthDay() +{ + return mByMonthSpin->value(); +} + +int RecurYearly::month() +{ + return mByMonthCombo->currentItem() + 1; +} + +int RecurYearly::posCount() +{ + int pos = mByPosDayCombo->currentItem(); + if ( pos <= 4 ) // positive count + return pos + 1; + else + return -pos + 4; +} + +int RecurYearly::posWeekday() +{ + return mByPosWeekdayCombo->currentItem() + 1; +} + +int RecurYearly::posMonth() +{ + return mByPosMonthCombo->currentItem() + 1; +} + +int RecurYearly::day() +{ + return mByDaySpin->value(); +} + +//////////////////////////// ExceptionsWidget ////////////////////////// + +ExceptionsWidget::ExceptionsWidget( QWidget *parent, const char *name ) : + QWidget( parent, name ) +{ + QBoxLayout *topLayout = new QVBoxLayout( this ); + + QGroupBox *groupBox = new QGroupBox( 1, Horizontal, i18n("E&xceptions"), + this ); + topLayout->addWidget( groupBox ); + + QWidget *box = new QWidget( groupBox ); + + QGridLayout *boxLayout = new QGridLayout( box ); + + mExceptionDateEdit = new KDateEdit( box ); + QWhatsThis::add( mExceptionDateEdit, + i18n("A date that should be considered an exception " + "to the recurrence rules for this event or to-do.") ); + mExceptionDateEdit->setDate( QDate::currentDate() ); + boxLayout->addWidget( mExceptionDateEdit, 0, 0 ); + + QPushButton *addExceptionButton = new QPushButton( i18n("&Add"), box ); + QWhatsThis::add( addExceptionButton, + i18n("Add this date as an exception " + "to the recurrence rules for this event or to-do.") ); + boxLayout->addWidget( addExceptionButton, 1, 0 ); + QPushButton *changeExceptionButton = new QPushButton( i18n("&Change"), box ); + QWhatsThis::add( changeExceptionButton, + i18n("Replace the currently selected date with this date.") ); + boxLayout->addWidget( changeExceptionButton, 2, 0 ); + QPushButton *deleteExceptionButton = new QPushButton( i18n("&Delete"), box ); + QWhatsThis::add( deleteExceptionButton, + i18n("Delete the currently selected date from the list of dates " + "that should be considered exceptions to the recurrence rules " + "for this event or to-do.") ); + boxLayout->addWidget( deleteExceptionButton, 3, 0 ); + + mExceptionList = new QListBox( box ); + QWhatsThis::add( mExceptionList, + i18n("Displays current dates that are being considered " + "exceptions to the recurrence rules for this event " + "or to-do.") ); + boxLayout->addMultiCellWidget( mExceptionList, 0, 3, 1, 1 ); + + boxLayout->setRowStretch( 4, 1 ); + boxLayout->setColStretch( 1, 3 ); + + connect( addExceptionButton, SIGNAL( clicked() ), + SLOT( addException() ) ); + connect( changeExceptionButton, SIGNAL( clicked() ), + SLOT( changeException() ) ); + connect( deleteExceptionButton, SIGNAL( clicked() ), + SLOT( deleteException() ) ); +} + +void ExceptionsWidget::addException() +{ + QDate date = mExceptionDateEdit->date(); + QString dateStr = KGlobal::locale()->formatDate( date ); + if( !mExceptionList->findItem( dateStr ) ) { + mExceptionDates.append( date ); + mExceptionList->insertItem( dateStr ); + } +} + +void ExceptionsWidget::changeException() +{ + int pos = mExceptionList->currentItem(); + if ( pos < 0 ) return; + + QDate date = mExceptionDateEdit->date(); + mExceptionDates[ pos ] = date; + mExceptionList->changeItem( KGlobal::locale()->formatDate( date ), pos ); +} + +void ExceptionsWidget::deleteException() +{ + int pos = mExceptionList->currentItem(); + if ( pos < 0 ) return; + + mExceptionDates.remove( mExceptionDates.at( pos ) ); + mExceptionList->removeItem( pos ); +} + +void ExceptionsWidget::setDates( const DateList &dates ) +{ + mExceptionList->clear(); + mExceptionDates.clear(); + DateList::ConstIterator dit; + for ( dit = dates.begin(); dit != dates.end(); ++dit ) { + mExceptionList->insertItem( KGlobal::locale()->formatDate(* dit ) ); + mExceptionDates.append( *dit ); + } +} + +DateList ExceptionsWidget::dates() +{ + return mExceptionDates; +} + +///////////////////////// ExceptionsDialog /////////////////////////// + +ExceptionsDialog::ExceptionsDialog( QWidget *parent, const char *name ) : + KDialogBase( parent, name, true, i18n("Edit Exceptions"), Ok|Cancel ) +{ + mExceptions = new ExceptionsWidget( this ); + setMainWidget( mExceptions ); +} + +void ExceptionsDialog::setDates( const DateList &dates ) +{ + mExceptions->setDates( dates ); +} + +DateList ExceptionsDialog::dates() +{ + return mExceptions->dates(); +} + +///////////////////////// RecurrenceRangeWidget /////////////////////////// + +RecurrenceRangeWidget::RecurrenceRangeWidget( QWidget *parent, + const char *name ) + : QWidget( parent, name ) +{ + QBoxLayout *topLayout = new QVBoxLayout( this ); + + mRangeGroupBox = new QGroupBox( 1, Horizontal, i18n("Recurrence Range"), + this ); + QWhatsThis::add( mRangeGroupBox, + i18n("Sets a range for which these recurrence rules will " + "apply to this event or to-do.") ); + topLayout->addWidget( mRangeGroupBox ); + + QWidget *rangeBox = new QWidget( mRangeGroupBox ); + QVBoxLayout *rangeLayout = new QVBoxLayout( rangeBox ); + rangeLayout->setSpacing( KDialog::spacingHint() ); + + mStartDateLabel = new QLabel( i18n("Begin on:"), rangeBox ); + QWhatsThis::add( mStartDateLabel, + i18n("The date on which the recurrences for this event or to-do " + "should begin.") ); + rangeLayout->addWidget( mStartDateLabel ); + + QButtonGroup *rangeButtonGroup = new QButtonGroup( this ); + rangeButtonGroup->hide(); + + mNoEndDateButton = new QRadioButton( i18n("&No ending date"), rangeBox ); + QWhatsThis::add( mNoEndDateButton, + i18n("Sets the event or to-do to recur forever.") ); + rangeButtonGroup->insert( mNoEndDateButton ); + rangeLayout->addWidget( mNoEndDateButton ); + + QBoxLayout *durationLayout = new QHBoxLayout( rangeLayout ); + durationLayout->setSpacing( KDialog::spacingHint() ); + + mEndDurationButton = new QRadioButton( i18n("End &after"), rangeBox ); + QWhatsThis::add( mEndDurationButton, + i18n("Sets the event or to-do to stop recurring after a " + "certain number of occurrences.") ); + rangeButtonGroup->insert( mEndDurationButton ); + durationLayout->addWidget( mEndDurationButton ); + + QString whatsThis = i18n("Number of times the event or to-do should recur " + "before stopping."); + mEndDurationEdit = new QSpinBox( 1, 9999, 1, rangeBox ); + QWhatsThis::add( mEndDurationEdit, whatsThis ); + durationLayout->addWidget( mEndDurationEdit ); + + QLabel *endDurationLabel = new QLabel( i18n("&occurrence(s)"), rangeBox ); + QWhatsThis::add( endDurationLabel, whatsThis ); + durationLayout ->addWidget( endDurationLabel ); + endDurationLabel->setBuddy( mEndDurationEdit ); + + QBoxLayout *endDateLayout = new QHBoxLayout( rangeLayout ); + endDateLayout->setSpacing( KDialog::spacingHint() ); + + mEndDateButton = new QRadioButton( i18n("End &on:"), rangeBox ); + QWhatsThis::add( mEndDateButton, + i18n("Sets the event or to-do to stop recurring on " + "a certain date.") ); + rangeButtonGroup->insert( mEndDateButton ); + endDateLayout->addWidget( mEndDateButton ); + + mEndDateEdit = new KDateEdit( rangeBox ); + QWhatsThis::add( mEndDateEdit, + i18n("Date after which the event or to-do should stop " + "recurring") ); + endDateLayout->addWidget( mEndDateEdit ); + + endDateLayout->addStretch( 1 ); + + connect( mNoEndDateButton, SIGNAL( toggled( bool ) ), + SLOT( showCurrentRange() ) ); + connect( mEndDurationButton, SIGNAL( toggled( bool ) ), + SLOT( showCurrentRange() ) ); + connect( mEndDateButton, SIGNAL( toggled( bool ) ), + SLOT( showCurrentRange() ) ); +} + +void RecurrenceRangeWidget::setDefaults( const QDateTime &from ) +{ + mNoEndDateButton->setChecked( true ); + + setDateTimes( from ); + setEndDate( from.date() ); +} + +void RecurrenceRangeWidget::setDuration( int duration ) +{ + if ( duration == -1 ) { + mNoEndDateButton->setChecked( true ); + } else if ( duration == 0 ) { + mEndDateButton->setChecked( true ); + } else { + mEndDurationButton->setChecked( true ); + mEndDurationEdit->setValue( duration ); + } +} + +int RecurrenceRangeWidget::duration() +{ + if ( mNoEndDateButton->isChecked() ) { + return -1; + } else if ( mEndDurationButton->isChecked() ) { + return mEndDurationEdit->value(); + } else { + return 0; + } +} + +void RecurrenceRangeWidget::setEndDate( const QDate &date ) +{ + mEndDateEdit->setDate( date ); +} + +QDate RecurrenceRangeWidget::endDate() +{ + return mEndDateEdit->date(); +} + +void RecurrenceRangeWidget::showCurrentRange() +{ + mEndDurationEdit->setEnabled( mEndDurationButton->isChecked() ); + mEndDateEdit->setEnabled( mEndDateButton->isChecked() ); +} + +void RecurrenceRangeWidget::setDateTimes( const QDateTime &start, + const QDateTime & ) +{ + mStartDateLabel->setText( i18n("Begins on: %1") + .arg( KGlobal::locale()->formatDate( start.date() ) ) ); +} + +///////////////////////// RecurrenceRangeDialog /////////////////////////// + +RecurrenceRangeDialog::RecurrenceRangeDialog( QWidget *parent, + const char *name ) : + KDialogBase( parent, name, true, i18n("Edit Recurrence Range"), Ok|Cancel ) +{ + mRecurrenceRangeWidget = new RecurrenceRangeWidget( this ); + setMainWidget( mRecurrenceRangeWidget ); +} + +void RecurrenceRangeDialog::setDefaults( const QDateTime &from ) +{ + mRecurrenceRangeWidget->setDefaults( from ); +} + +void RecurrenceRangeDialog::setDuration( int duration ) +{ + mRecurrenceRangeWidget->setDuration( duration ); +} + +int RecurrenceRangeDialog::duration() +{ + return mRecurrenceRangeWidget->duration(); +} + +void RecurrenceRangeDialog::setEndDate( const QDate &date ) +{ + mRecurrenceRangeWidget->setEndDate( date ); +} + +QDate RecurrenceRangeDialog::endDate() +{ + return mRecurrenceRangeWidget->endDate(); +} + +void RecurrenceRangeDialog::setDateTimes( const QDateTime &start, + const QDateTime &end ) +{ + mRecurrenceRangeWidget->setDateTimes( start, end ); +} + +//////////////////////////// RecurrenceChooser //////////////////////// + +RecurrenceChooser::RecurrenceChooser( QWidget *parent, const char *name ) : + QWidget( parent, name ) +{ + QBoxLayout *topLayout = new QVBoxLayout( this ); + + if ( KOPrefs::instance()->mCompactDialogs ) { + mTypeCombo = new QComboBox( this ); + QWhatsThis::add( mTypeCombo, + i18n("Sets the type of recurrence this event or to-do " + "should have.") ); + mTypeCombo->insertItem( i18n("Daily") ); + mTypeCombo->insertItem( i18n("Weekly") ); + mTypeCombo->insertItem( i18n("Monthly") ); + mTypeCombo->insertItem( i18n("Yearly") ); + + topLayout->addWidget( mTypeCombo ); + + connect( mTypeCombo, SIGNAL( activated( int ) ), SLOT( emitChoice() ) ); + } else { + mTypeCombo = 0; + + QButtonGroup *ruleButtonGroup = new QButtonGroup( 1, Horizontal, this ); + ruleButtonGroup->setFrameStyle( QFrame::NoFrame ); + topLayout->addWidget( ruleButtonGroup ); + + mDailyButton = new QRadioButton( i18n("&Daily"), ruleButtonGroup ); + QWhatsThis::add( mDailyButton, + i18n("Sets the event or to-do to recur daily according " + "to the specified rules.") ); + mWeeklyButton = new QRadioButton( i18n("&Weekly"), ruleButtonGroup ); + QWhatsThis::add( mWeeklyButton, + i18n("Sets the event or to-do to recur weekly according " + "to the specified rules.") ); + mMonthlyButton = new QRadioButton( i18n("&Monthly"), ruleButtonGroup ); + QWhatsThis::add( mMonthlyButton, + i18n("Sets the event or to-do to recur monthly according " + "to the specified rules.") ); + mYearlyButton = new QRadioButton( i18n("&Yearly"), ruleButtonGroup ); + QWhatsThis::add( mYearlyButton, + i18n("Sets the event or to-do to recur yearly according " + "to the specified rules.") ); + + connect( mDailyButton, SIGNAL( toggled( bool ) ), + SLOT( emitChoice() ) ); + connect( mWeeklyButton, SIGNAL( toggled( bool ) ), + SLOT( emitChoice() ) ); + connect( mMonthlyButton, SIGNAL( toggled( bool ) ), + SLOT( emitChoice() ) ); + connect( mYearlyButton, SIGNAL( toggled( bool ) ), + SLOT( emitChoice() ) ); + } +} + +int RecurrenceChooser::type() +{ + if ( mTypeCombo ) { + return mTypeCombo->currentItem(); + } else { + if ( mDailyButton->isChecked() ) return Daily; + else if ( mWeeklyButton->isChecked() ) return Weekly; + else if ( mMonthlyButton->isChecked() ) return Monthly; + else return Yearly; + } +} + +void RecurrenceChooser::setType( int type ) +{ + if ( mTypeCombo ) { + mTypeCombo->setCurrentItem( type ); + } else { + switch ( type ) { + case Daily: + mDailyButton->setChecked( true ); + break; + case Weekly: + mWeeklyButton->setChecked( true ); + break; + case Monthly: + mMonthlyButton->setChecked( true ); + break; + case Yearly: + default: + mYearlyButton->setChecked( true ); + break; + } + } +} + +void RecurrenceChooser::emitChoice() +{ + emit chosen ( type() ); +} + +/////////////////////////////// Main Widget ///////////////////////////// + +KOEditorRecurrence::KOEditorRecurrence( QWidget* parent, const char *name ) : + QWidget( parent, name ) +{ + QGridLayout *topLayout = new QGridLayout( this ); + topLayout->setSpacing( KDialog::spacingHint() ); + + mEnabledCheck = new QCheckBox( i18n("&Enable recurrence"), this ); + QWhatsThis::add( mEnabledCheck, + i18n("Enables recurrence for this event or to-do according " + "to the specified rules.") ); + connect( mEnabledCheck, SIGNAL( toggled( bool ) ), + SLOT( setRecurrenceEnabled( bool ) ) ); + topLayout->addMultiCellWidget( mEnabledCheck, 0, 0, 0, 1 ); + + + mTimeGroupBox = new QGroupBox( 1, Horizontal, i18n("Appointment Time "), + this ); + QWhatsThis::add( mTimeGroupBox, + i18n("Displays appointment time information.") ); + topLayout->addMultiCellWidget( mTimeGroupBox, 1, 1 , 0 , 1 ); + + if ( KOPrefs::instance()->mCompactDialogs ) { + mTimeGroupBox->hide(); + } + +// QFrame *timeFrame = new QFrame( mTimeGroupBox ); +// QBoxLayout *layoutTimeFrame = new QHBoxLayout( timeFrame ); +// layoutTimeFrame->setSpacing( KDialog::spacingHint() ); + + mDateTimeLabel = new QLabel( mTimeGroupBox ); +// mDateTimeLabel = new QLabel( timeFrame ); +// layoutTimeFrame->addWidget( mDateTimeLabel ); + + Qt::Orientation orientation; + if ( KOPrefs::instance()->mCompactDialogs ) orientation = Horizontal; + else orientation = Vertical; + + mRuleBox = new QGroupBox( 1, orientation, i18n("Recurrence Rule"), this ); + QWhatsThis::add( mRuleBox, + i18n("Options concerning the type of recurrence this event " + "or to-do should have.") ); + if ( KOPrefs::instance()->mCompactDialogs ) { + topLayout->addWidget( mRuleBox, 2, 0 ); + } else { + topLayout->addMultiCellWidget( mRuleBox, 2, 2, 0, 1 ); + } + + mRecurrenceChooser = new RecurrenceChooser( mRuleBox ); + connect( mRecurrenceChooser, SIGNAL( chosen( int ) ), + SLOT( showCurrentRule( int ) ) ); + + if ( !KOPrefs::instance()->mCompactDialogs ) { + QFrame *ruleSepFrame = new QFrame( mRuleBox ); + ruleSepFrame->setFrameStyle( QFrame::VLine | QFrame::Sunken ); + } + + mRuleStack = new QWidgetStack( mRuleBox ); + + mDaily = new RecurDaily( mRuleStack ); + mRuleStack->addWidget( mDaily, 0 ); + + mWeekly = new RecurWeekly( mRuleStack ); + mRuleStack->addWidget( mWeekly, 0 ); + + mMonthly = new RecurMonthly( mRuleStack ); + mRuleStack->addWidget( mMonthly, 0 ); + + mYearly = new RecurYearly( mRuleStack ); + mRuleStack->addWidget( mYearly, 0 ); + + showCurrentRule( mRecurrenceChooser->type() ); + + if ( KOPrefs::instance()->mCompactDialogs ) { + mRecurrenceRangeWidget = 0; + mRecurrenceRangeDialog = new RecurrenceRangeDialog( this ); + mRecurrenceRange = mRecurrenceRangeDialog; + mRecurrenceRangeButton = new QPushButton( i18n("Recurrence Range..."), + this ); + QWhatsThis::add( mRecurrenceRangeButton, + i18n("Options concerning the time range during which " + "this event or to-do should recur.") ); + topLayout->addWidget( mRecurrenceRangeButton, 3, 0 ); + connect( mRecurrenceRangeButton, SIGNAL( clicked() ), + SLOT( showRecurrenceRangeDialog() ) ); + + mExceptionsWidget = 0; + mExceptionsDialog = new ExceptionsDialog( this ); + mExceptions = mExceptionsDialog; + mExceptionsButton = new QPushButton( i18n("Exceptions..."), this ); + topLayout->addWidget( mExceptionsButton, 4, 0 ); + connect( mExceptionsButton, SIGNAL( clicked() ), + SLOT( showExceptionsDialog() ) ); + + } else { + mRecurrenceRangeWidget = new RecurrenceRangeWidget( this ); + QWhatsThis::add( mRecurrenceRangeWidget, + i18n("Options concerning the time range during which " + "this event or to-do should recur.") ); + mRecurrenceRangeDialog = 0; + mRecurrenceRange = mRecurrenceRangeWidget; + mRecurrenceRangeButton = 0; + topLayout->addWidget( mRecurrenceRangeWidget, 3, 0 ); + + mExceptionsWidget = new ExceptionsWidget( this ); + mExceptionsDialog = 0; + mExceptions = mExceptionsWidget; + mExceptionsButton = 0; + topLayout->addWidget( mExceptionsWidget, 3, 1 ); + } +} + +KOEditorRecurrence::~KOEditorRecurrence() +{ +} + +void KOEditorRecurrence::setRecurrenceEnabled( bool enabled ) +{ +// kdDebug(5850) << "KOEditorRecurrence::setRecurrenceEnabled(): " << (enabled ? "on" : "off") << endl; + + mTimeGroupBox->setEnabled( enabled ); + mRuleBox->setEnabled( enabled ); + if ( mRecurrenceRangeWidget ) mRecurrenceRangeWidget->setEnabled( enabled ); + if ( mRecurrenceRangeButton ) mRecurrenceRangeButton->setEnabled( enabled ); + if ( mExceptionsWidget ) mExceptionsWidget->setEnabled( enabled ); + if ( mExceptionsButton ) mExceptionsButton->setEnabled( enabled ); +} + +void KOEditorRecurrence::showCurrentRule( int current ) +{ + switch ( current ) { + case Daily: + mRuleStack->raiseWidget( mDaily ); + break; + case Weekly: + mRuleStack->raiseWidget( mWeekly ); + break; + case Monthly: + mRuleStack->raiseWidget( mMonthly ); + break; + default: + case Yearly: + mRuleStack->raiseWidget( mYearly ); + break; + } +} + +void KOEditorRecurrence::setDateTimes( const QDateTime &start, const QDateTime &end ) +{ +// kdDebug(5850) << "KOEditorRecurrence::setDateTimes" << endl; + + mEventStartDt = start; + mRecurrenceRange->setDateTimes( start, end ); + mDaily->setDateTimes( start, end ); + mWeekly->setDateTimes( start, end ); + mMonthly->setDateTimes( start, end ); + mYearly->setDateTimes( start, end ); + + // Now set the defaults for all unused types, use the start time for it + bool enabled = mEnabledCheck->isChecked(); + int type = mRecurrenceChooser->type(); + + if ( !enabled || type != RecurrenceChooser::Weekly ) { + QBitArray days( 7 ); + days.fill( 0 ); + days.setBit( (start.date().dayOfWeek()+6) % 7 ); + mWeekly->setDays( days ); + } + if ( !enabled || type != RecurrenceChooser::Monthly ) { + mMonthly->setByPos( ( start.date().day() - 1 ) / 7 + 1, start.date().dayOfWeek() - 1 ); + mMonthly->setByDay( start.date().day() ); + } + if ( !enabled || type != RecurrenceChooser::Yearly ) { + mYearly->setByDay( start.date().dayOfYear() ); + mYearly->setByPos( ( start.date().day() - 1 ) / 7 + 1, + start.date().dayOfWeek() - 1, start.date().month() ); + mYearly->setByMonth( start.date().day(), start.date().month() ); + } +} + +void KOEditorRecurrence::setDefaults( const QDateTime &from, const QDateTime &to, bool ) +{ + setDateTimes( from, to ); + + bool enabled = false; + mEnabledCheck->setChecked( enabled ); + setRecurrenceEnabled( enabled ); + + mRecurrenceRange->setDefaults( from ); + + mRecurrenceChooser->setType( RecurrenceChooser::Weekly ); + showCurrentRule( mRecurrenceChooser->type() ); + + mDaily->setFrequency( 1 ); + + mWeekly->setFrequency( 1 ); + QBitArray days( 7 ); + days.fill( 0 ); + days.setBit( (from.date().dayOfWeek()+6) % 7 ); + mWeekly->setDays( days ); + + mMonthly->setFrequency( 1 ); + mMonthly->setByPos( ( from.date().day() - 1 ) / 7 + 1, from.date().dayOfWeek() ); + mMonthly->setByDay( from.date().day() ); + + mYearly->setFrequency( 1 ); + mYearly->setByDay( from.date().dayOfYear() ); + mYearly->setByPos( ( from.date().day() - 1 ) / 7 + 1, + from.date().dayOfWeek(), from.date().month() ); + mYearly->setByMonth( from.date().day(), from.date().month() ); +} + +void KOEditorRecurrence::readIncidence(Incidence *incidence) +{ + if (!incidence) return; + + QBitArray rDays( 7 ); + int day = 0; + int count = 0; + int month = 0; + + if ( incidence->type() == "Todo" ) { + Todo *todo = static_cast<Todo *>(incidence); + setDefaults( todo->dtStart(true), todo->dtDue(), todo->doesFloat() ); + } else { + setDefaults( incidence->dtStart(), incidence->dtEnd(), incidence->doesFloat() ); + } + + uint recurs = incidence->recurrenceType(); + int f = 0; + Recurrence *r = 0; + + if ( recurs ) { + r = incidence->recurrence(); + f = r->frequency(); + } + + + mEnabledCheck->setChecked( recurs ); + setRecurrenceEnabled( recurs ); + + int recurrenceType = RecurrenceChooser::Weekly; + + switch ( recurs ) { + case Recurrence::rNone: + break; + case Recurrence::rDaily: + recurrenceType = RecurrenceChooser::Daily; + mDaily->setFrequency( f ); + break; + case Recurrence::rWeekly: + recurrenceType = RecurrenceChooser::Weekly; + mWeekly->setFrequency( f ); + mWeekly->setDays( r->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; + + QValueList<RecurrenceRule::WDayPos> rmp = r->monthPositions(); + if ( !rmp.isEmpty() ) { + mMonthly->setByPos( rmp.first().pos(), rmp.first().day() ); + } + + mMonthly->setFrequency( f ); + + break; } + case Recurrence::rMonthlyDay: { + recurrenceType = RecurrenceChooser::Monthly; + + QValueList<int> rmd = r->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 = incidence->dtStart().date().day(); + } else { + day = rmd.first(); + } + mMonthly->setByDay( day ); + + mMonthly->setFrequency( f ); + + break; } + case Recurrence::rYearlyMonth: { + recurrenceType = RecurrenceChooser::Yearly; + QValueList<int> rmd = r->yearDates(); + if ( rmd.isEmpty() ) { + day = incidence->dtStart().date().day(); + } else { + day = rmd.first(); + } + int month = incidence->dtStart().date().month(); + rmd = r->yearMonths(); + if ( !rmd.isEmpty() ) + month = rmd.first(); + mYearly->setByMonth( day, month ); + mYearly->setFrequency( f ); + break; } + case Recurrence::rYearlyPos: { + recurrenceType = RecurrenceChooser::Yearly; + + QValueList<int> months = r->yearMonths(); + if ( months.isEmpty() ) { + month = incidence->dtStart().date().month(); + } else { + month = months.first(); + } + + QValueList<RecurrenceRule::WDayPos> pos = r->yearPositions(); + + if ( pos.isEmpty() ) { + // Use dtStart if nothing is given (shouldn't happen!) + count = ( incidence->dtStart().date().day() - 1 ) / 7; + day = incidence->dtStart().date().dayOfWeek(); + } else { + count = pos.first().pos(); + day = pos.first().day(); + } + mYearly->setByPos( count, day, month ); + mYearly->setFrequency( f ); + break; } + case Recurrence::rYearlyDay: { + recurrenceType = RecurrenceChooser::Yearly; + QValueList<int> days = r->yearDays(); + if ( days.isEmpty() ) { + day = incidence->dtStart().date().dayOfYear(); + } else { + day = days.first(); + } + mYearly->setByDay( day ); + + mYearly->setFrequency( f ); + break; } + default: + break; + } + + mRecurrenceChooser->setType( recurrenceType ); + showCurrentRule( recurrenceType ); + + mRecurrenceRange->setDateTimes( incidence->recurrence()->startDateTime() ); + + if ( incidence->doesRecur() ) { + mRecurrenceRange->setDuration( r->duration() ); + if ( r->duration() == 0 ) mRecurrenceRange->setEndDate( r->endDate() ); + } + + mExceptions->setDates( incidence->recurrence()->exDates() ); +} + +void KOEditorRecurrence::writeIncidence( Incidence *incidence ) +{ + if ( !mEnabledCheck->isChecked() || !isEnabled() ) + { + if ( incidence->doesRecur() ) + incidence->recurrence()->unsetRecurs(); + return; + } + + Recurrence *r = incidence->recurrence(); + + // clear out any old settings; + r->unsetRecurs(); + + int duration = mRecurrenceRange->duration(); + QDate endDate; + if ( duration == 0 ) endDate = mRecurrenceRange->endDate(); + + int recurrenceType = mRecurrenceChooser->type(); + if ( recurrenceType == RecurrenceChooser::Daily ) { + r->setDaily( mDaily->frequency() ); + } else if ( recurrenceType == RecurrenceChooser::Weekly ) { + r->setWeekly( mWeekly->frequency(), mWeekly->days() ); + } else if ( recurrenceType == RecurrenceChooser::Monthly ) { + r->setMonthly( mMonthly->frequency() ); + + if ( mMonthly->byPos() ) { + int pos = mMonthly->count(); + + QBitArray days( 7 ); + days.fill( false ); + days.setBit( mMonthly->weekday() - 1 ); + r->addMonthlyPos( pos, days ); + } else { + // it's by day + r->addMonthlyDate( mMonthly->day() ); + } + } else if ( recurrenceType == RecurrenceChooser::Yearly ) { + r->setYearly( mYearly->frequency() ); + + switch ( mYearly->getType() ) { + case RecurYearly::byMonth: + r->addYearlyDate( mYearly->monthDay() ); + r->addYearlyMonth( mYearly->month() ); + break; + case RecurYearly::byPos: { + r->addYearlyMonth( mYearly->posMonth() ); + QBitArray days( 7 ); + days.fill( false ); + days.setBit( mYearly->posWeekday() - 1 ); + r->addYearlyPos( mYearly->posCount(), days ); + break; } + case RecurYearly::byDay: + r->addYearlyDay( mYearly->day() ); + break; + } + } // end "Yearly" + + if ( duration > 0 ) + r->setDuration( duration ); + else if ( duration == 0 ) + r->setEndDate( endDate ); + incidence->recurrence()->setExDates( mExceptions->dates() ); +} + +void KOEditorRecurrence::setDateTimeStr( const QString &str ) +{ + mDateTimeLabel->setText( str ); +} + +bool KOEditorRecurrence::validateInput() +{ + // Check input here. + // Check if the recurrence (if set to end at a date) is scheduled to end before the event starts. + if ( mEnabledCheck->isChecked() && (mRecurrenceRange->duration()==0) && + mEventStartDt.isValid() && ((mRecurrenceRange->endDate())<mEventStartDt.date()) ) { + KMessageBox::sorry( 0, + i18n("The end date '%1' of the recurrence must be after the start date '%2' of the event.") + .arg( KGlobal::locale()->formatDate( mRecurrenceRange->endDate() ) ) + .arg( KGlobal::locale()->formatDate( mEventStartDt.date() ) ) ); + return false; + } + int recurrenceType = mRecurrenceChooser->type(); + // Check if a weekly recurrence has at least one day selected + // TODO: Get rid of this, it's not really needed (by default the day should be taken from dtStart) + if( mEnabledCheck->isChecked() && recurrenceType == RecurrenceChooser::Weekly ) { + const QBitArray &days = mWeekly->days(); + bool valid = false; + for ( int i=0; i<7; ++i ) valid = valid || days.testBit( i ); + if ( !valid ) { + KMessageBox::sorry( 0, + i18n("A weekly recurring event or task has to have at least one weekday " + "associated with it.") ); + return false; + } + } + return true; +} + +void KOEditorRecurrence::showExceptionsDialog() +{ + DateList dates = mExceptions->dates(); + int result = mExceptionsDialog->exec(); + if ( result == QDialog::Rejected ) mExceptions->setDates( dates ); +} + +void KOEditorRecurrence::showRecurrenceRangeDialog() +{ + int duration = mRecurrenceRange->duration(); + QDate endDate = mRecurrenceRange->endDate(); + + int result = mRecurrenceRangeDialog->exec(); + if ( result == QDialog::Rejected ) { + mRecurrenceRange->setDuration( duration ); + mRecurrenceRange->setEndDate( endDate ); + } +} + +bool KOEditorRecurrence::doesRecur() +{ + return mEnabledCheck->isChecked(); +} + + +KOEditorRecurrenceDialog::KOEditorRecurrenceDialog(QWidget * parent) : + KDialogBase( parent, 0, false, i18n("Recurrence"), Ok ) +{ + mRecurrence = new KOEditorRecurrence( this ); + setMainWidget( mRecurrence ); +} diff --git a/korganizer/koeditorrecurrence.h b/korganizer/koeditorrecurrence.h new file mode 100644 index 000000000..2a0532a6e --- /dev/null +++ b/korganizer/koeditorrecurrence.h @@ -0,0 +1,352 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2000-2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef _KOEDITORRECURRENCE_H +#define _KOEDITORRECURRENCE_H + +#include <qdatetime.h> +#include <qwidget.h> +#include <qbitarray.h> + +#include <kdialogbase.h> + +#include <libkcal/incidencebase.h> + +class QWidgetStack; +class QSpinBox; +class QRadioButton; +class QGroupBox; +class QCheckBox; + +class KDateEdit; +namespace KCal { +class Incidence; +} +using namespace KCal; + +class RecurBase : public QWidget +{ + public: + RecurBase( QWidget *parent = 0, const char *name = 0 ); + + void setFrequency( int ); + int frequency(); + // FIXME: If we want to adjust the recurrence when the start/due date change, + // we need to reimplement this method in the derived classes! + void setDateTimes( const QDateTime &/*start*/, const QDateTime &/*end*/ ) {} + + QWidget *frequencyEdit(); + + protected: + static QComboBox *createWeekCountCombo( QWidget *parent=0, const char *name=0 ); + static QComboBox *createWeekdayCombo( QWidget *parent=0, const char *name=0 ); + static QComboBox *createMonthNameCombo( QWidget *parent=0, const char *name=0 ); + QBoxLayout *createFrequencySpinBar( QWidget *parent, QLayout *layout, + QString everyText, QString unitText ); + + private: + QSpinBox *mFrequencyEdit; +}; + +class RecurDaily : public RecurBase +{ + public: + RecurDaily( QWidget *parent = 0, const char *name = 0 ); +}; + +class RecurWeekly : public RecurBase +{ + public: + RecurWeekly( QWidget *parent = 0, const char *name = 0 ); + + void setDays( const QBitArray & ); + QBitArray days(); + + private: + QCheckBox *mDayBoxes[7]; +}; + +class RecurMonthly : public RecurBase +{ + public: + RecurMonthly( QWidget *parent = 0, const char *name = 0 ); + + void setByDay( int day ); + void setByPos( int count, int weekday ); + + bool byDay(); + bool byPos(); + + int day(); + + int count(); + int weekday(); + + private: + QRadioButton *mByDayRadio; + QComboBox *mByDayCombo; + + QRadioButton *mByPosRadio; + QComboBox *mByPosCountCombo; + QComboBox *mByPosWeekdayCombo; +}; + +class RecurYearly : public RecurBase +{ + public: + enum YearlyType { byDay, byPos, byMonth }; + + RecurYearly( QWidget *parent = 0, const char *name = 0 ); + + void setByDay( int day ); + void setByPos( int count, int weekday, int month ); + void setByMonth( int day, int month ); + + YearlyType getType(); + + int day(); + int posCount(); + int posWeekday(); + int posMonth(); + int monthDay(); + int month(); + + private: + QRadioButton *mByMonthRadio; + QRadioButton *mByPosRadio; + QRadioButton *mByDayRadio; + + QSpinBox *mByMonthSpin; + QComboBox *mByMonthCombo; + + QComboBox *mByPosDayCombo; + QComboBox *mByPosWeekdayCombo; + QComboBox *mByPosMonthCombo; + + QSpinBox *mByDaySpin; +}; + +class RecurrenceChooser : public QWidget +{ + Q_OBJECT + public: + RecurrenceChooser( QWidget *parent = 0, const char *name = 0 ); + + enum { Daily, Weekly, Monthly, Yearly }; + + void setType( int ); + int type(); + + signals: + void chosen( int ); + + protected slots: + void emitChoice(); + + private: + QComboBox *mTypeCombo; + + QRadioButton *mDailyButton; + QRadioButton *mWeeklyButton; + QRadioButton *mMonthlyButton; + QRadioButton *mYearlyButton; +}; + +class ExceptionsBase +{ + public: + virtual void setDates( const DateList & ) = 0; + virtual DateList dates() = 0; +}; + +class ExceptionsWidget : public QWidget, public ExceptionsBase +{ + Q_OBJECT + public: + ExceptionsWidget( QWidget *parent = 0, const char *name = 0 ); + + void setDates( const DateList & ); + DateList dates(); + + protected slots: + void addException(); + void changeException(); + void deleteException(); + + private: + KDateEdit *mExceptionDateEdit; + QListBox *mExceptionList; + DateList mExceptionDates; +}; + +class ExceptionsDialog : public KDialogBase, public ExceptionsBase +{ + public: + ExceptionsDialog( QWidget *parent, const char *name = 0 ); + + void setDates( const DateList & ); + DateList dates(); + + private: + ExceptionsWidget *mExceptions; +}; + +class RecurrenceRangeBase +{ + public: + virtual void setDefaults( const QDateTime &from ) = 0; + + virtual void setDuration( int ) = 0; + virtual int duration() = 0; + + virtual void setEndDate( const QDate & ) = 0; + virtual QDate endDate() = 0; + + virtual void setDateTimes( const QDateTime &start, + const QDateTime &end = QDateTime() ) = 0; +}; + +class RecurrenceRangeWidget : public QWidget, public RecurrenceRangeBase +{ + Q_OBJECT + public: + RecurrenceRangeWidget( QWidget *parent = 0, const char *name = 0 ); + + void setDefaults( const QDateTime &from ); + + void setDuration( int ); + int duration(); + + void setEndDate( const QDate & ); + QDate endDate(); + + void setDateTimes( const QDateTime &start, + const QDateTime &end = QDateTime() ); + + protected slots: + void showCurrentRange(); + + private: + QGroupBox *mRangeGroupBox; + QLabel *mStartDateLabel; + QRadioButton *mNoEndDateButton; + QRadioButton *mEndDurationButton; + QSpinBox *mEndDurationEdit; + QRadioButton *mEndDateButton; + KDateEdit *mEndDateEdit; +}; + +class RecurrenceRangeDialog : public KDialogBase, public RecurrenceRangeBase +{ + public: + RecurrenceRangeDialog( QWidget *parent = 0, const char *name = 0 ); + + void setDefaults( const QDateTime &from ); + + void setDuration( int ); + int duration(); + + void setEndDate( const QDate & ); + QDate endDate(); + + void setDateTimes( const QDateTime &start, + const QDateTime &end = QDateTime() ); + + private: + RecurrenceRangeWidget *mRecurrenceRangeWidget; +}; + +class KOEditorRecurrence : public QWidget +{ + Q_OBJECT + public: + KOEditorRecurrence ( QWidget *parent = 0, const char *name = 0 ); + virtual ~KOEditorRecurrence(); + + enum { Daily, Weekly, Monthly, Yearly }; + + /** Set widgets to default values */ + void setDefaults( const QDateTime &from, const QDateTime &to, bool allday ); + /** Read event object and setup widgets accordingly */ + void readIncidence( Incidence * ); + /** Write event settings to event object */ + void writeIncidence( Incidence * ); + + /** Check if the input is valid. */ + bool validateInput(); + + bool doesRecur(); + + public slots: + void setRecurrenceEnabled( bool ); + void setDateTimes( const QDateTime &start, const QDateTime &end ); + void setDateTimeStr( const QString & ); + + signals: + void dateTimesChanged( const QDateTime &start, const QDateTime &end ); + + protected slots: + void showCurrentRule( int ); + void showExceptionsDialog(); + void showRecurrenceRangeDialog(); + + private: + QCheckBox *mEnabledCheck; + + QGroupBox *mTimeGroupBox; + QLabel *mDateTimeLabel; + + QGroupBox *mRuleBox; + QWidgetStack *mRuleStack; + RecurrenceChooser *mRecurrenceChooser; + + RecurDaily *mDaily; + RecurWeekly *mWeekly; + RecurMonthly *mMonthly; + RecurYearly *mYearly; + + RecurrenceRangeBase *mRecurrenceRange; + RecurrenceRangeWidget *mRecurrenceRangeWidget; + RecurrenceRangeDialog *mRecurrenceRangeDialog; + QPushButton *mRecurrenceRangeButton; + + ExceptionsBase *mExceptions; + ExceptionsDialog *mExceptionsDialog; + ExceptionsWidget *mExceptionsWidget; + QPushButton *mExceptionsButton; + + QDateTime mEventStartDt; +}; + +class KOEditorRecurrenceDialog : public KDialogBase +{ + Q_OBJECT + public: + KOEditorRecurrenceDialog( QWidget *parent ); + KOEditorRecurrence* editor() const { return mRecurrence; } + + private: + KOEditorRecurrence *mRecurrence; +}; + +#endif diff --git a/korganizer/koeventeditor.cpp b/korganizer/koeventeditor.cpp new file mode 100644 index 000000000..31a909717 --- /dev/null +++ b/korganizer/koeventeditor.cpp @@ -0,0 +1,430 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001, 2002, 2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qtooltip.h> +#include <qframe.h> +#include <qpixmap.h> +#include <qlayout.h> +#include <qwidgetstack.h> +#include <qwhatsthis.h> + +#include <kiconloader.h> +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <libkcal/calendarresources.h> +#include <libkcal/resourcecalendar.h> +#include <libkcal/incidenceformatter.h> +#include <libkcal/calendarlocal.h> + +#include "koprefs.h" +#include "koeditorgeneralevent.h" +#include "koeditoralarms.h" +#include "koeditorrecurrence.h" +#include "koeditordetails.h" +#include "koeditorfreebusy.h" +#include "kogroupware.h" +#include "kodialogmanager.h" +#include "incidencechanger.h" + +#include "koeventeditor.h" + +KOEventEditor::KOEventEditor( Calendar *calendar, QWidget *parent ) + : KOIncidenceEditor( QString::null, calendar, parent ), + mEvent( 0 ), mCalendar( 0 ), mGeneral( 0 ), mRecurrence( 0 ), mFreeBusy( 0 ) +{ +} + +KOEventEditor::~KOEventEditor() +{ + if ( !mIsCounter ) + emit dialogClose( mEvent ); +} + +void KOEventEditor::init() +{ + setupGeneral(); +// setupAlarmsTab(); + setupRecurrence(); + setupFreeBusy(); + setupDesignerTabs( "event" ); + + // Propagate date time settings to recurrence tab + connect( mGeneral, SIGNAL( dateTimesChanged( const QDateTime &, const QDateTime & ) ), + mRecurrence, SLOT( setDateTimes( const QDateTime &, const QDateTime &) ) ); + connect( mGeneral, SIGNAL( dateTimeStrChanged( const QString & ) ), + mRecurrence, SLOT( setDateTimeStr( const QString & ) ) ); + connect( mFreeBusy, SIGNAL( dateTimesChanged( const QDateTime &, const QDateTime & ) ), + mRecurrence, SLOT( setDateTimes( const QDateTime &, const QDateTime & ) ) ); + + // Propagate date time settings to gantt tab and back + connect( mGeneral, SIGNAL( dateTimesChanged( const QDateTime &, const QDateTime & ) ), + mFreeBusy, SLOT( slotUpdateGanttView( const QDateTime &, const QDateTime & ) ) ); + connect( mFreeBusy, SIGNAL( dateTimesChanged( const QDateTime &, const QDateTime & ) ), + mGeneral, SLOT( setDateTimes( const QDateTime &, const QDateTime & ) ) ); + + connect( mGeneral, SIGNAL( focusReceivedSignal() ), + SIGNAL( focusReceivedSignal() ) ); + + connect( mGeneral, SIGNAL( openCategoryDialog() ), + SIGNAL( editCategories() ) ); + connect( this, SIGNAL( updateCategoryConfig() ), + mGeneral, SIGNAL( updateCategoryConfig() ) ); + + connect( mFreeBusy, SIGNAL(updateAttendeeSummary(int)), + mGeneral, SLOT(updateAttendeeSummary(int)) ); + + connect( mGeneral, SIGNAL(editRecurrence()), + mRecurrenceDialog, SLOT(show()) ); + connect( mRecurrenceDialog, SIGNAL(okClicked()), + SLOT(updateRecurrenceSummary()) ); + + connect( mGeneral, SIGNAL(acceptInvitation()), + mFreeBusy, SLOT(acceptForMe()) ); + connect( mGeneral, SIGNAL(declineInvitation()), + mFreeBusy, SLOT(declineForMe()) ); +} + +void KOEventEditor::reload() +{ + kdDebug(5850) << "KOEventEditor::reload()" << endl; + + if ( mEvent ) readEvent( mEvent, mCalendar ); +} + +void KOEventEditor::setupGeneral() +{ + mGeneral = new KOEditorGeneralEvent( this ); + + if( KOPrefs::instance()->mCompactDialogs ) { + QFrame *topFrame = addPage(i18n("General")); + QWhatsThis::add( topFrame, + i18n("The General tab allows you to set the most common " + "options for the event.") ); + + QBoxLayout *topLayout = new QVBoxLayout(topFrame); + topLayout->setSpacing(spacingHint()); + + mGeneral->initHeader( topFrame, topLayout ); + mGeneral->initTime(topFrame,topLayout); +// QBoxLayout *alarmLineLayout = new QHBoxLayout(topLayout); + mGeneral->initAlarm(topFrame,topLayout); + mGeneral->enableAlarm( false ); + + topLayout->addStretch( 1 ); + + QFrame *topFrame2 = addPage(i18n("Details")); + + QBoxLayout *topLayout2 = new QVBoxLayout(topFrame2); + topLayout2->setSpacing(spacingHint()); + + mGeneral->initClass(topFrame2,topLayout2); + mGeneral->initSecrecy( topFrame2, topLayout2 ); + mGeneral->initDescription(topFrame2,topLayout2); + } else { + QFrame *topFrame = addPage(i18n("&General")); + QWhatsThis::add( topFrame, + i18n("The General tab allows you to set the most common " + "options for the event.") ); + + QBoxLayout *topLayout = new QVBoxLayout(topFrame); + topLayout->setSpacing(spacingHint()); + + mGeneral->initInvitationBar( topFrame, topLayout ); + mGeneral->initHeader( topFrame, topLayout ); + mGeneral->initTime(topFrame,topLayout); + mGeneral->initDescription(topFrame,topLayout); + mGeneral->initAttachments(topFrame,topLayout); + connect( mGeneral, SIGNAL( openURL( const KURL& ) ), + this, SLOT( openURL( const KURL& ) ) ); + connect( this, SIGNAL( signalAddAttachments( const QStringList&, const QStringList&, bool ) ), + mGeneral, SLOT( addAttachments( const QStringList&, const QStringList&, bool ) ) ); + } + + mGeneral->finishSetup(); +} + +void KOEventEditor::modified (int /*modification*/) +{ + // Play dump, 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 + QFrame *topFrame = addPage( i18n("Rec&urrence") ); + + QWhatsThis::add( topFrame, + i18n("The Recurrence tab allows you to set options on " + "how often this event recurs.") ); + + QBoxLayout *topLayout = new QVBoxLayout( topFrame ); + + mRecurrence = new KOEditorRecurrence( topFrame ); + topLayout->addWidget( mRecurrence ); +#endif + mRecurrenceDialog = new KOEditorRecurrenceDialog( this ); + mRecurrenceDialog->hide(); + mRecurrence = mRecurrenceDialog->editor(); +} + +void KOEventEditor::setupFreeBusy() +{ + QFrame *freeBusyPage = addPage( i18n("&Attendees") ); + QWhatsThis::add( freeBusyPage, + i18n("The Free/Busy tab allows you to see whether " + "other attendees are free or busy during your event.") ); + + QBoxLayout *topLayout = new QVBoxLayout( freeBusyPage ); + + mAttendeeEditor = mFreeBusy = new KOEditorFreeBusy( spacingHint(), freeBusyPage ); + topLayout->addWidget( mFreeBusy ); +} + +void KOEventEditor::editIncidence( Incidence *incidence, Calendar *calendar ) +{ + Event*event = dynamic_cast<Event*>(incidence); + if ( event ) { + init(); + + mEvent = event; + mCalendar = calendar; + readEvent( mEvent, mCalendar ); + } + + setCaption( i18n("Edit Event") ); +} + +void KOEventEditor::newEvent() +{ + init(); + mEvent = 0; + loadDefaults(); + setCaption( i18n("New Event") ); +} + +void KOEventEditor::setDates( const QDateTime &from, const QDateTime &to, bool allDay ) +{ + mGeneral->setDefaults( from, to, allDay ); + mRecurrence->setDefaults( from, to, allDay ); + if( mFreeBusy ) { + if ( allDay ) + mFreeBusy->setDateTimes( from, to.addDays( 1 ) ); + else + mFreeBusy->setDateTimes( from, to ); + } +} + +void KOEventEditor::setTexts( const QString &summary, const QString &description ) +{ + if ( description.isEmpty() && summary.contains("\n") ) { + mGeneral->setDescription( summary ); + int pos = summary.find( "\n" ); + mGeneral->setSummary( summary.left( pos ) ); + } else { + mGeneral->setSummary( summary ); + mGeneral->setDescription( description ); + } +} + +void KOEventEditor::loadDefaults() +{ + QDateTime from( QDate::currentDate(), KOPrefs::instance()->mStartTime.time() ); + int addSecs = ( KOPrefs::instance()->mDefaultDuration.time().hour()*3600 ) + + ( KOPrefs::instance()->mDefaultDuration.time().minute()*60 ); + QDateTime to( from.addSecs( addSecs ) ); + + setDates( from, to, false ); +} + +bool KOEventEditor::processInput() +{ + kdDebug(5850) << "KOEventEditor::processInput()" << endl; + + if ( !validateInput() || !mChanger ) return false; + + QGuardedPtr<KOEditorFreeBusy> freeBusy( mFreeBusy ); + + if ( mEvent ) { + bool rc = true; + Event *oldEvent = mEvent->clone(); + Event *event = mEvent->clone(); + + kdDebug(5850) << "KOEventEditor::processInput() write event." << endl; + writeEvent( event ); + kdDebug(5850) << "KOEventEditor::processInput() event written." << endl; + + if( *event == *mEvent ) { + // Don't do anything + kdDebug(5850) << "Event not changed\n"; + 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"; + //IncidenceChanger::assignIncidence( mEvent, event ); + writeEvent( mEvent ); + if ( mIsCounter ) { + KOGroupware::instance()->sendCounterProposal( mCalendar, oldEvent, mEvent ); + // add dummy event at the position of the counter proposal + Event *event = mEvent->clone(); + event->clearAttendees(); + event->setSummary( i18n("My counter proposal for: %1").arg( mEvent->summary() ) ); + mChanger->addIncidence( event ); + } else { + mChanger->changeIncidence( oldEvent, mEvent ); + } + } + delete event; + delete oldEvent; + return rc; + } else { + mEvent = new Event; + mEvent->setOrganizer( Person( KOPrefs::instance()->fullName(), + 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 ) ) { + delete mEvent; + mEvent = 0; + return false; + } + } + // if "this" was deleted, freeBusy is 0 (being a guardedptr) + if ( freeBusy ) freeBusy->cancelReload(); + + return true; +} + +void KOEventEditor::processCancel() +{ + kdDebug(5850) << "KOEventEditor::processCancel()" << endl; + + if ( mFreeBusy ) mFreeBusy->cancelReload(); +} + +void KOEventEditor::deleteEvent() +{ + kdDebug(5850) << "Delete event" << endl; + + if ( mEvent ) + emit deleteIncidenceSignal( mEvent ); + emit dialogClose( mEvent ); + reject(); +} + +void KOEventEditor::readEvent( Event *event, Calendar *calendar, bool tmpl ) +{ + mGeneral->readEvent( event, calendar, tmpl ); + mRecurrence->readIncidence( event ); +// mAlarms->readIncidence( event ); + if ( mFreeBusy ) { + mFreeBusy->readEvent( event ); + mFreeBusy->triggerReload(); + } + + createEmbeddedURLPages( event ); + readDesignerFields( event ); + + if ( mIsCounter ) + mGeneral->invitationBar()->hide(); +} + +void KOEventEditor::writeEvent( Event *event ) +{ + mGeneral->writeEvent( event ); + if ( mFreeBusy ) + mFreeBusy->writeEvent( event ); + + cancelRemovedAttendees( event ); + + mRecurrence->writeIncidence( event ); + + writeDesignerFields( event ); +} + +bool KOEventEditor::validateInput() +{ + if ( !mGeneral->validateInput() ) return false; + if ( !mDetails->validateInput() ) return false; + if ( !mRecurrence->validateInput() ) return false; + + return true; +} + +int KOEventEditor::msgItemDelete() +{ + return KMessageBox::warningContinueCancel(this, + i18n("This item will be permanently deleted."), + i18n("KOrganizer Confirmation"),KGuiItem(i18n("Delete"),"editdelete")); +} + +void KOEventEditor::loadTemplate( /*const*/ CalendarLocal& cal ) +{ + const Event::List events = cal.events(); + if ( events.count() == 0 ) { + KMessageBox::error( this, + i18n("Template does not contain a valid event.") ); + } else { + kdDebug(5850) << "KOEventEditor::slotLoadTemplate(): readTemplate" << endl; + readEvent( events.first(), 0, true ); + } +} + +QStringList& KOEventEditor::templates() const +{ + return KOPrefs::instance()->mEventTemplates; +} + +void KOEventEditor::slotSaveTemplate( const QString &templateName ) +{ + kdDebug(5006) << "SlotSaveTemplate" << endl; + Event *event = new Event; + writeEvent( event ); + saveAsTemplate( event, templateName ); +} + +QObject *KOEventEditor::typeAheadReceiver() const +{ + return mGeneral->typeAheadReceiver(); +} + +void KOEventEditor::updateRecurrenceSummary() +{ + Event *ev = new Event(); + writeEvent( ev ); + mGeneral->updateRecurrenceSummary( IncidenceFormatter::recurrenceString( ev ) ); + delete ev; +} + +void KOEventEditor::selectInvitationCounterProposal(bool enable) +{ + KOIncidenceEditor::selectInvitationCounterProposal( enable ); + if ( enable ) + mGeneral->invitationBar()->hide(); +} + +#include "koeventeditor.moc" diff --git a/korganizer/koeventeditor.h b/korganizer/koeventeditor.h new file mode 100644 index 000000000..6d06fe276 --- /dev/null +++ b/korganizer/koeventeditor.h @@ -0,0 +1,134 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001,2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOEVENTEDITOR_H +#define KOEVENTEDITOR_H + +#include "koincidenceeditor.h" + +class KOEditorGeneralEvent; +class KOEditorRecurrence; +class KOEditorRecurrenceDialog; +class KOEditorFreeBusy; + +class SaveTemplateDialog; + +class KOEditorFreeBusy; + +namespace KCal { +class Calendar; +class Event; +} +using namespace KCal; + +/** + This class provides a dialog for editing an event. +*/ +class KOEventEditor : public KOIncidenceEditor +{ + Q_OBJECT + public: + /** + Construct new event editor. + */ + KOEventEditor( Calendar *calendar, QWidget *parent ); + virtual ~KOEventEditor(void); + + void init(); + /** This event has been modified externally */ + void modified (int change=0); + void reload(); + + /** + Clear event win for new event + */ + void newEvent(); + + /** + Sets the given summary and description. If description is empty and the + summary contains multiple lines, the summary will be used as description + and only the first line of summary will be used as the summary. + */ + void setTexts( const QString &summary, const QString &description = QString::null ); + /** + Edit an existing event. + */ + void editIncidence( Incidence *incidence, Calendar *calendar ); + + /** + Set widgets to the given date/time values + */ + void setDates( const QDateTime &from, const QDateTime &to, bool allDay ); + + /** + 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 ); + /** + Write event settings to event object + */ + void writeEvent( Event * ); + + QObject *typeAheadReceiver() const; + + void selectInvitationCounterProposal( bool enable ); + + signals: + void focusReceivedSignal(); + + protected slots: + void loadDefaults(); + void deleteEvent(); + + void slotSaveTemplate( const QString & ); + void updateRecurrenceSummary(); + + protected: + QString type() { return "Event"; } + void setupGeneral(); + void setupRecurrence(); + void setupFreeBusy(); + + /** Check if the input is valid. */ + bool validateInput(); + /** Process user input and create or update event. Returns false if input + * is not valid */ + bool processInput(); + void processCancel(); + int msgItemDelete(); + void loadTemplate( /*const*/ CalendarLocal& ); + QStringList& templates() const; + + private: + Event *mEvent; + Calendar* mCalendar; + + KOEditorGeneralEvent *mGeneral; + KOEditorRecurrenceDialog *mRecurrenceDialog; + KOEditorRecurrence *mRecurrence; + KOEditorFreeBusy *mFreeBusy; +}; + +#endif diff --git a/korganizer/koeventpopupmenu.cpp b/korganizer/koeventpopupmenu.cpp new file mode 100644 index 000000000..54272fd54 --- /dev/null +++ b/korganizer/koeventpopupmenu.cpp @@ -0,0 +1,195 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qcursor.h> + +#include <kactioncollection.h> +#include <klocale.h> +#include <kdebug.h> +#include <kiconloader.h> +#include <kurl.h> + +#include <libkcal/event.h> + +#include "koglobals.h" + +#include <korganizer/baseview.h> +#include "koeventpopupmenu.h" +#include "koeventpopupmenu.moc" +#include "kocorehelper.h" +#include "actionmanager.h" +#ifndef KORG_NOPRINTER +#include "calprinter.h" +#endif + +KOEventPopupMenu::KOEventPopupMenu() +{ + mCurrentIncidence = 0; + mCurrentDate = QDate(); + mHasAdditionalItems = false; + + insertItem( i18n("&Show"), this, SLOT( popupShow() ) ); + mEditOnlyItems.append( + insertItem(i18n("&Edit..."), this, SLOT( popupEdit() ) ) ); +#ifndef KORG_NOPRINTER + insertItem( KOGlobals::self()->smallIcon("printer1"), i18n("&Print..."), + this, SLOT( print() ) ); +#endif + //------------------------------------------------------------------------ + mEditOnlyItems.append( insertSeparator() ); + mEditOnlyItems.append( + insertItem( KOGlobals::self()->smallIcon("editcut"), i18n("&Cut"), + this, SLOT( popupCut() ) ) ); + mEditOnlyItems.append( + insertItem( KOGlobals::self()->smallIcon("editcopy"), i18n("&Copy"), + this, SLOT( popupCopy() ) ) ); + // paste is always possible + insertItem( KOGlobals::self()->smallIcon("editpaste"), i18n("&Paste"), + this, SLOT( popupPaste() ) ); + mEditOnlyItems.append( + insertItem( KOGlobals::self()->smallIcon("editdelete"), i18n("&Delete"), + this, SLOT( popupDelete() ) ) ); + //------------------------------------------------------------------------ + mEditOnlyItems.append( insertSeparator() ); + mEditOnlyItems.append( + insertItem( KOGlobals::self()->smallIcon("bell"), i18n("&Toggle Reminder"), + this, SLOT( popupAlarm() ) ) ); + //------------------------------------------------------------------------ + mRecurrenceItems.append( insertSeparator() ); + mRecurrenceItems.append( + insertItem( i18n("&Dissociate This Occurrence"), + this, SLOT( dissociateOccurrence() ) ) ); + mRecurrenceItems.append( + insertItem( i18n("&Dissociate Future Occurrences"), + this, SLOT( dissociateFutureOccurrence() ) ) ); + + insertSeparator(); + insertItem( KOGlobals::self()->smallIcon("mail_forward"), i18n( "Send as iCalendar..."), + this, SLOT(forward()) ); +} + +void KOEventPopupMenu::showIncidencePopup( Incidence *incidence, const QDate &qd ) +{ + mCurrentIncidence = incidence; + mCurrentDate = qd; + + if (mCurrentIncidence) { + // Enable/Disabled menu items only valid for editable events. + QValueList<int>::Iterator it; + for( it = mEditOnlyItems.begin(); it != mEditOnlyItems.end(); ++it ) { + setItemEnabled(*it,!mCurrentIncidence->isReadOnly()); + } + for ( it = mRecurrenceItems.begin(); it != mRecurrenceItems.end(); ++it ) { + setItemVisible( *it, mCurrentIncidence->doesRecur() ); + } + popup(QCursor::pos()); + } else { + kdDebug(5850) << "KOEventPopupMenu::showEventPopup(): No event selected" << endl; + } +} + +void KOEventPopupMenu::addAdditionalItem(const QIconSet &icon,const QString &text, + const QObject *receiver, const char *member, + bool editOnly) +{ + if (!mHasAdditionalItems) { + mHasAdditionalItems = true; + insertSeparator(); + } + int id = insertItem(icon,text,receiver,member); + if (editOnly) mEditOnlyItems.append(id); +} + +void KOEventPopupMenu::popupShow() +{ + if (mCurrentIncidence) emit showIncidenceSignal(mCurrentIncidence); +} + +void KOEventPopupMenu::popupEdit() +{ + if (mCurrentIncidence) emit editIncidenceSignal(mCurrentIncidence); +} + +void KOEventPopupMenu::print() +{ +#ifndef KORG_NOPRINTER + KOCoreHelper helper; + CalPrinter printer( this, 0, &helper ); + connect( this, SIGNAL(configChanged()), &printer, SLOT(updateConfig()) ); + + Incidence::List selectedIncidences; + selectedIncidences.append( mCurrentIncidence ); + + printer.print( KOrg::CalPrinterBase::Incidence, + mCurrentDate, mCurrentDate, selectedIncidences ); +#endif +} + +void KOEventPopupMenu::popupDelete() +{ + if (mCurrentIncidence) emit deleteIncidenceSignal(mCurrentIncidence); +} + +void KOEventPopupMenu::popupCut() +{ + if (mCurrentIncidence) emit cutIncidenceSignal(mCurrentIncidence); +} + +void KOEventPopupMenu::popupCopy() +{ + if (mCurrentIncidence) emit copyIncidenceSignal(mCurrentIncidence); +} + +void KOEventPopupMenu::popupPaste() +{ + emit pasteIncidenceSignal(); +} + + +void KOEventPopupMenu::popupAlarm() +{ + if (mCurrentIncidence) emit toggleAlarmSignal( mCurrentIncidence ); +} + +void KOEventPopupMenu::dissociateOccurrence() +{ + if ( mCurrentIncidence ) + emit dissociateOccurrenceSignal( mCurrentIncidence, mCurrentDate ); +} + +void KOEventPopupMenu::dissociateFutureOccurrence() +{ + if ( mCurrentIncidence ) + emit dissociateFutureOccurrenceSignal( mCurrentIncidence, mCurrentDate ); +} + +void KOEventPopupMenu::forward() +{ + KOrg::MainWindow *w = ActionManager::findInstance( KURL() ); + if ( !w || !mCurrentIncidence ) + return; + KActionCollection *ac = w->getActionCollection(); + KAction *action = ac->action( "schedule_forward" ); + action->activate(); +} diff --git a/korganizer/koeventpopupmenu.h b/korganizer/koeventpopupmenu.h new file mode 100644 index 000000000..9d5db17c4 --- /dev/null +++ b/korganizer/koeventpopupmenu.h @@ -0,0 +1,84 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOEVENTPOPUPMENU_H +#define KOEVENTPOPUPMENU_H +// +// Context menu for event views with standard event actions +// + +#include <qpopupmenu.h> +#include <qdatetime.h> + +namespace KCal { +class Incidence; +} +using namespace KCal; + +class KOEventPopupMenu : public QPopupMenu { + Q_OBJECT + public: + KOEventPopupMenu(); + + void addAdditionalItem(const QIconSet &icon,const QString &text, + const QObject *receiver, const char *member, + bool editOnly=false); + + + public slots: + void showIncidencePopup( Incidence *, const QDate & ); + + protected slots: + void popupShow(); + void popupEdit(); + void popupPaste(); + void print(); + void popupDelete(); + void popupCut(); + void popupCopy(); + void popupAlarm(); + void dissociateOccurrence(); + void dissociateFutureOccurrence(); + void forward(); + + signals: + void editIncidenceSignal(Incidence *); + void showIncidenceSignal(Incidence *); + void deleteIncidenceSignal(Incidence *); + void cutIncidenceSignal(Incidence *); + void copyIncidenceSignal(Incidence *); + void pasteIncidenceSignal(); + void toggleAlarmSignal(Incidence *); + void dissociateOccurrenceSignal( Incidence *, const QDate & ); + void dissociateFutureOccurrenceSignal( Incidence *, const QDate & ); + + private: + Incidence *mCurrentIncidence; + QDate mCurrentDate; + + bool mHasAdditionalItems; + QValueList<int> mEditOnlyItems; + QValueList<int> mRecurrenceItems; +}; + +#endif diff --git a/korganizer/koeventview.cpp b/korganizer/koeventview.cpp new file mode 100644 index 000000000..1f3e62a59 --- /dev/null +++ b/korganizer/koeventview.cpp @@ -0,0 +1,169 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2000, 2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qpopupmenu.h> +#include <qcursor.h> + +#include <klocale.h> +#include <kdebug.h> +#include <kiconloader.h> +#include <kmessagebox.h> +#include <kxmlguiclient.h> +#include <kxmlguifactory.h> + +#include <libkcal/calendar.h> + + +#include "kocore.h" +#include "koeventview.h" +#include "koeventpopupmenu.h" + +using namespace KOrg; +#include "koeventview.moc" + +//--------------------------------------------------------------------------- + +KOEventView::KOEventView(Calendar *cal,QWidget *parent,const char *name) + : KOrg::BaseView(cal,parent,name) +{ +} + +//--------------------------------------------------------------------------- + +KOEventView::~KOEventView() +{ +} + +//--------------------------------------------------------------------------- + +KOEventPopupMenu *KOEventView::eventPopup() +{ + KOEventPopupMenu *eventPopup = new KOEventPopupMenu; + + connect(eventPopup,SIGNAL(editIncidenceSignal(Incidence *)), + SIGNAL(editIncidenceSignal(Incidence *))); + connect(eventPopup,SIGNAL(showIncidenceSignal(Incidence *)), + SIGNAL(showIncidenceSignal(Incidence *))); + connect(eventPopup,SIGNAL(deleteIncidenceSignal(Incidence *)), + SIGNAL(deleteIncidenceSignal(Incidence *))); + connect(eventPopup,SIGNAL(cutIncidenceSignal(Incidence *)), + SIGNAL(cutIncidenceSignal(Incidence *))); + connect(eventPopup,SIGNAL(copyIncidenceSignal(Incidence *)), + SIGNAL(copyIncidenceSignal(Incidence *))); + connect(eventPopup,SIGNAL(pasteIncidenceSignal()), + SIGNAL(pasteIncidenceSignal())); + connect(eventPopup,SIGNAL(toggleAlarmSignal(Incidence *)), + SIGNAL(toggleAlarmSignal(Incidence*))); + connect(eventPopup,SIGNAL(dissociateOccurrenceSignal( Incidence *, const QDate & )), + SIGNAL(dissociateOccurrenceSignal( Incidence *, const QDate & ))); + connect(eventPopup,SIGNAL(dissociateFutureOccurrenceSignal( Incidence *, const QDate & )), + SIGNAL(dissociateFutureOccurrenceSignal( Incidence *, const QDate & ))); + + return eventPopup; +} + +QPopupMenu *KOEventView::newEventPopup() +{ + KXMLGUIClient *client = KOCore::self()->xmlguiClient( this ); + if ( !client ) { + kdError() << "KOEventView::newEventPopup(): no xmlGuiClient." << endl; + return 0; + } + if ( !client->factory() ) { + kdError() << "KOEventView::newEventPopup(): no factory" << endl; + return 0; // can happen if called too early + } + + return static_cast<QPopupMenu*> + ( client->factory()->container( "rmb_selection_popup", client ) ); +} +//--------------------------------------------------------------------------- + +void KOEventView::popupShow() +{ + emit showIncidenceSignal(mCurrentIncidence); +} + +//--------------------------------------------------------------------------- + +void KOEventView::popupEdit() +{ + emit editIncidenceSignal(mCurrentIncidence); +} + +//--------------------------------------------------------------------------- + +void KOEventView::popupDelete() +{ + emit deleteIncidenceSignal(mCurrentIncidence); +} + +//--------------------------------------------------------------------------- + +void KOEventView::popupCut() +{ + emit cutIncidenceSignal(mCurrentIncidence); +} + +//--------------------------------------------------------------------------- + +void KOEventView::popupCopy() +{ + emit copyIncidenceSignal(mCurrentIncidence); +} + +//--------------------------------------------------------------------------- + +void KOEventView::showNewEventPopup() +{ + QPopupMenu *popup = newEventPopup(); + if ( !popup ) { + kdError() << "KOEventView::showNewEventPopup(): popup creation failed" + << endl; + return; + } + + popup->popup( QCursor::pos() ); +} + +//--------------------------------------------------------------------------- + +void KOEventView::defaultAction( Incidence *incidence ) +{ + kdDebug(5850) << "KOEventView::defaultAction()" << endl; + + if ( !incidence ) return; + + kdDebug(5850) << " type: " << incidence->type() << endl; + + if ( incidence->isReadOnly() ) + emit showIncidenceSignal(incidence); + else + emit editIncidenceSignal(incidence); +} + +//--------------------------------------------------------------------------- + +#include "baseview.moc" + diff --git a/korganizer/koeventview.h b/korganizer/koeventview.h new file mode 100644 index 000000000..d2073d532 --- /dev/null +++ b/korganizer/koeventview.h @@ -0,0 +1,131 @@ +/* + This file is part of KOrganizer. + Copyright (c) 1999 Preston Brown <pbrown@kde.org> + Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef _KOEVENTVIEW_H +#define _KOEVENTVIEW_H + +#include <libkcal/incidencebase.h> + +#include <korganizer/baseview.h> + + +namespace KCal { +class Incidence; +} +using namespace KCal; + +class KOEventPopupMenu; +class QPopupMenu; + +/** + KOEventView is the abstract base class from which all other + calendar views for event data are derived. It provides methods for + displaying + appointments and events on one or more days. The actual number of + days that a view actually supports is not defined by this abstract class; + that is up to the classes that inherit from it. It also provides + methods for updating the display, retrieving the currently selected + event (or events), and the like. + + @short Abstract class from which all event views are derived. + @author Preston Brown <pbrown@kde.org> + @see KOListView, KOAgendaView, KOMonthView +*/ +class KOEventView : public KOrg::BaseView +{ + Q_OBJECT + + public: + /** + * Constructs a view. + * @param cal is a pointer to the calendar object from which events + * will be retrieved for display. + * @param parent is the parent QWidget. + * @param name is the view name. + */ + KOEventView(Calendar *cal,QWidget *parent=0,const char *name=0); + + /** + * Destructor. Views will do view-specific cleanups here. + */ + virtual ~KOEventView(); + + /** + * provides a hint back to the caller on the maximum number of dates + * that the view supports. A return value of 0 means no maximum. + */ + virtual int maxDatesHint() = 0; + + /** + * Construct a standard context menu for an event. + */ + KOEventPopupMenu *eventPopup(); + + /** + * Construct a standard context that allows to create a new event. + */ + QPopupMenu *newEventPopup(); + + /** This view is an view for displaying events. */ + bool isEventView() { return true; } + + public slots: + + /** + Perform the default action for an incidence, e.g. open the event editor, + when double-clicking an event in the agenda view. + */ + void defaultAction( Incidence * ); + + signals: + /** + * when the view changes the dates that are selected in one way or + * another, this signal is emitted. It should be connected back to + * the KDateNavigator object so that it changes appropriately, + * and any other objects that need to be aware that the list of + * selected dates has changed. + */ + void datesSelected(const DateList); + + //ET CVS MERGE ! + /** + * Emitted when an event is moved using the mouse in an agenda + * view (week / month). + */ + void shiftedEvent(const QDate& olddate, const QDate& newdate); + + + protected slots: + void popupShow(); + void popupEdit(); + void popupDelete(); + void popupCut(); + void popupCopy(); + virtual void showNewEventPopup(); + + protected: + Incidence *mCurrentIncidence; // Incidence selected e.g. for a context menu +}; + +#endif diff --git a/korganizer/koeventviewer.cpp b/korganizer/koeventviewer.cpp new file mode 100644 index 000000000..5567211e5 --- /dev/null +++ b/korganizer/koeventviewer.cpp @@ -0,0 +1,124 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001,2003 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "koeventviewer.h" + +#include "urihandler.h" + +#include <libkcal/incidence.h> +#include <libkcal/incidenceformatter.h> +#include <kdebug.h> +#include <koglobals.h> + +KOEventViewer::KOEventViewer( QWidget *parent, const char *name ) + : QTextBrowser( parent, name ), mDefaultText("") +{ + mIncidence = 0; +} + +KOEventViewer::~KOEventViewer() +{ +} + +void KOEventViewer::readSettings( KConfig * config ) +{ + if ( config ) { +// With each restart of KOrganizer the font site gets halfed. What should this +// be good for? +#if 0 + config->setGroup( QString("EventViewer-%1").arg( name() ) ); + int zoomFactor = config->readNumEntry("ZoomFactor", pointSize() ); + zoomTo( zoomFactor/2 ); + kdDebug(5850) << " KOEventViewer: restoring the pointSize: "<< pointSize() + << ", zoomFactor: " << zoomFactor << endl; +#endif + } +} + +void KOEventViewer::writeSettings( KConfig * config ) +{ + if ( config ) { + kdDebug(5850) << " KOEventViewer: saving the zoomFactor: "<< pointSize() << endl; + config->setGroup( QString("EventViewer-%1").arg( name() ) ); + config->writeEntry("ZoomFactor", pointSize() ); + } +} + +void KOEventViewer::setSource( const QString &n ) +{ + UriHandler::process( n ); +} + +bool KOEventViewer::appendIncidence( Incidence *incidence ) +{ + addText( IncidenceFormatter::extensiveDisplayString( incidence ) ); + return true; +} + +void KOEventViewer::setIncidence( Incidence *incidence ) +{ + clearEvents(); + if( incidence ) { + appendIncidence( incidence ); + mIncidence = incidence; + } else { + clearEvents( true ); + mIncidence = 0; + } +} + +void KOEventViewer::clearEvents( bool now ) +{ + mText = ""; + if ( now ) setText( mDefaultText ); +} + +void KOEventViewer::addText( const QString &text ) +{ + mText.append( text ); + setText( mText ); +} + +void KOEventViewer::setDefaultText( const QString &text ) +{ + mDefaultText = text; +} + +void KOEventViewer::changeIncidenceDisplay( Incidence *incidence, int action ) +{ + if ( mIncidence && ( incidence->uid() == mIncidence->uid() ) ) { + switch (action ) { + case KOGlobals::INCIDENCEEDITED:{ + setIncidence( incidence ); + break; + } + case KOGlobals::INCIDENCEDELETED: { + setIncidence( 0 ); + break; + } + } + } +} + +#include "koeventviewer.moc" diff --git a/korganizer/koeventviewer.h b/korganizer/koeventviewer.h new file mode 100644 index 000000000..31a4160d6 --- /dev/null +++ b/korganizer/koeventviewer.h @@ -0,0 +1,90 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001,2003 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOEVENTVIEWER_H +#define KOEVENTVIEWER_H + +#include <qtextbrowser.h> +#include <kdepimmacros.h> + +#include <kconfig.h> +namespace KCal { +class Incidence; +class Todo; +class Event; +class Journal; +} +using namespace KCal; + +/** + Viewer widget for events. +*/ +class KDE_EXPORT KOEventViewer : public QTextBrowser +{ + Q_OBJECT + public: + KOEventViewer( QWidget *parent = 0, const char *name = 0 ); + virtual ~KOEventViewer(); + + /** + Reimplemented from QTextBrowser to handle links. + */ + void setSource( const QString & ); + + virtual bool appendIncidence( Incidence * ); + + /** + Clear viewer. If \a now is set to true delete view immediately. If set to + false delete it with next call to appendIncidence(). + */ + void clearEvents( bool now = false ); + + /** + Add given text to currently shown content. + */ + + void addText( const QString &text ); + + /** + Set the default text that is showed when + there aren't a incidence to show + */ + void setDefaultText( const QString &text ); + + 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 ); + private: + Incidence *mIncidence; + QTextBrowser *mEventTextView; + QString mDefaultText; + QString mText; +}; + +#endif diff --git a/korganizer/koeventviewerdialog.cpp b/korganizer/koeventviewerdialog.cpp new file mode 100644 index 000000000..f99a9ac13 --- /dev/null +++ b/korganizer/koeventviewerdialog.cpp @@ -0,0 +1,59 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "koeventviewerdialog.h" + +#include "koeventviewer.h" + +#include <klocale.h> + +KOEventViewerDialog::KOEventViewerDialog( QWidget *parent, const char *name, + bool compact ) + : KDialogBase( parent, name, false, i18n("Event Viewer"), Ok, Ok, false, + i18n("Edit") ) +{ + mEventViewer = new KOEventViewer( 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 ); + } + connect( this, SIGNAL(finished()), this, SLOT(delayedDestruct()) ); +} + +KOEventViewerDialog::~KOEventViewerDialog() +{ +} + +void KOEventViewerDialog::addText( const QString &text ) +{ + mEventViewer->addText(text); +} + +#include "koeventviewerdialog.moc" diff --git a/korganizer/koeventviewerdialog.h b/korganizer/koeventviewerdialog.h new file mode 100644 index 000000000..750b29f05 --- /dev/null +++ b/korganizer/koeventviewerdialog.h @@ -0,0 +1,58 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2000, 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOEVENTVIEWERDIALOG_H +#define KOEVENTVIEWERDIALOG_H + +#include <kdialogbase.h> +#include <kdepimmacros.h> +#include "koeventviewer.h" + +namespace KCal { +class Incidence; +} +using namespace KCal; + +class KOEventViewer; + +/** + Viewer dialog for events. +*/ +class KDE_EXPORT KOEventViewerDialog : public KDialogBase +{ + Q_OBJECT + public: + KOEventViewerDialog( QWidget *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 addText( const QString &text ); + + private: + KOEventViewer *mEventViewer; +}; + +#endif diff --git a/korganizer/koglobals.cpp b/korganizer/koglobals.cpp new file mode 100644 index 000000000..21428e85b --- /dev/null +++ b/korganizer/koglobals.cpp @@ -0,0 +1,189 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2002,2003 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qapplication.h> + +#include <kdebug.h> +#include <kglobal.h> +#include <kconfig.h> +#include <kstandarddirs.h> +#include <kglobalsettings.h> +#include <klocale.h> +#include <kstaticdeleter.h> +#include <kiconloader.h> + +#include <kcalendarsystem.h> +#include <kholidays.h> + +#include "alarmclient.h" + +#include "koglobals.h" +#include "koprefs.h" +#include "korganizer_part.h" + +#if 0 // unused +class NopAlarmClient : public AlarmClient +{ + public: + void startDaemon() {} + void stopDaemon() {} +}; +#endif + +KOGlobals *KOGlobals::mSelf = 0; + +static KStaticDeleter<KOGlobals> koGlobalsDeleter; + +KOGlobals *KOGlobals::self() +{ + if ( !mSelf ) { + koGlobalsDeleter.setObject( mSelf, new KOGlobals ); + } + + return mSelf; +} + +KOGlobals::KOGlobals() + : mHolidays(0) +{ + // Needed to distinguish from global KInstance + // in case we are a KPart + mOwnInstance = new KInstance( "korganizer" ); + mOwnInstance->config()->setGroup( "General" ); + mOwnInstance->iconLoader()->addAppDir( "kdepim" ); + KGlobal::iconLoader()->addAppDir( "kdepim" ); + + mAlarmClient = new AlarmClient; +} + +KConfig* KOGlobals::config() const +{ + return mOwnInstance->config(); +} + +KOGlobals::~KOGlobals() +{ + delete mAlarmClient; + delete mOwnInstance; + delete mHolidays; +} + +const KCalendarSystem *KOGlobals::calendarSystem() const +{ + return KGlobal::locale()->calendar(); +} + +AlarmClient *KOGlobals::alarmClient() const +{ + return mAlarmClient; +} + +void KOGlobals::fitDialogToScreen( QWidget *wid, bool force ) +{ + bool resized = false; + + int w = wid->frameSize().width(); + int h = wid->frameSize().height(); + + QRect desk = KGlobalSettings::desktopGeometry( wid ); + if ( w > desk.width() ) { + w = desk.width(); + resized = true; + } + // FIXME: ugly hack. Is the -30 really to circumvent the size of kicker?! + if ( h > desk.height() - 30 ) { + h = desk.height() - 30; + resized = true; + } + + if ( resized || force ) { + wid->resize( w, h ); + wid->move( desk.x(), desk.y()+15 ); + if ( force ) wid->setFixedSize( w, h ); + } +} + +bool KOGlobals::reverseLayout() +{ +#if QT_VERSION >= 0x030000 + return QApplication::reverseLayout(); +#else + return false; +#endif +} + +QPixmap KOGlobals::smallIcon( const QString& name ) +{ + return SmallIcon( name, mOwnInstance ); +} + +QIconSet KOGlobals::smallIconSet( const QString& name, int size ) +{ + return SmallIconSet( name, size, mOwnInstance ); +} + +QStringList KOGlobals::holiday( const QDate &date ) +{ + QStringList hdays; + + if ( !mHolidays ) return hdays; + QValueList<KHoliday> list = mHolidays->getHolidays( date ); + QValueList<KHoliday>::ConstIterator it = list.begin(); + for ( ; it != list.end(); ++it ) { + hdays.append( (*it).text ); + } + return hdays; +} + +bool KOGlobals::isWorkDay( const QDate &date ) +{ + int mask( ~( KOPrefs::instance()->mWorkWeekMask ) ); + + bool nonWorkDay = ( mask & ( 1 << ( date.dayOfWeek() - 1 ) ) ); + if ( KOPrefs::instance()->mExcludeHolidays && mHolidays ) { + QValueList<KHoliday> list = mHolidays->getHolidays( date ); + QValueList<KHoliday>::ConstIterator it = list.begin(); + for ( ; it != list.end(); ++it ) { + nonWorkDay = nonWorkDay + || ( (*it).Category == KHolidays::HOLIDAY ); + } + } + return !nonWorkDay; +} + +int KOGlobals::getWorkWeekMask() +{ + return KOPrefs::instance()->mWorkWeekMask; +} + +void KOGlobals::setHolidays( KHolidays *h ) +{ + delete mHolidays; + mHolidays = h; +} + +KHolidays *KOGlobals::holidays() const +{ + return mHolidays; +} diff --git a/korganizer/koglobals.h b/korganizer/koglobals.h new file mode 100644 index 000000000..d03a5d8ce --- /dev/null +++ b/korganizer/koglobals.h @@ -0,0 +1,89 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KORG_GLOBALS_H +#define KORG_GLOBALS_H + +#include <kdepimmacros.h> + +class QPixmap; +class QIconSet; +class KCalendarSystem; +class AlarmClient; + +class KConfig; +class KInstance; +class KHolidays; + +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 }; + + static void fitDialogToScreen( QWidget *widget, bool force=false ); + KConfig *config() const; + + static bool reverseLayout(); + + const KCalendarSystem *calendarSystem() const; + + AlarmClient *alarmClient() const; + + ~KOGlobals(); + + QPixmap smallIcon( const QString& name ); + QIconSet smallIconSet( const QString& name, int size = 0 ); + + QStringList holiday( const QDate & ); + bool isWorkDay( const QDate & ); + int getWorkWeekMask(); + /** + Set which holidays the user wants to use. + @param h a KHolidays object initialized with the desired locale. + We capture this object, so you must not delete it. + */ + void setHolidays( KHolidays *h ); + + /** return the KHolidays object or 0 if none has been defined + */ + KHolidays *holidays() const; + + protected: + KOGlobals(); + + private: + static KOGlobals *mSelf; + + KInstance *mOwnInstance; + + AlarmClient *mAlarmClient; + + KHolidays *mHolidays; +}; + +#endif diff --git a/korganizer/kogroupware.cpp b/korganizer/kogroupware.cpp new file mode 100644 index 000000000..d788abddd --- /dev/null +++ b/korganizer/kogroupware.cpp @@ -0,0 +1,354 @@ +/* + This file is part of the Groupware/KOrganizer integration. + + Requires the Qt and KDE widget libraries, available at no cost at + http://www.trolltech.com and http://www.kde.org respectively + + Copyright (c) 2002-2004 Klarälvdalens Datakonsult AB + <info@klaralvdalens-datakonsult.se> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#include "kogroupware.h" +#include "freebusymanager.h" +#include "calendarview.h" +#include "mailscheduler.h" +#include "koprefs.h" +#include "koincidenceeditor.h" +#include <libemailfunctions/email.h> +#include <libkcal/attendee.h> +#include <libkcal/journal.h> +#include <libkcal/incidenceformatter.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <kstandarddirs.h> +#include <kdirwatch.h> +#include <qfile.h> +#include <qregexp.h> +#include <qdir.h> +#include <qtimer.h> + +FreeBusyManager *KOGroupware::mFreeBusyManager = 0; + +KOGroupware *KOGroupware::mInstance = 0; + +KOGroupware *KOGroupware::create( CalendarView *view, + KCal::CalendarResources *calendar ) +{ + if( !mInstance ) + mInstance = new KOGroupware( view, calendar ); + return mInstance; +} + +KOGroupware *KOGroupware::instance() +{ + // Doesn't create, that is the task of create() + Q_ASSERT( mInstance ); + return mInstance; +} + + + KOGroupware::KOGroupware( CalendarView* view, KCal::CalendarResources* cal ) + : QObject( 0, "kmgroupware_instance" ), mView( view ), mCalendar( cal ) +{ + // Set up the dir watch of the three incoming dirs + KDirWatch* watcher = KDirWatch::self(); + watcher->addDir( locateLocal( "data", "korganizer/income.accepted/" ) ); + watcher->addDir( locateLocal( "data", "korganizer/income.tentative/" ) ); + watcher->addDir( locateLocal( "data", "korganizer/income.counter/" ) ); + watcher->addDir( locateLocal( "data", "korganizer/income.cancel/" ) ); + watcher->addDir( locateLocal( "data", "korganizer/income.reply/" ) ); + watcher->addDir( locateLocal( "data", "korganizer/income.delegated/" ) ); + connect( watcher, SIGNAL( dirty( const QString& ) ), + this, SLOT( incomingDirChanged( const QString& ) ) ); + // Now set the ball rolling + QTimer::singleShot( 0, this, SLOT(initialCheckForChanges()) ); +} + +void KOGroupware::initialCheckForChanges() +{ + incomingDirChanged( locateLocal( "data", "korganizer/income.accepted/" ) ); + incomingDirChanged( locateLocal( "data", "korganizer/income.tentative/" ) ); + incomingDirChanged( locateLocal( "data", "korganizer/income.counter/" ) ); + incomingDirChanged( locateLocal( "data", "korganizer/income.cancel/" ) ); + incomingDirChanged( locateLocal( "data", "korganizer/income.reply/" ) ); + incomingDirChanged( locateLocal( "data", "korganizer/income.delegated/" ) ); +} + +void KOGroupware::slotViewNewIncidenceChanger( IncidenceChangerBase* changer ) +{ + // Call slot perhapsUploadFB if an incidence was added, changed or removed + connect( changer, SIGNAL( incidenceAdded( Incidence* ) ), + mFreeBusyManager, SLOT( slotPerhapsUploadFB() ) ); + connect( changer, SIGNAL( incidenceChanged( Incidence*, Incidence*, int ) ), + mFreeBusyManager, SLOT( slotPerhapsUploadFB() ) ); + connect( changer, SIGNAL( incidenceChanged( Incidence*, Incidence* ) ), + mFreeBusyManager, SLOT( slotPerhapsUploadFB() ) ) ; + connect( changer, SIGNAL( incidenceDeleted( Incidence * ) ), + mFreeBusyManager, SLOT( slotPerhapsUploadFB() ) ); +} + +FreeBusyManager *KOGroupware::freeBusyManager() +{ + if ( !mFreeBusyManager ) { + mFreeBusyManager = new FreeBusyManager( this, "freebusymanager" ); + mFreeBusyManager->setCalendar( mCalendar ); + connect( mCalendar, SIGNAL( calendarChanged() ), + mFreeBusyManager, SLOT( slotPerhapsUploadFB() ) ); + connect( mView, SIGNAL( newIncidenceChanger( IncidenceChangerBase* ) ), + this, SLOT( slotViewNewIncidenceChanger( IncidenceChangerBase* ) ) ); + slotViewNewIncidenceChanger( mView->incidenceChanger() ); + } + + return mFreeBusyManager; +} + +void KOGroupware::incomingDirChanged( const QString& path ) +{ + const QString incomingDirName = locateLocal( "data","korganizer/" ) + + "income."; + if ( !path.startsWith( incomingDirName ) ) { + kdDebug(5850) << "incomingDirChanged: Wrong dir " << path << endl; + return; + } + QString action = path.mid( incomingDirName.length() ); + while ( action.length() > 0 && action[ action.length()-1 ] == '/' ) + // Strip slashes at the end + action.truncate( action.length()-1 ); + + // Handle accepted invitations + QDir dir( path ); + const QStringList files = dir.entryList( QDir::Files ); + if ( files.isEmpty() ) + // No more files here + return; + + // Read the file and remove it + QFile f( path + "/" + files[0] ); + if (!f.open(IO_ReadOnly)) { + kdError(5850) << "Can't open file '" << files[0] << "'" << endl; + return; + } + QTextStream t(&f); + t.setEncoding( QTextStream::UnicodeUTF8 ); + QString receiver = KPIM::getFirstEmailAddress( t.readLine() ); + QString iCal = t.read(); + + f.remove(); + + ScheduleMessage *message = mFormat.parseScheduleMessage( mCalendar, iCal ); + if ( !message ) { + QString errorMessage; + if (mFormat.exception()) + errorMessage = i18n( "Error message: %1" ).arg( mFormat.exception()->message() ); + kdDebug(5850) << "MailScheduler::retrieveTransactions() Error parsing " + << errorMessage << endl; + KMessageBox::detailedError( mView, + i18n("Error while processing an invitation or update."), + errorMessage ); + return; + } + + KCal::Scheduler::Method method = + static_cast<KCal::Scheduler::Method>( message->method() ); + KCal::ScheduleMessage::Status status = message->status(); + KCal::Incidence* incidence = + dynamic_cast<KCal::Incidence*>( message->event() ); + KCal::MailScheduler scheduler( mCalendar ); + if ( action.startsWith( "accepted" ) || action.startsWith( "tentative" ) + || action.startsWith( "delegated" ) || action.startsWith( "counter" ) ) { + // Find myself and set my status. This can't be done in the scheduler, + // since this does not know the choice I made in the KMail bpf + KCal::Attendee::List attendees = incidence->attendees(); + KCal::Attendee::List::ConstIterator it; + for ( it = attendees.begin(); it != attendees.end(); ++it ) { + if( (*it)->email() == receiver ) { + if ( action.startsWith( "accepted" ) ) + (*it)->setStatus( KCal::Attendee::Accepted ); + else if ( action.startsWith( "tentative" ) ) + (*it)->setStatus( KCal::Attendee::Tentative ); + else if ( KOPrefs::instance()->outlookCompatCounterProposals() && action.startsWith( "counter" ) ) + (*it)->setStatus( KCal::Attendee::Tentative ); + else if ( action.startsWith( "delegated" ) ) + (*it)->setStatus( KCal::Attendee::Delegated ); + break; + } + } + if ( KOPrefs::instance()->outlookCompatCounterProposals() || !action.startsWith( "counter" ) ) + scheduler.acceptTransaction( incidence, method, status ); + } else if ( action.startsWith( "cancel" ) ) + // Delete the old incidence, if one is present + scheduler.acceptTransaction( incidence, KCal::Scheduler::Cancel, status ); + else if ( action.startsWith( "reply" ) ) { + if ( method != Scheduler::Counter ) { + scheduler.acceptTransaction( incidence, method, status ); + } else { + // accept counter proposal + scheduler.acceptCounterProposal( incidence ); + // send update to all attendees + sendICalMessage( mView, Scheduler::Request, incidence ); + } + } else + kdError(5850) << "Unknown incoming action " << action << endl; + + if ( action.startsWith( "counter" ) ) { + mView->editIncidence( incidence, true ); + KOIncidenceEditor *tmp = mView->editorDialog( incidence ); + tmp->selectInvitationCounterProposal( true ); + } + mView->updateView(); +} + +class KOInvitationFormatterHelper : public InvitationFormatterHelper +{ + public: + virtual QString generateLinkURL( const QString &id ) { return "kmail:groupware_request_" + id; } +}; + +/* This function sends mails if necessary, and makes sure the user really + * want to change his calendar. + * + * Return true means accept the changes + * Return false means revert the changes + */ +bool KOGroupware::sendICalMessage( QWidget* parent, + KCal::Scheduler::Method method, + Incidence* incidence, bool isDeleting, + bool statusChanged ) +{ + // If there are no attendees, don't bother + if( incidence->attendees().isEmpty() ) + return true; + + bool isOrganizer = KOPrefs::instance()->thatIsMe( incidence->organizer().email() ); + int rc = 0; + /* + * There are two scenarios: + * o "we" are the organizer, where "we" means any of the identities or mail + * addresses known to Kontact/PIM. If there are attendees, we need to mail + * them all, even if one or more of them are also "us". Otherwise there + * would be no way to invite a resource or our boss, other identities we + * also manage. + * o "we: are not the organizer, which means we changed the completion status + * of a todo, or we changed our attendee status from, say, tentative to + * accepted. In both cases we only mail the organizer. All other changes + * bring us out of sync with the organizer, so we won't mail, if the user + * insists on applying them. + */ + + if ( isOrganizer ) { + /* We are the organizer. If there is more than one attendee, or if there is + * only one, and it's not the same as the organizer, ask the user to send + * mail. */ + if ( incidence->attendees().count() > 1 + || incidence->attendees().first()->email() != incidence->organizer().email() ) { + QString 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(); + QString 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") ); + } else { + return true; + } + } else if( incidence->type() == "Todo" ) { + if( method == Scheduler::Request ) + // This is an update to be sent to the organizer + method = Scheduler::Reply; + + // Ask if the user wants to tell the organizer about the current status + QString txt = i18n( "Do you want to send a status update to the " + "organizer of this task?"); + rc = KMessageBox::questionYesNo( parent, txt, QString::null, i18n("Send Update"), i18n("Do Not Send") ); + } else if( incidence->type() == "Event" ) { + QString 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?" ); + method = Scheduler::Reply; + rc = KMessageBox::questionYesNo( parent, txt, QString::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 ); + } + } else { + kdWarning(5850) << "Groupware messages for Journals are not implemented yet!" << endl; + return true; + } + + if( rc == KMessageBox::Yes ) { + // We will be sending out a message here. Now make sure there is + // some summary + if( incidence->summary().isEmpty() ) + incidence->setSummary( i18n("<No summary given>") ); + + // Send the mail + KCal::MailScheduler scheduler( mCalendar ); + scheduler.performTransaction( incidence, method ); + + return true; + } else if( rc == KMessageBox::No ) + return true; + else + return false; +} + +void KOGroupware::sendCounterProposal(KCal::Calendar *calendar, KCal::Event * oldEvent, KCal::Event * newEvent) const +{ + if ( !oldEvent || !newEvent || *oldEvent == *newEvent || !KOPrefs::instance()->mUseGroupwareCommunication ) + return; + if ( KOPrefs::instance()->outlookCompatCounterProposals() ) { + 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() ) ); + KCal::MailScheduler scheduler( calendar ); + scheduler.performTransaction( tmp, Scheduler::Reply ); + delete tmp; + } else { + KCal::MailScheduler scheduler( calendar ); + scheduler.performTransaction( newEvent, Scheduler::Counter ); + } +} + +#include "kogroupware.moc" diff --git a/korganizer/kogroupware.h b/korganizer/kogroupware.h new file mode 100644 index 000000000..25f62cef4 --- /dev/null +++ b/korganizer/kogroupware.h @@ -0,0 +1,111 @@ +/* + This file is part of the Groupware/KOrganizer integration. + + Requires the Qt and KDE widget libraries, available at no cost at + http://www.trolltech.com and http://www.kde.org respectively + + Copyright (c) 2002-2004 Klarälvdalens Datakonsult AB + <info@klaralvdalens-datakonsult.se> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef KOGROUPWARE_H +#define KOGROUPWARE_H + +#include <libkcal/calendarresources.h> +#include <libkcal/icalformat.h> +#include <libkcal/scheduler.h> +#include <qstring.h> + +#include <kio/job.h> + +using namespace KCal; + +namespace KCal { +class Calendar; +class Event; +} +class CalendarView; +class FreeBusyManager; + +namespace KOrg { +class IncidenceChangerBase; +} + +using namespace KOrg; + +class KOGroupware : public QObject +{ + Q_OBJECT + public: + static KOGroupware* create( CalendarView*, KCal::CalendarResources* ); + static KOGroupware* instance(); + + FreeBusyManager *freeBusyManager(); + + /** Send iCal messages after asking the user + Returns false if the user cancels the dialog, and true if the + user presses Yes og or No. + */ + bool sendICalMessage( QWidget* parent, KCal::Scheduler::Method method, + Incidence* incidence, bool isDeleting = false, + bool statusChanged = false ); + + /** + Send counter proposal message. + @param oldEvent The original event provided in the invitations. + @param newEvent The new event as edited by the user. + */ + 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 + QString msTNEFToVPart( const QByteArray& tnef ); + + private slots: + /** Handle iCals given by KMail. */ + void incomingDirChanged( const QString& path ); + + /** Updates some slot connections when the view incidence changer changes */ + void slotViewNewIncidenceChanger( IncidenceChangerBase* changer ); + + void initialCheckForChanges(); + protected: + KOGroupware( CalendarView*, KCal::CalendarResources* ); + + private: + static KOGroupware *mInstance; + KCal::ICalFormat mFormat; + CalendarView *mView; + KCal::CalendarResources *mCalendar; + static FreeBusyManager *mFreeBusyManager; +}; + +#endif diff --git a/korganizer/kogroupwareprefspage.ui b/korganizer/kogroupwareprefspage.ui new file mode 100644 index 000000000..2efe88af6 --- /dev/null +++ b/korganizer/kogroupwareprefspage.ui @@ -0,0 +1,625 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>KOGroupwarePrefsPage</class> +<widget class="QWidget"> + <property name="name"> + <cstring>KOGroupwarePrefsPage</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>496</width> + <height>548</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QTabWidget"> + <property name="name"> + <cstring>groupwareTab</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>P&ublish</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <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> + </property> + <property name="alignment"> + <set>WordBreak|AlignVCenter</set> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>publishEnable</cstring> + </property> + <property name="text"> + <string>Publish your free/&busy information automatically</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Check this box to upload your Free/Busy information automatically. +It is possible to skip this option and mail or upload your Free/Busy information using the Schedule menu of KOrganizer. +Note: If KOrganizer is acting as a KDE Kolab client, this is not required, as the Kolab2 server taking care of publishing your Free/Busy information and manages the access to it from other users.</string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout8</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>publishDelayLabel</cstring> + </property> + <property name="text"> + <string>Minimum time between uploads (in minutes):</string> + </property> + <property name="buddy" stdset="0"> + <cstring>publishDelaySB</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>Configure minimum the interval of time in minutes between each upload here. This configuration is only effective in case you choose to publish your information automatically.</string> + </property> + </widget> + <widget class="QSpinBox"> + <property name="name"> + <cstring>publishDelay</cstring> + </property> + <property name="minValue"> + <number>1</number> + </property> + <property name="whatsThis" stdset="0"> + <string>Configure minimum the interval of time in minutes between each upload here. This configuration is only effective in case you choose to publish your information automatically.</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout16</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>TextLabel3</cstring> + </property> + <property name="text"> + <string>Publish</string> + </property> + <property name="buddy" stdset="0"> + <cstring>publishDaysSB</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>Configure the number of calendar days you wish to be published and available to others here.</string> + </property> + </widget> + <widget class="QSpinBox"> + <property name="name"> + <cstring>publishDays</cstring> + </property> + <property name="maxValue"> + <number>366</number> + </property> + <property name="minValue"> + <number>1</number> + </property> + <property name="value"> + <number>60</number> + </property> + <property name="whatsThis" stdset="0"> + <string>Configure the number of calendar days you wish to be published and available to others here.</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>TextLabel4</cstring> + </property> + <property name="text"> + <string>days of free/busy information</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Configure the number of calendar days you wish to be published and available to others here.</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>Spacer3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>ButtonGroup2</cstring> + </property> + <property name="title"> + <string>Server Information</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLineEdit" row="3" column="1"> + <property name="name"> + <cstring>publishUrl</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </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> + </property> + </widget> + <widget class="QCheckBox" row="7" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>publishSavePassword</cstring> + </property> + <property name="text"> + <string>Remember p&assword</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Check this box to make KOrganizer remember your password and skip asking you each time it uploads your Free/Busy information, by storing it in the configuration file. +For security reasons, it is not recommended to store your password in the configuration file.</string> + </property> + </widget> + <widget class="QLabel" row="6" column="0"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Password:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>publishPasswordED</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>Enter your groupware server login password here.</string> + </property> + </widget> + <widget class="QLineEdit" row="6" column="1"> + <property name="name"> + <cstring>publishPassword</cstring> + </property> + <property name="echoMode"> + <enum>Password</enum> + </property> + <property name="whatsThis" stdset="0"> + <string>Enter your groupware server login password here.</string> + </property> + </widget> + <widget class="QLineEdit" row="5" column="1"> + <property name="name"> + <cstring>publishUser</cstring> + </property> + <property name="minimumSize"> + <size> + <width>120</width> + <height>0</height> + </size> + </property> + <property name="whatsThis" stdset="0"> + <string>Enter the login information relative to your account on the server here. + +A Kolab2 server specificity: Registered your UID (Unique IDentifier). By default your UID would be your email address on the Kolab2 server but it may also be different. In the last case enter your UID.</string> + </property> + </widget> + <widget class="QLabel" row="5" column="0"> + <property name="name"> + <cstring>TextLabel6</cstring> + </property> + <property name="text"> + <string>Username:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>publishUserNameED</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>Enter the login information relative to your account on the server here. + +A Kolab2 server specificity: Registered your UID (Unique IDentifier). By default your UID would be your email address on the Kolab2 server but it may also be different. In the last case enter your UID.</string> + </property> + </widget> + <widget class="QFrame" row="4" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>frame5</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>TextLabel7</cstring> + </property> + <property name="text"> + <string>Server URL:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>anyServerURLED</cstring> + </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> + </property> + </widget> + </grid> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>50</height> + </size> + </property> + </spacer> + </vbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>&Retrieve</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>TextLabel2</cstring> + </property> + <property name="text"> + <string>By retrieving Free/Busy information that others have published, you can take their calendar into account when inviting them to a meeting.</string> + </property> + <property name="alignment"> + <set>WordBreak|AlignVCenter</set> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>retrieveEnable</cstring> + </property> + <property name="text"> + <string>Retrieve other peoples' free/&busy information automatically</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Check this box to retrieve other peoples' Free/Busy information automatically. Note that you have to fill the correct server information to make this possible.</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>fullDomainRetrieval</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>Use full email &address for retrieval</string> + </property> + <property name="toolTip" stdset="0"> + <string>Set this to retrieve user@domain.ifb instead of user.ifb from the server</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Check this box to download a free/busy file in the format "user@domain.ifb" (for example joe@company.com.ifb). Otherwise, it will download a free/busy file in the format user.ifb (for example joe.ifb). Ask the server Administrator if you are not sure about how to configure this option.</string> + </property> + </widget> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>ButtonGroup2_2</cstring> + </property> + <property name="title"> + <string>Server Information</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout7_2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>TextLabel7_2</cstring> + </property> + <property name="text"> + <string>Server URL:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>anyServerURLED</cstring> + </property> + <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/"</string> + </property> + </widget> + <widget class="QLineEdit"> + <property name="name"> + <cstring>retrieveUrl</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <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/"</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QFrame"> + <property name="name"> + <cstring>frame7</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout13</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLineEdit" row="0" column="1"> + <property name="name"> + <cstring>retrieveUser</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>Enter the login information relative to your account on the server here. + +A Kolab2 server specificity: Registered your UID (Unique IDentifier). By default your UID would be your email address on the Kolab2 server but it may also be different. In the last case enter your UID.</string> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>User&name:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>retrieveUser</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>Enter the login information relative to your account on the server here. + +A Kolab2 server specificity: Registered your UID (Unique IDentifier). By default your UID would be your email address on the Kolab2 server but it may also be different. In the last case enter your UID.</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel4</cstring> + </property> + <property name="text"> + <string>Passwor&d:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>retrievePassword</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>Enter your groupware server login password here.</string> + </property> + </widget> + <widget class="QLineEdit" row="1" column="1"> + <property name="name"> + <cstring>retrievePassword</cstring> + </property> + <property name="echoMode"> + <enum>Password</enum> + </property> + <property name="whatsThis" stdset="0"> + <string>Enter your groupware server login password here.</string> + </property> + </widget> + </grid> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>retrieveSavePassword</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>Re&member password</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Check this box to make KOrganizer remember your password and skip asking you each time it uploads your Free/Busy information, by storing it in the configuration file. +For security reasons, it is not recommended to store your password in the configuration file.</string> + </property> + </widget> + </vbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>160</height> + </size> + </property> + </spacer> + </vbox> + </widget> + </widget> + </vbox> +</widget> +<connections> + <connection> + <sender>publishDays</sender> + <signal>valueChanged(int)</signal> + <receiver>KOGroupwarePrefsPage</receiver> + <slot>slotChanged()</slot> + </connection> + <connection> + <sender>publishUrl</sender> + <signal>textChanged(const QString&)</signal> + <receiver>KOGroupwarePrefsPage</receiver> + <slot>slotChanged()</slot> + </connection> + <connection> + <sender>publishUser</sender> + <signal>textChanged(const QString&)</signal> + <receiver>KOGroupwarePrefsPage</receiver> + <slot>slotChanged()</slot> + </connection> + <connection> + <sender>publishPassword</sender> + <signal>textChanged(const QString&)</signal> + <receiver>KOGroupwarePrefsPage</receiver> + <slot>slotChanged()</slot> + </connection> + <connection> + <sender>publishSavePassword</sender> + <signal>toggled(bool)</signal> + <receiver>KOGroupwarePrefsPage</receiver> + <slot>slotChanged()</slot> + </connection> + <connection> + <sender>retrieveEnable</sender> + <signal>toggled(bool)</signal> + <receiver>KOGroupwarePrefsPage</receiver> + <slot>slotChanged()</slot> + </connection> + <connection> + <sender>retrieveUser</sender> + <signal>textChanged(const QString&)</signal> + <receiver>KOGroupwarePrefsPage</receiver> + <slot>slotChanged()</slot> + </connection> + <connection> + <sender>retrievePassword</sender> + <signal>textChanged(const QString&)</signal> + <receiver>KOGroupwarePrefsPage</receiver> + <slot>slotChanged()</slot> + </connection> + <connection> + <sender>retrieveSavePassword</sender> + <signal>toggled(bool)</signal> + <receiver>KOGroupwarePrefsPage</receiver> + <slot>slotChanged()</slot> + </connection> + <connection> + <sender>retrieveUrl</sender> + <signal>textChanged(const QString&)</signal> + <receiver>KOGroupwarePrefsPage</receiver> + <slot>slotChanged()</slot> + </connection> + <connection> + <sender>publishDelay</sender> + <signal>valueChanged(int)</signal> + <receiver>KOGroupwarePrefsPage</receiver> + <slot>slotChanged()</slot> + </connection> + <connection> + <sender>fullDomainRetrieval</sender> + <signal>toggled(bool)</signal> + <receiver>KOGroupwarePrefsPage</receiver> + <slot>slotChanged()</slot> + </connection> + <connection> + <sender>publishEnable</sender> + <signal>toggled(bool)</signal> + <receiver>KOGroupwarePrefsPage</receiver> + <slot>slotChanged()</slot> + </connection> +</connections> +<tabstops> + <tabstop>groupwareTab</tabstop> + <tabstop>publishEnable</tabstop> + <tabstop>publishDelay</tabstop> + <tabstop>publishDays</tabstop> + <tabstop>publishUrl</tabstop> + <tabstop>publishUser</tabstop> + <tabstop>publishPassword</tabstop> + <tabstop>publishSavePassword</tabstop> + <tabstop>retrieveEnable</tabstop> + <tabstop>fullDomainRetrieval</tabstop> + <tabstop>retrieveUrl</tabstop> + <tabstop>retrieveUser</tabstop> + <tabstop>retrievePassword</tabstop> + <tabstop>retrieveSavePassword</tabstop> +</tabstops> +<includes> + <include location="global" impldecl="in declaration">kdepimmacros.h</include> + <include location="local" impldecl="in implementation">kogroupwareprefspage.ui.h</include> +</includes> +<signals> + <signal>changed()</signal> +</signals> +<slots> + <slot>slotChanged()</slot> +</slots> +<exportmacro>KDE_EXPORT</exportmacro> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/korganizer/kogroupwareprefspage.ui.h b/korganizer/kogroupwareprefspage.ui.h new file mode 100644 index 000000000..aea1618ed --- /dev/null +++ b/korganizer/kogroupwareprefspage.ui.h @@ -0,0 +1,14 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** Qt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ + + +void KOGroupwarePrefsPage::slotChanged() +{ + emit changed(); +} diff --git a/korganizer/kohelper.cpp b/korganizer/kohelper.cpp new file mode 100644 index 000000000..5c0b4ccb5 --- /dev/null +++ b/korganizer/kohelper.cpp @@ -0,0 +1,84 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2005 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qcolor.h> + +#include <kdebug.h> + +#include <libkcal/incidence.h> +#include <libkcal/calendar.h> +#include <libkcal/calendarresources.h> +#include <libkcal/resourcecalendar.h> + +#include "koprefs.h" +#include "kohelper.h" + +QColor KOHelper::resourceColor( KCal::Calendar*calendar, KCal::Incidence*incidence ) +{ + QColor resourceColor = QColor(); //Default invalid color + //FIXME: dynamic_cast are dirty, Better We implements interface to get the color + // from the calendar + KCal::CalendarResources *calendarResource = dynamic_cast<KCal::CalendarResources*>( calendar ); + + if ( calendarResource ) { + KCal::ResourceCalendar *resourceCalendar = calendarResource->resource( incidence ); + + if( resourceCalendar ) { + QString identifier = resourceCalendar->identifier(); + resourceColor = *KOPrefs::instance()->resourceColor( identifier ); + + if ( !resourceCalendar->subresources().isEmpty() ) { + identifier = resourceCalendar->subresourceIdentifier( incidence ); + if ( identifier.isEmpty() ) + identifier = resourceCalendar->identifier(); + QColor subrescolor( *KOPrefs::instance()->resourceColor( identifier ) ); + if ( subrescolor.isValid() ) + resourceColor = subrescolor; + } + } +// } else { +// kdDebug(5850) << "resourceColor: Calendar is not a CalendarResources" <<endl; + } + return resourceColor; +} + +QString KOHelper::resourceLabel(KCal::Calendar * calendar, KCal::Incidence * incidence) +{ + KCal::CalendarResources *calendarResource = dynamic_cast<KCal::CalendarResources*>( calendar ); + if ( !calendarResource || ! incidence ) + return QString(); + + KCal::ResourceCalendar *resourceCalendar = calendarResource->resource( incidence ); + if( resourceCalendar ) { + if ( !resourceCalendar->subresources().isEmpty() ) { + QString subRes = resourceCalendar->subresourceIdentifier( incidence ); + if ( subRes.isEmpty() ) + return resourceCalendar->resourceName(); + return resourceCalendar->labelForSubresource( subRes ); + } + return resourceCalendar->resourceName(); + } + + return QString(); +} diff --git a/korganizer/kohelper.h b/korganizer/kohelper.h new file mode 100644 index 000000000..0f5ec764b --- /dev/null +++ b/korganizer/kohelper.h @@ -0,0 +1,53 @@ +/* + This file is part of KOrganizer. It provides several static methods + that are useful to all views. + + Copyright (c) 2005 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOHELPER_H +#define KOHELPER_H + +#include <kdepimmacros.h> + +namespace KCal { + class Calendar; + class Incidence; +} + +class KDE_EXPORT KOHelper +{ + public: + /** + This method returns the proper resource / subresource color for the + view. + @return The resource color for the incidence. If the incidence belongs + to a subresource, the color for the subresource is returned (if set). + */ + static QColor resourceColor( KCal::Calendar*calendar, KCal::Incidence*incidence ); + + /** + Returns the resource label the given incidence belongs to. + */ + static QString resourceLabel( KCal::Calendar *calendar, KCal::Incidence *incidence ); + +}; + +#endif diff --git a/korganizer/koidentitymanager.cpp b/korganizer/koidentitymanager.cpp new file mode 100644 index 000000000..eb68b939b --- /dev/null +++ b/korganizer/koidentitymanager.cpp @@ -0,0 +1,35 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2004 David Faure <faure@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "koidentitymanager.h" +#include "koprefs.h" + +// This is called to create a default identity in case emailidentities has none +// (i.e. the user never used KMail before) +// We provide the values from KOPrefs, since those are configurable in korganizer. +void KOrg::IdentityManager::createDefaultIdentity( QString& fullName, QString& emailAddress ) +{ + fullName = KOPrefs::instance()->fullName(); + emailAddress = KOPrefs::instance()->email(); +} diff --git a/korganizer/koidentitymanager.h b/korganizer/koidentitymanager.h new file mode 100644 index 000000000..69067d199 --- /dev/null +++ b/korganizer/koidentitymanager.h @@ -0,0 +1,45 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2004 David Faure <faure@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#ifndef KOIDENTITYMANAGER_H +#define KOIDENTITYMANAGER_H + +#include <libkpimidentities/identitymanager.h> + +namespace KOrg { + +class IdentityManager : public KPIM::IdentityManager +{ +public: + IdentityManager( QObject * parent=0, const char * name=0 ) + : KPIM::IdentityManager( true /*readonly*/, parent, name ) {} + +protected: + virtual void createDefaultIdentity( QString& fullName, QString& emailAddress ); +}; + +} // namespace + +#endif /* KOIDENTITYMANAGER_H */ + diff --git a/korganizer/koincidenceeditor.cpp b/korganizer/koincidenceeditor.cpp new file mode 100644 index 000000000..b854ea519 --- /dev/null +++ b/korganizer/koincidenceeditor.cpp @@ -0,0 +1,383 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qtooltip.h> +#include <qframe.h> +#include <qguardedptr.h> +#include <qpixmap.h> +#include <qlayout.h> +#include <qwidgetstack.h> +#include <qdatetime.h> +#include <qwhatsthis.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kstandarddirs.h> +#include <kmessagebox.h> +#include <kinputdialog.h> +#include <kio/netaccess.h> +#include <kabc/addressee.h> + +#include <libkdepim/designerfields.h> +#include <libkdepim/embeddedurlpage.h> + +#include <libkcal/calendarlocal.h> +#include <libkcal/incidence.h> +#include <libkcal/icalformat.h> + +#include "koprefs.h" +#include "koglobals.h" +#include "koeditordetails.h" +#include "koeditoralarms.h" +#include "urihandler.h" +#include "koincidenceeditor.h" +#include "templatemanagementdialog.h" + +KOIncidenceEditor::KOIncidenceEditor( const QString &caption, + Calendar *calendar, QWidget *parent ) + : KDialogBase( Tabbed, caption, Ok | Apply | Cancel | Default, Ok, + parent, 0, false, false ), + mAttendeeEditor( 0 ), mIsCounter( false ) +{ + // Set this to be the group leader for all subdialogs - this means + // modal subdialogs will only affect this dialog, not the other windows + setWFlags( getWFlags() | WGroupLeader ); + + mCalendar = calendar; + + if ( KOPrefs::instance()->mCompactDialogs ) { + showButton( Apply, false ); + showButton( Default, false ); + } else { + setButtonText( Default, i18n("&Templates...") ); + } + + connect( this, SIGNAL( defaultClicked() ), SLOT( slotManageTemplates() ) ); + connect( this, SIGNAL( finished() ), SLOT( delayedDestruct() ) ); +} + +KOIncidenceEditor::~KOIncidenceEditor() +{ +} + +void KOIncidenceEditor::setupAttendeesTab() +{ + QFrame *topFrame = addPage( i18n("Atte&ndees") ); + QWhatsThis::add( topFrame, + i18n("The Attendees tab allows you to Add or Remove " + "Attendees to/from this event or to-do.") ); + + QBoxLayout *topLayout = new QVBoxLayout( topFrame ); + + mAttendeeEditor = mDetails = new KOEditorDetails( spacingHint(), topFrame ); + topLayout->addWidget( mDetails ); +} + +void KOIncidenceEditor::slotApply() +{ + processInput(); +} + +void KOIncidenceEditor::slotOk() +{ + // "this" can be deleted before processInput() returns (processInput() opens + // a non-modal dialog when Kolab is used). So accept should only be executed + // when "this" is still valid + QGuardedPtr<QWidget> ptr( this ); + if ( processInput() && ptr ) accept(); +} + +void KOIncidenceEditor::slotCancel() +{ + processCancel(); + reject(); +} + +void KOIncidenceEditor::cancelRemovedAttendees( Incidence *incidence ) +{ + if ( !incidence ) return; + + // cancelAttendeeEvent removes all attendees from the incidence, + // and then only adds those that need to be cancelled (i.e. a mail needs to be sent to them). + if ( KOPrefs::instance()->thatIsMe( incidence->organizer().email() ) ) { + Incidence *ev = incidence->clone(); + ev->registerObserver( 0 ); + mAttendeeEditor->cancelAttendeeEvent( ev ); + if ( ev->attendeeCount() > 0 ) { + emit deleteAttendee( ev ); + } + delete( ev ); + } + +} + +void KOIncidenceEditor::slotManageTemplates() +{ + kdDebug(5850) << "KOIncidenceEditor::manageTemplates()" << endl; + + TemplateManagementDialog * const d = new TemplateManagementDialog( this, templates() ); + connect( d, SIGNAL( loadTemplate( const QString& ) ), + this, SLOT( slotLoadTemplate( const QString& ) ) ); + connect( d, SIGNAL( templatesChanged( const QStringList& ) ), + this, SLOT( slotTemplatesChanged( const QStringList& ) ) ); + connect( d, SIGNAL( saveTemplate( const QString& ) ), + this, SLOT( slotSaveTemplate( const QString& ) ) ); + d->exec(); + return; +} + +void KOIncidenceEditor::saveAsTemplate( Incidence *incidence, + const QString &templateName ) +{ + if ( !incidence || templateName.isEmpty() ) return; + + QString fileName = "templates/" + incidence->type(); + fileName.append( "/" + templateName ); + fileName = locateLocal( "data", "korganizer/" + fileName ); + + CalendarLocal cal( KOPrefs::instance()->mTimeZoneId ); + cal.addIncidence( incidence ); + ICalFormat format; + format.save( &cal, fileName ); +} + +void KOIncidenceEditor::slotLoadTemplate( const QString& templateName ) +{ + CalendarLocal cal( KOPrefs::instance()->mTimeZoneId ); + QString fileName = locateLocal( "data", "korganizer/templates/" + type() + "/" + + templateName ); + + if ( fileName.isEmpty() ) { + KMessageBox::error( this, i18n("Unable to find template '%1'.") + .arg( fileName ) ); + } else { + ICalFormat format; + if ( !format.load( &cal, fileName ) ) { + KMessageBox::error( this, i18n("Error loading template file '%1'.") + .arg( fileName ) ); + return; + } + } + loadTemplate( cal ); +} + +void KOIncidenceEditor::slotTemplatesChanged( const QStringList& newTemplates ) +{ + templates() = newTemplates; +} + +void KOIncidenceEditor::setupDesignerTabs( const QString &type ) +{ + QStringList activePages = KOPrefs::instance()->activeDesignerFields(); + + QStringList list = KGlobal::dirs()->findAllResources( "data", + "korganizer/designer/" + type + "/*.ui", true, true ); + for ( QStringList::iterator it = list.begin(); it != list.end(); ++it ) { + const QString &fn = (*it).mid( (*it).findRev('/') + 1 ); + if ( activePages.find( fn ) != activePages.end() ) { + addDesignerTab( *it ); + } + } +} + +QWidget *KOIncidenceEditor::addDesignerTab( const QString &uifile ) +{ + kdDebug(5850) << "Designer tab: " << uifile << endl; + + KPIM::DesignerFields *wid = new KPIM::DesignerFields( uifile, 0 ); + mDesignerFields.append( wid ); + + QFrame *topFrame = addPage( wid->title() ); + + QBoxLayout *topLayout = new QVBoxLayout( topFrame ); + + wid->reparent( topFrame, 0, QPoint() ); + topLayout->addWidget( wid ); + mDesignerFieldForWidget[ topFrame ] = wid; + + return topFrame; +} + +class KCalStorage : public KPIM::DesignerFields::Storage +{ + public: + KCalStorage( Incidence *incidence ) + : mIncidence( incidence ) + { + } + + QStringList keys() + { + QStringList keys; + + QMap<QCString, QString> props = mIncidence->customProperties(); + QMap<QCString, QString>::ConstIterator it; + for( it = props.begin(); it != props.end(); ++it ) { + QString customKey = it.key(); + QStringList parts = QStringList::split( "-", customKey ); + if ( parts.count() != 4 ) continue; + if ( parts[ 2 ] != "KORGANIZER" ) continue; + keys.append( parts[ 3 ] ); + } + + return keys; + } + + QString read( const QString &key ) + { + return mIncidence->customProperty( "KORGANIZER", key.utf8() ); + } + + void write( const QString &key, const QString &value ) + { + mIncidence->setCustomProperty( "KORGANIZER", key.utf8(), value ); + } + + private: + Incidence *mIncidence; +}; + +void KOIncidenceEditor::readDesignerFields( Incidence *i ) +{ + KCalStorage storage( i ); + KPIM::DesignerFields *fields; + for( fields = mDesignerFields.first(); fields; + fields = mDesignerFields.next() ) { + fields->load( &storage ); + } +} + +void KOIncidenceEditor::writeDesignerFields( Incidence *i ) +{ + kdDebug(5850) << "KOIncidenceEditor::writeDesignerFields()" << endl; + + KCalStorage storage( i ); + KPIM::DesignerFields *fields; + for( fields = mDesignerFields.first(); fields; + fields = mDesignerFields.next() ) { + kdDebug(5850) << "Write Field " << fields->title() << endl; + fields->save( &storage ); + } +} + + +void KOIncidenceEditor::setupEmbeddedURLPage( const QString &label, + const QString &url, const QString &mimetype ) +{ + kdDebug(5850) << "KOIncidenceEditor::setupEmbeddedURLPage()" << endl; + kdDebug(5850) << "label=" << label << ", url=" << url << ", mimetype=" << mimetype << endl; + QFrame *topFrame = addPage( label ); + QBoxLayout *topLayout = new QVBoxLayout( topFrame ); + + KPIM::EmbeddedURLPage *wid = new KPIM::EmbeddedURLPage( url, mimetype, + topFrame ); + topLayout->addWidget( wid ); + mEmbeddedURLPages.append( topFrame ); + connect( wid, SIGNAL( openURL( const KURL & ) ) , + this, SLOT( openURL( const KURL & ) ) ); + // TODO: Call this method only when the tab is actually activated! + wid->loadContents(); +} + +void KOIncidenceEditor::createEmbeddedURLPages( Incidence *i ) +{ + kdDebug(5850) << "KOIncidenceEditor::createEmbeddedURLPages()" << endl; + + if ( !i ) return; + if ( !mEmbeddedURLPages.isEmpty() ) { + kdDebug(5850) << "mEmbeddedURLPages are not empty, clearing it!" << endl; + mEmbeddedURLPages.setAutoDelete( true ); + mEmbeddedURLPages.clear(); + mEmbeddedURLPages.setAutoDelete( false ); + } + if ( !mAttachedDesignerFields.isEmpty() ) { + for ( QPtrList<QWidget>::Iterator it = mAttachedDesignerFields.begin(); + it != mAttachedDesignerFields.end(); ++it ) { + if ( mDesignerFieldForWidget.contains( *it ) ) { + mDesignerFields.remove( mDesignerFieldForWidget[ *it ] ); + } + } + mAttachedDesignerFields.setAutoDelete( true ); + mAttachedDesignerFields.clear(); + mAttachedDesignerFields.setAutoDelete( false ); + } + + Attachment::List att = i->attachments(); + for ( Attachment::List::Iterator it = att.begin(); it != att.end(); ++it ) { + Attachment *a = (*it); + kdDebug(5850) << "Iterating over the attachments " << endl; + kdDebug(5850) << "label=" << a->label() << ", url=" << a->uri() << ", mimetype=" << a->mimeType() << endl; + if ( a && a->showInline() && a->isUri() ) { + // TODO: Allow more mime-types, but add security checks! +/* if ( a->mimeType() == "application/x-designer" ) { + QString tmpFile; + if ( KIO::NetAccess::download( a->uri(), tmpFile, this ) ) { + mAttachedDesignerFields.append( addDesignerTab( tmpFile ) ); + KIO::NetAccess::removeTempFile( tmpFile ); + } + } else*/ + // TODO: Enable that check again! + if ( a->mimeType() == "text/html" ) + { + setupEmbeddedURLPage( a->label(), a->uri(), a->mimeType() ); + } + } + } +} + +void KOIncidenceEditor::openURL( const KURL &url ) +{ + QString uri = url.url(); + UriHandler::process( uri ); +} + +void KOIncidenceEditor::addAttachments( const QStringList &attachments, + const QStringList &mimeTypes, + bool inlineAttachments ) +{ + emit signalAddAttachments( attachments, mimeTypes, inlineAttachments ); +} + +void KOIncidenceEditor::addAttendees( const QStringList &attendees ) +{ + QStringList::ConstIterator it; + for ( it = attendees.begin(); it != attendees.end(); ++it ) { + QString name, email; + KABC::Addressee::parseEmailAddress( *it, name, email ); + mAttendeeEditor->insertAttendee( new Attendee( name, email ) ); + } +} + +void KOIncidenceEditor::selectInvitationCounterProposal(bool enable) +{ + mIsCounter = enable; + if ( mIsCounter ) { + setCaption( i18n( "Counter proposal" ) ); + setButtonOK( i18n( "Counter proposal" ) ); + enableButtonApply( false ); + } +} + + +#include "koincidenceeditor.moc" diff --git a/korganizer/koincidenceeditor.h b/korganizer/koincidenceeditor.h new file mode 100644 index 000000000..6816c7808 --- /dev/null +++ b/korganizer/koincidenceeditor.h @@ -0,0 +1,161 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001,2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOINCIDENCEEDITOR_H +#define KOINCIDENCEEDITOR_H + +#include <kdialogbase.h> +#include <kurl.h> + +class QDateTime; + +namespace KPIM { +class CategorySelectDialog; +class DesignerFields; +class EmbeddedURLPage; +} + +namespace KOrg { class IncidenceChangerBase; } + +class KOEditorDetails; +class KOAttendeeEditor; + +namespace KCal { +class Calendar; +class CalendarLocal; +class Incidence; +} +using namespace KCal; +using namespace KOrg; + +/** + This is the base class for the calendar component editors. +*/ +class KOIncidenceEditor : public KDialogBase +{ + Q_OBJECT + public: + /** + Construct new IncidenceEditor. + */ + KOIncidenceEditor( const QString &caption, Calendar *calendar, + QWidget *parent ); + virtual ~KOIncidenceEditor(); + + /** This incidence has been modified externally */ + virtual void modified (int /*change*/=0) {} + + virtual void reload() = 0; + + virtual void selectInvitationCounterProposal( bool enable ); + + public slots: + /** Edit an existing todo. */ + virtual void editIncidence(Incidence *, Calendar *) = 0; + virtual void setIncidenceChanger( IncidenceChangerBase *changer ) { + mChanger = changer; } + /** Initialize editor. This function creates the tab widgets. */ + virtual void init() = 0; + /** + Adds attachments to the editor + */ + void addAttachments( const QStringList &attachments, + const QStringList& mimeTypes = QStringList(), + bool inlineAttachment = false ); + /** + Adds attendees to the editor + */ + void addAttendees( const QStringList &attendees ); + + + signals: + void deleteAttendee( Incidence * ); + + void editCategories(); + void updateCategoryConfig(); + void dialogClose( Incidence * ); + void editCanceled( Incidence * ); + + void deleteIncidenceSignal( Incidence * ); + void signalAddAttachments( const QStringList &attachments, + const QStringList& mimeTypes = QStringList(), + bool inlineAttachment = false ); + + + protected slots: + void slotApply(); + void slotOk(); + void slotCancel(); + void openURL( const KURL &url ); + + virtual void slotManageTemplates(); + + virtual void slotSaveTemplate( const QString & ) = 0; + virtual void slotLoadTemplate( const QString& ); + virtual void slotTemplatesChanged( const QStringList& ); + + protected: + virtual QString type() { return QString::null; } + virtual QStringList& templates() const = 0; + virtual void loadTemplate( /*const*/ CalendarLocal& ) = 0; + + void setupAttendeesTab(); + void setupDesignerTabs( const QString &type ); + + void saveAsTemplate( Incidence *, const QString &name ); + + void readDesignerFields( Incidence *i ); + void writeDesignerFields( Incidence *i ); + // Returns the page widget. To remove the tab, just delete that one. + QWidget *addDesignerTab( const QString &uifile ); + + void setupEmbeddedURLPage( const QString &label, const QString &url, + const QString &mimetype ); + void createEmbeddedURLPages( Incidence *i ); + + /** + Process user input and create or update event. Returns false if input is invalid. + */ + virtual bool processInput() { return false; } + + virtual void processCancel() {} + + void cancelRemovedAttendees( Incidence *incidence ); + + Calendar *mCalendar; + + KOEditorDetails *mDetails; + KOAttendeeEditor *mAttendeeEditor; + KOrg::IncidenceChangerBase *mChanger; + + QPtrList<KPIM::DesignerFields> mDesignerFields; + QMap<QWidget*, KPIM::DesignerFields*> mDesignerFieldForWidget; + QPtrList<QWidget> mEmbeddedURLPages; + QPtrList<QWidget> mAttachedDesignerFields; + bool mIsCounter; +}; + +#endif + + diff --git a/korganizer/koincidencetooltip.cpp b/korganizer/koincidencetooltip.cpp new file mode 100644 index 000000000..c7065a28b --- /dev/null +++ b/korganizer/koincidencetooltip.cpp @@ -0,0 +1,60 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2003 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <libkcal/incidence.h> +#include <libkcal/incidenceformatter.h> + +#include "koincidencetooltip.h" +#include "koagendaitem.h" + +/** +@author Reinhold Kainhofer +some improvements by Mikolaj Machowski +*/ + +void KOIncidenceToolTip::add ( QWidget * widget, Incidence *incidence, + QToolTipGroup * group, const QString & longText ) +{ + if ( !widget || !incidence ) return; + QToolTip::add(widget, IncidenceFormatter::toolTipString( incidence ), group, longText); +} + +void KOIncidenceToolTip::add(KOAgendaItem * item, Incidence * incidence, QToolTipGroup * group) +{ + Q_UNUSED( incidence ); + Q_UNUSED( group ); + QToolTip::remove( item ); + new KOIncidenceToolTip( item ); +} + +void KOIncidenceToolTip::maybeTip(const QPoint & pos) +{ + Q_UNUSED( pos ); + KOAgendaItem *item = dynamic_cast<KOAgendaItem*>( parentWidget() ); + if ( !item ) + return; + if ( !mText ) + mText = IncidenceFormatter::toolTipString( item->incidence() ); + tip( QRect( QPoint( 0, 0 ), item->size() ), mText ); +} diff --git a/korganizer/koincidencetooltip.h b/korganizer/koincidencetooltip.h new file mode 100644 index 000000000..5f6e84a81 --- /dev/null +++ b/korganizer/koincidencetooltip.h @@ -0,0 +1,58 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2003 Reinhold Kainhofer <reinhhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOINCIDENCETOOLTIP_H +#define KOINCIDENCETOOLTIP_H + +#include <qtooltip.h> + +namespace KCal +{ +class Incidence; +} +using namespace KCal; + +class KOAgendaItem; + +/** +@author Reinhold Kainhofer +*/ +class KOIncidenceToolTip : public QToolTip +{ + public: + KOIncidenceToolTip(QWidget * widget, QToolTipGroup * group = 0 ):QToolTip (widget, group),mText(0) {} +/* ~KOIncidenceToolTip();*/ + + public: + static void add ( QWidget * widget, Incidence *incidence, + QToolTipGroup * group = 0, const QString & longText = "" ); + static void add( KOAgendaItem *item, Incidence *incidence = 0, + QToolTipGroup *group = 0 ); + + /* reimplmented from QToolTip */ + void maybeTip( const QPoint &pos ); + + private: + QString mText; +}; + +#endif diff --git a/korganizer/kojournaleditor.cpp b/korganizer/kojournaleditor.cpp new file mode 100644 index 000000000..1d2d75410 --- /dev/null +++ b/korganizer/kojournaleditor.cpp @@ -0,0 +1,233 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1997, 1998 Preston Brown <pbrown@kde.org> + Copyright (c) 2000-2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "kojournaleditor.h" + +#include "koeditorgeneraljournal.h" +#include "koeditordetails.h" +#include "kodialogmanager.h" +#include "koprefs.h" + +#include <libkcal/journal.h> +#include <libkcal/calendarlocal.h> +#include <korganizer/baseview.h> + +#include <kmessagebox.h> +#include <klocale.h> +#include <kdebug.h> + +#include <qlayout.h> + +using namespace KCal; + +KOJournalEditor::KOJournalEditor( Calendar *calendar, QWidget *parent ) : + KOIncidenceEditor( i18n("Edit Journal Entry"), calendar, parent ) +{ + mJournal = 0; +} + +KOJournalEditor::~KOJournalEditor() +{ + emit dialogClose( mJournal ); +} + +void KOJournalEditor::init() +{ + setupGeneral(); + setupAttendeesTab(); +} + +void KOJournalEditor::reload() +{ + kdDebug(5851)<<"reloading Journal"<<endl; + if ( mJournal ) readJournal( mJournal ); +} + +void KOJournalEditor::setupGeneral() +{ + mGeneral = new KOEditorGeneralJournal(this); + + if (KOPrefs::instance()->mCompactDialogs) { + QFrame *topFrame = addPage(i18n("General")); + + QBoxLayout *topLayout = new QVBoxLayout( topFrame ); + topLayout->setMargin( marginHint() ); + topLayout->setSpacing( spacingHint() ); + + mGeneral->initTitle( topFrame, topLayout ); + mGeneral->initDate( topFrame, topLayout ); + mGeneral->initDescription( topFrame, topLayout ); + } else { + QFrame *topFrame = addPage(i18n("&General")); + + QBoxLayout *topLayout = new QVBoxLayout(topFrame); + topLayout->setSpacing(spacingHint()); + + mGeneral->initTitle( topFrame, topLayout ); + mGeneral->initDate( topFrame, topLayout ); + mGeneral->initDescription( topFrame, topLayout ); + } + + mGeneral->finishSetup(); +} + +void KOJournalEditor::editIncidence( Incidence *incidence, Calendar * ) +{ + Journal *journal=dynamic_cast<Journal*>(incidence); + if (journal) + { + init(); + + mJournal = journal; + readJournal(mJournal); + } +} + + +void KOJournalEditor::newJournal() +{ + init(); + mJournal = 0; + loadDefaults(); +} + +void KOJournalEditor::setTexts( const QString &summary, const QString &description ) +{ + if ( description.isEmpty() && summary.contains("\n") ) { + mGeneral->setDescription( summary ); + int pos = summary.find( "\n" ); + mGeneral->setSummary( summary.left( pos ) ); + } else { + mGeneral->setSummary( summary ); + mGeneral->setDescription( description ); + } +} + + + +void KOJournalEditor::loadDefaults() +{ + setDate( QDate::currentDate() ); +} + +bool KOJournalEditor::processInput() +{ + if ( !validateInput() ) return false; + + if ( mJournal ) { + Journal *oldJournal = mJournal->clone(); + writeJournal( mJournal ); + mChanger->changeIncidence( oldJournal, mJournal ); + delete oldJournal; + } else { + mJournal = new Journal; + mJournal->setOrganizer( Person( KOPrefs::instance()->fullName(), + KOPrefs::instance()->email() ) ); + + writeJournal( mJournal ); + + if ( !mChanger->addIncidence( mJournal, this ) ) { + KODialogManager::errorSaveIncidence( this, mJournal ); + delete mJournal; + mJournal = 0; + return false; + } + } + + return true; +} + +void KOJournalEditor::deleteJournal() +{ + kdDebug(5850) << "Delete journal" << endl; + + if ( mJournal ) + emit deleteIncidenceSignal( mJournal ); + emit dialogClose( mJournal ); + reject(); +} + +void KOJournalEditor::setDate( const QDate &date ) +{ + mGeneral->setDefaults( date ); + mDetails->setDefaults(); +} + +void KOJournalEditor::readJournal( Journal *journal ) +{ + kdDebug(5851)<<"read Journal"<<endl; + mGeneral->readJournal( journal ); + mDetails->readEvent( journal ); +} + +void KOJournalEditor::writeJournal( Journal *journal ) +{ + mGeneral->writeJournal( journal ); + mDetails->writeEvent( journal ); +} + +bool KOJournalEditor::validateInput() +{ + return mGeneral->validateInput() && mDetails->validateInput(); +} + +int KOJournalEditor::msgItemDelete() +{ + return KMessageBox::warningContinueCancel( this, + i18n("This journal entry will be permanently deleted."), + i18n("KOrganizer Confirmation"), KGuiItem( i18n("Delete"), "editdelete" )); +} + +void KOJournalEditor::modified( int /*modification*/) +{ + // Play dump, just reload the Journal. This dialog has become so complicated that + // there is no point in trying to be smart here... + reload(); +} + +void KOJournalEditor::loadTemplate( /*const*/ CalendarLocal& cal) +{ + Journal::List journals = cal.journals(); + if ( journals.count() == 0 ) { + KMessageBox::error( this, + i18n("Template does not contain a valid journal.") ); + } else { + readJournal( journals.first() ); + } +} + +void KOJournalEditor::slotSaveTemplate( const QString &templateName ) +{ + Journal *journal = new Journal; + writeJournal( journal ); + saveAsTemplate( journal, templateName ); +} + +QStringList& KOJournalEditor::templates() const +{ + return KOPrefs::instance()->mJournalTemplates; +} +#include "kojournaleditor.moc" diff --git a/korganizer/kojournaleditor.h b/korganizer/kojournaleditor.h new file mode 100644 index 000000000..a6dc501d6 --- /dev/null +++ b/korganizer/kojournaleditor.h @@ -0,0 +1,109 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1997, 1998 Preston Brown <pbrown@kde.org> + Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOJOURNALEDITOR_H +#define KOJOURNALEDITOR_H + +#include "koincidenceeditor.h" + +#include <qdatetime.h> + +class QDateTime; +namespace KCal { +class Calendar; +class Journal; +class Incidence; +} +using namespace KCal; + +class KOEditorGeneralJournal; + +/** + This class provides a dialog for editing a Journal. +*/ +class KOJournalEditor : public KOIncidenceEditor +{ + Q_OBJECT + public: + /** + Constructs a new Journal editor. + */ + KOJournalEditor( Calendar *calendar, QWidget *parent ); + virtual ~KOJournalEditor(); + + void init(); + + void reload(); + + /** + Clear editor for new Journal + */ + void newJournal(); + + /** + Sets the given summary and description. If description is empty and the + summary contains multiple lines, the summary will be used as description + and only the first line of summary will be used as the summary. + */ + void setTexts( const QString &summary, const QString &description = QString::null ); + /** Edit an existing Journal. */ + void editIncidence(Incidence *, Calendar *); + + /** Set widgets to default values */ + void setDate( const QDate &date ); + /** Read event object and setup widgets accordingly */ + void readJournal( Journal * ); + /** Write event settings to event object */ + void writeJournal( Journal * ); + + int msgItemDelete(); + /** Check if the input is valid. */ + bool validateInput(); + /** Process user input and create or update event. Returns false if input + * is not valid */ + bool processInput(); + + /** This Journal has been modified externally */ + void modified (int change=0); + + protected slots: + void loadDefaults(); + void deleteJournal(); + + void slotSaveTemplate( const QString & ); + + protected: + QString type() { return "Journal"; } + void setupGeneral(); +// int msgItemDelete(); + + void loadTemplate( /*const*/ CalendarLocal& ); + QStringList& templates() const; + private: + Journal *mJournal; + KOEditorGeneralJournal *mGeneral; +}; + +#endif diff --git a/korganizer/kojournalview.cpp b/korganizer/kojournalview.cpp new file mode 100644 index 000000000..dd064169b --- /dev/null +++ b/korganizer/kojournalview.cpp @@ -0,0 +1,208 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +// +// View of Journal entries + +#include <qlayout.h> +#include <qpopupmenu.h> +#include <qvbox.h> +#include <qlabel.h> +#include <qscrollview.h> + +#include <klocale.h> +#include <kdebug.h> + +#include <libkcal/calendar.h> + +#include "journalentry.h" + +#include "kojournalview.h" +#include "koglobals.h" +using namespace KOrg; + +KOJournalView::KOJournalView(Calendar *calendar, QWidget *parent, + const char *name) + : KOrg::BaseView(calendar, parent, name) +{ + QVBoxLayout*topLayout = new QVBoxLayout( this ); + topLayout->setAutoAdd(true); + mSV = new QScrollView( this, "JournalScrollView" ); + mVBox = new QVBox( mSV->viewport() ); + mSV->setVScrollBarMode( QScrollView::Auto ); + mSV->setHScrollBarMode( QScrollView::AlwaysOff ); + mSV->setResizePolicy( QScrollView::AutoOneFit ); + mSV->addChild( mVBox ); +// mVBox->setSpacing( 10 ); +} + +KOJournalView::~KOJournalView() +{ +} + +void KOJournalView::appendJournal( Journal*journal, const QDate &dt) +{ + JournalDateEntry *entry = 0; + if ( mEntries.contains( dt ) ) { + entry = mEntries[dt]; + } else { + entry = new JournalDateEntry( calendar(), mVBox ); + entry->setDate( dt ); + entry->setIncidenceChanger( mChanger ); + entry->show(); + connect( this, SIGNAL(flushEntries()), entry, SIGNAL(flushEntries()) ); + connect( this, SIGNAL(setIncidenceChangerSignal( IncidenceChangerBase * ) ), + entry, SLOT(setIncidenceChanger( IncidenceChangerBase * ) ) ); + connect( this, SIGNAL( journalEdited( Journal* ) ), + entry, SLOT( journalEdited( Journal* ) ) ); + connect( this, SIGNAL( journalDeleted( Journal* ) ), + entry, SLOT( journalDeleted( Journal* ) ) ); + + connect( entry, SIGNAL( editIncidence( Incidence* ) ), + this, SIGNAL( editIncidenceSignal( Incidence* ) ) ); + connect( entry, SIGNAL( deleteIncidence( Incidence* ) ), + this, SIGNAL( deleteIncidenceSignal( Incidence* ) ) ); + connect( entry, SIGNAL( newJournal( const QDate & ) ), + this, SIGNAL( newJournalSignal( const QDate & ) ) ); + mEntries.insert( dt, entry ); + } + + if ( entry && journal ) { + entry->addJournal( journal ); + } +} + +int KOJournalView::currentDateCount() +{ + return mEntries.size(); +} + +Incidence::List KOJournalView::selectedIncidences() +{ + // We don't have a selection in the journal view. + // FIXME: The currently edited journal is the selected incidence... + Incidence::List eventList; + return eventList; +} + +void KOJournalView::clearEntries() +{ +// kdDebug(5850)<<"KOJournalView::clearEntries()"<<endl; + QMap<QDate, JournalDateEntry*>::Iterator it; + for ( it = mEntries.begin(); it != mEntries.end(); ++it ) { + delete (it.data()); + } + mEntries.clear(); +} +void KOJournalView::updateView() +{ + QMap<QDate, JournalDateEntry*>::Iterator it; + for ( it = mEntries.begin(); it != mEntries.end(); ++it ) { + it.data()->clear(); + Journal::List journals = calendar()->journals( it.key() ); + Journal::List::Iterator it1; + for ( it1 = journals.begin(); it1 != journals.end(); ++it1 ) { + it.data()->addJournal( *it1 ); + } + } +} + +void KOJournalView::flushView() +{ +// kdDebug(5850) << "KOJournalView::flushView(): "<< endl; + emit flushEntries(); +} + +void KOJournalView::showDates(const QDate &start, const QDate &end) +{ +// kdDebug(5850) << "KOJournalView::showDates(): "<<start.toString().latin1()<<" - "<<end.toString().latin1() << endl; + clearEntries(); + if ( end<start ) return; + + Journal::List::ConstIterator it; + Journal::List jnls; + QDate d=start; + for ( QDate d=start; d<=end; d=d.addDays(1) ) { + jnls = calendar()->journals( d ); + for ( it = jnls.begin(); it != jnls.end(); ++it ) { + appendJournal( *it, d ); + } + if ( jnls.count() < 1 ) { + // create an empty dateentry widget + appendJournal( 0, d ); + } + } +} + +void KOJournalView::showIncidences( const Incidence::List &incidences ) +{ +// 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() ); + } + } +} + +CalPrinterBase::PrintType KOJournalView::printType() +{ + return CalPrinterBase::Journallist; +} + +void KOJournalView::changeIncidenceDisplay(Incidence *incidence, int action) +{ +// kdDebug(5850) << "KOJournalView::changeIncidenceDisplay(): "<< endl; + Journal *journal = dynamic_cast<Journal*>(incidence); + if (journal) { + switch(action) { + case KOGlobals::INCIDENCEADDED: + appendJournal( journal, journal->dtStart().date() ); + break; + case KOGlobals::INCIDENCEEDITED: + emit journalEdited( journal ); + break; + case KOGlobals::INCIDENCEDELETED: + emit journalDeleted( journal ); + break; + default: + kdDebug(5850) << "KOListView::changeIncidenceDisplay(): Illegal action " << action << endl; + } + } +} + +void KOJournalView::setIncidenceChanger( IncidenceChangerBase *changer ) +{ + mChanger = changer; + emit setIncidenceChangerSignal( changer ); +} + +void KOJournalView::newJournal() +{ + emit newJournalSignal( QDate::currentDate() ); +} + +#include "kojournalview.moc" diff --git a/korganizer/kojournalview.h b/korganizer/kojournalview.h new file mode 100644 index 000000000..8c147d232 --- /dev/null +++ b/korganizer/kojournalview.h @@ -0,0 +1,84 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOJOURNALVIEW_H +#define KOJOURNALVIEW_H + +#include <korganizer/baseview.h> +#include "journalentry.h" + +class JournalEntry; +class QScrollView; +class QVBox; + +/** + * This class provides a journal view. + + * @short View for Journal components. + * @author Cornelius Schumacher <schumacher@kde.org>, Reinhold Kainhofer <reinhold@kainhofer.com> + * @see KOBaseView + */ +class KOJournalView : public KOrg::BaseView +{ + Q_OBJECT + public: + KOJournalView( Calendar *calendar, QWidget *parent = 0, + const char *name = 0); + ~KOJournalView(); + + virtual int currentDateCount(); + virtual Incidence::List selectedIncidences(); + DateList selectedDates() { return DateList(); } + void appendJournal( Journal*journal, const QDate &dt); + + CalPrinterBase::PrintType printType(); + + public slots: + // Don't update the view when midnight passed, otherwise we'll have data loss (bug 79145) + virtual void dayPassed( const QDate & ) {} + void updateView(); + void flushView(); + + void showDates( const QDate &start, const QDate &end ); + void showIncidences( const Incidence::List &incidenceList ); + + void changeIncidenceDisplay( Incidence *, int ); + void setIncidenceChanger( IncidenceChangerBase *changer ); + void newJournal(); + signals: + void flushEntries(); + void setIncidenceChangerSignal( IncidenceChangerBase * ); + void journalEdited( Journal* ); + void journalDeleted( Journal* ); + + protected: + void clearEntries(); + + private: + QScrollView *mSV; + QVBox *mVBox; + QMap<QDate, JournalDateEntry*> mEntries; +// DateList mSelectedDates; // List of dates to be displayed +}; + +#endif diff --git a/korganizer/kolistview.cpp b/korganizer/kolistview.cpp new file mode 100644 index 000000000..722a26460 --- /dev/null +++ b/korganizer/kolistview.cpp @@ -0,0 +1,461 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1999 Preston Brown <pbrown@kde.org> + Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qlistview.h> +#include <qlayout.h> +#include <qpopupmenu.h> +#include <qcursor.h> + +#include <klocale.h> +#include <kdebug.h> +#include <kiconloader.h> +#include <kglobal.h> + +#include <libkcal/calendar.h> +#include <libkcal/incidenceformatter.h> + +#include "koglobals.h" +#include "koprefs.h" +#include "koincidencetooltip.h" +#include "koeventpopupmenu.h" + +#include "kolistview.h" +#include "kolistview.moc" + + +KOListViewToolTip::KOListViewToolTip( QWidget* parent, + KListView* lv ) + :QToolTip(parent) +{ + eventlist=lv; +} + +void KOListViewToolTip::maybeTip( const QPoint & pos) +{ + QRect r; + QListViewItem *it = eventlist->itemAt(pos); + KOListViewItem *i = static_cast<KOListViewItem*>(it); + + if( i && KOPrefs::instance()->mEnableToolTips ) { + /* Calculate the rectangle. */ + r=eventlist->itemRect( it ); + /* Show the tip */ + QString tipText( IncidenceFormatter::toolTipString( i->data() ) ); + if ( !tipText.isEmpty() ) { + tip(r, tipText); + } + } + +} + +/** + This class provides the initialization of a KOListViewItem for calendar + components using the Incidence::Visitor. +*/ +class KOListView::ListItemVisitor : public IncidenceBase::Visitor +{ + public: + ListItemVisitor( KOListViewItem *item ) : mItem( item ) {} + ~ListItemVisitor() {} + + bool visit( Event * ); + bool visit( Todo * ); + bool visit( Journal * ); + + private: + KOListViewItem *mItem; +}; + +bool KOListView::ListItemVisitor::visit( Event *e ) +{ + mItem->setText(0,e->summary()); + if ( e->isAlarmEnabled() ) { + static const QPixmap alarmPxmp = KOGlobals::self()->smallIcon( "bell" ); + mItem->setPixmap(1,alarmPxmp); + mItem->setSortKey(1,"1"); + } + else + mItem->setSortKey(1,"0"); + + if ( e->doesRecur() ) { + static const QPixmap recurPxmp = KOGlobals::self()->smallIcon( "recur" ); + mItem->setPixmap(2,recurPxmp); + mItem->setSortKey(2,"1"); + } + else + mItem->setSortKey(2,"0"); + + static const QPixmap 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)); + } + mItem->setText( 7,e->categoriesStr()); + + return true; +} + +bool KOListView::ListItemVisitor::visit(Todo *t) +{ + static const QPixmap todoPxmp = KOGlobals::self()->smallIcon( "todo" ); + static const QPixmap todoDonePxmp = KOGlobals::self()->smallIcon( "checkedbox" ); + mItem->setPixmap(0, t->isCompleted() ? todoDonePxmp : todoPxmp ); + mItem->setText(0,t->summary()); + if ( t->isAlarmEnabled() ) { + static const QPixmap alarmPxmp = KOGlobals::self()->smallIcon( "bell" ); + mItem->setPixmap(1,alarmPxmp); + mItem->setSortKey(1, "1"); + } + else + mItem->setSortKey(1, "0"); + + if ( t->doesRecur() ) { + static const QPixmap 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) ); + } + } else { + mItem->setText(3,"---"); + mItem->setText(4,"---"); + } + + 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) ); + } + } else { + mItem->setText(5,"---"); + mItem->setText(6,"---"); + } + mItem->setText(7,t->categoriesStr()); + + + return true; +} + +bool KOListView::ListItemVisitor::visit(Journal *t) +{ + static const QPixmap jrnalPxmp = KOGlobals::self()->smallIcon( "journal" ); + mItem->setPixmap(0,jrnalPxmp); + // 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) ); + + return true; +} + +KOListView::KOListView( Calendar *calendar, QWidget *parent, + const char *name) + : KOEventView(calendar, parent, name) +{ + mActiveItem = 0; + + 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")); + + QBoxLayout *layoutTop = new QVBoxLayout(this); + layoutTop->addWidget(mListView); + + mPopupMenu = eventPopup(); +/* + mPopupMenu->insertSeparator(); + mPopupMenu->insertItem(i18n("Show Dates"), this, + SLOT(showDates())); + mPopupMenu->insertItem(i18n("Hide Dates"), this, + SLOT(hideDates())); +*/ + + QObject::connect( mListView, SIGNAL( doubleClicked( QListViewItem * ) ), + SLOT( defaultItemAction( QListViewItem * ) ) ); + QObject::connect( mListView, SIGNAL( returnPressed( QListViewItem * ) ), + SLOT( defaultItemAction( QListViewItem * ) ) ); + QObject::connect( mListView, SIGNAL( rightButtonClicked ( QListViewItem *, + const QPoint &, + int ) ), + SLOT( popupMenu( QListViewItem *, const QPoint &, int ) ) ); + QObject::connect( mListView, SIGNAL( selectionChanged() ), + SLOT( processSelectionChange() ) ); + +// setMinimumSize(100,100); + mListView->restoreLayout(KOGlobals::self()->config(),"KOListView Layout"); + + new KOListViewToolTip( mListView->viewport(), mListView ); + + mSelectedDates.append( QDate::currentDate() ); +} + +KOListView::~KOListView() +{ + delete mPopupMenu; +} + +int KOListView::maxDatesHint() +{ + return 0; +} + +int KOListView::currentDateCount() +{ + return mSelectedDates.count(); +} + +Incidence::List KOListView::selectedIncidences() +{ + Incidence::List eventList; + + QListViewItem *item = mListView->selectedItem(); + if (item) eventList.append(((KOListViewItem *)item)->data()); + + return eventList; +} + +DateList KOListView::selectedDates() +{ + return mSelectedDates; +} + +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); + } else { + mListView->setColumnWidth(1, oldColWidth1); + mListView->setColumnWidth(3, oldColWidth3); + } + mListView->repaint(); +} + +void KOListView::showDates() +{ + showDates(true); +} + +void KOListView::hideDates() +{ + showDates(false); +} + +void KOListView::updateView() +{ + kdDebug(5850) << "KOListView::updateView() does nothing" << endl; +} + +void KOListView::showDates(const QDate &start, const QDate &end) +{ + clear(); + + QDate date = start; + while( date <= end ) { + addIncidences( calendar()->incidences(date) ); + mSelectedDates.append( date ); + date = date.addDays( 1 ); + } + + emit incidenceSelected( 0 ); +} + +void KOListView::addIncidences( const Incidence::List &incidenceList ) +{ + Incidence::List::ConstIterator it; + for( it = incidenceList.begin(); it != incidenceList.end(); ++it ) { + addIncidence( *it ); + } +} + +void KOListView::addIncidence(Incidence *incidence) +{ + if ( mUidDict.find( incidence->uid() ) ) return; + + mUidDict.insert( incidence->uid(), incidence ); + + KOListViewItem *item = new KOListViewItem( incidence, mListView ); + ListItemVisitor v(item); + if (incidence->accept(v)) return; + else delete item; +} + +void KOListView::showIncidences( const Incidence::List &incidenceList ) +{ + clear(); + + addIncidences( incidenceList ); + + // After new creation of list view no events are selected. + emit incidenceSelected( 0 ); +} + +void KOListView::changeIncidenceDisplay(Incidence *incidence, int action) +{ + KOListViewItem *item; + QDate f = mSelectedDates.first(); + QDate l = mSelectedDates.last(); + + QDate date; + if ( incidence->type() == "Todo" ) + date = static_cast<Todo *>(incidence)->dtDue().date(); + else + date = incidence->dtStart().date(); + + switch(action) { + case KOGlobals::INCIDENCEADDED: { + if ( date >= f && date <= l ) + addIncidence( incidence ); + break; + } + case KOGlobals::INCIDENCEEDITED: { + item = getItemForIncidence(incidence); + if (item) { + delete item; + mUidDict.remove( incidence->uid() ); + } + if ( date >= f && date <= l ) + addIncidence( incidence ); + } + break; + case KOGlobals::INCIDENCEDELETED: { + item = getItemForIncidence(incidence); + if (item) + delete item; + break; + } + default: + kdDebug(5850) << "KOListView::changeIncidenceDisplay(): Illegal action " << action << endl; + } +} + +KOListViewItem *KOListView::getItemForIncidence(Incidence *incidence) +{ + KOListViewItem *item = (KOListViewItem *)mListView->firstChild(); + while (item) { +// kdDebug(5850) << "Item " << item->text(0) << " found" << endl; + if (item->data() == incidence) return item; + item = (KOListViewItem *)item->nextSibling(); + } + return 0; +} + +void KOListView::defaultItemAction(QListViewItem *i) +{ + KOListViewItem *item = static_cast<KOListViewItem *>( i ); + if ( item ) defaultAction( item->data() ); +} + +void KOListView::popupMenu(QListViewItem *item,const QPoint &,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, QDate() ); + } + else { + showNewEventPopup(); + } +} + +void KOListView::readSettings(KConfig *config) +{ + mListView->restoreLayout(config,"KOListView Layout"); +} + +void KOListView::writeSettings(KConfig *config) +{ + mListView->saveLayout(config,"KOListView Layout"); +} + +void KOListView::processSelectionChange() +{ + kdDebug(5850) << "KOListView::processSelectionChange()" << endl; + + KOListViewItem *item = + static_cast<KOListViewItem *>( mListView->selectedItem() ); + + if ( !item ) { + emit incidenceSelected( 0 ); + } else { + emit incidenceSelected( item->data() ); + } +} + +void KOListView::clearSelection() +{ + mListView->selectAll( false ); +} + +void KOListView::clear() +{ + mSelectedDates.clear(); + mListView->clear(); + mUidDict.clear(); +} diff --git a/korganizer/kolistview.h b/korganizer/kolistview.h new file mode 100644 index 000000000..d2586ea4a --- /dev/null +++ b/korganizer/kolistview.h @@ -0,0 +1,118 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1999 Preston Brown <pbrown@kde.org> + Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef _KOLISTVIEW_H +#define _KOLISTVIEW_H + +#include <qdict.h> +#include <qtooltip.h> + +#include <libkcal/incidence.h> + +#include "koeventview.h" +#include "customlistviewitem.h" + +using namespace KCal; + +typedef CustomListViewItem<Incidence *> KOListViewItem; + +class KOListView; + +class KOListViewToolTip : public QToolTip +{ + public: + KOListViewToolTip (QWidget* parent, KListView* lv ); + + protected: + void maybeTip( const QPoint & pos); + + private: + KListView* eventlist; +}; + + +/** + This class provides a multi-column list view of events. It can + display events from one particular day or several days, it doesn't + matter. To use a view that only handles one day at a time, use + KODayListView. + + @short multi-column list view of various events. + @author Preston Brown <pbrown@kde.org> + @see KOBaseView, KODayListView +*/ +class KOListView : public KOEventView +{ + Q_OBJECT + public: + KOListView(Calendar *calendar, QWidget *parent = 0, + const char *name = 0); + ~KOListView(); + + virtual int maxDatesHint(); + virtual int currentDateCount(); + virtual Incidence::List selectedIncidences(); + virtual DateList selectedDates(); + + void showDates(bool show); + + void readSettings(KConfig *config); + void writeSettings(KConfig *config); + + void clear(); + + public slots: + virtual void updateView(); + virtual void showDates( const QDate &start, const QDate &end ); + virtual void showIncidences( const Incidence::List &incidenceList ); + + void clearSelection(); + + void showDates(); + void hideDates(); + + void changeIncidenceDisplay(Incidence *, int); + + void defaultItemAction(QListViewItem *item); + void popupMenu(QListViewItem *item,const QPoint &,int); + + protected slots: + void processSelectionChange(); + + protected: + void addIncidences( const Incidence::List & ); + void addIncidence(Incidence *); + KOListViewItem *getItemForIncidence(Incidence *incidence); + + private: + class ListItemVisitor; + KListView *mListView; + KOEventPopupMenu *mPopupMenu; + KOListViewItem *mActiveItem; + QDict<Incidence> mUidDict; + DateList mSelectedDates; +}; + +#endif diff --git a/korganizer/komailclient.cpp b/korganizer/komailclient.cpp new file mode 100644 index 000000000..c9e021979 --- /dev/null +++ b/korganizer/komailclient.cpp @@ -0,0 +1,301 @@ +/* + This file is part of KOrganizer. + Copyright (c) 1998 Barry D Benowitz + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <unistd.h> +#include <stdio.h> + +#include <klocale.h> +#include <kstandarddirs.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <kurl.h> +#include <kapplication.h> +#include <dcopclient.h> +#include <kprocess.h> + +#include <libkcal/event.h> +#include <libkcal/todo.h> +#include <libkcal/incidenceformatter.h> + +#include "version.h" +#include "koprefs.h" + +#include "komailclient.h" + +KOMailClient::KOMailClient() +{ +} + +KOMailClient::~KOMailClient() +{ +} + +bool KOMailClient::mailAttendees(IncidenceBase *incidence,const QString &attachment) +{ + Attendee::List attendees = incidence->attendees(); + if (attendees.count() == 0) return false; + + const QString from = incidence->organizer().fullName(); + const QString organizerEmail = incidence->organizer().email(); + QStringList toList; + for(uint i=0; i<attendees.count();++i) { + const QString 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; + } + if( toList.count() == 0 ) + // Not really to be called a groupware meeting, eh + return false; + QString to = toList.join( ", " ); + + QString subject; + if(incidence->type()!="FreeBusy") { + Incidence *inc = static_cast<Incidence *>(incidence); + subject = inc->summary(); + } else { + subject = "Free Busy Object"; + } + + QString body = IncidenceFormatter::mailBodyString(incidence); + + bool bcc = KOPrefs::instance()->mBcc; + + return send(from,to,subject,body,bcc,attachment); +} + +bool KOMailClient::mailOrganizer(IncidenceBase *incidence,const QString &attachment, const QString &sub) +{ + QString to = incidence->organizer().fullName(); + + QString from = KOPrefs::instance()->email(); + + QString subject = sub; + if(incidence->type()!="FreeBusy") { + Incidence *inc = static_cast<Incidence *>(incidence); + if ( subject.isEmpty() ) + subject = inc->summary(); + } else { + subject = "Free Busy Message"; + } + + QString body = IncidenceFormatter::mailBodyString(incidence); + + bool bcc = KOPrefs::instance()->mBcc; + + return send(from,to,subject,body,bcc,attachment); +} + +bool KOMailClient::mailTo(IncidenceBase *incidence,const QString &recipients, + const QString &attachment) +{ + QString from = KOPrefs::instance()->email(); + QString subject; + if(incidence->type()!="FreeBusy") { + Incidence *inc = static_cast<Incidence *>(incidence); + subject = inc->summary(); + } else { + subject = "Free Busy Message"; + } + QString body = IncidenceFormatter::mailBodyString(incidence); + bool bcc = KOPrefs::instance()->mBcc; + kdDebug () << "KOMailClient::mailTo " << recipients << endl; + return send(from,recipients,subject,body,bcc,attachment); +} + +bool KOMailClient::send(const QString &from,const QString &to, + const QString &subject,const QString &body,bool bcc, + const QString &attachment) +{ + kdDebug(5850) << "KOMailClient::sendMail():\nFrom: " << from << "\nTo: " << to + << "\nSubject: " << subject << "\nBody: \n" << body + << "\nAttachment:\n" << attachment << endl; + + if (KOPrefs::instance()->mMailClient == KOPrefs::MailClientSendmail) { + bool needHeaders = true; + + QString command = KStandardDirs::findExe(QString::fromLatin1("sendmail"), + QString::fromLatin1("/sbin:/usr/sbin:/usr/lib")); + if (!command.isNull()) command += QString::fromLatin1(" -oi -t"); + else { + command = KStandardDirs::findExe(QString::fromLatin1("mail")); + if (command.isNull()) return false; // give up + + command.append(QString::fromLatin1(" -s ")); + command.append(KProcess::quote(subject)); + + if (bcc) { + command.append(QString::fromLatin1(" -b ")); + command.append(KProcess::quote(from)); + } + + command.append(" "); + command.append(KProcess::quote(to)); + + needHeaders = false; + } + + FILE * fd = popen(command.local8Bit(),"w"); + if (!fd) + { + kdError() << "Unable to open a pipe to " << command << endl; + return false; + } + + QString textComplete; + if (needHeaders) + { + textComplete += QString::fromLatin1("From: ") + from + '\n'; + textComplete += QString::fromLatin1("To: ") + to + '\n'; + if (bcc) textComplete += QString::fromLatin1("Bcc: ") + from + '\n'; + textComplete += QString::fromLatin1("Subject: ") + subject + '\n'; + textComplete += QString::fromLatin1("X-Mailer: KOrganizer") + korgVersion + '\n'; + } + textComplete += '\n'; // end of headers + textComplete += body; + textComplete += '\n'; + textComplete += attachment; + + fwrite(textComplete.local8Bit(),textComplete.length(),1,fd); + + pclose(fd); + } else { + if (!kapp->dcopClient()->isApplicationRegistered("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; + } else { + QString meth; + int idx = attachment.find("METHOD"); + if (idx>=0) { + idx = attachment.find(':',idx)+1; + const int newline = attachment.find('\n',idx); + meth = attachment.mid(idx, newline - idx - 1); + meth = meth.lower().stripWhiteSpace(); + } else { + meth = "publish"; + } + if (!kMailOpenComposer(to,"",bcc ? from : "",subject,body,0,"cal.ics","7bit", + attachment.utf8(),"text","calendar","method",meth, + "attachment","utf-8")) return false; + } + } + return true; +} + +int KOMailClient::kMailOpenComposer(const QString& arg0,const QString& arg1, + const QString& arg2,const QString& arg3,const QString& arg4,int arg5, + const KURL& arg6) +{ + //kdDebug(5850) << "KOMailClient::kMailOpenComposer( " + // << arg0 << " , " << arg1 << arg2 << " , " << arg3 + // << arg4 << " , " << arg5 << " , " << arg6 << " )" << endl; + int result = 0; + + QByteArray data, replyData; + QCString replyType; + QDataStream arg( data, IO_WriteOnly ); + arg << arg0; + arg << arg1; + arg << arg2; + arg << arg3; + arg << arg4; + arg << arg5; + arg << arg6; +#if KDE_IS_VERSION( 3, 2, 90 ) + kapp->updateRemoteUserTimestamp( "kmail" ); +#endif + if (kapp->dcopClient()->call("kmail","KMailIface","openComposer(QString,QString,QString,QString,QString,int,KURL)", data, replyType, replyData ) ) { + if ( replyType == "int" ) { + QDataStream _reply_stream( replyData, IO_ReadOnly ); + _reply_stream >> result; + } else { + kdDebug(5850) << "kMailOpenComposer() call failed." << endl; + } + } else { + kdDebug(5850) << "kMailOpenComposer() call failed." << endl; + } + return result; +} + +int KOMailClient::kMailOpenComposer( const QString& arg0, const QString& arg1, + const QString& arg2, const QString& arg3, + const QString& arg4, int arg5, const QString& arg6, + const QCString& arg7, const QCString& arg8, + const QCString& arg9, const QCString& arg10, + const QCString& arg11, const QString& arg12, + const QCString& arg13, const QCString& arg14 ) +{ + //kdDebug(5850) << "KOMailClient::kMailOpenComposer( " + // << arg0 << " , " << arg1 << arg2 << " , " << arg3 + // << arg4 << " , " << arg5 << " , " << arg6 + // << arg7 << " , " << arg8 << " , " << arg9 + // << arg10<< " , " << arg11<< " , " << arg12 + // << arg13<< " , " << arg14<< " )" << endl; + + int result = 0; + + QByteArray data, replyData; + QCString replyType; + QDataStream arg( data, IO_WriteOnly ); + arg << arg0; + arg << arg1; + arg << arg2; + arg << arg3; + arg << arg4; + arg << arg5; + arg << arg6; + arg << arg7; + arg << arg8; + arg << arg9; + arg << arg10; + arg << arg11; + arg << arg12; + arg << arg13; + arg << arg14; +#if KDE_IS_VERSION( 3, 2, 90 ) + kapp->updateRemoteUserTimestamp("kmail"); +#endif + if ( kapp->dcopClient()->call("kmail","KMailIface", + "openComposer(QString,QString,QString,QString,QString,int,QString,QCString,QCString,QCString,QCString,QCString,QString,QCString,QCString)", data, replyType, replyData ) ) { + if ( replyType == "int" ) { + QDataStream _reply_stream( replyData, IO_ReadOnly ); + _reply_stream >> result; + } else { + kdDebug(5850) << "kMailOpenComposer() call failed." << endl; + } + } else { + kdDebug(5850) << "kMailOpenComposer() call failed." << endl; + } + return result; +} + + diff --git a/korganizer/komailclient.h b/korganizer/komailclient.h new file mode 100644 index 000000000..ad9b756bb --- /dev/null +++ b/korganizer/komailclient.h @@ -0,0 +1,68 @@ +/* + This file is part of KOrganizer. + Copyright (c) 1998 Barry D Benowitz + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOMAILCLIENT_H +#define KOMAILCLIENT_H + +#include <qstring.h> + +class KURL; +namespace KCal { +class IncidenceBase; +} +using namespace KCal; + +class KOMailClient +{ + public: + KOMailClient(); + virtual ~KOMailClient(); + + bool mailAttendees(IncidenceBase *,const QString &attachment=QString::null); + bool mailOrganizer(IncidenceBase *,const QString &attachment=QString::null, const QString &sub = QString::null); + bool mailTo(IncidenceBase *,const QString &recipients,const QString &attachment=QString::null); + + 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 QString &from,const QString &to,const QString &subject, + const QString &body,bool bcc=false, + const QString &attachment=QString::null); + + int kMailOpenComposer(const QString& to, const QString& cc, + const QString& bcc, const QString& subject, + const QString& body, int hidden, + const QString& attachName, const QCString& attachCte, + const QCString& attachData, + const QCString& attachType, + const QCString& attachSubType, + const QCString& attachParamAttr, + const QString& attachParamValue, + const QCString& attachContDisp, + const QCString& attachCharset); + int kMailOpenComposer(const QString& arg0,const QString& arg1, + const QString& arg2,const QString& arg3, + const QString& arg4,int arg5,const KURL& arg6); +}; + +#endif diff --git a/korganizer/komessagebox.cpp b/korganizer/komessagebox.cpp new file mode 100644 index 000000000..d3189ffaa --- /dev/null +++ b/korganizer/komessagebox.cpp @@ -0,0 +1,63 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <kmessagebox.h> +#include <kdialogbase.h> +#include <qpushbutton.h> + +#include "komessagebox.h" + +int KOMessageBox::fourBtnMsgBox( QWidget *parent, QMessageBox::Icon type, + const QString &text, const QString &caption, + const KGuiItem &button1, const KGuiItem &button2, + const KGuiItem &button3, int options) +{ + KDialogBase *dialog= new KDialogBase( parent, "KOMessageBox", true, + caption.isEmpty() ? "" : caption, + KDialogBase::Yes | KDialogBase::No | KDialogBase::Ok | KDialogBase::Cancel, + KDialogBase::Yes, + true/*, button1, button2, button3*/); + dialog->setButtonOK( button3 ); + dialog->setButtonText( KDialogBase::Yes, button1.text() ); + dialog->setButtonText( KDialogBase::No, button2.text() ); + QObject::connect( dialog->actionButton( KDialogBase::Yes ), SIGNAL( clicked() ), dialog, SLOT(slotYes())); + QObject::connect( dialog->actionButton( KDialogBase::No ), SIGNAL( clicked() ), dialog, SLOT(slotNo())); +// QObject::connect( dialog, SIGNAL( noClicked() ), dialog, SLOT(slotNo())); + + + bool checkboxResult = false; + int result = KMessageBox::createKMessageBox(dialog, type, text, QStringList(), + QString::null, &checkboxResult, options); + switch (result) { + case KDialogBase::Yes: result = KMessageBox::Yes; break; + case KDialogBase::No: result = KMessageBox::No; break; + case KDialogBase::Ok: result = KMessageBox::Continue; break; + case KDialogBase::Cancel: result = KMessageBox::Cancel; break; + default: break; + } + + return result; +} + + diff --git a/korganizer/komessagebox.h b/korganizer/komessagebox.h new file mode 100644 index 000000000..be40eeb6e --- /dev/null +++ b/korganizer/komessagebox.h @@ -0,0 +1,43 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOMESSAGEBOX_H +#define KOMESSAGEBOX_H + +#include <kguiitem.h> +#include <kstdguiitem.h> +#include <kmessagebox.h> +#include <qmessagebox.h> +#include <qstring.h> + + +class KOMessageBox +{ + public: + static int fourBtnMsgBox( QWidget *parent, QMessageBox::Icon type, + const QString &text, const QString &caption = QString::null, + const KGuiItem &button1 = KStdGuiItem::yes(), const KGuiItem &button2 = KStdGuiItem::no(), + const KGuiItem &button3 = KStdGuiItem::cont(), + int options = 0 ); +}; + +#endif diff --git a/korganizer/komonthview.cpp b/korganizer/komonthview.cpp new file mode 100644 index 000000000..3c88bb01f --- /dev/null +++ b/korganizer/komonthview.cpp @@ -0,0 +1,1090 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qpopupmenu.h> +#include <qfont.h> +#include <qfontmetrics.h> +#include <qkeycode.h> +#include <qhbox.h> +#include <qvbox.h> +#include <qpushbutton.h> +#include <qtooltip.h> +#include <qpainter.h> +#include <qcursor.h> +#include <qlistbox.h> +#include <qlayout.h> +#include <qlabel.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kglobal.h> +#include <kconfig.h> +#include <kiconloader.h> +#include <kwordwrap.h> + +#include <kcalendarsystem.h> +#include <libkcal/calfilter.h> +#include <libkcal/calendar.h> +#include <libkcal/incidenceformatter.h> +#include <libkcal/calendarresources.h> + +#include "koprefs.h" +#include "koglobals.h" +#include "koincidencetooltip.h" +#include "koeventpopupmenu.h" +#include "kohelper.h" + +#include "komonthview.h" +#include "komonthview.moc" + +//-------------------------------------------------------------------------- + +KOMonthCellToolTip::KOMonthCellToolTip( QWidget *parent, + KNoScrollListBox *lv ) + : QToolTip( parent ) +{ + eventlist = lv; +} + +void KOMonthCellToolTip::maybeTip( const QPoint & pos ) +{ + QRect r; + QListBoxItem *it = eventlist->itemAt( pos ); + MonthViewItem *i = static_cast<MonthViewItem*>( it ); + + if( i && KOPrefs::instance()->mEnableToolTips ) { + /* Calculate the rectangle. */ + r=eventlist->itemRect( it ); + /* Show the tip */ + QString tipText( IncidenceFormatter::toolTipString( i->incidence() ) ); + if ( !tipText.isEmpty() ) { + tip( r, tipText ); + } + } +} + +KNoScrollListBox::KNoScrollListBox( QWidget *parent, const char *name ) + : QListBox( parent, name ), + mSqueezing( false ) +{ + QPalette pal = palette(); + pal.setColor( QColorGroup::Foreground, KOPrefs::instance()->agendaBgColor().dark( 150 ) ); + pal.setColor( QColorGroup::Base, KOPrefs::instance()->agendaBgColor() ); + setPalette( pal ); +} + +void KNoScrollListBox::setBackground( bool primary, bool workDay ) +{ + QColor color; + if ( workDay ) { + color = KOPrefs::instance()->workingHoursColor(); + } else { + color = KOPrefs::instance()->agendaBgColor(); + } + + QPalette pal = palette(); + if ( primary ) { + pal.setColor( QColorGroup::Base, color ); + } else { + pal.setColor( QColorGroup::Base, color.dark( 115 ) ); + } + setPalette( pal ); +} + +void KNoScrollListBox::keyPressEvent( QKeyEvent *e ) +{ + switch( e->key() ) { + case Key_Right: + scrollBy( 4, 0 ); + break; + case Key_Left: + scrollBy( -4, 0 ); + break; + case Key_Up: + if ( !count() ) break; + setCurrentItem( ( currentItem() + count() - 1 ) % count() ); + if ( !itemVisible( currentItem() ) ) { + if ( (unsigned int)currentItem() == ( count() - 1 ) ) { + setTopItem( currentItem() - numItemsVisible() + 1 ); + } else { + setTopItem( topItem() - 1 ); + } + } + break; + case Key_Down: + if ( !count() ) break; + setCurrentItem( ( currentItem() + 1 ) % count() ); + if( !itemVisible( currentItem() ) ) { + if( currentItem() == 0 ) { + setTopItem( 0 ); + } else { + setTopItem( topItem() + 1 ); + } + } + case Key_Shift: + emit shiftDown(); + break; + default: + break; + } +} + +void KNoScrollListBox::keyReleaseEvent( QKeyEvent *e ) +{ + switch( e->key() ) { + case Key_Shift: + emit shiftUp(); + break; + default: + break; + } +} + +void KNoScrollListBox::mousePressEvent( QMouseEvent *e ) +{ + QListBox::mousePressEvent( e ); + + if ( e->button() == RightButton ) { + emit rightClick(); + } +} + +void KNoScrollListBox::contentsMouseDoubleClickEvent ( QMouseEvent * e ) +{ + QListBox::contentsMouseDoubleClickEvent( e ); + QListBoxItem *item = itemAt( e->pos() ); + if ( !item ) { + emit doubleClicked( item ); + } +} + +void KNoScrollListBox::resizeEvent( QResizeEvent *e ) +{ + bool s = count() && ( maxItemWidth() > e->size().width() ); + if ( mSqueezing || s ) + triggerUpdate( false ); + + mSqueezing = s; + QListBox::resizeEvent( e ); +} + +MonthViewItem::MonthViewItem( Incidence *incidence, const QDateTime &qd, + const QString & s ) : QListBoxItem() +{ + setText( s ); + + mIncidence = incidence; + mDateTime = qd; + + mEventPixmap = KOGlobals::self()->smallIcon( "appointment" ); + 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 = QColor(); + mEvent = false; + mTodo = false; + mTodoDone = false; + mRecur = false; + mAlarm = false; + mReply = false; +} + +void MonthViewItem::paint( QPainter *p ) +{ +#if QT_VERSION >= 0x030000 + bool sel = isSelected(); +#else + bool sel = selected(); +#endif + + QColor bgColor = palette().color( QPalette::Normal, + sel ? QColorGroup::Highlight : QColorGroup::Background ); + int offset=0; + if ( KOPrefs::instance()->monthViewUsesResourceColor() && + mResourceColor.isValid() ) { + p->setBackgroundColor( mResourceColor ); + p->eraseRect( 0, 0, listBox()->maxItemWidth(), height( listBox() ) ); + offset=2; + } + if ( KOPrefs::instance()->monthViewUsesCategoryColor() ) { + 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; +// } + if ( mTodo ) { + p->drawPixmap( x, 0, mTodoPixmap ); + x += mTodoPixmap.width() + 2; + } + if ( mTodoDone ) { + p->drawPixmap( x, 0, mTodoDonePixmap ); + x += mTodoPixmap.width() + 2; + } + if ( mRecur ) { + p->drawPixmap( x, 0, mRecurPixmap ); + x += mRecurPixmap.width() + 2; + } + if ( mAlarm ) { + p->drawPixmap( x, 0, mAlarmPixmap ); + x += mAlarmPixmap.width() + 2; + } + if ( mReply ) { + p->drawPixmap(x, 0, mReplyPixmap ); + x += mReplyPixmap.width() + 2; + } + QFontMetrics fm = p->fontMetrics(); + int yPos; + int pmheight = QMAX( mRecurPixmap.height(), + QMAX( mAlarmPixmap.height(), mReplyPixmap.height() ) ); + if( pmheight < fm.height() ) + yPos = fm.ascent() + fm.leading()/2; + else + yPos = pmheight/2 - fm.height()/2 + fm.ascent(); + QColor textColor = getTextColor( bgColor ); + p->setPen( textColor ); + + KWordWrap::drawFadeoutText( p, x, yPos, listBox()->width() - x, text() ); +} + +int MonthViewItem::height( const QListBox *lb ) const +{ + return QMAX( QMAX( mRecurPixmap.height(), mReplyPixmap.height() ), + QMAX( mAlarmPixmap.height(), lb->fontMetrics().lineSpacing()+1) ); +} + +int MonthViewItem::width( const QListBox *lb ) const +{ + int x = 3; + if( mRecur ) { + x += mRecurPixmap.width()+2; + } + if( mAlarm ) { + x += mAlarmPixmap.width()+2; + } + if( mReply ) { + x += mReplyPixmap.width()+2; + } + + return( x + lb->fontMetrics().boundingRect( text() ).width() + 1 ); +} + + +MonthViewCell::MonthViewCell( KOMonthView *parent) + : QWidget( parent ), + mMonthView( parent ), mPrimary( false ), mHoliday( false ) +{ + QVBoxLayout *topLayout = new QVBoxLayout( this ); + + mLabel = new QLabel( this ); + mLabel->setFrameStyle( QFrame::Panel | QFrame::Plain ); + mLabel->setLineWidth( 1 ); + mLabel->setAlignment( AlignCenter ); + + mItemList = new KNoScrollListBox( this ); + mItemList->setMinimumSize( 10, 10 ); + mItemList->setFrameStyle( QFrame::Panel | QFrame::Plain ); + mItemList->setLineWidth( 1 ); + + new KOMonthCellToolTip( mItemList->viewport(), + static_cast<KNoScrollListBox *>( mItemList ) ); + + topLayout->addWidget( mItemList ); + + mLabel->raise(); + + mStandardPalette = palette(); + + enableScrollBars( false ); + + updateConfig(); + + connect( mItemList, SIGNAL( doubleClicked( QListBoxItem *) ), + SLOT( defaultAction( QListBoxItem * ) ) ); + connect( mItemList, SIGNAL( rightButtonPressed( QListBoxItem *, + const QPoint &) ), + SLOT( contextMenu( QListBoxItem * ) ) ); + connect( mItemList, SIGNAL( clicked( QListBoxItem * ) ), + SLOT( select() ) ); +} + +void MonthViewCell::setDate( const QDate &date ) +{ +// kdDebug(5850) << "MonthViewCell::setDate(): " << date.toString() << endl; + + mDate = date; + + setFrameWidth(); + + QString text; + if ( KOGlobals::self()->calendarSystem()->day( date ) == 1 ) { + text = i18n("'Month day' for month view cells", "%1 %2") + .arg( KOGlobals::self()->calendarSystem()->monthName( date, true ) ) + .arg( KOGlobals::self()->calendarSystem()->day(mDate) ); + QFontMetrics fm( mLabel->font() ); + mLabel->resize( mLabelSize + QSize( fm.width( text ), 0 ) ); + } else { + mLabel->resize( mLabelSize ); + text = QString::number( KOGlobals::self()->calendarSystem()->day(mDate) ); + } + mLabel->setText( text ); + + resizeEvent( 0 ); +} + +QDate MonthViewCell::date() const +{ + return mDate; +} + +void MonthViewCell::setFrameWidth() +{ + // show current day with a thicker frame + if ( mDate == QDate::currentDate() ) + mItemList->setLineWidth( 3 ); + else + mItemList->setLineWidth( 1 ); +} + +void MonthViewCell::setPrimary( bool primary ) +{ + mPrimary = primary; + + if ( mPrimary ) { + mLabel->setBackgroundMode( PaletteBase ); + } else { + mLabel->setBackgroundMode( PaletteBackground ); + } + + mItemList->setBackground( mPrimary, KOGlobals::self()->isWorkDay( mDate ) ); +} + +bool MonthViewCell::isPrimary() const +{ + return mPrimary; +} + +void MonthViewCell::setHoliday( bool holiday ) +{ + mHoliday = holiday; + + if ( holiday ) { + setPalette( mHolidayPalette ); + } else { + setPalette( mStandardPalette ); + } +} + +void MonthViewCell::setHolidayString( const QString &holiday ) +{ + mHolidayString = holiday; +} + +void MonthViewCell::updateCell() +{ + setFrameWidth(); + + if ( mDate == QDate::currentDate() ) { + setPalette( mTodayPalette ); + + QPalette pal = mItemList->palette(); + pal.setColor( QColorGroup::Foreground, KOPrefs::instance()->highlightColor() ); + mItemList->setPalette( pal ); + } + else { + if ( mHoliday ) + setPalette( mHolidayPalette ); + else + setPalette( mStandardPalette ); + + QPalette pal = mItemList->palette(); + pal.setColor( QColorGroup::Foreground, KOPrefs::instance()->agendaBgColor().dark( 150 ) ); + mItemList->setPalette( pal ); + } + + mItemList->clear(); + + if ( !mHolidayString.isEmpty() ) { + MonthViewItem *item = new MonthViewItem( 0, QDateTime( mDate ), mHolidayString ); + item->setPalette( mHolidayPalette ); + mItemList->insertItem( item ); + } +} + +class MonthViewCell::CreateItemVisitor : + public IncidenceBase::Visitor +{ + public: + CreateItemVisitor() : mItem(0) { emails = KOPrefs::instance()->allEmails(); } + + bool act( IncidenceBase *incidence, QDate date, QPalette stdPal, int multiDay ) + { + mItem = 0; + mDate = date; + mStandardPalette = stdPal; + mMultiDay = multiDay; + return incidence->accept( *this ); + } + MonthViewItem *item() const { return mItem; } + QStringList emails; + + protected: + bool visit( Event *event ) { + QString text; + QDateTime dt( mDate ); + // take the time 0:00 into account, which is non-inclusive + QDate dtEnd = event->dtEnd().addSecs( event->doesFloat() ? 0 : -1).date(); + int length = event->dtStart().daysTo( dtEnd ); + if ( event->isMultiDay() ) { + if ( mDate == event->dtStart().date() + || ( mMultiDay == 0 && event->recursOn( mDate ) ) ) { + text = "(-- " + event->summary(); + dt = event->dtStart(); + } else if ( !event->doesRecur() && mDate == dtEnd + // last day of a recurring multi-day event? + || ( mMultiDay == length && event->recursOn( mDate.addDays( -length ) ) ) ) { + text = event->summary() + " --)"; + } else if (!(event->dtStart().date().daysTo(mDate) % 7) && length > 7 ) { + text = "-- " + event->summary() + " --"; + } else { + text = "----------------"; + dt = QDateTime( mDate ); + } + } else { + if (event->doesFloat()) + text = event->summary(); + else { + text = KGlobal::locale()->formatTime(event->dtStart().time()); + dt.setTime( event->dtStart().time() ); + text += ' ' + event->summary(); + } + } + + mItem = new MonthViewItem( event, dt, text ); + mItem->setEvent( true ); + if (KOPrefs::instance()->monthViewUsesCategoryColor()) { + QStringList categories = event->categories(); + QString cat = categories.first(); + if (cat.isEmpty()) { + mItem->setPalette(QPalette(KOPrefs::instance()->mEventColor, KOPrefs::instance()->mEventColor)); + } else { + mItem->setPalette(QPalette(*(KOPrefs::instance()->categoryColor(cat)), *(KOPrefs::instance()->categoryColor(cat)))); + } + } else { + mItem->setPalette( mStandardPalette ); + } + + Attendee *me = event->attendeeByMails( emails ); + if ( me != 0 ) { + mItem->setReply( me->status() == Attendee::NeedsAction && me->RSVP() ); + } else + mItem->setReply(false); + return true; + } + bool visit( Todo *todo ) { + QString text; + if ( !KOPrefs::instance()->showAllDayTodo() ) + return false; + QDateTime dt( mDate ); + if ( todo->hasDueDate() && !todo->doesFloat() ) { + text += KGlobal::locale()->formatTime( todo->dtDue().time() ); + text += ' '; + dt.setTime( todo->dtDue().time() ); + } + text += todo->summary(); + + mItem = new MonthViewItem( todo, dt, text ); + if ( todo->doesRecur() ) { + mDate < todo->dtDue().date() ? + mItem->setTodoDone( true ) : mItem->setTodo( true ); + } + else + todo->isCompleted() ? mItem->setTodoDone( true ) : mItem->setTodo( true ); + mItem->setPalette( mStandardPalette ); + return true; + } + protected: + MonthViewItem *mItem; + QDate mDate; + QPalette mStandardPalette; + int mMultiDay; +}; + + +void MonthViewCell::addIncidence( Incidence *incidence, CreateItemVisitor& v, int multiDay ) +{ + if ( v.act( incidence, mDate, mStandardPalette, multiDay ) ) { + MonthViewItem *item = v.item(); + if ( item ) { + item->setAlarm( incidence->isAlarmEnabled() ); + item->setRecur( incidence->recurrenceType() ); + + QColor resourceColor = KOHelper::resourceColor( mCalendar, incidence ); + if ( !resourceColor.isValid() ) + resourceColor = KOPrefs::instance()->mEventColor; + item->setResourceColor( resourceColor ); + + // FIXME: Find the correct position (time-wise) to insert the item. + // Currently, the items are displayed in "random" order instead of + // chronologically sorted. + uint i = 0; + int pos = -1; + QDateTime dt( item->incidenceDateTime() ); + + while ( i < mItemList->count() && pos<0 ) { + QListBoxItem *item = mItemList->item( i ); + MonthViewItem *mvitem = dynamic_cast<MonthViewItem*>( item ); + if ( mvitem && mvitem->incidenceDateTime()>dt ) { + pos = i; + } + ++i; + } + mItemList->insertItem( item, pos ); + } + } +} + +void MonthViewCell::removeIncidence( Incidence *incidence ) +{ + for ( uint i = 0; i < mItemList->count(); ++i ) { + MonthViewItem *item = static_cast<MonthViewItem *>(mItemList->item( i ) ); + if ( item && item->incidence() && + item->incidence()->uid() == incidence->uid() ) { + mItemList->removeItem( i ); + --i; + } + } +} + +void MonthViewCell::updateConfig() +{ + setFont( KOPrefs::instance()->mMonthViewFont ); + + QFontMetrics fm( font() ); + mLabelSize = fm.size( 0, "30" ) + + QSize( mLabel->frameWidth() * 2, mLabel->frameWidth() * 2 ) + + QSize( 2, 2 ); +// mStandardPalette = mOriginalPalette; + QColor bg = mStandardPalette.color( QPalette::Active, QColorGroup::Background ); + int h,s,v; + bg.getHsv( &h, &s, &v ); + if ( date().month() %2 == 0 ) { + if ( v < 128 ) { + bg = bg.light( 125 ); + } else { + bg = bg.dark( 125 ); + } + } + setPaletteBackgroundColor( bg ); +// mStandardPalette.setColor( QColorGroup::Background, bg);*/ + + mHolidayPalette = mStandardPalette; + mHolidayPalette.setColor( QColorGroup::Foreground, + KOPrefs::instance()->holidayColor() ); + mHolidayPalette.setColor( QColorGroup::Text, + KOPrefs::instance()->holidayColor() ); + mTodayPalette = mStandardPalette; + mTodayPalette.setColor( QColorGroup::Foreground, + KOPrefs::instance()->highlightColor() ); + mTodayPalette.setColor( QColorGroup::Text, + KOPrefs::instance()->highlightColor() ); + updateCell(); + + mItemList->setBackground( mPrimary, KOGlobals::self()->isWorkDay( mDate ) ); +} + +void MonthViewCell::enableScrollBars( bool enabled ) +{ + if ( enabled ) { + mItemList->setVScrollBarMode( QScrollView::Auto ); + mItemList->setHScrollBarMode( QScrollView::Auto ); + } else { + mItemList->setVScrollBarMode( QScrollView::AlwaysOff ); + mItemList->setHScrollBarMode( QScrollView::AlwaysOff ); + } +} + +Incidence *MonthViewCell::selectedIncidence() +{ + int index = mItemList->currentItem(); + if ( index < 0 ) return 0; + + MonthViewItem *item = + static_cast<MonthViewItem *>( mItemList->item( index ) ); + + if ( !item ) return 0; + + return item->incidence(); +} + +QDate MonthViewCell::selectedIncidenceDate() +{ + QDate qd; + int index = mItemList->currentItem(); + if ( index < 0 ) return qd; + + MonthViewItem *item = + static_cast<MonthViewItem *>( mItemList->item( index ) ); + + if ( !item ) return qd; + + return item->incidenceDateTime().date(); +} + +void MonthViewCell::select() +{ + // setSelectedCell will deselect currently selected cells + mMonthView->setSelectedCell( this ); + + if( KOPrefs::instance()->enableMonthScroll() ) + enableScrollBars( true ); + + // don't mess up the cell when it represents today + if( mDate != QDate::currentDate() ) { + mItemList->setFrameStyle( QFrame::Sunken | QFrame::Panel ); + mItemList->setLineWidth( 3 ); + } +} + +void MonthViewCell::deselect() +{ + mItemList->clearSelection(); + mItemList->setFrameStyle( QFrame::Plain | QFrame::Panel ); + setFrameWidth(); + + enableScrollBars( false ); +} + +void MonthViewCell::resizeEvent ( QResizeEvent * ) +{ + mLabel->move( width() - mLabel->width(), height() - mLabel->height() ); +} + +void MonthViewCell::defaultAction( QListBoxItem *item ) +{ + select(); + + if ( !item ) { + emit newEventSignal( date() ); + } else { + MonthViewItem *eventItem = static_cast<MonthViewItem *>( item ); + Incidence *incidence = eventItem->incidence(); + if ( incidence ) mMonthView->defaultAction( incidence ); + } +} + +void MonthViewCell::contextMenu( QListBoxItem *item ) +{ + select(); + + if ( item ) { + MonthViewItem *eventItem = static_cast<MonthViewItem *>( item ); + Incidence *incidence = eventItem->incidence(); + if ( incidence ) mMonthView->showEventContextMenu( incidence, date() ); + } + else { + mMonthView->showGeneralContextMenu(); + } +} + + +KOMonthView::KOMonthView( Calendar *calendar, QWidget *parent, const char *name ) + : KOEventView( calendar, parent, name ), + mDaysPerWeek( 7 ), mNumWeeks( 6 ), mNumCells( mDaysPerWeek * mNumWeeks ), + mShortDayLabels( false ), mWidthLongDayLabel( 0 ), mSelectedCell( 0 ) +{ + mCells.setAutoDelete( true ); + + QGridLayout *dayLayout = new QGridLayout( this ); + + QFont bfont = font(); + bfont.setBold( true ); + + QFont mfont = bfont; + mfont.setPointSize( 20 ); + + // month name on top + mLabel = new QLabel( this ); + mLabel->setFont( mfont ); + mLabel->setAlignment( AlignCenter ); + mLabel->setLineWidth( 0 ); + mLabel->setFrameStyle( QFrame::Plain ); + + dayLayout->addMultiCellWidget( mLabel, 0, 0, 0, mDaysPerWeek ); + + // create the day of the week labels (Sun, Mon, etc) and add them to + // the layout. + mDayLabels.resize( mDaysPerWeek ); + int i; + for( i = 0; i < mDaysPerWeek; i++ ) { + QLabel *label = new QLabel( this ); + label->setFont( bfont ); + label->setFrameStyle( QFrame::Panel | QFrame::Raised ); + label->setLineWidth( 1 ); + label->setAlignment( AlignCenter ); + + mDayLabels.insert( i, label ); + + dayLayout->addWidget( label, 1, i ); + dayLayout->addColSpacing( i, 10 ); + dayLayout->setColStretch( i, 1 ); + } + + int row, col; + + mCells.resize( mNumCells ); + 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, SIGNAL( defaultAction( Incidence * ) ), + SLOT( defaultAction( Incidence * ) ) ); + connect( cell, SIGNAL( newEventSignal( const QDate & ) ), + SIGNAL( newEventSignal( const QDate & ) ) ); + } + dayLayout->setRowStretch( row + 2, 1 ); + } + + mEventContextMenu = eventPopup(); + + updateConfig(); + + emit incidenceSelected( 0 ); +} + +KOMonthView::~KOMonthView() +{ + delete mEventContextMenu; +} + +int KOMonthView::maxDatesHint() +{ + return mNumCells; +} + +int KOMonthView::currentDateCount() +{ + return mNumCells; +} + +Incidence::List KOMonthView::selectedIncidences() +{ + Incidence::List selected; + + if ( mSelectedCell ) { + Incidence *incidence = mSelectedCell->selectedIncidence(); + if ( incidence ) selected.append( incidence ); + } + + return selected; +} + +DateList KOMonthView::selectedDates() +{ + DateList selected; + + if ( mSelectedCell ) { + QDate qd = mSelectedCell->selectedIncidenceDate(); + if ( qd.isValid() ) selected.append( qd ); + } + + return selected; +} + +bool KOMonthView::eventDurationHint( QDateTime &startDt, QDateTime &endDt, bool &allDay ) +{ + if ( mSelectedCell ) { + startDt.setDate( mSelectedCell->date() ); + endDt.setDate( mSelectedCell->date() ); + allDay = true; + return true; + } + return false; +} + +void KOMonthView::updateConfig() +{ + mWeekStartDay = KGlobal::locale()->weekStartDay(); + + QFontMetrics fontmetric( mDayLabels[0]->font() ); + mWidthLongDayLabel = 0; + + for ( int i = 0; i < 7; ++i ) { + int width = + fontmetric.width( KOGlobals::self()->calendarSystem()->weekDayName( i + 1 ) ); + if ( width > mWidthLongDayLabel ) mWidthLongDayLabel = width; + } + + updateDayLabels(); + + for ( uint i = 0; i < mCells.count(); ++i ) { + mCells[i]->updateConfig(); + } +} + +void KOMonthView::updateDayLabels() +{ + kdDebug(5850) << "KOMonthView::updateDayLabels()" << endl; + + const KCalendarSystem*calsys=KOGlobals::self()->calendarSystem(); + int currDay; + for ( int i = 0; i < 7; i++ ) { + currDay = i+mWeekStartDay; + if ( currDay > 7 ) currDay -= 7; + mDayLabels[i]->setText( calsys->weekDayName( currDay, mShortDayLabels ) ); + } +} + +void KOMonthView::showDates( const QDate &start, const QDate & ) +{ +// kdDebug(5850) << "KOMonthView::showDates(): " << start.toString() << endl; + + const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem(); + + mDateToCell.clear(); + + // show first day of month on top for readability issues + mStartDate = start.addDays( -start.day() + 1 ); + // correct begin of week + int weekdayCol=( mStartDate.dayOfWeek() + 7 - mWeekStartDay ) % 7; + mStartDate = mStartDate.addDays( -weekdayCol ); + + mLabel->setText( i18n( "monthname year", "%1 %2" ) + .arg( calSys->monthName( start ) ) + .arg( calSys->year( start ) ) ); + if ( !KOPrefs::instance()->fullViewMonth() ) { + mLabel->show(); + } else { + mLabel->hide(); + } + + bool primary = false; + uint i; + for( i = 0; i < mCells.size(); ++i ) { + QDate date = mStartDate.addDays( i ); + if ( calSys->day( date ) == 1 ) { + primary = !primary; + } + + mCells[i]->setDate( date ); + mDateToCell[ date ] = mCells[ i ]; + if( date == start ) + mCells[i]->select(); + + mCells[i]->setPrimary( primary ); + + bool isHoliday = calSys->dayOfWeek( date ) == calSys->weekDayOfPray() + || !KOGlobals::self()->isWorkDay( date ); + mCells[i]->setHoliday( isHoliday ); + + // add holiday, if present + QStringList holidays( KOGlobals::self()->holiday( date ) ); + mCells[i]->setHolidayString( holidays.join( i18n("delimiter for joining holiday names", ", " ) ) ); + } + + updateView(); +} + +void KOMonthView::showIncidences( const Incidence::List & ) +{ + kdDebug(5850) << "KOMonthView::showIncidences( const Incidence::List & ) is not implemented yet." << endl; +} + +class KOMonthView::GetDateVisitor : public IncidenceBase::Visitor +{ + public: + GetDateVisitor() {} + + bool act( IncidenceBase *incidence ) + { + return incidence->accept( *this ); + } + QDateTime startDate() const { return mStartDate; } + QDateTime endDate() const { return mEndDate; } + + protected: + bool visit( Event *event ) { + mStartDate = event->dtStart(); + mEndDate = event->dtEnd(); + return true; + } + bool visit( Todo *todo ) { + if ( todo->hasDueDate() ) { + mStartDate = todo->dtDue(); + mEndDate = todo->dtDue(); + }// else +// return false; + return true; + } + bool visit( Journal *journal ) { + mStartDate = journal->dtStart(); + mEndDate = journal->dtStart(); + return true; + } + protected: + QDateTime mStartDate; + QDateTime mEndDate; +}; + +void KOMonthView::changeIncidenceDisplayAdded( Incidence *incidence, MonthViewCell::CreateItemVisitor& v) +{ + GetDateVisitor gdv; + + if ( !gdv.act( incidence ) ) { + kdDebug(5850) << "Visiting GetDateVisitor failed." << endl; + return; + } + + bool floats = incidence->doesFloat(); + + if ( incidence->doesRecur() ) { + for ( uint i = 0; i < mCells.count(); ++i ) { + if ( incidence->recursOn( mCells[i]->date() ) ) { + + // handle multiday events + int length = gdv.startDate().daysTo( gdv.endDate().addSecs( floats ? 0 : -1 ).date() ); + for ( int j = 0; j <= length && i+j < mCells.count(); ++j ) { + mCells[i+j]->addIncidence( incidence, v, j ); + } + } + } + } else { + // addSecs(-1) is added to handle 0:00 cases (because it's non-inclusive according to rfc) + if ( gdv.endDate().isValid() ) { + QDate endDate = gdv.endDate().addSecs( floats ? 0 : -1).date(); + for ( QDate date = gdv.startDate().date(); + date <= endDate; date = date.addDays( 1 ) ) { + MonthViewCell *mvc = mDateToCell[ date ]; + if ( mvc ) mvc->addIncidence( incidence, v ); + } + } + } +} + +void KOMonthView::changeIncidenceDisplay( Incidence *incidence, int action ) +{ + MonthViewCell::CreateItemVisitor v; + switch ( action ) { + case KOGlobals::INCIDENCEADDED: + changeIncidenceDisplayAdded( incidence, v ); + break; + case KOGlobals::INCIDENCEEDITED: + for( uint i = 0; i < mCells.count(); i++ ) + mCells[i]->removeIncidence( incidence ); + changeIncidenceDisplayAdded( incidence, v ); + break; + case KOGlobals::INCIDENCEDELETED: + for( uint i = 0; i < mCells.count(); i++ ) + mCells[i]->removeIncidence( incidence ); + break; + default: + return; + } +} + +void KOMonthView::updateView() +{ + for( uint i = 0; i < mCells.count(); ++i ) { + mCells[i]->updateCell(); + } + + Incidence::List incidences = calendar()->incidences(); + Incidence::List::ConstIterator it; + + MonthViewCell::CreateItemVisitor v; + for ( it = incidences.begin(); it != incidences.end(); ++it ) + changeIncidenceDisplayAdded( *it, v ); + + processSelectionChange(); +} + +void KOMonthView::resizeEvent( QResizeEvent * ) +{ + // select the appropriate heading string size. E.g. "Wednesday" or "Wed". + // note this only changes the text if the requested size crosses the + // threshold between big enough to support the full name and not big + // enough. + if( mDayLabels[0]->width() < mWidthLongDayLabel ) { + if ( !mShortDayLabels ) { + mShortDayLabels = true; + updateDayLabels(); + } + } else { + if ( mShortDayLabels ) { + mShortDayLabels = false; + updateDayLabels(); + } + } +} + +void KOMonthView::showEventContextMenu( Incidence *incidence, const QDate &qd ) +{ + mEventContextMenu->showIncidencePopup( incidence, qd ); +} + +void KOMonthView::showGeneralContextMenu() +{ + showNewEventPopup(); +} + +void KOMonthView::setSelectedCell( MonthViewCell *cell ) +{ + if ( mSelectedCell && cell != mSelectedCell ) + mSelectedCell->deselect(); + + mSelectedCell = cell; + + if ( !mSelectedCell ) + emit incidenceSelected( 0 ); + else + emit incidenceSelected( mSelectedCell->selectedIncidence() ); +} + +void KOMonthView::processSelectionChange() +{ + Incidence::List incidences = selectedIncidences(); + if (incidences.count() > 0) { + emit incidenceSelected( incidences.first() ); + } else { + emit incidenceSelected( 0 ); + } +} + +void KOMonthView::clearSelection() +{ + if ( mSelectedCell ) { + mSelectedCell->deselect(); + mSelectedCell = 0; + } +} diff --git a/korganizer/komonthview.h b/korganizer/komonthview.h new file mode 100644 index 000000000..44e36b055 --- /dev/null +++ b/korganizer/komonthview.h @@ -0,0 +1,304 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#ifndef _KOMONTHVIEW_H +#define _KOMONTHVIEW_H + +#include <qlistbox.h> +#include <qptrvector.h> +#include <qtooltip.h> +#include "koeventview.h" + +class KNoScrollListBox; + +class KOMonthCellToolTip : public QToolTip +{ + public: + KOMonthCellToolTip (QWidget* parent, KNoScrollListBox* lv ); + + protected: + void maybeTip( const QPoint & pos); + + private: + KNoScrollListBox* eventlist; +}; + + +class KNoScrollListBox: public QListBox +{ + Q_OBJECT + public: + KNoScrollListBox(QWidget *parent=0, const char *name=0); + ~KNoScrollListBox() {} + + void setBackground( bool primary, bool workday ); + + signals: + void shiftDown(); + void shiftUp(); + void rightClick(); + + protected slots: + void keyPressEvent(QKeyEvent *); + void keyReleaseEvent(QKeyEvent *); + void mousePressEvent(QMouseEvent *); + void resizeEvent(QResizeEvent *); + void contentsMouseDoubleClickEvent( QMouseEvent * e ); + + private: + bool mSqueezing; +}; + + +class MonthViewItem: public QListBoxItem +{ + public: + MonthViewItem( Incidence *, const QDateTime &qd, const QString & title ); + + void setEvent(bool on) { mEvent = on; } + void setTodo(bool on) { mTodo = on; } + void setTodoDone(bool on) { mTodoDone = on; } + void setRecur(bool on) { mRecur = on; } + void setAlarm(bool on) { mAlarm = on; } + void setReply(bool on) { mReply = on; } + + void setPalette(const QPalette &p) { mPalette = p; } + QPalette palette() const { return mPalette; } + + Incidence *incidence() const { return mIncidence; } + QDateTime incidenceDateTime() { return mDateTime; } + + void setResourceColor( QColor& color ) { mResourceColor = color; } + QColor &resourceColor() { return mResourceColor; } + protected: + virtual void paint(QPainter *); + virtual int height(const QListBox *) const; + virtual int width(const QListBox *) const; + //Color of the resource + QColor mResourceColor; + private: + bool mEvent; + bool mTodo; + bool mTodoDone; + bool mRecur; + bool mAlarm; + bool mReply; + + QPixmap mEventPixmap; + QPixmap mTodoPixmap; + QPixmap mTodoDonePixmap; + QPixmap mAlarmPixmap; + QPixmap mRecurPixmap; + QPixmap mReplyPixmap; + + QPalette mPalette; + QDateTime mDateTime; + + Incidence *mIncidence; +}; + + +class KOMonthView; + +/** This class represents one day in KOrganizer's month view. + +@see KOMonthView +*/ +class MonthViewCell : public QWidget +{ + Q_OBJECT + public: + class CreateItemVisitor; + MonthViewCell( KOMonthView * ); + + /** Sets the date of the cell */ + void setDate( const QDate & ); + /** @return Date of cell */ + QDate date() const; + + /** + 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 + after the current month. + @param primary If true, the cell will be set as primary. Else it will be + set as non-primary. + */ + void setPrimary( bool primary ); + /** + @return True if this cell is primary, else false. + */ + bool isPrimary() const; + + /** Make this cell show as a holiday */ + void setHoliday( bool ); + /** + Sets the holiday name to this cell. This will not call + setHoliday( true ). + @param name The name of the holiday. + */ + void setHolidayString( const QString &name ); + + void updateCell(); + /** Adds an incidence to the cell. + Sets the right text and icons for this incidence. + @param incidence The incidence to be added. + @param v A visitor which creates a MonthViewItem for the given @p incidence + @param multiDay Specifies which day of a multi-day event is added to the + cell. The first day is 0 (default). + */ + void addIncidence( Incidence *incidence, MonthViewCell::CreateItemVisitor&v, int multiDay = 0 ); + /** Removes an incidence from the cell. + @return True if successful, false if deletion failed + (e.g. when given incidence doesn't exist in the cell. + */ + void removeIncidence( Incidence * ); + + void updateConfig(); + + void enableScrollBars( bool ); + + Incidence *selectedIncidence(); + QDate selectedIncidenceDate(); + + void deselect(); + + void setCalendar( Calendar*cal ) { mCalendar = cal; } + signals: + void defaultAction( Incidence * ); + /** + Notify the view manager that we want to create a new event, so an editor + will pop up. + @param date The date of the event we want create. + */ + void newEventSignal( const QDate &date ); + + public slots: + void select(); + + protected: + void setFrameWidth(); + void resizeEvent( QResizeEvent * ); + + protected slots: + void defaultAction( QListBoxItem * ); + void contextMenu( QListBoxItem * ); + + private: + KOMonthView *mMonthView; + // We need the calendar for paint the ResourceColor + Calendar *mCalendar; + + QDate mDate; + bool mPrimary; + bool mHoliday; + QString mHolidayString; + + QLabel *mLabel; + KNoScrollListBox *mItemList; + + QSize mLabelSize; +// QPalette mOriginalPalette; + QPalette mHolidayPalette; + QPalette mStandardPalette; + QPalette mTodayPalette; +}; + +/** + The class KOMonthView represents the monthly view in KOrganizer. + It holds several instances of the class MonthViewCell. + + @short KOMonthview represents the montly view in KOrganizer. + @see KOBaseView, KODayListView, MonthViewCell +*/ +class KOMonthView: public KOEventView +{ + Q_OBJECT + public: + KOMonthView(Calendar *cal, QWidget *parent = 0, const char *name = 0 ); + ~KOMonthView(); + + /** Returns maximum number of days supported by the komonthview */ + virtual int maxDatesHint(); + + /** Returns number of currently shown dates. */ + virtual int currentDateCount(); + + /** Returns the currently selected events */ + virtual Incidence::List selectedIncidences(); + + /** Returns dates of the currently selected events */ + virtual DateList selectedDates(); + + virtual bool eventDurationHint(QDateTime &startDt, QDateTime &endDt, bool &allDay); + + public slots: + virtual void updateView(); + virtual void updateConfig(); + virtual void showDates(const QDate &start, const QDate &end); + virtual void showIncidences( const Incidence::List &incidenceList ); + + void changeIncidenceDisplay(Incidence *, int); + void changeIncidenceDisplayAdded(Incidence *, MonthViewCell::CreateItemVisitor&); + + void clearSelection(); + + void showEventContextMenu( Incidence *, const QDate & ); + void showGeneralContextMenu(); + + void setSelectedCell( MonthViewCell * ); + + protected slots: + void processSelectionChange(); + + protected: + void resizeEvent(QResizeEvent *); + + void viewChanged(); + void updateDayLabels(); + + private: + class GetDateVisitor; + int mDaysPerWeek; + int mNumWeeks; + int mNumCells; + int mWeekStartDay; + + QPtrVector<MonthViewCell> mCells; + QMap<QDate,MonthViewCell *> mDateToCell; + QPtrVector<QLabel> mDayLabels; + + bool mShortDayLabels; + int mWidthLongDayLabel; + + QDate mStartDate; + QDate mSelectedDate; + + MonthViewCell *mSelectedCell; + + KOEventPopupMenu *mEventContextMenu; + QLabel *mLabel; +}; + +#endif diff --git a/korganizer/konewstuff.cpp b/korganizer/konewstuff.cpp new file mode 100644 index 000000000..331126b38 --- /dev/null +++ b/korganizer/konewstuff.cpp @@ -0,0 +1,74 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <kapplication.h> +#include <kdebug.h> + +#include <libkcal/calendarlocal.h> +#include <libkcal/filestorage.h> + +#include "koprefs.h" +#include "calendarview.h" + +#include "konewstuff.h" + +KONewStuff::KONewStuff( CalendarView *view ) : + KNewStuff( "korganizer/calendar", view ), + mView( view ) +{ +} + +bool KONewStuff::install( const QString &fileName ) +{ + kdDebug(5850) << "KONewStuff::install(): " << fileName << endl; + + CalendarLocal cal( KOPrefs::instance()->mTimeZoneId ); + FileStorage storage( &cal, fileName ); + if ( !storage.load() ) { + KMessageBox::error( mView, i18n("Could not load calendar.") ); + return false; + } + + Event::List events = cal.events(); + + QStringList eventList; + + Event::List::ConstIterator it; + for( it = events.begin(); it != events.end(); ++it ) { + QString text = (*it)->summary(); + eventList.append( text ); + } + + int result = KMessageBox::warningContinueCancelList( mView, + i18n("The downloaded events will be merged into your current calendar."), + eventList ); + + if ( result != KMessageBox::Continue ) return false; + + return mView->openCalendar( fileName, true ); +} + +bool KONewStuff::createUploadFile( const QString &fileName ) +{ + return mView->saveCalendar( fileName ); +} diff --git a/korganizer/konewstuff.h b/korganizer/konewstuff.h new file mode 100644 index 000000000..c9a5333a8 --- /dev/null +++ b/korganizer/konewstuff.h @@ -0,0 +1,43 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KONEWSTUFF_H +#define KONEWSTUFF_H + +#include "knewstuff/knewstuff.h" + +class KOrganizer; +class CalendarView; + +class KONewStuff : public KNewStuff +{ + public: + KONewStuff( CalendarView * ); + + bool install( const QString &fileName ); + bool createUploadFile( const QString &fileName ); + + private: + CalendarView *mView; +}; + +#endif diff --git a/korganizer/koprefs.cpp b/korganizer/koprefs.cpp new file mode 100644 index 000000000..a44aaf6e8 --- /dev/null +++ b/korganizer/koprefs.cpp @@ -0,0 +1,420 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001,2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <time.h> +#include <unistd.h> + +#include <qdir.h> +#include <qstring.h> +#include <qfont.h> +#include <qcolor.h> +#include <qmap.h> +#include <qstringlist.h> + +#include <kglobalsettings.h> +#include <kglobal.h> +#include <kconfig.h> +#include <klocale.h> +#include <kdebug.h> +#include <kemailsettings.h> +#include <kstaticdeleter.h> +#include <kstringhandler.h> + +#include <libkmime/kmime_header_parsing.h> + +#include "koprefs.h" +#include <libkpimidentities/identitymanager.h> +#include <libkpimidentities/identity.h> +#include <libemailfunctions/email.h> +#include <kabc/stdaddressbook.h> +#include <ktimezones.h> +#include "kocore.h" + +KOPrefs *KOPrefs::mInstance = 0; +static KStaticDeleter<KOPrefs> insd; + +QColor getTextColor(const QColor &c) +{ + float luminance = (c.red() * 0.299) + (c.green() * 0.587) + (c.blue() * 0.114); + return (luminance > 128.0) ? QColor( 0, 0 ,0 ) : QColor( 255, 255 ,255 ); +} + + +KOPrefs::KOPrefs() : + KOPrefsBase() +{ + mCategoryColors.setAutoDelete( true ); + mResourceColors.setAutoDelete( true ); + + mDefaultCategoryColor = QColor( 151, 235, 121 ); + + mDefaultResourceColor = QColor();//Default is a color invalid + + mDefaultTimeBarFont = KGlobalSettings::generalFont(); + // make a large default time bar font, at least 16 points. + mDefaultTimeBarFont.setPointSize( + QMAX( mDefaultTimeBarFont.pointSize() + 4, 16 ) ); + + mDefaultMonthViewFont = KGlobalSettings::generalFont(); + // make it a bit smaller + mDefaultMonthViewFont.setPointSize( mDefaultMonthViewFont.pointSize() - 2 ); + + KConfigSkeleton::setCurrentGroup( "General" ); + + addItemPath( "Html Export File", mHtmlExportFile, + QDir::homeDirPath() + "/" + i18n( "Default export file", "calendar.html" ) ); + + timeBarFontItem()->setDefaultValue( mDefaultTimeBarFont ); + monthViewFontItem()->setDefaultValue( mDefaultMonthViewFont ); + eventColorItem()->setDefaultValue( mDefaultCategoryColor ); + + // Load it now, not deep within some painting code + mMyAddrBookMails = KABC::StdAddressBook::self()->whoAmI().emails(); +} + + +KOPrefs::~KOPrefs() +{ + kdDebug(5850) << "KOPrefs::~KOPrefs()" << endl; +} + + +KOPrefs *KOPrefs::instance() +{ + if ( !mInstance ) { + insd.setObject( mInstance, new KOPrefs() ); + mInstance->readConfig(); + } + + return mInstance; +} + +void KOPrefs::usrSetDefaults() +{ + // Default should be set a bit smarter, respecting username and locale + // settings for example. + + KEMailSettings settings; + QString tmp = settings.getSetting(KEMailSettings::RealName); + if ( !tmp.isEmpty() ) setUserName( tmp ); + tmp = settings.getSetting(KEMailSettings::EmailAddress); + if ( !tmp.isEmpty() ) setUserEmail( tmp ); + fillMailDefaults(); + + mTimeBarFont = mDefaultTimeBarFont; + mMonthViewFont = mDefaultMonthViewFont; + + setTimeZoneIdDefault(); + + KPimPrefs::usrSetDefaults(); +} + +void KOPrefs::fillMailDefaults() +{ + userEmailItem()->swapDefault(); + QString defEmail = userEmailItem()->value(); + userEmailItem()->swapDefault(); + + if ( userEmail() == defEmail ) { + // No korg settings - but maybe there's a kcontrol[/kmail] setting available + KEMailSettings settings; + if ( !settings.getSetting( KEMailSettings::EmailAddress ).isEmpty() ) + mEmailControlCenter = true; + } +} + +void KOPrefs::setTimeZoneIdDefault() +{ + QString zone; + + zone = KTimezones().local()->name(); + + kdDebug() << "----- time zone: " << zone << endl; + + mTimeZoneId = zone; +} + +void KOPrefs::setCategoryDefaults() +{ + mCustomCategories.clear(); + + mCustomCategories << i18n("Appointment") << i18n("Business") + << i18n("Meeting") << i18n("Phone Call") << i18n("Education") + << i18n("Holiday") << i18n("Vacation") << i18n("Special Occasion") + << i18n("Personal") << i18n("Travel") << i18n("Miscellaneous") + << i18n("Birthday"); +} + + +void KOPrefs::usrReadConfig() +{ + config()->setGroup("General"); + mCustomCategories = config()->readListEntry("Custom Categories"); + if (mCustomCategories.isEmpty()) setCategoryDefaults(); + + // old category colors, ignore if they have the old default + // should be removed a few versions after 3.2... + config()->setGroup("Category Colors"); + QValueList<QColor> oldCategoryColors; + QStringList::Iterator it; + for (it = mCustomCategories.begin();it != mCustomCategories.end();++it ) { + QColor c = config()->readColorEntry(*it, &mDefaultCategoryColor); + oldCategoryColors.append( (c == QColor(196,196,196)) ? + mDefaultCategoryColor : c); + } + + // new category colors + config()->setGroup("Category Colors2"); + QValueList<QColor>::Iterator it2; + for (it = mCustomCategories.begin(), it2 = oldCategoryColors.begin(); + it != mCustomCategories.end(); ++it, ++it2 ) { + QColor c = config()->readColorEntry(*it, &*it2); + if ( c != mDefaultCategoryColor ) + setCategoryColor(*it,c); + } + + config()->setGroup( "Resources Colors" ); + QMap<QString, QString> map = config()->entryMap( "Resources Colors" ); + + QMapIterator<QString, QString> it3; + for( it3 = map.begin(); it3 != map.end(); ++it3 ) { + kdDebug(5850)<< "KOPrefs::usrReadConfig: key: " << it3.key() << " value: " + << it3.data()<<endl; + setResourceColor( it3.key(), config()->readColorEntry( it3.key(), + &mDefaultResourceColor ) ); + } + + + if (mTimeZoneId.isEmpty()) { + setTimeZoneIdDefault(); + } + +#if 0 + config()->setGroup("FreeBusy"); + if( mRememberRetrievePw ) + mRetrievePassword = KStringHandler::obscure( config()->readEntry( "Retrieve Server Password" ) ); +#endif + KPimPrefs::usrReadConfig(); + fillMailDefaults(); +} + + +void KOPrefs::usrWriteConfig() +{ + config()->setGroup("General"); + config()->writeEntry("Custom Categories",mCustomCategories); + + config()->setGroup("Category Colors2"); + QDictIterator<QColor> it(mCategoryColors); + while (it.current()) { + config()->writeEntry(it.currentKey(),*(it.current())); + ++it; + } + + config()->setGroup( "Resources Colors" ); + QDictIterator<QColor> it2( mResourceColors ); + while( it2.current() ) { + config()->writeEntry( it2.currentKey(), *( it2.current() ) ); + ++it2; + } + + if( !mFreeBusyPublishSavePassword ) { + KConfigSkeleton::ItemPassword *i = freeBusyPublishPasswordItem(); + i->setValue( "" ); + i->writeConfig( config() ); + } + if( !mFreeBusyRetrieveSavePassword ) { + KConfigSkeleton::ItemPassword *i = freeBusyRetrievePasswordItem(); + i->setValue( "" ); + i->writeConfig( config() ); + } + +#if 0 + if( mRememberRetrievePw ) + config()->writeEntry( "Retrieve Server Password", KStringHandler::obscure( mRetrievePassword ) ); + else + config()->deleteEntry( "Retrieve Server Password" ); +#endif + + KPimPrefs::usrWriteConfig(); +} + +void KOPrefs::setCategoryColor( const QString &cat, const QColor & color) +{ + mCategoryColors.replace( cat, new QColor( color ) ); +} + +QColor *KOPrefs::categoryColor( const QString &cat ) +{ + QColor *color = 0; + + if ( !cat.isEmpty() ) color = mCategoryColors[ cat ]; + + if ( color ) return color; + else return &mDefaultCategoryColor; +} + + +bool KOPrefs::hasCategoryColor( const QString& cat ) const +{ + return mCategoryColors[ cat ]; +} + +void KOPrefs::setResourceColor ( const QString &cal, const QColor &color ) +{ + kdDebug(5850)<<"KOPrefs::setResourceColor: " << cal << " color: "<< + color.name()<<endl; + mResourceColors.replace( cal, new QColor( color ) ); +} + +QColor* KOPrefs::resourceColor( const QString &cal ) +{ + QColor *color=0; + if( !cal.isEmpty() ) color = mResourceColors[cal]; + + // assign default color if enabled + if ( !cal.isEmpty() && !color && assignDefaultResourceColors() ) { + QColor defColor( 0x37, 0x7A, 0xBC ); + if ( defaultResourceColorSeed() > 0 && defaultResourceColorSeed() - 1 < (int)defaultResourceColors().size() ) { + defColor = QColor( defaultResourceColors()[defaultResourceColorSeed()-1] ); + } else { + int h, s, v; + defColor.getHsv( h, s, v ); + h = ( defaultResourceColorSeed() % 12 ) * 30; + s -= s * ( (defaultResourceColorSeed() / 12) % 2 ) * 0.5; + defColor.setHsv( h, s, v ); + } + setDefaultResourceColorSeed( defaultResourceColorSeed() + 1 ); + setResourceColor( cal, defColor ); + color = mResourceColors[cal]; + } + + if (color && color->isValid() ) + return color; + else + return &mDefaultResourceColor; +} + +QString KOPrefs::fullName() +{ + if ( mEmailControlCenter ) { + KEMailSettings settings; + return settings.getSetting( KEMailSettings::RealName ); + } else { + return userName(); + } +} + +QString KOPrefs::email() +{ + if ( mEmailControlCenter ) { + KEMailSettings settings; + return settings.getSetting( KEMailSettings::EmailAddress ); + } else { + return userEmail(); + } +} + +QStringList KOPrefs::allEmails() +{ + // Grab emails from the email identities + QStringList lst = KOCore::self()->identityManager()->allEmails(); + // Add emails configured in korganizer + lst += mAdditionalMails; + // Add emails from the user's kaddressbook entry + lst += mMyAddrBookMails; + // Add the email entered as the userEmail here + lst += email(); + + // Warning, this list could contain duplicates. + return lst; +} + +QStringList KOPrefs::fullEmails() +{ + QStringList fullEmails; + // The user name and email from the config dialog: + fullEmails << QString("%1 <%2>").arg( fullName() ).arg( email() ); + + QStringList::Iterator it; + // Grab emails from the email identities + KPIM::IdentityManager *idmanager = KOCore::self()->identityManager(); + QStringList lst = idmanager->identities(); + KPIM::IdentityManager::ConstIterator it1; + for ( it1 = idmanager->begin() ; it1 != idmanager->end() ; ++it1 ) { + fullEmails << (*it1).fullEmailAddr(); + } + // Add emails configured in korganizer + lst = mAdditionalMails; + for ( it = lst.begin(); it != lst.end(); ++it ) { + fullEmails << QString("%1 <%2>").arg( fullName() ).arg( *it ); + } + // Add emails from the user's kaddressbook entry + KABC::Addressee me = KABC::StdAddressBook::self()->whoAmI(); + lst = me.emails(); + for ( it = lst.begin(); it != lst.end(); ++it ) { + fullEmails << me.fullEmail( *it ); + } + + // Warning, this list could contain duplicates. + return fullEmails; +} + +bool KOPrefs::thatIsMe( const QString& _email ) +{ + // NOTE: this method is called for every created agenda view item, so we need to keep + // performance in mind + + /* identityManager()->thatIsMe() is quite expensive since it does parsing of + _email in a way which is unnecessarily complex for what we can have here, + so we do that ourselves. This makes sense since this + + if ( KOCore::self()->identityManager()->thatIsMe( _email ) ) + return true; + */ + + // in case email contains a full name, strip it out + // the below is the simpler but slower version of the following KMime code + // const QString email = KPIM::getEmailAddress( _email ); + const QCString tmp = _email.utf8(); + const char *cursor = tmp.data(); + const char *end = tmp.data() + tmp.length(); + KMime::Types::Mailbox mbox; + KMime::HeaderParsing::parseMailbox( cursor, end, mbox ); + const QString email = mbox.addrSpec.asString(); + + for ( KPIM::IdentityManager::ConstIterator it = KOCore::self()->identityManager()->begin(); + it != KOCore::self()->identityManager()->end(); ++it ) { + if ( email == (*it).emailAddr() ) + return true; + } + + if ( mAdditionalMails.find( email ) != mAdditionalMails.end() ) + return true; + QStringList lst = mMyAddrBookMails; + if ( lst.find( email ) != lst.end() ) + return true; + return false; +} diff --git a/korganizer/koprefs.h b/korganizer/koprefs.h new file mode 100644 index 000000000..d341183ed --- /dev/null +++ b/korganizer/koprefs.h @@ -0,0 +1,116 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOPREFS_H +#define KOPREFS_H + +#include <qdict.h> + +#include <kdepimmacros.h> + +#include "koprefs_base.h" + +class KConfig; +class QFont; +class QColor; +class QStringList; + +QColor getTextColor(const QColor &c); + + +class KDE_EXPORT KOPrefs : public KOPrefsBase +{ + public: + virtual ~KOPrefs(); + + /** Get instance of KOPrefs. It is made sure that there is only one + instance. */ + static KOPrefs *instance(); + + /** Set preferences to default values */ + void usrSetDefaults(); + + /** Read preferences from config file */ + void usrReadConfig(); + + /** Write preferences to config file */ + void usrWriteConfig(); + + protected: + void setCategoryDefaults(); + void setTimeZoneIdDefault(); + + /** Fill empty mail fields with default values. */ + void fillMailDefaults(); + + private: + /** Constructor disabled for public. Use instance() to create a KOPrefs + object. */ + KOPrefs(); + + static KOPrefs *mInstance; + + public: + // preferences data + void setFullName( const QString & ); + QString fullName(); + void setEmail( const QString & ); + QString email(); + /// Returns all email addresses for the user. + QStringList allEmails(); + /// Returns all email addresses together with the full username for the user. + QStringList fullEmails(); + /// Return true if the given email belongs to the user + bool thatIsMe( const QString& email ); + + void setCategoryColor( const QString &cat, const QColor &color ); + QColor *categoryColor( const QString &cat ); + bool hasCategoryColor( const QString &cat ) const; + + void setResourceColor ( const QString &, const QColor & ); + QColor* resourceColor( const QString & ); + + QString mHtmlExportFile; + + // Groupware passwords + QString mPublishPassword; + QString mRetrievePassword; + + private: + QDict<QColor> mCategoryColors; + QColor mDefaultCategoryColor; + + QDict<QColor> mResourceColors; + QColor mDefaultResourceColor; + + QFont mDefaultTimeBarFont; + QFont mDefaultMonthViewFont; + + QStringList mMyAddrBookMails; + + public: // Do not use - except in KOPrefsDialogMain + QString mName; + QString mEmail; +}; + +#endif diff --git a/korganizer/koprefs_base.kcfgc b/korganizer/koprefs_base.kcfgc new file mode 100644 index 000000000..9af07329c --- /dev/null +++ b/korganizer/koprefs_base.kcfgc @@ -0,0 +1,11 @@ +# Code generation options for kconfig_compiler +File=korganizer.kcfg +ClassName=KOPrefsBase +Singleton=false +Mutators=true +Inherits=KPimPrefs +IncludeFiles=libkdepim/kpimprefs.h +MemberVariables=public +GlobalEnums=true +ItemAccessors=true +SetUserTexts=true diff --git a/korganizer/koprefsdialog.cpp b/korganizer/koprefsdialog.cpp new file mode 100644 index 000000000..99045c309 --- /dev/null +++ b/korganizer/koprefsdialog.cpp @@ -0,0 +1,1218 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2000-2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (c) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qlayout.h> +#include <qlabel.h> +#include <qgroupbox.h> +#include <qbuttongroup.h> +#include <qlineedit.h> +#include <qslider.h> +#include <qfile.h> +#include <qcombobox.h> +#include <qhbox.h> +#include <qvbox.h> +#include <qgrid.h> +#include <qspinbox.h> +#include <qcheckbox.h> +#include <qradiobutton.h> +#include <qpushbutton.h> +#include <qstrlist.h> +#include <qlistview.h> +#include <qtabwidget.h> +#include <qwhatsthis.h> + +#include <kcolorbutton.h> +#include <kdebug.h> +#include <klocale.h> +#include <kglobal.h> +#include <kmessagebox.h> +#include <kiconloader.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> + +#if defined(USE_SOLARIS) +#include <sys/param.h> + +#define ZONEINFODIR "/usr/share/lib/zoneinfo" +#define INITFILE "/etc/default/init" +#endif + +#include "koprefs.h" + +#include "koprefsdialog.h" +#include "kogroupwareprefspage.h" +#include "ktimeedit.h" +#include "koglobals.h" +#include "stdcalendar.h" +#include <kdepimmacros.h> + + +KOPrefsDialogMain::KOPrefsDialogMain( QWidget *parent, const char *name ) + : KPrefsModule( KOPrefs::instance(), parent, name ) +{ + QBoxLayout *topTopLayout = new QVBoxLayout( this ); + + QVBox *topFrame = new QVBox( this ); + topTopLayout->addWidget( topFrame ); + + topFrame->setSpacing( KDialog::spacingHint() ); + + KPrefsWidBool *emailControlCenter = + addWidBool( KOPrefs::instance()->emailControlCenterItem(), topFrame ); + connect(emailControlCenter->checkBox(),SIGNAL(toggled(bool)), + SLOT(toggleEmailSettings(bool))); + + mUserEmailSettings = new QGrid( 2, topFrame ); + + addWidString( KOPrefs::instance()->userNameItem(), mUserEmailSettings ); + addWidString( KOPrefs::instance()->userEmailItem(), mUserEmailSettings ); + + QGroupBox *saveGroup = new QGroupBox(1,Horizontal,i18n("Saving Calendar"), + topFrame); + + addWidBool( KOPrefs::instance()->htmlWithSaveItem(), saveGroup ); + + KPrefsWidBool *autoSave = addWidBool( KOPrefs::instance()->autoSaveItem(), saveGroup ); + + QHBox *intervalBox = new QHBox( saveGroup ); + addWidInt( KOPrefs::instance()->autoSaveIntervalItem(), intervalBox ); + connect( autoSave->checkBox(), SIGNAL( toggled( bool ) ), + intervalBox, SLOT( setEnabled( bool ) ) ); + intervalBox->setSpacing( KDialog::spacingHint() ); + new QWidget( intervalBox ); + + addWidBool( KOPrefs::instance()->confirmItem(), topFrame ); + addWidRadios( KOPrefs::instance()->destinationItem(), topFrame); + addWidRadios( KOPrefs::instance()->defaultEmailAttachMethodItem(), topFrame ); + + topTopLayout->addStretch( 1 ); + + load(); +} + +void KOPrefsDialogMain::toggleEmailSettings( bool on ) +{ + mUserEmailSettings->setEnabled( !on ); +/* if (on) { + KEMailSettings settings; + mNameEdit->setText( settings.getSetting(KEMailSettings::RealName) ); + mEmailEdit->setText( settings.getSetting(KEMailSettings::EmailAddress) ); + } else { + mNameEdit->setText( KOPrefs::instance()->mName ); + mEmailEdit->setText( KOPrefs::instance()->mEmail ); + }*/ +} + +extern "C" +{ + KDE_EXPORT KCModule *create_korganizerconfigmain( QWidget *parent, const char * ) + { + return new KOPrefsDialogMain( parent, "kcmkorganizermain" ); + } +} + + +class KOPrefsDialogTime : public KPrefsModule +{ + public: + KOPrefsDialogTime( QWidget *parent, const char *name ) + : KPrefsModule( KOPrefs::instance(), parent, name ) + { + QBoxLayout *topTopLayout = new QVBoxLayout( this ); + + QWidget *topFrame = new QWidget( this ); + topTopLayout->addWidget( topFrame ); + + QGridLayout *topLayout = new QGridLayout(topFrame,6,2); + topLayout->setSpacing( KDialog::spacingHint() ); + + QHBox *timeZoneBox = new QHBox( topFrame ); + topLayout->addMultiCellWidget( timeZoneBox, 0, 0, 0, 1 ); + + QLabel *timeZoneLabel = new QLabel( i18n("Timezone:"), timeZoneBox ); + QString whatsThis = i18n( "Select your timezone from the list of " + "locations on this drop down box. If your city " + "is not listed, select one which shares the " + "same timezone. KOrganizer will automatically " + "adjust for daylight savings." ); + QWhatsThis::add( timeZoneLabel, whatsThis ); + mTimeZoneCombo = new QComboBox( timeZoneBox ); + + connect( mTimeZoneCombo, SIGNAL( activated( int ) ), + SLOT( slotWidChanged() ) ); + + FILE *f; + char tempstring[101] = "Unknown"; + QString sCurrentlySet(i18n("Unknown")); + int nCurrentlySet = 0; + QStringList list; + + // read the currently set time zone + #if defined(USE_SOLARIS) // MARCO + char buf[MAXPATHLEN]; + + snprintf(buf, MAXPATHLEN, + "/bin/fgrep 'TZ=' %s | /bin/head -n 1 | /bin/cut -b 4-", + INITFILE); + + if (f = popen(buf, "r")) + { + if (fgets(buf, MAXPATHLEN - 1, f) != NULL) + { + buf[strlen(buf) - 1] = '\0'; + sCurrentlySet = QString(buf); + } + pclose(f); + } + #else + if((f = fopen("/etc/timezone", "r")) != NULL) { + // get the currently set timezone + fgets(tempstring, 100, f); + tempstring[strlen(tempstring) - 1] = '\0'; + sCurrentlySet = QString(tempstring); + fclose(f); + } + #endif // !USE_SOLARIS + + mTimeZoneCombo->insertItem(i18n("[No selection]")); + + // Read all system time zones + #if defined(USE_SOLARIS) // MARCO + snprintf(buf, MAXPATHLEN, + "/bin/find %s \\( -name src -prune \\) -o -type f -print | /bin/cut -b %d-", + ZONEINFODIR, strlen(ZONEINFODIR) + 2); + + if (f = popen(buf, "r")) + { + while(fgets(buf, MAXPATHLEN - 1, f) != NULL) + { + buf[strlen(buf) - 1] = '\0'; + list.append(buf); + } + pclose(f); + } + + #else + f = popen("grep -e ^[^#] /usr/share/zoneinfo/zone.tab | cut -f 3","r"); + if (!f) return; + while(fgets(tempstring, 100, f) != NULL) { + tempstring[strlen(tempstring)-1] = '\0'; + list.append(i18n(tempstring)); + tzonenames << tempstring; + } + pclose(f); + #endif // !USE_SOLARIS + list.sort(); + + mTimeZoneCombo->insertStringList(list); + + // find the currently set time zone and select it + for ( int i = 0; i < mTimeZoneCombo->count(); ++i ) + { + if (mTimeZoneCombo->text(i) == sCurrentlySet) + { + nCurrentlySet = i; + break; + } + } + + mTimeZoneCombo->setCurrentItem(nCurrentlySet); + QWhatsThis::add( mTimeZoneCombo, whatsThis ); + + // holiday region selection + QHBox *holidayRegBox = new QHBox( topFrame ); + topLayout->addMultiCellWidget( holidayRegBox, 1, 1, 0, 1 ); + + QLabel *holidayLabel = new QLabel( i18n( "Use holiday region:" ), holidayRegBox ); + whatsThis = i18n( "Select from which region you want to use the " + "holidays here. Defined holidays are shown as " + "non-working days in the date navigator, the " + "agenda view, etc." ); + QWhatsThis::add( holidayLabel, whatsThis ); + + mHolidayCombo = new QComboBox( holidayRegBox ); + connect( mHolidayCombo, SIGNAL( activated( int ) ), + SLOT( slotWidChanged() ) ); + + QWhatsThis::add( mHolidayCombo, whatsThis ); + + QString currentHolidayName; + QStringList holidayList; + QStringList countryList = KHolidays::locations(); + QStringList::ConstIterator it; + + for ( it = countryList.begin(); it != countryList.end(); ++it ) { + QString countryFile = locate( "locale", + "l10n/" + (*it) + "/entry.desktop" ); + QString regionName; + if ( !countryFile.isEmpty() ) { + KSimpleConfig cfg( countryFile ); + cfg.setGroup( "KCM Locale" ); + regionName = cfg.readEntry( "Name" ); + } + if (regionName.isEmpty()) regionName = (*it); + + holidayList << regionName; + mRegionMap[regionName] = (*it); //store region for saving to config file + + if ( KOGlobals::self()->holidays() + && ((*it) == KOGlobals::self()->holidays()->location()) ) + currentHolidayName = regionName; + } + holidayList.sort(); + holidayList.push_front( i18n("(None)") ); //be able to disable holidays + + mHolidayCombo->insertStringList(holidayList); + + for (int i=0; i < mHolidayCombo->count(); ++i) { + if ( mHolidayCombo->text(i) == currentHolidayName ) { + mHolidayCombo->setCurrentItem(i); + break; + } + } + + KPrefsWidTime *dayBegins = + addWidTime( KOPrefs::instance()->dayBeginsItem(), topFrame ); + topLayout->addWidget( dayBegins->label(), 2, 0 ); + topLayout->addWidget( dayBegins->timeEdit(), 2, 1 ); + + KPrefsWidTime *defaultTime = + addWidTime( KOPrefs::instance()->startTimeItem(), topFrame ); + topLayout->addWidget( defaultTime->label(), 3, 0); + topLayout->addWidget( defaultTime->timeEdit(), 3, 1); + + KPrefsWidDuration *defaultDuration = + addWidDuration( KOPrefs::instance()->defaultDurationItem(), topFrame ); + topLayout->addWidget( defaultDuration->label(), 4, 0 ); + topLayout->addWidget( defaultDuration->timeEdit(), 4, 1 ); + + QStringList alarmList; + alarmList << i18n( "1 minute" ) << i18n( "5 minutes" ) + << i18n( "10 minutes" ) << i18n( "15 minutes" ) + << i18n( "30 minutes" ); + QLabel *alarmLabel = new QLabel( i18n( "Default reminder time:" ), topFrame); + topLayout->addWidget( alarmLabel, 5, 0 ); + QWhatsThis::add( alarmLabel, + i18n( "Enter the default reminder time here." ) ); + mAlarmTimeCombo = new QComboBox( topFrame ); + QWhatsThis::add( mAlarmTimeCombo, + i18n( "Enter the default reminder time here." ) ); + connect( mAlarmTimeCombo, SIGNAL( activated( int ) ), + SLOT( slotWidChanged() ) ); + mAlarmTimeCombo->insertStringList( alarmList ); + topLayout->addWidget( mAlarmTimeCombo, 5, 1 ); + + + QGroupBox *workingHoursGroup = new QGroupBox(1,Horizontal, + i18n("Working Hours"), + topFrame); + topLayout->addMultiCellWidget( workingHoursGroup, 6, 6, 0, 1 ); + + QHBox *workDaysBox = new QHBox( workingHoursGroup ); + // Respect start of week setting + int weekStart=KGlobal::locale()->weekStartDay(); + for ( int i = 0; i < 7; ++i ) { + const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem(); + QString weekDayName = calSys->weekDayName( (i + weekStart + 6)%7 + 1, true ); + if ( KOPrefs::instance()->mCompactDialogs ) { + weekDayName = weekDayName.left( 1 ); + } + int index = ( i + weekStart + 6 ) % 7; + mWorkDays[ index ] = new QCheckBox( weekDayName, workDaysBox ); + QWhatsThis::add( mWorkDays[ index ], + i18n( "Check this box to make KOrganizer mark the " + "working hours for this day of the week. " + "If this is a work day for you, check " + "this box, or the working hours will not be " + "marked with color." ) ); + + connect( mWorkDays[ index ], SIGNAL( stateChanged( int ) ), + SLOT( slotWidChanged() ) ); + } + + QHBox *workStartBox = new QHBox(workingHoursGroup); + addWidTime( KOPrefs::instance()->workingHoursStartItem(), workStartBox ); + + QHBox *workEndBox = new QHBox(workingHoursGroup); + addWidTime( KOPrefs::instance()->workingHoursEndItem(), workEndBox ); + + + addWidBool( KOPrefs::instance()->excludeHolidaysItem(), + workingHoursGroup ); + + topLayout->setRowStretch(7,1); + + load(); + } + + protected: + void usrReadConfig() + { + setCombo( mTimeZoneCombo, + i18n( KOPrefs::instance()->mTimeZoneId.utf8() ) ); + + mAlarmTimeCombo->setCurrentItem( KOPrefs::instance()->mAlarmTime ); + for ( int i = 0; i < 7; ++i ) { + mWorkDays[i]->setChecked( (1<<i) & (KOPrefs::instance()->mWorkWeekMask) ); + } + } + + void usrWriteConfig() + { + // Find untranslated selected zone + QStringList::Iterator tz; + for ( tz = tzonenames.begin(); tz != tzonenames.end(); ++tz ) + if (mTimeZoneCombo->currentText() == i18n((*tz).utf8())) + break; + if (tz != tzonenames.end()) + KOPrefs::instance()->mTimeZoneId = (*tz); + else + KOPrefs::instance()->mTimeZoneId = mTimeZoneCombo->currentText(); + + KOPrefs::instance()->mHolidays = ( mHolidayCombo->currentItem() == 0 ) ? // (None) + QString::null : + mRegionMap[mHolidayCombo->currentText()]; + + KOPrefs::instance()->mAlarmTime = mAlarmTimeCombo->currentItem(); + int mask = 0; + for ( int i = 0; i < 7; ++i ) { + if (mWorkDays[i]->isChecked()) mask = mask | (1<<i); + } + KOPrefs::instance()->mWorkWeekMask = mask; + KOPrefs::instance()->writeConfig(); + } + + void setCombo( QComboBox *combo, const QString &text, + const QStringList *tags = 0 ) + { + if (tags) { + int i = tags->findIndex(text); + if (i > 0) combo->setCurrentItem(i); + } else { + for(int i=0;i<combo->count();++i) { + if (combo->text(i) == text) { + combo->setCurrentItem(i); + break; + } + } + } + } + + private: + QComboBox *mTimeZoneCombo; + QStringList tzonenames; + QComboBox *mHolidayCombo; + QMap<QString,QString> mRegionMap; + QComboBox *mAlarmTimeCombo; + QCheckBox *mWorkDays[7]; +}; + +extern "C" +{ + KCModule *create_korganizerconfigtime( QWidget *parent, const char * ) + { + KGlobal::locale()->insertCatalogue( "timezones" ); + return new KOPrefsDialogTime( parent, "kcmkorganizertime" ); + } +} + + +class KOPrefsDialogViews : public KPrefsModule +{ + public: + KOPrefsDialogViews( QWidget *parent, const char *name ) + : KPrefsModule( KOPrefs::instance(), parent, name ) + { + QBoxLayout *topTopLayout = new QVBoxLayout( this ); + + QWidget *topFrame = new QWidget( this ); + topTopLayout->addWidget( topFrame ); + + QBoxLayout *topLayout = new QVBoxLayout( topFrame ); + topLayout->setSpacing( KDialog::spacingHint() ); + + KPrefsWidBool *enableToolTips = + addWidBool( KOPrefs::instance()->enableToolTipsItem(), topFrame ); + topLayout->addWidget( enableToolTips->checkBox() ); + + KPrefsWidBool *showTodosAgenda = + addWidBool( KOPrefs::instance()->showAllDayTodoItem(), topFrame ); + topLayout->addWidget( showTodosAgenda->checkBox() ); + + /*** Date Navigator Group ***/ + QGroupBox *dateNavGroup = new QGroupBox( 1, Horizontal, + i18n("Date Navigator"), + topFrame ); + addWidBool( KOPrefs::instance()->dailyRecurItem(), dateNavGroup ); + addWidBool( KOPrefs::instance()->weeklyRecurItem(), dateNavGroup ); + topLayout->addWidget( dateNavGroup ); + + + /*** Agenda View Group ***/ + QGroupBox *agendaGroup = new QGroupBox( 1, Horizontal, + i18n("Agenda View"), + topFrame ); + + QHBox *hourSizeBox = new QHBox( agendaGroup ); + KPrefsWidInt *hourSize = + addWidInt( KOPrefs::instance()->hourSizeItem(), hourSizeBox ); + hourSize->spinBox()->setSuffix(i18n("suffix in the hour size spin box", " pixel")); + // horizontal spacer: + new QWidget( hourSizeBox ); + + QHBox *nextDaysBox = new QHBox( agendaGroup ); + KPrefsWidInt *nextDays = + addWidInt( KOPrefs::instance()->nextXDaysItem(), nextDaysBox ); + nextDays->spinBox()->setSuffix(i18n("suffix in the N days spin box", " days")); + new QWidget( nextDaysBox ); + + KPrefsWidBool *marcusBainsEnabled = + addWidBool( KOPrefs::instance()->marcusBainsEnabledItem(), agendaGroup ); + + KPrefsWidBool *marcusBainsShowSeconds = + addWidBool( KOPrefs::instance()->marcusBainsShowSecondsItem(), agendaGroup ); + connect( marcusBainsEnabled->checkBox(), SIGNAL( toggled( bool ) ), + marcusBainsShowSeconds->checkBox(), SLOT( setEnabled( bool ) ) ); + + addWidBool( KOPrefs::instance()->selectionStartsEditorItem(), agendaGroup ); + + addWidCombo( KOPrefs::instance()->agendaViewColorsItem(), agendaGroup ); + + addWidCombo( KOPrefs::instance()->agendaViewCalendarDisplayItem(), agendaGroup ); + + topLayout->addWidget( agendaGroup ); + + /*** Month and Todo view groups side by side, to save space. ***/ + QHBoxLayout *hbox = new QHBoxLayout(); + topLayout->addLayout( hbox ); + + /*** Month View Group ***/ + QGroupBox *monthGroup = new QGroupBox( 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 ); + + + /*** Todo View Group ***/ + QGroupBox *todoGroup = new QGroupBox( 1, Horizontal, + i18n("To-do View"), + topFrame ); + addWidBool( KOPrefs::instance()->fullViewTodoItem(), todoGroup ); + addWidBool( KOPrefs::instance()->recordTodosInJournalsItem(), todoGroup ); + hbox->addWidget( todoGroup ); + + topLayout->addStretch( 1 ); + + load(); + } +}; + +extern "C" +{ + KCModule *create_korganizerconfigviews( QWidget *parent, const char * ) + { + return new KOPrefsDialogViews( parent, "kcmkorganizerviews" ); + } +} + + +class KOPrefsDialogFonts : public KPrefsModule +{ + public: + KOPrefsDialogFonts( QWidget *parent, const char *name ) + : KPrefsModule( KOPrefs::instance(), parent, name ) + { + QBoxLayout *topTopLayout = new QVBoxLayout( this ); + + QWidget *topFrame = new QWidget( this ); + topTopLayout->addWidget( topFrame ); + + QGridLayout *topLayout = new QGridLayout(topFrame,5,3); + topLayout->setSpacing( KDialog::spacingHint() ); + + KPrefsWidFont *timeBarFont = + addWidFont( KOPrefs::instance()->timeBarFontItem(), topFrame, + KGlobal::locale()->formatTime( QTime( 12, 34 ) ) ); + topLayout->addWidget(timeBarFont->label(),0,0); + topLayout->addWidget(timeBarFont->preview(),0,1); + topLayout->addWidget(timeBarFont->button(),0,2); + + KPrefsWidFont *monthViewFont = + addWidFont( KOPrefs::instance()->monthViewFontItem(), topFrame, + KGlobal::locale()->formatTime(QTime(12,34)) + " " + + i18n("Event text") ); + + topLayout->addWidget(monthViewFont->label(),1,0); + topLayout->addWidget(monthViewFont->preview(),1,1); + topLayout->addWidget(monthViewFont->button(),1,2); + + KPrefsWidFont *agendaViewFont = + addWidFont( KOPrefs::instance()->agendaViewFontItem(), + topFrame, i18n("Event text") ); + topLayout->addWidget(agendaViewFont->label(),2,0); + topLayout->addWidget(agendaViewFont->preview(),2,1); + topLayout->addWidget(agendaViewFont->button(),2,2); + + KPrefsWidFont *marcusBainsFont = + addWidFont( KOPrefs::instance()->marcusBainsFontItem(), topFrame, + KGlobal::locale()->formatTime( QTime( 12, 34, 23 ) ) ); + topLayout->addWidget(marcusBainsFont->label(),3,0); + topLayout->addWidget(marcusBainsFont->preview(),3,1); + topLayout->addWidget(marcusBainsFont->button(),3,2); + + topLayout->setColStretch(1,1); + topLayout->setRowStretch(4,1); + + load(); + } +}; + +extern "C" +{ + KCModule *create_korganizerconfigfonts( QWidget *parent, const char * ) + { + return new KOPrefsDialogFonts( parent, "kcmkorganizerfonts" ); + } +} + + +KOPrefsDialogColors::KOPrefsDialogColors( QWidget *parent, const char *name ) + : KPrefsModule( KOPrefs::instance(), parent, name ) +{ + QBoxLayout *topTopLayout = new QVBoxLayout( this ); + + QWidget *topFrame = new QWidget( this ); + topTopLayout->addWidget( topFrame ); + + QGridLayout *topLayout = new QGridLayout(topFrame,7,2); + topLayout->setSpacing( KDialog::spacingHint() ); + + // Holiday Color + KPrefsWidColor *holidayColor = + addWidColor( KOPrefs::instance()->holidayColorItem(), topFrame ); + topLayout->addWidget(holidayColor->label(),0,0); + topLayout->addWidget(holidayColor->button(),0,1); + + // Highlight Color + KPrefsWidColor *highlightColor = + addWidColor( KOPrefs::instance()->highlightColorItem(), topFrame ); + 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); + + // working hours color + KPrefsWidColor *workingHoursColor = + addWidColor( KOPrefs::instance()->workingHoursColorItem(), topFrame ); + topLayout->addWidget(workingHoursColor->label(),4,0); + topLayout->addWidget(workingHoursColor->button(),4,1); + + // Todo due today color + KPrefsWidColor *todoDueTodayColor = + addWidColor( KOPrefs::instance()->todoDueTodayColorItem(), topFrame ); + topLayout->addWidget(todoDueTodayColor->label(),5,0); + topLayout->addWidget(todoDueTodayColor->button(),5,1); + + // Todo overdue color + KPrefsWidColor *todoOverdueColor = + addWidColor( KOPrefs::instance()->todoOverdueColorItem(), topFrame ); + topLayout->addWidget(todoOverdueColor->label(),6,0); + topLayout->addWidget(todoOverdueColor->button(),6,1); + + // categories colors + QGroupBox *categoryGroup = new QGroupBox(1,Horizontal,i18n("Categories"), + topFrame); + topLayout->addMultiCellWidget(categoryGroup,7,7,0,1); + + mCategoryCombo = new QComboBox(categoryGroup); + mCategoryCombo->insertStringList(KOPrefs::instance()->mCustomCategories); + QWhatsThis::add( mCategoryCombo, + i18n( "Select here the event category you want to modify. " + "You can change the selected category color using " + "the button below." ) ); + connect(mCategoryCombo,SIGNAL(activated(int)),SLOT(updateCategoryColor())); + + mCategoryButton = new KColorButton(categoryGroup); + QWhatsThis::add( mCategoryButton, + i18n( "Choose here the color of the event category selected " + "using the combo box above." ) ); + connect(mCategoryButton,SIGNAL(changed(const QColor &)),SLOT(setCategoryColor())); + updateCategoryColor(); + + // resources colors + QGroupBox *resourceGroup = new QGroupBox(1,Horizontal,i18n("Resources"), + topFrame); + topLayout->addMultiCellWidget(resourceGroup,8,8,0,1); + + mResourceCombo = new QComboBox(resourceGroup); + QWhatsThis::add( mResourceCombo, + i18n( "Select here resource you want to modify. " + "You can change the selected resource color using " + "the button below." ) ); + connect(mResourceCombo,SIGNAL(activated(int)),SLOT(updateResourceColor())); + + mResourceButton = new KColorButton(resourceGroup); + QWhatsThis::add( mResourceButton, + i18n( "Choose here the color of the resource selected " + "using the combo box above." ) ); + connect(mResourceButton,SIGNAL(changed(const QColor &)),SLOT(setResourceColor())); + updateResources(); + + topLayout->setRowStretch(9,1); + + load(); +} + +void KOPrefsDialogColors::usrWriteConfig() +{ + QDictIterator<QColor> itCat(mCategoryDict); + while (itCat.current()) { + KOPrefs::instance()->setCategoryColor(itCat.currentKey(),*itCat.current()); + ++itCat; + } + + QDictIterator<QColor> itRes(mResourceDict); + while (itRes.current()) { + KOPrefs::instance()->setResourceColor(itRes.currentKey(),*itRes.current()); + ++itRes; + } +} + +void KOPrefsDialogColors::usrReadConfig() +{ + updateCategories(); + updateResources(); +} + +void KOPrefsDialogColors::updateCategories() +{ + mCategoryCombo->clear(); + mCategoryCombo->insertStringList(KOPrefs::instance()->mCustomCategories); + updateCategoryColor(); +} + +void KOPrefsDialogColors::setCategoryColor() +{ + mCategoryDict.replace(mCategoryCombo->currentText(), new QColor(mCategoryButton->color())); + slotWidChanged(); +} + +void KOPrefsDialogColors::updateCategoryColor() +{ + QString cat = mCategoryCombo->currentText(); + QColor *color = mCategoryDict.find(cat); + if (!color) { + color = KOPrefs::instance()->categoryColor(cat); + } + if (color) { + mCategoryButton->setColor(*color); + } +} + +void KOPrefsDialogColors::updateResources() +{ + mResourceCombo->clear(); + mResourceIdentifier.clear(); + kdDebug( 5850) << "KOPrefsDialogColors::updateResources()" << endl; + + KCal::CalendarResourceManager *manager = KOrg::StdCalendar::self()->resourceManager(); + + kdDebug(5850) << "Loading Calendar resources...:" << endl; + KCal::CalendarResourceManager::Iterator it; + for( it = manager->begin(); it != manager->end(); ++it ) { + if ( !(*it)->subresources().isEmpty() ) { + QStringList subresources = (*it)->subresources(); + for ( uint i = 0; i < subresources.count(); ++i ) { + QString resource = subresources[ i ]; + if ( (*it)->subresourceActive( resource ) ) { + mResourceCombo->insertItem( (*it)->labelForSubresource( resource ) ); + mResourceIdentifier.append( resource ); + } + } + } + + mResourceCombo->insertItem( (*it)->resourceName() ); + mResourceIdentifier.append( (*it)->identifier() ); + } + + updateResourceColor(); +} + +void KOPrefsDialogColors::setResourceColor() +{ + kdDebug( 5850) << "KOPrefsDialogColors::setResorceColor()" << endl; + + mResourceDict.replace( mResourceIdentifier[mResourceCombo->currentItem()], + new QColor( mResourceButton->color() ) ); + slotWidChanged(); +} + +void KOPrefsDialogColors::updateResourceColor() +{ + kdDebug( 5850 ) << "KOPrefsDialogColors::updateResourceColor()" << endl; + QString res= mResourceIdentifier[mResourceCombo->currentItem()]; + QColor *color = mCategoryDict.find(res); + if( !color ) { + color = KOPrefs::instance()->resourceColor( res ); + } + if( color ) { + mResourceButton->setColor(*color); + } +} +extern "C" +{ + KCModule *create_korganizerconfigcolors( QWidget *parent, const char * ) + { + return new KOPrefsDialogColors( parent, "kcmkorganizercolors" ); + } +} + + +KOPrefsDialogGroupScheduling::KOPrefsDialogGroupScheduling( QWidget *parent, const char *name ) + : KPrefsModule( KOPrefs::instance(), parent, name ) +{ + QBoxLayout *topTopLayout = new QVBoxLayout( this ); + + QWidget *topFrame = new QWidget( this ); + topTopLayout->addWidget( topFrame ); + + QGridLayout *topLayout = new QGridLayout(topFrame,6,2); + topLayout->setSpacing( KDialog::spacingHint() ); + + KPrefsWidBool *useGroupwareBool = + addWidBool( KOPrefs::instance()->useGroupwareCommunicationItem(), + topFrame ); + topLayout->addMultiCellWidget(useGroupwareBool->checkBox(),0,0,0,1); + // FIXME: This radio button should only be available when KMail is chosen +// connect(thekmailradiobuttonupthere,SIGNAL(toggled(bool)), +// useGroupwareBool->checkBox(), SLOT(enabled(bool))); + + KPrefsWidBool *bcc = + addWidBool( KOPrefs::instance()->bccItem(), topFrame ); + topLayout->addMultiCellWidget(bcc->checkBox(),1,1,0,1); + + KPrefsWidRadios *mailClientGroup = + addWidRadios( KOPrefs::instance()->mailClientItem(), topFrame ); + topLayout->addMultiCellWidget(mailClientGroup->groupBox(),2,2,0,1); + + +#if 0 + KPrefsWidRadios *schedulerGroup = + addWidRadios(i18n("Scheduler Mail Client"),KOPrefs::instance()->mIMIPScheduler, + topFrame); + schedulerGroup->addRadio("Dummy"); // Only for debugging + schedulerGroup->addRadio(i18n("Mail client")); + + topLayout->addMultiCellWidget(schedulerGroup->groupBox(),0,0,0,1); +#endif + + QLabel *aMailsLabel = new QLabel(i18n("Additional email addresses:"),topFrame); + QString whatsThis = i18n( "Add, edit or remove additional e-mails addresses " + "here. These email addresses are the ones you " + "have in addition to the one set in personal " + "preferences. If you are an attendee of one event, " + "but use another email address there, you need to " + "list this address here so KOrganizer can " + "recognize it as yours." ); + QWhatsThis::add( aMailsLabel, whatsThis ); + topLayout->addMultiCellWidget(aMailsLabel,3,3,0,1); + mAMails = new QListView(topFrame); + QWhatsThis::add( mAMails, whatsThis ); + + mAMails->addColumn(i18n("Email"),300); + topLayout->addMultiCellWidget(mAMails,4,4,0,1); + + QLabel *aEmailsEditLabel = new QLabel(i18n("Additional email address:"),topFrame); + whatsThis = i18n( "Edit additional e-mails addresses here. To edit an " + "address select it from the list above " + "or press the \"New\" button below. These email " + "addresses are the ones you have in addition to the " + "one set in personal preferences." ); + QWhatsThis::add( aEmailsEditLabel, whatsThis ); + topLayout->addWidget(aEmailsEditLabel,5,0); + aEmailsEdit = new QLineEdit(topFrame); + QWhatsThis::add( aEmailsEdit, whatsThis ); + aEmailsEdit->setEnabled(false); + topLayout->addWidget(aEmailsEdit,5,1); + + QPushButton *add = new QPushButton(i18n("New"),topFrame,"new"); + whatsThis = i18n( "Press this button to add a new entry to the " + "additional e-mail addresses list. Use the edit " + "box above to edit the new entry." ); + QWhatsThis::add( add, whatsThis ); + topLayout->addWidget(add,6,0); + QPushButton *del = new QPushButton(i18n("Remove"),topFrame,"remove"); + QWhatsThis::add( del, whatsThis ); + topLayout->addWidget(del,6,1); + + //topLayout->setRowStretch(2,1); + connect(add, SIGNAL( clicked() ), this, SLOT(addItem()) ); + connect(del, SIGNAL( clicked() ), this, SLOT(removeItem()) ); + connect(aEmailsEdit,SIGNAL( textChanged(const QString&) ), this,SLOT(updateItem())); + connect(mAMails,SIGNAL(selectionChanged(QListViewItem *)),SLOT(updateInput())); + + load(); +} + +void KOPrefsDialogGroupScheduling::usrReadConfig() +{ + mAMails->clear(); + for ( QStringList::Iterator it = KOPrefs::instance()->mAdditionalMails.begin(); + it != KOPrefs::instance()->mAdditionalMails.end(); ++it ) { + QListViewItem *item = new QListViewItem(mAMails); + item->setText(0,*it); + mAMails->insertItem(item); + } +} + +void KOPrefsDialogGroupScheduling::usrWriteConfig() +{ + KOPrefs::instance()->mAdditionalMails.clear(); + QListViewItem *item; + item = mAMails->firstChild(); + while (item) + { + KOPrefs::instance()->mAdditionalMails.append( item->text(0) ); + item = item->nextSibling(); + } +} + +void KOPrefsDialogGroupScheduling::addItem() +{ + aEmailsEdit->setEnabled(true); + QListViewItem *item = new QListViewItem(mAMails); + mAMails->insertItem(item); + mAMails->setSelected(item,true); + aEmailsEdit->setText(i18n("(EmptyEmail)")); + slotWidChanged(); +} + +void KOPrefsDialogGroupScheduling::removeItem() +{ + QListViewItem *item; + item = mAMails->selectedItem(); + if (!item) return; + mAMails->takeItem(item); + item = mAMails->selectedItem(); + if (!item) { + aEmailsEdit->setText(""); + aEmailsEdit->setEnabled(false); + } + if (mAMails->childCount() == 0) { + aEmailsEdit->setEnabled(false); + } + slotWidChanged(); +} + +void KOPrefsDialogGroupScheduling::updateItem() +{ + QListViewItem *item; + item = mAMails->selectedItem(); + if (!item) return; + item->setText(0,aEmailsEdit->text()); + slotWidChanged(); +} + +void KOPrefsDialogGroupScheduling::updateInput() +{ + QListViewItem *item; + item = mAMails->selectedItem(); + if (!item) return; + aEmailsEdit->setEnabled(true); + aEmailsEdit->setText(item->text(0)); +} + +extern "C" +{ + KCModule *create_korganizerconfiggroupscheduling( QWidget *parent, + const char * ) + { + return new KOPrefsDialogGroupScheduling( parent, + "kcmkorganizergroupscheduling" ); + } +} + + +KOPrefsDialogGroupwareScheduling::KOPrefsDialogGroupwareScheduling( QWidget *parent, const char *name ) + : KPrefsModule( KOPrefs::instance(), parent, name ) +{ + mGroupwarePage = new KOGroupwarePrefsPage( this ); + connect( mGroupwarePage, SIGNAL( changed() ), SLOT( slotWidChanged() ) ); + ( new QVBoxLayout( this ) )->addWidget( mGroupwarePage ); + + load(); +} + +void KOPrefsDialogGroupwareScheduling::usrReadConfig() +{ + mGroupwarePage->publishEnable->setChecked( KOPrefs::instance()->mFreeBusyPublishAuto ); + mGroupwarePage->publishDelay->setValue( KOPrefs::instance()->mFreeBusyPublishDelay ); + mGroupwarePage->publishDays->setValue( KOPrefs::instance()->mFreeBusyPublishDays ); + + mGroupwarePage->publishUrl->setText( KOPrefs::instance()->mFreeBusyPublishUrl ); + mGroupwarePage->publishUser->setText( KOPrefs::instance()->mFreeBusyPublishUser ); + mGroupwarePage->publishPassword->setText( KOPrefs::instance()->mFreeBusyPublishPassword ); + mGroupwarePage->publishSavePassword->setChecked( KOPrefs::instance()->mFreeBusyPublishSavePassword ); + + mGroupwarePage->retrieveEnable->setChecked( KOPrefs::instance()->mFreeBusyRetrieveAuto ); + mGroupwarePage->fullDomainRetrieval->setChecked( KOPrefs::instance()->mFreeBusyFullDomainRetrieval ); + mGroupwarePage->retrieveUrl->setText( KOPrefs::instance()->mFreeBusyRetrieveUrl ); + mGroupwarePage->retrieveUser->setText( KOPrefs::instance()->mFreeBusyRetrieveUser ); + mGroupwarePage->retrievePassword->setText( KOPrefs::instance()->mFreeBusyRetrievePassword ); + mGroupwarePage->retrieveSavePassword->setChecked( KOPrefs::instance()->mFreeBusyRetrieveSavePassword ); +} + +void KOPrefsDialogGroupwareScheduling::usrWriteConfig() +{ + KOPrefs::instance()->mFreeBusyPublishAuto = mGroupwarePage->publishEnable->isChecked(); + KOPrefs::instance()->mFreeBusyPublishDelay = mGroupwarePage->publishDelay->value(); + KOPrefs::instance()->mFreeBusyPublishDays = mGroupwarePage->publishDays->value(); + + KOPrefs::instance()->mFreeBusyPublishUrl = mGroupwarePage->publishUrl->text(); + KOPrefs::instance()->mFreeBusyPublishUser = mGroupwarePage->publishUser->text(); + KOPrefs::instance()->mFreeBusyPublishPassword = mGroupwarePage->publishPassword->text(); + KOPrefs::instance()->mFreeBusyPublishSavePassword = mGroupwarePage->publishSavePassword->isChecked(); + + KOPrefs::instance()->mFreeBusyRetrieveAuto = mGroupwarePage->retrieveEnable->isChecked(); + KOPrefs::instance()->mFreeBusyFullDomainRetrieval = mGroupwarePage->fullDomainRetrieval->isChecked(); + KOPrefs::instance()->mFreeBusyRetrieveUrl = mGroupwarePage->retrieveUrl->text(); + KOPrefs::instance()->mFreeBusyRetrieveUser = mGroupwarePage->retrieveUser->text(); + KOPrefs::instance()->mFreeBusyRetrievePassword = mGroupwarePage->retrievePassword->text(); + KOPrefs::instance()->mFreeBusyRetrieveSavePassword = mGroupwarePage->retrieveSavePassword->isChecked(); +} + +extern "C" +{ + KCModule *create_korganizerconfigfreebusy( QWidget *parent, const char * ) + { + return new KOPrefsDialogGroupwareScheduling( parent, + "kcmkorganizerfreebusy" ); + } +} + + + +class PluginItem : public QCheckListItem { + public: + PluginItem( QListView *parent, KService::Ptr service ) : + QCheckListItem( parent, service->name(), QCheckListItem::CheckBox ), mService( service ) + {} + KService::Ptr service() { return mService; } + private: + KService::Ptr mService; +}; + + +/** + Dialog for selecting and configuring KOrganizer plugins +*/ +KOPrefsDialogPlugins::KOPrefsDialogPlugins( QWidget *parent, const char* name ) + : KPrefsModule( KOPrefs::instance(), parent, name ) +{ + QBoxLayout *topTopLayout = new QVBoxLayout( this ); + + QWidget *topFrame = new QWidget( this ); + topTopLayout->addWidget( topFrame ); + QBoxLayout *topLayout = new QVBoxLayout( topFrame ); + topLayout->setSpacing( KDialog::spacingHint() ); + + mListView = new QListView( topFrame ); + mListView->addColumn( i18n("Name") ); + mListView->setResizeMode( QListView::LastColumn ); + topLayout->addWidget( mListView ); + + mDescription = new QLabel( topFrame ); + mDescription->setAlignment( QLabel::NoAccel | QLabel::WordBreak | QLabel::AlignVCenter ); + mDescription->setFrameShape( QLabel::Panel ); + mDescription->setFrameShadow( QLabel::Sunken ); + mDescription->setMinimumSize( QSize( 0, 55 ) ); + mDescription->setSizePolicy( + QSizePolicy( (QSizePolicy::SizeType)5, (QSizePolicy::SizeType)0, + 0, 0, mDescription->sizePolicy().hasHeightForWidth() ) ); + topLayout->addWidget( mDescription ); + + + QWidget *buttonRow = new QWidget( topFrame ); + QBoxLayout *buttonRowLayout = new QHBoxLayout( buttonRow ); + mConfigureButton = new KPushButton( KGuiItem( i18n("Configure &Plugin..."), + "configure", QString::null, i18n("This button allows you to configure" + " the plugin that you have selected in the list above") ), buttonRow ); + + buttonRowLayout->addWidget( mConfigureButton ); + buttonRowLayout->addItem( new QSpacerItem(1, 1, QSizePolicy::Expanding) ); + topLayout->addWidget( buttonRow ); + connect( mConfigureButton, SIGNAL( clicked() ), SLOT( configure() ) ); + + connect( mListView, SIGNAL( selectionChanged( QListViewItem* ) ), + SLOT( selectionChanged( QListViewItem* ) ) ); + connect( mListView, SIGNAL( clicked( QListViewItem* ) ), + SLOT( slotWidChanged() ) ); + + load(); +// usrReadConfig(); + selectionChanged( 0 ); +} + +void KOPrefsDialogPlugins::usrReadConfig() +{ + mListView->clear(); + KTrader::OfferList plugins = KOCore::self()->availablePlugins(); + plugins += KOCore::self()->availableParts(); + + QStringList selectedPlugins = KOPrefs::instance()->mSelectedPlugins; + + KTrader::OfferList::ConstIterator it; + for( it = plugins.begin(); it != plugins.end(); ++it ) { + QCheckListItem *item = new PluginItem( mListView, *it ); + if ( selectedPlugins.find( (*it)->desktopEntryName() ) != + selectedPlugins.end() ) { + item->setOn( true ); + } + } +} + +void KOPrefsDialogPlugins::usrWriteConfig() +{ + QStringList selectedPlugins; + + PluginItem *item = static_cast<PluginItem *>( mListView->firstChild() ); + while( item ) { + if( item->isOn() ) { + selectedPlugins.append( item->service()->desktopEntryName() ); + } + item = static_cast<PluginItem *>( item->nextSibling() ); + } + KOPrefs::instance()->mSelectedPlugins = selectedPlugins; +} + +void KOPrefsDialogPlugins::configure() +{ + PluginItem *item = static_cast<PluginItem *>( mListView->selectedItem() ); + if ( !item ) return; + + KOrg::Plugin *plugin = KOCore::self()->loadPlugin( item->service() ); + + if ( plugin ) { + plugin->configure( this ); + delete plugin; + } else { + KMessageBox::sorry( this, i18n( "Unable to configure this plugin" ), + "PluginConfigUnable" ); + } +} + +void KOPrefsDialogPlugins::selectionChanged( QListViewItem *i ) +{ + PluginItem *item = dynamic_cast<PluginItem*>( i ); + if ( !item ) { + mConfigureButton->setEnabled( false ); + mDescription->setText( QString::null ); + return; + } + + QVariant variant = item->service()->property( "X-KDE-KOrganizer-HasSettings" ); + + bool hasSettings = true; + if ( variant.isValid() ) + hasSettings = variant.toBool(); + + mDescription->setText( item->service()->comment() ); + mConfigureButton->setEnabled( hasSettings ); + + slotWidChanged(); +} + +extern "C" +{ + KCModule *create_korganizerconfigplugins( QWidget *parent, const char * ) + { + return new KOPrefsDialogPlugins( parent, + "kcmkorganizerplugins" ); + } +} + + +extern "C" +{ + KCModule *create_korgdesignerfields( QWidget *parent, const char * ) { + return new KOPrefsDesignerFields( parent, "kcmkorgdesignerfields" ); + } +} + +KOPrefsDesignerFields::KOPrefsDesignerFields( QWidget *parent, const char *name ) + : KCMDesignerFields( parent, name ) +{ +} + +QString KOPrefsDesignerFields::localUiDir() +{ + QString dir = locateLocal( "data", "korganizer/designer/event/"); + kdDebug() << "KOPrefsDesignerFields::localUiDir(): " << dir << endl; + return dir; +} + +QString KOPrefsDesignerFields::uiPath() +{ + return "korganizer/designer/event/"; +} + +void KOPrefsDesignerFields::writeActivePages( const QStringList &activePages ) +{ + KOPrefs::instance()->setActiveDesignerFields( activePages ); + KOPrefs::instance()->writeConfig(); +} + +QStringList KOPrefsDesignerFields::readActivePages() +{ + return KOPrefs::instance()->activeDesignerFields(); +} + +QString KOPrefsDesignerFields::applicationName() +{ + return "KORGANIZER"; +} + +#include "koprefsdialog.moc" diff --git a/korganizer/koprefsdialog.h b/korganizer/koprefsdialog.h new file mode 100644 index 000000000..797c50e5b --- /dev/null +++ b/korganizer/koprefsdialog.h @@ -0,0 +1,152 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2000,2001,2002,2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (c) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOPREFSDIALOG_H +#define KOPREFSDIALOG_H + +#include <libkdepim/kprefsdialog.h> +#include <libkdepim/kcmdesignerfields.h> + +#include <qdict.h> + +class QLineEdit; +class QLabel; +class QSpinBox; +class QComboBox; +class KColorButton; +class KPushButton; +class QColor; +class QListView; + +class KDE_EXPORT KOPrefsDialogMain : public KPrefsModule +{ + Q_OBJECT + public: + KOPrefsDialogMain( QWidget *parent, const char *name ); + + protected slots: + void toggleEmailSettings( bool on ); + private: + QWidget *mUserEmailSettings; +}; + +class KDE_EXPORT KOPrefsDialogColors : public KPrefsModule +{ + Q_OBJECT + public: + KOPrefsDialogColors( QWidget *parent, const char *name ); + + protected: + void usrWriteConfig(); + void usrReadConfig(); + + protected slots: + void updateCategories(); + void setCategoryColor(); + void updateCategoryColor(); + + void updateResources(); + void setResourceColor(); + void updateResourceColor(); + private: + QComboBox *mCategoryCombo; + KColorButton *mCategoryButton; + QDict<QColor> mCategoryDict; + + QComboBox *mResourceCombo; + KColorButton *mResourceButton; + QDict<QColor> mResourceDict; + //For translation Identifier <->idx in Combo + QStringList mResourceIdentifier; +}; + +class KDE_EXPORT KOPrefsDialogGroupScheduling : public KPrefsModule +{ + Q_OBJECT + public: + KOPrefsDialogGroupScheduling( QWidget *parent, const char *name ); + + protected: + void usrReadConfig(); + void usrWriteConfig(); + + protected slots: + void addItem(); + void removeItem(); + void updateItem(); + void updateInput(); + + private: + QListView *mAMails; + QLineEdit *aEmailsEdit; +}; + +class KOGroupwarePrefsPage; + +class KDE_EXPORT KOPrefsDialogGroupwareScheduling : public KPrefsModule +{ + Q_OBJECT + public: + KOPrefsDialogGroupwareScheduling( QWidget *parent, const char *name ); + + protected: + void usrReadConfig(); + void usrWriteConfig(); + + private: + KOGroupwarePrefsPage* mGroupwarePage; +}; + +class KDE_EXPORT KOPrefsDialogPlugins : public KPrefsModule +{ + Q_OBJECT + public: + KOPrefsDialogPlugins( QWidget *parent, const char *name ); + + protected slots: + void usrReadConfig(); + void usrWriteConfig(); + void configure(); + void selectionChanged( QListViewItem* ); + + private: + void buildList(); + QListView *mListView; + QLabel *mDescription; + KPushButton *mConfigureButton; +}; + +class KDE_EXPORT KOPrefsDesignerFields : public KPIM::KCMDesignerFields +{ + public: + KOPrefsDesignerFields( QWidget *parent = 0, const char *name = 0 ); + + protected: + QString localUiDir(); + QString uiPath(); + void writeActivePages( const QStringList & ); + QStringList readActivePages(); + QString applicationName(); +}; + +#endif diff --git a/korganizer/korgac/Makefile.am b/korganizer/korgac/Makefile.am new file mode 100644 index 000000000..ac56f3640 --- /dev/null +++ b/korganizer/korgac/Makefile.am @@ -0,0 +1,28 @@ +INCLUDES= -I$(top_srcdir) -I$(top_srcdir)/korganizer $(all_includes) + +bin_PROGRAMS = korgac + +korgac_LDFLAGS = $(all_libraries) $(KDE_RPATH) +korgac_LDADD = $(LIB_KDEUI) \ + $(top_builddir)/korganizer/libkorganizer_eventviewer.la +korgac_SOURCES = korgacmain.cpp alarmdialog.cpp \ + alarmdockwindow.cpp koalarmclient.cpp \ + alarmclientiface.skel + +check_PROGRAMS = testalarmdlg + +testalarmdlg_LDFLAGS = $(all_libraries) $(KDE_RPATH) +testalarmdlg_LDADD = $(LIB_KDEUI) $(top_builddir)/libkcal/libkcal.la \ + $(top_builddir)/korganizer/libkorganizer_eventviewer.la +testalarmdlg_SOURCES = testalarmdlg.cpp alarmdialog.cpp + +noinst_HEADERS = alarmclientiface.h alarmdialog.h \ + alarmdockwindow.h koalarmclient.h + +METASOURCES = AUTO + +SUBDIRS = pixmaps + +autostart_DATA = korgac.desktop +autostartdir = $(datadir)/autostart + diff --git a/korganizer/korgac/alarmclientiface.h b/korganizer/korgac/alarmclientiface.h new file mode 100644 index 000000000..c4edd9f43 --- /dev/null +++ b/korganizer/korgac/alarmclientiface.h @@ -0,0 +1,40 @@ +/* + This file is part of the KOrganizer alarm client. + + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef ALARMCLIENTIFACE_H +#define ALARMCLIENTIFACE_H + +#include <dcopobject.h> +#include <qstringlist.h> + +class AlarmClientIface : virtual public DCOPObject +{ + K_DCOP + k_dcop: + virtual ASYNC quit() = 0; + + virtual ASYNC forceAlarmCheck() = 0; + virtual ASYNC dumpDebug() = 0; + virtual QStringList dumpAlarms() = 0; + + virtual void debugShowDialog() = 0; +}; + +#endif diff --git a/korganizer/korgac/alarmdialog.cpp b/korganizer/korgac/alarmdialog.cpp new file mode 100644 index 000000000..68e1822dc --- /dev/null +++ b/korganizer/korgac/alarmdialog.cpp @@ -0,0 +1,444 @@ +/* + This file is part of the KOrganizer alarm daemon. + + Copyright (c) 2000,2003 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qhbox.h> +#include <qvbox.h> +#include <qlabel.h> +#include <qfile.h> +#include <qspinbox.h> +#include <qlayout.h> +#include <qpushbutton.h> +#include <qcstring.h> +#include <qdatastream.h> + +#include <kapplication.h> +#include <kconfig.h> +#include <kiconloader.h> +#include <dcopclient.h> +#include <klocale.h> +#include <kprocess.h> +#include <kaudioplayer.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <knotifyclient.h> +#include <kcombobox.h> +#include <klistview.h> +#include <kwin.h> +#include <klockfile.h> + +#include <libkcal/event.h> + +#include "koeventviewer.h" + +#include "alarmdialog.h" +#include "alarmdialog.moc" + +class AlarmListItem : public KListViewItem +{ + public: + AlarmListItem( Incidence *incidence, QListView *parent ) : + KListViewItem( parent ), + mIncidence( incidence->clone() ), + mNotified( false ) + {} + + ~AlarmListItem() + { + delete mIncidence; + } + + Incidence *mIncidence; + QDateTime mRemindAt; + bool mNotified; +}; + +typedef QValueList<AlarmListItem*> ItemList; + +AlarmDialog::AlarmDialog( QWidget *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) +{ + KGlobal::iconLoader()->addAppDir( "kdepim" ); + setButtonOK( i18n( "Dismiss" ) ); + + QWidget *topBox = plainPage(); + QBoxLayout *topLayout = new QVBoxLayout( topBox ); + topLayout->setSpacing( spacingHint() ); + + QLabel *label = new QLabel( i18n("The following events triggered reminders:"), + topBox ); + topLayout->addWidget( label ); + + mIncidenceListView = new KListView( topBox ); + mIncidenceListView->addColumn( i18n( "Summary" ) ); + mIncidenceListView->addColumn( i18n( "Due" ) ); + mIncidenceListView->setAllColumnsShowFocus( true ); + mIncidenceListView->setSelectionMode( QListView::Extended ); + topLayout->addWidget( mIncidenceListView ); + connect( mIncidenceListView, SIGNAL(selectionChanged()), SLOT(updateButtons()) ); + connect( mIncidenceListView, SIGNAL(doubleClicked(QListViewItem*)), SLOT(slotUser2()) ); + connect( mIncidenceListView, SIGNAL(currentChanged(QListViewItem*)), SLOT(showDetails()) ); + connect( mIncidenceListView, SIGNAL(selectionChanged()), SLOT(showDetails()) ); + + mDetailView = new KOEventViewer( topBox ); + topLayout->addWidget( mDetailView ); + + QHBox *suspendBox = new QHBox( topBox ); + suspendBox->setSpacing( spacingHint() ); + topLayout->addWidget( suspendBox ); + + QLabel *l = new QLabel( i18n("Suspend &duration:"), suspendBox ); + mSuspendSpin = new QSpinBox( 1, 9999, 1, suspendBox ); + mSuspendSpin->setValue( 5 ); // default suspend duration + l->setBuddy( mSuspendSpin ); + + mSuspendUnit = new KComboBox( suspendBox ); + mSuspendUnit->insertItem( i18n("minute(s)") ); + mSuspendUnit->insertItem( i18n("hour(s)") ); + mSuspendUnit->insertItem( i18n("day(s)") ); + mSuspendUnit->insertItem( i18n("week(s)") ); + connect( &mSuspendTimer, SIGNAL(timeout()), SLOT(wakeUp()) ); + + // showButton( User2/*3*/, false ); + + setMinimumSize( 300, 200 ); +} + +AlarmDialog::~AlarmDialog() +{ + mIncidenceListView->clear(); +} + +void AlarmDialog::addIncidence( Incidence *incidence, const QDateTime &reminderAt ) +{ + AlarmListItem *item = new AlarmListItem( incidence, mIncidenceListView ); + item->setText( 0, incidence->summary() ); + item->mRemindAt = reminderAt; + Todo *todo; + if ( dynamic_cast<Event*>( incidence ) ) { + item->setPixmap( 0, SmallIcon( "appointment" ) ); + if ( incidence->doesRecur() ) { + QDateTime 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 )) ) { + item->setPixmap( 0, SmallIcon( "todo" ) ); + item->setText( 1, todo->dtDueStr() ); + } + if ( activeCount() == 1 ) {// previously empty + mIncidenceListView->clearSelection(); + item->setSelected( true ); + } + showDetails(); +} + +void AlarmDialog::slotOk() +{ + ItemList selection = selectedItems(); + for ( ItemList::Iterator it = selection.begin(); it != selection.end(); ++it ) { + if ( (*it)->itemBelow() ) + (*it)->itemBelow()->setSelected( true ); + else if ( (*it)->itemAbove() ) + (*it)->itemAbove()->setSelected( true ); + delete *it; + } + if ( activeCount() == 0 ) + accept(); + else { + updateButtons(); + showDetails(); + } + emit reminderCount( activeCount() ); +} + +void AlarmDialog::slotUser1() +{ + dismissAll(); +} + +void AlarmDialog::suspend() +{ + if ( !isVisible() ) + return; + + int unit=1; + switch (mSuspendUnit->currentItem()) { + case 3: // weeks + unit *= 7; + case 2: // days + unit *= 24; + case 1: // hours + unit *= 60; + case 0: // minutes + unit *= 60; + default: + break; + } + + for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) { + AlarmListItem * item = static_cast<AlarmListItem*>( it.current() ); + if ( item->isSelected() && item->isVisible() ) { + item->setVisible( false ); + item->setSelected( false ); + item->mRemindAt = QDateTime::currentDateTime().addSecs( unit * mSuspendSpin->value() ); + item->mNotified = false; + } + } + + setTimer(); + if ( activeCount() == 0 ) + accept(); + else { + updateButtons(); + showDetails(); + } + emit reminderCount( activeCount() ); +} + +void AlarmDialog::setTimer() +{ + int nextReminderAt = -1; + for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) { + AlarmListItem * item = static_cast<AlarmListItem*>( it.current() ); + if ( item->mRemindAt > QDateTime::currentDateTime() ) { + int secs = QDateTime::currentDateTime().secsTo( item->mRemindAt ); + nextReminderAt = nextReminderAt <= 0 ? secs : QMIN( nextReminderAt, secs ); + } + } + + if ( nextReminderAt >= 0 ) { + mSuspendTimer.stop(); + mSuspendTimer.start( 1000 * (nextReminderAt + 1), true ); + } +} + +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", QString::null ) ) + KMessageBox::error( 0, i18n("Could not start KOrganizer.") ); + } + + kapp->dcopClient()->send( "korganizer", "KOrganizerIface", + "editIncidence(QString)", + incidence->uid() ); + + // get desktop # where korganizer (or kontact) runs + QByteArray replyData; + QCString 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; + QDataStream 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() +{ + suspend(); +} + +void AlarmDialog::dismissAll() +{ + for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ) { + AlarmListItem *item = static_cast<AlarmListItem*>( it.current() ); + if ( !item->isVisible() ) { + ++it; + continue; + } + delete item; + } + setTimer(); + accept(); + emit reminderCount( activeCount() ); +} + +void AlarmDialog::show() +{ + mIncidenceListView->clearSelection(); + if ( mIncidenceListView->firstChild() ) + mIncidenceListView->firstChild()->setSelected( true ); + updateButtons(); + KDialogBase::show(); + KWin::setState( winId(), NET::KeepAbove ); + KWin::setOnAllDesktops( winId(), true ); + eventNotification(); +} + +void AlarmDialog::eventNotification() +{ + bool beeped = false, found = false; + + QValueList<AlarmListItem*> list; + for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) { + AlarmListItem *item = static_cast<AlarmListItem*>( it.current() ); + if ( !item->isVisible() || item->mNotified ) + continue; + found = true; + item->mNotified = true; + Alarm::List alarms = item->mIncidence->alarms(); + Alarm::List::ConstIterator it; + for ( it = alarms.begin(); it != alarms.end(); ++it ) { + Alarm *alarm = *it; + // FIXME: Check whether this should be done for all multiple alarms + if (alarm->type() == Alarm::Procedure) { + // FIXME: Add a message box asking whether the procedure should really be executed + kdDebug(5890) << "Starting program: '" << alarm->programFile() << "'" << endl; + KProcess proc; + proc << QFile::encodeName(alarm->programFile()); + proc.start(KProcess::DontCare); + } + else if (alarm->type() == Alarm::Audio) { + beeped = true; + KAudioPlayer::play(QFile::encodeName(alarm->audioFile())); + } + } + } + + if ( !beeped && found ) { + KNotifyClient::beep(); + } +} + +void AlarmDialog::wakeUp() +{ + bool activeReminders = false; + for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) { + AlarmListItem * item = static_cast<AlarmListItem*>( it.current() ); + if ( item->mRemindAt <= QDateTime::currentDateTime() ) { + if ( !item->isVisible() ) { + item->setVisible( true ); + item->setSelected( false ); + } + activeReminders = true; + } else { + item->setVisible( false ); + } + } + + if ( activeReminders ) + show(); + setTimer(); + showDetails(); + emit reminderCount( activeCount() ); +} + +void AlarmDialog::slotSave() +{ + KConfig *config = kapp->config(); + KLockFile::Ptr lock = config->lockFile(); + if ( lock.data()->lock() != KLockFile::LockOK ) + return; + + config->setGroup( "General" ); + int numReminders = config->readNumEntry("Reminders", 0); + + for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) { + AlarmListItem * item = static_cast<AlarmListItem*>( it.current() ); + config->setGroup( QString("Incidence-%1").arg(numReminders) ); + config->writeEntry( "UID", item->mIncidence->uid() ); + config->writeEntry( "RemindAt", item->mRemindAt ); + ++numReminders; + } + + config->setGroup( "General" ); + config->writeEntry( "Reminders", numReminders ); + config->sync(); + lock.data()->unlock(); +} + +void AlarmDialog::updateButtons() +{ + ItemList selection = selectedItems(); + enableButton( User2, selection.count() == 1 ); + enableButton( Ok, selection.count() > 0 ); + enableButton( User3, selection.count() > 0 ); +} + +QValueList< AlarmListItem * > AlarmDialog::selectedItems() const +{ + QValueList<AlarmListItem*> list; + for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) { + if ( it.current()->isSelected() ) + list.append( static_cast<AlarmListItem*>( it.current() ) ); + } + return list; +} + +int AlarmDialog::activeCount() +{ + int count = 0; + for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) { + AlarmListItem * item = static_cast<AlarmListItem*>( it.current() ); + if ( item->isVisible() ) + ++count; + } + return count; +} + +void AlarmDialog::suspendAll() +{ + mIncidenceListView->clearSelection(); + for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) { + if ( it.current()->isVisible() ) + it.current()->setSelected( true ); + } + suspend(); +} + +void AlarmDialog::showDetails() +{ + mDetailView->clearEvents( true ); + mDetailView->clear(); + AlarmListItem *item = static_cast<AlarmListItem*>( mIncidenceListView->currentItem() ); + if ( !item || !item->isVisible() ) + return; + mDetailView->appendIncidence( item->mIncidence ); +} diff --git a/korganizer/korgac/alarmdialog.h b/korganizer/korgac/alarmdialog.h new file mode 100644 index 000000000..085ae8a9b --- /dev/null +++ b/korganizer/korgac/alarmdialog.h @@ -0,0 +1,86 @@ +/* + This file is part of the KDE alarm daemon. + Copyright (c) 2000 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef ALARMDIALOG_H +#define ALARMDIALOG_H +// +// Alarm dialog. +// +#include <qtimer.h> +#include <qdatetime.h> + +#include <kdialogbase.h> + +#include <libkcal/event.h> +#include <libkcal/calendarlocal.h> + +using namespace KCal; + +class KOEventViewer; +class QSpinBox; +class KComboBox; +class KListView; +class AlarmListItem; + +class AlarmDialog : public KDialogBase { + Q_OBJECT + public: + AlarmDialog( QWidget *parent = 0, const char *name = 0 ); + virtual ~AlarmDialog(); + + void addIncidence( Incidence *incidence, const QDateTime &reminderAt ); + void eventNotification(); + + public slots: + void slotOk(); + void slotUser1(); + void slotUser2(); + void slotUser3(); + void slotSave(); + void wakeUp(); + void show(); + void suspend(); + void suspendAll(); + void dismissAll(); + + signals: + void reminderCount( int count ); + + private slots: + void updateButtons(); + void showDetails(); + + private: + bool startKOrganizer(); + void setTimer(); + int activeCount(); + QValueList<AlarmListItem*> selectedItems() const; + + KListView *mIncidenceListView; + KOEventViewer *mDetailView; + + QSpinBox *mSuspendSpin; + KComboBox *mSuspendUnit; + QTimer mSuspendTimer; +}; + +#endif diff --git a/korganizer/korgac/alarmdockwindow.cpp b/korganizer/korgac/alarmdockwindow.cpp new file mode 100644 index 000000000..5f2c419c7 --- /dev/null +++ b/korganizer/korgac/alarmdockwindow.cpp @@ -0,0 +1,195 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "alarmdockwindow.h" +#include "koalarmclient.h" + +#include <kapplication.h> +#include <kdebug.h> +#include <kdeversion.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kconfig.h> +#include <kurl.h> +#include <kstandarddirs.h> +#include <dcopclient.h> +#include <kpopupmenu.h> +#include <kmessagebox.h> +#include <kaction.h> +#include <kstdaction.h> + +#include <qtooltip.h> +#include <qfile.h> + +#include <stdlib.h> + +AlarmDockWindow::AlarmDockWindow( const char *name ) + : KSystemTray( 0, name ) +{ + // Read the autostart status from the config file + KConfig *config = kapp->config(); + config->setGroup("General"); + bool autostart = config->readBoolEntry( "Autostart", true ); + bool alarmsEnabled = config->readBoolEntry( "Enabled", true ); + + mName = i18n( "KOrganizer Reminder Daemon" ); + setCaption( mName ); + + // Set up icons + KGlobal::iconLoader()->addAppDir( "korgac" ); + mPixmapEnabled = loadIcon( "korgac" ); + mPixmapDisabled = loadIcon( "korgac_disabled" ); + + setPixmap( alarmsEnabled ? mPixmapEnabled : mPixmapDisabled ); + + // Set up the context menu + mSuspendAll = contextMenu()->insertItem( i18n("Suspend All"), this, SLOT( slotSuspendAll() ) ); + mDismissAll = contextMenu()->insertItem( i18n("Dismiss All"), this, SLOT( slotDismissAll() ) ); + contextMenu()->setItemEnabled( mSuspendAll, false ); + contextMenu()->setItemEnabled( mDismissAll, false ); + + contextMenu()->insertSeparator(); + mAlarmsEnabledId = contextMenu()->insertItem( i18n("Reminders Enabled"), this, + SLOT( toggleAlarmsEnabled() ) ); + mAutostartId = contextMenu()->insertItem( i18n("Start Reminder Daemon at Login"), this, + SLOT( toggleAutostart() ) ); + contextMenu()->setItemChecked( mAutostartId, autostart ); + contextMenu()->setItemChecked( mAlarmsEnabledId, alarmsEnabled ); + + // Disable standard quit behaviour. We have to intercept the quit even, if the + // main window is hidden. + KActionCollection *ac = actionCollection(); + const char *quitName = KStdAction::name( KStdAction::Quit ); + KAction *quit = ac->action( quitName ); + if ( !quit ) { + kdDebug(5890) << "No Quit standard action." << endl; + } else { +#if KDE_IS_VERSION(3,3,90) + quit->disconnect( SIGNAL( activated() ), this, + SLOT( maybeQuit() ) ); + connect( quit, SIGNAL( activated() ), SLOT( slotQuit() ) ); + } +#else //FIXME: remove for KDE 4.0 + quit->disconnect( SIGNAL( activated() ), qApp, + SLOT( closeAllWindows() ) ); + } + connect( this, SIGNAL( quitSelected() ), SLOT( slotQuit() ) ); +#endif + + QToolTip::add(this, mName ); +} + +AlarmDockWindow::~AlarmDockWindow() +{ +} + +void AlarmDockWindow::slotUpdate( int reminders ) +{ + QToolTip::remove( this ); + if ( reminders > 0 ) + { + QToolTip::add( this, i18n( "There is 1 active reminder.", + "There are %n active reminders.", reminders ) ); + contextMenu()->setItemEnabled( mSuspendAll, true ); + contextMenu()->setItemEnabled( mDismissAll, true ); + } + else + { + QToolTip::add( this, mName ); + contextMenu()->setItemEnabled( mSuspendAll, false ); + contextMenu()->setItemEnabled( mDismissAll, false ); + } +} + +void AlarmDockWindow::toggleAlarmsEnabled() +{ + kdDebug(5890) << "AlarmDockWindow::toggleAlarmsEnabled()" << endl; + + KConfig *config = kapp->config(); + config->setGroup( "General" ); + + bool enabled = !contextMenu()->isItemChecked( mAlarmsEnabledId ); + contextMenu()->setItemChecked( mAlarmsEnabledId, enabled ); + setPixmap( enabled ? mPixmapEnabled : mPixmapDisabled ); + + config->writeEntry( "Enabled", enabled ); + config->sync(); +} + +void AlarmDockWindow::toggleAutostart() +{ + bool autostart = !contextMenu()->isItemChecked( mAutostartId ); + + enableAutostart( autostart ); +} + +void AlarmDockWindow::slotSuspendAll() +{ + emit suspendAllSignal(); +} + +void AlarmDockWindow::slotDismissAll() +{ + emit dismissAllSignal(); +} + +void AlarmDockWindow::enableAutostart( bool enable ) +{ + KConfig *config = kapp->config(); + config->setGroup( "General" ); + config->writeEntry( "Autostart", enable ); + config->sync(); + + contextMenu()->setItemChecked( mAutostartId, enable ); +} + +void AlarmDockWindow::mousePressEvent( QMouseEvent *e ) +{ + if ( e->button() == LeftButton ) { + kapp->startServiceByDesktopName( "korganizer", QString::null ); + } else { + KSystemTray::mousePressEvent( e ); + } +} + +//void AlarmDockWindow::closeEvent( QCloseEvent * ) +void AlarmDockWindow::slotQuit() +{ + int result = KMessageBox::questionYesNoCancel( this, + i18n("Do you want to start the KOrganizer reminder daemon at login " + "(note that you will not get reminders whilst the daemon is not running)?"), + i18n("Close KOrganizer Reminder Daemon"), + i18n("Start"), i18n("Do Not Start"), + QString::fromLatin1("AskForStartAtLogin") + ); + + bool autostart = true; + if ( result == KMessageBox::No ) autostart = false; + enableAutostart( autostart ); + + if ( result != KMessageBox::Cancel ) + emit quitSignal(); +} + +#include "alarmdockwindow.moc" diff --git a/korganizer/korgac/alarmdockwindow.h b/korganizer/korgac/alarmdockwindow.h new file mode 100644 index 000000000..5671b92f7 --- /dev/null +++ b/korganizer/korgac/alarmdockwindow.h @@ -0,0 +1,70 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef ALARMDOCKWINDOW_H +#define ALARMDOCKWINDOW_H + +#include <ksystemtray.h> + +#include <qpixmap.h> + +class AlarmDockWindow : public KSystemTray +{ + Q_OBJECT + public: + AlarmDockWindow( const char *name = 0 ); + virtual ~AlarmDockWindow(); + + void enableAutostart( bool enabled ); + + public slots: + void toggleAlarmsEnabled(); + void toggleAutostart(); + void slotUpdate( int reminders ); + + signals: + void quitSignal(); + void suspendAllSignal(); + void dismissAllSignal(); + + protected: + void mousePressEvent( QMouseEvent * ); +// void closeEvent( QCloseEvent * ); + + protected slots: + void slotQuit(); + void slotSuspendAll(); + void slotDismissAll(); + + private: + QPixmap mPixmapEnabled; + QPixmap mPixmapDisabled; + QString mName; + + int mAlarmsEnabledId; + int mAutostartId; + int mSuspendAll; + int mDismissAll; +}; + +#endif diff --git a/korganizer/korgac/koalarmclient.cpp b/korganizer/korgac/koalarmclient.cpp new file mode 100644 index 000000000..c4ef2de82 --- /dev/null +++ b/korganizer/korgac/koalarmclient.cpp @@ -0,0 +1,210 @@ +/* + KOrganizer Alarm Daemon Client. + + This file is part of KOrganizer. + + Copyright (c) 2002,2003 Cornelius Schumacher + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "koalarmclient.h" + +#include "alarmdockwindow.h" +#include "alarmdialog.h" + +#include <libkcal/calendarresources.h> + +#include <kstandarddirs.h> +#include <kdebug.h> +#include <klocale.h> +#include <kapplication.h> +#include <kwin.h> + +#include <qpushbutton.h> + +KOAlarmClient::KOAlarmClient( QObject *parent, const char *name ) + : DCOPObject( "ac" ), QObject( parent, name ), mDialog( 0 ) +{ + kdDebug(5890) << "KOAlarmClient::KOAlarmClient()" << endl; + + mDocker = new AlarmDockWindow; + mDocker->show(); + connect( this, SIGNAL( reminderCount( int ) ), mDocker, SLOT( slotUpdate( int ) ) ); + connect( mDocker, SIGNAL( quitSignal() ), SLOT( slotQuit() ) ); + + KConfig c( locate( "config", "korganizerrc" ) ); + c.setGroup( "Time & Date" ); + QString tz = c.readEntry( "TimeZoneId" ); + kdDebug(5890) << "TimeZone: " << tz << endl; + + mCalendar = new CalendarResources( tz ); + mCalendar->readConfig(); + mCalendar->load(); + + connect( &mCheckTimer, SIGNAL( timeout() ), SLOT( checkAlarms() ) ); + + KConfig *config = kapp->config(); + config->setGroup( "Alarms" ); + int interval = config->readNumEntry( "Interval", 60 ); + kdDebug(5890) << "KOAlarmClient check interval: " << interval << " seconds." + << endl; + mLastChecked = config->readDateTimeEntry( "CalendarsLastChecked" ); + + // load reminders that were active when quitting + config->setGroup( "General" ); + int numReminders = config->readNumEntry( "Reminders", 0 ); + for ( int i=1; i<=numReminders; ++i ) + { + QString group( QString( "Incidence-%1" ).arg( i ) ); + config->setGroup( group ); + QString uid = config->readEntry( "UID" ); + QDateTime dt = config->readDateTimeEntry( "RemindAt" ); + if ( !uid.isEmpty() ) + createReminder( mCalendar->incidence( uid ), dt ); + config->deleteGroup( group ); + } + config->setGroup( "General" ); + if (numReminders) { + config->writeEntry( "Reminders", 0 ); + config->sync(); + } + + checkAlarms(); + mCheckTimer.start( 1000 * interval ); // interval in seconds +} + +KOAlarmClient::~KOAlarmClient() +{ + delete mCalendar; + delete mDocker; + delete mDialog; +} + +void KOAlarmClient::checkAlarms() +{ + KConfig *cfg = kapp->config(); + + cfg->setGroup( "General" ); + if ( !cfg->readBoolEntry( "Enabled", true ) ) return; + + QDateTime from = mLastChecked.addSecs( 1 ); + mLastChecked = QDateTime::currentDateTime(); + + kdDebug(5891) << "Check: " << from.toString() << " - " << mLastChecked.toString() << endl; + + QValueList<Alarm *> alarms = mCalendar->alarms( from, mLastChecked ); + + QValueList<Alarm *>::ConstIterator it; + for( it = alarms.begin(); it != alarms.end(); ++it ) { + kdDebug(5891) << "REMINDER: " << (*it)->parent()->summary() << endl; + Incidence *incidence = mCalendar->incidence( (*it)->parent()->uid() ); + createReminder( incidence, QDateTime::currentDateTime() ); + } +} + +void KOAlarmClient::createReminder( KCal::Incidence *incidence, QDateTime dt ) +{ + if ( !incidence ) + return; + + if ( !mDialog ) { + mDialog = new AlarmDialog(); + connect( mDialog, SIGNAL(reminderCount(int)), mDocker, SLOT(slotUpdate(int)) ); + connect( mDocker, SIGNAL(suspendAllSignal()), mDialog, SLOT(suspendAll()) ); + connect( mDocker, SIGNAL(dismissAllSignal()), mDialog, SLOT(dismissAll()) ); + connect( this, SIGNAL( saveAllSignal() ), mDialog, SLOT( slotSave() ) ); + } + + mDialog->addIncidence( incidence, dt ); + mDialog->wakeUp(); + saveLastCheckTime(); +} + +void KOAlarmClient::slotQuit() +{ + emit saveAllSignal(); + saveLastCheckTime(); + quit(); +} + +void KOAlarmClient::saveLastCheckTime() +{ + KConfigGroup cg( KGlobal::config(), "Alarms"); + cg.writeEntry( "CalendarsLastChecked", mLastChecked ); + KGlobal::config()->sync(); +} + +void KOAlarmClient::quit() +{ + kdDebug(5890) << "KOAlarmClient::quit()" << endl; + kapp->quit(); +} + +bool KOAlarmClient::commitData( QSessionManager& ) +{ + emit saveAllSignal(); + saveLastCheckTime(); + return true; +} + +void KOAlarmClient::forceAlarmCheck() +{ + checkAlarms(); + saveLastCheckTime(); +} + +void KOAlarmClient::dumpDebug() +{ + KConfig *cfg = kapp->config(); + + cfg->setGroup( "Alarms" ); + QDateTime lastChecked = cfg->readDateTimeEntry( "CalendarsLastChecked" ); + + kdDebug(5890) << "Last Check: " << lastChecked << endl; +} + +QStringList KOAlarmClient::dumpAlarms() +{ + QDateTime start = QDateTime( QDateTime::currentDateTime().date(), + QTime( 0, 0 ) ); + QDateTime end = start.addDays( 1 ).addSecs( -1 ); + + QStringList lst; + // Don't translate, this is for debugging purposes. + lst << QString("AlarmDeamon::dumpAlarms() from ") + start.toString()+ " to " + + end.toString(); + + QValueList<Alarm*> alarms = mCalendar->alarms( start, end ); + QValueList<Alarm*>::ConstIterator it; + for( it = alarms.begin(); it != alarms.end(); ++it ) { + Alarm *a = *it; + lst << QString(" ") + a->parent()->summary() + " (" + + a->time().toString() + ")"; + } + + return lst; +} + +void KOAlarmClient::debugShowDialog() +{ +// showAlarmDialog(); +} + +#include "koalarmclient.moc" diff --git a/korganizer/korgac/koalarmclient.h b/korganizer/korgac/koalarmclient.h new file mode 100644 index 000000000..241a3eda8 --- /dev/null +++ b/korganizer/korgac/koalarmclient.h @@ -0,0 +1,84 @@ +/* + KOrganizer Alarm Daemon Client. + + This file is part of KOrganizer. + + Copyright (c) 2002,2003 Cornelius Schumacher + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOALARMCLIENT_H +#define KOALARMCLIENT_H + +#include "alarmclientiface.h" + +#include <kapplication.h> + +#include <qtimer.h> +#include <qdatetime.h> + +class AlarmDialog; +class AlarmDockWindow; + +namespace KCal { +class CalendarResources; +class Incidence; +} + +class KOAlarmClient : public QObject, virtual public AlarmClientIface, public KSessionManaged +{ + Q_OBJECT + public: + KOAlarmClient( QObject *parent = 0, const char *name = 0 ); + ~KOAlarmClient(); + + bool commitData( QSessionManager & ); + + // DCOP interface + void quit(); + void forceAlarmCheck(); + void dumpDebug(); + QStringList dumpAlarms(); + + void debugShowDialog(); + + public slots: + void slotQuit(); + + protected slots: + void checkAlarms(); + + signals: + void reminderCount( int ); + void saveAllSignal(); + + private: + void createReminder( KCal::Incidence *incidence, QDateTime dt ); + void saveLastCheckTime(); + + AlarmDockWindow *mDocker; // the panel icon + KCal::CalendarResources *mCalendar; + + QDateTime mLastChecked; + QTimer mCheckTimer; + + AlarmDialog *mDialog; +}; + +#endif diff --git a/korganizer/korgac/korgac.desktop b/korganizer/korgac/korgac.desktop new file mode 100644 index 000000000..cad7d7e5e --- /dev/null +++ b/korganizer/korgac/korgac.desktop @@ -0,0 +1,98 @@ +# KDE Config File +[Desktop Entry] +Name=KOrganizer Reminder Client +Name[af]=KOrganizer herhinner kliënt +Name[ar]=زبون المنبه لِــ KOrganizer +Name[bg]=Аларма на KOrganizer +Name[ca]=Client de l'alarma de KOrganizer +Name[cs]=Klient upomínek KOrganizeru +Name[da]=KOrganizer-påmindelsesklient +Name[de]=KOrganizer Erinnerungsfunktion +Name[el]=Πελάτης υπενθύμισης του KOrganizer +Name[eo]=Alarmilo por Organizilo +Name[es]=Cliente de recordatorio para KOrganizer +Name[et]=KOrganizeri meeldetuletuse klientprogramm +Name[eu]=KOrganizer-en oroigarrien bezeroa +Name[fa]=کارخواه یادآوریکنندۀ KOrganizer +Name[fi]=KOrganizer-hälytysasiakas +Name[fr]=Client d'alarme de KOrganizer +Name[fy]=KOrganizer omtinkerdaemon +Name[gl]=Cliente de Lembranzas de KOrganizer +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 +Name[mk]=Клиент за потсетување во КОрганизатор +Name[nb]=KOrganizer klient for påminning +Name[nds]=KOrganizer-Anstöötgever +Name[ne]=केडीई आयोजक रिमाइन्डर क्लाइन्ट +Name[nl]=KOrganizer herinneringsdaemon +Name[nn]=Alarmklient for KOrganizer +Name[pl]=Klient przypominania KOrganizera +Name[pt]=Cliente de Avisos do KOrganizer +Name[pt_BR]=Cliente do Alarme do KOrganizer +Name[ru]=Уведомления KOrganizer +Name[sk]=Klient pripomienok pre KOrganizer +Name[sl]=Odjemalec za opomnik KOrganizerja +Name[sr]=Клијент подсетника KOrganizer-а +Name[sr@Latn]=Klijent podsetnika KOrganizer-a +Name[sv]=Korganizer-påminnelseklient +Name[tr]=KOrganizer Hatırlatma İstemcisi +Name[uk]=Клієнт нагадувань KOrganizer +Name[zh_CN]=KOrganizer 定时器客户端程序 +Name[zh_TW]=KOrganizer 提醒客戶端程式 +Exec=korgac --miniicon korganizer +Icon=korganizer +Type=Application +GenericName=KOrganizer Reminder Daemon Client +GenericName[af]=Korganizer herhinner bediener kliënt +GenericName[bg]=Демон за алармата на KOrganizer +GenericName[ca]=Client del dimoni d'alarma de KOrganizer +GenericName[cs]=Klient démona přípomínek KOrganizeru +GenericName[da]=KOrganizer-påmindelsesklient +GenericName[de]=Hintergrund-Erinnerungsfunktion für KOrganizer +GenericName[el]=Δαίμονας πελάτη υπενθύμισης του KOrganizer +GenericName[eo]=Kliento por la alarmo-demono de Organizilo +GenericName[es]=Cliente del daemon de recordatorio para KOrganizer +GenericName[et]=KOrganizeri meeldetuletusdeemoni klientprogramm +GenericName[eu]=KOrganizer-en oroigarrien deabruaren bezeroa +GenericName[fa]=کارخواه شبح یادآوری KOrganizer +GenericName[fi]=KOrganizer hälytyspalvelimen asiakas +GenericName[fr]=Client pour le démon d'alarme de KOrganizer +GenericName[fy]=KOrganizer omtinkerdaemon +GenericName[gl]=Daemon do Cliente de Lembranzas de KOrganizer +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 +GenericName[nb]=KOrganizer klient for påminningstjenesten +GenericName[nds]=Client för den Anstötendämoon vun KOrganizer +GenericName[ne]=केडीई आयोजक रिमाइन्डर डेइमन क्लाइन्ट +GenericName[nl]=KOrganizer herinneringsdaemon +GenericName[nn]=Alarmnisseklient for KOrganizer +GenericName[pl]=Klient demona przypominania KOrganizera +GenericName[pt]=Cliente do Servidor de Avisos do KOrganizer +GenericName[pt_BR]=Cliente do Servidor de Alarme do KOrganizer +GenericName[ru]=Клиент службы уведомлений KOrganizer +GenericName[sk]=Klient KOrganizer pre démona pripomienok +GenericName[sl]=Pritajeni odjemalec za opomnik KOrganizerja +GenericName[sr]=Клијент демона подсетника KOrganizer-а +GenericName[sr@Latn]=Klijent demona podsetnika KOrganizer-a +GenericName[sv]=Korganizer-alarmdemonklient +GenericName[tr]=KOrganizer Hatırlatma Servisi İstemcisi +GenericName[uk]=Демон клієнта нагадування для KOrganizer +GenericName[zh_CN]=KOrganizer 定时守护进程的客户端程序 +GenericName[zh_TW]=KOrganizr 提醒守護程式客戶端 +Terminal=false +X-KDE-autostart-after=panel +X-KDE-autostart-condition=korgacrc:General:Autostart:true +NoDisplay=true +OnlyShowIn=KDE; diff --git a/korganizer/korgac/korgacmain.cpp b/korganizer/korgac/korgacmain.cpp new file mode 100644 index 000000000..b4c9df7f6 --- /dev/null +++ b/korganizer/korgac/korgacmain.cpp @@ -0,0 +1,86 @@ +/* + This file is part of the KOrganizer alarm client. + + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <stdlib.h> + +#include <kglobal.h> +#include <kdebug.h> +#include <klocale.h> +#include <kcmdlineargs.h> +#include <kaboutdata.h> +#include <kuniqueapplication.h> + +#include "koalarmclient.h" + +class MyApp : public KUniqueApplication +{ + public: + MyApp() : mClient( 0 ) {} + int newInstance() + { + // Check if we already have a running alarm daemon widget + if ( mClient ) return 0; + + mClient = new KOAlarmClient; + + return 0; + } + + private: + KOAlarmClient *mClient; +}; + + +static const char korgacVersion[] = "0.9"; + +static const KCmdLineOptions options[] = +{ + { 0, 0, 0 } +}; + +int main( int argc, char **argv ) +{ + KLocale::setMainCatalogue( "korganizer" ); + KAboutData aboutData( "korgac", I18N_NOOP("KOrganizer Reminder Daemon"), + korgacVersion, I18N_NOOP("KOrganizer Reminder Daemon"), + KAboutData::License_GPL, + "(c) 2003 Cornelius Schumacher", + 0, "http://pim.kde.org" ); + aboutData.addAuthor( "Cornelius Schumacher", I18N_NOOP("Maintainer"), + "schumacher@kde.org" ); + aboutData.addAuthor( "Reinhold Kainhofer", I18N_NOOP("Maintainer"), + "kainhofer@kde.org" ); + + KCmdLineArgs::init( argc, argv, &aboutData ); + KCmdLineArgs::addCmdLineOptions( options ); + KUniqueApplication::addCmdLineOptions(); + + if ( !MyApp::start() ) exit( 0 ); + + MyApp app; + app.disableSessionManagement(); + KGlobal::locale()->insertCatalogue( "libkcal" ); + + return app.exec(); +} diff --git a/korganizer/korgac/pixmaps/Makefile.am b/korganizer/korgac/pixmaps/Makefile.am new file mode 100644 index 000000000..504e613ac --- /dev/null +++ b/korganizer/korgac/pixmaps/Makefile.am @@ -0,0 +1,2 @@ +korgacicondir = $(kde_datadir)/korgac/icons +korgacicon_ICON = AUTO diff --git a/korganizer/korgac/pixmaps/cr22-action-korgac.png b/korganizer/korgac/pixmaps/cr22-action-korgac.png Binary files differnew file mode 100644 index 000000000..304a02b10 --- /dev/null +++ b/korganizer/korgac/pixmaps/cr22-action-korgac.png diff --git a/korganizer/korgac/pixmaps/cr22-action-korgac_disabled.png b/korganizer/korgac/pixmaps/cr22-action-korgac_disabled.png Binary files differnew file mode 100644 index 000000000..fa1ae2852 --- /dev/null +++ b/korganizer/korgac/pixmaps/cr22-action-korgac_disabled.png diff --git a/korganizer/korgac/testalarmdlg.cpp b/korganizer/korgac/testalarmdlg.cpp new file mode 100644 index 000000000..69352a175 --- /dev/null +++ b/korganizer/korgac/testalarmdlg.cpp @@ -0,0 +1,71 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qwidget.h> + +#include <kaboutdata.h> +#include <kapplication.h> +#include <kdebug.h> +#include <klocale.h> +#include <kcmdlineargs.h> + +#include "alarmdialog.h" + +int main(int argc,char **argv) +{ + KAboutData aboutData("testkabc",I18N_NOOP("TestKabc"),"0.1"); + KCmdLineArgs::init(argc,argv,&aboutData); + + KApplication app; + + Event *e1 = new Event; + e1->setSummary( "This is a summary." ); + QDateTime now = QDateTime::currentDateTime(); + e1->setDtStart( now ); + 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" ); + + Todo *t1 = new Todo; + t1->setSummary( "To-do A" ); + t1->setDtDue( now ); + t1->newAlarm(); + + Event *e2 = new Event; + e2->setSummary( "This is another summary." ); + e2->setDtStart( now ); + e2->setDtEnd( now.addDays( 1 ) ); + e2->newAlarm(); + + AlarmDialog dlg; + app.setMainWidget( &dlg ); + dlg.addIncidence( e1, QDateTime::currentDateTime() ); + dlg.addIncidence( t1, QDateTime::currentDateTime() ); + dlg.addIncidence( e2, QDateTime::currentDateTime() ); + dlg.show(); + dlg.eventNotification(); + + app.exec(); +} diff --git a/korganizer/korganizer.cpp b/korganizer/korganizer.cpp new file mode 100644 index 000000000..87dc79f4f --- /dev/null +++ b/korganizer/korganizer.cpp @@ -0,0 +1,310 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1997, 1998, 1999 + Preston Brown (preston.brown@yale.edu) + Fester Zigterman (F.J.F.ZigtermanRustenburg@student.utwente.nl) + Ian Dawes (iadawes@globalserve.net) + Laszlo Boloni (boloni@cs.purdue.edu) + + Copyright (c) 2000-2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "korganizer.h" + +#include "komailclient.h" +#include "calendarview.h" +#include "koviewmanager.h" +#include "kodialogmanager.h" +#include "kowindowlist.h" +#include "koprefs.h" +#include "kocore.h" +#include "konewstuff.h" +#include "actionmanager.h" +#include "koglobals.h" +#include "alarmclient.h" +#include "resourceview.h" +#include "korganizerifaceimpl.h" + +#include <korganizer/part.h> + +#include <libkdepim/statusbarprogresswidget.h> +#include <libkdepim/progressdialog.h> + +#include <libkcal/calendarlocal.h> +#include <libkcal/calendarresources.h> +#include <libkcal/resourcecalendar.h> + +#include <kglobal.h> +#include <kdebug.h> +#include <kiconloader.h> +#include <kstandarddirs.h> +#include <kstdaccel.h> +#include <kfiledialog.h> +#include <kaction.h> +#include <kstdaction.h> +#include <kedittoolbar.h> +#include <ktempfile.h> +#include <kio/netaccess.h> +#include <kmessagebox.h> +#include <dcopclient.h> +#include <kprocess.h> +#include <kwin.h> +#include <ktip.h> +#include <kstdguiitem.h> +#include <kstatusbar.h> + +#include <qcursor.h> +#include <qtimer.h> +#include <qvbox.h> +#include <qfile.h> +#include <qlabel.h> +#include <qlayout.h> + +#include <stdlib.h> + +using namespace KParts; +#include "korganizer.moc" +using namespace KOrg; + +KOrganizer::KOrganizer( const char *name ) + : KParts::MainWindow( 0, name ), + KOrg::MainWindow() +{ + // Set this to be the group leader for all subdialogs - this means + // modal subdialogs will only affect this dialog, not the other windows + setWFlags( getWFlags() | WGroupLeader ); + + kdDebug(5850) << "KOrganizer::KOrganizer()" << endl; + KOCore::self()->addXMLGUIClient( this, this ); +// setMinimumSize(600,400); // make sure we don't get resized too small... + + mCalendarView = new CalendarView( this, "KOrganizer::CalendarView" ); + setCentralWidget(mCalendarView); + + mActionManager = new ActionManager( this, mCalendarView, this, this, false ); + (void)new KOrganizerIfaceImpl( mActionManager, this, "IfaceImpl" ); +} + +KOrganizer::~KOrganizer() +{ + delete mActionManager; + + KOCore::self()->removeXMLGUIClient( this ); +} + +void KOrganizer::init( bool document ) +{ + kdDebug(5850) << "KOrganizer::init() " + << ( document ? "hasDocument" : "resources" ) << endl; + + setHasDocument( document ); + + // Create calendar object, which manages all calendar information associated + // with this calendar view window. + if ( hasDocument() ) { + mActionManager->createCalendarLocal(); + } else { + mActionManager->createCalendarResources(); + } + + mActionManager->init(); + connect( mActionManager, SIGNAL( actionNew( const KURL & ) ), + SLOT( newMainWindow( const KURL & ) ) ); + + mActionManager->loadParts(); + + initActions(); + readSettings(); + + KStatusBar *bar = statusBar(); + + bar->insertItem( "", ID_GENERAL, 10 ); + connect( bar, SIGNAL( pressed( int ) ), SLOT( statusBarPressed( int ) ) ); + + KPIM::ProgressDialog *progressDialog = new KPIM::ProgressDialog( bar, this ); + progressDialog->hide(); + + KPIM::StatusbarProgressWidget *progressWidget; + progressWidget = new KPIM::StatusbarProgressWidget( progressDialog, bar ); + progressWidget->show(); + + bar->addWidget( progressWidget, 0, true ); + + connect( mActionManager->view(), SIGNAL( statusMessage( const QString & ) ), + SLOT( showStatusMessage( const QString & ) ) ); + + setStandardToolBarMenuEnabled( true ); + setTitle(); + + kdDebug(5850) << "KOrganizer::KOrganizer() done" << endl; +} + +void KOrganizer::newMainWindow( const KURL &url ) +{ + KOrganizer *korg = new KOrganizer(); + if ( url.isValid() || url.isEmpty() ) { + korg->init( true ); + if ( korg->openURL( url ) || url.isEmpty() ) { + korg->show(); + } else { + delete korg; + } + } else { + korg->init( false ); + korg->show(); + } +} + +void KOrganizer::readSettings() +{ + // read settings from the KConfig, supplying reasonable + // defaults where none are to be found + + KConfig *config = KOGlobals::self()->config(); + + mActionManager->readSettings(); + + config->sync(); +} + + +void KOrganizer::writeSettings() +{ + kdDebug(5850) << "KOrganizer::writeSettings" << endl; + + KConfig *config = KOGlobals::self()->config(); + + mActionManager->writeSettings(); + config->sync(); +} + + +void KOrganizer::initActions() +{ + + setInstance( KGlobal::instance() ); + + setXMLFile( "korganizerui.rc" ); + setStandardToolBarMenuEnabled( true ); + createStandardStatusBarAction(); + + KStdAction::keyBindings(guiFactory(), SLOT(configureShortcuts()), actionCollection()); + KStdAction::configureToolbars(this, SLOT(configureToolbars() ), actionCollection()); + KStdAction::quit( this, SLOT( close() ), actionCollection() ); + setAutoSaveSettings(); + + createGUI( 0 ); +} + +bool KOrganizer::queryClose() +{ + kdDebug(5850) << "KOrganizer::queryClose()" << endl; + + bool close = mActionManager->queryClose(); + + // Write configuration. I don't know if it really makes sense doing it this + // way, when having opened multiple calendars in different CalendarViews. + if ( close ) writeSettings(); + + return close; +} + +bool KOrganizer::queryExit() +{ + // Don't call writeSettings here, because filename isn't valid anymore. It is + // now called in queryClose. +// writeSettings(); + return true; +} + +void KOrganizer::statusBarPressed( int /*id*/ ) +{ +} + +void KOrganizer::showStatusMessage( const QString &message ) +{ + statusBar()->message(message,2000); +} + +bool KOrganizer::openURL( const KURL &url, bool merge ) +{ + return mActionManager->openURL( url, merge ); +} + +bool KOrganizer::saveURL() +{ + return mActionManager->saveURL(); +} + +bool KOrganizer::saveAsURL( const KURL & kurl ) +{ + return mActionManager->saveAsURL( kurl ) ; +} + +KURL KOrganizer::getCurrentURL() const +{ + return mActionManager->url(); +} + +void KOrganizer::saveProperties( KConfig *config ) +{ + return mActionManager->saveProperties( config ); +} + +void KOrganizer::readProperties( KConfig *config ) +{ + return mActionManager->readProperties( config ); +} + +KOrg::CalendarViewBase *KOrganizer::view() const +{ + return mActionManager->view(); +} + +void KOrganizer::setTitle() +{ +// kdDebug(5850) << "KOrganizer::setTitle" << endl; + + QString title; + if ( !hasDocument() ) { + title = i18n("Calendar"); + } else { + KURL url = mActionManager->url(); + + if ( !url.isEmpty() ) { + if ( url.isLocalFile() ) title = url.fileName(); + else title = url.prettyURL(); + } else { + title = i18n("New Calendar"); + } + + if ( mCalendarView->isReadOnly() ) { + title += " [" + i18n("read-only") + "]"; + } + } + + title += " - <" + mCalendarView->currentFilterName() + "> "; + + setCaption( title, !mCalendarView->isReadOnly() && + mCalendarView->isModified() ); +} diff --git a/korganizer/korganizer.desktop b/korganizer/korganizer.desktop new file mode 100644 index 000000000..2f717f7a4 --- /dev/null +++ b/korganizer/korganizer.desktop @@ -0,0 +1,150 @@ +[Desktop Entry] +MimeType=text/calendar;text/x-vcalendar; +Comment=Calendar and Scheduling Program +Comment[af]=Kalender en Skedulering Program +Comment[ar]=برنامج الجدولة والتقويم +Comment[bg]=Програма за календар и разписание +Comment[bs]=Kalendar i rokovnik +Comment[ca]=Un programa de calendari i planificació +Comment[cs]=Kalendářový a plánovací program +Comment[cy]=Rhaglen Galendr a Drefnlennu +Comment[da]=Kalender- og planlægningsprogram +Comment[de]=Ein Kalender und Zeitplaner +Comment[el]=Πρόγραμμα ημερολογίου και προγραμματισμού +Comment[eo]=Kalendara kaj plana programo +Comment[es]=Calendario y planificador +Comment[et]=Kalendri ja ajakava haldamise rakendus +Comment[eu]=Egutegi eta antolaketa progrmaa +Comment[fa]=تقویم و برنامۀ زمانبندی +Comment[fi]=Kalenteri ja ajanhallintaohjelma +Comment[fr]=Calendrier et agenda personnel +Comment[fy]=Aginda- en ôfsprakenprogramma +Comment[gl]=Programa de Calendario e Axenda +Comment[he]=תוכניות לוח שנה ותזמון משימות +Comment[hi]=कैलेन्डर तथा समय-सारणी प्रोग्राम +Comment[hr]=Kalendar i rokovnik +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 +Comment[lv]=Kalendāra un Plānošanas Programma +Comment[mk]=Програма за календари и закажувања +Comment[ms]=Kalendar dan Program Penjadualan +Comment[mt]=Programm b' kalendarju w skeda +Comment[nb]=Et kalender- og tidsplanleggingsprogram +Comment[nds]=Kalenner un Tietplaner +Comment[ne]=क्यालेन्डर र कार्यतालिका कार्यक्रम +Comment[nl]=Agenda- en afsprakenprogramma +Comment[nn]=Kalender- og planleggingsprogram +Comment[nso]=Lenaneo la Peakanyo ya Tshupamabaka +Comment[pl]=Kalendarz i terminarz +Comment[pt]=Calendário e Programa de Escalonamento +Comment[pt_BR]=Programa de Calendário e Agenda +Comment[ro]=Program de planificare şi calendar +Comment[ru]=Календарь и личное расписание +Comment[se]=Kaleandar- ja plánenprográmma +Comment[sk]=Kalendár a plánovací program +Comment[sl]=Program za koledar in razporejanje +Comment[sr]=Календарски и планерски програм +Comment[sr@Latn]=Kalendarski i planerski program +Comment[sv]=Kalender- och schemaläggningsprogram +Comment[ta]=நாள்காட்டி மற்றும் திட்ட நிரல் +Comment[tg]=Тақвимот ва ҷадвали шахсӣ +Comment[th]=โปรแกรมจัดการบันทึกประจำวันและตารางการนัดหมาย +Comment[tr]=Takvim ve Zamanlama Programı +Comment[uk]=Програма календаря та розкладу +Comment[uz]=Kalendar va rejalashtirish dasturi +Comment[uz@cyrillic]=Календар ва режалаштириш дастури +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 +Comment[zh_CN]=日历和日程安排程序 +Comment[zh_TW]=行事曆與排程軟體 +Comment[zu]=Ikhalenda kanye Neprogramu Yokugcina isikhathi +Exec=korganizer %U +Icon=korganizer +Path= +DocPath=korganizer/index.html +Type=Application +Terminal=false +Name=KOrganizer +Name[af]=Korganizer +Name[cy]=KTrefnydd +Name[eo]=KOrganizilo +Name[hi]=के-आर्गेनाइज़र +Name[lv]=KOrganaizers +Name[mk]=КОрганизатор +Name[ne]=केडीई आयोजक +Name[nso]=KMokopanyi +Name[pl]=Organizator +Name[sv]=Korganizer +Name[ta]=கேஅமைப்பாளர் +Name[ven]=Mulugisi wa K +Name[zh_TW]=KOrganizer 行事曆 +GenericName=Personal Organizer +GenericName[af]=Persoonlike Organiseerder +GenericName[ar]=المنظم الشخصي +GenericName[be]=Пэрсанальны арганізатар +GenericName[bg]=Организатор +GenericName[bs]=Lični organizer +GenericName[ca]=Organitzador personal +GenericName[cs]=Osobní organizér +GenericName[cy]=Trefnydd Personol +GenericName[da]=Personlig organisering +GenericName[de]=Persönliche Daten organisieren +GenericName[el]=Προσωπικός οργανωτής +GenericName[en_GB]=Personal Organiser +GenericName[eo]=Persona Organizilo +GenericName[es]=Organizador personal +GenericName[et]=Personaalne ajaarvestus +GenericName[eu]=Antolatzaile pertsonala +GenericName[fa]=سازماندهندۀ شخصی +GenericName[fi]=Henkilökohtainen ajanhallintaohjelma +GenericName[fr]=Organiseur personnel +GenericName[fy]=Persoanlike organizer +GenericName[gl]=Organizador Persoal +GenericName[he]=מנהל זמן אישי +GenericName[hi]=निजी प्रबंधक +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ė +GenericName[mk]=Личен организатор +GenericName[ms]=Penyusun Peribadi +GenericName[nb]=Personlig planlegger +GenericName[nds]=Persöönlich Mötenkalenner +GenericName[ne]=व्यक्तिगत आयोजक +GenericName[nl]=Persoonlijke organizer +GenericName[nn]=Personleg organiserar +GenericName[pl]=Osobisty organizator +GenericName[pt]=Organizador Pessoal +GenericName[pt_BR]=Organizador Pessoal +GenericName[ro]=Organizator personal +GenericName[ru]=Персональный органайзер +GenericName[sk]=Osobný plánovač +GenericName[sl]=Osebni organizator +GenericName[sr]=Лични планер +GenericName[sr@Latn]=Lični planer +GenericName[sv]=Filofax +GenericName[ta]=தனிப்பயன் அமைப்பாளர் +GenericName[tg]=Органайзери инфиродӣ +GenericName[tr]=Kişisel Bilgi Yöneticisi +GenericName[uk]=Персональний тижневик +GenericName[uz]=Shaxsiy organayzer +GenericName[uz@cyrillic]=Шахсий органайзер +GenericName[zh_CN]=个人日程安排 +GenericName[zh_TW]=個人行程組織軟體 +ServiceTypes=Browser/View,DCOP/Organizer +X-KDE-Library=libkorganizerpart +X-KDE-StartupNotify=true +X-DCOP-ServiceType=Unique +X-DCOP-ServiceName=korganizer +Categories=Qt;KDE;Office;ProjectManagement; diff --git a/korganizer/korganizer.h b/korganizer/korganizer.h new file mode 100644 index 000000000..ab9f44f68 --- /dev/null +++ b/korganizer/korganizer.h @@ -0,0 +1,140 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1997, 1998, 1999 + Preston Brown (preston.brown@yale.edu) + Fester Zigterman (F.J.F.ZigtermanRustenburg@student.utwente.nl) + Ian Dawes (iadawes@globalserve.net) + Laszlo Boloni (boloni@cs.purdue.edu) + + Copyright (c) 2000-2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KORGANIZER_H +#define KORGANIZER_H + +#include <kurl.h> + +#include <korganizer/mainwindow.h> +#include <korganizer/part.h> +#include <kparts/mainwindow.h> + +class KTempFile; +class KRecentFilesAction; +class KOWindowList; +class KToggleAction; +class KProcess; +class KONewStuff; +class ActionManager; +class CalendarView; + +namespace KCal { class CalendarResources; } + +using namespace KCal; + +// Workaround for moc workaround for visual c++ 6.0 sucking +typedef KOrg::MainWindow KOrgMainWindow; +typedef KParts::MainWindow KPartsMainWindow; + +/** + This is the main class for KOrganizer. It extends the KDE KMainWindow. + it provides the main view that the user sees upon startup, as well as + menus, buttons, etc. etc. + + @short constructs a new main window for korganizer + @author Preston Brown +*/ +class KOrganizer : public KPartsMainWindow, public KOrgMainWindow +{ + Q_OBJECT + public: + /** + Constructs a new main window. + @param name Qt internal widget name + */ + KOrganizer( const char *name = 0 ); + virtual ~KOrganizer(); + + void init( bool hasDocument ); + + KOrg::CalendarViewBase *view() const; + ActionManager *actionManager() { return mActionManager; } + KActionCollection *getActionCollection() const { return actionCollection(); } + + /** + Open calendar file from URL. Merge into current calendar, if \a merge is + true. + */ + bool openURL( const KURL &url, bool merge = false ); + /** Save calendar file to URL of current calendar */ + bool saveURL(); + /** Save calendar file to URL */ + bool saveAsURL( const KURL & kurl ); + /** Get current URL */ + KURL getCurrentURL() const; + + virtual KXMLGUIFactory *mainGuiFactory() { return factory(); } + virtual KXMLGUIClient *mainGuiClient() { return this; } + virtual QWidget *topLevelWidget() { return this; } + + public slots: + /** show status message */ + void showStatusMessage( const QString & ); + + protected slots: + + /** using the KConfig associated with the kapp variable, read in the + * settings from the config file. + */ + void readSettings(); + + /** write current state to config file. */ + void writeSettings(); + + void statusBarPressed( int ); + + /** Sets title of window according to filename and modification state */ + void setTitle(); + + void newMainWindow( const KURL & ); + + protected: + void initActions(); +// void initViews(); + + /** supplied so that close events close calendar properly.*/ + bool queryClose(); + bool queryExit(); + + /* Session management */ + void saveProperties( KConfig * ); + void readProperties( KConfig * ); + + private: + CalendarView *mCalendarView; // Main view widget + KOrg::Part::List mParts; // List of parts loaded + + // status bar ids + enum { ID_HISTORY, ID_GENERAL, ID_ACTIVE, ID_MESSAGES_IN, ID_MESSAGES_OUT }; + ActionManager *mActionManager; +}; + +#endif diff --git a/korganizer/korganizer.kcfg b/korganizer/korganizer.kcfg new file mode 100644 index 000000000..eaf23fb34 --- /dev/null +++ b/korganizer/korganizer.kcfg @@ -0,0 +1,530 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 + http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" > + <kcfgfile name="korganizerrc"/> + <include>klocale.h</include> + + <group name="General"> + <entry type="Bool" key="Auto Save"> + <label>Enable automatic saving of manually opened calendar files</label> + <whatsthis>Check this box to save your calendar file automatically when you exit KOrganizer without asking and periodically, as you work. This setting does not affect the automatic saving of the standard calendar, which is automatically saved after each change.</whatsthis> + <default>true</default> + </entry> + <entry type="Int" key="Auto Save Interval"> + <label>Save &interval in minutes</label> + <whatsthis>Set the interval between automatic saving of calendar events in minutes here. This setting only applies to files that are opened manually. The standard KDE-wide calendar is automatically saved after each change.</whatsthis> + <default>10</default> + <min>1</min> + </entry> + <entry type="Bool" key="Confirm Deletes" name="Confirm"> + <label>Confirm deletes</label> + <whatsthis>Check this box to display a confirmation dialog when deleting items.</whatsthis> + <default>true</default> + </entry> + + <entry type="Bool" key="Archive Events"> + <label>Archive events</label> + <default>true</default> + </entry> + <entry type="Bool" key="Archive Todos"> + <label>Archive to-dos</label> + <default>true</default> + </entry> + + <entry type="Bool" key="Auto Archive"> + <label>Regularly archive events</label> + <default>false</default> + </entry> + <entry type="Enum" key="Archive Action"> + <label>What to do when archiving</label> + <choices> + <choice name="actionDelete"> + <label>Delete old events</label> + </choice> + <choice name="actionArchive"> + <label>Archive old events to a separate file</label> + </choice> + </choices> + <default>actionArchive</default> + </entry> + <entry type="Int" key="Expiry Time"> + <label>If auto-archiving is enabled, events older than this amount will be archived. The unit of this value is specified in another field.</label> + <default>1</default> + </entry> + <entry type="Enum" key="Expiry Unit" name="ExpiryUnit"> + <label>The unit in which the expiry time is expressed.</label> + <choices> + <choice name="UnitDays"> + <label>In days</label> + </choice> + <choice name="UnitWeeks"> + <label>In weeks</label> + </choice> + <choice name="UnitMonths"> + <label>In months</label> + </choice> + </choices> + <default>UnitMonths</default> + </entry> + <entry type="String" key="Archive File"> + <label>URL of the file where old events should be archived</label> + </entry> + + <entry type="Bool" key="Html With Save"> + <label>Export to HTML with every save</label> + <whatsthis>Check this box to export the calendar to an HTML-file every time you save it. By default, this file will be called calendar.html and placed in the user home folder.</whatsthis> + <default>false</default> + </entry> + <entry type="Enum" key="Destination" name="Destination"> + <label>New Events, To-dos and Journal Entries Should</label> + <choices> + <choice name="standardDestination"> + <label>Be added to the standard resource</label> + <whatsthis>Select this option to always record new events, to-dos and journal entries using the standard resource.</whatsthis> + </choice> + <choice name="askDestination"> + <label>Be asked which resource to use</label> + <whatsthis>Select this option to choose the resource to be used to record the item each time you create a new event, to-do or journal entry. This choice is recommended if you intend to use the shared folders functionality of the Kolab server or have to manage multiple accounts using Kontact as a KDE Kolab client. </whatsthis> + </choice> + </choices> + <default>askDestination</default> + </entry> + </group> + + <group name="Personal Settings"> + <entry type="Bool" key="Bcc"> + <label>Send copy to owner when mailing events</label> + <whatsthis>Check this box to get a copy of all e-mail messages that KOrganizer sends at your request to event attendees.</whatsthis> + <default>false</default> + </entry> + <entry type="Bool" key="Use Control Center Email" name="EmailControlCenter"> + <label>Use email settings from Control Center</label> + <whatsthis>Check this box to use the KDE-wide e-mail settings, which are defined using the KDE Control Center "Password & User Account" Module. Uncheck this box to be able to specify your full name and e-mail.</whatsthis> + <default>true</default> + </entry> + <entry type="String" key="user_name" name="UserName"> + <label>Full &name</label> + <whatsthis>Enter your full name here. This name will be displayed as "Organizer" in to-dos and events you create.</whatsthis> + <default code="true">i18n("Anonymous")</default> + </entry> + <entry type="String" key="user_email" name="UserEmail"> + <label>E&mail address</label> + <whatsthis>Enter here your e-mail address. This e-mail address will be used to identify the owner of the calendar, and displayed in events and to-dos you create.</whatsthis> + <default code="true">i18n("nobody@nowhere")</default> + </entry> + <entry type="Enum" key="Mail Client"> + <label>Mail Client</label> + <choices> + <choice name="MailClientKMail"> + <label>KMail</label> + <whatsthis>Select this option to use KMail as the mail transport. The mail transport is used for groupware functionality.</whatsthis> + </choice> + <choice name="MailClientSendmail"> + <label>Sendmail</label> + <whatsthis>Select this option to use sendmail as the mail transport. The mail transport is used for groupware functionality. Please check if you have sendmail installed before selecting this option.</whatsthis> + </choice> + </choices> + <default>MailClientKMail</default> + </entry> + </group> + + <group name="Time & Date"> + <entry type="String" name="TimeZoneId"> + <whatsthis>Select your timezone from the list of locations on this drop down box. If your city is not listed, select one which shares the same timezone. KOrganizer will automatically adjust for daylight savings.</whatsthis> + </entry> + <entry type="String" name="Holidays"> + <label>Use holiday region:</label> + <whatsthis>Select from which region you want to use the holidays here. Defined holidays are shown as non-working days in the date navigator, the agenda view, etc.</whatsthis> + </entry> + <entry type="DateTime" name="StartTime"> + <label>Default appointment time</label> + <whatsthis>Enter the default time for events here. The default is used if you do not supply a start time.</whatsthis> + <default>QDateTime(QDate(), QTime(10,0))</default> + </entry> + <entry type="DateTime" name="DefaultDuration"> + <label>Default duration of new appointment (HH:MM)</label> + <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> + </group> + + <group name="Views"> + <entry type="Int" key="Hour Size"> + <label>Hour size</label> + <whatsthis>Select on this spin box the height of the hour rows in the schedule view.</whatsthis> + <default>10</default> + <min>4</min> + <max>30</max> + </entry> + <entry type="Bool" key="Show Daily Recurrences" name="DailyRecur"> + <label>Show events that recur daily in date navigator</label> + <whatsthis>Check this box to show the days containing daily recurring events in bold typeface in the Date Navigator, or uncheck it to give more prominence to other (non daily recurring) events.</whatsthis> + <default>true</default> + </entry> + <entry type="Bool" key="Show Weekly Recurrences" name="WeeklyRecur"> + <label>Show events that recur weekly in date navigator</label> + <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="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> + <default>true</default> + </entry> + <entry type="Bool" name="ShowAllDayTodo"> + <label>Show to-dos in day, week and month views</label> + <whatsthis>Check this box to display to-dos in the day, week, and month view. This is helpful when you have a lot of (recurring) to-dos.</whatsthis> + <default>true</default> + </entry> + <entry type="Bool" key="Enable Month-View Scrollbars" name="EnableMonthScroll"> + <label>Enable scrollbars in month view cells</label> + <whatsthis>Check this box to display scrollbars when clicking on a cell in the month view; they will only appear when needed though.</whatsthis> + <default>false</default> + </entry> + <entry type="Bool" name="SelectionStartsEditor"> + <label>Time range selection in agenda view starts event editor</label> + <whatsthis>Check this box to start the event editor automatically when you select a time range in the daily and weekly view. To select a time range, drag the mouse from the start time to the end time of the event you are about to plan.</whatsthis> + <default>false</default> + </entry> + + <entry type="Bool" key="Show current-time line" name="MarcusBainsEnabled"> + <label>Show current-time (Marcus Bains) line</label> + <whatsthis>Check this box to display a red line in the day or week view indicating the current-time line (Marcus Bains line).</whatsthis> + <default>true</default> + </entry> + <entry type="Bool" key="Current-time line shows seconds" name="MarcusBainsShowSeconds"> + <label>Show seconds on current-time line</label> + <whatsthis>Check this box if you want to show seconds on the current-time line.</whatsthis> + <default>true</default> + </entry> + + <entry type="Enum" key="AgendaViewColors"> + <label>Colors used in agenda view</label> + <whatsthis>Choose the colors of the agenda view items.</whatsthis> + <choices> + <choice name="CategoryInsideResourceOutside"> + <label>Category inside, calendar outside</label> + </choice> + <choice name="ResourceInsideCategoryOutside"> + <label>Calendar inside, category outside</label> + </choice> + <choice name="CategoryOnly"> + <label>Only category</label> + </choice> + <choice name="ResourceOnly"> + <label>Only calendar</label> + </choice> + </choices> + <default>CategoryInsideResourceOutside</default> + </entry> + + <entry type="Enum" name="Agenda View Calendar Display"> + <label>Agenda View Calendar Display</label> + <choices> + <choice name="CalendarsMerged"> + <label>Merge all calendars into one view</label> + </choice> + <choice name="CalendarsSideBySide"> + <label>Show calendars side by side</label> + </choice> + <choice name="AllCalendarViews"> + <label>Switch between views with tabs</label> + </choice> + </choices> + <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> + <default>QDateTime(QDate(), QTime(7,0))</default> + </entry> + + <entry type="DateTime" name="WorkingHoursStart"> + <label>Daily starting hour</label> + <whatsthis>Enter the start time for the working hours here. The working hours will be marked with color by KOrganizer.</whatsthis> + <default>QDateTime(QDate(), QTime(8,0))</default> + </entry> + <entry type="DateTime" name="WorkingHoursEnd"> + <label>Daily ending hour</label> + <whatsthis>Enter the ending time for the working hours here. The working hours will be marked with color by KOrganizer.</whatsthis> + <default>QDateTime(QDate(), QTime(17,0))</default> + </entry> + <entry type="Int" key="Work Week Mask" name="WorkWeekMask"> + <default>31</default> + </entry> + <entry type="Bool" key="Exclude Holidays"> + <label>Exclude holidays</label> + <whatsthis>Check this box to prevent KOrganizer from marking the working hours on holidays.</whatsthis> + <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> + + <entry type="Bool" key="Full View Month"> + <label>Month view uses full window</label> + <whatsthis>Check this box to use the full KOrganizer window when displaying the month view. If this box is checked, you will gain some space for the monthly view, but other widgets, such as the date navigator, the item details and the resources list, will not be displayed.</whatsthis> + <default>false</default> + </entry> + <entry type="Bool" key="Full View Todo"> + <label>To-do list view uses full window</label> + <whatsthis>Check this box to use the full KOrganizer window when displaying the to-do list view. If this box is checked, you will gain some space for the to-do list view, but other widgets, such as the date navigator, the to-do details and the resources list, will not be displayed.</whatsthis> + <default>true</default> + </entry> + + <entry type="Bool" key="Record Todos In Journals"> + <label>Record completed to-dos in journal entries</label> + <whatsthis>Check this box to record the completion of a to-do in a new entry of your journal automatically.</whatsthis> + <default>false</default> + </entry> + + <entry type="Bool" key="Quick Todo" name="EnableQuickTodo"> + <default>true</default> + </entry> + + <entry type="Int" key="Next X Days"> + <label>Next x days</label> + <whatsthis>Select on this spin box the number of "x" days to be displayed in the next days view. To access the the next "x" days view, choose the "Next X Days" menu item from the "View" menu.</whatsthis> + <default>3</default> + </entry> + + </group> + + <group name="Layout"> + <entry type="Bool" key="CompactDialogs"> + <default>false</default> + </entry> + <entry type="Bool" key="VerticalScreen"> + <default>false</default> + </entry> + </group> + + <group name="KOrganizer Plugins"> + <entry type="StringList" name="SelectedPlugins"> + <default>holidays,webexport</default> + </entry> + </group> + + <group name="Editors"> + <entry type="StringList" name="EventTemplates"> + </entry> + <entry type="StringList" name="TodoTemplates"> + </entry> + <entry type="StringList" name="JournalTemplates"> + </entry> + + <entry type="StringList" name="ActiveDesignerFields"> + </entry> + </group> + + <group name="Group Scheduling"> + <entry type="Enum" name="IMIPScheduler"> + <choices> + <choice name="IMIPDummy"/> + <choice name="IMIPKMail"/> + </choices> + <default>IMIPKMail</default> + </entry> + <entry type="Bool" key="Use Groupware Communication"> + <label>Use Groupware communication</label> + <whatsthis>Check this box to enable automatic generation of mails when creating, updating or deleting events (or to-dos) involving other attendees. You should check this box if you want to use the groupware functionality (e.g. Configuring Kontact as a KDE Kolab client).</whatsthis> + <default>true</default> + </entry> + + <entry type="StringList" name="AdditionalMails"> + </entry> + + <entry name="OutlookCompatCounterProposals" type="Bool"> + <label>Send Outlook-like pseudo counter proposals</label> + <default>false</default> + </entry> + + </group> + + <group name="Colors"> + <entry type="Color" key="Holiday Color"> + <label>Holiday color</label> + <whatsthis>Select the holiday color here. The holiday color will be used for the holiday name in the month view and the holiday number in the date navigator.</whatsthis> + <default>255, 100, 100</default> + </entry> + <entry type="Color" key="Highlight Color"> + <label>Highlight color</label> + <whatsthis>Select the highlight color here. The highlight color will be used for marking the currently selected area in your agenda and in the date navigator.</whatsthis> + <default>100, 100, 255</default> + </entry> + <entry type="Color" key="AgendaBackgroundColor" name="AgendaBgColor"> + <label>Agenda view background color</label> + <whatsthis>Select the agenda view background color here.</whatsthis> + <default>255, 255, 255</default> + </entry> + <entry type="Color" key="WorkingHoursColor"> + <label>Working hours color</label> + <whatsthis>Select the working hours color for the agenda view here.</whatsthis> + <default>255, 235, 154</default> + </entry> + <entry type="Color" key="Todo due today Color" name="TodoDueTodayColor"> + <label>To-do due today color</label> + <whatsthis>Select the to-do due today color here.</whatsthis> + <default>255, 200, 50</default> + </entry> + <entry type="Color" key="Todo overdue Color" name="TodoOverdueColor"> + <label>To-do overdue color</label> + <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> + <default>151, 235, 121</default> + </entry> + + <entry type="Bool" key="AssignDefaultResourceColors"> + <default>true</default> + </entry> + <entry type="Int" key="DefaultResourceColorSeed"> + <default>0</default> + </entry> + <entry type="StringList" key="DefaultResourceColors"> + <default>#c1d4e7,#d0e7c1,#e3e7c1,#e7c1e6,#a1b1c1</default> + </entry> + + </group> + + <group name="Fonts"> + <entry type="Font" key="TimeBar Font"> + <label>Time bar</label> + <whatsthis>Press this button to configure the time bar font. The time bar is the widget that shows the hours in the agenda view. This button will open the "Select Font" dialog, allowing you to choose the hour font for the time bar.</whatsthis> + </entry> + <entry type="Font" key="AgendaView Font"> + <label>Agenda view</label> + <whatsthis>Press this button to configure the agenda view font. This button will open the "Select Font" dialog, allowing you to choose the font for the events in the agenda view.</whatsthis> + </entry> + <entry type="Font" key="MarcusBains Font"> + <label>Current-time line</label> + <whatsthis>Press this button to configure the current-time line font. This button will open the "Select Font" dialog, allowing you to choose the font for the current-time line in the agenda view.</whatsthis> + </entry> + <entry type="Font" key="MonthView Font"> + <label>Month view</label> + <whatsthis>Press this button to configure the month view font. This button will open the "Select Font" dialog, allowing you to choose the font for the items in the month view.</whatsthis> + </entry> + </group> + + <group name="FreeBusy"> + + <entry type="Bool" name="FreeBusyPublishAuto"> + <default>false</default> + </entry> + + <entry type="Int" name="FreeBusyPublishDelay"> + <default>5</default> + </entry> + <entry type="Int" key="FreeBusyPublishDays"> + <default>60</default> + </entry> + + <entry type="String" name="FreeBusyPublishUrl"> + <label>Free/Busy Publish URL</label> + <whatsthis>URL for publishing free/busy information</whatsthis> + </entry> + <entry type="String" name="FreeBusyPublishUser"> + <label>Free/Busy Publish Username</label> + <whatsthis>Username for publishing free/busy information</whatsthis> + </entry> + <entry type="Password" name="FreeBusyPublishPassword"> + <label>Free/Busy Publish Password</label> + <whatsthis>Password for publishing free/busy information</whatsthis> + </entry> + <entry type="Bool" name="FreeBusyPublishSavePassword"> + <default>false</default> + </entry> + + <entry type="Bool" name="FreeBusyRetrieveAuto"> + <label>Enable Automatic Free/Busy Retrieval</label> + <default>false</default> + </entry> + + <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> + </entry> + + <entry type="Bool" name="FreeBusyFullDomainRetrieval"> + <label>Use full email address for retrieval</label> + <whatsthis>With this setting, you can change the filename that will be fetched from the server. With this checked, it will download a free/busy file called user@domain.ifb, for example nn@kde.org.ifb. Without this set, it will download user.ifb, for example nn.ifb.</whatsthis> + <default>false</default> + </entry> + + <entry type="String" name="FreeBusyRetrieveUrl"> + <label>Free/Busy Retrieval URL</label> + </entry> + <entry type="String" name="FreeBusyRetrieveUser"> + <label>Free/Busy Retrieval Username</label> + </entry> + <entry type="Password" name="FreeBusyRetrievePassword"> + <label>Free/Busy Retrieval Password</label> + <whatsthis>Password for retrieving free/busy information</whatsthis> + </entry> + <entry type="Bool" name="FreeBusyRetrieveSavePassword"> + <default>false</default> + </entry> + + </group> + + <group name="Kontact"> + <entry type="Enum" name="DefaultEmailAttachMethod"> + <label>Default email attachment method</label> + <whatsthis>The default way of attaching dropped emails to an event</whatsthis> + <choices> + <choice name="Ask"> + <label>Always ask</label> + </choice> + <choice name="Link"> + <label>Only attach link to message</label> + </choice> + <choice name="InlineFull"> + <label>Attach complete message</label> + </choice> + <choice name="InlineBody"> + <label>Attach message without attachments</label> + </choice> + </choices> + <default>Ask</default> + </entry> + <entry type="Enum" name="DefaultTodoAttachMethod"> + <label>Default todo attachment method</label> + <whatsthis>The default way of attaching dropped emails to a task</whatsthis> + <choices> + <choice name="TodoAttachAsk"> + <label>Always ask</label> + </choice> + <choice name="TodoAttachLink"> + <label>Only attach link to message</label> + </choice> + <choice name="TodoAttachInlineFull"> + <label>Attach complete message</label> + </choice> + </choices> + <default>TodoAttachInlineFull</default> + </entry> + </group> +</kcfg> diff --git a/korganizer/korganizer.upd b/korganizer/korganizer.upd new file mode 100644 index 000000000..186188e0b --- /dev/null +++ b/korganizer/korganizer.upd @@ -0,0 +1,46 @@ +Id=korganizer_3.4_GroupwareCleanup +File=korganizerrc +Group=Group Scheduling +RemoveKey=IMIP auto refresh +RemoveKey=IMIP auto insert reply +RemoveKey=IMIP auto insert request +RemoveKey=IMIP auto FreeBusy +RemoveKey=IMIP auto save FreeBusy +RemoveKey=IMIPSend +# +# +Id=korganizer_3.4_WebExport +File=korganizerrc,libkcal_htmlexportrc +Group=HtmlExport,KOrganizer-General +Key=ExcludeConfidentialEvent,Exclude Private +Key=ExcludePrivateEvent,Exclude Confidential +# +Group=HtmlExport,KOrganizer-Events +Key=Event,Event View +Key=Month,Month View +Key=AttendeesEvent,Export Attendees +Key=CategoriesEvent,Export Categories +# +Group=HtmlExport,KOrganizer-Todos +Key=Todo,Todo View +Key=DueDates,Export Due Date +Key=AttendeesTodo,Export Attendees +Key=CategoriesTodo,Export Categories +RemoveKey=ExcludeConfidentialTodo +RemoveKey=ExcludePrivateTodo +# +# +Id=korganizer_3.4_FilterAction +File=korganizerrc +Group=FilterView,General +Key=Current Filter +# +Group=FilterView +RemoveKey=FilterEnabled +# +# +Id=korganizer_3.4_HolidayPlugin +File=korganizerrc +Group=Calendar/Holiday Plugin,Time & Date +Key=Holidays +RemoveGroup=Calendar/Holiday Plugin diff --git a/korganizer/korganizer_configcolors.desktop b/korganizer/korganizer_configcolors.desktop new file mode 100644 index 000000000..59582a536 --- /dev/null +++ b/korganizer/korganizer_configcolors.desktop @@ -0,0 +1,193 @@ +[Desktop Entry] +Icon=colors +Type=Service +ServiceTypes=KCModule + +X-KDE-ModuleType=Library +X-KDE-Library=korganizer +X-KDE-FactoryName=korganizerconfigcolors +X-KDE-HasReadOnlyMode=false +X-KDE-ParentApp=korganizer +X-KDE-ParentComponents=korganizer,kontact_korganizerplugin +X-KDE-CfgDlgHierarchy=KOrganizer + +Name=Colors +Name[af]=Kleure +Name[ar]=الألوان +Name[az]=Rənglər +Name[be]=Колеры +Name[bg]=Цветове +Name[br]=Livioù +Name[bs]=Boje +Name[cs]=Barvy +Name[cy]=Lliwiau +Name[da]=Farver +Name[de]=Farben +Name[el]=Χρώματα +Name[en_GB]=Colours +Name[eo]=Koloroj +Name[es]=Colores +Name[et]=Värvid +Name[eu]=Koloreak +Name[fa]=رنگها +Name[fi]=Värit +Name[fr]=Couleurs +Name[fy]=Kleuren +Name[ga]=Dathanna +Name[gl]=Cores +Name[he]=צבעים +Name[hi]=रंग +Name[hr]=Boje +Name[hu]=Színek +Name[id]=Warna +Name[is]=Litir +Name[it]=Colori +Name[ja]=色 +Name[ka]=ფერები +Name[kk]=Түстері +Name[km]=ពណ៌ +Name[lt]=Spalvos +Name[lv]=Krāsas +Name[mk]=Бои +Name[ms]=Warna +Name[mt]=Kuluri +Name[nb]=Farger +Name[nds]=Klören +Name[ne]=रङ +Name[nl]=Kleuren +Name[nn]=Fargar +Name[pl]=Kolory +Name[pt]=Cores +Name[pt_BR]=Cores +Name[ro]=Culori +Name[ru]=Цвета +Name[rw]=Amabara +Name[se]=Ivnnit +Name[sk]=Farby +Name[sl]=Barve +Name[sr]=Боје +Name[sr@Latn]=Boje +Name[sv]=Färger +Name[ta]=வண்ணங்கள் +Name[tg]=Рангҳо +Name[th]=สี +Name[tr]=Renkler +Name[uk]=Кольори +Name[uz]=Ranglar +Name[uz@cyrillic]=Ранглар +Name[ven]=Mivhala +Name[vi]=Màu +Name[xh]=Imibala +Name[zh_CN]=颜色 +Name[zh_TW]=顏色 +Name[zu]=Imibala +Comment=KOrganizer Colors Configuration +Comment[af]=KOrganizer kleure opstelling +Comment[ar]=إعداد ألوان KOrganizer +Comment[be]=Канфігурацыя колераў KOrganizer +Comment[bg]=Настройки на цветовете за KOrganizer +Comment[bs]=KOrganizer podešavanje boja +Comment[ca]=Configuració de colors a KOrganizer +Comment[cs]=Nastavení barev KOrganizeru +Comment[cy]=Ffurfweddiad Lliwiau KTrefnydd +Comment[da]=KOrganizer farveindstilling +Comment[de]=Farbenfestlegung für KOrganizer +Comment[el]=Ρύθμιση χρωμάτων του KOrganizer +Comment[en_GB]=KOrganizer Colours Configuration +Comment[eo]=KOrganizilo Kolor-agordo +Comment[es]=Configuración de los colores de KOrganizer +Comment[et]=KOrganizeri värvide seadistamine +Comment[eu]=KOrganizer-en koloreen konfigurazioa +Comment[fa]=پیکربندی رنگهای KOrganizer +Comment[fi]=KOrganizer värien asetukset +Comment[fr]=Configuration des couleurs de KOrganizer +Comment[fy]=KOrganizer kleuren ynstelle +Comment[gl]=Configuración de Cores de KOrganizer +Comment[he]=הגדרות צבעים של הארגונית +Comment[hi]=के-आर्गेनाइज़र रंग कॉन्फ़िगरेशन +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 +Comment[mk]=Конфигурација на боите +Comment[ms]=KOnfigurasi Warna KOrganizer +Comment[nb]=KOrganizer fargeoppsett +Comment[nds]=Klören för KOrganizer instellen +Comment[ne]=केडीई आयोजक रङ कन्फिगरेसन +Comment[nl]=KOrganizer kleuren instellen +Comment[nn]=KOrganizer, fargeinnstillingar +Comment[pl]=Konfiguracja kolorów KOrganizera +Comment[pt]=Configuração de Cores do KOrganizer +Comment[pt_BR]=Configuração de Cores do KOrganizer +Comment[ro]=Configurare culori KOrganizer +Comment[ru]=Настройка цветов органайзера KDE +Comment[se]=KOrganizer, ivdneheivehusat +Comment[sk]=Nastavenie farieb pre KOrganizer +Comment[sl]=Nastavitve barv v KOrganizerju +Comment[sr]=Подешавање боја у KOrganizer-у +Comment[sr@Latn]=Podešavanje boja u KOrganizer-u +Comment[sv]=Inställning av Korganizers färger +Comment[ta]=கேஅமைப்பவர் வண்ணங்களின் கட்டமைப்பு +Comment[tg]=Танзимотҳои ранги органайзери KDE +Comment[tr]=KOrganizer Renk Yapılandırması +Comment[uk]=Налаштування кольорів у KOrganizer +Comment[zh_CN]=KOrganizer 颜色配置 +Comment[zh_TW]=KOrganizer 顏色設定 +Keywords=korganizer,colors +Keywords[be]=K Арганізатар,колеры,korganizer,colors +Keywords[bg]=организатор, цветове, настройки, korganizer, colors +Keywords[br]=korganizer,livioù +Keywords[bs]=korganizer,colors,boje,boja +Keywords[cs]=korganizer,barvy +Keywords[cy]=korganizer,ktrefnydd,lliwiau +Keywords[da]=korganizer,farver +Keywords[de]=KOrganizer,Farben +Keywords[el]=korganizer,χρώματα +Keywords[en_GB]=korganizer,colours +Keywords[eo]=korganizilo, koloroj +Keywords[es]=korganizer,colores +Keywords[et]=korganizer,värvid +Keywords[eu]=korganizer,koloreak +Keywords[fa]=korganizer،رنگها +Keywords[fi]=korganizer,värit +Keywords[fr]=korganizer,couleurs +Keywords[fy]=korganizer,colors,kleuren +Keywords[ga]=korganizer,dathanna +Keywords[gl]=korganizer,cores +Keywords[he]=korganizer,colors, ארגונית, צבעים +Keywords[hi]=के-आर्गेनाइज़र,रंग +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,корганизатор,бои +Keywords[ms]=korganizer,warna +Keywords[nb]=korganizer,farger +Keywords[nds]=KOrganizer,Klören +Keywords[ne]=केडीई आयोजक, रङ +Keywords[nl]=korganizer,colors,kleuren +Keywords[nn]=korganizer,fargar +Keywords[pl]=korganizer,kolory,kolor +Keywords[pt]=korganizer,cores +Keywords[pt_BR]=korganizer,cores +Keywords[ro]=korganizer,culori +Keywords[ru]=korganizer,colors,органайзер,цвета +Keywords[sk]=korganizer,farby +Keywords[sl]=korganizer,barve +Keywords[sr]=korganizer,colors,планер,боје +Keywords[sr@Latn]=korganizer,colors,planer,boje +Keywords[sv]=korganizer,färger +Keywords[ta]=கேஅமைப்பாளர், வண்ணங்கள் +Keywords[tg]=korganizer,colors,органайзер,рангҳо +Keywords[tr]=korganizer,renkler +Keywords[uk]=korganizer,кольори +Keywords[uz]=korganizer,organayzer,ranglar +Keywords[uz@cyrillic]=korganizer,органайзер,ранглар +Keywords[zh_CN]=korganizer,colors,颜色 diff --git a/korganizer/korganizer_configdesignerfields.desktop b/korganizer/korganizer_configdesignerfields.desktop new file mode 100644 index 000000000..99f9e4b58 --- /dev/null +++ b/korganizer/korganizer_configdesignerfields.desktop @@ -0,0 +1,161 @@ +[Desktop Entry] +Icon=dlgedit +Type=Service +ServiceTypes=KCModule +DocPath=korganizer/preferences.html + +X-KDE-ModuleType=Library +X-KDE-Library=korganizer +X-KDE-FactoryName=korgdesignerfields +X-KDE-ParentApp=kaddressbook +X-KDE-ParentComponents=korganizer,kontact_korganizerplugin +X-KDE-CfgDlgHierarchy=KOrganizer + +Name=Custom Pages +Name[af]=Pasmaak Blaaie +Name[ar]=الصفحات المعتادة +Name[bg]=Потребителски полета +Name[br]=Pajennoù dre ziouer +Name[bs]=Vlastite stranice +Name[ca]=Pàgines a mida +Name[cs]=Vlastní stránky +Name[da]=Brugervalgte sider +Name[de]=Benutzerdefinierte Seiten +Name[el]=Προσαρμοσμένες σελίδες +Name[eo]=Propraj Paĝoj +Name[es]=Páginas personalizadas +Name[et]=Omaloodud leheküljed +Name[eu]=Orri pertsonalizatuak +Name[fa]=صفحات سفارشی +Name[fi]=Omat sivut +Name[fr]=Pages personnalisées +Name[fy]=Oanpaste siden +Name[ga]=Leathanaigh Shaincheaptha +Name[gl]=Páxinas Personalizadas +Name[he]=דפים מותאמים אישית +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 +Name[mk]=Сопствени страници +Name[ms]=Halaman Kebiasaan +Name[nb]=Tilpassede sider +Name[nds]=Egen Sieden +Name[ne]=अनुकूल पृष्ठ +Name[nl]=Aangepaste pagina's +Name[nn]=Tilpassa sider +Name[pl]=Własne strony +Name[pt]=Páginas Personalizadas +Name[pt_BR]=Páginas personalizadas +Name[ru]=Дополнительные поля +Name[se]=Iežat siiddut +Name[sk]=Vlastné stránky +Name[sl]=Prilagojene strani +Name[sr]=Посебне странице +Name[sr@Latn]=Posebne stranice +Name[sv]=Egna sidor +Name[ta]=தனிபயன் பக்கங்கள் +Name[tg]=Варақаҳои замимавии истифодашаванда +Name[tr]=Özel Sayfa +Name[uk]=Нетипові сторінки +Name[zh_CN]=定制页 +Comment=Configure the Custom Pages +Comment[af]=Stel die pasmaak blaaie op +Comment[ar]=إعداد الصفحات المعتادة +Comment[bg]=Настройки на потребителските полета +Comment[br]=Kefluniañ ar pajennoù diouzhoc'h +Comment[bs]=Podesite vlastite stranice +Comment[ca]=Configura les pàgines a mida +Comment[cs]=Nastavení vlastních stránek +Comment[da]=Indstil de selvvalgte sider +Comment[de]=Einstellungen für benutzerdefinierte Seiten +Comment[el]=Ρύθμιση των προσαρμοσμένων σελίδων +Comment[eo]=Agordi la proprajn paĝojn +Comment[es]=Configura las páginas personalizadas +Comment[et]=Omaloodud lehekülgede seadistamine +Comment[eu]=Konfiguratu orri pertsonalizatuak +Comment[fa]=پیکربندی صفحات سفارشی +Comment[fi]=Muokkaa omia sivuja +Comment[fr]=Configurer les pages personnalisées +Comment[fy]=Hjir kinne jo de oanpaste siden ynstelle +Comment[ga]=Cumraigh na Leathanaigh Shaincheaptha +Comment[gl]=Configurar as Páxinas Personalizadas +Comment[he]=הגדר את הדפים המותאמים אישית +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 +Comment[mk]=Конфигурирајте ги сопствените страници +Comment[ms]=Konfigurkan Halaman Langganan +Comment[nb]=Stille inn de tilpassede sidene +Comment[nds]=Egen Sieden instellen +Comment[ne]=अनुकूल पृष्ठ कन्फिगर गर्नुहोस् +Comment[nl]=Hier kunt u de aangepaste pagina's instellen +Comment[nn]=Set opp dei tilpassa sidene +Comment[pl]=Konfiguracja własnych stron +Comment[pt]=Configurar as Páginas Personalizadas +Comment[pt_BR]=Configurar Páginas personalizadas +Comment[ru]=Настройка пользовательских вкладок +Comment[se]=Heivet iežat siidduid +Comment[sk]=Nastavenie vlastných stránok +Comment[sl]=Nastavi prilagojene strani +Comment[sr]=Подешавање посебних страница +Comment[sr@Latn]=Podešavanje posebnih stranica +Comment[sv]=Anpassa egna sidor +Comment[ta]=தனிபயன் பக்கங்களை கட்டமை +Comment[tg]=Танзимоти варақаҳои замимавии истифодашаванда +Comment[tr]=Özel Sayfaları Yapılandır +Comment[uk]=Налаштування нетипових сторінок +Comment[zh_CN]=配置定制页 +Comment[zh_TW]=設定 Custom Pages +Keywords=korganizer, configure, settings, custom fields +Keywords[bg]=организатор, настройки, korganizer, configure, settings, custom fields +Keywords[ca]=korganizer, configura, opcions, camps a mida +Keywords[cs]=korganizer,nastavení,vlastní pole +Keywords[da]=korganizer, indstil, opsætning, brugervalgte felter +Keywords[de]=KOrganizer,konfigurieren,Einstellungen,benutzerdefinierte Felder +Keywords[el]=korganizer, ρύθμιση, ρυθμίσεις, προσαρμοσμένα πεδία +Keywords[es]=korganizer, configurar, opciones, campos personalizados +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[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 +Keywords[he]=korganizer, configure, settings, custom fields, הגדרות, תצורה, שדות, מותאמים אישית +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, корганизатор, конфигурација, конфигурирање, поставувања, сопствени полиња +Keywords[ms]=korganizer, konfigur, seting, medan kebiasaan +Keywords[nb]=kaddressbook, sette opp, innstillinger, tilpassede felter +Keywords[nds]=KOrganizer,Instellen,egen Feller +Keywords[ne]=केडीई आयोजक, कन्फिगर, सेटिङ, अनुकूल फिल्ड +Keywords[nl]=korganizer, configuratie, instellingen, aangepaste velden +Keywords[nn]=korganizer, oppsett, innstillingar, tilpassa felt +Keywords[pl]=korganizer,konfiguracja,ustawienia,własne pola +Keywords[pt]=korganizer, configurar, configuração, campos personalizados +Keywords[pt_BR]=korganizer,configurar,configurações, campos personalizados +Keywords[ru]=korganizer, configure, settings, custom fields, настройка, органайзер +Keywords[sl]=korganizer, nastavi, nastavitve, prilagojena polja +Keywords[sr]=korganizer, configure, settings, custom fields, подешавање, посебна поља +Keywords[sr@Latn]=korganizer, configure, settings, custom fields, podešavanje, posebna polja +Keywords[sv]=korganizer,anpassa,inställningar,egna fält +Keywords[ta]=கேஅமைப்பாளர், வடிவமைப்பு, அமைப்புகள், தனிபயன் புலங்கள் +Keywords[tr]=korganizer, yapılandır, yapılandırma, özel alanlar +Keywords[uk]=korganizer, configure, settings, custom fields, налаштування, параметри, нетипові поля +Keywords[zh_CN]=korganizer, configure, settings, custom fields, 配置, 设置, 定制项 diff --git a/korganizer/korganizer_configfonts.desktop b/korganizer/korganizer_configfonts.desktop new file mode 100644 index 000000000..c1c1a1f25 --- /dev/null +++ b/korganizer/korganizer_configfonts.desktop @@ -0,0 +1,190 @@ +[Desktop Entry] +Icon=fonts +Type=Service +ServiceTypes=KCModule + +X-KDE-ModuleType=Library +X-KDE-Library=korganizer +X-KDE-FactoryName=korganizerconfigfonts +X-KDE-HasReadOnlyMode=false +X-KDE-ParentApp=korganizer +X-KDE-ParentComponents=korganizer,kontact_korganizerplugin +X-KDE-CfgDlgHierarchy=KOrganizer + +Name=Fonts +Name[af]=Skrif tipes +Name[ar]=المحارف +Name[az]=Yazı növləri +Name[be]=Шрыфты +Name[bg]=Шрифтове +Name[br]=Fontoù +Name[bs]=Fontovi +Name[ca]=Tipus de lletres +Name[cs]=Písma +Name[cy]=Wynebfathau +Name[da]=Skrifttyper +Name[de]=Schriften +Name[el]=Γραμματοσειρές +Name[eo]=Tiparoj +Name[es]=Tipografías +Name[et]=Fondid +Name[eu]=Letra-tipoak +Name[fa]=قلمها +Name[fi]=Kirjasimet +Name[fr]=Polices +Name[fy]=Lettertypen +Name[ga]=Clónna +Name[gl]=Fontes +Name[he]=גופנים +Name[hi]=फ़ॉन्ट्स +Name[hr]=Pisma +Name[hu]=Betűtípusok +Name[is]=Letur +Name[it]=Tipi di carattere +Name[ja]=フォント +Name[ka]=შრიფტები +Name[kk]=Қаріптері +Name[km]=ពុម្ពអក្សរ +Name[lt]=Šriftai +Name[lv]=Fonti +Name[mk]=Фонтови +Name[ms]=Fon +Name[nb]=Skrifter +Name[nds]=Schriftoorden +Name[ne]=फन्ट +Name[nl]=Lettertypen +Name[nn]=Skrifttypar +Name[pl]=Czcionki +Name[pt]=Tipos de Letra +Name[pt_BR]=Fontes +Name[ro]=Fonturi +Name[ru]=Шрифты +Name[rw]=Imyandikire +Name[se]=Fonttat +Name[sk]=Písma +Name[sl]=Pisave +Name[sr]=Фонтови +Name[sr@Latn]=Fontovi +Name[sv]=Teckensnitt +Name[ta]=எழுத்துருக்கள் +Name[tg]=Ҳарфҳо +Name[th]=รูปแบบตัวอักษร +Name[tr]=Yazı tipleri +Name[uk]=Шрифти +Name[uz]=Shriftlar +Name[uz@cyrillic]=Шрифтлар +Name[ven]=Fontu +Name[vi]=Phông +Name[xh]=Ubungakanani bamagama +Name[zh_CN]=字体 +Name[zh_TW]=字型 +Comment=KOrganizer Fonts Configuration +Comment[af]=KOrganizer skrif tipe opstelling +Comment[ar]=إعداد المحارف لِــ KOrganizer +Comment[be]=Канфігурацыя шрыфтоў "K Арганізатара" +Comment[bg]=Настройки на шрифтовете за KOrganizer +Comment[bs]=KOrganizer podešavanje fontova +Comment[ca]=Configuració de lletres al KOrganizer +Comment[cs]=Nastavení písem KOrganizeru +Comment[cy]=ffurfweddiad Wynebfathau KTrefnydd +Comment[da]=KOrganizer skrifttypeindstilling +Comment[de]=Schriftenfestlegung für KOrganizer +Comment[el]=Ρύθμιση γραμματοσειρών του KOrganizer +Comment[eo]=KOrganizilo Tipar-agordo +Comment[es]=Configuración de las tipografías de KOrganizer +Comment[et]=KOrganizeri fontide seadistamine +Comment[eu]=KOrganizer-en letra-tipoen konfigurazioa +Comment[fa]=پیکربندی قلمهای KOrganizer +Comment[fi]=Korganizer kirjasinten asetukset +Comment[fr]=Configuration des polices de KOrganizer +Comment[fy]=KOrganizer lettertypen ynstelle +Comment[gl]=Configuración de Fontes de KOrganizer +Comment[he]=הגדרות גופנים של הארגונים +Comment[hi]=के-आर्गेनाइज़र फ़ॉन्ट्स कॉन्फ़िगरेशन +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 +Comment[mk]=Конфигурација на фонтовите +Comment[ms]=Konfigurasi Fon KOrganizer +Comment[nb]=KOrganizer skriftoppsett +Comment[nds]=Schriftoorden för KOrganizer instellen +Comment[ne]=केडीई आयोजक फन्ट कन्फिगरेसन +Comment[nl]=KOrganizer lettertypen instellen +Comment[nn]=KOrganizer, skriftinnstillingar +Comment[pl]=Konfiguracja czcionek KOrganizera +Comment[pt]=Configuração dos Tipos de Letra do KOrganizer +Comment[pt_BR]=Configuração de Fontes do KOrganizer +Comment[ro]=Configurare fonturi KOrganizer +Comment[ru]=Настройка шрифтов органайзера KDE +Comment[se]=KOrganizer, fontaheivehusat +Comment[sk]=Nastavenie písiem pre KOrganizer +Comment[sl]=Nastavitev pisav v KOrganizerju +Comment[sr]=Подешавање фонтова у KOrganizer-у +Comment[sr@Latn]=Podešavanje fontova u KOrganizer-u +Comment[sv]=Inställning av Korganizers teckensnitt +Comment[ta]=கேஅமைப்பாளர் எழுத்துருக்கள் கட்டமைப்பு +Comment[tg]=Танзимотҳои ҳуруфҳои органайзери KDE +Comment[tr]=KOrganizer Yazıtipi Yapılandırması +Comment[uk]=Налаштування шрифтів у KOrganizer +Comment[zh_CN]=KOrganizer 字体配置 +Comment[zh_TW]=KOrganizer 字型設定 +Keywords=korganizer,fonts +Keywords[af]=korganizer, fonts +Keywords[be]=K Арганізатар,шрыфты,korganizer,fonts +Keywords[bg]=организатор, шрифтове, настройки, korganizer, fonts +Keywords[br]=korganizer,nodrezhoù +Keywords[bs]=korganizer,fonts,fontovi +Keywords[ca]=korganizer,lletres +Keywords[cs]=korganizer,písma +Keywords[cy]=korganizer,ktrefnydd,wynebfathau +Keywords[da]=korganizer,skrifttyper +Keywords[de]=KOrganizer,Schriften +Keywords[el]=korganizer,γραμματοσειρές +Keywords[eo]=korganizilo, tiparoj +Keywords[es]=korganizer,tipografías +Keywords[et]=korganizer,fondid +Keywords[eu]=korganizer,letra-tipoak +Keywords[fa]=korganizer،قلمها +Keywords[fi]=korganizer,kirjasimet +Keywords[fr]=korganizer,polices +Keywords[fy]=korganizer,fonts,lettertypen +Keywords[ga]=korganizer,clónna,clófhoirne +Keywords[gl]=korganizer,fontes +Keywords[he]=korganizer,fonts,ארגונית,גופנים,גופן,פונט,פונטים +Keywords[hi]=के-आर्गेनाइज़र,फ़ॉन्ट्स +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,корганизатор,фонтови +Keywords[ms]=korganizer,fon +Keywords[nb]=korganizer,skrifter, skrifttyper +Keywords[nds]=KOrganizer,Schriftoorden +Keywords[ne]=केडीई आयोजक, फन्ट +Keywords[nl]=korganizer,fonts,lettertypen +Keywords[nn]=korganizer,skrift +Keywords[pl]=korganizer,czcionki +Keywords[pt]=korganizer,tipos de letra +Keywords[pt_BR]=korganizer,fontes +Keywords[ro]=korganizer,fonturi +Keywords[ru]=korganizer,fonts,органайзер,шрифты +Keywords[sk]=korganizer,písma +Keywords[sl]=korganizer,pisave +Keywords[sr]=korganizer,fonts,планер,фонтови,фонт,текст +Keywords[sr@Latn]=korganizer,fonts,planer,fontovi,font,tekst +Keywords[sv]=korganizer,teckensnitt +Keywords[ta]=கேஅமைப்பாளர்,எழுத்துரு +Keywords[tg]=korganizer,fonts,органайзер,ҳуруфҳо +Keywords[tr]=korganizer,yazıtipleri +Keywords[uk]=korganizer,шрифти +Keywords[uz]=korganizer,organayzer,shriftlar +Keywords[uz@cyrillic]=korganizer,органайзер,шрифтлар +Keywords[zh_CN]=korganizer,fonts,字体 diff --git a/korganizer/korganizer_configfreebusy.desktop b/korganizer/korganizer_configfreebusy.desktop new file mode 100644 index 000000000..84640ab8f --- /dev/null +++ b/korganizer/korganizer_configfreebusy.desktop @@ -0,0 +1,161 @@ +[Desktop Entry] +Icon=personal +Type=Service +ServiceTypes=KCModule + +X-KDE-ModuleType=Library +X-KDE-Library=korganizer +X-KDE-FactoryName=korganizerconfigfreebusy +X-KDE-HasReadOnlyMode=false +X-KDE-ParentApp=korganizer +X-KDE-ParentComponents=korganizer,kontact_korganizerplugin +X-KDE-CfgDlgHierarchy=KOrganizer + +Name=Free/Busy +Name[af]=Beskikbaar/Besig +Name[ar]=متوفّر/مشغول +Name[bg]=Свободен/зает +Name[bs]=Slobodan/Zauzet +Name[ca]=Lliure/ocupat +Name[cs]=Aktivita +Name[cy]=Rhydd/Prysur +Name[da]=Fri/Optaget +Name[de]=Frei/Beschäftigt +Name[eo]=Libera/Okupita +Name[es]=Libre/Ocupado +Name[et]=Vaba/hõivatud +Name[eu]=Libre/Lanpetuta +Name[fa]=آزاد/اشغال +Name[fi]=Vapaa/Varattu +Name[fr]=Disponibilité +Name[fy]=Frij/beset +Name[gl]=Ceibe/Ocupado +Name[hi]=फ्री/बिज़ी +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 +Name[mk]=Слободен/зафатен +Name[ms]=Lapang/Sibuk +Name[nb]=Ledig/Opptatt +Name[nds]=Free/Bunnen +Name[ne]=स्वतन्त्र/व्यस्त +Name[nl]=Vrij/bezet +Name[nn]=Ledig/opptatt +Name[pl]=Wolny/zajęty +Name[pt]=Livre/Ocupado +Name[pt_BR]=Livre/Ocupado +Name[ru]=Занятое время +Name[sk]=Voľný čas +Name[sl]=Prost/zaseden +Name[sr]=Слободан/заузет +Name[sr@Latn]=Slobodan/zauzet +Name[sv]=Ledig/upptagen +Name[ta]=சுதந்திரமான/வேலையில் இருக்கும் +Name[tg]=Озод/машғул аст +Name[tr]=Boş/Meşgul +Name[uk]=Вільний/зайнятий час +Name[uz]=Boʻsh/Band +Name[uz@cyrillic]=Бўш/Банд +Name[zh_CN]=忙/闲 +Name[zh_TW]=行程資訊 +Comment=KOrganizer Free/Busy Configuration +Comment[af]=KOrganizer Beskikbaar/Besig opstelling +Comment[bg]=Настройки на свободно/заето за KOrganizer +Comment[bs]=KOrganizer podešavanje za Slobodan/Zauzet +Comment[ca]=Configuració de Lliure/ocupat per a KOrganizer +Comment[cs]=Nastavení aktivity pro KOrganizer +Comment[cy]=Ffurfweddiad Rhydd/Prysur KTrefnydd +Comment[da]=KOrganizer Fri/Optaget-indstilling +Comment[de]=Frei/Beschäftigt-Festlegung für KOrganizer +Comment[el]=Ρυθμίσεις KOrganizer Free/Busy +Comment[eo]=KOrganizilo Agordo pri libero/okupito +Comment[es]=Configuración de libre/ocupado de KOrganizer +Comment[et]=KOrganizeri vaba/hõivatuse seadistused +Comment[eu]=KOrganizer-en Libre/Lanpetuta konfigurazioa +Comment[fa]=پیکربندی آزاد/اشغال KOrganizer +Comment[fi]=KOrganizer vapaa/varattu asetukset +Comment[fr]=Configuration de la disponibilité pour KOrganizer +Comment[fy]=KOrganizer frij/beset ynstelle +Comment[gl]=Configuración de Dispoñibilidade de Korganizer +Comment[hi]=के-आर्गेनाइज़र फ्री/बिज़ी कॉन्फ़िगरेशन +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 +Comment[mk]=Конфигурација на слободни/зафатени термини +Comment[ms]=Konfigurasi Lapang/Sibuk KOrganizer +Comment[nb]=KOrganizer oppsett for ledig/opptatt tid +Comment[nds]=Free/Bunnen-Instellen för KOrganizer +Comment[ne]=केडीई आयोजक स्वतन्त्र/व्यस्त कन्फिगरेसन +Comment[nl]=KOrganizer vrij/bezet instellen +Comment[nn]=KOrganizer, ledig/opptatt-innstillingar +Comment[pl]=Konfiguracja czasu wolnego/zajętego dla KOrganizera +Comment[pt]=Configuração de Livre/Ocupado do KOrganizer +Comment[pt_BR]=Configuração Livre/Ocupado do KOrganizer +Comment[ru]=Настройка свободного и занятого времени органайзера KDE +Comment[sk]=Nastavenie voľného času pre KOrganizer +Comment[sl]=Nastavitev prost/zaseden za KOrganizer +Comment[sr]=Подешавање слободног/заузетог у KOrganizer-у +Comment[sr@Latn]=Podešavanje slobodnog/zauzetog u KOrganizer-u +Comment[sv]=Inställning av ledig/upptagen i Korganizer +Comment[ta]=கேஅமைப்பாளர்,சுதந்திரமான/செயலிலுள்ள கட்டமைப்பு +Comment[tg]=Танзимоти вақти озоди органайзери KDE +Comment[tr]=KOrganizer Boş/Meşgul Yapılandırması +Comment[uk]=Налаштування вільного/зайнятого часу в KOrganizer +Comment[zh_CN]=KOrganizer 空闲/忙碌配置 +Comment[zh_TW]=KOrganizer 行程資訊設定 +Keywords=korganizer,freebusy,scheduling +Keywords[af]=korganizer, freebusy, scheduling +Keywords[bg]=организатор, свободно, заето, настройки, korganizer, freebusy, scheduling +Keywords[bs]=korganizer,freebusy,scheduling,raspored +Keywords[ca]=korganizer,lliure ocupat,planificació +Keywords[cs]=korganizer,volný,zaneprázdněn,plánování +Keywords[cy]=korganizer,ktrefnydd,rhydd,prysur,trefnlennu +Keywords[da]=korganizer,fri/optaget,skemalægning +Keywords[de]=KOrganizer,Frei/Beschäftigt,Ablaufplanung +Keywords[el]=korganizer,freebusy,προγραμματισμός +Keywords[es]=korganizer,libreocupado,planificación +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[fy]=korganizer,freebusy,scheduling,plannen,frij,beset,roaster +Keywords[gl]=korganizer,dispoñibilidade,axenda +Keywords[hi]=के-आर्गेनाइज़र,फ्री-बिज़ी,समय-सारणी +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 +Keywords[nb]=korganizer,ledigopptatt,planlegger +Keywords[nds]=KOrganizer,Free/Bunnen,Free,Bunnen,Planen,Plaan +Keywords[ne]=केडीई आयोजक, स्वतन्त्र व्यस्त, कार्यतालिका +Keywords[nl]=korganizer,freebusy,scheduling,plannen,vrij,bezet,rooster +Keywords[nn]=korganizer,ledigopptatt,planlegging +Keywords[pl]=korganizer,wolny/zajęty,planowanie +Keywords[pt]=korganizer,livre,ocupado,escalonamento +Keywords[pt_BR]=korganizer,livreocupado,agendamento +Keywords[ru]=korganizer,freebusy,scheduling,органайзер,занятое время,календарь +Keywords[sk]=korganizer,voľný čas,plánovanie +Keywords[sl]=korganizer,freebusy,razporejanje +Keywords[sr]=korganizer,freebusy,scheduling,слободан,заузет,планирање +Keywords[sr@Latn]=korganizer,freebusy,scheduling,slobodan,zauzet,planiranje +Keywords[sv]=korganizer,ledig/upptagen,schemaläggning +Keywords[ta]=கேஅமைப்பாளர்,சுதந்திரமான/திட்டம் அமைத்தல் +Keywords[tg]=korganizer,freebusy,scheduling,органайзер, вақти холӣ,ҷадвал +Keywords[tr]=korganizer,boş/meşgul,zamanlama +Keywords[uk]=korganizer,вільно,зайнято,час,розклад +Keywords[zh_CN]=korganizer,freebusy,scheduling,空闲,忙碌,日程安排 diff --git a/korganizer/korganizer_configgroupautomation.desktop b/korganizer/korganizer_configgroupautomation.desktop new file mode 100644 index 000000000..8e3227bc7 --- /dev/null +++ b/korganizer/korganizer_configgroupautomation.desktop @@ -0,0 +1,164 @@ +[Desktop Entry] +Icon=personal +Type=Service +ServiceTypes=KCModule + +X-KDE-ModuleType=Library +X-KDE-Library=korganizer +X-KDE-FactoryName=korganizerconfiggroupautomation +X-KDE-HasReadOnlyMode=false +X-KDE-ParentApp=korganizer +X-KDE-ParentComponents=korganizer,kontact_korganizerplugin +X-KDE-CfgDlgHierarchy=KOrganizer + +Name=Group Automation +Name[af]=Groep outomatisasie +Name[bg]=Организация +Name[bs]=Automatizacija grupe +Name[ca]=Automatització de grups +Name[cs]=Řízení skupiny +Name[cy]=Ymysgogi Grŵp +Name[da]=Gruppeautomation +Name[de]=Gruppen-Automation +Name[el]=Αυτοματισμός ομάδας +Name[eo]=Grup-aŭtomatigo +Name[es]=Automatización del grupo +Name[et]=Grupitöö +Name[eu]=Talde automatizazioa +Name[fa]=خودکارسازی گروه +Name[fi]=Ryhmän automatisointi +Name[fr]=Automatisation des groupes +Name[fy]=Groepautomatisearring +Name[gl]=Automatización de Grupo +Name[hi]=समूह स्वचालन +Name[hu]=Csoportmunka +Name[is]=Hópsjálfvirkni +Name[it]=Automazione gruppi +Name[ja]=グループ自動化 +Name[ka]=ჯგუფური ავტომატიზაცია +Name[kk]=Топтың біріккен жұмысы +Name[km]=ស្វ័យប្រតិកម្មក្រុម +Name[lt]=Grupių automatizavimas +Name[mk]=Автоматизација на групи +Name[ms]=Automasi Kumpulan +Name[nb]=Gruppeautomat +Name[nds]=Koppel-Akschonen +Name[ne]=समूह स्वचालिकरण +Name[nl]=Groepautomatisering +Name[nn]=Gruppeautomatisering +Name[pl]=Automatyzacja pracy grupowej +Name[pt]=Automação do Grupo +Name[pt_BR]=Automação de Grupo +Name[ru]=Совместная работа +Name[se]=Joavkoautomatiseren +Name[sk]=Skupinová automatizácia +Name[sl]=Avtomatizacija skupin +Name[sr]=Аутоматизација група +Name[sr@Latn]=Automatizacija grupa +Name[sv]=Gruppautomation +Name[ta]= குழு தானியங்கி +Name[tg]=Кори гурӯҳӣ +Name[tr]=Grup Otomasyonu +Name[uk]=Автоматизація груп +Name[zh_CN]=组自动化 +Name[zh_TW]=群組自動化 +Comment=KOrganizer Group Automation Configuration +Comment[af]=KOrganizer groep outomatisasie opstelling +Comment[bg]=Настройки на организация за KOrganizer +Comment[bs]=KOrganizer podešavanje automatizacije grupe +Comment[ca]=Configuració de l'automatització de grups a KOrganizer +Comment[cs]=Nastavení skupinového řízení KOrganizeru +Comment[cy]=Ffurfweddiad Ymysgogi Grŵp KTrefnydd +Comment[da]=KOrganizer gruppeautomation indstilling +Comment[de]=Einrichtung von Gruppen-Automatismen für KOrganizer +Comment[el]=Ρύθμιση αυτοματισμού ομάδας του KOrganizer +Comment[eo]=KOrganizilo Grup-aŭtomatiga Agordo +Comment[es]=Configuración del automatización del grupo de KOrganizer +Comment[et]=KOrganizeri grupitöö seadistamine +Comment[eu]=KOrganizer-en talde automatizazioaren konfigurazioa +Comment[fa]=پیکربندی خودکارسازی گروه KOrganizer +Comment[fi]=Korganizer ryhmän automatisoinnin asetukset +Comment[fr]=Configuration de l'automatisation des groupes de KOrganizer +Comment[fy]=KOrganizer groepautomatisearring ynstelle +Comment[gl]=Configuración da Automatización de Grupo de KOrganizer +Comment[hi]=के-आर्गेनाइज़र फ़ॉन्ट्स कॉन्फ़िगरेशन +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 +Comment[mk]=Конфигурација на автоматизација на групи +Comment[ms]=Konfigurasi Automasi Kumpulan KOrganizer +Comment[nb]=KOrganizer oppsett for gruppeautomat +Comment[nds]=Automaatsche Koppel-Akschonen för KOrganizer instellen +Comment[ne]=केडीई आयोजक समूह स्वचालिकरण कन्फिगरेसन +Comment[nl]=KOrganizer groepautomatisering instellen +Comment[nn]=KOrganizer, innstillingar for gruppeautomatisering +Comment[pl]=Konfiguracja automatyzacji pracy grupowej dla KOrganizera +Comment[pt]=Configuração da Automação do Grupo do KOrganizer +Comment[pt_BR]=Configuração de Automação de Grupo do KOrganizer +Comment[ru]=Настройка совместной работы в органайзере KDE +Comment[se]=KOrganizer, joavkoautomatiserema heivehusat +Comment[sk]=Nastavenie skupinovej automatizácie pre KOrganizer +Comment[sl]=Nastavitev avtomatizacije v KOrganizerju +Comment[sr]=Подешавање аутоматизације група у KOrganizer-у +Comment[sr@Latn]=Podešavanje automatizacije grupa u KOrganizer-u +Comment[sv]=Inställning av Korganizers gruppautomation +Comment[ta]=கேஅமைப்பாளர் குழு தானியங்கி கட்டமைப்பு +Comment[tg]=Танзимоти кори гурӯҳӣ дар органайзер-KDE +Comment[tr]=KOrganizer Grup Otomasyon Yapılandırması +Comment[uk]=Налаштування автоматизації груп у KOrganizer +Comment[zh_CN]=KOrganizer 组自动化配置 +Comment[zh_TW]=KOrganizer 群組自動化設定 +Keywords=korganizer,group,automation +Keywords[af]=korganizer, group, automation +Keywords[bg]=организатор, организация, настройки, korganizer, group, automation +Keywords[bs]=korganizer,group,automation,automatizacija,grupa,grupe +Keywords[ca]=korganizer,grup,automatització +Keywords[cs]=korganizer,skupina,řízení +Keywords[cy]=korganizer,ktrefnydd,grŵp,ymysgogi +Keywords[da]=korganizer,gruppe,automation +Keywords[de]=KOrganizer,Gruppe,Automatisierung +Keywords[el]=korganizer,ομάδα,αυτοματοποίηση +Keywords[eo]=korganizilo,grupo,aŭtomatigo +Keywords[es]=korganizer,grupo,automatización +Keywords[et]=korganizer,grupid,grupitöö +Keywords[eu]=korganizer,taldea,automatizazioa +Keywords[fa]=korganizer،گروه، خودکارسازی +Keywords[fi]=korganizer,ryhmä,automaatio +Keywords[fr]=korganizer,groupes,automatisation +Keywords[fy]=korganizer,groep,automatisearring +Keywords[gl]=korganizer,grupo,automatización +Keywords[hi]=के-आर्गेनाइज़र,समूह,स्वचालन +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,корганизатор,група,групи,автоматизација +Keywords[ms]=korganizer,kumpulan,automasi +Keywords[nb]=korganizer,gruppe,automat,automatisering +Keywords[nds]=KOrganizer,Koppel,automaatsch,Akschoon +Keywords[ne]=केडीई आयोजक, समूह, स्वचालिकरण +Keywords[nl]=korganizer,groep,automatisering +Keywords[nn]=korganizer,gruppe,automatisering +Keywords[pl]=korganizer,grupy,praca grupowa,automatyzacja +Keywords[pt]=korganizer,grupo,automação +Keywords[pt_BR]=korganizer,grupo,automação +Keywords[ro]=korganizer,grup,automatizare +Keywords[ru]=korganizer,group,automation,совместная работа,органайзер +Keywords[sk]=korganizer,skupina,automatizácia +Keywords[sl]=korganizer,skupina,samodejnost +Keywords[sr]=korganizer,group,automation,група,аутоматизација,планер +Keywords[sr@Latn]=korganizer,group,automation,grupa,automatizacija,planer +Keywords[sv]=korganizer,grupp,automation +Keywords[ta]=கேஅமைப்பாளர், குழு, தானியக்கம் +Keywords[tg]=korganizer,group,automation,кори гурӯҳӣ, органайзер +Keywords[tr]=korganizer,grup,otomasyon +Keywords[uk]=korganizer,група,автоматизація +Keywords[zh_CN]=korganizer,group,automation,组,自动化 diff --git a/korganizer/korganizer_configgroupscheduling.desktop b/korganizer/korganizer_configgroupscheduling.desktop new file mode 100644 index 000000000..d5fe9975e --- /dev/null +++ b/korganizer/korganizer_configgroupscheduling.desktop @@ -0,0 +1,162 @@ +[Desktop Entry] +Icon=personal +Type=Service +ServiceTypes=KCModule + +X-KDE-ModuleType=Library +X-KDE-Library=korganizer +X-KDE-FactoryName=korganizerconfiggroupscheduling +X-KDE-HasReadOnlyMode=false +X-KDE-ParentApp=korganizer +X-KDE-ParentComponents=korganizer,kontact_korganizerplugin +X-KDE-CfgDlgHierarchy=KOrganizer + +Name=Group Scheduling +Name[af]=Groep Skedulering +Name[ar]=جدولة المجموعة +Name[bg]=Разписание +Name[bs]=Raspoređivanje grupe +Name[ca]=Planificació de grups +Name[cs]=Skupinové plánování +Name[cy]=Trefnlennu Grŵp +Name[da]=Gruppeskemalægning +Name[de]=Gruppenplanung +Name[el]=Προγραμματισμός ομάδας +Name[es]=Planificación de grupo +Name[et]=Grupitöö ajakavad +Name[eu]=Talde antolaketa +Name[fa]=زمانبندی گروه +Name[fi]=Ryhmän ajastus +Name[fr]=Planification des tâches +Name[fy]=Groepsplanning +Name[gl]=Organización de Grupo +Name[hi]=समूह समय-सारणी +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 +Name[mk]=Закажување групи +Name[ms]=Penjadualan Kumpulan +Name[nb]=Gruppeplanlegging +Name[nds]=Koppelplanen +Name[ne]=समूह कार्यतालिका +Name[nl]=Groepsplanning +Name[nn]=Gruppeplanlegging +Name[pl]=Planowanie grupowe +Name[pt]=Escalonamento do Grupo +Name[pt_BR]=Agendamento de Grupo +Name[ro]=Planificare grup +Name[ru]=Календарь группы +Name[se]=Joavkoplánen +Name[sk]=Skupinové plánovanie +Name[sl]=Razporejanje skupin +Name[sr]=Распоређивање група +Name[sr@Latn]=Raspoređivanje grupa +Name[sv]=Gruppschemaläggning +Name[ta]=குழு திட்ட வரையறை +Name[tg]=Ҷадвали гурӯҳҳо +Name[tr]=Group Zamanlama +Name[uk]=Розклад груп +Name[zh_CN]=组日程安排 +Name[zh_TW]=群組排程 +Comment=KOrganizer Group Scheduling Configuration +Comment[af]=KOrganizer groep skedulering opstelling +Comment[ar]=إعداد جدولة مجموعة KOrganizer +Comment[bg]=Настройки на разписание за KOrganizer +Comment[bs]=KOrganizer podešavanje raspoređivanja grupe +Comment[ca]=Configuració de la planificació de grups a KOrganizer +Comment[cs]=Nastavení skupinového plánování KOrganizeru +Comment[cy]=Ffurfweddiad Trefnlennu Grŵp KTrefnydd +Comment[da]=KOrganizer gruppeskemalægning indstilling +Comment[de]=Einrichtung von Gruppen-Planungen für KOrganizer +Comment[el]=Ρύθμιση προγραμματισμού ομάδας του KOrganizer +Comment[es]=Configuración de la planificación de grupos de KOrganizer +Comment[et]=Korganizeri grupitöö ajakavade seadistamine +Comment[eu]=KOrganizer-en talde antolaketaren konfigurazioa +Comment[fa]=پیکربندی زمانبندی گروه KOrganizer +Comment[fi]=KOrganizer ryhmäajastuksen asetukset +Comment[fr]=Configuration de la planification des groupes de KOrganizer +Comment[fy]=KOrganizer groepsplanning ynstelle +Comment[gl]=Configuración da Axenda de Grupo de KOrganizer +Comment[hi]=के-आर्गेनाइज़र समूह समय-सारणी कॉन्फ़िगरेशन +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 +Comment[mk]=Конфигурација на закажување групи +Comment[ms]=Konfigurasi Penjadualan Kumpulan KOrganizer +Comment[nb]=Gruppeplanleggingsoppsett for KOrganizer +Comment[nds]=Koppelplanen för KOrganizer instellen +Comment[ne]=केडीई आयोजक समूह कार्यतालिका कन्फिगरेसन +Comment[nl]=KOrganizer groepsplanning instellen +Comment[nn]=KOrganizer, innstillingar for gruppeplanlegging +Comment[pl]=Konfiguracja planowania grupowego dla KOrganizera +Comment[pt]=Configuração do Escalonamento do Grupo do KOrganizer +Comment[pt_BR]=Configuração de Agendamento de Grupo do KOrganizer +Comment[ru]=Настройка календаря группы органайзера KDE +Comment[se]=KOrganizer, joavkoplánema heivehusat +Comment[sk]=Nastavenie skupinového plánovania pre KOrganizer +Comment[sl]=Nastavitev razporejanja skupin v KOrganizerju +Comment[sr]=Подешавање распоређивања група у KOrganizer-у +Comment[sr@Latn]=Podešavanje raspoređivanja grupa u KOrganizer-u +Comment[sv]=Inställning av Korganizers gruppschemaläggning +Comment[ta]=கேஅமைப்பாளர் குழு நேர அமைப்புக்கான கட்டமைப்பு +Comment[tg]=Танзимоти ҷадвали гурӯҳҳои органайзер-KDE +Comment[tr]=KOrganizer Grup Zamanlama Yapılandırması +Comment[uk]=Налаштування групового розкладу в KOrganizer +Comment[zh_CN]=Korganizer 组日程安排配置 +Comment[zh_TW]=KOrganizer 群組排程設定 +Keywords=korganizer,group,scheduling +Keywords[bg]=организатор, разписание, настройки, korganizer, group, scheduling +Keywords[bs]=korganizer,group,scheduling,raspoređivanje,grupa,grupe +Keywords[ca]=korganizer,grup,planificació +Keywords[cs]=korganizer,skupina,plánování +Keywords[cy]=korganizer,ktrefnydd,grŵp,trefnlenni +Keywords[da]=korganizer,gruppe,skemalægning +Keywords[de]=KOrganizer,Gruppe,Planung +Keywords[el]=korganizer,ομάδα,προγραμματισμός +Keywords[es]=korganizer,grupo,planificación +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[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,корганизатор,група,групи,закажување +Keywords[ms]=korganizer,kumpulan,penjadualan +Keywords[nb]=korganizer,gruppe,planlegging +Keywords[nds]=KOrganizer,Koppel,Plaan,planen +Keywords[ne]=केडीई आयोजक, समूह, कार्यतालिका +Keywords[nl]=korganizer,group,scheduling,plannen,groep +Keywords[nn]=korganizer,gruppe,planlegging +Keywords[pl]=korganizer,grupa,planowanie +Keywords[pt]=korganizer,grupo,escalonamento +Keywords[pt_BR]=korganizer,grupo,agendamento +Keywords[ro]=korganizer,grup,planificare +Keywords[ru]=korganizer,group,scheduling,календарь группы,органайзер +Keywords[sk]=korganizer,skupina,plánovanie +Keywords[sl]=korganizer,skupina,razporejanje +Keywords[sr]=korganizer,group,scheduling,планер,група,распоред,распоређивање +Keywords[sr@Latn]=korganizer,group,scheduling,planer,grupa,raspored,raspoređivanje +Keywords[sv]=korganizer,grupp,schemaläggning +Keywords[ta]=கேஅமைப்பாளர்,குழு, திட்டம் அமைத்தல் +Keywords[tg]=korganizer,group,scheduling,ҷадвалигурӯҳҳо,органайзер +Keywords[tr]=korganizer,grup,zamanlama +Keywords[uk]=korganizer,груп,розклад +Keywords[zh_CN]=korganizer,group,scheduling,组,日程安排 diff --git a/korganizer/korganizer_configmain.desktop b/korganizer/korganizer_configmain.desktop new file mode 100644 index 000000000..52e70ee05 --- /dev/null +++ b/korganizer/korganizer_configmain.desktop @@ -0,0 +1,173 @@ +[Desktop Entry] +Icon=identity +Type=Service +ServiceTypes=KCModule + +X-KDE-ModuleType=Library +X-KDE-Library=korganizer +X-KDE-FactoryName=korganizerconfigmain +X-KDE-HasReadOnlyMode=false +X-KDE-ParentApp=korganizer +X-KDE-ParentComponents=korganizer,kontact_korganizerplugin +X-KDE-CfgDlgHierarchy=KOrganizer + +Name=Personal +Name[af]=Persoonlik +Name[ar]=الشخصي +Name[be]=Пэрсанальныя +Name[bg]=Персоналност +Name[br]=Diouzhoc'h +Name[bs]=Lično +Name[cs]=Osobní +Name[cy]=Personol +Name[da]=Personlig +Name[de]=Persönliches +Name[el]=Προσωπικό +Name[eo]=Personaĵoj +Name[et]=Isiklik +Name[eu]=Pertsonala +Name[fa]=شخصی +Name[fi]=Henkilökohtainen +Name[fr]=Personnel +Name[fy]=Persoanlik +Name[ga]=Pearsanta +Name[gl]=Persoal +Name[he]=אישי +Name[hi]=निजी +Name[hu]=Alapbeállítások +Name[is]=Persónulegt +Name[it]=Personale +Name[ja]=個人設定 +Name[ka]=პირადი +Name[kk]=Дербес +Name[km]=ផ្ទាល់ខ្លួន +Name[lt]=Suasmeninimas +Name[mk]=Лично +Name[ms]=Peribadi +Name[nb]=Personlig +Name[nds]=Persöönlich +Name[ne]=व्यक्तिगत +Name[nl]=Persoonlijk +Name[nn]=Personleg +Name[pl]=Osobiste +Name[pt]=Pessoal +Name[pt_BR]=Pessoal +Name[ru]=Общие +Name[se]=Peršuvnnalaš +Name[sk]=Osobné +Name[sl]=Osebno +Name[sr]=Лично +Name[sr@Latn]=Lično +Name[sv]=Personlig inställning +Name[ta]=அந்தரங்கமான +Name[tg]=Танзимотҳои шахсӣ +Name[tr]=Kişisel +Name[uk]=Особисті +Name[uz]=Shaxsiy +Name[uz@cyrillic]=Шахсий +Name[zh_CN]=个人 +Name[zh_TW]=個人 +Comment=KOrganizer Main Configuration +Comment[af]=KOrganizer hoof opstelling +Comment[bg]=Главни настройки за KOrganizer +Comment[br]=Kefluniadur kentañ KOrganizer +Comment[bs]=KOrganizer glavno podešavanje +Comment[ca]=Configuració principal a KOrganizer +Comment[cs]=Hlavní nastavení KOrganizeru +Comment[cy]=Prif Ffurfweddiad KTrefnydd +Comment[da]=KOrganizer hovedindstilling +Comment[de]=Grundeinrichtung für KOrganizer +Comment[el]=Κύρια ρύθμιση του KOrganizer +Comment[eo]=KOrganizilo-Ĉefagordo +Comment[es]=Configuración principal de KOrganizer +Comment[et]=KOrganizeri põhiseadistused +Comment[eu]=KOrganizer-en konfigurazio nagusia +Comment[fa]=پیکربندی اصلی KOrganizer +Comment[fi]=KOrganizerin pääasetukset +Comment[fr]=Configuration principale de KOrganizer +Comment[fy]=KOrganizer algemiene ynstellings +Comment[ga]=Príomhchumraíocht KOrganizer +Comment[gl]=Configuración Principal de KOrganizer +Comment[he]=תצורה ראשית של הארגונית +Comment[hi]=के-आर्गेनाइज़र मुख्य कॉन्फ़िगरेशन +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 +Comment[mk]=Главна конфигурација на КОрганизатор +Comment[ms]=Konfigurasi Utama KOrganizer +Comment[nb]=KOrganizer hovedoppsett +Comment[nds]=Hööftinstellen för KOrganizer +Comment[ne]=केडीई आयोजक मुख्य कन्फिगरेसन +Comment[nl]=KOrganizer algemene instellingen +Comment[nn]=KOrganizer, hovudinnstillingar +Comment[pl]=Główna konfiguracja KOrganizera +Comment[pt]=Configuração Principal do KOrganizer +Comment[pt_BR]=Configuração Principal do KOrganizer +Comment[ru]=Общие настройки органайзера KDE +Comment[se]=Korganizer, váldoheivehusat +Comment[sk]=Hlavné nastavenie KOrganizer +Comment[sl]=Glavne nastavitve KOrganizerja +Comment[sr]=Главна подешавања у KOrganizer-у +Comment[sr@Latn]=Glavna podešavanja u KOrganizer-u +Comment[sv]=Korganizers huvudinställning +Comment[ta]=கேஅமைப்பாளர் முக்கிய கட்டமைப்பு +Comment[tg]=Танзимотҳои умумии органайзер-KDE +Comment[tr]=KOrganizer Temel Yapılandırması +Comment[uk]=Налаштування особистих даних у KOrganizer +Comment[zh_CN]=KOrganizer 主要配置 +Comment[zh_TW]=KOrganizer 主設定 +Keywords=korganizer,main,personal +Keywords[bg]=организатор, главни, персонални, настройки, korganizer, main, personal +Keywords[bs]=korganizer,main,personal,lično +Keywords[ca]=korganizer,principal,personal +Keywords[cs]=korganizer,hlavní,osobní +Keywords[cy]=korganizer,ktrefnydd,prif,personol +Keywords[da]=korganizer,hoved,personlig +Keywords[de]=KOrganizer,Persönliches +Keywords[el]=korganizer,κύρια,προσωπικό +Keywords[es]=korganizer,principal,personal +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[fy]=korganizer,algemien, persoanlik +Keywords[gl]=korganizer,principal,persoal +Keywords[he]=korganizer,main,personal,ארגונית,תצורה,הגדרה,הגדרות +Keywords[hi]=के-आर्गेनाइज़र,मुख्य,निजी +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,корганизатор,главно,лично +Keywords[ms]=korganizer,utama,peribadi +Keywords[nb]=korganizer,hoved,personlig +Keywords[nds]=KOrganizer,hööft,persöönlich,instellen,hööftinstellen +Keywords[ne]=केडीई आयोजक, मुख्य, व्यक्तिगत +Keywords[nl]=korganizer,algemeen,persoonlijk +Keywords[nn]=korganizer,hovud,personleg +Keywords[pl]=korganizer,główny,główna,osobisty,osobista,osobiste +Keywords[pt]=korganizer,principal,pessoal +Keywords[pt_BR]=korganizer,principal,pessoal +Keywords[ro]=korganizer,principal,personal +Keywords[ru]=korganizer,main,personal,почта,персональные настройки,органайзер +Keywords[sk]=korganizer,hlavné,osobné +Keywords[sl]=korganizer,glavne,osebne +Keywords[sr]=korganizer,main,personal,планер,главни,лични,лично +Keywords[sr@Latn]=korganizer,main,personal,planer,glavni,lični,lično +Keywords[sv]=korganizer,huvudinställning,personlig inställning +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[zh_CN]=korganizer,main,personal,主要,个人 diff --git a/korganizer/korganizer_configplugins.desktop b/korganizer/korganizer_configplugins.desktop new file mode 100644 index 000000000..7e4c332a2 --- /dev/null +++ b/korganizer/korganizer_configplugins.desktop @@ -0,0 +1,156 @@ +[Desktop Entry] +Icon=identity +Type=Service +ServiceTypes=KCModule + +X-KDE-ModuleType=Library +X-KDE-Library=korganizer +X-KDE-FactoryName=korganizerconfigplugins +X-KDE-HasReadOnlyMode=false +X-KDE-ParentApp=korganizer +X-KDE-ParentComponents=korganizer,kontact_korganizerplugin +X-KDE-CfgDlgHierarchy=KOrganizer + +Name=Plugins +Name[af]=Inprop modules +Name[ar]=القوابس +Name[be]=Дапаўненні +Name[bg]=Приставки +Name[br]=Lugantoù +Name[ca]=Endollables +Name[cs]=Moduly +Name[cy]=Ategion +Name[da]=Plugin +Name[de]=Module +Name[el]=Πρόσθετα +Name[eo]=Kromaĵoj +Name[es]=Extensiones +Name[et]=Pluginad +Name[eu]=Plugin-ak +Name[fa]=وصلهها +Name[fi]=Liitännäiset +Name[fr]=Modules externes +Name[ga]=Breiseáin +Name[gl]=Extensións +Name[he]=תוספים +Name[hu]=Bővítőmodulok +Name[is]=Íforrit +Name[it]=Plugin +Name[ja]=プラグイン +Name[ka]=მოდულები +Name[kk]=Плагин модульдері +Name[km]=កម្មវិធីជំនួយ +Name[lt]=Priedai +Name[mk]=Приклучоци +Name[ms]=Plugin +Name[nb]=Programtillegg +Name[nds]=Modulen +Name[ne]=प्लगइन +Name[nn]=Programtillegg +Name[pl]=Wtyczki +Name[pt]='Plugins' +Name[ru]=Модули +Name[rw]=Amacomeka +Name[sk]=Moduly +Name[sl]=Vstavki +Name[sr]=Прикључци +Name[sr@Latn]=Priključci +Name[sv]=Insticksprogram +Name[ta]=சொருகுப்பொருள்கள் +Name[tr]=Eklentiler +Name[uk]=Втулки +Name[uz]=Plaginlar +Name[uz@cyrillic]=Плагинлар +Name[zh_CN]=插件 +Name[zh_TW]=外掛程式 +Comment=KOrganizer Plugin Configuration +Comment[af]=Korganizer inprop module opstelling +Comment[be]=Канфігурацыя дапаўненняў "K Арганізатара" +Comment[bg]=Настройки на приставките за KOrganizer +Comment[br]=Kefluniadur al lugent KOrganizer +Comment[ca]=Configuració de l'endollable de KOrganizer +Comment[cs]=Nastavení modulů KOrganizeru +Comment[da]=KOrganizer plugin-indstilling +Comment[de]=Modul-Einrichtung für KOrganizer +Comment[el]=Ρύθμιση προσθέτων του KOrganizer +Comment[eo]=KOrganizilo-Kromaĵagordo +Comment[es]=Configuración de las extensiones de KOrganizer +Comment[et]=KOrganizeri pluginate seadistused +Comment[eu]=KOrganizer-en plugin konfigurazioa +Comment[fa]=پیکربندی وصلۀ KOrganizer +Comment[fi]=KOrganizerin liitännäisen asetukset +Comment[fr]=Configuration du module KOrganizer +Comment[fy]=KOrganizer pluginynstellings +Comment[gl]=Configuración de Extensións de KOrganizer +Comment[he]=הגדרות תוסף הארגונית +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 +Comment[mk]=Конфигурација на приклучоци +Comment[ms]=Konfigurasi Plugin KOrganizer +Comment[nb]=KOrganizer oppsett for programtillegg +Comment[nds]=Modulen för KOrganizer instellen +Comment[ne]=केडीई आयोजक प्लगइन कन्फिगरेसन +Comment[nl]=KOrganizer plugininstellingen +Comment[nn]=Oppsett av KOrganizer-programtillegg +Comment[pl]=Konfiguracja wtyczek KOrganizera +Comment[pt]=Configuração de 'Plugins' do KOrganizer +Comment[pt_BR]=Configuração dos Plug-ins do KOrganizer +Comment[ru]=Настройки модуля KOrganizer +Comment[sk]=Nastavenie modulu KOrganizer +Comment[sl]=Nastavitve vstavka KOrganizerja +Comment[sr]=Подешавање прикључака KOrganizer-а +Comment[sr@Latn]=Podešavanje priključaka KOrganizer-a +Comment[sv]=Korganizers inställning av insticksprogram +Comment[ta]=கேஅமைப்பாளர் சொருகுப்பொருள் வடிவமைப்பு +Comment[tr]=KOrganizer Eklenti Yapılandırması +Comment[uk]=Втулок налаштування KOrganizer +Comment[zh_CN]=KOrganizer 插件配置 +Comment[zh_TW]=KOrganizer外掛程式設定 +Keywords=korganizer,plugin,module +Keywords[be]=K Арганізатар,дапаўненне,модуль,korganizer,plugin,module +Keywords[bg]=организатор, модул, приставка, korganizer, plugin, module +Keywords[ca]=korganizer,endollable,mòdul +Keywords[cs]=korganizer,modul +Keywords[da]=korganizer,plugin,modul +Keywords[de]=KOrganizer,Modul,Plugin +Keywords[el]=korganizer,πρόσθετο,άρθρωμα +Keywords[es]=korganizer,extensión,plugin,módulo +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[ga]=korganizer,breiseán,modúl +Keywords[gl]=korganizer,extensión,módulo +Keywords[he]=korganizer,plugin,module,מודול,תוסף,ארגונית +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,корганизатор,приклучок,приклучоци,модул.модули +Keywords[ms]=korganizer,plugin,modul +Keywords[nb]=korganizer,programtillegg,modul +Keywords[nds]=KOrganizer,Moduul,Modulen,Plugins +Keywords[ne]=केडीई आयोजक, प्लगइन, मोड्युल +Keywords[nn]=korganizer,programtillegg,modul +Keywords[pl]=korganizer,wtyczka,moduł +Keywords[pt]=korganizer,'plugin',módulo +Keywords[pt_BR]=korganizer,plugin,módulo +Keywords[ru]=korganizer,plugin,module,органайзер,модуль +Keywords[sl]=korganizer,vstavek,modul +Keywords[sr]=korganizer,plugin,module,прикључак,модул +Keywords[sr@Latn]=korganizer,plugin,module,priključak,modul +Keywords[sv]=korganizer,insticksprogram,modul +Keywords[ta]=கேஅமைப்பாளர்,சொருகுப்பொருள்,பகுதி +Keywords[tr]=korganizer,eklenti,modül +Keywords[uk]=korganizer,plugin,module,втулок,модуль +Keywords[zh_CN]=korganizer,plugin,module,插件,模块 diff --git a/korganizer/korganizer_configtime.desktop b/korganizer/korganizer_configtime.desktop new file mode 100644 index 000000000..72d7629a1 --- /dev/null +++ b/korganizer/korganizer_configtime.desktop @@ -0,0 +1,180 @@ +[Desktop Entry] +Icon=clock +Type=Service +ServiceTypes=KCModule + +X-KDE-ModuleType=Library +X-KDE-Library=korganizer +X-KDE-FactoryName=korganizerconfigtime +X-KDE-HasReadOnlyMode=false +X-KDE-ParentApp=korganizer +X-KDE-ParentComponents=korganizer,kontact_korganizerplugin +X-KDE-CfgDlgHierarchy=KOrganizer + +Name=Time & Date +Name[af]=Datum & Tyd +Name[ar]=الوقت و التاريخ +Name[be]=Час і дата +Name[bg]=Дата и час +Name[br]=Deiziad hag eur +Name[bs]=Vrijeme i datum +Name[ca]=Hora i data +Name[cs]=Datum a čas +Name[cy]=Amser & Dyddiad +Name[da]=Tid & Dato +Name[de]=Zeit & Datum +Name[el]=Ώρα & Ημερομηνία +Name[eo]=Tempo & Dato +Name[es]=Fecha y hora +Name[et]=Aeg +Name[eu]=Ordua eta data +Name[fa]=زمان و تاریخ +Name[fi]=Aika ja päiväys +Name[fr]=Date et heure +Name[fy]=Datum & tiid +Name[ga]=Am & Dáta +Name[gl]=Hora e Data +Name[he]=תאריך ושעה +Name[hi]=तारीख़ व समय +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 +Name[mk]=Датуми и времиња +Name[ms]=Waktu & Tarikh +Name[nb]=Dato og klokkeslett +Name[nds]=Tiet & Datum +Name[ne]=मिति र समय +Name[nl]=Datum & tijd +Name[nn]=Tidsinnstillingar +Name[pl]=Czas i data +Name[pt]=Data e Hora +Name[pt_BR]=Data & Hora +Name[ro]=Timp şi dată +Name[ru]=Дата и время +Name[se]=Áigi ja beaivvit +Name[sk]=Dátum a čas +Name[sl]=Čas in datum +Name[sr]=Време и датум +Name[sr@Latn]=Vreme i datum +Name[sv]=Tid och datum +Name[ta]=நேரம் & தேதி +Name[tg]=Сана ва вақт +Name[tr]=Saat & Tarih +Name[uk]=Час та дата +Name[uz]=Sana va vaqt +Name[uz@cyrillic]=Сана ва вақт +Name[zh_CN]=时间和日期 +Name[zh_TW]=時間與日期 +Comment=KOrganizer Time Configuration +Comment[af]=KOrganizer tyd opstelling +Comment[ar]=إعداد الوقت لِــ KOrganizer +Comment[be]=Канфігурацыя часу "K Арганізатара" +Comment[bg]=Настройки на дата и час за KOrganizer +Comment[bs]=KOrganizer podešavanje vremena +Comment[ca]=Configuració del temps a KOrganizer +Comment[cs]=Nastavení času v KOrganizeru +Comment[cy]=Ffurfweddiad Amser KTrefnydd +Comment[da]=KOrganizer tidsindstilling +Comment[de]=Zeitliche Vorgaben für KOrganizer +Comment[el]=Ρύθμιση ώρας του KOrganizer +Comment[eo]=KOrganizilo-tempagordo +Comment[es]=Configuración de la hora de KOrganizer +Comment[et]=KOrganizeri ajaseadistused +Comment[eu]=KOrganizer-en ordu/data konfigurazioa +Comment[fa]=پیکربندی زمان KOrganizer +Comment[fi]=KOrganizerin aika-asetukset +Comment[fr]=Configuration de l'heure de KOrganizer +Comment[fy]=KOrganizer datum en tiid ynstelle +Comment[gl]=Configuración de Hora de KOrganizer +Comment[he]=הגדרות שעה בארגונית +Comment[hi]=के-आर्गेनाइज़र समय कॉन्फ़िगरेशन +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 +Comment[mk]=Конфигурација на датуми и времиња +Comment[ms]=Konfigurasi Waktu KOrganizer +Comment[nb]=KOrganizer tidsoppsett +Comment[nds]=Tietinstellen för KOrganizer +Comment[ne]=केडीई आयोजक समय कन्फिगरेसन +Comment[nl]=KOrganizer datum en tijd instellen +Comment[nn]=KOrganizer, tidsinnstillingar +Comment[pl]=Konfiguracja czasu dla KOrganizera +Comment[pt]=Configuração da Hora no KOrganizer +Comment[pt_BR]=Configuração de Tempo do KOrganizer +Comment[ro]=Configurare timp KOrganizer +Comment[ru]=Настройка времени органайзера KDE +Comment[sk]=Nastavenie času pre KOrganizer +Comment[sl]=Nastavitev časa v KOrganizerju +Comment[sr]=Подешавање времена у KOrganizer-у +Comment[sr@Latn]=Podešavanje vremena u KOrganizer-u +Comment[sv]=Inställning av Korganizers tid +Comment[ta]=கேஅமைப்பாளர் நேர கட்டமைப்பு +Comment[tg]=Танзимоти вақти органайзери KDE +Comment[tr]=KOrganizer Zaman Yapılandırması +Comment[uk]=Налаштування часу та дати в KOrganizer +Comment[zh_CN]=KOrganizer 时间配置 +Comment[zh_TW]=KOrganizer 時間設定 +Keywords=korganizer,time +Keywords[be]=K Арганізатар,час,korganizer,time +Keywords[bg]=организатор, дата, час, настройки, korganizer, time +Keywords[br]=korganizer,amzer +Keywords[bs]=korganizer,time,vrijeme +Keywords[ca]=korganizer,temps +Keywords[cs]=korganizer,čas +Keywords[cy]=korganizer,ktrefnydd,amser +Keywords[da]=korganizer,tid +Keywords[de]=KOrganizer,Zeit +Keywords[el]=korganizer,ώρα +Keywords[eo]=korganizilo,tempo +Keywords[es]=korganizer,hora +Keywords[et]=korganizer,aeg +Keywords[eu]=korganizer,ordua,data +Keywords[fa]=korganizer،زمان +Keywords[fi]=korganizer,aika +Keywords[fr]=korganizer,date +Keywords[fy]=datum,tijd,tiid,korganizer +Keywords[ga]=korganizer,am +Keywords[gl]=korganizer,hora +Keywords[he]=korganizer,time,ארגונית,שעה +Keywords[hi]=के-आर्गेनाइज़र,समय +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,корганизатор,датум,време +Keywords[ms]=korganizer,waktu +Keywords[nb]=korganizer,tid +Keywords[nds]=KOrganizer,Tiet +Keywords[ne]=केडीई आयोजक, समय +Keywords[nl]=datum,tijd,korganizer +Keywords[nn]=korganizer,tid +Keywords[pl]=korganizer,czas,data,daty +Keywords[pt]=korganizer,hora +Keywords[pt_BR]=korganizer,tempo +Keywords[ro]=korganizer,timp +Keywords[ru]=korganizer,time,органайзер,время +Keywords[sk]=korganizer,čas +Keywords[sl]=korganizer,čas +Keywords[sr]=korganizer,time,време,планер +Keywords[sr@Latn]=korganizer,time,vreme,planer +Keywords[sv]=korganizer,tid +Keywords[ta]=கேஅமைப்பாளர்,நேரம் +Keywords[tg]=korganizer,time,органайзер,вақт +Keywords[tr]=korganizer,zaman +Keywords[uk]=korganizer,час,дата +Keywords[uz]=korganizer,organayzer,sana,vaqt +Keywords[uz@cyrillic]=korganizer,органайзер,сана,вақт +Keywords[zh_CN]=korganizer,time,时间 diff --git a/korganizer/korganizer_configviews.desktop b/korganizer/korganizer_configviews.desktop new file mode 100644 index 000000000..dd20819ac --- /dev/null +++ b/korganizer/korganizer_configviews.desktop @@ -0,0 +1,175 @@ +[Desktop Entry] +Icon=viewmag +Type=Service +ServiceTypes=KCModule + +X-KDE-ModuleType=Library +X-KDE-Library=korganizer +X-KDE-FactoryName=korganizerconfigviews +X-KDE-HasReadOnlyMode=false +X-KDE-ParentApp=korganizer +X-KDE-ParentComponents=korganizer,kontact_korganizerplugin +X-KDE-CfgDlgHierarchy=KOrganizer + +Name=Views +Name[af]=Aansigte +Name[ar]=العروض +Name[be]=Выгляды +Name[bg]=Изгледи +Name[br]=Gweloù +Name[bs]=Pogledi +Name[ca]=Vistes +Name[cs]=Pohledy +Name[cy]=Golygon +Name[da]=Visninger +Name[de]=Ansichten +Name[el]=Προβολές +Name[eo]=Rigardoj +Name[es]=Vistas +Name[et]=Vaated +Name[eu]=Ikuspegiak +Name[fa]=نماها +Name[fi]=Näkymät +Name[fr]=Vues +Name[fy]=Werjeften +Name[ga]=Amhairc +Name[gl]=Vistas +Name[he]=תצוגות +Name[hi]=दृश्य +Name[hu]=Nézetek +Name[is]=Sýnir +Name[it]=Viste +Name[ja]=ビューア +Name[ka]=ხედები +Name[kk]=Көріністері +Name[km]=ទិដ្ឋភាព +Name[lt]=Žiūrikliai +Name[mk]=Приказ +Name[ms]=Paparan +Name[nb]=Visninger +Name[nds]=Ansichten +Name[ne]=दृश्य +Name[nl]=Weergaven +Name[nn]=Visingar +Name[pl]=Widoki +Name[pt]=Janelas +Name[pt_BR]=Visões +Name[ro]=Vizualizări +Name[ru]=Вид +Name[se]=Čájeheamit +Name[sk]=Pohľady +Name[sl]=Prikazi +Name[sr]=Прикази +Name[sr@Latn]=Prikazi +Name[sv]=Vyer +Name[ta]=காட்சிகள் +Name[tg]=Намудҳо +Name[tr]=Görünümler +Name[uk]=Перегляди +Name[uz]=Koʻrinishlar +Name[uz@cyrillic]=Кўринишлар +Name[zh_CN]=视图 +Name[zh_TW]=檢視 +Comment=KOrganizer View Configuration +Comment[af]=KOrganizer aansig opstelling +Comment[be]=Канфігурацыя выгляду "K Арганізатара" +Comment[bg]=Настройки на изгледи за KOrganizer +Comment[bs]=KOrganizer podešavanje pogleda +Comment[ca]=Configuració de la vista a KOrganizer +Comment[cs]=Nastavení pohledů KOrganizeru +Comment[cy]=Ffurfweddiad Golygon KTrefnydd +Comment[da]=KOrganizer visningsindstilling +Comment[de]=Ansichts-Einstellungen für KOrganizer +Comment[el]=Ρύθμιση προβολής του KOrganizer +Comment[eo]=KOrganizilo-Rigardagordo +Comment[es]=Configuración de la vista de KOrganizer +Comment[et]=KOrganizeri vaateseadistused +Comment[eu]=KOrganizer-en ikuspegi konfigurazioa +Comment[fa]=پیکربندی نمای KOrganizer +Comment[fi]=KOrganizerin näkymäasetukset +Comment[fr]=Configuration des vues de KOrganizer +Comment[fy]=KOrganizer werjefte ynstelle +Comment[gl]=Configuración de Vista de KOrganizer +Comment[hi]=के-आर्गेनाइज़र दृश्य कॉन्फ़िगरेशन +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 +Comment[mk]=Конфигурација на приказот +Comment[ms]=Konfigurasi Paparan KOrganizer +Comment[nb]=KOrganizer visningsoppsett +Comment[nds]=Ansichteninstellen för KOrganizer +Comment[ne]=केडीई आयोजक दृश्य कन्फिगरेसन +Comment[nl]=KOrganizer weergave instellen +Comment[nn]=KOrganizer, visingsinnstillingar +Comment[pl]=Konfiguracja widoków KOrganizera +Comment[pt]=Configuração da Janela do KOrganizer +Comment[pt_BR]=Configuração de Visões do KOrganizer +Comment[ru]=Настройка видов органайзера KDE +Comment[sk]=Nastavenie pohľadov pre KOrganizer +Comment[sl]=Nastavitev prikaza KOrganizerja +Comment[sr]=Подешавање приказа у KOrganizer-у +Comment[sr@Latn]=Podešavanje prikaza u KOrganizer-u +Comment[sv]=Inställning av Korganizers vyer +Comment[ta]=கேஅமைப்பாளர் காட்சி கட்டமைப்பு +Comment[tg]=Танзимоти намудҳои органайзери KDE +Comment[tr]=KOrganizer Görünüm Yapılandırması +Comment[uk]=Налаштування переглядів у KOrganizer +Comment[zh_CN]=KOrganizer 视图配置 +Comment[zh_TW]=KOrganizer 檢視設定 +Keywords=korganizer,view +Keywords[be]=K Арганізатар,выгляд,korganizer,view +Keywords[bg]=организатор, изглед, изгледи, настройки, korganizer, view +Keywords[br]=korganizer,gwell +Keywords[bs]=korganizer,view,pogled +Keywords[ca]=korganizer,vista +Keywords[cs]=korganizer,pohled +Keywords[cy]=korganizer,ktrefnydd,golwg +Keywords[da]=korganizer,visning +Keywords[de]=KOrganizer,Ansicht +Keywords[el]=korganizer,προβολή +Keywords[eo]=korganizilo,rigardo +Keywords[es]=korganizer,vista +Keywords[et]=korganizer,vaade +Keywords[eu]=korganizer,ikuspegia +Keywords[fa]=korganizer،نما +Keywords[fi]=korganizer,näkymä +Keywords[fr]=korganizer,vues +Keywords[fy]=korganizer,weergave, werjefte +Keywords[ga]=korganizer,amharc +Keywords[gl]=korganizer,vista +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,корганизатор,приказ +Keywords[ms]=korganizer,paparan +Keywords[nb]=korganizer,visning +Keywords[nds]=KOrganizer,Ansichten +Keywords[ne]=केडीई आयोजक, दृश्य +Keywords[nl]=korganizer,weergave +Keywords[nn]=korganizer,vising +Keywords[pl]=korganizer,widok +Keywords[pt]=korganizer,janela +Keywords[pt_BR]=korganizer,visão +Keywords[ro]=korganizer,vizualizare +Keywords[ru]=korganizer,view,органайзер,виды +Keywords[sk]=korganizer,pohľad,zobrazenie +Keywords[sl]=korganizer,prikaz +Keywords[sr]=korganizer,view,планер,приказ +Keywords[sr@Latn]=korganizer,view,planer,prikaz +Keywords[sv]=korganizer,vy +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[zh_CN]=korganizer,view,视图 diff --git a/korganizer/korganizer_options.h b/korganizer/korganizer_options.h new file mode 100644 index 000000000..cbe7e036b --- /dev/null +++ b/korganizer/korganizer_options.h @@ -0,0 +1,45 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1997-1999 Preston Brown <pbrown@kde.org> + Copyright (c) 2001,2003 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#ifndef KORGANIZER_OPTIONS_H +#define KORGANIZER_OPTIONS_H + +#include <kcmdlineargs.h> +#include <klocale.h> + +static const KCmdLineOptions korganizer_options[] = +{ + { "i", 0, 0 }, + { "import", I18N_NOOP("Import the given calendars as new resources into the default calendar"), 0 }, + { "m", 0, 0 }, + { "merge", I18N_NOOP("Merge the given calendars into the standard calendar (i.e. copy the events)"), 0 }, + { "o", 0, 0 }, + { "open", I18N_NOOP("Open the given calendars in a new window"), 0 }, + { "+[calendars]", I18N_NOOP("Calendar files or urls. Unless -i, -o or -m is explicitly specified, the user will be asked whether to import, merge or open in a separate window."), 0 }, + KCmdLineLastOption +}; + +#endif /* KORGANIZER_OPTIONS_H */ + diff --git a/korganizer/korganizer_part.cpp b/korganizer/korganizer_part.cpp new file mode 100644 index 000000000..32786943d --- /dev/null +++ b/korganizer/korganizer_part.cpp @@ -0,0 +1,237 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2000 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "korganizer_part.h" + +#include "calendarview.h" +#include "actionmanager.h" +#include "koglobals.h" +#include "koprefs.h" +#include "resourceview.h" +#include "aboutdata.h" +#include "kocore.h" +#include "korganizerifaceimpl.h" +#include "stdcalendar.h" +#include "alarmclient.h" + +#include <libkcal/calendarlocal.h> +#include <libkcal/calendarresources.h> +#include <libkcal/resourcecalendar.h> + +#include <kpopupmenu.h> +#include <kinstance.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kaction.h> +#include <kdebug.h> +#include <kstandarddirs.h> +#include <kconfig.h> +#include <kprocess.h> +#include <ktempfile.h> +#include <kstatusbar.h> +#include <kparts/genericfactory.h> + +#include <kparts/statusbarextension.h> + +#include <sidebarextension.h> +#include <infoextension.h> + +#include <qapplication.h> +#include <qfile.h> +#include <qtimer.h> +#include <qlayout.h> + +typedef KParts::GenericFactory< KOrganizerPart > KOrganizerFactory; +K_EXPORT_COMPONENT_FACTORY( libkorganizerpart, KOrganizerFactory ) + +KOrganizerPart::KOrganizerPart( QWidget *parentWidget, const char *widgetName, + QObject *parent, const char *name, + const QStringList & ) : + KParts::ReadOnlyPart(parent, name), mTopLevelWidget( parentWidget->topLevelWidget() ) +{ + KGlobal::locale()->insertCatalogue( "libkcal" ); + KGlobal::locale()->insertCatalogue( "libkdepim" ); + KGlobal::locale()->insertCatalogue( "kdgantt" ); + + KOCore::self()->addXMLGUIClient( mTopLevelWidget, this ); + + QString pname( name ); + + // create a canvas to insert our widget + QWidget *canvas = new QWidget( parentWidget, widgetName ); + canvas->setFocusPolicy( QWidget::ClickFocus ); + setWidget( canvas ); + mView = new CalendarView( canvas ); + + mActionManager = new ActionManager( this, mView, this, this, true ); + (void)new KOrganizerIfaceImpl( mActionManager, this, "IfaceImpl" ); + + if ( pname == "kontact" ) { + mActionManager->createCalendarResources(); + setHasDocument( false ); + KOrg::StdCalendar::self()->load(); + mView->updateCategories(); + } else { + mActionManager->createCalendarLocal(); + setHasDocument( true ); + } + + mStatusBarExtension = new KParts::StatusBarExtension( this ); + + setInstance( KOrganizerFactory::instance() ); + + QVBoxLayout *topLayout = new QVBoxLayout( canvas ); + topLayout->addWidget( mView ); + + new KParts::SideBarExtension( mView->leftFrame(), this, "SBE" ); + + KParts::InfoExtension *ie = new KParts::InfoExtension( this, + "KOrganizerInfo" ); + connect( mView, SIGNAL( incidenceSelected( Incidence * ) ), + SLOT( slotChangeInfo( Incidence * ) ) ); + connect( this, SIGNAL( textChanged( const QString & ) ), + ie, SIGNAL( textChanged( const QString & ) ) ); + + mActionManager->init(); + mActionManager->readSettings(); + + setXMLFile( "korganizer_part.rc" ); + mActionManager->loadParts(); + setTitle(); +} + +KOrganizerPart::~KOrganizerPart() +{ + mActionManager->saveCalendar(); + mActionManager->writeSettings(); + + delete mActionManager; + mActionManager = 0; + + closeURL(); + + KOCore::self()->removeXMLGUIClient( mTopLevelWidget ); +} + +KAboutData *KOrganizerPart::createAboutData() +{ + return new KOrg::AboutData; +} + +void KOrganizerPart::startCompleted( KProcess *process ) +{ + delete process; +} + +void KOrganizerPart::slotChangeInfo( Incidence *incidence ) +{ + if ( incidence ) { + emit textChanged( incidence->summary() + " / " + + incidence->dtStartTimeStr() ); + } else { + emit textChanged( QString::null ); + } +} + +QWidget *KOrganizerPart::topLevelWidget() +{ + return mView->topLevelWidget(); +} + +ActionManager *KOrganizerPart::actionManager() +{ + return mActionManager; +} + +void KOrganizerPart::showStatusMessage( const QString &message ) +{ + KStatusBar *statusBar = mStatusBarExtension->statusBar(); + if ( statusBar ) statusBar->message( message ); +} + +KOrg::CalendarViewBase *KOrganizerPart::view() const +{ + return mView; +} + +bool KOrganizerPart::openURL( const KURL &url, bool merge ) +{ + return mActionManager->openURL( url, merge ); +} + +bool KOrganizerPart::saveURL() +{ + return mActionManager->saveURL(); +} + +bool KOrganizerPart::saveAsURL( const KURL &kurl ) +{ + return mActionManager->saveAsURL( kurl ); +} + +KURL KOrganizerPart::getCurrentURL() const +{ + return mActionManager->url(); +} + +bool KOrganizerPart::openFile() +{ + mView->openCalendar( m_file ); + mView->show(); + return true; +} + +// FIXME: This is copied verbatim from the KOrganizer class. Move it to the common base class! +void KOrganizerPart::setTitle() +{ +// kdDebug(5850) << "KOrganizer::setTitle" << endl; +// FIXME: Inside kontact we want to have different titles depending on the +// type of view (calendar, to-do, journal). How can I add the filter +// name in that case? +/* + QString title; + if ( !hasDocument() ) { + title = i18n("Calendar"); + } else { + KURL url = mActionManager->url(); + + if ( !url.isEmpty() ) { + if ( url.isLocalFile() ) title = url.fileName(); + else title = url.prettyURL(); + } else { + title = i18n("New Calendar"); + } + + if ( mView->isReadOnly() ) { + title += " [" + i18n("read-only") + "]"; + } + } + + title += " - <" + mView->currentFilterName() + "> "; + + emit setWindowCaption( title );*/ +} + +#include "korganizer_part.moc" diff --git a/korganizer/korganizer_part.h b/korganizer/korganizer_part.h new file mode 100644 index 000000000..cb1bf99c9 --- /dev/null +++ b/korganizer/korganizer_part.h @@ -0,0 +1,105 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2000,2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KORGANIZER_PART_H +#define KORGANIZER_PART_H + +#include <kurl.h> +#include <kparts/part.h> + +#include <korganizer/mainwindow.h> + + +class KInstance; +class KAboutData; +class KProcess; + +class CalendarView; +class ActionManager; + +namespace KCal { + class CalendarResources; + class Calendar; + class Incidence; +} +using namespace KCal; +namespace KParts { +class StatusBarExtension; +} +namespace KOrg { +class CalendarViewBase; +} + +class KOrganizerPart: public KParts::ReadOnlyPart, + public KOrg::MainWindow +{ + Q_OBJECT + public: + KOrganizerPart( QWidget *parentWidget, const char *widgetName, + QObject *parent, const char *name, const QStringList & ); + virtual ~KOrganizerPart(); + + static KAboutData *createAboutData(); + + virtual KOrg::CalendarViewBase *view() const; + + /** Load calendar file from URL. Merge into current calendar, if \a merge is true. */ + virtual bool openURL( const KURL &url, bool merge = false ); + /** Save calendar file to URL of current calendar */ + virtual bool saveURL(); + /** Save calendar file to URL */ + virtual bool saveAsURL( const KURL &kurl ); + + /** Get current URL */ + virtual KURL getCurrentURL() const; + + virtual KXMLGUIFactory *mainGuiFactory() { return factory(); } + virtual KXMLGUIClient *mainGuiClient() { return this; } + virtual QWidget *topLevelWidget(); + virtual ActionManager *actionManager(); + virtual KActionCollection *getActionCollection() const { return actionCollection(); } + virtual void showStatusMessage( const QString &message ); + + void setTitle(); + + public slots: + void slotChangeInfo( Incidence * ); + + protected: + virtual bool openFile(); + + protected slots: + void startCompleted( KProcess * ); + + private: + CalendarView *mView; + ActionManager *mActionManager; + KParts::StatusBarExtension *mStatusBarExtension; + QWidget *mTopLevelWidget; + + signals: + void textChanged( const QString & ); +}; + +#endif diff --git a/korganizer/korganizer_part.rc b/korganizer/korganizer_part.rc new file mode 100644 index 000000000..da92935a0 --- /dev/null +++ b/korganizer/korganizer_part.rc @@ -0,0 +1,175 @@ +<!DOCTYPE kpartgui> +<kpartgui name="korganizer" version="43"> + + <MenuBar> + <Menu name="file"><text>&File</text> + <Merge/> + <Action name="print_setup" append="print_merge"/> + <Action name="korganizer_print"/> + <Action name="korganizer_quickprint"/> + <Separator/> + <Menu name="import"><text>&Import</text> + <Action name="import_icalendar"/> + <Action name="import_ical"/> + <Merge/> + <Separator/> + <Action name="downloadnewstuff"/> + </Menu> + <Menu name="export"><text>&Export</text> + <Action name="export_web" /> + <Action name="export_icalendar"/> + <Action name="export_vcalendar"/> + <Merge/> + <Separator/> + <Action name="uploadnewstuff"/> + </Menu> + <Separator/> + <Action name="file_archive"/> + <Action name="purge_completed"/> + <Separator/> + <Action name="korganizer_close"/> + </Menu> + <Menu name="edit"><text>&Edit</text> + <Action name="korganizer_undo"/> + <Action name="korganizer_redo"/> + <Separator/> + <Action name="korganizer_cut"/> + <Action name="korganizer_copy"/> + <Action name="korganizer_paste"/> + <Separator/> + <Action name="edit_delete" append="edit_paste_merge"/> + <Separator/> + <Action name="korganizer_find"/> + </Menu> + <Menu name="view"><text>&View</text> + <Action name="view_whatsnext"/> + <Separator/> + <Action name="view_day"/> + <Action name="view_nextx"/> + <Action name="view_workweek"/> + <Action name="view_week"/> + <Action name="view_month"/> + <Action name="view_timeline"/> + <Separator/> + <Action name="view_list"/> + <Action name="view_todo"/> + <Action name="view_journal"/> + <Merge/> + <Separator/> + <Action name="update"/> + <Separator/> + <Action name="hide_completed_todos"/> + <Separator/> + <Action name="filter_select" append="save_merge"/> + <Separator/> + <Menu name="zoom"><text>&Zoom</text> + <Action name="zoom_in_horizontally"/> + <Action name="zoom_out_horizontally"/> + <Separator/> + <Action name="zoom_in_vertically"/> + <Action name="zoom_out_vertically"/> + </Menu> + </Menu> + <Menu name="go_document"><text>&Go</text> + <Action name="go_previous"/> + <Action name="go_next"/> + <Separator/> + <Action name="go_today"/> + <Action name="go_select"/> + </Menu> + <Menu name="actions"><text>&Actions</text> + <Action name="new_event"/> + <Action name="new_todo"/> + <Action name="new_subtodo"/> + <Action name="new_journal"/> + <Separator/> + <Action name="show_incidence"/> + <Action name="edit_incidence"/> + <Action name="delete_incidence"/> + <Separator/> + <Action name="unsub_todo"/> + <Separator/> + <Action name="assign_resource"/> + <Action name="activate_alarm"/> + </Menu> + <Menu name="schedule"><text>S&chedule</text> + <Action name="schedule_publish"/> + <Action name="schedule_request"/> + <Action name="schedule_reply"/> + <Action name="schedule_cancel"/> + <Action name="schedule_refresh"/> + <Action name="schedule_counter"/> + <Action name="schedule_forward"/> + <Separator/> + <Action name="mail_freebusy"/> + <Action name="upload_freebusy"/> + </Menu> + <Menu name="settings"><text>&Settings</text> + <Menu name="sidebar" append="show_merge"><text>&Sidebar</text> + <Action name="show_datenavigator"/> + <Action name="show_todoview"/> + <Action name="show_eventviewer"/> + <Action name="show_resourceview"/> + <Action name="show_resourcebuttons" append="show_merge"/> + </Menu> + <Separator/> + <Action name="conf_datetime" append="save_merge"/> + <Action name="conf_resources" append="save_merge"/> + <Separator/> + <Action name="edit_filters" append="save_merge"/> + <Action name="edit_categories" append="save_merge"/> + <Separator/> + <Action name="options_configure_keybinding" group="settings_configure"/> + <Action name="options_configure_toolbars" group="settings_configure" /> + <Action name="korganizer_configure" group="settings_configure" /> + </Menu> + <Menu name="help"><text>&Help</text> + <Action name="show_intro"/> + </Menu> + </MenuBar> + + <ToolBar name="mainToolBar"><text>Main</text> + <Action name="go_previous"/> + <Action name="go_today"/> + <Action name="go_next"/> + <Action name="mail_appointment"/> + <Action name="new_event"/> + <Action name="new_todo"/> + </ToolBar> + + <ToolBar name="korganizer_toolbar"><text>Views</text> + <Action name="view_whatsnext"/> + <Action name="view_list"/> + <Action name="view_day"/> + <Action name="view_workweek"/> + <Action name="view_week"/> + <Action name="view_nextx"/> + <Action name="view_month"/> + <Action name="view_timeline"/> + <Action name="view_todo"/> + <Action name="view_journal"/> + <Merge/> + </ToolBar> + + <ToolBar name="schedule_toolbar" hidden="true"><text>Schedule</text> + <Action name="schedule_publish"/> + <Action name="schedule_request"/> + <Action name="schedule_reply"/> + </ToolBar> + + <ToolBar name="filter_toolbar" hidden="true"><text>Filters Toolbar</text> + <Action name="filter_label"/> + <Action name="filter_select"/> + <Action name="edit_filters"/> + </ToolBar> + + <Menu name="rmb_selection_popup"> + <Action name="new_event"/> + <Action name="new_todo"/> + <Separator/> + <Action name="korganizer_paste"/> + <Merge/> + </Menu> + + +</kpartgui> diff --git a/korganizer/korganizeriface.h b/korganizer/korganizeriface.h new file mode 100644 index 000000000..dac62e2bf --- /dev/null +++ b/korganizer/korganizeriface.h @@ -0,0 +1,59 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef KORGANIZERIFACE_H +#define KORGANIZERIFACE_H + +#include <dcopobject.h> + + +class KOrganizerIface : virtual public DCOPObject +{ + K_DCOP + k_dcop: + virtual bool openURL(const QString &url) = 0; + virtual bool mergeURL(const QString &url) = 0; + virtual void closeURL() = 0; + virtual bool saveURL() = 0; + virtual bool saveAsURL(const QString &url) = 0; + virtual QString getCurrentURLasString() const = 0; + virtual bool editIncidence(const QString &uid) = 0; + virtual bool deleteIncidence(const QString &uid) = 0; + /** + Delete the incidence with the given unique ID from the active calendar. + @param uid The incidence's unique ID. + @param force If true, all recurrences and sub-todos (if applicable) will + be deleted without prompting for confirmation. + */ + virtual bool deleteIncidence(const QString &uid, bool force) = 0; + /** + Add an incidence to the active calendar. + @param iCal A calendar in iCalendar format containing the incidence. The + calendar must consist of a VCALENDAR component which contains + the incidence (VEVENT, VTODO, VJOURNAL or VFREEBUSY) and + optionally a VTIMEZONE component. If there is more than one + incidence, only the first is added to KOrganizer's calendar. + */ + virtual bool addIncidence(const QString &iCal) = 0; + + virtual void loadProfile( const QString& path ) = 0; + virtual void saveToProfile( const QString& path ) const = 0; +}; + +#endif diff --git a/korganizer/korganizerifaceimpl.cpp b/korganizer/korganizerifaceimpl.cpp new file mode 100644 index 000000000..31103432b --- /dev/null +++ b/korganizer/korganizerifaceimpl.cpp @@ -0,0 +1,103 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this 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 Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#include "korganizerifaceimpl.h" +#include "actionmanager.h" + + +KOrganizerIfaceImpl::KOrganizerIfaceImpl( ActionManager* actionManager, + QObject* parent, const char* name ) + : DCOPObject( "KOrganizerIface" ), QObject( parent, name ), + mActionManager( actionManager ) +{ +} + +KOrganizerIfaceImpl::~KOrganizerIfaceImpl() +{ +} + +bool KOrganizerIfaceImpl::openURL( const QString &url ) +{ + return mActionManager->openURL( url ); +} + +bool KOrganizerIfaceImpl::mergeURL( const QString &url ) +{ + return mActionManager->mergeURL( url ); +} + +void KOrganizerIfaceImpl::closeURL() +{ + return mActionManager->closeURL(); +} + +bool KOrganizerIfaceImpl::saveURL() +{ + return mActionManager->saveURL(); +} + +bool KOrganizerIfaceImpl::saveAsURL( const QString &url ) +{ + return mActionManager->saveAsURL( url ); +} + +QString KOrganizerIfaceImpl::getCurrentURLasString() const +{ + return mActionManager->getCurrentURLasString(); +} + +bool KOrganizerIfaceImpl::deleteIncidence( const QString &uid, bool force ) +{ + return mActionManager->deleteIncidence( uid, force ); +} + +bool KOrganizerIfaceImpl::editIncidence( const QString &uid ) +{ + return mActionManager->editIncidence( uid ); +} + +bool KOrganizerIfaceImpl::addIncidence( const QString &ical ) +{ + return mActionManager->addIncidence( ical ); +} + +void KOrganizerIfaceImpl::loadProfile( const QString& path ) +{ + mActionManager->loadProfile( path ); +} + +void KOrganizerIfaceImpl::saveToProfile( const QString& path ) const +{ + mActionManager->saveToProfile( path ); +} + + diff --git a/korganizer/korganizerifaceimpl.h b/korganizer/korganizerifaceimpl.h new file mode 100644 index 000000000..228f1b4fa --- /dev/null +++ b/korganizer/korganizerifaceimpl.h @@ -0,0 +1,76 @@ +/* + This file is part of KOrganizer + Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + */ + +#ifndef KORGANIZER_SHARED_H +#define KORGANIZER_SHARED_H + +#include "korganizeriface.h" + +#include <qobject.h> +#include <kdepimmacros.h> + +class ActionManager; + + +class KDE_EXPORT KOrganizerIfaceImpl : public QObject, virtual public KOrganizerIface { +public: + KOrganizerIfaceImpl( ActionManager* mActionManager, + QObject* parent=0, const char* name=0 ); + ~KOrganizerIfaceImpl(); + + bool openURL( const QString &url ); + bool mergeURL( const QString &url ); + void closeURL(); + bool saveURL(); + bool saveAsURL( const QString &url ); + QString getCurrentURLasString() const; + + bool editIncidence( const QString &uid ); + /** @reimp from KOrganizerIface::deleteIncidence() */ + bool deleteIncidence( const QString &uid ) { return deleteIncidence( uid, false ); } + /** @reimp from KOrganizerIface::deleteIncidence() */ + bool deleteIncidence( const QString &uid, bool force ); + + /** @reimp from KOrganizerIface::addIncidence() */ + bool addIncidence( const QString &iCal ); + + /** @reimp from KOrganizerIface::loadProfile() */ + void loadProfile( const QString& path ); + + /** @reimp from KOrganizerIface::saveToProfile() */ + void saveToProfile( const QString& path ) const; + +private: + ActionManager* mActionManager; +}; + + +#endif // KORGANIZER_SHARED_H + diff --git a/korganizer/korganizerui.rc b/korganizer/korganizerui.rc new file mode 100644 index 000000000..82e97f713 --- /dev/null +++ b/korganizer/korganizerui.rc @@ -0,0 +1,168 @@ +<!DOCTYPE kpartgui> +<kpartgui name="korganizer" version="44"> + + <MenuBar> + <Menu name="file"><text>&File</text> + <Menu name="import"><text>&Import</text> + <Action name="import_icalendar"/> + <Action name="import_ical"/> + <Merge/> + <Separator/> + <Action name="downloadnewstuff"/> + </Menu> + <Menu name="export"><text>&Export</text> + <Action name="export_web" /> + <Action name="export_icalendar"/> + <Action name="export_vcalendar"/> + <Merge/> + <Separator/> + <Action name="uploadnewstuff"/> + </Menu> + <Separator/> + <Action name="file_archive"/> + <Action name="purge_completed"/> + <Separator/> + </Menu> + <Menu name="edit"><text>&Edit</text> + <Merge/> + <Separator/> + <Action name="edit_delete" append="edit_paste_merge"/> + </Menu> + <Menu name="view"><text>&View</text> + <Action name="view_whatsnext"/> + <Separator/> + <Action name="view_day"/> + <Action name="view_nextx"/> + <Action name="view_workweek"/> + <Action name="view_week"/> + <Action name="view_month"/> + <Action name="view_timeline"/> + <Separator/> + <Action name="view_list"/> + <Action name="view_todo"/> + <Action name="view_journal"/> + <Merge/> + <Separator/> + <Action name="update"/> + <Separator/> + <Action name="hide_completed_todos"/> + <Separator/> + <Action name="filter_select" append="save_merge"/> + <Separator/> + <Menu name="zoom"><text>&Zoom</text> + <Action name="zoom_in_horizontally"/> + <Action name="zoom_out_horizontally"/> + <Separator/> + <Action name="zoom_in_vertically"/> + <Action name="zoom_out_vertically"/> + </Menu> + </Menu> + <Menu name="go_document"><text>&Go</text> + <Action name="go_today"/> + <Action name="go_select"/> + </Menu> + <Menu name="actions"><text>&Actions</text> + <Action name="new_event"/> + <Action name="new_todo"/> + <Action name="new_subtodo"/> + <Action name="new_journal"/> + <Separator/> + <Action name="show_incidence"/> + <Action name="edit_incidence"/> + <Action name="delete_incidence"/> + <Separator/> + <Action name="unsub_todo"/> + <Separator/> + <Action name="assign_resource"/> + <Separator/> + <Action name="activate_alarm"/> + </Menu> + <Menu name="schedule"><text>S&chedule</text> + <Action name="schedule_publish"/> + <Action name="schedule_request"/> + <Action name="schedule_reply"/> + <Action name="schedule_cancel"/> + <Action name="schedule_refresh"/> + <Action name="schedule_counter"/> + <Action name="schedule_forward"/> + <Separator/> + <Action name="mail_freebusy"/> + <Action name="upload_freebusy"/> + </Menu> + <Menu name="settings"><text>&Settings</text> + <Menu name="sidebar" append="show_merge"><text>&Sidebar</text> + <Action name="show_datenavigator"/> + <Action name="show_todoview"/> + <Action name="show_eventviewer"/> + <Action name="show_resourceview"/> + <Action name="show_resourcebuttons" append="show_merge"/> + </Menu> + <Separator/> + <Action name="conf_datetime" append="save_merge"/> + <Action name="conf_resources" append="save_merge"/> + <Separator/> + <Action name="edit_filters" append="save_merge"/> + <Action name="edit_categories" append="save_merge"/> + </Menu> + <Menu name="help"><text>&Help</text> + <Action name="show_intro"/> + <Action name="help_tipofday"/> + </Menu> + </MenuBar> + + <ToolBar noMerge="1" name="mainToolBar"><text>Main</text> + <Action name="new_event"/> + <Action name="new_todo"/> + <Action name="file_print"/> + <Action name="mail_appointment"/> + <Separator/> + <Action name="edit_undo"/> + <Action name="edit_redo"/> + <Action name="edit_cut"/> + <Action name="edit_copy"/> + <Action name="edit_paste"/> + <Separator/> + <Action name="edit_find"/> + <Separator/> + <Action name="go_previous"/> + <Action name="go_next"/> + <Action name="go_today"/> + </ToolBar> + + <ToolBar name="korganizer_toolbar"><text>Views</text> + <Action name="view_whatsnext"/> + <Action name="view_list"/> + <Action name="view_day"/> + <Action name="view_workweek"/> + <Action name="view_week"/> + <Action name="view_nextx"/> + <Action name="view_month"/> + <Action name="view_timeline"/> + <Action name="view_todo"/> + <Action name="view_journal"/> + <Merge/> + </ToolBar> + + <ToolBar name="schedule_toolbar" hidden="true"><text>Schedule</text> + <Action name="schedule_publish"/> + <Action name="schedule_request"/> + <Action name="schedule_reply"/> + <Action name="addressbook"/> + </ToolBar> + + <ToolBar name="filter_toolbar" hidden="true"><text>Filters Toolbar</text> + <Action name="filter_label"/> + <Action name="filter_select"/> + <Action name="edit_filters"/> + </ToolBar> + + <Menu name="rmb_selection_popup"> + <Action name="new_event"/> + <Action name="new_todo"/> + <Separator/> + <Action name="edit_paste"/> + <Merge/> + </Menu> + + +</kpartgui> diff --git a/korganizer/korgplugins.cpp b/korganizer/korgplugins.cpp new file mode 100644 index 000000000..5bd9be910 --- /dev/null +++ b/korganizer/korgplugins.cpp @@ -0,0 +1,91 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#include <kaboutdata.h> +#include <kapplication.h> +#include <kdebug.h> +#include <klocale.h> +#include <kcmdlineargs.h> + +#include <calendar/plugin.h> + +#include "kocore.h" + +int main(int argc,char **argv) +{ + KAboutData aboutData("korgplugins",I18N_NOOP("KOrgPlugins"),"0.1"); + KCmdLineArgs::init(argc,argv,&aboutData); + + KApplication app; + + KTrader::OfferList plugins = KOCore::self()->availablePlugins(); + KTrader::OfferList::ConstIterator it; + for(it = plugins.begin(); it != plugins.end(); ++it) { + kdDebug(5850) << "Plugin: " << (*it)->desktopEntryName() << " (" + << (*it)->name() << ")" << endl; + KOrg::Plugin *p = KOCore::self()->loadPlugin(*it); + if (!p) { + kdDebug(5850) << "Plugin loading failed." << endl; + } else { + kdDebug(5850) << "PLUGIN INFO: " << p->info() << endl; + } + } + + plugins = KOCore::self()->availablePrintPlugins(); + for(it = plugins.begin(); it != plugins.end(); ++it) { + kdDebug(5850) << "Print plugin: " << (*it)->desktopEntryName() << " (" + << (*it)->name() << ")" << endl; + KOrg::PrintPlugin *p = KOCore::self()->loadPrintPlugin(*it); + if (!p) { + kdDebug(5850) << "Print plugin loading failed." << endl; + } else { + kdDebug(5850) << "PRINT PLUGIN INFO: " << p->info() << endl; + } + } + + plugins = KOCore::self()->availableParts(); + for(it = plugins.begin(); it != plugins.end(); ++it) { + kdDebug(5850) << "Part: " << (*it)->desktopEntryName() << " (" + << (*it)->name() << ")" << endl; + KOrg::Part *p = KOCore::self()->loadPart(*it,0); + if (!p) { + kdDebug(5850) << "Part loading failed." << endl; + } else { + kdDebug(5850) << "PART INFO: " << p->info() << endl; + } + } + + plugins = KOCore::self()->availableCalendarDecorations(); + for(it = plugins.begin(); it != plugins.end(); ++it) { + kdDebug(5850) << "CalendarDecoration: " << (*it)->desktopEntryName() << " (" + << (*it)->name() << ")" << endl; + KOrg::CalendarDecoration *p = KOCore::self()->loadCalendarDecoration(*it); + if (!p) { + kdDebug(5850) << "Calendar decoration loading failed." << endl; + } else { + kdDebug(5850) << "CALENDAR DECORATION INFO: " << p->info() << endl; + } + } + +} diff --git a/korganizer/kotimelineview.cpp b/korganizer/kotimelineview.cpp new file mode 100644 index 000000000..24f981a53 --- /dev/null +++ b/korganizer/kotimelineview.cpp @@ -0,0 +1,355 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2007 Till Adam <adam@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + + +#include <libkcal/calendar.h> +#include <libkcal/calendarresources.h> + +#include <qlayout.h> + +#include <kdgantt/KDGanttViewTaskItem.h> +#include <kdgantt/KDGanttViewSubwidgets.h> + +#include "koeventpopupmenu.h" +#include "koglobals.h" +#include "koprefs.h" +#include "timelineitem.h" + +#include "kotimelineview.h" + +using namespace KOrg; +using namespace KCal; + +KOTimelineView::KOTimelineView(Calendar *calendar, QWidget *parent, + const char *name) + : KOEventView(calendar, parent, name), + mEventPopup( 0 ) +{ + QVBoxLayout* vbox = new QVBoxLayout(this); + mGantt = new KDGanttView(this); + mGantt->setCalendarMode( true ); + mGantt->setShowLegendButton( false ); + mGantt->setFixedHorizon( true ); + mGantt->removeColumn( 0 ); + mGantt->addColumn( i18n("Calendar") ); + mGantt->setHeaderVisible( true ); + if ( KGlobal::locale()->use12Clock() ) + mGantt->setHourFormat( KDGanttView::Hour_12 ); + else + mGantt->setHourFormat( KDGanttView::Hour_24_FourDigit ); + + + vbox->addWidget( mGantt ); + + connect( mGantt, SIGNAL(gvCurrentChanged(KDGanttViewItem*)), + SLOT(itemSelected(KDGanttViewItem*)) ); + connect( mGantt, SIGNAL(itemDoubleClicked(KDGanttViewItem*)), + SLOT(itemDoubleClicked(KDGanttViewItem*)) ); + connect( mGantt, SIGNAL(itemRightClicked(KDGanttViewItem*)), + SLOT(itemRightClicked(KDGanttViewItem*)) ); + connect( mGantt, SIGNAL(gvItemMoved(KDGanttViewItem*)), + SLOT(itemMoved(KDGanttViewItem*)) ); + connect( mGantt, SIGNAL(rescaling(KDGanttView::Scale)), + SLOT(overscale(KDGanttView::Scale)) ); + connect( mGantt, SIGNAL( dateTimeDoubleClicked( const QDateTime& ) ), + SLOT( newEventWithHint( const QDateTime& ) ) ); +} + +KOTimelineView::~KOTimelineView() +{ + delete mEventPopup; +} + +/*virtual*/ +KCal::ListBase<KCal::Incidence> KOTimelineView::selectedIncidences() +{ + return KCal::ListBase<KCal::Incidence>(); +} + +/*virtual*/ +KCal::DateList KOTimelineView::selectedDates() +{ + return KCal::DateList(); +} + +/*virtual*/ +int KOTimelineView::currentDateCount() +{ + return 0; +} + +/*virtual*/ +void KOTimelineView::showDates(const QDate& start, const QDate& end) +{ + mStartDate = start; + mEndDate = end; + mHintDate = QDateTime(); + mGantt->setHorizonStart( QDateTime(start) ); + mGantt->setHorizonEnd( QDateTime(end.addDays(1)) ); + mGantt->setMinorScaleCount( 1 ); + mGantt->setScale( KDGanttView::Hour ); + mGantt->setMinimumScale( KDGanttView::Hour ); + mGantt->setMaximumScale( KDGanttView::Hour ); + mGantt->zoomToFit(); + + mGantt->setUpdateEnabled( false ); + mGantt->clear(); + + // item for every calendar + TimelineItem *item = 0; + CalendarResources *calres = dynamic_cast<CalendarResources*>( calendar() ); + if ( !calres ) { + item = new TimelineItem( i18n("Calendar"), mGantt ); + mCalendarItemMap[0][QString()] = item; + } else { + CalendarResourceManager *manager = calres->resourceManager(); + for ( CalendarResourceManager::ActiveIterator it = manager->activeBegin(); it != manager->activeEnd(); ++it ) { + QColor resourceColor = *KOPrefs::instance()->resourceColor( (*it)->identifier() ); + if ( (*it)->canHaveSubresources() ) { + QStringList subResources = (*it)->subresources(); + for ( QStringList::ConstIterator subit = subResources.constBegin(); subit != subResources.constEnd(); ++subit ) { + QString type = (*it)->subresourceType( *subit ); + if ( !(*it)->subresourceActive( *subit ) || (!type.isEmpty() && type != "event") ) + continue; + item = new TimelineItem( (*it)->labelForSubresource( *subit ), mGantt ); + resourceColor = *KOPrefs::instance()->resourceColor( (*it)->identifier() ); + QColor subrescol = *KOPrefs::instance()->resourceColor( *subit ); + if ( subrescol.isValid() ) + resourceColor = subrescol; + if ( resourceColor.isValid() ) + item->setColors( resourceColor, resourceColor, resourceColor ); + mCalendarItemMap[*it][*subit] = item; + } + } else { + item = new TimelineItem( (*it)->resourceName(), mGantt ); + if ( resourceColor.isValid() ) + item->setColors( resourceColor, resourceColor, resourceColor ); + mCalendarItemMap[*it][QString()] = item; + } + } + } + + // add incidences + Event::List events; + for ( QDate day = start; day <= end; day = day.addDays( 1 ) ) { + events = calendar()->events( day, EventSortStartDate, SortDirectionAscending ); + for ( Event::List::ConstIterator it = events.constBegin(); it != events.constEnd(); ++it ) { + insertIncidence( *it, day ); + } + } + + mGantt->setUpdateEnabled( true ); +} + +/*virtual*/ +void KOTimelineView::showIncidences(const KCal::ListBase<KCal::Incidence>&) +{ +} + +/*virtual*/ +void KOTimelineView::updateView() +{ + if ( mStartDate.isValid() && mEndDate.isValid() ) + showDates( mStartDate, mEndDate ); +} + +/*virtual*/ +void KOTimelineView::changeIncidenceDisplay(KCal::Incidence* incidence, int mode) +{ + kdDebug() << k_funcinfo << incidence << " " << mode << endl; + switch ( mode ) { + case KOGlobals::INCIDENCEADDED: + insertIncidence( incidence ); + break; + case KOGlobals::INCIDENCEEDITED: + removeIncidence( incidence ); + insertIncidence( incidence ); + break; + case KOGlobals::INCIDENCEDELETED: + removeIncidence( incidence ); + break; + default: + updateView(); + } +} + +void KOTimelineView::itemSelected( KDGanttViewItem *item ) +{ + TimelineSubItem *tlitem = dynamic_cast<TimelineSubItem*>( item ); + if ( tlitem ) + emit incidenceSelected( tlitem->incidence() ); +} + +void KOTimelineView::itemDoubleClicked( KDGanttViewItem *item ) +{ + TimelineSubItem *tlitem = dynamic_cast<TimelineSubItem*>( item ); + if ( tlitem ) + emit editIncidenceSignal( tlitem->incidence() ); +} + +void KOTimelineView::itemRightClicked( KDGanttViewItem *item ) +{ + mHintDate = mGantt->getDateTimeForCoordX( QCursor::pos().x(), true ); + TimelineSubItem *tlitem = dynamic_cast<TimelineSubItem*>( item ); + if ( !tlitem ) { + showNewEventPopup(); + return; + } + if ( !mEventPopup ) + mEventPopup = eventPopup(); + mEventPopup->showIncidencePopup( tlitem->incidence(), QDate() ); +} + +bool KOTimelineView::eventDurationHint(QDateTime & startDt, QDateTime & endDt, bool & allDay) +{ + startDt = mHintDate; + endDt = mHintDate.addSecs( 2 * 60 * 60 ); + allDay = false; + return mHintDate.isValid(); +} + +//slot +void KOTimelineView::newEventWithHint( const QDateTime& dt ) +{ + mHintDate = dt; + emit newEventSignal( dt ); +} + +TimelineItem * KOTimelineView::calendarItemForIncidence(KCal::Incidence * incidence) +{ + CalendarResources *calres = dynamic_cast<CalendarResources*>( calendar() ); + TimelineItem *item = 0; + if ( !calres ) { + item = mCalendarItemMap[0][QString()]; + } else { + ResourceCalendar *res = calres->resource( incidence ); + if ( !res ) + return 0; + if ( res->canHaveSubresources() ) { + QString subRes = res->subresourceIdentifier( incidence ); + item = mCalendarItemMap[res][subRes]; + } else { + item = mCalendarItemMap[res][QString()]; + } + } + return item; +} + +void KOTimelineView::insertIncidence(KCal::Incidence * incidence, const QDate &day ) +{ + TimelineItem *item = calendarItemForIncidence( incidence ); + if ( !item ) { + kdWarning() << k_funcinfo << "Help! Something is really wrong here!" << endl; + return; + } + + if ( incidence->doesRecur() ) { + QValueList<QDateTime> l = incidence->startDateTimesForDate( day ); + if ( l.isEmpty() ) { + // strange, but seems to happen for some recurring events... + item->insertIncidence( incidence, QDateTime( day, incidence->dtStart().time() ), + QDateTime( day, incidence->dtEnd().time() ) ); + } else { + for ( QValueList<QDateTime>::ConstIterator it = l.constBegin(); + it != l.constEnd(); ++it ) { + item->insertIncidence( incidence, *it, incidence->endDateForStart( *it ) ); + } + } + } else { + if ( incidence->dtStart().date() == day || incidence->dtStart().date() < mStartDate ) + item->insertIncidence( incidence ); + } +} + +void KOTimelineView::insertIncidence(KCal::Incidence * incidence) +{ + KCal::Event *event = dynamic_cast<KCal::Event*>( incidence ); + if ( !event ) + return; + if ( incidence->doesRecur() ) + insertIncidence( incidence, QDate() ); + for ( QDate day = mStartDate; day <= mEndDate; day = day.addDays( 1 ) ) { + Event::List events = calendar()->events( day, EventSortStartDate, SortDirectionAscending ); + for ( Event::List::ConstIterator it = events.constBegin(); it != events.constEnd(); ++it ) { + if ( events.contains( event ) ) + insertIncidence( *it, day ); + } + } +} + +void KOTimelineView::removeIncidence(KCal::Incidence * incidence) +{ + TimelineItem *item = calendarItemForIncidence( incidence ); + if ( item ) { + item->removeIncidence( incidence ); + } else { + // try harder, the incidence might already be removed from the resource + typedef QMap<QString, KOrg::TimelineItem*> M2_t; + typedef QMap<KCal::ResourceCalendar*, M2_t> M1_t; + for ( M1_t::ConstIterator it1 = mCalendarItemMap.constBegin(); it1 != mCalendarItemMap.constEnd(); ++it1 ) { + for ( M2_t::ConstIterator it2 = it1.data().constBegin(); it2 != it1.data().constEnd(); ++it2 ) { + if ( it2.data() ) { + it2.data()->removeIncidence( incidence ); + } + } + } + } +} + +void KOTimelineView::itemMoved(KDGanttViewItem * item) +{ + TimelineSubItem *tlit = dynamic_cast<TimelineSubItem*>( item ); + if ( !tlit ) + return; + Incidence *i = tlit->incidence(); + mChanger->beginChange( i ); + QDateTime newStart = tlit->startTime(); + if ( i->doesFloat() ) + newStart = QDateTime( newStart.date() ); + int delta = tlit->originalStart().secsTo( newStart ); + i->setDtStart( i->dtStart().addSecs( delta ) ); + int duration = tlit->startTime().secsTo( tlit->endTime() ); + int allDayOffset = 0; + if ( i->doesFloat() ) { + duration /= (60*60*24); + duration *= (60*60*24); + allDayOffset = (60*60*24); + duration -= allDayOffset; + if ( duration < 0 ) duration = 0; + } + i->setDuration( duration ); + TimelineItem *parent = static_cast<TimelineItem*>( tlit->parent() ); + parent->moveItems( i, tlit->originalStart().secsTo( newStart ), duration + allDayOffset ); + mChanger->endChange( i ); +} + +void KOTimelineView::overscale(KDGanttView::Scale scale) +{ + Q_UNUSED( scale ); + mGantt->setZoomFactor( 1, false ); + mGantt->setScale( KDGanttView::Hour ); + mGantt->setMinorScaleCount( 12 ); +} + +#include "kotimelineview.moc" diff --git a/korganizer/kotimelineview.h b/korganizer/kotimelineview.h new file mode 100644 index 000000000..c1bfb89ee --- /dev/null +++ b/korganizer/kotimelineview.h @@ -0,0 +1,85 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2007 Till Adam <adam@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOTIMELINEVIEW_H +#define KOTIMELINEVIEW_H + +#include <koeventview.h> +#include <kdgantt/KDGanttView.h> +#include <qmap.h> + +class KDGanttViewItem; + +namespace KCal { + class ResourceCalendar; +} + +namespace KOrg { + class TimelineItem; +} + +/** + This class provides a view .... +*/ +class KOTimelineView : public KOEventView +{ + Q_OBJECT + public: + KOTimelineView(Calendar *calendar, QWidget *parent = 0, + const char *name = 0); + ~KOTimelineView(); + + virtual KCal::ListBase<KCal::Incidence> selectedIncidences(); + virtual KCal::DateList selectedDates(); + virtual int currentDateCount(); + virtual void showDates(const QDate&, const QDate&); + virtual void showIncidences(const KCal::ListBase<KCal::Incidence>&); + virtual void updateView(); + virtual void changeIncidenceDisplay(KCal::Incidence* incidence, int mode); + virtual int maxDatesHint() { return 0; } + + virtual bool eventDurationHint(QDateTime &startDt, QDateTime &endDt, bool &allDay); + + private: + KOrg::TimelineItem* calendarItemForIncidence( KCal::Incidence* incidence ); + void insertIncidence( KCal::Incidence* incidence ); + void insertIncidence( KCal::Incidence* incidence, const QDate &day ); + void removeIncidence( KCal::Incidence* incidence ); + + private slots: + void itemSelected( KDGanttViewItem *item ); + void itemDoubleClicked( KDGanttViewItem *item ); + void itemRightClicked( KDGanttViewItem *item ); + void itemMoved( KDGanttViewItem *item ); + void overscale( KDGanttView::Scale scale ); + void newEventWithHint( const QDateTime & ); + + private: + KDGanttView* mGantt; + QMap<KCal::ResourceCalendar*, QMap<QString, KOrg::TimelineItem*> > mCalendarItemMap; + KOEventPopupMenu *mEventPopup; + QDate mStartDate, mEndDate; + QDateTime mHintDate; +}; + +#endif diff --git a/korganizer/kotodoeditor.cpp b/korganizer/kotodoeditor.cpp new file mode 100644 index 000000000..a4e5f11c8 --- /dev/null +++ b/korganizer/kotodoeditor.cpp @@ -0,0 +1,361 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1997, 1998 Preston Brown <pbrown@kde.org> + Copyright (c) 2000-2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qtooltip.h> +#include <qframe.h> +#include <qpixmap.h> +#include <qlayout.h> +#include <qdatetime.h> + +#include <kiconloader.h> +#include <klocale.h> +#include <kmessagebox.h> + +#include <libkcal/calendarlocal.h> +#include <libkcal/calendarresources.h> +#include <libkcal/resourcecalendar.h> + +#include "koprefs.h" +#include "koeditorattachments.h" +#include "kogroupware.h" +#include "kodialogmanager.h" +#include "incidencechanger.h" + +#include "koeditorgeneraltodo.h" +#include "koeditordetails.h" +#include "koeditorrecurrence.h" + +#include "kotodoeditor.h" +#include "kocore.h" + +KOTodoEditor::KOTodoEditor( Calendar *calendar, QWidget *parent ) : + KOIncidenceEditor( QString::null, calendar, parent ) +{ + mTodo = 0; + mCalendar = 0; + mRelatedTodo = 0; +} + +KOTodoEditor::~KOTodoEditor() +{ + emit dialogClose( mTodo ); +} + +void KOTodoEditor::init() +{ + kdDebug(5850) << k_funcinfo << endl; + setupGeneral(); + setupRecurrence(); + setupAttendeesTab(); +// setupAttachmentsTab(); + + connect( mGeneral, SIGNAL( dateTimeStrChanged( const QString & ) ), + mRecurrence, SLOT( setDateTimeStr( const QString & ) ) ); + connect( mGeneral, SIGNAL( signalDateTimeChanged( const QDateTime &, const QDateTime & ) ), + mRecurrence, SLOT( setDateTimes( const QDateTime &, const QDateTime & ) ) ); + + connect( mGeneral, SIGNAL( openCategoryDialog() ), + SIGNAL( editCategories() ) ); + + connect( mDetails, SIGNAL(updateAttendeeSummary(int)), + mGeneral, SLOT(updateAttendeeSummary(int)) ); +} + +void KOTodoEditor::reload() +{ + if ( mTodo ) readTodo( mTodo, mCalendar ); +} + +void KOTodoEditor::setupGeneral() +{ + mGeneral = new KOEditorGeneralTodo(this); + + if (KOPrefs::instance()->mCompactDialogs) { + QFrame *topFrame = addPage(i18n("General")); + + QBoxLayout *topLayout = new QVBoxLayout(topFrame); + topLayout->setMargin(marginHint()); + topLayout->setSpacing(spacingHint()); + + mGeneral->initHeader( topFrame, topLayout ); + mGeneral->initTime(topFrame,topLayout); + QHBoxLayout *priorityLayout = new QHBoxLayout( topLayout ); + mGeneral->initPriority(topFrame,priorityLayout); + topLayout->addStretch(1); + + QFrame *topFrame2 = addPage(i18n("Details")); + + QBoxLayout *topLayout2 = new QVBoxLayout(topFrame2); + topLayout2->setMargin(marginHint()); + topLayout2->setSpacing(spacingHint()); + + QHBoxLayout *completionLayout = new QHBoxLayout( topLayout2 ); + mGeneral->initCompletion(topFrame2,completionLayout); + + mGeneral->initAlarm(topFrame,topLayout); + + mGeneral->initSecrecy( topFrame2, topLayout2 ); + mGeneral->initDescription(topFrame2,topLayout2); + } else { + QFrame *topFrame = addPage(i18n("&General")); + + QBoxLayout *topLayout = new QVBoxLayout(topFrame); + topLayout->setSpacing(spacingHint()); + + mGeneral->initHeader( topFrame, topLayout ); + mGeneral->initTime(topFrame,topLayout); + mGeneral->initStatus(topFrame,topLayout); + QBoxLayout *alarmLineLayout = new QHBoxLayout(topLayout); + mGeneral->initAlarm(topFrame,alarmLineLayout); + alarmLineLayout->addStretch( 1 ); + mGeneral->initDescription(topFrame,topLayout); + mGeneral->initAttachments(topFrame,topLayout); + connect( mGeneral, SIGNAL( openURL( const KURL& ) ), + this, SLOT( openURL( const KURL& ) ) ); + connect( this, SIGNAL( signalAddAttachments( const QStringList&, const QStringList&, bool ) ), + mGeneral, SLOT( addAttachments( const QStringList&, const QStringList&, bool ) ) ); + } + mGeneral->enableAlarm( true ); + + mGeneral->finishSetup(); +} + +void KOTodoEditor::setupRecurrence() +{ + QFrame *topFrame = addPage( i18n("Rec&urrence") ); + + QBoxLayout *topLayout = new QVBoxLayout( topFrame ); + + mRecurrence = new KOEditorRecurrence( topFrame ); + topLayout->addWidget( mRecurrence ); + + mRecurrence->setEnabled( false ); + connect(mGeneral,SIGNAL(dueDateEditToggle( bool ) ), + mRecurrence, SLOT( setEnabled( bool ) ) ); +} + +void KOTodoEditor::editIncidence(Incidence *incidence, Calendar *calendar) +{ + kdDebug(5850) << k_funcinfo << endl; + Todo *todo=dynamic_cast<Todo*>(incidence); + if (todo) + { + init(); + + mTodo = todo; + mCalendar = calendar; + readTodo( mTodo, mCalendar ); + } + + setCaption( i18n("Edit To-do") ); +} + +void KOTodoEditor::newTodo() +{ + kdDebug(5850) << k_funcinfo << endl; + init(); + mTodo = 0; + mCalendar = 0; + setCaption( i18n("New To-do") ); + loadDefaults(); +} + +void KOTodoEditor::setTexts( const QString &summary, const QString &description ) +{ + if ( description.isEmpty() && summary.contains("\n") ) { + mGeneral->setDescription( summary ); + int pos = summary.find( "\n" ); + mGeneral->setSummary( summary.left( pos ) ); + } else { + mGeneral->setSummary( summary ); + mGeneral->setDescription( description ); + } +} + + + +void KOTodoEditor::loadDefaults() +{ + kdDebug(5850) << k_funcinfo << endl; + setDates( QDateTime::currentDateTime().addDays(7), true, 0 ); + mGeneral->toggleAlarm( true ); +} + +bool KOTodoEditor::processInput() +{ + if ( !validateInput() ) return false; + + if ( mTodo ) { + bool rc = true; + Todo *oldTodo = mTodo->clone(); + Todo *todo = mTodo->clone(); + + kdDebug(5850) << "KOTodoEditor::processInput() write event." << endl; + writeTodo( todo ); + kdDebug(5850) << "KOTodoEditor::processInput() event written." << endl; + + if( *mTodo == *todo ) + // Don't do anything + kdDebug(5850) << "Todo not changed\n"; + else { + kdDebug(5850) << "Todo changed\n"; + //IncidenceChanger::assignIncidence( mTodo, todo ); + writeTodo( mTodo ); + mChanger->changeIncidence( oldTodo, mTodo ); + } + delete todo; + delete oldTodo; + return rc; + + } else { + mTodo = new Todo; + mTodo->setOrganizer( Person( KOPrefs::instance()->fullName(), + KOPrefs::instance()->email() ) ); + + writeTodo( mTodo ); + + if ( !mChanger->addIncidence( mTodo, this ) ) { + delete mTodo; + mTodo = 0; + return false; + } + } + + return true; + +} + +void KOTodoEditor::deleteTodo() +{ + if (mTodo) + emit deleteIncidenceSignal( mTodo ); + emit dialogClose(mTodo); + reject(); +} + +void KOTodoEditor::setDates( const QDateTime &due, bool allDay, Todo *relatedEvent ) +{ + mRelatedTodo = relatedEvent; + + // inherit some properties from parent todo + if ( mRelatedTodo ) { + mGeneral->setCategories( mRelatedTodo->categories() ); + } + if ( !due.isValid() && mRelatedTodo && mRelatedTodo->hasDueDate() ) { + mGeneral->setDefaults( mRelatedTodo->dtDue(), allDay ); + } else { + mGeneral->setDefaults( due, allDay ); + } + + mDetails->setDefaults(); + if ( mTodo ) + mRecurrence->setDefaults( mTodo->dtStart(), due, false ); + else + mRecurrence->setDefaults( QDateTime::currentDateTime(), due, false ); +} + +void KOTodoEditor::readTodo( Todo *todo, Calendar *calendar ) +{ + if ( !todo ) return; +// mRelatedTodo = todo->relatedTo(); + kdDebug(5850)<<"read todo"<<endl; + mGeneral->readTodo( todo, calendar ); + mDetails->readEvent( todo ); + mRecurrence->readIncidence( todo ); + + createEmbeddedURLPages( todo ); + readDesignerFields( todo ); +} + +void KOTodoEditor::writeTodo( Todo *todo ) +{ + Incidence *oldIncidence = todo->clone(); + + mRecurrence->writeIncidence( todo ); + mGeneral->writeTodo( todo ); + mDetails->writeEvent( todo ); + + if ( *(oldIncidence->recurrence()) != *(todo->recurrence() ) ) { + todo->setDtDue( todo->dtDue(), true ); + if ( todo->hasStartDate() ) + todo->setDtStart( todo->dtStart() ); + } + writeDesignerFields( todo ); + + // set related incidence, i.e. parent to-do in this case. + if ( mRelatedTodo ) { + todo->setRelatedTo( mRelatedTodo ); + } + + cancelRemovedAttendees( todo ); +} + +bool KOTodoEditor::validateInput() +{ + if ( !mGeneral->validateInput() ) return false; + if ( !mRecurrence->validateInput() ) return false; + if ( !mDetails->validateInput() ) return false; + return true; +} + +int KOTodoEditor::msgItemDelete() +{ + return KMessageBox::warningContinueCancel(this, + i18n("This item will be permanently deleted."), + i18n("KOrganizer Confirmation"), KStdGuiItem::del() ); +} + +void KOTodoEditor::modified (int /*modification*/) +{ + // Play dump, just reload the todo. This dialog has become so complicated that + // there is no point in trying to be smart here... + reload(); +} + +void KOTodoEditor::loadTemplate( /*const*/ CalendarLocal& cal ) +{ + Todo::List todos = cal.todos(); + if ( todos.count() == 0 ) { + KMessageBox::error( this, + i18n("Template does not contain a valid to-do.") ); + } else { + readTodo( todos.first(), 0 ); + } +} + +void KOTodoEditor::slotSaveTemplate( const QString &templateName ) +{ + Todo *todo = new Todo; + writeTodo( todo ); + saveAsTemplate( todo, templateName ); +} + +QStringList& KOTodoEditor::templates() const +{ + return KOPrefs::instance()->mTodoTemplates; +} + +#include "kotodoeditor.moc" diff --git a/korganizer/kotodoeditor.h b/korganizer/kotodoeditor.h new file mode 100644 index 000000000..2451ea807 --- /dev/null +++ b/korganizer/kotodoeditor.h @@ -0,0 +1,104 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1997, 1998 Preston Brown <pbrown@kde.org> + Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef _KOTODOEDITOR_H +#define _KOTODOEDITOR_H + +#include "koincidenceeditor.h" + +class QDateTime; +class KOEditorGeneralTodo; +class KOEditorRecurrence; +/** + This class provides a dialog for editing a Todo. +*/ +class KOTodoEditor : public KOIncidenceEditor +{ + Q_OBJECT + public: + /** + Constructs a new todo editor. + */ + KOTodoEditor( Calendar *calendar, QWidget *parent ); + virtual ~KOTodoEditor(); + + void init(); + + void reload(); + + /** + Edit new todo. Use the set* methods to set appropriate default values if needed + */ + void newTodo(); + + /** + Sets the given summary and description. If description is empty and the + summary contains multiple lines, the summary will be used as description + and only the first line of summary will be used as the summary. + */ + void setTexts( const QString &summary, const QString &description = QString::null ); + /** Edit an existing todo. */ + void editIncidence(Incidence *incidence, Calendar* calendar); + + /** Set widgets to default values */ + void setDates( const QDateTime &due, bool allDay = true, Todo *relatedTodo = 0 ); + /** Read event object and setup widgets accordingly */ + void readTodo(Todo *todo, Calendar *calendar); + /** Write event settings to event object */ + void writeTodo(Todo *); + + /** Check if the input is valid. */ + bool validateInput(); + /** Process user input and create or update event. Returns false if input + * is not valid */ + bool processInput(); + + /** This todo has been modified externally */ + void modified (int change=0); + + protected slots: + void loadDefaults(); + void deleteTodo(); + void slotSaveTemplate( const QString & ); + + protected: + void loadTemplate( /*const*/ CalendarLocal& ); + QStringList& templates() const; + QString type() { return "Todo"; } + void setupGeneral(); + void setupRecurrence(); + int msgItemDelete(); + + private: + Todo *mTodo; + Calendar *mCalendar; + + Todo *mRelatedTodo; + + KOEditorGeneralTodo *mGeneral; + KOEditorRecurrence *mRecurrence; +}; + +#endif diff --git a/korganizer/kotodoview.cpp b/korganizer/kotodoview.cpp new file mode 100644 index 000000000..f43ca2f69 --- /dev/null +++ b/korganizer/kotodoview.cpp @@ -0,0 +1,1121 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2000,2001,2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qlayout.h> +#include <qheader.h> +#include <qcursor.h> +#include <qlabel.h> +#include <qtimer.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kglobal.h> +#include <kiconloader.h> +#include <kmessagebox.h> + +#include <libkcal/icaldrag.h> +#include <libkcal/vcaldrag.h> +#include <libkcal/dndfactory.h> +#include <libkcal/calendarresources.h> +#include <libkcal/resourcecalendar.h> +#include <libkcal/calfilter.h> +#include <libkcal/incidenceformatter.h> + +#include <libkdepim/clicklineedit.h> +#include <libkdepim/kdatepickerpopup.h> + +#include <libemailfunctions/email.h> + +#include "docprefs.h" + +#include "koincidencetooltip.h" +#include "kodialogmanager.h" +#include "kotodoview.h" +#include "koprefs.h" +#include "koglobals.h" +using namespace KOrg; +#include "kotodoviewitem.h" +#include "kotodoview.moc" +#ifndef KORG_NOPRINTER +#include "kocorehelper.h" +#include "calprinter.h" +#endif + +KOTodoListViewToolTip::KOTodoListViewToolTip (QWidget* parent, + KOTodoListView* lv ) + :QToolTip(parent) +{ + todolist=lv; +} + +void KOTodoListViewToolTip::maybeTip( const QPoint & pos) +{ + QRect r; + int headerPos; + int col=todolist->header()->sectionAt(todolist->contentsX() + pos.x()); + KOTodoViewItem *i=(KOTodoViewItem *)todolist->itemAt(pos); + + /* Check wether a tooltip is necessary. */ + if( i && KOPrefs::instance()->mEnableToolTips ) + { + + /* Calculate the rectangle. */ + r=todolist->itemRect(i); + headerPos = todolist->header()->sectionPos(col)-todolist->contentsX(); + r.setLeft( (headerPos < 0 ? 0 : headerPos) ); + r.setRight(headerPos + todolist->header()->sectionSize(col)); + + /* Show the tip */ + QString tipText( IncidenceFormatter::toolTipString( i->todo() ) );; + if ( !tipText.isEmpty() ) { + tip(r, tipText); + } + } + +} + + + +KOTodoListView::KOTodoListView( QWidget *parent, const char *name ) + : KListView( parent, name ), mCalendar( 0 ), mChanger( 0 ) +{ + mOldCurrent = 0; + mMousePressed = false; + + /* Create a Tooltip */ + tooltip = new KOTodoListViewToolTip( viewport(), this ); +} + +KOTodoListView::~KOTodoListView() +{ + delete tooltip; +} + +void KOTodoListView::setCalendar( Calendar *cal ) +{ + mCalendar = cal; + setAcceptDrops( mCalendar ); + viewport()->setAcceptDrops( mCalendar ); +} + +bool KOTodoListView::event(QEvent *e) +{ + int tmp=0; + KOTodoViewItem *i; + + /* Checks for an ApplicationPaletteChange event and updates + * the small Progress bars to make therm have the right colors. */ + if(e->type()==QEvent::ApplicationPaletteChange) + { + + KListView::event(e); + i=(KOTodoViewItem *)itemAtIndex(tmp); + + while(i!=0) + { + i->construct(); + tmp++; + i=(KOTodoViewItem *)itemAtIndex(tmp); + } + + } + + return (KListView::event(e) || e->type()==QEvent::ApplicationPaletteChange); +} + +void KOTodoListView::contentsDragEnterEvent(QDragEnterEvent *e) +{ +#ifndef KORG_NODND +// kdDebug(5850) << "KOTodoListView::contentsDragEnterEvent" << endl; + if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) && + !QTextDrag::canDecode( e ) ) { + e->ignore(); + return; + } + + mOldCurrent = currentItem(); +#endif +} + +void KOTodoListView::contentsDragMoveEvent(QDragMoveEvent *e) +{ +#ifndef KORG_NODND +// kdDebug(5850) << "KOTodoListView::contentsDragMoveEvent" << endl; + + if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) && + !QTextDrag::canDecode( e ) ) { + e->ignore(); + return; + } + + e->accept(); +#endif +} + +void KOTodoListView::contentsDragLeaveEvent( QDragLeaveEvent * ) +{ +#ifndef KORG_NODND +// kdDebug(5850) << "KOTodoListView::contentsDragLeaveEvent" << endl; + + setCurrentItem(mOldCurrent); + setSelected(mOldCurrent,true); +#endif +} + +void KOTodoListView::contentsDropEvent( QDropEvent *e ) +{ +#ifndef KORG_NODND + kdDebug(5850) << "KOTodoListView::contentsDropEvent" << endl; + + if ( !mCalendar || !mChanger || + ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) && + !QTextDrag::canDecode( e ) ) ) { + e->ignore(); + return; + } + + DndFactory factory( mCalendar ); + Todo *todo = factory.createDropTodo(e); + + if ( todo ) { + e->acceptAction(); + + KOTodoViewItem *destination = + (KOTodoViewItem *)itemAt(contentsToViewport(e->pos())); + Todo *destinationEvent = 0; + if (destination) destinationEvent = destination->todo(); + + Todo *existingTodo = mCalendar->todo(todo->uid()); + + if( existingTodo ) { + kdDebug(5850) << "Drop existing Todo " << existingTodo << " onto " << destinationEvent << endl; + Incidence *to = destinationEvent; + while(to) { + if (to->uid() == todo->uid()) { + KMessageBox::information(this, + i18n("Cannot move to-do to itself or a child of itself."), + i18n("Drop To-do"), "NoDropTodoOntoItself" ); + delete todo; + return; + } + to = to->relatedTo(); + } + Todo*oldTodo = existingTodo->clone(); + if ( mChanger->beginChange( existingTodo ) ) { + existingTodo->setRelatedTo( destinationEvent ); + mChanger->changeIncidence( oldTodo, existingTodo, KOGlobals::RELATION_MODIFIED ); + mChanger->endChange( existingTodo ); + } else { + KMessageBox::sorry( this, i18n("Unable to change to-do's parent, " + "because the to-do cannot be locked.") ); + } + delete oldTodo; + delete todo; + } else { +// kdDebug(5850) << "Drop new Todo" << endl; + todo->setRelatedTo(destinationEvent); + if ( !mChanger->addIncidence( todo, this ) ) { + KODialogManager::errorSaveIncidence( this, todo ); + delete todo; + return; + } + } + } + else { + QString text; + KOTodoViewItem *todoi = dynamic_cast<KOTodoViewItem *>(itemAt( contentsToViewport(e->pos()) )); + if ( ! todoi ) { + // Not dropped on a todo item: + e->ignore(); + kdDebug( 5850 ) << "KOTodoListView::contentsDropEvent(): Not dropped on a todo item" << endl; + kdDebug( 5850 ) << "TODO: Create a new todo with the given data" << endl; + // FIXME: Create a new todo with the given text/contact/whatever + } else if ( QTextDrag::decode(e, text) ) { + //QListViewItem *qlvi = itemAt( contentsToViewport(e->pos()) ); + kdDebug(5850) << "Dropped : " << text << endl; + Todo*todo = todoi->todo(); + if( mChanger->beginChange( todo ) ) { + Todo*oldtodo = todo->clone(); + + if( text.startsWith( "file:" ) ) { + todo->addAttachment( new Attachment( text ) ); + } else { + QStringList emails = KPIM::splitEmailAddrList( text ); + for(QStringList::ConstIterator it = emails.begin();it!=emails.end();++it) { + kdDebug(5850) << " Email: " << (*it) << endl; + int pos = (*it).find("<"); + QString name = (*it).left(pos); + QString email = (*it).mid(pos); + if (!email.isEmpty() && todoi) { + todo->addAttendee( new Attendee( name, email ) ); + } + } + } + mChanger->changeIncidence( oldtodo, todo ); + mChanger->endChange( todo ); + } else { + KMessageBox::sorry( this, i18n("Unable to add attendees to the to-do, " + "because the to-do cannot be locked.") ); + } + } + else { + kdDebug(5850) << "KOTodoListView::contentsDropEvent(): Todo from drop not decodable" << endl; + e->ignore(); + } + } +#endif +} + +void KOTodoListView::contentsMousePressEvent(QMouseEvent* e) +{ + QListView::contentsMousePressEvent(e); + QPoint p(contentsToViewport(e->pos())); + QListViewItem *i = itemAt(p); + if (i) { + // if the user clicked into the root decoration of the item, don't + // try to start a drag! + if (p.x() > header()->sectionPos(header()->mapToIndex(0)) + + treeStepSize() * (i->depth() + (rootIsDecorated() ? 1 : 0)) + + itemMargin() || + p.x() < header()->sectionPos(header()->mapToIndex(0))) { + if (e->button()==Qt::LeftButton) { + mPressPos = e->pos(); + mMousePressed = true; + } + } + } +} + +void KOTodoListView::contentsMouseMoveEvent(QMouseEvent* e) +{ +#ifndef KORG_NODND +// kdDebug(5850) << "KOTodoListView::contentsMouseMoveEvent()" << endl; + QListView::contentsMouseMoveEvent(e); + if (mMousePressed && (mPressPos - e->pos()).manhattanLength() > + QApplication::startDragDistance()) { + mMousePressed = false; + QListViewItem *item = itemAt(contentsToViewport(mPressPos)); + if ( item && mCalendar ) { +// kdDebug(5850) << "Start Drag for item " << item->text(0) << endl; + DndFactory factory( mCalendar ); + ICalDrag *vd = factory.createDrag( + ((KOTodoViewItem *)item)->todo(),viewport()); + if (vd->drag()) { + kdDebug(5850) << "KOTodoListView::contentsMouseMoveEvent(): Delete drag source" << endl; + } +/* + QString source = fullPath(item); + if ( QFile::exists(source) ) { + KURL url; + url.setPath(source); + KURLDrag* ud = KURLDrag::newDrag(KURL::List(url), viewport()); + if ( ud->drag() ) + QMessageBox::information( this, "Drag source", + QString("Delete ")+source, "Not implemented" ); +*/ + } + } +#endif +} + +void KOTodoListView::contentsMouseReleaseEvent(QMouseEvent *e) +{ + QListView::contentsMouseReleaseEvent(e); + mMousePressed = false; +} + +void KOTodoListView::contentsMouseDoubleClickEvent(QMouseEvent *e) +{ + if (!e) return; + + QPoint vp = contentsToViewport(e->pos()); + + QListViewItem *item = itemAt(vp); + + if (!item) return; + + emit doubleClicked(item,vp,0); +} + +///////////////////////////////////////////////////////////////////////////// + +KOTodoView::KOTodoView( Calendar *calendar, QWidget *parent, const char* name) + : KOrg::BaseView( calendar, parent, name ) +{ + QBoxLayout *topLayout = new QVBoxLayout( this ); + + QLabel *title = new QLabel( i18n("To-dos:"), this ); + title->setFrameStyle( QFrame::Panel | QFrame::Raised ); + topLayout->addWidget( title ); + + mQuickAdd = new KPIM::ClickLineEdit( this, i18n( "Click to add a new to-do" ) ); + mQuickAdd->setAcceptDrops( false ); + topLayout->addWidget( mQuickAdd ); + + if ( !KOPrefs::instance()->mEnableQuickTodo ) mQuickAdd->hide(); + + mTodoListView = new KOTodoListView( this ); + topLayout->addWidget( mTodoListView ); + + mTodoListView->setRootIsDecorated( true ); + mTodoListView->setAllColumnsShowFocus( true ); + + mTodoListView->setShowSortIndicator( true ); + + mTodoListView->addColumn( i18n("Summary") ); + mTodoListView->addColumn( i18n("Recurs") ); + mTodoListView->addColumn( i18n("Priority") ); + mTodoListView->setColumnAlignment( ePriorityColumn, AlignHCenter ); + mTodoListView->addColumn( i18n("Complete") ); + mTodoListView->setColumnAlignment( ePercentColumn, AlignRight ); + mTodoListView->addColumn( i18n("Due Date/Time") ); + mTodoListView->setColumnAlignment( eDueDateColumn, AlignLeft ); + mTodoListView->addColumn( i18n("Categories") ); +#if 0 + mTodoListView->addColumn( i18n("Sort Id") ); + mTodoListView->setColumnAlignment( 4, AlignHCenter ); +#endif + + mTodoListView->setMinimumHeight( 60 ); + mTodoListView->setItemsRenameable( true ); + mTodoListView->setRenameable( 0 ); + + mTodoListView->setColumnWidthMode( eSummaryColumn, QListView::Manual ); + mTodoListView->setColumnWidthMode( eRecurColumn, QListView::Manual ); + mTodoListView->setColumnWidthMode( ePriorityColumn, QListView::Manual ); + mTodoListView->setColumnWidthMode( ePercentColumn, QListView::Manual ); + mTodoListView->setColumnWidthMode( eDueDateColumn, QListView::Manual ); + mTodoListView->setColumnWidthMode( eCategoriesColumn, QListView::Manual ); +#if 0 + mTodoListView->setColumnWidthMode( eDescriptionColumn, QListView::Manual ); +#endif + + mPriorityPopupMenu = new QPopupMenu( this ); + mPriority[ mPriorityPopupMenu->insertItem( i18n("Unspecified priority", "unspecified") ) ] = 0; + mPriority[ mPriorityPopupMenu->insertItem( i18n( "1 (highest)") ) ] = 1; + mPriority[ mPriorityPopupMenu->insertItem( i18n( "2" ) ) ] = 2; + mPriority[ mPriorityPopupMenu->insertItem( i18n( "3" ) ) ] = 3; + mPriority[ mPriorityPopupMenu->insertItem( i18n( "4" ) ) ] = 4; + mPriority[ mPriorityPopupMenu->insertItem( i18n( "5 (medium)" ) ) ] = 5; + mPriority[ mPriorityPopupMenu->insertItem( i18n( "6" ) ) ] = 6; + mPriority[ mPriorityPopupMenu->insertItem( i18n( "7" ) ) ] = 7; + mPriority[ mPriorityPopupMenu->insertItem( i18n( "8" ) ) ] = 8; + mPriority[ mPriorityPopupMenu->insertItem( i18n( "9 (lowest)" ) ) ] = 9; + connect( mPriorityPopupMenu, SIGNAL( activated( int ) ), + SLOT( setNewPriority( int ) )); + + mPercentageCompletedPopupMenu = new QPopupMenu(this); + for (int i = 0; i <= 100; i+=10) { + QString label = QString ("%1 %").arg (i); + mPercentage[mPercentageCompletedPopupMenu->insertItem (label)] = i; + } + connect( mPercentageCompletedPopupMenu, SIGNAL( activated( int ) ), + SLOT( setNewPercentage( int ) ) ); + + mMovePopupMenu = new KDatePickerPopup( + KDatePickerPopup::NoDate | + KDatePickerPopup::DatePicker | + KDatePickerPopup::Words ); + mCopyPopupMenu = new KDatePickerPopup( + KDatePickerPopup::NoDate | + KDatePickerPopup::DatePicker | + KDatePickerPopup::Words ); + + + connect( mMovePopupMenu, SIGNAL( dateChanged( QDate )), + SLOT( setNewDate( QDate ) ) ); + connect( mCopyPopupMenu, SIGNAL( dateChanged( QDate )), + SLOT( copyTodoToDate( QDate ) ) ); + + mItemPopupMenu = new QPopupMenu(this); + mItemPopupMenu->insertItem(i18n("&Show"), this, + SLOT (showTodo())); + mItemPopupMenu->insertItem(i18n("&Edit..."), this, + SLOT (editTodo()), 0, ePopupEdit ); +#ifndef KORG_NOPRINTER + mItemPopupMenu->insertItem(KOGlobals::self()->smallIcon("printer1"), i18n("&Print..."), this, SLOT( printTodo() ) ); +#endif + mItemPopupMenu->insertItem(KOGlobals::self()->smallIconSet("editdelete"), i18n("&Delete"), this, + SLOT (deleteTodo()), 0, ePopupDelete ); + mItemPopupMenu->insertSeparator(); + mItemPopupMenu->insertItem(KOGlobals::self()->smallIconSet("todo"), i18n("New &To-do..."), this, + SLOT (newTodo())); + mItemPopupMenu->insertItem(i18n("New Su&b-to-do..."), this, + SLOT (newSubTodo())); + mItemPopupMenu->insertItem( i18n("&Make this To-do Independent"), this, + SIGNAL( unSubTodoSignal() ), 0, ePopupUnSubTodo ); + mItemPopupMenu->insertItem( i18n("Make all Sub-to-dos &Independent"), this, + SIGNAL( unAllSubTodoSignal() ), 0, ePopupUnAllSubTodo ); + mItemPopupMenu->insertSeparator(); + mItemPopupMenu->insertItem( i18n("&Copy To"), mCopyPopupMenu, ePopupCopyTo ); + mItemPopupMenu->insertItem(i18n("&Move To"), mMovePopupMenu, ePopupMoveTo ); + mItemPopupMenu->insertSeparator(); + mItemPopupMenu->insertItem(i18n("delete completed to-dos","Pur&ge Completed"), + this, SLOT( purgeCompleted() ) ); + + connect( mMovePopupMenu, SIGNAL( dateChanged( QDate ) ), + mItemPopupMenu, SLOT( hide() ) ); + connect( mCopyPopupMenu, SIGNAL( dateChanged( QDate ) ), + mItemPopupMenu, SLOT( hide() ) ); + + mPopupMenu = new QPopupMenu(this); + mPopupMenu->insertItem(KOGlobals::self()->smallIconSet("todo"), i18n("&New To-do..."), this, + SLOT (newTodo())); + mPopupMenu->insertItem(i18n("delete completed to-dos","&Purge Completed"), + this, SLOT(purgeCompleted())); + + mDocPrefs = new DocPrefs( name ); + + // Double clicking conflicts with opening/closing the subtree + connect( mTodoListView, SIGNAL( doubleClicked( QListViewItem *, + const QPoint &, int ) ), + SLOT( editItem( QListViewItem *, const QPoint &, int ) ) ); + connect( mTodoListView, SIGNAL( returnPressed( QListViewItem * ) ), + SLOT( editItem( QListViewItem * ) ) ); + connect( mTodoListView, SIGNAL( contextMenuRequested( QListViewItem *, + const QPoint &, int ) ), + SLOT( popupMenu( QListViewItem *, const QPoint &, int ) ) ); + connect( mTodoListView, SIGNAL( expanded( QListViewItem * ) ), + SLOT( itemStateChanged( QListViewItem * ) ) ); + connect( mTodoListView, SIGNAL( collapsed( QListViewItem * ) ), + SLOT( itemStateChanged( QListViewItem * ) ) ); + +#if 0 + connect(mTodoListView,SIGNAL(selectionChanged(QListViewItem *)), + SLOT(selectionChanged(QListViewItem *))); + connect(mTodoListView,SIGNAL(clicked(QListViewItem *)), + SLOT(selectionChanged(QListViewItem *))); + connect(mTodoListView,SIGNAL(pressed(QListViewItem *)), + SLOT(selectionChanged(QListViewItem *))); +#endif + connect( mTodoListView, SIGNAL(selectionChanged() ), + SLOT( processSelectionChange() ) ); + connect( mQuickAdd, SIGNAL( returnPressed () ), + SLOT( addQuickTodo() ) ); +} + +KOTodoView::~KOTodoView() +{ + delete mDocPrefs; +} + +void KOTodoView::setCalendar( Calendar *cal ) +{ + BaseView::setCalendar( cal ); + mTodoListView->setCalendar( cal ); +} + +void KOTodoView::updateView() +{ +// kdDebug(5850) << "KOTodoView::updateView()" << endl; + int oldPos = mTodoListView->contentsY(); + mItemsToDelete.clear(); + mTodoListView->clear(); + + Todo::List todoList = calendar()->todos(); + +/* + kdDebug(5850) << "KOTodoView::updateView(): Todo List:" << endl; + Event *t; + for(t = todoList.first(); t; t = todoList.next()) { + kdDebug(5850) << " " << t->getSummary() << endl; + + if (t->getRelatedTo()) { + kdDebug(5850) << " (related to " << t->getRelatedTo()->getSummary() << ")" << endl; + } + + QPtrList<Event> l = t->getRelations(); + Event *c; + for(c=l.first();c;c=l.next()) { + kdDebug(5850) << " - relation: " << c->getSummary() << endl; + } + } +*/ + + // Put for each Event a KOTodoViewItem in the list view. Don't rely on a + // specific order of events. That means that we have to generate parent items + // recursively for proper hierarchical display of Todos. + mTodoMap.clear(); + Todo::List::ConstIterator it; + for( it = todoList.begin(); it != todoList.end(); ++it ) { + if ( !mTodoMap.contains( *it ) ) { + insertTodoItem( *it ); + } + } + + // Restore opened/closed state + mTodoListView->blockSignals( true ); + if( mDocPrefs ) restoreItemState( mTodoListView->firstChild() ); + mTodoListView->blockSignals( false ); + + mTodoListView->setContentsPos( 0, oldPos ); + + processSelectionChange(); +} + +void KOTodoView::restoreItemState( QListViewItem *item ) +{ + while( item ) { + KOTodoViewItem *todoItem = (KOTodoViewItem *)item; + todoItem->setOpen( mDocPrefs->readBoolEntry( todoItem->todo()->uid() ) ); + if( item->childCount() > 0 ) restoreItemState( item->firstChild() ); + item = item->nextSibling(); + } +} + + +QMap<Todo *,KOTodoViewItem *>::ConstIterator + KOTodoView::insertTodoItem(Todo *todo) +{ +// kdDebug(5850) << "KOTodoView::insertTodoItem(): " << todo->getSummary() << endl; + Incidence *incidence = todo->relatedTo(); + if (incidence && incidence->type() == "Todo") { + // Use dynamic_cast, because in the future the related item might also be an event + Todo *relatedTodo = dynamic_cast<Todo *>(incidence); + + // just make sure we know we have this item already to avoid endless recursion (Bug 101696) + mTodoMap.insert(todo,0); + +// kdDebug(5850) << " has Related" << endl; + QMap<Todo *,KOTodoViewItem *>::ConstIterator itemIterator; + itemIterator = mTodoMap.find(relatedTodo); + if (itemIterator == mTodoMap.end()) { +// kdDebug(5850) << " related not yet in list" << endl; + itemIterator = insertTodoItem (relatedTodo); + } + // isn't this pretty stupid? We give one Todo to the KOTodoViewItem + // and one into the map. Sure finding is more easy but why? -zecke + KOTodoViewItem *todoItem; + + // in case we found a related parent, which has no KOTodoViewItem yet, this must + // be the case where 2 items refer to each other, therefore simply create item as root item + if ( *itemIterator == 0 ) { + todo->setRelatedTo(0); // break the recursion, else we will have troubles later + todoItem = new KOTodoViewItem(mTodoListView,todo,this); + } + else + todoItem = new KOTodoViewItem(*itemIterator,todo,this); + + return mTodoMap.insert(todo,todoItem); + } else { +// kdDebug(5850) << " no Related" << endl; + // see above -zecke + KOTodoViewItem *todoItem = new KOTodoViewItem(mTodoListView,todo,this); + return mTodoMap.insert(todo,todoItem); + } +} + +void KOTodoView::removeTodoItems() +{ + KOTodoViewItem *item; + for ( item = mItemsToDelete.first(); item; item = mItemsToDelete.next() ) { + Todo *todo = item->todo(); + if ( todo && mTodoMap.contains( todo ) ) { + mTodoMap.remove( todo ); + } + delete item; + } + mItemsToDelete.clear(); +} + + +bool KOTodoView::scheduleRemoveTodoItem( KOTodoViewItem *todoItem ) +{ + if ( todoItem ) { + mItemsToDelete.append( todoItem ); + QTimer::singleShot( 0, this, SLOT( removeTodoItems() ) ); + return true; + } else + return false; +} + +void KOTodoView::updateConfig() +{ + mTodoListView->repaintContents(); +} + +Incidence::List KOTodoView::selectedIncidences() +{ + Incidence::List selected; + + KOTodoViewItem *item = (KOTodoViewItem *)(mTodoListView->selectedItem()); +// if (!item) item = mActiveItem; + if (item) selected.append(item->todo()); + + return selected; +} + +Todo::List KOTodoView::selectedTodos() +{ + Todo::List selected; + + KOTodoViewItem *item = (KOTodoViewItem *)(mTodoListView->selectedItem()); +// if (!item) item = mActiveItem; + if (item) selected.append(item->todo()); + + return selected; +} + +void KOTodoView::changeIncidenceDisplay(Incidence *incidence, int action) +{ + // The todo view only displays todos, so exit on all other incidences + if ( incidence->type() != "Todo" ) + return; + CalFilter *filter = calendar()->filter(); + bool isFiltered = filter && !filter->filterIncidence( incidence ); + Todo *todo = static_cast<Todo *>(incidence); + if ( todo ) { + KOTodoViewItem *todoItem = 0; + if ( mTodoMap.contains( todo ) ) { + todoItem = mTodoMap[todo]; + } + switch ( action ) { + case KOGlobals::INCIDENCEADDED: + case KOGlobals::INCIDENCEEDITED: + // If it's already there, edit it, otherwise just add + if ( todoItem ) { + if ( isFiltered ) { + scheduleRemoveTodoItem( todoItem ); + } else { + // correctly update changes in relations + Todo*parent = dynamic_cast<Todo*>( todo->relatedTo() ); + KOTodoViewItem*parentItem = 0; + if ( parent && mTodoMap.contains(parent) ) { + parentItem = mTodoMap[ parent ]; + } + if ( todoItem->parent() != parentItem ) { + // The relations changed + if ( parentItem ) { + parentItem->insertItem( todoItem ); + } else { + mTodoListView->insertItem( todoItem ); + } + } + todoItem->construct(); + } + } else { + if ( !isFiltered ) { + insertTodoItem( todo ); + } + } + mTodoListView->sort(); + break; + case KOGlobals::INCIDENCEDELETED: + if ( todoItem ) { + scheduleRemoveTodoItem( todoItem ); + } + break; + default: + QTimer::singleShot( 0, this, SLOT( updateView() ) ); + } + } else { + // use a QTimer here, because when marking todos finished using + // the checkbox, this slot gets called, but we cannot update the views + // because we're still inside KOTodoViewItem::stateChange + QTimer::singleShot(0,this,SLOT(updateView())); + } +} + +void KOTodoView::showDates(const QDate &, const QDate &) +{ +} + +void KOTodoView::showIncidences( const Incidence::List & ) +{ + 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; + } +} + +void KOTodoView::editItem( QListViewItem *item ) +{ + if (item) + emit editIncidenceSignal( static_cast<KOTodoViewItem *>( item )->todo() ); +} + +void KOTodoView::editItem( QListViewItem *item, const QPoint &, int ) +{ + editItem( item ); +} + +void KOTodoView::showItem( QListViewItem *item ) +{ + if (item) + emit showIncidenceSignal( static_cast<KOTodoViewItem *>( item )->todo() ); +} + +void KOTodoView::showItem( QListViewItem *item, const QPoint &, int ) +{ + showItem( item ); +} + +void KOTodoView::popupMenu( QListViewItem *item, const QPoint &, int column ) +{ + mActiveItem = static_cast<KOTodoViewItem *>( item ); + if ( mActiveItem && mActiveItem->todo() && + !mActiveItem->todo()->isReadOnly() ) { + bool editable = !mActiveItem->todo()->isReadOnly(); + mItemPopupMenu->setItemEnabled( ePopupEdit, editable ); + mItemPopupMenu->setItemEnabled( ePopupDelete, editable ); + mItemPopupMenu->setItemEnabled( ePopupMoveTo, editable ); + mItemPopupMenu->setItemEnabled( ePopupCopyTo, editable ); + mItemPopupMenu->setItemEnabled( ePopupUnSubTodo, editable ); + mItemPopupMenu->setItemEnabled( ePopupUnAllSubTodo, editable ); + + if ( editable ) { + QDate date = mActiveItem->todo()->dtDue().date(); + if ( mActiveItem->todo()->hasDueDate () ) { + mMovePopupMenu->datePicker()->setDate( date ); + } else { + mMovePopupMenu->datePicker()->setDate( QDate::currentDate() ); + } + switch ( column ) { + case ePriorityColumn: + mPriorityPopupMenu->popup( QCursor::pos() ); + break; + case ePercentColumn: { + mPercentageCompletedPopupMenu->popup( QCursor::pos() ); + break; + } + case eDueDateColumn: + mMovePopupMenu->popup( QCursor::pos() ); + break; + case eCategoriesColumn: + getCategoryPopupMenu( mActiveItem )->popup( QCursor::pos() ); + break; + default: + mCopyPopupMenu->datePicker()->setDate( date ); + mCopyPopupMenu->datePicker()->setDate( QDate::currentDate() ); + mItemPopupMenu->setItemEnabled( ePopupUnSubTodo, + mActiveItem->todo()->relatedTo() ); + mItemPopupMenu->setItemEnabled( ePopupUnAllSubTodo, + !mActiveItem->todo()->relations().isEmpty() ); + mItemPopupMenu->popup( QCursor::pos() ); + } + } else { + mItemPopupMenu->popup( QCursor::pos() ); + } + } else mPopupMenu->popup( QCursor::pos() ); +} + +void KOTodoView::newTodo() +{ + kdDebug() << k_funcinfo << endl; + emit newTodoSignal( QDate::currentDate().addDays(7) ); +} + +void KOTodoView::newSubTodo() +{ + if (mActiveItem) { + emit newSubTodoSignal(mActiveItem->todo()); + } +} + +void KOTodoView::editTodo() +{ + editItem( mActiveItem ); +} + +void KOTodoView::showTodo() +{ + showItem( mActiveItem ); +} + +void KOTodoView::printTodo() +{ +#ifndef KORG_NOPRINTER + KOCoreHelper helper; + CalPrinter printer( this, BaseView::calendar(), &helper ); + connect( this, SIGNAL(configChanged()), &printer, SLOT(updateConfig()) ); + + Incidence::List selectedIncidences; + selectedIncidences.append( mActiveItem->todo() ); + + printer.print( KOrg::CalPrinterBase::Incidence, + QDate(), QDate(), selectedIncidences ); +#endif +} + +void KOTodoView::deleteTodo() +{ + if (mActiveItem) { + emit deleteIncidenceSignal( mActiveItem->todo() ); + } +} + +void KOTodoView::setNewPriority(int index) +{ + if ( !mActiveItem || !mChanger ) return; + Todo *todo = mActiveItem->todo(); + if ( !todo->isReadOnly () && + mChanger->beginChange( todo ) ) { + Todo *oldTodo = todo->clone(); + todo->setPriority(mPriority[index]); + mActiveItem->construct(); + + mChanger->changeIncidence( oldTodo, todo, KOGlobals::PRIORITY_MODIFIED ); + mChanger->endChange( todo ); + delete oldTodo; + } +} + +void KOTodoView::setNewPercentage( KOTodoViewItem *item, int percentage ) +{ + kdDebug(5850) << "KOTodoView::setNewPercentage( " << percentage << "), item = " << item << endl; + if ( !item || !mChanger ) return; + Todo *todo = item->todo(); + if ( !todo ) return; + + if ( !todo->isReadOnly () && mChanger->beginChange( todo ) ) { + Todo *oldTodo = todo->clone(); + +/* Old code to make sub-items's percentage related to this one's: + QListViewItem *myChild = firstChild(); + KOTodoViewItem *item; + while( myChild ) { + item = static_cast<KOTodoViewItem*>(myChild); + item->stateChange(state); + myChild = myChild->nextSibling(); + }*/ + if ( percentage == 100 ) { + todo->setCompleted( QDateTime::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( QCheckListItem::Off ); + else todo->setPercentComplete( percentage ); + } else { + todo->setCompleted( false ); + todo->setPercentComplete( percentage ); + } + item->construct(); + if ( todo->doesRecur() && percentage == 100 ) + mChanger->changeIncidence( oldTodo, todo, KOGlobals::COMPLETION_MODIFIED_WITH_RECURRENCE ); + else + mChanger->changeIncidence( oldTodo, todo, KOGlobals::COMPLETION_MODIFIED ); + mChanger->endChange( todo ); + delete oldTodo; + } else { + item->construct(); + kdDebug(5850) << "No active item, active item is read-only, or locking failed" << endl; + } +} + +void KOTodoView::setNewPercentage( int index ) +{ + setNewPercentage( mActiveItem, mPercentage[index] ); +} + +void KOTodoView::setNewDate( QDate date ) +{ + if ( !mActiveItem || !mChanger ) return; + Todo *todo = mActiveItem->todo(); + if ( !todo ) return; + + if ( !todo->isReadOnly() && mChanger->beginChange( todo ) ) { + Todo *oldTodo = todo->clone(); + + QDateTime dt; + dt.setDate( date ); + + if ( !todo->doesFloat() ) + dt.setTime( todo->dtDue().time() ); + + if ( date.isNull() ) + todo->setHasDueDate( false ); + else if ( !todo->hasDueDate() ) + todo->setHasDueDate( true ); + todo->setDtDue( dt ); + + mActiveItem->construct(); + mChanger->changeIncidence( oldTodo, todo, KOGlobals::COMPLETION_MODIFIED ); + mChanger->endChange( todo ); + delete oldTodo; + } else { + kdDebug(5850) << "No active item, active item is read-only, or locking failed" << endl; + } +} + +void KOTodoView::copyTodoToDate( QDate date ) +{ + QDateTime dt( date ); + + if ( mActiveItem && mChanger ) { + Todo *newTodo = mActiveItem->todo()->clone(); + newTodo->recreate(); + + newTodo->setHasDueDate( !date.isNull() ); + newTodo->setDtDue( dt ); + newTodo->setPercentComplete( 0 ); + + // avoid forking + if ( newTodo->doesRecur() ) + newTodo->recurrence()->unsetRecurs(); + + mChanger->addIncidence( newTodo, this ); + } +} + +QPopupMenu *KOTodoView::getCategoryPopupMenu( KOTodoViewItem *todoItem ) +{ + QPopupMenu *tempMenu = new QPopupMenu( this ); + QStringList checkedCategories = todoItem->todo()->categories(); + + tempMenu->setCheckable( true ); + QStringList::Iterator it; + for ( it = KOPrefs::instance()->mCustomCategories.begin(); + it != KOPrefs::instance()->mCustomCategories.end(); + ++it ) { + int index = tempMenu->insertItem( *it ); + mCategory[ index ] = *it; + if ( checkedCategories.find( *it ) != checkedCategories.end() ) + tempMenu->setItemChecked( index, true ); + } + + connect ( tempMenu, SIGNAL( activated( int ) ), + SLOT( changedCategories( int ) ) ); + return tempMenu; +} + +void KOTodoView::changedCategories(int index) +{ + if ( !mActiveItem || !mChanger ) return; + Todo *todo = mActiveItem->todo(); + if ( !todo ) return; + + if ( !todo->isReadOnly() && mChanger->beginChange( todo ) ) { + Todo *oldTodo = todo->clone(); + + QStringList categories = todo->categories (); + if ( categories.find( mCategory[index] ) != categories.end() ) + categories.remove( mCategory[index] ); + else + categories.insert( categories.end(), mCategory[index] ); + categories.sort(); + todo->setCategories( categories ); + mActiveItem->construct(); + mChanger->changeIncidence( oldTodo, todo, KOGlobals::CATEGORY_MODIFIED ); + mChanger->endChange( todo ); + delete oldTodo; + } else { + kdDebug(5850) << "No active item, active item is read-only, or locking failed" << endl; + } +} + +void KOTodoView::setDocumentId( const QString &id ) +{ + kdDebug(5850) << "KOTodoView::setDocumentId()" << endl; + + mDocPrefs->setDoc( id ); +} + +void KOTodoView::itemStateChanged( QListViewItem *item ) +{ + if (!item) return; + + KOTodoViewItem *todoItem = (KOTodoViewItem *)item; + +// kdDebug(5850) << "KOTodoView::itemStateChanged(): " << todoItem->todo()->summary() << endl; + + if( mDocPrefs ) mDocPrefs->writeEntry( todoItem->todo()->uid(), todoItem->isOpen() ); +} + +void KOTodoView::setNewPercentageDelayed( KOTodoViewItem *item, int percentage ) +{ + mPercentChangedMap.append( qMakePair( item, percentage ) ); + + QTimer::singleShot( 0, this, SLOT( processDelayedNewPercentage() ) ); +} + +void KOTodoView::processDelayedNewPercentage() +{ + QValueList< QPair< KOTodoViewItem *, int> >::Iterator it; + for ( it = mPercentChangedMap.begin(); it != mPercentChangedMap.end(); ++it ) + setNewPercentage( (*it).first, (*it).second ); + + mPercentChangedMap.clear(); +} + +void KOTodoView::saveLayout(KConfig *config, const QString &group) const +{ + mTodoListView->saveLayout(config,group); +} + +void KOTodoView::restoreLayout(KConfig *config, const QString &group) +{ + mTodoListView->restoreLayout(config,group); +} + +void KOTodoView::processSelectionChange() +{ +// kdDebug(5850) << "KOTodoView::processSelectionChange()" << endl; + + KOTodoViewItem *item = + static_cast<KOTodoViewItem *>( mTodoListView->selectedItem() ); + + if ( !item ) { + emit incidenceSelected( 0 ); + } else { + emit incidenceSelected( item->todo() ); + } +} + +void KOTodoView::clearSelection() +{ + mTodoListView->selectAll( false ); +} + +void KOTodoView::purgeCompleted() +{ + emit purgeCompletedSignal(); +} + +void KOTodoView::addQuickTodo() +{ + if ( ! mQuickAdd->text().stripWhiteSpace().isEmpty() ) { + Todo *todo = new Todo(); + todo->setSummary( mQuickAdd->text() ); + todo->setOrganizer( Person( KOPrefs::instance()->fullName(), + KOPrefs::instance()->email() ) ); + if ( !mChanger->addIncidence( todo, this ) ) { + KODialogManager::errorSaveIncidence( this, todo ); + delete todo; + return; + } + mQuickAdd->setText( QString::null ); + } +} + +void KOTodoView::setIncidenceChanger( IncidenceChangerBase *changer ) +{ + mChanger = changer; + mTodoListView->setIncidenceChanger( changer ); +} diff --git a/korganizer/kotodoview.h b/korganizer/kotodoview.h new file mode 100644 index 000000000..aee9037ea --- /dev/null +++ b/korganizer/kotodoview.h @@ -0,0 +1,248 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2000,2001,2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOTODOVIEW_H +#define KOTODOVIEW_H + +#include <qmap.h> +#include <qtooltip.h> + +#include <klistview.h> + +#include <libkcal/todo.h> +#include <korganizer/baseview.h> + +class QDragEnterEvent; +class QDragMoveEvent; +class QDragLeaveEvent; +class QDropEvent; +class QPopupMenu; + +class KOTodoListView; +class KOTodoViewItem; +class KDatePickerPopup; + +class DocPrefs; + +namespace KPIM { + class ClickLineEdit; +} +namespace KCal { +class Incidence; +class Calendar; +} +using namespace KCal; +using namespace KOrg; + +class KOTodoListViewToolTip : public QToolTip +{ + public: + KOTodoListViewToolTip( QWidget *parent, KOTodoListView *lv ); + + protected: + void maybeTip( const QPoint &pos ); + + private: + KOTodoListView *todolist; +}; + + +class KOTodoListView : public KListView +{ + Q_OBJECT + public: + KOTodoListView( QWidget *parent = 0, const char *name = 0 ); + ~KOTodoListView(); + + void setCalendar( Calendar * ); + + void setIncidenceChanger( IncidenceChangerBase *changer ) { mChanger = changer; } + + protected: + virtual bool event( QEvent * ); + + void contentsDragEnterEvent( QDragEnterEvent * ); + void contentsDragMoveEvent( QDragMoveEvent * ); + void contentsDragLeaveEvent( QDragLeaveEvent * ); + void contentsDropEvent( QDropEvent * ); + + void contentsMousePressEvent( QMouseEvent * ); + void contentsMouseMoveEvent( QMouseEvent * ); + void contentsMouseReleaseEvent( QMouseEvent * ); + void contentsMouseDoubleClickEvent( QMouseEvent * ); + + private: + Calendar *mCalendar; + KOrg::IncidenceChangerBase *mChanger; + + QPoint mPressPos; + bool mMousePressed; + QListViewItem *mOldCurrent; + KOTodoListViewToolTip *tooltip; +}; + + +/** + This class provides a multi-column list view of todo events. + + @short multi-column list view of todo events. + @author Cornelius Schumacher <schumacher@kde.org> +*/ +class KOTodoView : public KOrg::BaseView +{ + Q_OBJECT + public: + KOTodoView( Calendar *cal, QWidget *parent = 0, const char *name = 0 ); + ~KOTodoView(); + + void setCalendar( Calendar * ); + + Incidence::List selectedIncidences(); + Todo::List selectedTodos(); + + DateList selectedDates() { return DateList(); } + + /** Return number of shown dates. TodoView does not show dates, */ + int currentDateCount() { return 0; } + + CalPrinterBase::PrintType printType(); + + void setDocumentId( const QString & ); + + void saveLayout( KConfig *config, const QString &group ) const; + void restoreLayout( KConfig *config, const QString &group ); + /** Create a popup menu to set categories */ + QPopupMenu *getCategoryPopupMenu( KOTodoViewItem *todoItem ); + void setIncidenceChanger( IncidenceChangerBase *changer ); + + public slots: + void updateView(); + void updateConfig(); + + void changeIncidenceDisplay( Incidence *, int ); + + void showDates( const QDate &start, const QDate &end ); + void showIncidences( const Incidence::List &incidenceList ); + + void clearSelection(); + + void editItem( QListViewItem *item, const QPoint &, int ); + void editItem( QListViewItem *item ); + void showItem( QListViewItem *item, const QPoint &, int ); + void showItem( QListViewItem *item ); + void popupMenu( QListViewItem *item, const QPoint &, int ); + void newTodo(); + void newSubTodo(); + void showTodo(); + void editTodo(); + void printTodo(); + void deleteTodo(); + + void setNewPercentage( KOTodoViewItem *item, int percentage ); + + void setNewPriority( int ); + void setNewPercentage( int ); + void setNewDate( QDate ); + void copyTodoToDate( QDate ); + void changedCategories( int ); + + void purgeCompleted(); + + void itemStateChanged( QListViewItem * ); + + void setNewPercentageDelayed( KOTodoViewItem *item, int percentage ); + void processDelayedNewPercentage(); + + signals: + void unSubTodoSignal(); + void unAllSubTodoSignal(); + + void purgeCompletedSignal(); + + protected slots: + void processSelectionChange(); + void addQuickTodo(); + void removeTodoItems(); + + private: + /* + * the TodoEditor approach is rather unscaling in the long + * run. + * Korganizer keeps it in memory and we need to update + * 1. make KOTodoViewItem a QObject again? + * 2. add a public method for setting one todo modified? + * 3. add a private method for setting a todo modified + friend here? + * -- zecke 2002-07-08 + */ + friend class KOTodoViewItem; + + QMap<Todo *,KOTodoViewItem *>::ConstIterator insertTodoItem( Todo *todo ); + bool scheduleRemoveTodoItem( KOTodoViewItem *todoItem ); + void restoreItemState( QListViewItem * ); + + KOTodoListView *mTodoListView; + QPopupMenu *mItemPopupMenu; + QPopupMenu *mPopupMenu; + QPopupMenu *mPriorityPopupMenu; + QPopupMenu *mPercentageCompletedPopupMenu; + QPopupMenu *mCategoryPopupMenu; + KDatePickerPopup *mMovePopupMenu; + KDatePickerPopup *mCopyPopupMenu; + + QMap<int, int> mPercentage; + QMap<int, int> mPriority; + QMap<int, QString> mCategory; + + KOTodoViewItem *mActiveItem; + + QMap<Todo *,KOTodoViewItem *> mTodoMap; + QPtrList<KOTodoViewItem> mItemsToDelete; + QValueList< QPair<KOTodoViewItem *, int> > mPercentChangedMap; + + DocPrefs *mDocPrefs; + QString mCurrentDoc; + KPIM::ClickLineEdit *mQuickAdd; + + public: + enum { + eSummaryColumn = 0, + eRecurColumn = 1, + ePriorityColumn = 2, + ePercentColumn = 3, + eDueDateColumn = 4, + eCategoriesColumn = 5, + eDescriptionColumn = 6 + }; + enum { + ePopupEdit = 1300, + ePopupDelete = 1301, + ePopupMoveTo = 1302, + ePopupCopyTo = 1303, + ePopupUnSubTodo = 1304, + ePopupUnAllSubTodo = 1305 + }; + +}; + +#endif diff --git a/korganizer/kotodoviewitem.cpp b/korganizer/kotodoviewitem.cpp new file mode 100644 index 000000000..bb5f08c52 --- /dev/null +++ b/korganizer/kotodoviewitem.cpp @@ -0,0 +1,262 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com> + Copyright (c) 2005 Rafal Rzepecki <divide@users.sourceforge.net> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qpainter.h> + +#include <klocale.h> +#include <kdebug.h> +#include <qpainter.h> +#include <qpixmap.h> + +#include "kotodoviewitem.h" +#include "kotodoview.h" +#include "koprefs.h" +#include "koglobals.h" + +KOTodoViewItem::KOTodoViewItem( QListView *parent, Todo *todo, KOTodoView *kotodo) + : QCheckListItem( parent , "", CheckBox ), mTodo( todo ), mTodoView( kotodo ) +{ + construct(); +} + +KOTodoViewItem::KOTodoViewItem( KOTodoViewItem *parent, Todo *todo, KOTodoView *kotodo ) + : QCheckListItem( parent, "", CheckBox ), mTodo( todo ), mTodoView( kotodo ) +{ + construct(); +} + +inline int KOTodoViewItem::compareDueDates( const KOTodoViewItem *b ) const +{ + if ( mEffectiveDueDate.isValid() && + !b->mEffectiveDueDate.isValid() ) + return -1; + else if ( !mEffectiveDueDate.isValid() && + b->mEffectiveDueDate.isValid() ) + return 1; + else + return b->mEffectiveDueDate.secsTo( mEffectiveDueDate ); +} + +int KOTodoViewItem::compare( QListViewItem *it, int col, bool ascending ) const +{ + KOTodoViewItem *i = dynamic_cast<KOTodoViewItem *>( it ); + if ( !i ) + return QListViewItem::compare( it, col, ascending ); + + // throw completed todos to the bottom + if ( mTodo->isCompleted() && !i->todo()->isCompleted() ) + return ascending ? 1 : -1; + 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; + return compareDueDates( i ); + case ( KOTodoView::ePercentColumn ): + return mTodo->percentComplete() - i->todo()->percentComplete(); + case ( KOTodoView::eDueDateColumn ): + c = compareDueDates( i ); + if ( c ) + return c; + 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 QListViewItem::compare( it, col, ascending ); + } +} + +#if QT_VERSION >= 300 +void KOTodoViewItem::paintBranches(QPainter *p,const QColorGroup & cg,int w, + int y,int h) +{ + QListViewItem::paintBranches(p,cg,w,y,h); +} +#else +#endif + +void KOTodoViewItem::construct() +{ + if ( !mTodo ) return; + m_init = true; + + setOn( mTodo->isCompleted() ); + setText( KOTodoView::eSummaryColumn, mTodo->summary()); + static const QPixmap recurPxmp = KOGlobals::self()->smallIcon("recur"); + if ( mTodo->doesRecur() ) + setPixmap( KOTodoView::eRecurColumn, recurPxmp ); + + if ( mTodo->priority()==0 ) { + setText( KOTodoView::ePriorityColumn, i18n("--") ); + } else { + setText( KOTodoView::ePriorityColumn, QString::number(mTodo->priority()) ); + } + setText( KOTodoView::ePercentColumn, QString::number(mTodo->percentComplete()) ); + + if (mTodo->hasDueDate()) { + QString dtStr = mTodo->dtDueDateStr(); + if (!mTodo->doesFloat()) { + dtStr += " " + mTodo->dtDueTimeStr(); + } + setText( KOTodoView::eDueDateColumn, dtStr ); + mEffectiveDueDate = mTodo->dtDue(); + KOTodoViewItem *myParent; + if ( ( myParent = dynamic_cast<KOTodoViewItem *>( parent() ) ) ) + if ( !myParent->mEffectiveDueDate.isValid() || + myParent->mEffectiveDueDate > mEffectiveDueDate ) { + myParent->mEffectiveDueDate = mEffectiveDueDate; + } + } else + setText( KOTodoView::eDueDateColumn, "" ); + + setText( KOTodoView::eCategoriesColumn, mTodo->categoriesStr() ); + +#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 + // of sort id. + int pos = mTodo->description().findRev('#'); + if (pos < 0) { + setText( KOTodoView::eDescriptionColumn, "" ); + } else { + QString str = mTodo->description().mid(pos+1); + str.stripWhiteSpace(); + setText( KOTodoView::eDescriptionColumn, str ); + } +#endif + + m_known = false; + m_init = false; +} + +void KOTodoViewItem::stateChange( bool state ) +{ + // do not change setting on startup or if no valid todo item is given + if ( m_init || !mTodo ) return; + + if ( mTodo->isReadOnly() ) { + setOn( mTodo->isCompleted() ); + return; + } + + kdDebug(5850) << "State changed, modified " << state << endl; + mTodoView->setNewPercentageDelayed( this, state ? 100 : 0 ); +} + +bool KOTodoViewItem::isAlternate() +{ +#ifndef KORG_NOLVALTERNATION + KOTodoListView *lv = static_cast<KOTodoListView *>(listView()); + if (lv && lv->alternateBackground().isValid()) + { + KOTodoViewItem *above = 0; + above = dynamic_cast<KOTodoViewItem *>(itemAbove()); + m_known = above ? above->m_known : true; + if (m_known) + { + m_odd = above ? !above->m_odd : false; + } + else + { + KOTodoViewItem *item; + bool previous = true; + if (QListViewItem::parent()) + { + item = dynamic_cast<KOTodoViewItem *>(QListViewItem::parent()); + if (item) + previous = item->m_odd; + item = dynamic_cast<KOTodoViewItem *>(QListViewItem::parent()->firstChild()); + } + else + { + item = dynamic_cast<KOTodoViewItem *>(lv->firstChild()); + } + + while(item) + { + item->m_odd = previous = !previous; + item->m_known = true; + item = dynamic_cast<KOTodoViewItem *>(item->nextSibling()); + } + } + return m_odd; + } + return false; +#else + return false; +#endif +} + +void KOTodoViewItem::paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int alignment) +{ + QColorGroup _cg = cg; + // If no todo is set, just don't paint anything... + if ( !mTodo ) return; +#ifndef KORG_NOLVALTERNATION + if (isAlternate()) + _cg.setColor(QColorGroup::Base, static_cast< KOTodoListView* >(listView())->alternateBackground()); + if (mTodo->hasDueDate()) { + if (mTodo->dtDue().date()==QDate::currentDate() && + !mTodo->isCompleted()) { + _cg.setColor(QColorGroup::Base, KOPrefs::instance()->mTodoDueTodayColor); + _cg.setColor(QColorGroup::Text, getTextColor(KOPrefs::instance()->mTodoDueTodayColor)); + } + if (mTodo->dtDue().date() < QDate::currentDate() && + !mTodo->isCompleted()) { + _cg.setColor(QColorGroup::Base, KOPrefs::instance()->mTodoOverdueColor); + _cg.setColor(QColorGroup::Text, getTextColor(KOPrefs::instance()->mTodoOverdueColor)); + } + } +#endif + + // show the progess by a horizontal bar + if ( column == KOTodoView::ePercentColumn ) { + p->save(); + int progress = (int)(( (width-6)*mTodo->percentComplete())/100.0 + 0.5); + + p->fillRect( 0, 0, width, height(), _cg.base() ); // background + p->setPen( KGlobalSettings::textColor() ); //border + p->setBrush( KGlobalSettings::baseColor() ); //filling + p->drawRect( 2, 2, width-4, height()-4); + p->fillRect( 3, 3, progress, height()-6, + KGlobalSettings::highlightColor() ); + p->restore(); + } else { + QCheckListItem::paintCell(p, _cg, column, width, alignment); + } +} diff --git a/korganizer/kotodoviewitem.h b/korganizer/kotodoviewitem.h new file mode 100644 index 000000000..5cb362af9 --- /dev/null +++ b/korganizer/kotodoviewitem.h @@ -0,0 +1,90 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2000, 2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com> + Copyright (c) 2005 Rafal Rzepecki <divide@users.sourceforge.net> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOTODOVIEWITEM_H +#define KOTODOVIEWITEM_H + +#include <qmap.h> +#include <qlistview.h> +#include <qpalette.h> +#include <qdatetime.h> + +namespace KCal { +class Todo; +} +using namespace KCal; + +class KOTodoView; + +/** + This class provides a way of displaying a single Event of Todo-Type in a + KTodoView. + + @author Cornelius Schumacher <schumacher@kde.org> + @see KOTodoView +*/ +class KOTodoViewItem : public QCheckListItem +{ + public: + /** + Constructor. + + @param parent is the list view to which this item belongs. + @param todo is the todo to have the item display information for. + @param kotodo is a pointer to the KOTodoView object. + */ + KOTodoViewItem(QListView *parent, Todo *todo, KOTodoView *kotodo); + KOTodoViewItem(KOTodoViewItem *parent, Todo *todo, KOTodoView *kotodo); + virtual ~KOTodoViewItem() {} + + void construct(); + + Todo *todo() const { return mTodo; } + + bool isAlternate(); + int compare( QListViewItem *i, int col, bool ascending ) const; + virtual void paintCell(QPainter *p, const QColorGroup &cg, + int column, int width, int alignment); + + protected: +#if QT_VERSION >= 300 + void paintBranches(QPainter *p,const QColorGroup & cg,int w,int y,int h); +#else +#endif + virtual void stateChange(bool); + + private: + Todo *mTodo; + KOTodoView *mTodoView; + QDateTime mEffectiveDueDate; + int compareDueDates( const KOTodoViewItem *b ) const; + + uint m_odd : 1; + uint m_known : 1; + uint m_unused : 30; + bool m_init; +}; + +#endif diff --git a/korganizer/koviewmanager.cpp b/korganizer/koviewmanager.cpp new file mode 100644 index 000000000..d7929039e --- /dev/null +++ b/korganizer/koviewmanager.cpp @@ -0,0 +1,477 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001,2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qwidgetstack.h> +#include <qtabwidget.h> + +#include <kconfig.h> +#include <kglobal.h> + +#include "calendarview.h" +#include "datenavigator.h" +#include "kotodoview.h" +#include "koagendaview.h" +#include "komonthview.h" +#include "kolistview.h" +#include "kowhatsnextview.h" +#include "kojournalview.h" +#include "kotimelineview.h" +#include "koprefs.h" +#include "koglobals.h" +#include "navigatorbar.h" +#include "multiagendaview.h" + +#include "koviewmanager.h" +#include "koviewmanager.moc" + +KOViewManager::KOViewManager( CalendarView *mainView ) : + QObject(), mMainView( mainView ) +{ + mCurrentView = 0; + + mLastEventView = 0; + + mWhatsNextView = 0; + mTodoView = 0; + mAgendaView = 0; + mAgendaSideBySideView = 0; + mMonthView = 0; + mListView = 0; + mJournalView = 0; + mTimelineView = 0; + mAgendaViewTabs = 0; +} + +KOViewManager::~KOViewManager() +{ +} + + +KOrg::BaseView *KOViewManager::currentView() +{ + return mCurrentView; +} + +void KOViewManager::readSettings(KConfig *config) +{ + config->setGroup("General"); + QString view = config->readEntry("Current View"); + + if (view == "WhatsNext") showWhatsNextView(); + else if (view == "Month") showMonthView(); + else if (view == "List") showListView(); + else if (view == "Journal") showJournalView(); + else if (view == "Todo") showTodoView(); + else if (view == "Timeline") showTimelineView(); + else showAgendaView(); +} + +void KOViewManager::writeSettings(KConfig *config) +{ + config->setGroup("General"); + + QString view; + if (mCurrentView == mWhatsNextView) view = "WhatsNext"; + else if (mCurrentView == mMonthView) view = "Month"; + else if (mCurrentView == mListView) view = "List"; + else if (mCurrentView == mJournalView) view = "Journal"; + else if (mCurrentView == mTodoView) view = "Todo"; + else if (mCurrentView == mTimelineView) view = "Timeline"; + else view = "Agenda"; + + config->writeEntry("Current View",view); + + if (mAgendaView) { + mAgendaView->writeSettings(config); + } + if (mListView) { + mListView->writeSettings(config); + } + if (mTodoView) { + mTodoView->saveLayout(config,"Todo View"); + } +} + +void KOViewManager::showView(KOrg::BaseView *view) +{ + if( view == mCurrentView ) return; + + mCurrentView = view; + + if ( mCurrentView && mCurrentView->isEventView() ) { + mLastEventView = mCurrentView; + } + + if ( mAgendaView ) mAgendaView->deleteSelectedDateTime(); + + raiseCurrentView(); + mMainView->processIncidenceSelection( 0 ); + + mMainView->updateView(); + + mMainView->adaptNavigationUnits(); +} + +void KOViewManager::raiseCurrentView() +{ + if ((mMonthView && KOPrefs::instance()->mFullViewMonth && mCurrentView == mMonthView) || + (mTodoView && KOPrefs::instance()->mFullViewTodo && mCurrentView == mTodoView)) { + mMainView->showLeftFrame( false ); + if ( mCurrentView == mTodoView ) { + mMainView->navigatorBar()->hide(); + } else { + mMainView->navigatorBar()->show(); + } + } else { + mMainView->showLeftFrame( true ); + mMainView->navigatorBar()->hide(); + } + mMainView->viewStack()->raiseWidget( widgetForView( mCurrentView ) ); +} + +void KOViewManager::updateView() +{ + if ( mCurrentView ) mCurrentView->updateView(); +} + +void KOViewManager::updateView(const QDate &start, const QDate &end) +{ +// kdDebug(5850) << "KOViewManager::updateView()" << endl; + + if (mCurrentView) mCurrentView->showDates(start, end); + + if (mTodoView) mTodoView->updateView(); +} + +void KOViewManager::connectView(KOrg::BaseView *view) +{ + if (!view) return; + + // selecting an incidence + connect( view, SIGNAL( incidenceSelected( Incidence * ) ), + mMainView, SLOT( processMainViewSelection( Incidence * ) ) ); + + // showing/editing/deleting an incidence. The calendar view takes care of the action. + connect(view, SIGNAL(showIncidenceSignal(Incidence *)), + mMainView, SLOT(showIncidence(Incidence *))); + connect(view, SIGNAL(editIncidenceSignal(Incidence *)), + mMainView, SLOT(editIncidence(Incidence *))); + connect(view, SIGNAL(deleteIncidenceSignal(Incidence *)), + mMainView, SLOT(deleteIncidence(Incidence *))); + connect(view, SIGNAL(copyIncidenceSignal(Incidence *)), + mMainView, SLOT(copyIncidence(Incidence *))); + connect(view, SIGNAL(cutIncidenceSignal(Incidence *)), + mMainView, SLOT(cutIncidence(Incidence *))); + connect(view, SIGNAL(pasteIncidenceSignal()), + mMainView, SLOT(pasteIncidence())); + connect(view, SIGNAL(toggleAlarmSignal(Incidence *)), + mMainView, SLOT(toggleAlarm(Incidence *))); + connect(view,SIGNAL(dissociateOccurrenceSignal( Incidence *, const QDate & )), + mMainView, SLOT(dissociateOccurrence( Incidence *, const QDate & ))); + connect(view,SIGNAL(dissociateFutureOccurrenceSignal( Incidence *, const QDate & )), + mMainView, SLOT(dissociateFutureOccurrence( Incidence *, const QDate & ))); + + // signals to create new incidences + connect( view, SIGNAL( newEventSignal() ), + mMainView, SLOT( newEvent() ) ); + connect( view, SIGNAL( newEventSignal( const QDateTime & ) ), + mMainView, SLOT( newEvent( const QDateTime & ) ) ); + connect( view, SIGNAL( newEventSignal( const QDateTime &, const QDateTime & ) ), + mMainView, SLOT( newEvent( const QDateTime &, const QDateTime & ) ) ); + connect( view, SIGNAL( newEventSignal( const QDate & ) ), + mMainView, SLOT( newEvent( const QDate & ) ) ); + connect( view, SIGNAL( newTodoSignal( const QDate & ) ), + mMainView, SLOT( newTodo( const QDate & ) ) ); + connect( view, SIGNAL( newSubTodoSignal( Todo * ) ), + mMainView, SLOT( newSubTodo( Todo *) ) ); + connect( view, SIGNAL( newJournalSignal( const QDate & ) ), + mMainView, SLOT( newJournal( const QDate & ) ) ); + + // reload settings + connect(mMainView, SIGNAL(configChanged()), view, SLOT(updateConfig())); + + // Notifications about added, changed and deleted incidences + connect( mMainView, SIGNAL( dayPassed( const QDate & ) ), + view, SLOT( dayPassed( const QDate & ) ) ); + connect( view, SIGNAL( startMultiModify( const QString & ) ), + mMainView, SLOT( startMultiModify( const QString & ) ) ); + connect( view, SIGNAL( endMultiModify() ), + mMainView, SLOT( endMultiModify() ) ); + + connect( mMainView, SIGNAL( newIncidenceChanger( IncidenceChangerBase* ) ), + view, SLOT( setIncidenceChanger( IncidenceChangerBase * ) ) ); + view->setIncidenceChanger( mMainView->incidenceChanger() ); +} + +void KOViewManager::connectTodoView( KOTodoView* todoView ) +{ + if (!todoView) return; + + // SIGNALS/SLOTS FOR TODO VIEW + connect( todoView, SIGNAL( purgeCompletedSignal() ), + mMainView, SLOT( purgeCompleted() ) ); + connect( todoView, SIGNAL( unSubTodoSignal() ), + mMainView, SLOT( todo_unsub() ) ); + connect( todoView, SIGNAL( unAllSubTodoSignal() ), + mMainView, SLOT( makeSubTodosIndependents() ) ); +} + +void KOViewManager::zoomInHorizontally() +{ + if( mAgendaView == mCurrentView ) mAgendaView->zoomInHorizontally(); +} +void KOViewManager::zoomOutHorizontally() +{ + if( mAgendaView== mCurrentView ) mAgendaView->zoomOutHorizontally(); +} +void KOViewManager::zoomInVertically() +{ + if( mAgendaView== mCurrentView ) mAgendaView->zoomInVertically(); +} +void KOViewManager::zoomOutVertically() +{ + if( mAgendaView== mCurrentView ) mAgendaView->zoomOutVertically(); +} + +void KOViewManager::addView(KOrg::BaseView *view) +{ + connectView( view ); +#if QT_VERSION >= 300 + mMainView->viewStack()->addWidget( view ); +#else + mMainView->viewStack()->addWidget( view, 1 ); +#endif +} + +void KOViewManager::showWhatsNextView() +{ + if (!mWhatsNextView) { + mWhatsNextView = new KOWhatsNextView(mMainView->calendar(),mMainView->viewStack(), + "KOViewManager::WhatsNextView"); + addView(mWhatsNextView); + } + showView(mWhatsNextView); +} + +void KOViewManager::showListView() +{ + if (!mListView) { + mListView = new KOListView(mMainView->calendar(), mMainView->viewStack(), "KOViewManager::ListView"); + addView(mListView); + } + 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; + + QWidget *parent = mMainView->viewStack(); + if ( !mAgendaViewTabs && showBoth ) { + mAgendaViewTabs = new QTabWidget( mMainView->viewStack() ); + connect( mAgendaViewTabs, SIGNAL( currentChanged( QWidget* ) ), + this, SLOT( currentAgendaViewTabChanged( QWidget* ) ) ); + parent = mAgendaViewTabs; + } + + if ( !mAgendaView && showMerged ) { + mAgendaView = new KOAgendaView(mMainView->calendar(), parent, "KOViewManager::AgendaView"); + + addView(mAgendaView); + + connect(mAgendaView, SIGNAL( toggleExpand() ), + mMainView, SLOT( toggleExpand() ) ); + connect(mMainView, SIGNAL( calendarViewExpanded( bool ) ), + mAgendaView, SLOT( setExpandedButton( bool ) ) ); + + connect( mAgendaView,SIGNAL( zoomViewHorizontally(const QDate &, int )), + mMainView->dateNavigator(),SLOT( selectDates( const QDate &, int ) ) ); + mAgendaView->readSettings(); + } + + if ( !mAgendaSideBySideView && showSideBySide ) { + mAgendaSideBySideView = + new MultiAgendaView( mMainView->calendar(), parent, + "KOViewManager::AgendaSideBySideView" ); + + addView(mAgendaSideBySideView); + +/* connect(mAgendaSideBySideView, SIGNAL( toggleExpand() ), + mMainView, SLOT( toggleExpand() ) ); + connect(mMainView, SIGNAL( calendarViewExpanded( bool ) ), + mAgendaSideBySideView, SLOT( setExpandedButton( bool ) ) ); + + connect( mAgendaSideBySideView,SIGNAL( zoomViewHorizontally(const QDate &, int )), + mMainView->dateNavigator(),SLOT( selectDates( const QDate &, int ) ) );*/ + } + + if ( showBoth && mAgendaViewTabs ) { + if ( mAgendaView && mAgendaViewTabs->indexOf( mAgendaView ) < 0 ) + mAgendaViewTabs->addTab( mAgendaView, i18n("Merged calendar") ); + if ( mAgendaSideBySideView && mAgendaViewTabs->indexOf( mAgendaSideBySideView ) < 0 ) + mAgendaViewTabs->addTab( mAgendaSideBySideView, i18n("Calendars Side by Side") ); + } else { + if ( mAgendaView && mMainView->viewStack()->id( mAgendaView ) < 0 ) + mMainView->viewStack()->addWidget( mAgendaView ); + if ( mAgendaSideBySideView && mMainView->viewStack()->id( mAgendaSideBySideView ) < 0 ) + mMainView->viewStack()->addWidget( mAgendaSideBySideView ); + } + + if ( mAgendaViewTabs && showBoth ) + showView( static_cast<KOrg::BaseView*>( mAgendaViewTabs->currentPage() ) ); + else if ( mAgendaView && showMerged ) + showView( mAgendaView ); + else if ( mAgendaSideBySideView && showSideBySide ) + showView( mAgendaSideBySideView ); +} + +void KOViewManager::showDayView() +{ + showAgendaView(); + mMainView->dateNavigator()->selectDates( 1 ); +} + +void KOViewManager::showWorkWeekView() +{ + showAgendaView(); + mMainView->dateNavigator()->selectWorkWeek(); +} + +void KOViewManager::showWeekView() +{ + showAgendaView(); + mMainView->dateNavigator()->selectWeek(); +} + +void KOViewManager::showNextXView() +{ + showAgendaView(); + mMainView->dateNavigator()->selectDates( QDate::currentDate(), + KOPrefs::instance()->mNextXDays ); +} + +void KOViewManager::showMonthView() +{ + if (!mMonthView) { + mMonthView = new KOMonthView(mMainView->calendar(), mMainView->viewStack(), "KOViewManager::MonthView"); + addView(mMonthView); + } + + showView(mMonthView); +} + +void KOViewManager::showTodoView() +{ + if ( !mTodoView ) { + mTodoView = new KOTodoView( mMainView->calendar(), mMainView->viewStack(), + "KOViewManager::TodoView" ); + mTodoView->setCalendar( mMainView->calendar() ); + addView( mTodoView ); + connectTodoView( mTodoView ); + + KConfig *config = KOGlobals::self()->config(); + mTodoView->restoreLayout( config, "Todo View" ); + } + + showView( mTodoView ); +} + +void KOViewManager::showJournalView() +{ + if (!mJournalView) { + mJournalView = new KOJournalView(mMainView->calendar(),mMainView->viewStack(), + "KOViewManager::JournalView"); + addView(mJournalView); + } + + showView(mJournalView); +} + + +void KOViewManager::showTimelineView() +{ + if (!mTimelineView) { + mTimelineView = new KOTimelineView(mMainView->calendar(),mMainView->viewStack(), + "KOViewManager::TimelineView"); + addView(mTimelineView); + } + showView(mTimelineView); +} + +void KOViewManager::showEventView() +{ + if ( mLastEventView ) showView( mLastEventView ); + else showWeekView(); +} + +Incidence *KOViewManager::currentSelection() +{ + if ( !mCurrentView ) return 0; + Incidence::List incidenceList = mCurrentView->selectedIncidences(); + if ( incidenceList.isEmpty() ) return 0; + + return incidenceList.first(); +} + +QDate KOViewManager::currentSelectionDate() +{ + QDate qd; + if (mCurrentView) { + DateList qvl = mCurrentView->selectedDates(); + if (!qvl.isEmpty()) qd = qvl.first(); + } + return qd; +} + +void KOViewManager::setDocumentId( const QString &id ) +{ + if (mTodoView) mTodoView->setDocumentId( id ); +} + + +QWidget* KOViewManager::widgetForView( KOrg::BaseView* view ) const +{ + const bool showBoth = KOPrefs::instance()->agendaViewCalendarDisplay() == KOPrefs::AllCalendarViews; + if ( (view == mAgendaView || view == mAgendaSideBySideView) && mAgendaViewTabs && showBoth ) { + return mAgendaViewTabs; + } + return view; +} + + +void KOViewManager::currentAgendaViewTabChanged( QWidget* widget ) +{ + showView( static_cast<KOrg::BaseView*>( widget ) ); +} + +void KOViewManager::resourcesChanged() +{ + if ( mAgendaView ) + mAgendaView->resourcesChanged(); + if ( mAgendaSideBySideView ) + mAgendaSideBySideView->resourcesChanged(); +} diff --git a/korganizer/koviewmanager.h b/korganizer/koviewmanager.h new file mode 100644 index 000000000..4a401d189 --- /dev/null +++ b/korganizer/koviewmanager.h @@ -0,0 +1,134 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOVIEWMANAGER_H +#define KOVIEWMANAGER_H + +#include <qobject.h> +class QWidget; +class QTabWidget; + +class CalendarView; + +class KOListView; +class KOAgendaView; +class KOMonthView; +class KOTodoView; +class KOWhatsNextView; +class KOJournalView; +class KOTimelineView; + +namespace KOrg { + class BaseView; + class MultiAgendaView; +} +using namespace KCal; + +/** + This class manages the views of the calendar. It owns the objects and handles + creation and selection. +*/ +class KOViewManager : public QObject +{ + Q_OBJECT + public: + KOViewManager( CalendarView * ); + virtual ~KOViewManager(); + + /** changes the view to be the currently selected view */ + void showView( KOrg::BaseView * ); + + void readSettings( KConfig *config ); + void writeSettings( KConfig *config ); + + /** Read which view was shown last from config file */ + void readCurrentView( KConfig * ); + /** Write which view is currently shown to config file */ + void writeCurrentView( KConfig * ); + + KOrg::BaseView *currentView(); + + void setDocumentId( const QString & ); + + void updateView(); + void updateView( const QDate &start, const QDate &end ); + + void raiseCurrentView(); + + void connectView( KOrg::BaseView * ); + void addView( KOrg::BaseView * ); + + Incidence *currentSelection(); + QDate currentSelectionDate(); + + KOAgendaView *agendaView() const { return mAgendaView; } + KOrg::MultiAgendaView *multiAgendaView() const { return mAgendaSideBySideView; } + KOTodoView *todoView() const { return mTodoView; } + + public slots: + void showWhatsNextView(); + void showListView(); + void showAgendaView(); + void showDayView(); + void showWorkWeekView(); + void showWeekView(); + void showNextXView(); + void showMonthView(); + void showTodoView(); + void showTimelineView(); + void showJournalView(); + + void showEventView(); + + void connectTodoView( KOTodoView *todoView ); + + void zoomInHorizontally(); + void zoomOutHorizontally(); + void zoomInVertically(); + void zoomOutVertically(); + + void resourcesChanged(); + + private slots: + void currentAgendaViewTabChanged( QWidget* ); + private: + QWidget* widgetForView( KOrg::BaseView* ) const; + CalendarView *mMainView; + + KOAgendaView *mAgendaView; + MultiAgendaView *mAgendaSideBySideView; + KOListView *mListView; + KOMonthView *mMonthView; + KOTodoView *mTodoView; + KOWhatsNextView *mWhatsNextView; + KOJournalView *mJournalView; + KOTimelineView *mTimelineView; + + KOrg::BaseView *mCurrentView; + + KOrg::BaseView *mLastEventView; + QTabWidget *mAgendaViewTabs; +}; + +#endif diff --git a/korganizer/kowhatsnextview.cpp b/korganizer/kowhatsnextview.cpp new file mode 100644 index 000000000..d4b6618aa --- /dev/null +++ b/korganizer/kowhatsnextview.cpp @@ -0,0 +1,335 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qlayout.h> +#include <qtextbrowser.h> +#include <qtextcodec.h> +#include <qfileinfo.h> +#include <qlabel.h> + +#include <kglobal.h> +#include <klocale.h> +#include <kdebug.h> +#include <kiconloader.h> +#include <kmessagebox.h> + +#include <libkcal/calendar.h> + +#include "koglobals.h" +#include "koprefs.h" +#include "koeventviewerdialog.h" + +#include "kowhatsnextview.h" + +using namespace KOrg; + +void WhatsNextTextBrowser::setSource(const QString& n) +{ + kdDebug(5850) << "WhatsNextTextBrowser::setSource(): " << n << endl; + + if (n.startsWith("event:")) { + emit showIncidence(n); + return; + } else if (n.startsWith("todo:")) { + emit showIncidence(n); + return; + } else { + QTextBrowser::setSource(n); + } +} + +KOWhatsNextView::KOWhatsNextView(Calendar *calendar, QWidget *parent, + const char *name) + : KOrg::BaseView(calendar, parent, name) +{ +// QLabel *dateLabel = +// new QLabel(KGlobal::locale()->formatDate(QDate::currentDate()),this); +// dateLabel->setMargin(2); +// dateLabel->setAlignment(AlignCenter); + + mView = new WhatsNextTextBrowser(this); + connect(mView,SIGNAL(showIncidence(const QString &)),SLOT(showIncidence(const QString &))); + + QBoxLayout *topLayout = new QVBoxLayout(this); +// topLayout->addWidget(dateLabel); + topLayout->addWidget(mView); +} + +KOWhatsNextView::~KOWhatsNextView() +{ +} + +int KOWhatsNextView::currentDateCount() +{ + return mStartDate.daysTo( mEndDate ); +} + +void KOWhatsNextView::updateView() +{ + KIconLoader kil("kdepim"); + QString *ipath = new QString(); + kil.loadIcon("kdepim",KIcon::NoGroup,32,KIcon::DefaultState,ipath); + + mText = "<table width=\"100%\">\n"; + mText += "<tr bgcolor=\"#3679AD\"><td><h1>"; + mText += "<img src=\""; + mText += *ipath; + mText += "\">"; + mText += "<font color=\"white\"> "; + mText += i18n("What's Next?") + "</font></h1>"; + mText += "</td></tr>\n<tr><td>"; + + mText += "<h2>"; + if ( mStartDate.daysTo( mEndDate ) < 1 ) { + mText += KGlobal::locale()->formatDate( mStartDate ); + } else { + mText += i18n("Date from - to", "%1 - %2") + .arg( KGlobal::locale()->formatDate( mStartDate ) ) + .arg( KGlobal::locale()->formatDate( mEndDate ) ); + } + mText+="</h2>\n"; + + Event::List events; + for ( QDate date = mStartDate; date <= mEndDate; date = date.addDays( 1 ) ) + events += calendar()->events(date, EventSortStartDate, SortDirectionAscending); + + if (events.count() > 0) { + mText += "<p></p>"; + kil.loadIcon("appointment",KIcon::NoGroup,22,KIcon::DefaultState,ipath); + mText += "<h2><img src=\""; + mText += *ipath; + mText += "\">"; + mText += i18n("Events:") + "</h2>\n"; + mText += "<table>\n"; + Event::List::ConstIterator it; + for( it = events.begin(); it != events.end(); ++it ) { + Event *ev = *it; + if ( !ev->doesRecur() ){ + appendEvent(ev); + } else { + // FIXME: This should actually be cleaned up. Libkcal should + // provide a method to return a list of all recurrences in a + // given time span. + Recurrence *recur = ev->recurrence(); + int duration = ev->dtStart().secsTo( ev->dtEnd() ); + QDateTime start = recur->getPreviousDateTime( + QDateTime( mStartDate, QTime() ) ); + QDateTime end = start.addSecs( duration ); + if ( end.date() >= mStartDate ) { + appendEvent( ev, start, end ); + } + start = recur->getNextDateTime( start ); + while ( start.isValid() && start.date() <= mEndDate ) { + appendEvent( ev, start ); + start = recur->getNextDateTime( start ); + } + } + } + mText += "</table>\n"; + } + + mTodos.clear(); + Todo::List todos = calendar()->todos( TodoSortDueDate, SortDirectionAscending ); + if ( todos.count() > 0 ) { + kil.loadIcon("todo",KIcon::NoGroup,22,KIcon::DefaultState,ipath); + mText += "<h2><img src=\""; + mText += *ipath; + mText += "\">"; + mText += i18n("To-do:") + "</h2>\n"; + mText += "<ul>\n"; + Todo::List::ConstIterator it; + for( it = todos.begin(); it != todos.end(); ++it ) { + Todo *todo = *it; + if ( !todo->isCompleted() && todo->hasDueDate() && todo->dtDue().date() <= mEndDate ) + appendTodo(todo); + } + bool gotone = false; + int priority = 1; + while (!gotone && priority<=9 ) { + for( it = todos.begin(); it != todos.end(); ++it ) { + Todo *todo = *it; + if (!todo->isCompleted() && (todo->priority() == priority) ) { + appendTodo(todo); + gotone = true; + } + } + priority++; + kdDebug(5850) << "adding the todos..." << endl; + } + mText += "</ul>\n"; + } + + QStringList myEmails( KOPrefs::instance()->allEmails() ); + int replies = 0; + events = calendar()->events( QDate::currentDate(), QDate(2975,12,6) ); + Event::List::ConstIterator it2; + for( it2 = events.begin(); it2 != events.end(); ++it2 ) { + Event *ev = *it2; + Attendee *me = ev->attendeeByMails( myEmails ); + if (me!=0) { + if (me->status()==Attendee::NeedsAction && me->RSVP()) { + if (replies == 0) { + mText += "<p></p>"; + kil.loadIcon("reply",KIcon::NoGroup,22,KIcon::DefaultState,ipath); + mText += "<h2><img src=\""; + mText += *ipath; + mText += "\">"; + mText += i18n("Events and to-dos that need a reply:") + "</h2>\n"; + mText += "<table>\n"; + } + replies++; + appendEvent( ev ); + } + } + } + todos = calendar()->todos(); + Todo::List::ConstIterator it3; + for( it3 = todos.begin(); it3 != todos.end(); ++it3 ) { + Todo *to = *it3; + Attendee *me = to->attendeeByMails( myEmails ); + if (me!=0) { + if (me->status()==Attendee::NeedsAction && me->RSVP()) { + if (replies == 0) { + mText += "<p></p>"; + kil.loadIcon("reply",KIcon::NoGroup,22,KIcon::DefaultState,ipath); + mText += "<h2><img src=\""; + mText += *ipath; + mText += "\">"; + mText += i18n("Events and to-dos that need a reply:") + "</h2>\n"; + mText += "<table>\n"; + } + replies++; + appendEvent(to); + } + } + kdDebug () << "check for todo-replies..." << endl; + } + if (replies > 0 ) mText += "</table>\n"; + + + mText += "</td></tr>\n</table>\n"; + + kdDebug(5850) << "KOWhatsNextView::updateView: text: " << mText << endl; + + delete ipath; + + mView->setText(mText); +} + +void KOWhatsNextView::showDates( const QDate &start, const QDate &end ) +{ + mStartDate = start; + mEndDate = end; + updateView(); +} + +void KOWhatsNextView::showIncidences( const Incidence::List & ) +{ +} + +void KOWhatsNextView::changeIncidenceDisplay(Incidence *, int action) +{ + switch(action) { + case KOGlobals::INCIDENCEADDED: + case KOGlobals::INCIDENCEEDITED: + case KOGlobals::INCIDENCEDELETED: + updateView(); + break; + default: + kdDebug(5850) << "KOWhatsNextView::changeIncidenceDisplay(): Illegal action " << action << endl; + } +} + +void KOWhatsNextView::appendEvent( Incidence *ev, const QDateTime &start, + const QDateTime &end ) +{ + kdDebug(5850) << "KOWhatsNextView::appendEvent(): " << ev->uid() << endl; + + mText += "<tr><td><b>"; +// if (!ev->doesFloat()) { + if (ev->type()=="Event") { + Event *event = static_cast<Event *>(ev); + QDateTime starttime( start ); + if ( !starttime.isValid() ) + starttime = event->dtStart(); + QDateTime endtime( end ); + if ( !endtime.isValid() ) + endtime = starttime.addSecs( + event->dtStart().secsTo( event->dtEnd() ) ); + + if ( starttime.date().daysTo( endtime.date() ) >= 1 ) { + mText += i18n("date from - to", "%1 - %2") + .arg( KGlobal::locale()->formatDateTime( starttime ) ) + .arg( KGlobal::locale()->formatDateTime( endtime ) ); + } else { + /*if (reply) */ + mText += i18n("date, from - to", "%1, %2 - %3") + .arg( KGlobal::locale()->formatDate( starttime.date(), true ) ) + .arg( KGlobal::locale()->formatTime( starttime.time() ) ) + .arg( KGlobal::locale()->formatTime( endtime.time() ) ); + } + } +// } + mText += "</b></td><td><a "; + if (ev->type()=="Event") mText += "href=\"event:"; + if (ev->type()=="Todo") mText += "href=\"todo:"; + mText += ev->uid() + "\">"; + mText += ev->summary(); + mText += "</a></td></tr>\n"; +} + +void KOWhatsNextView::appendTodo( Incidence *ev ) +{ + if ( mTodos.find( ev ) != mTodos.end() ) return; + + mTodos.append( ev ); + + mText += "<li><a href=\"todo:" + ev->uid() + "\">"; + mText += ev->summary(); + mText += "</a>"; + + 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 += "</li>\n"; +} + +void KOWhatsNextView::showIncidence( const QString &uid ) +{ + kdDebug(5850) << "KOWhatsNextView::showIncidence(): " << uid << endl; + Incidence *incidence = 0; + + if ( uid.startsWith( "event://" ) ) { + incidence = calendar()->incidence( uid.mid( 8 ) ); + } else if ( uid.startsWith( "todo://" ) ) { + incidence = calendar()->incidence( uid.mid( 7 ) ); + } + if ( incidence ) emit showIncidenceSignal( incidence ); +} + +#include "kowhatsnextview.moc" diff --git a/korganizer/kowhatsnextview.h b/korganizer/kowhatsnextview.h new file mode 100644 index 000000000..7632fd028 --- /dev/null +++ b/korganizer/kowhatsnextview.h @@ -0,0 +1,86 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOWHATSNEXTVIEW_H +#define KOWHATSNEXTVIEW_H + +#include <qtextbrowser.h> + +#include <korganizer/baseview.h> + +class QListView; + +class KOEventViewerDialog; + +class WhatsNextTextBrowser : public QTextBrowser { + Q_OBJECT + public: + WhatsNextTextBrowser(QWidget *parent) : QTextBrowser(parent) {} + + void setSource(const QString &); + + signals: + void showIncidence(const QString &uid); +}; + + +/** + This class provides a view of the next events and todos +*/ +class KOWhatsNextView : public KOrg::BaseView +{ + Q_OBJECT + public: + KOWhatsNextView(Calendar *calendar, QWidget *parent = 0, + const char *name = 0); + ~KOWhatsNextView(); + + virtual int currentDateCount(); + virtual Incidence::List selectedIncidences() { return Incidence::List(); } + DateList selectedDates() { return DateList(); } + + public slots: + virtual void updateView(); + virtual void showDates(const QDate &start, const QDate &end); + virtual void showIncidences( const Incidence::List &incidenceList ); + + void changeIncidenceDisplay(Incidence *, int); + + protected: + void appendEvent( Incidence *, const QDateTime &start = QDateTime(), + const QDateTime &end = QDateTime() ); + void appendTodo( Incidence * ); + + private slots: + void showIncidence(const QString &); + + private: + QTextBrowser *mView; + QString mText; + QDate mStartDate; + QDate mEndDate; + + Incidence::List mTodos; +}; + +#endif diff --git a/korganizer/kowindowlist.cpp b/korganizer/kowindowlist.cpp new file mode 100644 index 000000000..8af857cb4 --- /dev/null +++ b/korganizer/kowindowlist.cpp @@ -0,0 +1,72 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2000,2003 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <kdebug.h> + +#include "actionmanager.h" +#include "kowindowlist.h" +#include "kowindowlist.moc" + +KOWindowList::KOWindowList( const char *name ) + : QObject( 0, name ), mDefaultWindow( 0 ) +{ +// kdDebug(5850) << "KOWindowList::KOWindowList()" << endl; +} + +KOWindowList::~KOWindowList() +{ +} + +void KOWindowList::addWindow( KOrg::MainWindow *korg ) +{ + if ( !korg->hasDocument() ) mDefaultWindow = korg; + else mWindowList.append( korg ); +} + +void KOWindowList::removeWindow( KOrg::MainWindow *korg ) +{ + if ( korg == mDefaultWindow ) mDefaultWindow = 0; + else mWindowList.removeRef( korg ); +} + +bool KOWindowList::lastInstance() +{ + if ( mWindowList.count() == 1 && !mDefaultWindow ) return true; + if ( mWindowList.count() == 0 && mDefaultWindow ) return true; + else return false; +} + +KOrg::MainWindow *KOWindowList::findInstance( const KURL &url ) +{ + KOrg::MainWindow *inst; + for( inst = mWindowList.first(); inst; inst = mWindowList.next() ) + if ( inst->getCurrentURL() == url ) + return inst; + return 0; +} + +KOrg::MainWindow *KOWindowList::defaultInstance() +{ + return mDefaultWindow; +} diff --git a/korganizer/kowindowlist.h b/korganizer/kowindowlist.h new file mode 100644 index 000000000..b8fc3190f --- /dev/null +++ b/korganizer/kowindowlist.h @@ -0,0 +1,86 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2000,2003 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOWINDOWLIST_H +#define KOWINDOWLIST_H + +#include <qobject.h> + +namespace KOrg { +class MainWindow; +} + +class KURL; + +/** + This class manages a list of KOrganizer instances, each associated with a + window displaying a calendar. It acts as relay for signals between this + windows and manages information, which requires interaction of all instances. + + @short manages a list of all KOrganizer instances + @author Cornelius Schumacher +*/ +class KOWindowList : public QObject +{ + Q_OBJECT + public: + /** + Constructs a new list of KOrganizer windows. There should only be one + instance of this class. The ActionManager class takes care of this. + */ + KOWindowList( const char *name = 0 ); + virtual ~KOWindowList(); + + /** + Is there only one instance left? + */ + bool lastInstance(); + + /** + Is there a instance with this URL? + */ + KOrg::MainWindow *findInstance( const KURL &url ); + + /** + Return default instance. This is the main window for the resource based + calendar. + */ + KOrg::MainWindow *defaultInstance(); + + public slots: + /** + Register a main window. + */ + void addWindow( KOrg::MainWindow * ); + /** + Unregister a main window. + */ + void removeWindow( KOrg::MainWindow * ); + + private: + QPtrList<KOrg::MainWindow> mWindowList; // list of all existing KOrganizer instances + + KOrg::MainWindow *mDefaultWindow; +}; + +#endif diff --git a/korganizer/mailscheduler.cpp b/korganizer/mailscheduler.cpp new file mode 100644 index 000000000..bbd3daee5 --- /dev/null +++ b/korganizer/mailscheduler.cpp @@ -0,0 +1,192 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qdir.h> +#include <qfile.h> +#include <qregexp.h> + +#include <klocale.h> +#include <kstandarddirs.h> +#include <kdebug.h> + +#include <libkcal/calendar.h> +#include <libkcal/event.h> +#include <libkcal/icalformat.h> + +#include "komailclient.h" +#include "incidencechanger.h" + +#include "mailscheduler.h" + + +using namespace KCal; + +MailScheduler::MailScheduler( Calendar *calendar ) + : IMIPScheduler( calendar ) +{ +} + +MailScheduler::~MailScheduler() +{ +} + +bool MailScheduler::publish( IncidenceBase *incidence, + const QString &recipients ) +{ + QString messageText = mFormat->createScheduleMessage( incidence, + Scheduler::Publish ); + KOMailClient mailer; + return mailer.mailTo( incidence, recipients, messageText ); +} + +bool MailScheduler::performTransaction( IncidenceBase *incidence, + Method method, + const QString &recipients ) +{ + QString messageText = mFormat->createScheduleMessage( incidence, method ); + + KOMailClient mailer; + return mailer.mailTo( incidence, recipients, messageText ); +} + +bool MailScheduler::performTransaction( IncidenceBase *incidence, + Method method ) +{ + QString messageText = mFormat->createScheduleMessage( incidence, method ); + + KOMailClient mailer; + bool status; + if ( method == Request || + method == Cancel || + method == Add || + method == Declinecounter ) { + status = mailer.mailAttendees( incidence, messageText ); + } else { + QString subject; + Incidence *inc = dynamic_cast<Incidence*>( incidence ); + if ( inc && method == Counter ) + subject = i18n( "Counter proposal: %1" ).arg( inc->summary() ); + status = mailer.mailOrganizer( incidence, messageText, subject ); + } + return status; +} + +QPtrList<ScheduleMessage> MailScheduler::retrieveTransactions() +{ + QString incomingDirName = locateLocal( "data", "korganizer/income" ); + kdDebug(5850) << "MailScheduler::retrieveTransactions: dir: " + << incomingDirName << endl; + + QPtrList<ScheduleMessage> messageList; + + QDir incomingDir( incomingDirName ); + QStringList incoming = incomingDir.entryList( QDir::Files ); + QStringList::ConstIterator it; + for( it = incoming.begin(); it != incoming.end(); ++it ) { + kdDebug(5850) << "-- File: " << (*it) << endl; + + QFile f( incomingDirName + "/" + (*it) ); + bool inserted = false; + QMap<IncidenceBase*, QString>::Iterator iter; + for ( iter = mEventMap.begin(); iter != mEventMap.end(); ++iter ) { + if ( iter.data() == incomingDirName + "/" + (*it) ) + inserted = true; + } + if ( !inserted ) { + if ( !f.open( IO_ReadOnly ) ) { + kdDebug(5850) + << "MailScheduler::retrieveTransactions(): Can't open file'" + << (*it) << "'" << endl; + } else { + QTextStream t( &f ); + t.setEncoding( QTextStream::Latin1 ); + QString messageString = t.read(); + messageString.replace( QRegExp( "\n[ \t]"), "" ); + messageString = QString::fromUtf8( messageString.latin1() ); + ScheduleMessage *mess = mFormat->parseScheduleMessage( mCalendar, + messageString ); + if ( mess) { + kdDebug(5850) + << "MailScheduler::retrieveTransactions: got message '" + << (*it) << "'" << endl; + messageList.append( mess ); + mEventMap[ mess->event() ] = incomingDirName + "/" + (*it); + } else { + QString errorMessage; + if ( mFormat->exception() ) { + errorMessage = mFormat->exception()->message(); + } + kdDebug(5850) + << "MailScheduler::retrieveTransactions() Error parsing message: " + << errorMessage << endl; + } + f.close(); + } + } + } + return messageList; +} + +bool MailScheduler::deleteTransaction( IncidenceBase *incidence ) +{ + bool status; + QFile f( mEventMap[incidence] ); + mEventMap.remove( incidence ); + if ( !f.exists() ) { + status = false; + } else { + status = f.remove(); + } + return status; +} + +QString MailScheduler::freeBusyDir() +{ + return locateLocal( "data", "korganizer/freebusy" ); +} + +bool MailScheduler::acceptCounterProposal( Incidence *incidence ) +{ + if ( !incidence ) + return false; + + Incidence *exInc = mCalendar->incidence( incidence->uid() ); + if ( !exInc ) + exInc = mCalendar->incidenceFromSchedulingID( incidence->uid() ); + incidence->setRevision( incidence->revision() + 1 ); + if ( exInc ) { + incidence->setRevision( QMAX( incidence->revision(), exInc->revision() + 1 ) ); + // some stuff we don't want to change, just to be safe + incidence->setSchedulingID( exInc->schedulingID() ); + incidence->setUid( exInc->uid() ); + + mCalendar->beginChange( exInc ); + IncidenceChanger::assignIncidence( exInc, incidence ); + exInc->updated(); + mCalendar->endChange( exInc ); + } else { + mCalendar->addIncidence( incidence ); + } + return true; +} diff --git a/korganizer/mailscheduler.h b/korganizer/mailscheduler.h new file mode 100644 index 000000000..50a60dcff --- /dev/null +++ b/korganizer/mailscheduler.h @@ -0,0 +1,65 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001,2004 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef MAILSCHEDULER_H +#define MAILSCHEDULER_H + +#include <qptrlist.h> +#include <qmap.h> +#include <qstring.h> + +#include <libkcal/imipscheduler.h> + +namespace KCal { + +/* + This class implements the iTIP interface using the email interface specified + as Mail. +*/ +class MailScheduler : public IMIPScheduler +{ + public: + MailScheduler( Calendar * ); + virtual ~MailScheduler(); + + bool publish ( IncidenceBase *incidence, const QString &recipients ); + bool performTransaction( IncidenceBase *incidence, Method method ); + bool performTransaction( IncidenceBase *incidence, Method method, + const QString &recipients ); + QPtrList<ScheduleMessage> retrieveTransactions(); + + bool deleteTransaction( IncidenceBase *incidence ); + + /** Returns the directory where the free-busy information is stored */ + virtual QString freeBusyDir(); + + /** Accepts a counter proposal */ + bool acceptCounterProposal( Incidence *incidence ); + + private: + QMap<IncidenceBase *, QString> mEventMap; +}; + +} + +#endif diff --git a/korganizer/main.cpp b/korganizer/main.cpp new file mode 100644 index 000000000..997956447 --- /dev/null +++ b/korganizer/main.cpp @@ -0,0 +1,59 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1997-1999 Preston Brown <pbrown@kde.org> + Copyright (c) 2001,2003 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "koapp.h" +#include "aboutdata.h" + +#include <kglobal.h> +#include <kdebug.h> +#include <kaboutdata.h> +#include <kcmdlineargs.h> +#include <klocale.h> + +#include "korganizer.h" +#include "korganizer_options.h" + +int main ( int argc, char **argv ) +{ + KOrg::AboutData aboutData; + + KCmdLineArgs::init( argc, argv, &aboutData ); + KCmdLineArgs::addCmdLineOptions( korganizer_options ); + KUniqueApplication::addCmdLineOptions(); + + if ( !KOrganizerApp::start() ) return 0; + + KOrganizerApp app; + + KGlobal::locale()->insertCatalogue( "libkcal" ); + KGlobal::locale()->insertCatalogue( "libkdepim" ); + KGlobal::locale()->insertCatalogue( "kdgantt" ); + + if ( app.isRestored() ) { + RESTORE( KOrganizer ) + } + + return app.exec(); +} diff --git a/korganizer/makechangelog b/korganizer/makechangelog new file mode 100755 index 000000000..624d505a0 --- /dev/null +++ b/korganizer/makechangelog @@ -0,0 +1,7 @@ +#!/bin/sh +# Generate ChangeLog file. +# +# This does not work as expected. Fix it before creating a ChangeLog for the +# next time. + +rcs2log -i 4 -R | fmt > ChangeLog diff --git a/korganizer/multiagendaview.cpp b/korganizer/multiagendaview.cpp new file mode 100644 index 000000000..e2a7281e8 --- /dev/null +++ b/korganizer/multiagendaview.cpp @@ -0,0 +1,484 @@ +/* + 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 "multiagendaview.h" + +#include "koagendaview.h" +#include "koagenda.h" +#include "koprefs.h" +#include "timelabels.h" + +#include <libkcal/calendarresources.h> + +#include <kglobalsettings.h> + +#include <qlayout.h> +#include <qvbox.h> +#include <qobjectlist.h> + +#define FOREACH_VIEW(av) \ +for(QValueList<KOAgendaView*>::ConstIterator it = mAgendaViews.constBegin(); \ + it != mAgendaViews.constEnd();) \ + for(KOAgendaView* av = (it != mAgendaViews.constEnd() ? (*it) : 0); \ + it != mAgendaViews.constEnd(); ++it, av = (*it) ) + +using namespace KOrg; + +MultiAgendaView::MultiAgendaView(Calendar * cal, QWidget * parent, const char *name ) : + AgendaView( cal, parent, name ), + mLastMovedSplitter( 0 ), + mUpdateOnShow( false ), + mPendingChanges( true ) +{ + QBoxLayout *topLevelLayout = new QHBoxLayout( this ); + + QFontMetrics fm( font() ); + int topLabelHeight = 2 * fm.height(); + + QVBox *topSideBox = new QVBox( this ); + QWidget *topSideSpacer = new QWidget( topSideBox ); + topSideSpacer->setFixedHeight( topLabelHeight ); + mLeftSplitter = new QSplitter( Qt::Vertical, topSideBox ); + mLeftSplitter->setOpaqueResize( KGlobalSettings::opaqueResize() ); + QLabel *label = new QLabel( i18n("All Day"), mLeftSplitter ); + label->setAlignment( Qt::AlignRight | Qt::AlignVCenter | Qt::WordBreak ); + QVBox *sideBox = new QVBox( mLeftSplitter ); + EventIndicator *eiSpacer = new EventIndicator( EventIndicator::Top, sideBox ); + eiSpacer->changeColumns( 0 ); + mTimeLabels = new TimeLabels( 24, sideBox ); + eiSpacer = new EventIndicator( EventIndicator::Bottom, sideBox ); + eiSpacer->changeColumns( 0 ); + mLeftBottomSpacer = new QWidget( topSideBox ); + topLevelLayout->addWidget( topSideBox ); + + mScrollView = new QScrollView( this ); + mScrollView->setResizePolicy( QScrollView::Manual ); + mScrollView->setVScrollBarMode( QScrollView::AlwaysOff ); + mScrollView->setFrameShape( QFrame::NoFrame ); + topLevelLayout->addWidget( mScrollView, 100 ); + mTopBox = new QHBox( mScrollView->viewport() ); + mScrollView->addChild( mTopBox ); + + topSideBox = new QVBox( this ); + topSideSpacer = new QWidget( topSideBox ); + topSideSpacer->setFixedHeight( topLabelHeight ); + mRightSplitter = new QSplitter( Qt::Vertical, topSideBox ); + mRightSplitter->setOpaqueResize( KGlobalSettings::opaqueResize() ); + new QWidget( mRightSplitter ); + sideBox = new QVBox( mRightSplitter ); + eiSpacer = new EventIndicator( EventIndicator::Top, sideBox ); + eiSpacer->setFixedHeight( eiSpacer->minimumHeight() ); + eiSpacer->changeColumns( 0 ); + mScrollBar = new QScrollBar( Qt::Vertical, sideBox ); + eiSpacer = new EventIndicator( EventIndicator::Bottom, sideBox ); + eiSpacer->setFixedHeight( eiSpacer->minimumHeight() ); + eiSpacer->changeColumns( 0 ); + mRightBottomSpacer = new QWidget( topSideBox ); + topLevelLayout->addWidget( topSideBox ); + + recreateViews(); +} + +void MultiAgendaView::recreateViews() +{ + if ( !mPendingChanges ) + return; + mPendingChanges = false; + + deleteViews(); + + CalendarResources *calres = dynamic_cast<CalendarResources*>( calendar() ); + if ( !calres ) { + // fallback to single-agenda + KOAgendaView* av = new KOAgendaView( calendar(), mTopBox ); + mAgendaViews.append( av ); + mAgendaWidgets.append( av ); + av->show(); + } else { + CalendarResourceManager *manager = calres->resourceManager(); + for ( CalendarResourceManager::ActiveIterator it = manager->activeBegin(); it != manager->activeEnd(); ++it ) { + if ( (*it)->canHaveSubresources() ) { + QStringList subResources = (*it)->subresources(); + for ( QStringList::ConstIterator subit = subResources.constBegin(); subit != subResources.constEnd(); ++subit ) { + QString type = (*it)->subresourceType( *subit ); + if ( !(*it)->subresourceActive( *subit ) || (!type.isEmpty() && type != "event") ) + continue; + addView( (*it)->labelForSubresource( *subit ), *it, *subit ); + } + } else { + addView( (*it)->resourceName(), *it ); + } + } + } + + // no resources activated, so stop here to avoid crashing somewhere down the line, TODO: show a nice message instead + if ( mAgendaViews.isEmpty() ) + return; + + setupViews(); + QTimer::singleShot( 0, this, SLOT(slotResizeScrollView()) ); + mTimeLabels->updateConfig(); + + QScrollBar *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(), SIGNAL(valueChanged(int)), + mScrollBar, SLOT(setValue(int)) ); + connect( mScrollBar, SIGNAL(valueChanged(int)), + mTimeLabels, SLOT(positionChanged(int)) ); + + installSplitterEventFilter( mLeftSplitter ); + installSplitterEventFilter( mRightSplitter ); + resizeSplitters(); +} + +void MultiAgendaView::deleteViews() +{ + for ( QValueList<QWidget*>::ConstIterator it = mAgendaWidgets.constBegin(); + it != mAgendaWidgets.constEnd(); ++it ) { + delete *it; + } + mAgendaViews.clear(); + mAgendaWidgets.clear(); + mLastMovedSplitter = 0; +} + +void MultiAgendaView::setupViews() +{ + FOREACH_VIEW( agenda ) { + connect( agenda, SIGNAL( newEventSignal() ), + SIGNAL( newEventSignal() ) ); + connect( agenda, SIGNAL( editIncidenceSignal( Incidence * ) ), + SIGNAL( editIncidenceSignal( Incidence * ) ) ); + connect( agenda, SIGNAL( showIncidenceSignal( Incidence * ) ), + SIGNAL( showIncidenceSignal( Incidence * ) ) ); + connect( agenda, SIGNAL( deleteIncidenceSignal( Incidence * ) ), + SIGNAL( deleteIncidenceSignal( Incidence * ) ) ); + connect( agenda, SIGNAL( startMultiModify( const QString & ) ), + SIGNAL( startMultiModify( const QString & ) ) ); + connect( agenda, SIGNAL( endMultiModify() ), + SIGNAL( endMultiModify() ) ); + + connect( agenda, SIGNAL( incidenceSelected( Incidence * ) ), + SIGNAL( incidenceSelected( Incidence * ) ) ); + + connect( agenda, SIGNAL(cutIncidenceSignal(Incidence*)), + SIGNAL(cutIncidenceSignal(Incidence*)) ); + connect( agenda, SIGNAL(copyIncidenceSignal(Incidence*)), + SIGNAL(copyIncidenceSignal(Incidence*)) ); + connect( agenda, SIGNAL(pasteIncidenceSignal()), + SIGNAL(pasteIncidenceSignal()) ); + connect( agenda, SIGNAL(toggleAlarmSignal(Incidence*)), + SIGNAL(toggleAlarmSignal(Incidence*)) ); + connect( agenda, SIGNAL(dissociateOccurrenceSignal(Incidence*, const QDate&)), + SIGNAL(dissociateOccurrenceSignal(Incidence*, const QDate&)) ); + connect( agenda, SIGNAL(dissociateFutureOccurrenceSignal(Incidence*, const QDate&)), + SIGNAL(dissociateFutureOccurrenceSignal(Incidence*, const QDate&)) ); + + connect( agenda, SIGNAL(newEventSignal(const QDate&)), + SIGNAL(newEventSignal(const QDate&)) ); + connect( agenda, SIGNAL(newEventSignal(const QDateTime&)), + SIGNAL(newEventSignal(const QDateTime&)) ); + connect( agenda, SIGNAL(newEventSignal(const QDateTime&, const QDateTime&)), + SIGNAL(newEventSignal(const QDateTime&, const QDateTime&)) ); + connect( agenda, SIGNAL(newTodoSignal(const QDate&)), + SIGNAL(newTodoSignal(const QDate&)) ); + + connect( agenda, SIGNAL(incidenceSelected(Incidence*)), + SLOT(slotSelectionChanged()) ); + + connect( agenda, SIGNAL(timeSpanSelectionChanged()), + SLOT(slotClearTimeSpanSelection()) ); + + disconnect( agenda->agenda(), SIGNAL(zoomView(const int,const QPoint&,const Qt::Orientation)), agenda, 0 ); + connect( agenda->agenda(), SIGNAL(zoomView(const int,const QPoint&,const Qt::Orientation)), + SLOT(zoomView(const int,const QPoint&,const Qt::Orientation)) ); + } + + FOREACH_VIEW( agenda ) { + agenda->readSettings(); + } + + int minWidth = 0; + for ( QValueList<QWidget*>::ConstIterator it = mAgendaWidgets.constBegin(); it != mAgendaWidgets.constEnd(); ++it ) + minWidth = QMAX( minWidth, (*it)->minimumSizeHint().width() ); + for ( QValueList<QWidget*>::ConstIterator it = mAgendaWidgets.constBegin(); it != mAgendaWidgets.constEnd(); ++it ) + (*it)->setMinimumWidth( minWidth ); +} + +MultiAgendaView::~ MultiAgendaView() +{ +} + +Incidence::List MultiAgendaView::selectedIncidences() +{ + Incidence::List list; + FOREACH_VIEW(agendaView) { + list += agendaView->selectedIncidences(); + } + return list; +} + +DateList MultiAgendaView::selectedDates() +{ + DateList list; + FOREACH_VIEW(agendaView) { + list += agendaView->selectedDates(); + } + return list; +} + +int MultiAgendaView::currentDateCount() +{ + FOREACH_VIEW( agendaView ) + return agendaView->currentDateCount(); + return 0; +} + +void MultiAgendaView::showDates(const QDate & start, const QDate & end) +{ + mStartDate = start; + mEndDate = end; + recreateViews(); + FOREACH_VIEW( agendaView ) + agendaView->showDates( start, end ); +} + +void MultiAgendaView::showIncidences(const Incidence::List & incidenceList) +{ + FOREACH_VIEW( agendaView ) + agendaView->showIncidences( incidenceList ); +} + +void MultiAgendaView::updateView() +{ + recreateViews(); + FOREACH_VIEW( agendaView ) + agendaView->updateView(); +} + +void MultiAgendaView::changeIncidenceDisplay(Incidence * incidence, int mode) +{ + FOREACH_VIEW( agendaView ) + agendaView->changeIncidenceDisplay( incidence, mode ); +} + +int MultiAgendaView::maxDatesHint() +{ + FOREACH_VIEW( agendaView ) + return agendaView->maxDatesHint(); + return 0; +} + +void MultiAgendaView::slotSelectionChanged() +{ + FOREACH_VIEW( agenda ) { + if ( agenda != sender() ) + agenda->clearSelection(); + } +} + +bool MultiAgendaView::eventDurationHint(QDateTime & startDt, QDateTime & endDt, bool & allDay) +{ + FOREACH_VIEW( agenda ) { + bool valid = agenda->eventDurationHint( startDt, endDt, allDay ); + if ( valid ) + return true; + } + return false; +} + +void MultiAgendaView::slotClearTimeSpanSelection() +{ + FOREACH_VIEW( agenda ) { + if ( agenda != sender() ) + agenda->clearTimeSpanSelection(); + } +} + +void MultiAgendaView::setTypeAheadReceiver(QObject * o) +{ + FOREACH_VIEW( agenda ) + agenda->setTypeAheadReceiver( o ); +} + +void MultiAgendaView::finishTypeAhead() +{ + FOREACH_VIEW( agenda ) + agenda->finishTypeAhead(); +} + +void MultiAgendaView::addView( const QString &label, KCal::ResourceCalendar * res, const QString & subRes ) +{ + QVBox *box = new QVBox( mTopBox ); + QLabel *l = new QLabel( label, box ); + l->setAlignment( AlignVCenter | AlignHCenter ); + KOAgendaView* av = new KOAgendaView( calendar(), box, 0, true ); + av->setResource( res, subRes ); + av->setIncidenceChanger( mChanger ); + av->agenda()->setVScrollBarMode( QScrollView::AlwaysOff ); + mAgendaViews.append( av ); + mAgendaWidgets.append( box ); + box->show(); + mTimeLabels->setAgenda( av->agenda() ); + + connect( av->agenda()->verticalScrollBar(), SIGNAL(valueChanged(int)), + mTimeLabels, SLOT(positionChanged(int)) ); + connect( mTimeLabels->verticalScrollBar(), SIGNAL(valueChanged(int)), + av, SLOT(setContentsPos(int)) ); + + installSplitterEventFilter( av->splitter() ); +} + +void MultiAgendaView::resizeEvent(QResizeEvent * ev) +{ + resizeScrollView( ev->size() ); + AgendaView::resizeEvent( ev ); +} + +void MultiAgendaView::resizeScrollView(const QSize & size) +{ + const int widgetWidth = size.width() - mTimeLabels->width() - mScrollBar->width(); + int width = QMAX( mTopBox->sizeHint().width(), widgetWidth ); + int height = size.height(); + if ( width > widgetWidth ) { + const int sbHeight = mScrollView->horizontalScrollBar()->height(); + height -= sbHeight; + mLeftBottomSpacer->setFixedHeight( sbHeight ); + mRightBottomSpacer->setFixedHeight( sbHeight ); + } else { + mLeftBottomSpacer->setFixedHeight( 0 ); + mRightBottomSpacer->setFixedHeight( 0 ); + } + mScrollView->resizeContents( width, height ); + mTopBox->resize( width, height ); +} + +void MultiAgendaView::setIncidenceChanger(IncidenceChangerBase * changer) +{ + AgendaView::setIncidenceChanger( changer ); + FOREACH_VIEW( agenda ) + agenda->setIncidenceChanger( changer ); +} + +void MultiAgendaView::updateConfig() +{ + AgendaView::updateConfig(); + mTimeLabels->updateConfig(); + FOREACH_VIEW( agenda ) + agenda->updateConfig(); +} + +// KDE4: not needed anymore, QSplitter has a moved signal there +bool MultiAgendaView::eventFilter(QObject * obj, QEvent * event) +{ + if ( obj->className() == QCString("QSplitterHandle") ) { + if ( (event->type() == QEvent::MouseMove && KGlobalSettings::opaqueResize()) + || event->type() == QEvent::MouseButtonRelease ) { + FOREACH_VIEW( agenda ) { + if ( agenda->splitter() == obj->parent() ) + mLastMovedSplitter = agenda->splitter(); + } + if ( mLeftSplitter == obj->parent() ) + mLastMovedSplitter = mLeftSplitter; + else if ( mRightSplitter == obj->parent() ) + mLastMovedSplitter = mRightSplitter; + QTimer::singleShot( 0, this, SLOT(resizeSplitters()) ); + } + } + return AgendaView::eventFilter( obj, event ); +} + +void MultiAgendaView::resizeSplitters() +{ + if ( !mLastMovedSplitter ) + mLastMovedSplitter = mAgendaViews.first()->splitter(); + FOREACH_VIEW( agenda ) { + if ( agenda->splitter() == mLastMovedSplitter ) + continue; + agenda->splitter()->setSizes( mLastMovedSplitter->sizes() ); + } + if ( mLastMovedSplitter != mLeftSplitter ) + mLeftSplitter->setSizes( mLastMovedSplitter->sizes() ); + if ( mLastMovedSplitter != mRightSplitter ) + mRightSplitter->setSizes( mLastMovedSplitter->sizes() ); +} + +void MultiAgendaView::zoomView( const int delta, const QPoint & pos, const Qt::Orientation ori ) +{ + if ( ori == Qt::Vertical ) { + if ( delta > 0 ) { + if ( KOPrefs::instance()->mHourSize > 4 ) + KOPrefs::instance()->mHourSize--; + } else { + KOPrefs::instance()->mHourSize++; + } + } + + FOREACH_VIEW( agenda ) + agenda->zoomView( delta, pos, ori ); + + mTimeLabels->updateConfig(); + mTimeLabels->positionChanged(); + mTimeLabels->repaint(); +} + +// KDE4: not needed, use existing QSplitter signals instead +void MultiAgendaView::installSplitterEventFilter(QSplitter * splitter) +{ + QObjectList *objlist = splitter->queryList( "QSplitterHandle" ); + // HACK: when not being visible, the splitter handle is sometimes not found + // for unknown reasons, so trigger an update when we are shown again + if ( objlist->count() == 0 && !isVisible() ) + mUpdateOnShow = true; + QObjectListIt it( *objlist ); + QObject *obj; + while ( (obj = it.current()) != 0 ) { + obj->removeEventFilter( this ); + obj->installEventFilter( this ); + ++it; + } + delete objlist; +} + +void MultiAgendaView::slotResizeScrollView() +{ + resizeScrollView( size() ); +} + +void MultiAgendaView::show() +{ + AgendaView::show(); + if ( mUpdateOnShow ) { + mUpdateOnShow = false; + mPendingChanges = true; // force a full view recreation + showDates( mStartDate, mEndDate ); + } +} + +void MultiAgendaView::resourcesChanged() +{ + mPendingChanges = true; + FOREACH_VIEW( agenda ) + agenda->resourcesChanged(); +} + +#include "multiagendaview.moc" diff --git a/korganizer/multiagendaview.h b/korganizer/multiagendaview.h new file mode 100644 index 000000000..8145dd66b --- /dev/null +++ b/korganizer/multiagendaview.h @@ -0,0 +1,107 @@ +/* + 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 KORG_MULTIAGENDAVIEW_H_H +#define KORG_MULTIAGENDAVIEW_H_H + +#include "agendaview.h" + +class QScrollView; +class QHBox; +class QSplitter; +class KOAgendaView; +class TimeLabels; +class QScrollBar; + +namespace KCal { + class ResourceCalendar; +} + +namespace KOrg { + +/** + Shows one agenda for every resource side-by-side. +*/ +class MultiAgendaView : public AgendaView +{ + Q_OBJECT + public: + explicit MultiAgendaView( Calendar* cal, QWidget *parent = 0, const char *name = 0 ); + ~MultiAgendaView(); + + Incidence::List selectedIncidences(); + DateList selectedDates(); + int currentDateCount(); + int maxDatesHint(); + + bool eventDurationHint(QDateTime &startDt, QDateTime &endDt, bool &allDay); + + void setTypeAheadReceiver( QObject *o ); + + public slots: + void showDates( const QDate &start, const QDate &end ); + void showIncidences( const Incidence::List &incidenceList ); + void updateView(); + void changeIncidenceDisplay( Incidence *incidence, int mode ); + void updateConfig(); + + void setIncidenceChanger( IncidenceChangerBase *changer ); + + void finishTypeAhead(); + + void show(); + + void resourcesChanged(); + + protected: + void resizeEvent( QResizeEvent *ev ); + bool eventFilter( QObject *obj, QEvent *event ); + + private: + void addView( const QString &label, KCal::ResourceCalendar *res, const QString &subRes = QString::null ); + void deleteViews(); + void recreateViews(); + void setupViews(); + void resizeScrollView( const QSize &size ); + void installSplitterEventFilter( QSplitter *splitter ); + + private slots: + void slotSelectionChanged(); + void slotClearTimeSpanSelection(); + void resizeSplitters(); + void zoomView( const int delta, const QPoint &pos, const Qt::Orientation ori ); + void slotResizeScrollView(); + + private: + QValueList<KOAgendaView*> mAgendaViews; + QValueList<QWidget*> mAgendaWidgets; + QHBox *mTopBox; + QScrollView *mScrollView; + TimeLabels *mTimeLabels; + QSplitter *mLeftSplitter, *mRightSplitter; + QSplitter *mLastMovedSplitter; + QScrollBar *mScrollBar; + QWidget *mLeftBottomSpacer, *mRightBottomSpacer; + QDate mStartDate, mEndDate; + bool mUpdateOnShow; + bool mPendingChanges; +}; + +} + +#endif diff --git a/korganizer/navigatorbar.cpp b/korganizer/navigatorbar.cpp new file mode 100644 index 000000000..dd7b45ea6 --- /dev/null +++ b/korganizer/navigatorbar.cpp @@ -0,0 +1,193 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qstring.h> +#include <qtooltip.h> +#include <qpushbutton.h> +#include <qlayout.h> +#include <qframe.h> +#include <qpopupmenu.h> +#include <qlabel.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kglobal.h> +#include <kiconloader.h> + +#include "koglobals.h" +#include "koprefs.h" + +#include <kcalendarsystem.h> + +#include "navigatorbar.h" + +ActiveLabel::ActiveLabel( QWidget *parent, const char *name ) + : QLabel( parent, name ) +{ +} + +void ActiveLabel::mouseReleaseEvent( QMouseEvent * ) +{ + emit clicked(); +} + + +NavigatorBar::NavigatorBar( QWidget *parent, const char *name ) + : QWidget( parent, name ), mHasMinWidth( false ) +{ + QFont tfont = font(); + tfont.setPointSize( 10 ); + tfont.setBold( false ); + + bool isRTL = KOGlobals::self()->reverseLayout(); + + QPixmap pix; + // Create backward navigation buttons + mPrevYear = new QPushButton( this ); + pix = KOGlobals::self()->smallIcon( isRTL ? "2rightarrow" : "2leftarrow" ); + mPrevYear->setPixmap( pix ); + mPrevYear->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); + QToolTip::add( mPrevYear, i18n("Previous year") ); + + pix = KOGlobals::self()->smallIcon( isRTL ? "1rightarrow" : "1leftarrow"); + mPrevMonth = new QPushButton( this ); + mPrevMonth->setPixmap( pix ); + mPrevMonth->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); + QToolTip::add( mPrevMonth, i18n("Previous month") ); + + // Create forward navigation buttons + pix = KOGlobals::self()->smallIcon( isRTL ? "1leftarrow" : "1rightarrow"); + mNextMonth = new QPushButton( this ); + mNextMonth->setPixmap( pix ); + mNextMonth->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); + QToolTip::add( mNextMonth, i18n("Next month") ); + + pix = KOGlobals::self()->smallIcon( isRTL ? "2leftarrow" : "2rightarrow"); + mNextYear = new QPushButton( this ); + mNextYear->setPixmap( pix ); + mNextYear->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); + QToolTip::add( mNextYear, i18n("Next year") ); + + // Create month name button + mMonth = new ActiveLabel( this ); + mMonth->setFont( tfont ); + mMonth->setAlignment( AlignCenter ); + mMonth->setMinimumHeight( mPrevYear->sizeHint().height() ); + QToolTip::add( mMonth, i18n("Select a month") ); + + // set up control frame layout + QBoxLayout *ctrlLayout = new QHBoxLayout( 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, SIGNAL( clicked() ), SIGNAL( goPrevYear() ) ); + connect( mPrevMonth, SIGNAL( clicked() ), SIGNAL( goPrevMonth() ) ); + connect( mNextMonth, SIGNAL( clicked() ), SIGNAL( goNextMonth() ) ); + connect( mNextYear, SIGNAL( clicked() ), SIGNAL( goNextYear() ) ); + connect( mMonth, SIGNAL( clicked() ), SLOT( selectMonth() ) ); +} + +NavigatorBar::~NavigatorBar() +{ +} + +void NavigatorBar::showButtons( bool left, bool right ) +{ + if ( left ) { + mPrevYear->show(); + mPrevMonth->show(); + } else { + mPrevYear->hide(); + mPrevMonth->hide(); + } + + if ( right ) { + mNextYear->show(); + mNextMonth->show(); + } else { + mNextYear->hide(); + mNextMonth->hide(); + } + +} + +void NavigatorBar::selectDates( const KCal::DateList &dateList ) +{ + if ( dateList.count() > 0 ) { + mDate = dateList.first(); + + const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem(); + + if ( !mHasMinWidth ) { + // 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 = QFontMetrics( mMonth->font() ).width( QString("%1 8888") + .arg( calSys->monthName( i, calSys->year( mDate ) ) ) ); + if ( w > maxwidth ) maxwidth = w; + } + 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 ) ) ); + } +} + +void NavigatorBar::selectMonth() +{ + // every year can have different month names (in some calendar systems) + const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem(); + + int i, month, months = calSys->monthsInYear( mDate ); + + QPopupMenu *popup = new QPopupMenu( mMonth ); + + for ( i = 1; i <= months; i++ ) + popup->insertItem( calSys->monthName( i, calSys->year( mDate ) ), i ); + + popup->setActiveItem( calSys->month( mDate ) - 1 ); + popup->setMinimumWidth( mMonth->width() ); + + if ( ( month = popup->exec( mMonth->mapToGlobal( QPoint( 0, 0 ) ), + calSys->month( mDate ) - 1 ) ) == -1 ) { + delete popup; + return; // canceled + } + + emit goMonth( month ); + + delete popup; +} + +#include "navigatorbar.moc" diff --git a/korganizer/navigatorbar.h b/korganizer/navigatorbar.h new file mode 100644 index 000000000..171c6b408 --- /dev/null +++ b/korganizer/navigatorbar.h @@ -0,0 +1,82 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef NAVIGATORBAR_H +#define NAVIGATORBAR_H + +#include <libkcal/incidencebase.h> + +#include <qlabel.h> + +class QPushButton; +class QFrame; + +class ActiveLabel : public QLabel +{ + Q_OBJECT + public: + ActiveLabel( QWidget *parent, const char *name = 0 ); + + signals: + void clicked(); + + protected: + void mouseReleaseEvent ( QMouseEvent * e ); +}; + + +class NavigatorBar: public QWidget +{ + Q_OBJECT + public: + NavigatorBar( QWidget *parent = 0, const char *name = 0 ); + ~NavigatorBar(); + + void showButtons( bool left, bool right ); + + public slots: + void selectDates( const KCal::DateList & ); + + signals: + void goNextMonth(); + void goPrevMonth(); + void goNextYear(); + void goPrevYear(); + void goMonth(int month); + + private slots: + void selectMonth(); + + private: + bool mHasMinWidth; + + QDate mDate; + + QPushButton *mPrevYear; + QPushButton *mPrevMonth; + ActiveLabel *mMonth; + QPushButton *mNextMonth; + QPushButton *mNextYear; +}; + +#endif diff --git a/korganizer/pixmaps/Makefile.am b/korganizer/pixmaps/Makefile.am new file mode 100644 index 000000000..7b8b618f3 --- /dev/null +++ b/korganizer/pixmaps/Makefile.am @@ -0,0 +1,2 @@ +korganizericondir = $(kde_datadir)/korganizer/icons +korganizericon_ICON = AUTO diff --git a/korganizer/pixmaps/cr16-action-1day.png b/korganizer/pixmaps/cr16-action-1day.png Binary files differnew file mode 100644 index 000000000..ca55f9077 --- /dev/null +++ b/korganizer/pixmaps/cr16-action-1day.png diff --git a/korganizer/pixmaps/cr16-action-5days.png b/korganizer/pixmaps/cr16-action-5days.png Binary files differnew file mode 100644 index 000000000..514fee3f5 --- /dev/null +++ b/korganizer/pixmaps/cr16-action-5days.png diff --git a/korganizer/pixmaps/cr16-action-7days.png b/korganizer/pixmaps/cr16-action-7days.png Binary files differnew file mode 100644 index 000000000..c9c0d51b3 --- /dev/null +++ b/korganizer/pixmaps/cr16-action-7days.png diff --git a/korganizer/pixmaps/cr16-action-dayview.png b/korganizer/pixmaps/cr16-action-dayview.png Binary files differnew file mode 100644 index 000000000..0b38b7378 --- /dev/null +++ b/korganizer/pixmaps/cr16-action-dayview.png diff --git a/korganizer/pixmaps/cr16-action-downindicator.png b/korganizer/pixmaps/cr16-action-downindicator.png Binary files differnew file mode 100644 index 000000000..00cc5a30e --- /dev/null +++ b/korganizer/pixmaps/cr16-action-downindicator.png diff --git a/korganizer/pixmaps/cr16-action-findf.png b/korganizer/pixmaps/cr16-action-findf.png Binary files differnew file mode 100644 index 000000000..416d06459 --- /dev/null +++ b/korganizer/pixmaps/cr16-action-findf.png diff --git a/korganizer/pixmaps/cr16-action-groupevent.png b/korganizer/pixmaps/cr16-action-groupevent.png Binary files differnew file mode 100644 index 000000000..31b6f3399 --- /dev/null +++ b/korganizer/pixmaps/cr16-action-groupevent.png diff --git a/korganizer/pixmaps/cr16-action-groupeventtentative.png b/korganizer/pixmaps/cr16-action-groupeventtentative.png Binary files differnew file mode 100644 index 000000000..200336efb --- /dev/null +++ b/korganizer/pixmaps/cr16-action-groupeventtentative.png diff --git a/korganizer/pixmaps/cr16-action-list.png b/korganizer/pixmaps/cr16-action-list.png Binary files differnew file mode 100644 index 000000000..41b4cd8bd --- /dev/null +++ b/korganizer/pixmaps/cr16-action-list.png diff --git a/korganizer/pixmaps/cr16-action-mailappt.png b/korganizer/pixmaps/cr16-action-mailappt.png Binary files differnew file mode 100644 index 000000000..ce32938a6 --- /dev/null +++ b/korganizer/pixmaps/cr16-action-mailappt.png diff --git a/korganizer/pixmaps/cr16-action-month.png b/korganizer/pixmaps/cr16-action-month.png Binary files differnew file mode 100644 index 000000000..51a17c6ed --- /dev/null +++ b/korganizer/pixmaps/cr16-action-month.png diff --git a/korganizer/pixmaps/cr16-action-nomailappt.png b/korganizer/pixmaps/cr16-action-nomailappt.png Binary files differnew file mode 100644 index 000000000..03737189b --- /dev/null +++ b/korganizer/pixmaps/cr16-action-nomailappt.png diff --git a/korganizer/pixmaps/cr16-action-organizer.png b/korganizer/pixmaps/cr16-action-organizer.png Binary files differnew file mode 100644 index 000000000..e507dadbf --- /dev/null +++ b/korganizer/pixmaps/cr16-action-organizer.png diff --git a/korganizer/pixmaps/cr16-action-playsound.png b/korganizer/pixmaps/cr16-action-playsound.png Binary files differnew file mode 100644 index 000000000..a893d6229 --- /dev/null +++ b/korganizer/pixmaps/cr16-action-playsound.png diff --git a/korganizer/pixmaps/cr16-action-runprog.png b/korganizer/pixmaps/cr16-action-runprog.png Binary files differnew file mode 100644 index 000000000..2ec47645d --- /dev/null +++ b/korganizer/pixmaps/cr16-action-runprog.png diff --git a/korganizer/pixmaps/cr16-action-smallcal.png b/korganizer/pixmaps/cr16-action-smallcal.png Binary files differnew file mode 100644 index 000000000..0d9c2b154 --- /dev/null +++ b/korganizer/pixmaps/cr16-action-smallcal.png diff --git a/korganizer/pixmaps/cr16-action-smallclock.png b/korganizer/pixmaps/cr16-action-smallclock.png Binary files differnew file mode 100644 index 000000000..3c1eae5f8 --- /dev/null +++ b/korganizer/pixmaps/cr16-action-smallclock.png diff --git a/korganizer/pixmaps/cr16-action-upindicator.png b/korganizer/pixmaps/cr16-action-upindicator.png Binary files differnew file mode 100644 index 000000000..ffb263e44 --- /dev/null +++ b/korganizer/pixmaps/cr16-action-upindicator.png diff --git a/korganizer/pixmaps/cr16-action-webexport.png b/korganizer/pixmaps/cr16-action-webexport.png Binary files differnew file mode 100644 index 000000000..a655ce357 --- /dev/null +++ b/korganizer/pixmaps/cr16-action-webexport.png diff --git a/korganizer/pixmaps/cr16-action-whatsnext.png b/korganizer/pixmaps/cr16-action-whatsnext.png Binary files differnew file mode 100644 index 000000000..bcc7ff298 --- /dev/null +++ b/korganizer/pixmaps/cr16-action-whatsnext.png diff --git a/korganizer/pixmaps/cr22-action-1day.png b/korganizer/pixmaps/cr22-action-1day.png Binary files differnew file mode 100644 index 000000000..146be66f5 --- /dev/null +++ b/korganizer/pixmaps/cr22-action-1day.png diff --git a/korganizer/pixmaps/cr22-action-5days.png b/korganizer/pixmaps/cr22-action-5days.png Binary files differnew file mode 100644 index 000000000..c61d63d6e --- /dev/null +++ b/korganizer/pixmaps/cr22-action-5days.png diff --git a/korganizer/pixmaps/cr22-action-7days.png b/korganizer/pixmaps/cr22-action-7days.png Binary files differnew file mode 100644 index 000000000..2e3b37da4 --- /dev/null +++ b/korganizer/pixmaps/cr22-action-7days.png diff --git a/korganizer/pixmaps/cr22-action-agenda.png b/korganizer/pixmaps/cr22-action-agenda.png Binary files differnew file mode 100644 index 000000000..74ec53eae --- /dev/null +++ b/korganizer/pixmaps/cr22-action-agenda.png diff --git a/korganizer/pixmaps/cr22-action-delete.png b/korganizer/pixmaps/cr22-action-delete.png Binary files differnew file mode 100644 index 000000000..6fb193f06 --- /dev/null +++ b/korganizer/pixmaps/cr22-action-delete.png diff --git a/korganizer/pixmaps/cr22-action-emptybox-mask.png b/korganizer/pixmaps/cr22-action-emptybox-mask.png Binary files differnew file mode 100644 index 000000000..df26e7483 --- /dev/null +++ b/korganizer/pixmaps/cr22-action-emptybox-mask.png diff --git a/korganizer/pixmaps/cr22-action-emptybox.png b/korganizer/pixmaps/cr22-action-emptybox.png Binary files differnew file mode 100644 index 000000000..a29cad121 --- /dev/null +++ b/korganizer/pixmaps/cr22-action-emptybox.png diff --git a/korganizer/pixmaps/cr22-action-list.png b/korganizer/pixmaps/cr22-action-list.png Binary files differnew file mode 100644 index 000000000..8f786bc6a --- /dev/null +++ b/korganizer/pixmaps/cr22-action-list.png diff --git a/korganizer/pixmaps/cr22-action-month.png b/korganizer/pixmaps/cr22-action-month.png Binary files differnew file mode 100644 index 000000000..7153a3b9f --- /dev/null +++ b/korganizer/pixmaps/cr22-action-month.png diff --git a/korganizer/pixmaps/cr22-action-search.png b/korganizer/pixmaps/cr22-action-search.png Binary files differnew file mode 100644 index 000000000..4f880ab65 --- /dev/null +++ b/korganizer/pixmaps/cr22-action-search.png diff --git a/korganizer/pixmaps/cr22-action-send.png b/korganizer/pixmaps/cr22-action-send.png Binary files differnew file mode 100644 index 000000000..384cbf34e --- /dev/null +++ b/korganizer/pixmaps/cr22-action-send.png diff --git a/korganizer/pixmaps/cr22-action-webexport.png b/korganizer/pixmaps/cr22-action-webexport.png Binary files differnew file mode 100644 index 000000000..1ae24b2b9 --- /dev/null +++ b/korganizer/pixmaps/cr22-action-webexport.png diff --git a/korganizer/pixmaps/cr22-action-whatsnext.png b/korganizer/pixmaps/cr22-action-whatsnext.png Binary files differnew file mode 100644 index 000000000..02577bb80 --- /dev/null +++ b/korganizer/pixmaps/cr22-action-whatsnext.png diff --git a/korganizer/pixmaps/cr22-action-xdays.png b/korganizer/pixmaps/cr22-action-xdays.png Binary files differnew file mode 100644 index 000000000..53986555f --- /dev/null +++ b/korganizer/pixmaps/cr22-action-xdays.png diff --git a/korganizer/pixmaps/cr32-action-1day.png b/korganizer/pixmaps/cr32-action-1day.png Binary files differnew file mode 100644 index 000000000..97bc5cdf3 --- /dev/null +++ b/korganizer/pixmaps/cr32-action-1day.png diff --git a/korganizer/pixmaps/cr32-action-5days.png b/korganizer/pixmaps/cr32-action-5days.png Binary files differnew file mode 100644 index 000000000..0e02d4c4e --- /dev/null +++ b/korganizer/pixmaps/cr32-action-5days.png diff --git a/korganizer/pixmaps/cr32-action-7days.png b/korganizer/pixmaps/cr32-action-7days.png Binary files differnew file mode 100644 index 000000000..0d0908b71 --- /dev/null +++ b/korganizer/pixmaps/cr32-action-7days.png diff --git a/korganizer/pixmaps/cr32-action-list.png b/korganizer/pixmaps/cr32-action-list.png Binary files differnew file mode 100644 index 000000000..fd1eec19e --- /dev/null +++ b/korganizer/pixmaps/cr32-action-list.png diff --git a/korganizer/pixmaps/cr32-action-month.png b/korganizer/pixmaps/cr32-action-month.png Binary files differnew file mode 100644 index 000000000..3c1a0b177 --- /dev/null +++ b/korganizer/pixmaps/cr32-action-month.png diff --git a/korganizer/pixmaps/cr32-action-xdays.png b/korganizer/pixmaps/cr32-action-xdays.png Binary files differnew file mode 100644 index 000000000..441e2f802 --- /dev/null +++ b/korganizer/pixmaps/cr32-action-xdays.png diff --git a/korganizer/plugins/Makefile.am b/korganizer/plugins/Makefile.am new file mode 100644 index 000000000..58cf02ea0 --- /dev/null +++ b/korganizer/plugins/Makefile.am @@ -0,0 +1,6 @@ +if include_exchange_SUBDIR +exchange_SUBDIR=exchange +endif + +SUBDIRS=datenums hebrew printing $(exchange_SUBDIR) + diff --git a/korganizer/plugins/datenums/Makefile.am b/korganizer/plugins/datenums/Makefile.am new file mode 100644 index 000000000..8081a5645 --- /dev/null +++ b/korganizer/plugins/datenums/Makefile.am @@ -0,0 +1,14 @@ +INCLUDES = -I$(top_srcdir)/korganizer/interfaces -I$(top_srcdir)/korganizer $(all_includes) + +kde_module_LTLIBRARIES = libkorg_datenums.la + +libkorg_datenums_la_SOURCES = configdialog.cpp datenums.cpp +libkorg_datenums_la_LDFLAGS = -module $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) +libkorg_datenums_la_LIBADD = $(top_builddir)/korganizer/libkorganizer.la $(LIB_KDEUI) + +noinst_HEADERS = datenums.h + +servicedir = $(kde_servicesdir)/korganizer +service_DATA = datenums.desktop + +METASOURCES = AUTO diff --git a/korganizer/plugins/datenums/configdialog.cpp b/korganizer/plugins/datenums/configdialog.cpp new file mode 100644 index 000000000..d26a1fd86 --- /dev/null +++ b/korganizer/plugins/datenums/configdialog.cpp @@ -0,0 +1,80 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include <qlayout.h> +#include <qlabel.h> +#include <qvbuttongroup.h> +#include <qradiobutton.h> + +#include <klocale.h> +#include <kmessagebox.h> +#include <kapplication.h> +#include <kglobal.h> +#include <kconfig.h> +#include <kstandarddirs.h> +#include <ksimpleconfig.h> + +#include "configdialog.h" +#include "configdialog.moc" + +ConfigDialog::ConfigDialog(QWidget *parent) + : KDialogBase(Plain,i18n("Configure Day Numbers"),Ok|Cancel,Ok,parent) +{ + QFrame *topFrame = plainPage(); + QVBoxLayout *topLayout = new QVBoxLayout(topFrame,0,spacingHint()); + +// QLabel *label = new QLabel(i18n("Show date numbers:"),topFrame); +// topLayout->addWidget(label); + mDayNumGroup = new QVButtonGroup( i18n("Show Date Number"), topFrame ); + topLayout->addWidget( mDayNumGroup ); + + new QRadioButton( i18n("Show day number"), mDayNumGroup ); + new QRadioButton( i18n("Show days to end of year"), mDayNumGroup ); + new QRadioButton( i18n("Show both"), mDayNumGroup ); + + load(); +} + +ConfigDialog::~ConfigDialog() +{ +} + +void ConfigDialog::load() +{ + KConfig config( "korganizerrc", true, false); // Open read-only, no kdeglobals + config.setGroup("Calendar/DateNum Plugin"); + int datenum = config.readNumEntry( "ShowDayNumbers", 0 ); + mDayNumGroup->setButton( datenum ); +} + +void ConfigDialog::save() +{ + KConfig config( "korganizerrc", false, false); // Open read-write, no kdeglobals + config.setGroup("Calendar/DateNum Plugin"); + config.writeEntry("ShowDayNumbers", mDayNumGroup->selectedId() ); + config.sync(); +} + +void ConfigDialog::slotOk() +{ + save(); + + accept(); +} diff --git a/korganizer/plugins/datenums/configdialog.h b/korganizer/plugins/datenums/configdialog.h new file mode 100644 index 000000000..15efaf049 --- /dev/null +++ b/korganizer/plugins/datenums/configdialog.h @@ -0,0 +1,44 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef CONFIGDIALOG_H +#define CONFIGDIALOG_H + +#include <kdialogbase.h> + +class QButtonGroup; + +class ConfigDialog : public KDialogBase +{ + Q_OBJECT + public: + ConfigDialog(QWidget *parent=0); + virtual ~ConfigDialog(); + + protected: + void load(); + void save(); + + protected slots: + void slotOk(); + + private: + QButtonGroup *mDayNumGroup; +}; + +#endif diff --git a/korganizer/plugins/datenums/datenums.cpp b/korganizer/plugins/datenums/datenums.cpp new file mode 100644 index 000000000..a849f39f3 --- /dev/null +++ b/korganizer/plugins/datenums/datenums.cpp @@ -0,0 +1,72 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "datenums.h" +#include "koglobals.h" +#include <kconfig.h> +#include <kstandarddirs.h> + +#include "configdialog.h" +#include <kcalendarsystem.h> + +class DatenumsFactory : public CalendarDecorationFactory { + public: + CalendarDecoration *create() { return new Datenums; } +}; + +K_EXPORT_COMPONENT_FACTORY( libkorg_datenums, DatenumsFactory ) + + +Datenums::Datenums() +{ + KConfig config( "korganizerrc", true, false); // Open read-only, no kdeglobals + config.setGroup("Calendar/DateNum Plugin"); + mDateNum = config.readNumEntry( "ShowDayNumbers", 0 ); +} + +void Datenums::configure(QWidget *parent) +{ + ConfigDialog *dlg = new ConfigDialog(parent); + dlg->exec(); + delete dlg; +} + + +QString Datenums::shortText(const QDate &date) +{ + int doy = KOGlobals::self()->calendarSystem()->dayOfYear(date); + switch (mDateNum) { + case 1: // only days until end of year + return QString::number( KOGlobals::self()->calendarSystem()->daysInYear(date) - doy ); + break; + case 2: // both day of year and days till end of year + return i18n("dayOfYear / daysTillEndOfYear", "%1 / %2").arg( doy ) + .arg(KOGlobals::self()->calendarSystem()->daysInYear(date) - doy); + break; + case 0: // only day of year + default: + return QString::number( doy ); + } + return QString::number( doy ); +} + +QString Datenums::info() +{ + return i18n("This plugin provides numbers of days and weeks."); +} diff --git a/korganizer/plugins/datenums/datenums.desktop b/korganizer/plugins/datenums/datenums.desktop new file mode 100644 index 000000000..b5010edc9 --- /dev/null +++ b/korganizer/plugins/datenums/datenums.desktop @@ -0,0 +1,99 @@ +[Desktop Entry] +X-KDE-Library=libkorg_datenums +Name=Date Numbers Plugin for Calendars +Name[af]=Dag nommer inprop module vir kalenders +Name[ar]=قابس أرقام التاريخ للتقويم +Name[bg]=Приставка на календара за дати +Name[bs]=Dodatak za kalendar - brojevi datuma +Name[ca]=Endollable de números de data per als calendaris +Name[cs]=Modul pro očíslování dat v kalendáři +Name[da]=Datonumre-plugin for kalendere +Name[de]=Kalendertag-Modul für Kalender +Name[el]=Πρόσθετο αριθμού ημερών για Ημερολόγια +Name[eo]=Datnumera kromaĵo por Kalendaro +Name[es]=Accesorio de números de fecha para calendarios +Name[et]=Kuupäeva nummerdamise plugin kalendritele +Name[eu]=Egutegientzako data zenbakiak +Name[fa]=وصلۀ عدد تاریخ برای تقویمها +Name[fi]=Päivämääräliitännäinen kalentereihin +Name[fr]=Module de numérotation des jours +Name[fy]=Datumgetallenplugin foar aginda's +Name[gl]=Engadido para Números dos Días nos Calendarios +Name[he]=תוסף מספרי תאריכים ללוחות שנה +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 +Name[ms]=Plugin Bilangan Tarikh untuk Kalendar +Name[nb]=Datonummer programtillegg for Kalender +Name[nds]=Kalennerdag-Moduul för Kalenners +Name[ne]=क्यालेन्डरका लागि मिति सङ्ख्या प्लगइन +Name[nl]=Datumgetallenplugin voor agenda's +Name[nn]=Datonummer programtillegg for Kalender +Name[pl]=Wtyczka numerów dni dla Kalendarzy +Name[pt]='plugin' de Números de Datas para Calendários +Name[pt_BR]=Plugin-de Números e Datas para Calendários +Name[ru]=Даты календаря +Name[sk]=Modul dátumov pre kalendáre +Name[sl]=Datumski vstavek za koledarje +Name[sr]=Прикључак календара за бројеве датума +Name[sr@Latn]=Priključak kalendara za brojeve datuma +Name[sv]=Datuminsticksprogram för kalendrar +Name[ta]=நாள்காட்டிகளுக்கான தேதி எண்களின் சொருகுப்பொருள் +Name[tg]=Санаҳои тақвим +Name[tr]=Takvimler için Tarih Rakamları Eklentisi +Name[uk]=Втулок дат для календарів +Name[zh_CN]=日历的日期数字插件 +Name[zh_TW]=行事曆日期數字外掛程式 +Comment=For each day this plugin shows its daynumber of the year at the top of the agenda view. For example, February 1 is day 32 of the year. +Comment[af]=Die inprop module vertoon die dag nommer van die jaar bo aan die agenda aansig. Bv: 1 Februarie is dag 32 van die jaar. +Comment[bg]=Приставката служи за показване на деня от началото на годината. Примерно, 1-ви февруари е 32-ия ден от годината. +Comment[ca]=Per cada dia, aquest endollable mostra el número de dia de l'any al capdamunt de la vista d'agenda. Per exemple, 1 de Febrer és el dia 32 de l'any. +Comment[cs]=tento modul pro každý den zobrazuje pořadí dne v roce na vrcholu pohledu. Např. 1. únor je 32 druhý den v roce. +Comment[da]=For hver dag viser dette plugin nummeret for dagen i året for oven i agendavisningen. For eksempel er 1. februar 1 is den 32. dag i året. +Comment[de]=Für jeden Tag des Jahres wird mit diesem Modul der Kalendertag oben in der Tagesansicht angezeigt. Der 1. Februar ist beispielsweise der 32. Kalendertag des Jahres. +Comment[el]=Για κάθε μέρα, αυτό το πρόσθετο εμφανίζει τον αύξοντα αριθμό της ημέρας του έτους στην προβολή προγράμματος εργασίας. Για παράδειγμα, η 1ι Φεβρουαρίου είναι η ημέρα 32 του έτους. +Comment[es]=Para cada día, esta extensión mostrará el número del día en el año en la parte superior de la vista de la agenda. Por ejemplo, el 1 de febrero es el día número 32 del año. +Comment[et]=See plugin näitab iga päevakavavaate ülaosas iga päeva järjekorranumbrit aastas. Näiteks 1. veebruar on aasta 32. päev. +Comment[eu]=Egun bakoitzeko, plugin honek bere urteko egun-zenbakia erakutsiko du agenda ikuspegiaren goiko aldean. Adibidez, Otsailak 1 urtearen 32. eguna da. +Comment[fa]=در هر روز، این وصله عدد مربوط به روز سال را در بالای نمای agenda نمایش میدهد. مثلاً ۱ فوریه، سی و دومین روز سال میباشد. +Comment[fi]=Tämä liitännäinen näyttää jokaisen päivän järjestysnumeron vuoden alusta agendanäkymässä. Esimerkiksi helmikuun ensimmäinen päivä on vuoden 32. päivä. +Comment[fr]=Pour chaque jour, ce module montre le numéro du jour en haut de la vue agenda. Par exemple, le 1er février est le 32ème jour de l'année. +Comment[fy]=Dizze plugin soarget derfoar dat it nûmer fan de dei boppe de agindawerjefte setten wurdt. Bygelyks, by 1 february heard deinûmer 32. +Comment[gl]=Este engadido amosa cada día o número de día anual na vista superior da axenda. Por exemplo, o 1 de febreiro é o día 32 do ano. +Comment[hu]=Megjeleníti az év elejétől eltelt napok számát az áttekintő nézet tetején. Például február elseje az év 32. napja. +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. +Comment[ms]=Setiap hari plugin ini memaparkan bilangan hari tahun tersebut di atas paparan agenda. Contohnya , 1 Februari adalah hari ke 32 bagi tahun tersebut. +Comment[nb]=For hver dag viser dette programtillegget dagens nummer i året øverst på dagsvisningen. 1. februar er f.eks. dag nr. 32 i året. +Comment[nds]=Dit Moduul wiest för elkeen Dag sien Nummer in't Johr baven de Dagansicht. De 1. Februor is t.B. de 32. Dag vun't Johr. +Comment[ne]=प्रत्येक दिनका लागि यो प्लगइनले एजेन्डा दृश्यको माथि यस वर्षको दिन नम्बर देखाउछ । उदारणका लागि, फेब्रुवरी १ वर्षको बत्तिसौ दिन हो । +Comment[nl]=Deze plugin zorgt ervoor dat het dagnummer boven de agendaweergave wordt geplaatst. Bijvoorbeeld, bij 1 februari hoort dagnummer 32. +Comment[nn]=For kvar dag vil dette programtillegget visa nummeret til denne dagen i året øvst i tidsplanen. 1. februar vil til dømes visast som dag 32. +Comment[pl]=Ta wtyczka dla każdego dnia pokazuje jego numer kolejny w roku, na szczycie widoku planu. Na przykład, 1 luty to 32 dzień roku. +Comment[pt]=Para cada dia, este 'plugin' mostra o seu número de dia do ano no topo da agenda. Por exemplo, o dia 1 de Fevereiro é o dia 32 do ano. +Comment[pt_BR]=Para cada dia, esse plug-in mostra o número do dia no topo da visão de agenda. Por exemplo, 1º de fevereiro é o dia 32 do ano. +Comment[ru]=Этот модуль показывает номер дня в году для каждой даты. Например, для 1 февраля будет показан номер 32. +Comment[sk]=Tento modul pre každý deň zobrazí jeho číslo dňa v roku navrchu pohľadu agendy. Napríklad 1. február je deň číslo 32 v roku. +Comment[sl]=Za vsak dan ta vstavek prikazuje številko dneva v letu na vrhu praikaza agende. Npr., 1. februar je 32. dan v letu. +Comment[sr]=За сваки датум овај прикључак приказује његов број дана у години на врху приказа распореда. На пример, 1. фебруар је 32. дан у години. +Comment[sr@Latn]=Za svaki datum ovaj priključak prikazuje njegov broj dana u godini na vrhu prikaza rasporeda. Na primer, 1. februar je 32. dan u godini. +Comment[sv]=Insticksprogrammet visar dagens nummer under året för varje dag längst upp i agendavyn. Till exempel är 1:a februari den 32:e dagen under året. +Comment[ta]=ஒவ்வோரு நாளும் நிகழ்ச்சி நிரல் காட்சியின் மேற்புறத்தில் வருடத்தின் நாளின் எண்ணை இந்த சொருகுப்பொருள் காட்டுகிறது. உதாரணமாக, பிப்ரவரி 1 வருடத்தின் 32வது நாள் +Comment[tr]=Bu eklenti, her gün için tarih bilgisini gün sayısı olarak ajanda görünümünün yukarısında gösterir. Örneğin, 1 Şubat yılın 32. günüdür. +Comment[uk]=Цей втулок показує зверху перегляду щоденника номер для кожного дня року. Наприклад, 1-го лютого - це 32 день року. +Comment[zh_CN]=此插件可对每天在议事日程视图中上方显示该日在一年中的序号。例如,2月1日是一年的第32天。 +Comment[zh_TW]=對每一天,此外掛程式會顯示這是一年中的第幾天。 +Type=Service +ServiceTypes=Calendar/Plugin,Calendar/Decoration +X-KDE-KOrganizer-HasSettings=true +X-KDE-PluginInterfaceVersion=2 diff --git a/korganizer/plugins/datenums/datenums.h b/korganizer/plugins/datenums/datenums.h new file mode 100644 index 000000000..af3e46473 --- /dev/null +++ b/korganizer/plugins/datenums/datenums.h @@ -0,0 +1,41 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef KORG_DATENUMS_H +#define KORG_DATENUMS_H + +#include <qstring.h> + +#include <calendar/calendardecoration.h> + +using namespace KOrg; + +class Datenums : public CalendarDecoration { + public: + Datenums(); + ~Datenums() {} + + void configure(QWidget *parent); + QString shortText(const QDate &); + + QString info(); + protected: + int mDateNum; +}; + +#endif diff --git a/korganizer/plugins/exchange/Makefile.am b/korganizer/plugins/exchange/Makefile.am new file mode 100644 index 000000000..39290aadd --- /dev/null +++ b/korganizer/plugins/exchange/Makefile.am @@ -0,0 +1,27 @@ +# $Id$ + +SUBDIRS= + +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/korganizer/interfaces \ + -I$(top_srcdir)/libkpimexchange/core -I$(top_builddir)/libkpimexchange/core \ + -I$(top_srcdir) \ + $(all_includes) + +kde_module_LTLIBRARIES = libkorg_exchange.la + +libkorg_exchange_la_SOURCES = exchange.cpp exchangedialog.cpp exchangeconfig.cpp +libkorg_exchange_la_LDFLAGS = -module $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) +libkorg_exchange_la_LIBADD = $(top_builddir)/korganizer/libkorganizer.la \ + $(top_builddir)/libkpimexchange/libkpimexchange.la \ + $(LIB_KDEUI) $(LIB_KPARTS) + +noinst_HEADERS = exchange.h exchangedialog.h exchangeconfig.h + +servicedir = $(kde_servicesdir)/korganizer +service_DATA = exchange.desktop + +rcdir = $(kde_datadir)/korganizer/plugins +rc_DATA = exchangeui.rc + diff --git a/korganizer/plugins/exchange/exchange.cpp b/korganizer/plugins/exchange/exchange.cpp new file mode 100644 index 000000000..86377f046 --- /dev/null +++ b/korganizer/plugins/exchange/exchange.cpp @@ -0,0 +1,238 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2002 Jan-Pascal van Best <janpascal@vanbest.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 <qfile.h> + +#include <kapplication.h> +#include <kconfig.h> +#include <kstandarddirs.h> + +#include <kurl.h> +#include <kdebug.h> + +#include <kmessagebox.h> +#include <klocale.h> +#include <kaction.h> +#include <kglobal.h> + +#include "korganizer/korganizer.h" +#include "korganizer/calendarview.h" + +#include <exchangeclient.h> +#include <exchangeaccount.h> + +#include "exchange.h" +#include "exchangedialog.h" +#include "exchangeconfig.h" + + +using namespace KCal; // Needed for connecting slots + +class ExchangeFactory : public KOrg::PartFactory { + public: + KOrg::Part *create(KOrg::MainWindow *parent, const char *name) + { + kdDebug(5850) << "Registering Exchange Plugin...\n"; + KGlobal::locale()->insertCatalogue("libkpimexchange"); + return new Exchange(parent,name); + } +}; + +K_EXPORT_COMPONENT_FACTORY( libkorg_exchange, ExchangeFactory ) + +Exchange::Exchange(KOrg::MainWindow *parent, const char *name) : + KOrg::Part(parent,name) +{ + setInstance( new KInstance( "korganizer" ) ); + + kdDebug(5850) << "Creating Exchange Plugin...\n"; + + mAccount = new KPIM::ExchangeAccount( "Calendar/Exchange Plugin" ); + mClient = new KPIM::ExchangeClient( mAccount ); + mClient->setWindow( parent->topLevelWidget() ); + + setXMLFile("plugins/exchangeui.rc"); + + new KAction(i18n("&Download..."), 0, this, SLOT(download()), + actionCollection(), "exchange_download"); + + KAction *action = new KAction(i18n("&Upload Event..."), 0, this, SLOT(upload()), + actionCollection(), "exchange_upload"); + QObject::connect(mainWindow()->view(),SIGNAL(incidenceSelected(Incidence *)), + this, SLOT(slotIncidenceSelected(Incidence *))); + action->setEnabled( false ); + QObject::connect(this,SIGNAL(enableIncidenceActions(bool)), + action,SLOT(setEnabled(bool))); + + action = new KAction(i18n("De&lete Event"), 0, this, SLOT(remove()), + actionCollection(), "exchange_delete"); + QObject::connect(this,SIGNAL(enableIncidenceActions(bool)), + action,SLOT(setEnabled(bool))); + action->setEnabled( false ); + + new KAction(i18n("&Configure..."), 0, this, SLOT(configure()), + actionCollection(), "exchange_configure"); + + connect( this, SIGNAL( calendarChanged() ), mainWindow()->view(), SLOT( updateView() ) ); + connect( this, SIGNAL( calendarChanged(const QDate &, const QDate &)), + mainWindow()->view(), SLOT(updateView(const QDate &, const QDate &)) ); +} + +Exchange::~Exchange() +{ + kdDebug(5850) << "Exchange Plugin destructor" << endl; +} + +QString Exchange::info() +{ + return i18n("This plugin imports and export calendar events from/to a Microsoft Exchange 2000 Server."); +} + +QString Exchange::shortInfo() +{ + return i18n("Exchange Plugin"); +} + +void Exchange::slotIncidenceSelected( Incidence *incidence ) +{ + emit enableIncidenceActions( incidence != 0 ); +} + +void Exchange::download() +{ + ExchangeDialog dialog( mainWindow()->view()->startDate(), mainWindow()->view()->endDate() ); + + if (dialog.exec() != QDialog::Accepted ) + return; + + QDate start = dialog.m_start->date(); + QDate end = dialog.m_end->date(); + + KCal::Calendar* calendar = mainWindow()->view()->calendar(); + + int result = mClient->downloadSynchronous(calendar, start, end, true ); + + if ( result == KPIM::ExchangeClient::ResultOK ) + emit calendarChanged(); + else + showError( result, mClient->detailedErrorString() ); + +} + +void Exchange::upload() +{ + kdDebug(5850) << "Called Exchange::upload()" << endl; + + Event* event = dynamic_cast<Event *> ( mainWindow()->view()->currentSelection() ); + if ( ! event ) + { + KMessageBox::information( 0L, i18n("Please select an appointment."), i18n("Exchange Plugin") ); + return; + } + if ( KMessageBox::warningContinueCancel( 0L, i18n("Exchange Upload is EXPERIMENTAL, you may lose data on this appointment!"), i18n("Exchange Plugin"), i18n("&Upload") ) + == KMessageBox::Continue ) { + kdDebug(5850) << "Trying to add appointment " << event->summary() << endl; + int result = mClient->uploadSynchronous( event ); + if ( result != KPIM::ExchangeClient::ResultOK ) + showError( result, mClient->detailedErrorString() ); + } +} + +void Exchange::remove() +{ + kdDebug(5850) << "Called Exchange::remove()" << endl; + + Event* event = dynamic_cast<Event *> ( mainWindow()->view()->currentSelection() ); + if ( ! event ) + { + KMessageBox::information( 0L, i18n("Please select an appointment."), i18n("Exchange Plugin") ); + return; + } + + if ( KMessageBox::warningContinueCancel( 0L, i18n("Exchange Delete is EXPERIMENTAL, if this is a recurring event it will delete all instances!"), i18n("Exchange Plugin"), KGuiItem(i18n("&Delete"),"editdelete") ) + == KMessageBox::Continue ) { + kdDebug(5850) << "Trying to delete appointment " << event->summary() << endl; + int result = mClient->removeSynchronous( event ); + + if ( result == KPIM::ExchangeClient::ResultOK ) { + mainWindow()->view()->calendar()->deleteEvent( event ); + emit calendarChanged(); + } else + showError( result, mClient->detailedErrorString() ); + } +} + +void Exchange::configure() +{ + kdDebug(5850) << "Exchange::configure" << endl; + ExchangeConfig dialog( mAccount ); + + if (dialog.exec() == QDialog::Accepted ) + mAccount->save( "Calendar/Exchange Plugin" ); +} + +void Exchange::showError( int error, const QString& moreInfo /* = QString::null */ ) +{ + QString errorText; + switch( error ) { + case KPIM::ExchangeClient::ResultOK: + errorText = i18n( "No Error" ); + break; + case KPIM::ExchangeClient::CommunicationError: + errorText = i18n( "The Exchange server could not be reached or returned an error." ); + break; + case KPIM::ExchangeClient::ServerResponseError: + errorText = i18n( "Server response could not be interpreted." ); + break; + case KPIM::ExchangeClient::IllegalAppointmentError: + errorText = i18n( "Appointment data could not be interpreted." ); + break; + case KPIM::ExchangeClient::NonEventError: + errorText = i18n( "This should not happen: trying to upload wrong type of event." ); + break; + case KPIM::ExchangeClient::EventWriteError: + errorText = i18n( "An error occurred trying to write an appointment to the server." ); + break; + case KPIM::ExchangeClient::DeleteUnknownEventError: + errorText = i18n( "Trying to delete an event that is not present on the server." ); + break; + case KPIM::ExchangeClient::UnknownError: + default: + errorText = i18n( "Unknown Error" ); + } + + if ( error != KPIM::ExchangeClient::ResultOK ) { + if ( moreInfo.isNull() ) + KMessageBox::error( mainWindow()->topLevelWidget(), errorText, i18n( "Exchange Plugin" ) ); + else + KMessageBox::detailedError( mainWindow()->topLevelWidget(), errorText, moreInfo, i18n( "Exchange Plugin" ) ); + } +} + +void Exchange::test() +{ + kdDebug(5850) << "Entering test()" << endl; + mClient->test(); +} + +void Exchange::test2() +{ + kdDebug(5850) << "Entering test2()" << endl; +} +#include "exchange.moc" diff --git a/korganizer/plugins/exchange/exchange.desktop b/korganizer/plugins/exchange/exchange.desktop new file mode 100644 index 000000000..121bf9863 --- /dev/null +++ b/korganizer/plugins/exchange/exchange.desktop @@ -0,0 +1,101 @@ +[Desktop Entry] +X-KDE-Library=libkorg_exchange +Name=Microsoft Exchange 2000 Plugin for KOrganizer +Name[af]=Microsoft Exchange 2000 inprop module vir KOrganizer +Name[be]=Дапаўненне K Арганізатара "Microsoft Exchange 2000" +Name[bg]=Приставка на организатора за връзка с Microsoft Exchange 2000 +Name[bs]=Microsoft Exchange 2000 dodatak za KOrganizer +Name[ca]=Endollable Microsoft Exchange 2000 per a KOrganizer +Name[cs]=Modul Microsoft Exchange 2000 pro KOrganizer +Name[da]=Microsoft Exchange 2000-plugin for KOrganizer +Name[de]=Microsoft Exchange 2000-Modul für KOrganizer +Name[el]=Πρόσθετο Microsoft Exchange 2000 του KOrganizer +Name[eo]=Microsoft Exchange 2000-kromaĵo por Organizilo +Name[es]=Accesorio de Microsoft Exchange 2000 para KOrganizer +Name[et]=Microsoft Exchange 2000 plugin KOrganizeri jaoks +Name[eu]=KOrganizer-en Microsoft Exchange 2000 plugin-a +Name[fa]=وصلۀ Microsoft Exchange ۲۰۰۰ برای KOrganizer +Name[fi]=KOrganizerin Microsoft Exchange 2000 -liitännäinen +Name[fr]=Module Microsoft Exchange 2000 pour KOrganizer +Name[fy]=Microsoft Exchange 2000 plugin foar KOrganizer +Name[ga]=Breiseán Microsoft Exchange 2000 le haghaidh KOrganizer +Name[gl]=Extensión de Microsoft Exchange 2000 para KOrganizer +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 +Name[mk]=Приклучок за КОрганизатор за Microsoft Exchange 2000 +Name[ms]=PLugin Microsoft Exchange 2000 untuk KOrganizer +Name[nb]=Microsoft Exchange 2000 programtillegg for KOrganizer +Name[nds]=MSExchange2000-Moduul för KOrganizer +Name[ne]=केडीई आयोजकका लागि माइक्रोसफ्ट एक्सचेन्ज 2000 +Name[nl]=Microsoft Exchange 2000 plugin voor KOrganizer +Name[nn]=Microsoft Exchange 2000 programtillegg for KOrganizer +Name[pl]=Wtyczka Microsoft Exchange 2000 dla Organizatora +Name[pt]='Plugin' do Microsoft Exchange 2000 para o KOrganizer +Name[pt_BR]=Plug-in do Microsoft Exchange 2000 para o KOrganizer +Name[ru]=Доступ к Microsoft Exchange 2000 +Name[sk]=KOrganizer modul pre Microsoft Exchange 2000 +Name[sl]=Vstavek za Microsoft Exchange 2000 za KOrganizer +Name[sr]=Прикључак KOrganizer-а за Microsoft Exchange 2000 +Name[sr@Latn]=Priključak KOrganizer-a za Microsoft Exchange 2000 +Name[sv]=Microsoft Exchange 2000-insticksprogram för Korganizer +Name[ta]=கேஅமைப்பாளருக்கான மைக்ரோசாஃப்ட் எக்ஸ்சேன்ஜ் 2000 சொருகுப்பொருள் +Name[tg]=Дастрасӣ ба Microsoft Exchange 2000 +Name[tr]=KOrganizer için Microsoft Exchange 2000 Eklentisi +Name[uk]=Втулок Microsoft Exchange 2000 для KOrganizer +Name[zh_CN]=KOrganizer 的 Microsoft Exchange 2000 插件 +Name[zh_TW]=KOrganizer 的 Microsoft Exchange 2000 外掛程式 +Comment=This plugin allows korganizer users to work with Microsoft Exchange 2000 groupware servers. +Comment[af]=Hierdie inprop module maak dit vir korganizer gebruikers moontlik om met Microsoft Exchange 2000 bedieners te praat. +Comment[bg]=Приставката служи за връзка на Korganizer със сървъра Microsoft Exchange 2000 groupware. +Comment[ca]=Aquest endollable permet als usuaris de korganizer treballar amb servidors groupware Microsoft Exchange 2000. +Comment[cs]=tento modul umožňuje pracovat uživatelům korganizeru s Microsoft Exchange 2000 groupware servery. +Comment[da]=Dette plugin tillader brugere af korganizer at arbejde med Microsoft Exchange 2000 groupware servere. +Comment[de]=Mit diesem Modul kann KOrganizer mit Microsoft Exchange 2000 Groupware-Servern zusammenarbeiten. +Comment[el]=Αυτό το πρόσθετο επιτρέπει στους χρήστες του korganizer να δουλεύουν με εξυπηρετητές groupware του Microsoft Exchange 2000. +Comment[es]=Esta extensión permite que los usuarios de korganizer trabajen con servidores de groupware de Microsoft Exchange 2000. +Comment[et]=See plugin võimaldab KOrganizeri kasutajatel pruukida Microsoft Exchange 2000 grupitööservereid. +Comment[eu]=Plugin honek korganizer-en erabiltzaileei Microsoft Exchange 2000 groupware zerbitzariekin lan egiteko aukera ematen die. +Comment[fa]=این وصله به کاربران korganizer اجازه میدهد که با کارسازهای Microsoft Exchange 2000 groupware کار کند. +Comment[fi]=Tämä liitännäinen mahdollistaa KOrganizer-käyttäjien työskentelemisen Microsoft Exchange 2000 -ryhmätyöpalvelimien kanssa. +Comment[fr]=Ce module permet à KOrganizer de fonctionner avec Microsoft Exchange 2000 +Comment[fy]=Dizze plugin makket it mooglik om Microsoft Exchange 2000 te brûken yn KOrganizer. +Comment[gl]=Este engadido permite que os usuarios de korganizer traballen con servidores de traballo en grupo Microsoft Exchange 2000 +Comment[hu]=Ez a modul lehetővé teszi KOrganizer-felhasználóknak Microsoft Exchange 2000-kiszolgálón tárolt csoportmunka-adatok elérését. +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. +Comment[mk]=Овој приклучок им овозможува на корисниците на КОрганизатор да работат со groupware-серверите на Microsoft Exchange 2000. +Comment[ms]=Plugin ini membenarkan pengguna korganizer bekerja bersama pelayan groupware Microsoft Exchange 2000. +Comment[nb]=Med dette programtillegget kan korganizer-brukere arbeide med gruppevare-tjenere fra Microsoft Exchange 2000.i +Comment[nds]=Över dit Moduul köönt KOrganizer-Brukers mit Groupware-Servers för MSExchange-2000 arbeiden. +Comment[ne]=यो प्लगइनले माइक्रोसफ्ट एक्सचेन्ज 2000 ग्रुपवेयर सर्भरमा केडीई आयोजकलाई कार्य गर्न अनुमति दिन्छ । +Comment[nl]=Deze plugin maakt het mogelijk om Microsoft Exchange 2000 te gebruiken in KOrganizer. +Comment[nn]=Dette programtillegget lèt KOrganizer-brukarar arbeida saman med Microsoft Exchange 2000-gruppevaretenarar. +Comment[pl]=Ta wtyczka pozwala KOrganizerowi współpracować z serwerami pracy grupowej Microsoft Exchange. +Comment[pt]=Este 'plugin' permite aos utilizadores do KOrganizer lidarem com servidores de 'groupware' do Microsoft Exchange 2000. +Comment[pt_BR]=Esse plug-in permite que o KOrganizer conecte-se à servidores groupware Microsoft Exchance 2000 +Comment[ru]=Этот модуль позволяет пользователям органайзера работать с серверами совместной работы Microsoft Exchange 2000. +Comment[sk]=Tento modul umožní, aby korganizer užívatelia pracovali s Microsoft Exchange 2000 groupware servermi. +Comment[sl]=Ta vstavke omogoča uporabnikom KOrganizerja delo s strežniki Microsoft Exchange 2000. +Comment[sr]=Овај прикључак омогућава корисницима KOrganizer-а да раде са Microsoft-овим Exchange 2000 groupware серверима. +Comment[sr@Latn]=Ovaj priključak omogućava korisnicima KOrganizer-a da rade sa Microsoft-ovim Exchange 2000 groupware serverima. +Comment[sv]=Insticksprogrammet gör det möjligt för användare av Korganizer att arbeta med Microsoft Exchange 2000 grupprogramservrar. +Comment[ta]=இந்த சொருகுப்பொருள் korganizer பயனர்களை மைக்ரோசாப்ட் எக்ஸ்சேஞ்ச் 2000 குழுவாரி சேவகன்களில் பணி செய்ய அனுமதிக்கிறது. +Comment[tr]=Bu eklenti KOrganizer kullanıcılarının Microsoft Exchange 2000 sunucuları ile çalışabilmelerini sağlar. +Comment[uk]=Цей втулок дозволяє користувачам korganizer працювати з серверами групової роботи Microsoft Exchange 2000. +Comment[zh_CN]=此插件允许 KOrganizer 用户与 Microsoft Exchange 2000 群件服务器协同工作。 +Comment[zh_TW]=這個外掛程式允許 KOrganizer 使用者與 Microsoft Exchange 2000 群組伺服器一起工作。 +Type=Service +ServiceTypes=KOrganizer/Part +X-KDE-KOrganizer-HasSettings=false +X-KDE-PluginInterfaceVersion=2 diff --git a/korganizer/plugins/exchange/exchange.h b/korganizer/plugins/exchange/exchange.h new file mode 100644 index 000000000..a145bd12f --- /dev/null +++ b/korganizer/plugins/exchange/exchange.h @@ -0,0 +1,68 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2002 Jan-Pascal van Best <janpascal@vanbest.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 KORG_EXCHANGE_H +#define KORG_EXCHANGE_H + +#include <qstring.h> +#include <qdatetime.h> + +#include <korganizer/part.h> + +#include <libkcal/incidence.h> +#include <libkcal/event.h> + +#include <exchangeaccount.h> +#include <exchangeclient.h> + +// using namespace KOrg; +using namespace KCal; + +class Exchange : public KOrg::Part { + Q_OBJECT + public: + Exchange( KOrg::MainWindow *, const char *name ); + ~Exchange(); + + QString info(); + // This method is used for the category of the key bindings + QString shortInfo(); + + signals: + void enableIncidenceActions( bool ); + void calendarChanged(); + void calendarChanged(const QDate&start,const QDate&end); + + private slots: + void download(); + void upload(); + void remove(); + void configure(); + void test(); + void slotIncidenceSelected( Incidence * ); + + private: + void test2(); + void showError( int error, const QString& moreInfo = QString::null ); + + KPIM::ExchangeClient *mClient; + KPIM::ExchangeAccount* mAccount; +}; + +#endif + diff --git a/korganizer/plugins/exchange/exchangeconfig.cpp b/korganizer/plugins/exchange/exchangeconfig.cpp new file mode 100644 index 000000000..e75265caa --- /dev/null +++ b/korganizer/plugins/exchange/exchangeconfig.cpp @@ -0,0 +1,135 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2002 Jan-Pascal van Best <janpascal@vanbest.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 <qlayout.h> +#include <qlabel.h> +#include <qcombobox.h> + +#include <kapplication.h> +#include <kconfig.h> +#include <klocale.h> +#include <kdebug.h> +#include <kmessagebox.h> + +#include <exchangeaccount.h> + +#include "exchangeconfig.h" + +ExchangeConfig::ExchangeConfig( KPIM::ExchangeAccount* account, QWidget* parent ) + : KDialogBase(Plain,i18n("Exchange Plugin"),Ok|Cancel,Ok,parent) +{ + mAccount = account; + + kdDebug(5850) << "Creating ExchangeConfig with account: " << + account->host() << ":" << account->account() << endl; + + QFrame *topFrame = plainPage(); + QGridLayout *topLayout = new QGridLayout( topFrame, 5, 3, 3 ); + + m_host = new KLineEdit( mAccount->host(), topFrame ); + topLayout->addWidget( new QLabel( i18n( "Exchange server:" ), topFrame ), 0, 0 ); + topLayout->addWidget( m_host, 0, 1 ); + + m_port = new KLineEdit( mAccount->port(), topFrame ); + topLayout->addWidget( new QLabel( i18n( "Port:" ), topFrame ), 1, 0 ); + topLayout->addWidget( m_port, 1, 1 ); + + m_user = new KLineEdit( mAccount->account(), topFrame ); + topLayout->addWidget( new QLabel( i18n( "User:" ), topFrame ), 2, 0 ); + topLayout->addWidget( m_user, 2, 1 ); + connect( m_user, SIGNAL(textChanged(const QString&)), this, SLOT(slotUserChanged(const QString&)) ); + + m_password = new KLineEdit( mAccount->password(), topFrame ); + topLayout->addWidget( new QLabel( i18n( "Password:" ), topFrame ), 3, 0 ); + topLayout->addWidget( m_password, 3, 1 ); + m_password->setEchoMode( QLineEdit::Password ); + + m_autoMailbox = new QCheckBox( i18n( "Determine mailbox automatically" ), topFrame ); + topLayout->addMultiCellWidget( m_autoMailbox, 4, 4, 0, 1 ); + connect( m_autoMailbox, SIGNAL(toggled(bool)), this, SLOT(slotToggleAuto(bool)) ); + + m_mailbox= new KLineEdit( mAccount->mailbox(), topFrame ); + topLayout->addWidget( new QLabel( i18n( "Mailbox URL:" ), topFrame ), 5, 0 ); + topLayout->addWidget( m_mailbox, 5, 1 ); + + m_tryFindMailbox = new QPushButton( "&Find", topFrame ); + topLayout->addWidget( m_tryFindMailbox, 5, 2 ); + connect( m_tryFindMailbox, SIGNAL(clicked()), this, SLOT(slotFindClicked()) ); + + kapp->config()->setGroup( "Calendar/Exchange Plugin" ); + bool autoChecked = kapp->config()->readBoolEntry( "auto-mailbox", true ); + m_autoMailbox->setChecked( autoChecked ); +} + +ExchangeConfig::~ExchangeConfig() +{ +} + +void ExchangeConfig::slotToggleAuto( bool on ) +{ + m_mailbox->setEnabled( ! on ); +// m_tryFindMailbox->setEnabled( ! on ); +// if ( on ) { +// m_mailbox->setText( "webdav://" + m_host->text() + "/exchange/" + m_user->text() ); +// } +} + +void ExchangeConfig::slotUserChanged( const QString& /*text*/ ) +{ +// if ( m_mailboxEqualsUser->isChecked() ) { +// m_mailbox->setText( "webdav://" + m_host->text() + "/exchange/" + text ); +// } +} + +void ExchangeConfig::slotOk() +{ + if ( m_autoMailbox->isChecked() ) { + QString mailbox = mAccount->tryFindMailbox( m_host->text(), m_port->text(), m_user->text(), m_password->text() ); + if ( mailbox.isNull() ) { + kdWarning() << "Could not find Exchange mailbox URL, incomplete settings!"<< endl; + KMessageBox::sorry( this, "Could not determine mailbox URL" ); + return; // Do not accept + } else { + mAccount->setMailbox( mailbox ); + } + } else { + mAccount->setMailbox( m_mailbox->text() ); + } + mAccount->setHost( m_host->text() ); + mAccount->setPort( m_port->text() ); + mAccount->setAccount( m_user->text() ); + mAccount->setPassword( m_password->text() ); + + kapp->config()->setGroup( "Calendar/Exchange Plugin" ); + kapp->config()->writeEntry( "auto-mailbox", m_autoMailbox->isChecked() ); + + accept(); +} + +void ExchangeConfig::slotFindClicked() +{ + QString mailbox = mAccount->tryFindMailbox( m_host->text(), m_port->text(), m_user->text(), m_password->text() ); + if ( mailbox.isNull() ) { + KMessageBox::sorry( this, "Could not determine mailbox URL" ); + } else { + m_mailbox->setText( mailbox ); + } +} + +#include "exchangeconfig.moc" diff --git a/korganizer/plugins/exchange/exchangeconfig.h b/korganizer/plugins/exchange/exchangeconfig.h new file mode 100644 index 000000000..ba974ba26 --- /dev/null +++ b/korganizer/plugins/exchange/exchangeconfig.h @@ -0,0 +1,60 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2002 Jan-Pascal van Best <janpascal@vanbest.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 EXCHANGECONFIG_H +#define EXCHANGECONFIG_H + +#include <qcheckbox.h> +#include <qpushbutton.h> +#include <kdialogbase.h> +#include <klineedit.h> +//#include <kpassdlg.h> + +#include <exchangeaccount.h> + +class ExchangeConfig : public KDialogBase +{ + Q_OBJECT + public: + ExchangeConfig(KPIM::ExchangeAccount* account, QWidget *parent=0); + virtual ~ExchangeConfig(); + +// protected: +// void load(); +// void save(); + + protected slots: + void slotToggleAuto( bool on ); + void slotUserChanged( const QString& text ); + void slotFindClicked(); + void slotOk(); + + private: + public: + KPIM::ExchangeAccount* mAccount; + KLineEdit *m_host; + KLineEdit *m_port; + KLineEdit *m_user; + QCheckBox *m_autoMailbox; + KLineEdit *m_mailbox; + QPushButton* m_tryFindMailbox; + KLineEdit *m_password; +}; + +#endif + diff --git a/korganizer/plugins/exchange/exchangedialog.cpp b/korganizer/plugins/exchange/exchangedialog.cpp new file mode 100644 index 000000000..249b07a91 --- /dev/null +++ b/korganizer/plugins/exchange/exchangedialog.cpp @@ -0,0 +1,58 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2002 Jan-Pascal van Best <janpascal@vanbest.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 <qlayout.h> +#include <qlabel.h> +#include <qcombobox.h> + +#include <klocale.h> +#include <kmessagebox.h> +#include <kapplication.h> +#include <kglobal.h> +#include <kstandarddirs.h> +#include <ksimpleconfig.h> + +#include "exchangedialog.h" + +ExchangeDialog::ExchangeDialog( const QDate &_start, const QDate &_end, QWidget *parent) + : KDialogBase(Plain,i18n("Exchange Plugin"),Ok|Cancel,Ok,parent) +{ + QFrame *topFrame = plainPage(); + QGridLayout *topLayout = new QGridLayout( topFrame, 2, 2, 3 ); + + QLabel *label = new QLabel(i18n("Start date:"),topFrame); + topLayout->addWidget(label, 0, 0); + + m_start = new KDateWidget( _start, topFrame ); + topLayout->addWidget( m_start, 0, 1 ); + + m_end = new KDateWidget( _end, topFrame ); + topLayout->addWidget( new QLabel( i18n( "End date:" ), topFrame ), 1, 0 ); + topLayout->addWidget( m_end, 1, 1 ); +} + +ExchangeDialog::~ExchangeDialog() +{ +} + +void ExchangeDialog::slotOk() +{ + accept(); +} +#include "exchangedialog.moc" diff --git a/korganizer/plugins/exchange/exchangedialog.h b/korganizer/plugins/exchange/exchangedialog.h new file mode 100644 index 000000000..440d48fd9 --- /dev/null +++ b/korganizer/plugins/exchange/exchangedialog.h @@ -0,0 +1,43 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2002 Jan-Pascal van Best <janpascal@vanbest.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 EXCHANGEDIALOG_H +#define EXCHANGEDIALOG_H + +#include <kdialogbase.h> +#include <kdatewidget.h> + +class QComboBox; + +class ExchangeDialog : public KDialogBase +{ + Q_OBJECT + public: + ExchangeDialog( const QDate &start, const QDate &end, QWidget *parent=0); + virtual ~ExchangeDialog(); + + protected slots: + void slotOk(); + + private: + public: + KDateWidget *m_start; + KDateWidget *m_end; +}; + +#endif diff --git a/korganizer/plugins/exchange/exchangeui.rc b/korganizer/plugins/exchange/exchangeui.rc new file mode 100644 index 000000000..b1caad16b --- /dev/null +++ b/korganizer/plugins/exchange/exchangeui.rc @@ -0,0 +1,13 @@ +<!DOCTYPE kpartgui> +<kpartgui name="exchange" version="1"> + + <MenuBar> + <Menu name="exchange"><text>Exchange</text> + <Action name="exchange_download" /> + <Action name="exchange_upload" /> + <Action name="exchange_delete" /> + <Action name="exchange_configure" /> + </Menu> + </MenuBar> + +</kpartgui> diff --git a/korganizer/plugins/hebrew/Makefile.am b/korganizer/plugins/hebrew/Makefile.am new file mode 100644 index 000000000..4f48cc58b --- /dev/null +++ b/korganizer/plugins/hebrew/Makefile.am @@ -0,0 +1,16 @@ +# $Id$ + +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/korganizer/interfaces $(all_includes) + +kde_module_LTLIBRARIES = libkorg_hebrew.la + +libkorg_hebrew_la_SOURCES = hebrew.cpp configdialog.cpp holiday.cpp parsha.cpp converter.cpp +libkorg_hebrew_la_LDFLAGS = -module $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) +libkorg_hebrew_la_LIBADD = $(LIB_KDECORE) $(LIB_KDEUI) + +noinst_HEADERS = hebrew.h configdialog.h parsha.h converter.h holiday.h + +servicedir = $(kde_servicesdir)/korganizer +service_DATA = hebrew.desktop diff --git a/korganizer/plugins/hebrew/README b/korganizer/plugins/hebrew/README new file mode 100644 index 000000000..297df67fb --- /dev/null +++ b/korganizer/plugins/hebrew/README @@ -0,0 +1,12 @@ +Jewish calendar plugin for KOrganizer, by Jonathan Singer <jsinger@leeta.net> + +Note that it only applies to modern (Gregorian) dates, as KDE/Qt does not +support Julian dates. See my KLuach application <http://www.leeta.net/kluach> +if you want to look up historical dates. + +TRANSLATORS! The weird-looking text strings are the names of Jewish months, +holidays and whatnot. They aren't translateable (although European or Near +Eastern languages may spell them differently) and should usually just be changed +into local characters with the same sound. "I" and "II" are Roman numerals. + +Date routines from Jewish Calendar by Frank Yellin diff --git a/korganizer/plugins/hebrew/configdialog.cpp b/korganizer/plugins/hebrew/configdialog.cpp new file mode 100644 index 000000000..aad50a680 --- /dev/null +++ b/korganizer/plugins/hebrew/configdialog.cpp @@ -0,0 +1,91 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2003 Jonathan Singer <jsinger@leeta.net> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public 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 "configdialog.h" +#include "configdialog.moc" +#include <klocale.h> +#include <qlayout.h> +#include <kapplication.h> +#include <kglobal.h> +#include <kconfig.h> +#include <kstandarddirs.h> +#include <ksimpleconfig.h> + +ConfigDialog::ConfigDialog(QWidget * parent):KDialogBase(Plain, i18n("Configure Holidays"), Ok|Cancel, Ok, + parent) +{ + QFrame *topFrame = plainPage(); + QVBoxLayout *topLayout = + new QVBoxLayout(topFrame, 0, spacingHint()); + + israel_box = new QCheckBox(topFrame); + israel_box->setText(i18n("Use Israeli holidays")); + topLayout->addWidget(israel_box); + + parsha_box = new QCheckBox(topFrame); + parsha_box->setText(i18n("Show weekly parsha")); + topLayout->addWidget(parsha_box); + + omer_box = new QCheckBox(topFrame); + omer_box->setText(i18n("Show day of Omer")); + topLayout->addWidget(omer_box); + + chol_box = new QCheckBox(topFrame); + chol_box->setText(i18n("Show Chol HaMoed")); + topLayout->addWidget(chol_box); + + load(); +} + +ConfigDialog::~ConfigDialog() +{ +} + +void ConfigDialog::load() +{ + KConfig config("korganizerrc", true, false); // Open read-only, no kdeglobals + + config.setGroup("Calendar/Hebrew Calendar Plugin"); + israel_box->setChecked(config. + readBoolEntry("Israel", + (KGlobal::locale()-> + country() == ".il"))); + parsha_box->setChecked(config.readBoolEntry("Parsha", true)); + chol_box->setChecked(config.readBoolEntry("Chol_HaMoed", true)); + omer_box->setChecked(config.readBoolEntry("Omer", true)); + +} + +void ConfigDialog::save() +{ + KConfig config("korganizerrc", false, false); // Open read-write, no kdeglobals + + config.setGroup("Calendar/Hebrew Calendar Plugin"); + config.writeEntry("Israel", israel_box->isChecked()); + config.writeEntry("Parsha", parsha_box->isChecked()); + config.writeEntry("Chol_HaMoed", chol_box->isChecked()); + config.writeEntry("Omer", omer_box->isChecked()); + config.sync(); +} + +void ConfigDialog::slotOk() +{ + save(); + + accept(); +} diff --git a/korganizer/plugins/hebrew/configdialog.h b/korganizer/plugins/hebrew/configdialog.h new file mode 100644 index 000000000..1d0d18115 --- /dev/null +++ b/korganizer/plugins/hebrew/configdialog.h @@ -0,0 +1,49 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2003 Jonathan Singer <jsinger@leeta.net> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public 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 CONFIGDIALOG_H +#define CONFIGDIALOG_H + +#include <kdialogbase.h> +#include <qcheckbox.h> + +/** +@author Jonathan Singer +*/ +class ConfigDialog:public KDialogBase +{ +Q_OBJECT public: + + ConfigDialog(QWidget * parent = 0); + virtual ~ ConfigDialog(); + +protected: + void load(); + void save(); + + protected slots: void slotOk(); + +private: + QCheckBox * omer_box; + QCheckBox *parsha_box; + QCheckBox *israel_box; + QCheckBox *chol_box; + +}; + +#endif diff --git a/korganizer/plugins/hebrew/converter.cpp b/korganizer/plugins/hebrew/converter.cpp new file mode 100644 index 000000000..1381292e6 --- /dev/null +++ b/korganizer/plugins/hebrew/converter.cpp @@ -0,0 +1,345 @@ +/*************************************************************************** + * Copyright (C) 2003 by Jonathan Singer * + * jsinger@leeta.net * + * Calendar routines from Hebrew Calendar by Frank Yellin * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "converter.h" +#include <klocale.h> + +Converter::Converter() +{ + +} + +Converter::~Converter() +{ +} + +long Converter::absolute_from_gregorian(int year, int month, int day) +{ + int xyear, day_number; + + xyear = year - 1; + day_number = day + 31 * (month - 1); + if (month > 2) + { + day_number -= (23 + (4 * month)) / 10; + if (gregorian_leap_year_p(year)) + day_number++; + } + return day_number + /* the day number within the current year */ + 365L * xyear + /* days in prior years */ + (xyear / 4) + /* Julian leap years */ + (-(xyear / 100)) + /* deduct century years */ + (xyear / 400); /* add Gregorian leap years */ +} + +/* Given a Hebrew date, calculate the number of days since + * January 0, 0001, Gregorian + */ +long Converter::absolute_from_hebrew(int year, int month, int day) +{ + long sum = day + hebrew_elapsed_days(year) - 1373429L; + int i; + + if (month < 7) + { + int months = hebrew_months_in_year(year); + + for (i = 7; i <= months; ++i) + sum += hebrew_month_length(year, i); + for (i = 1; i < month; ++i) + sum += hebrew_month_length(year, i); + } + else + { + for (i = 7; i < month; ++i) + sum += hebrew_month_length(year, i); + } + return sum; +} + +/* Given an absolute date, calculate the gregorian date */ +void + Converter::gregorian_from_absolute(long date, int *yearp, + int *monthp, int *dayp) +{ + int year, month, day; + + for (year = date / 366; + date >= absolute_from_gregorian(year + 1, 1, 1); ++year) ; + for (month = 1; + (month <= 11) + && (date >= absolute_from_gregorian(year, 1 + month, 1)); + ++month ) ; + day = 1 + date - absolute_from_gregorian(year, month, 1); + *yearp = year; + *monthp = month; + *dayp = day; +} + +/* Given an absolute date, calculate the Hebrew date */ +void + Converter::hebrew_from_absolute(long date, int *yearp, int *monthp, + int *dayp) +{ + int year, month, day, gyear, gmonth, gday, months; + + gregorian_from_absolute(date, &gyear, &gmonth, &gday); + year = gyear + 3760; + while (date >= absolute_from_hebrew(1 + year, 7, 1)) + year++; + months = hebrew_months_in_year(year); + for (month = 7; + date > absolute_from_hebrew(year, month, + hebrew_month_length(year, month)); + month = 1 + (month % months)) ; + day = 1 + date - absolute_from_hebrew(year, month, 1); + *yearp = year; + *monthp = month; + *dayp = day; +} + +/* Number of months in a Hebrew year */ +int Converter::hebrew_months_in_year(int year) +{ + if (hebrew_leap_year_p(year)) + return 13; + else + return 12; +} + +enum +{ Nissan = + 1, Iyar, Sivan, Tamuz, Ab, Elul, Tishrei, Cheshvan, Kislev, Tevet, + Shvat, Adar, AdarII, AdarI = 12 +}; + +enum +{ January = + 1, February, March, April, May, June, July, August, September, + October, November, December +}; + +/* Number of days in a Hebrew month */ +int Converter::hebrew_month_length(int year, int month) +{ + switch (month) + { + case Tishrei: + case Shvat: + case Nissan: + case Sivan: + case Ab: + return 30; + + case Tevet: + case Iyar: + case Tamuz: + case Elul: + case AdarII: + return 29; + + case Cheshvan: + // 29 days, unless it's a long year. + if ((hebrew_year_length(year) % 10) == 5) + return 30; + else + return 29; + + case Kislev: + // 30 days, unless it's a short year. + if ((hebrew_year_length(year) % 10) == 3) + return 29; + else + return 30; + + case Adar: + // Adar (non-leap year) has 29 days. Adar I has 30 days. + if (hebrew_leap_year_p(year)) + return 30; + else + return 29; + + default: + return 0; + } +} + +/* Number of days in a Julian or gregorian month */ +int + Converter::secular_month_length(int year, + int month /*, bool julianp */ ) +{ + switch (month) + { + case January: + case March: + case May: + case July: + case August: + case October: + case December: + return 31; + case April: + case June: + case September: + case November: + return 30; + case February: + if (gregorian_leap_year_p(year)) + return 29; + else + return 28; + default: + return 0; + } +} + +/* Is it a Leap year in the gregorian calendar */ +bool Converter::gregorian_leap_year_p(int year) +{ + if ((year % 4) != 0) + return 0; + if ((year % 400) == 0) + return 1; + if ((year % 100) == 0) + return 0; + return 1; +} + +/* Is it a leap year in the Jewish Calendar */ +bool Converter::hebrew_leap_year_p(int year) +{ + switch (year % 19) + { + case 0: + case 3: + case 6: + case 8: + case 11: + case 14: + case 17: + return 1; + default: + return 0; + } +} + +/* Return the number of days from 1 Tishrei 0001 to the beginning of the given year. + * Since this routine gets called frequently with the same year arguments, we cache + * the most recent values. + */ +#define MEMORY 5 +long Converter::hebrew_elapsed_days(int year) +{ + static int saved_year[MEMORY] = { -1, -1, -1, -1, -1 }; + static long saved_value[MEMORY]; + int i; + + for (i = 0; i < MEMORY; ++i) + if (year == saved_year[i]) + return saved_value[i]; + for (i = 0; i < MEMORY-1; ++i) { + saved_year[i] = saved_year[1 + i]; + saved_value[i] = saved_value[1 + i]; + } + saved_year[MEMORY - 1] = year; + saved_value[MEMORY - 1] = hebrew_elapsed_days2(year); + return saved_value[MEMORY - 1]; +} + +long Converter::hebrew_elapsed_days2(int year) +{ + long prev_year = year - 1; + long months_elapsed = 235L * (prev_year / 19) /* months in complete cycles so far */ + + 12L * (prev_year % 19) /* regular months in this cycle */ + + (((prev_year % 19) * 7 + 1) / 19); /* leap months this cycle */ + long parts_elapsed = 5604 + 13753 * months_elapsed; + long day = 1 + 29 * months_elapsed + parts_elapsed / 25920; + long parts = parts_elapsed % 25920; + int weekday = (day % 7); + long alt_day = ((parts >= 19440) + || (weekday == 2 && (parts >= 9924) + && !hebrew_leap_year_p(year)) || (weekday == 1 + && (parts >= + 16789) + && + hebrew_leap_year_p + (prev_year))) + ? day + 1 : day; + switch (alt_day % 7) + { + case 0: + case 3: + case 5: + return 1 + alt_day; + default: + return alt_day; + } +} + +/* Number of days in the given Hebrew year */ +int Converter::hebrew_year_length(int year) +{ + return hebrew_elapsed_days(1 + year) - hebrew_elapsed_days(year); +} + +/* Fill in the DateResult structure based on the given secular date */ +void + Converter::SecularToHebrewConversion(int syear, int smonth, + int sday, + struct DateResult *result) +{ + int hyear, hmonth, hday; + long absolute; + + absolute = absolute_from_gregorian(syear, smonth, sday); + + hebrew_from_absolute(absolute, &hyear, &hmonth, &hday); + + result->year = hyear; + result->month = hmonth; + result->day = hday; + finish_up(absolute, hyear, hmonth, syear, smonth, result); +} + +/* Fill in the DateResult structure based on the given Hebrew date */ +void + Converter::HebrewToSecularConversion(int hyear, int hmonth, + int hday, + struct DateResult *result) +{ + int syear, smonth, sday; + long absolute; + + absolute = absolute_from_hebrew(hyear, hmonth, hday); + gregorian_from_absolute(absolute, &syear, &smonth, &sday); + result->year = hyear; + result->month = hmonth; + result->day = hday; + finish_up(absolute, hyear, hmonth, syear, smonth, result); +} + +/* This is common code for filling up the DateResult structure */ +void + Converter::finish_up(long absolute, int hyear, int hmonth, + int syear, int smonth, + struct DateResult *result) +{ + result->hebrew_month_length = hebrew_month_length(hyear, hmonth); + result->secular_month_length = secular_month_length(syear, smonth); + result->hebrew_leap_year_p = hebrew_leap_year_p(hyear); + result->secular_leap_year_p = gregorian_leap_year_p(syear); + result->kvia = (hebrew_year_length(hyear) % 10) - 3; + // absolute is -1 on 1/1/0001 Julian + result->day_of_week = (7 + absolute) % 7; + result->hebrew_day_number = + absolute - absolute_from_hebrew(hyear, 7, 1) + 1; + +} diff --git a/korganizer/plugins/hebrew/converter.h b/korganizer/plugins/hebrew/converter.h new file mode 100644 index 000000000..8a3bc8baf --- /dev/null +++ b/korganizer/plugins/hebrew/converter.h @@ -0,0 +1,75 @@ +/*************************************************************************** + * Copyright (C) 2003 by Jonathan Singer * + * jsinger@leeta.net * + * Calendar routines from Hebrew Calendar by Frank Yellin * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef CONVERTER_H +#define CONVERTER_H + +#include <qstring.h> +#include <qstringlist.h> + +struct DateResult +{ + int year; + int month; + int day; + int day_of_week; + + int hebrew_month_length, secular_month_length; + bool hebrew_leap_year_p, secular_leap_year_p; + int kvia; + int hebrew_day_number; +}; + +/** +@author Jonathan Singer +*/ +class Converter +{ +public: + + Converter(); + ~Converter(); + + static bool hebrew_leap_year_p(int year); + static bool gregorian_leap_year_p(int year); + + static long absolute_from_gregorian(int year, int month, int day); + static long absolute_from_hebrew(int year, int month, int day); + + static void gregorian_from_absolute(long date, int *yearp, + int *monthp, int *dayp); + static void hebrew_from_absolute(long date, int *yearp, int *monthp, + int *dayp); + + static int hebrew_months_in_year(int year); + static int hebrew_month_length(int year, int month); + static int secular_month_length(int year, int month); + + static long hebrew_elapsed_days(int year); + static long hebrew_elapsed_days2(int year); + static int hebrew_year_length(int year); + + static void finish_up(long absolute, int hyear, int hmonth, + int syear, int smonth, + struct DateResult *result); + + static void SecularToHebrewConversion(int year, int month, int day, + struct DateResult *result); + static void HebrewToSecularConversion(int year, int month, int day, + struct DateResult *result); + +private: + + static QStringList HebrewMonthNames; + static QStringList SecularMonthNames; + +}; + +#endif diff --git a/korganizer/plugins/hebrew/hebrew.cpp b/korganizer/plugins/hebrew/hebrew.cpp new file mode 100644 index 000000000..4c557d00d --- /dev/null +++ b/korganizer/plugins/hebrew/hebrew.cpp @@ -0,0 +1,112 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2003 Jonathan Singer <jsinger@leeta.net> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public 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 <kglobal.h> +#include <kconfig.h> +#include <kstandarddirs.h> +#include <ksimpleconfig.h> +#include <kcalendarsystem.h> +#include <kcalendarsystemfactory.h> +#include "hebrew.h" +#include "configdialog.h" +#include "parsha.h" +#include "converter.h" +#include "holiday.h" + +bool Hebrew::IsraelP; + +class HebrewFactory:public CalendarDecorationFactory +{ +public: + CalendarDecoration * create() + { + return new Hebrew; + } +}; + +K_EXPORT_COMPONENT_FACTORY( libkorg_hebrew, HebrewFactory ) + + +QString Hebrew::shortText(const QDate & date) +{ + + KConfig config("korganizerrc", true, false); // Open read-only, no kdeglobals + + config.setGroup("Calendar/Hebrew Calendar Plugin"); + IsraelP = + config.readBoolEntry("Israel", + (KGlobal::locale()->country() == ".il")); + Holiday::ParshaP = config.readBoolEntry("Parsha", true); + Holiday::CholP = config.readBoolEntry("Chol_HaMoed", true); + Holiday::OmerP = config.readBoolEntry("Omer", true); + QString *label_text = new QString(); + + int day = date.day(); + int month = date.month(); + int year = date.year(); + + // core calculations!! + struct DateResult result; + + Converter::SecularToHebrewConversion(year, month, day, /*0, */ + &result); + int hebrew_day = result.day; + int hebrew_month = result.month; + int hebrew_year = result.year; + int hebrew_day_of_week = result.day_of_week; + bool hebrew_leap_year_p = result.hebrew_leap_year_p; + int hebrew_kvia = result.kvia; + int hebrew_day_number = result.hebrew_day_number; + + QStringList holidays = + Holiday::FindHoliday(hebrew_month, hebrew_day, + hebrew_day_of_week + 1, hebrew_kvia, + hebrew_leap_year_p, IsraelP, + hebrew_day_number, hebrew_year); + + KCalendarSystem *cal = KCalendarSystemFactory::create("hebrew"); + *label_text = QString("%1 %2").arg(cal->dayString(date, false)) + .arg(cal->monthName(date)); + + if (holidays.count()) + { + int count = holidays.count(); + + for (int h = 0; h <= count; ++h) + { + *label_text += "\n" + holidays[h]; + } + } + + return *label_text; +} + +QString Hebrew::info() +{ + return + i18n("This plugin provides the date in the Jewish calendar."); +} + +void Hebrew::configure(QWidget * parent) +{ + ConfigDialog *dlg = new ConfigDialog(parent); //parent? + + dlg->exec(); + delete dlg; +} diff --git a/korganizer/plugins/hebrew/hebrew.desktop b/korganizer/plugins/hebrew/hebrew.desktop new file mode 100644 index 000000000..86c88328d --- /dev/null +++ b/korganizer/plugins/hebrew/hebrew.desktop @@ -0,0 +1,101 @@ +[Desktop Entry] +X-KDE-Library=libkorg_hebrew +Name=Jewish Calendar Plugin +Name[af]=Joodse kalender inprop module +Name[bg]=Приставка за еврейския календар +Name[br]=Lugent deiziadur yudev +Name[bs]=Dodatak za hebrejski kalendar +Name[ca]=Endollable de calendari jueu +Name[cs]=Modul židovského kalendáře +Name[da]=Jødisk kalender-plugin +Name[de]=Modul für jüdischen Kalender +Name[el]=Πρόσθετο εβραϊκού ημερολογίου +Name[eo]=Judkalendar-kromaĵo +Name[es]=Accesorio de calendario judío +Name[et]=Juudi kalendri plugin +Name[eu]=Egutegi judutar plugin-a +Name[fa]=وصلۀ تقویم یهودی +Name[fi]=Juutalaisen kalenterin laajennus +Name[fr]=Module de prise en charge du calendrier juif +Name[fy]=Joadske kalenderplugin +Name[gl]=Extensión para Calendario Xudeu +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 +Name[mk]=Приклучок за еврејски календар +Name[ms]=PLugin Kalender Yahudi +Name[nb]=Programtillegg for jødisk kalender +Name[nds]=Moduul för juudschen Kalenner +Name[ne]=यहूदि क्यालेन्डर प्लगइन +Name[nl]=Joodse kalenderplugin +Name[nn]=Programtillegg for jødisk kalender +Name[pl]=Wtyczka kalendarza żydowskiego +Name[pt]='Plugin' do Calendário Judeu +Name[pt_BR]=Plug-in de Calendário Judaico +Name[ru]=Еврейский календарь +Name[sk]=Modul Židovského kalendára +Name[sl]=Vstavek za židovski koledar +Name[sr]=Прикључак календара за јеврејски календар +Name[sr@Latn]=Priključak kalendara za jevrejski kalendar +Name[sv]=Insticksprogram för judisk kalender +Name[ta]=ஜூவிஷ் நாள்காட்டி சொருகுப்பொருள் +Name[tg]=Тақвимоти яҳудӣ +Name[tr]=İbrani Takvimi Eklentisi +Name[uk]=Втулок єврейського календаря +Name[zh_CN]=犹太教日历插件 +Name[zh_TW]=猶太行事曆外掛程式 +Comment=Shows all dates in korganizer also in the Jewish calendar system. +Comment[af]=Vertoon alle datums in KOrganizer ook volgens die Joodse kalender. +Comment[bg]=Приставката служи за показване на датите според еврейския календар. +Comment[ca]=Mostra totes les dates del korganizer també en el sistema del calendari jueu. +Comment[cs]=Zobrazení všech dat v korganizeru také v židovském kalendáři. +Comment[da]=Viser alle datoer i korganizer også i det jødiske kalendersystem. +Comment[de]=Zeigt alle Daten in KOrganizer auch im jüdischen Kalendarium an. +Comment[el]=Εμφανίζει όλες τις ημερομηνίες στο korganizer και στο εβραϊκό ημερολογιακό σύστημα. +Comment[es]=Muestra todas las fechas de korganizer también en el sistema de calendario judío. +Comment[et]=Näitab KOrganizeris kõiki kuupäevi ka juudi kalendri järgi. +Comment[eu]=korganizer-en data guztiak egutegi judutar sisteman ere erakusten ditu. +Comment[fa]=همۀ تاریخهای korganizer، همچنین سیستم تقویم یهودی را نمایش میدهد. +Comment[fi]=Näyttää kaikki päivät KOrganizerissa myös Juutalaisen kalenterijärjestelmän mukaan. +Comment[fr]=Affiche toutes les dates de KOrganizer selon le calendrier Juif +Comment[fy]=Lit alle datums yn KOrganizer ek yn it Joadske kalinderssysteem sjen. +Comment[gl]=Amosa todas as datas en korganizer, tamén o sistema de calendario xudeu. +Comment[he]=מציג את כל התאריכים בארגונית גם בלוח השנה העברי +Comment[hu]=A KOrganizer dátumait kiírja a hagyományos zsidó naptár szerint is. +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. +Comment[mk]=Ги прикажува сите датуми во КОрганизатор и според еврејскиот календар. +Comment[ms]=Memaparkan semua tarikh dalam korganizer dan juga dalam sistem kalendar Yahudi. +Comment[nb]=Viser alle datoer i korganizer også i det jødiske kalendersystemet. +Comment[nds]=Wiest all Daten binnen KOrganizer ok in den juudschen Kalenner. +Comment[ne]=केडीई आयोजकमा पनि सबै मिति यहूदि क्यालेन्डर प्रणालीमा देखाउछ । +Comment[nl]=Toont alle data in KOrganizer ook in het Joodse kalendersysteem. +Comment[nn]=Viser alle datoane i KOrganizer i den jødiske kalenderen. +Comment[pl]=Pokazuje wszystkie daty w KOrganizerze również w kalendarzu żydowskim. +Comment[pt]=Mostra todas as datas no KOrganizer também no sistema de calendários Judeu. +Comment[pt_BR]=Mostra todas as datas no KOrganizer também no sistema de calendário judaico +Comment[ru]=Показывать все даты по еврейскому календарю. +Comment[sk]=Zobrazí všetky dátumy v korganizer tiež aj židovskom kalendári. +Comment[sl]=Prikaže vse datume v KOrganizerju; tudi v židovskem koledarskem sistemu. +Comment[sr]=Приказује све датуме у KOrganizer-у и по јеврејском календарском систему. +Comment[sr@Latn]=Prikazuje sve datume u KOrganizer-u i po jevrejskom kalendarskom sistemu. +Comment[sv]=Visar också alla datum i Korganizer enligt den judiska kalendern. +Comment[ta]=korganizer மற்றும் ஜேவிஷ் நாட்காட்டி அமைப்பில் ல் உள்ள எல்லா தேதிகளையும் காட்டுகிறது. +Comment[tr]=KOrganizer'da tüm tarihleri İbrani takvimine göre gösterir. +Comment[uk]=Показує всі дати в korganizer також і в системі єврейського календаря. +Comment[zh_CN]=在 KOrganizer 中显示犹太教日历系统的全部日期。 +Comment[zh_TW]=顯示所有猶太行事曆的日期 +Type=Service +ServiceTypes=Calendar/Plugin,Calendar/Decoration +X-KDE-KOrganizer-HasSettings=true +X-KDE-PluginInterfaceVersion=2 diff --git a/korganizer/plugins/hebrew/hebrew.h b/korganizer/plugins/hebrew/hebrew.h new file mode 100644 index 000000000..1153c1012 --- /dev/null +++ b/korganizer/plugins/hebrew/hebrew.h @@ -0,0 +1,47 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2003 Jonathan Singer <jsinger@leeta.net> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public 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 KORG_HEBREW_H +#define KORG_HEBREW_H + +#include <qstring.h> +#include <qstringlist.h> +#include <calendar/calendardecoration.h> + +using namespace KOrg; + +class Hebrew:public CalendarDecoration +{ +public: + Hebrew() + { + } + ~Hebrew() + { + } + void configure(QWidget * parent); + QString shortText(const QDate &); + + QString info(); + static bool IsraelP; + +private: + +}; + +#endif diff --git a/korganizer/plugins/hebrew/holiday.cpp b/korganizer/plugins/hebrew/holiday.cpp new file mode 100644 index 000000000..732a00447 --- /dev/null +++ b/korganizer/plugins/hebrew/holiday.cpp @@ -0,0 +1,431 @@ +/*************************************************************************** + * Copyright (C) 2003 by Jonathan Singer * + * jsinger@leeta.net * + * Calendar routines from Hebrew Calendar by Frank Yellin * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "holiday.h" +#include <klocale.h> + +bool Holiday::CholP; +bool Holiday::OmerP; +bool Holiday::ParshaP; + +QStringList Holiday::holidays; +int Holiday::HolidayFlags; + +Holiday::Holiday() +{ + +} + +Holiday::~Holiday() +{ +} + +/* Given a day of the Hebrew month, figuring out all the interesting holidays that +* correspond to that date. ParshaP, OmerP, and CholP determine whether we should +* given info about the Parsha of the week, the Sfira, or Chol Hamoed. +* +* We are also influenced by the IsraelP flag +*/ + +QStringList + Holiday::FindHoliday(int month, int day, int weekday, int kvia, + bool leap_year_p, bool israel_p, + int day_number, int year) +{ + + enum + { Sunday = 1, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday + }; + + holidays.clear(); + bool shabbat_p = (weekday == Saturday); // Is it a Saturday? + + // Treat Adar in a non-leap year as if it were Adar II. + if ((month == 12) && !leap_year_p) + month = 13; + switch (month) + { + case 1: /* Nissan */ + switch (day) + { + case 1: + if (shabbat_p) + holidays << + i18n + ("These are Jewish holidays and mostly do not have translations. They may have different spellings in your language; otherwise, just translate the sound to your characters", + "Sh. HaHodesh"); + break; + case 14: + if (!shabbat_p) + // If it's Shabbat, we have three pieces of info. + // This is the least important. + holidays << i18n("Erev Pesach"); + /* Fall thru */ + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + // The Saturday before Pesach (8th-14th) + if (shabbat_p) + holidays << i18n("Sh. HaGadol"); + break; + case 15: + case 16: + case 21: + case 22: + if (!israel_p || (day == 15) || (day == 21)) + { + holidays << i18n("Pesach"); + break; + } + else if (day == 22) + break; + /* else fall through */ + case 17: + case 18: + case 19: + case 20: + if (CholP) + holidays << i18n("Chol Hamoed"); + break; + case 27: + // Yom HaShoah only exists since Israel was established. + if (year > 1948 + 3760) + holidays << i18n("Yom HaShoah"); + break; + } + if ((day > 15) && OmerP) + // Count the Omer, starting after the first day of Pesach. + holidays << Sfirah(day - 15); + break; + + case 2: /* Iyar */ + switch (day) + { + case 2: + case 3: + case 4: + case 5: + // Yom HaAtzmaut is on the 5th, unless that's a Saturday, in which + // case it is moved back two days to Thursday. Yom HaZikaron is + // the day before Yom HaAtzmaut. + if (year >= 1948 + 3760) + { // only after Israel established. + switch (weekday) + { + case Wednesday: + if (day == 5) + holidays << i18n("Yom HaAtzmaut"); + else + holidays << i18n("Yom HaZikaron"); + break; + case Thursday: + // This can't be 2 Iyar. + holidays << i18n("Yom HaAtzmaut"); + break; + case Friday: + case Saturday: + // These are never either of them. + break; + default: + // All other days follow the normal rules. + if (day == 4) + holidays << i18n("Yom HaZikaron"); + else if (day == 5) + holidays << i18n("Yom HaAtzmaut"); + } + } + break; + case 28: + // only since the 1967 war + if (year > 1967 + 3760) + holidays << i18n("Yom Yerushalayim"); + break; + case 18: + holidays << i18n("Lag BaOmer"); + break; + } + if ((day != 18) && OmerP) + // Sfirah the whole month. But Lag BaOmer is already mentioned. + holidays << Sfirah(day + 15); + + break; + + case 3: /* Sivan */ + switch (day) + { + case 1: + case 2: + case 3: + case 4: + // Sfirah until Shavuot + if (OmerP) + holidays << Sfirah(day + 44); + break; + case 5: + // Don't need to mention Sfira(49) if there's already two other + // pieces of information + if (OmerP && !shabbat_p) + holidays << Sfirah(49); + holidays << i18n("Erev Shavuot"); + break; + case 6: + case 7: + if (!israel_p || (day == 6)) + holidays << i18n("Shavuot"); + break; + } + break; + + case 4: /* Tamuz */ + // 17th of Tamuz, except Shabbat pushes it to Sunday. + if ((!shabbat_p && (day == 17)) + || ((weekday == 1) && (day == 18))) + holidays << i18n("Tzom Tammuz"); + break; + + case 5: /* Ab */ + if (shabbat_p && (3 <= day) && (day <= 16)) + // The shabbat before and after Tisha B'Av are special + if (day <= 9) + holidays << i18n("Sh. Hazon"); + else + holidays << i18n("Sh. Nahamu"); + else if ((!shabbat_p && (day == 9)) + || ((weekday == 1) && (day == 10))) + // 9th of Av, except Shabbat pushes it to Sunday. + holidays << i18n("Tisha B'Av"); + break; + + case 6: /* Elul */ + if ((day >= 20) && (day <= 26) && shabbat_p) + holidays << i18n("S'lichot"); + else if (day == 29) + holidays << i18n("Erev R.H."); + break; + + case 7: /* Tishrei */ + switch (day) + { + case 1: + case 2: + holidays << i18n("Rosh Hashana"); + break; + case 3: + if (shabbat_p) + holidays << i18n("Sh. Shuvah"); + else + holidays << i18n("Tzom Gedalia"); + break; + case 4: + if (weekday == 1) + holidays << i18n("Tzom Gedalia"); + /* fall through */ + case 5: + case 6: + case 7: + case 8: + if (shabbat_p) + holidays << i18n("Sh. Shuvah"); + break; + case 9: + holidays << i18n("Erev Y.K."); + break; + case 10: + holidays << i18n("Yom Kippur"); + break; + case 14: + holidays << i18n("Erev Sukkot"); + break; + case 15: + case 16: + if (!israel_p || (day == 15)) + { + holidays << i18n("Sukkot"); + break; + } + /* else fall through */ + case 17: + case 18: + case 19: + case 20: + if (CholP) + holidays << i18n("Chol Hamoed"); + break; + case 21: + holidays << i18n("Hoshana Rabah"); + break; + case 22: + holidays << i18n("Shmini Atzeret"); + break; + case 23: + if (!israel_p) + holidays << i18n("Simchat Torah"); + break; + } + break; + case 8: /* Cheshvan */ + break; + + case 9: /* Kislev */ + if (day == 24) + holidays << i18n("Erev Hanukah"); + else if (day >= 25) + holidays << i18n("Hanukah"); + break; + + case 10: /* Tevet */ + if (day <= (kvia == 0 ? 3 : 2)) + // Need to know length of Kislev to determine last day of Chanukah + holidays << i18n("Hanukah"); + else if (((day == 10) && !shabbat_p) + || ((day == 11) && (weekday == 1))) + // 10th of Tevet. Shabbat pushes it to Sunday + holidays << i18n("Tzom Tevet"); + break; + + case 11: /* Shvat */ + switch (day) + { + // The info for figuring out Shabbat Shirah is from the Gnu code. I + // assume it's correct. +// static char *song = i18n("Sh. Shirah"; + case 10: + if ((kvia != 0) && shabbat_p) + holidays << i18n("Sh. Shirah"); + break; + case 11: + case 12: + case 13: + case 14: + case 16: + if (shabbat_p) + holidays << i18n("Sh. Shirah"); + break; + case 15: + if (shabbat_p) + holidays << i18n("Sh. Shirah"); + holidays << i18n("Tu B'Shvat"); + case 17: + if ((kvia == 0) && shabbat_p) + holidays << i18n("Sh. Shirah"); + break; + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + // The last shabbat on or before 1 Adar or 1 AdarII + if (shabbat_p && !leap_year_p) + holidays << i18n("Sh. Shekalim"); + break; + } + break; + + case 12: /* Adar I */ + if (day == 14) + // Eat Purim Katan Candy + holidays << i18n("Purim Katan"); + else if ((day >= 25) && shabbat_p) + // The last shabbat on or before 1 Adar II. + holidays << i18n("Sh. Shekalim"); + break; + + case 13: /* Adar II or Adar */ + switch (day) + { + case 1: + if (shabbat_p) + holidays << i18n("Sh. Shekalim"); + break; + case 11: + case 12: + // Ta'anit ester is on the 13th. But shabbat moves it back to + // Thursday. + if (weekday == Thursday) + holidays << i18n("Ta'anit Ester"); + /* Fall thru */ + case 7: + case 8: + case 9: + case 10: + // The Shabbat before purim is Shabbat Zachor + if (shabbat_p) + holidays << i18n("Sh. Zachor"); + break; + case 13: + if (shabbat_p) + holidays << i18n("Sh. Zachor"); + else + holidays << i18n("Erev Purim"); + // It's Ta'anit Esther, unless it's a Friday or Saturday + if (weekday < Friday) + holidays << i18n("Ta'anit Ester"); + break; + case 14: + holidays << i18n("Purim"); + break; + case 15: + if (!shabbat_p) + holidays << i18n("Shushan Purim"); + break; + case 16: + if (weekday == 1) + holidays << i18n("Shushan Purim"); + break; + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + if (shabbat_p) + holidays << i18n("Sh. Parah"); + break; + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + if (shabbat_p) + holidays << i18n("Sh. HaHodesh"); + break; + } + break; + } + if (shabbat_p && ParshaP) + // Find the Parsha on Shabbat. + holidays << Parsha::FindParshaName(day_number, kvia, leap_year_p, + israel_p); + return holidays; +} + +/* Return a string corresponding to the nth day of the Omer */ +QString Holiday::Sfirah(int day) +{ + /*static char buffer[40]; + char *endings[] = {"th", "st", "nd", "rd"}; + int remainder = day % 10; + // 11-19 and anything not ending with 1, 2, or 3 uses -th as suffix. + if ( ((day >= 11) && (day <= 19)) || (remainder > 3)) remainder = 0; + sprintf(buffer, "%d%s day Omer", day, endings[remainder]); + return buffer; */ + QString buffer; + + buffer.setNum(day); + buffer + i18n(" Omer"); // Fix this to original function + return buffer; + +} diff --git a/korganizer/plugins/hebrew/holiday.h b/korganizer/plugins/hebrew/holiday.h new file mode 100644 index 000000000..6c8c61d9d --- /dev/null +++ b/korganizer/plugins/hebrew/holiday.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2003 by Jonathan Singer * + * jsinger@leeta.net * + * Calendar routines from Hebrew Calendar by Frank Yellin * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef HOLIDAY_H +#define HOLIDAY_H + +#include <qstring.h> +#include <qstringlist.h> +#include <parsha.h> +/** +@author Jonathan Singer +*/ +class Holiday +{ +public: + + Holiday(); + ~Holiday(); + + static QStringList FindHoliday(int month, int day, int weekday, + int kvia, bool leap_year_p, + bool israel_p, int day_number, + int year); + + static QString Sfirah(int); + + static bool CholP; + static bool OmerP; + static bool ParshaP; + +private: + + static QStringList holidays; + static int HolidayFlags; //supposed to be extern + +//parsha Parsha_lookup; +}; + +#endif diff --git a/korganizer/plugins/hebrew/parsha.cpp b/korganizer/plugins/hebrew/parsha.cpp new file mode 100644 index 000000000..21fdf8a4e --- /dev/null +++ b/korganizer/plugins/hebrew/parsha.cpp @@ -0,0 +1,273 @@ +/*************************************************************************** + * Copyright (C) 2003 by Jonathan Singer * + * jsinger@leeta.net * + * Calendar routines from Hebrew Calendar by Frank Yellin * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "parsha.h" +#include <klocale.h> + +QStringList Parsha::parshiot_names; + +Parsha::Parsha() +{ + +} + +Parsha::~Parsha() +{ +} + +QString + Parsha::FindParshaName(int daynumber, int kvia, bool leap_p, + bool israel_p) +{ +// The names of the Parshiot. + parshiot_names << + i18n + ("These are weekly readings and do not have translations. They may have different spellings in your language; otherwise, just translate the sound to your characters", + "Bereshit") << i18n("Noach") << i18n("Lech L'cha") << + i18n("Vayera") << i18n("Chaye Sarah") << i18n("Toldot") << + i18n("Vayetze") << i18n("Vayishlach") << i18n("Vayeshev") << + i18n("Miketz") << i18n("Vayigash") << i18n("Vayechi") << + i18n("Shemot") << i18n("Vaera") << i18n("Bo") << i18n("Beshalach") + << i18n("Yitro") << i18n("Mishpatim") << i18n("Terumah") << + i18n("Tetzaveh") << i18n("Ki Tisa") << i18n("Vayakhel") << + i18n("Pekudei") << i18n("Vayikra") << i18n("Tzav") << + i18n("Shemini") << i18n("Tazria") << i18n("Metzora") << + i18n("Acharei Mot") << i18n("Kedoshim") << i18n("Emor") << + i18n("Behar") << i18n("Bechukotai") << i18n("Bemidbar") << + i18n("Naso") << i18n("Behaalotcha") << i18n("Shelach") << + i18n("Korach") << i18n("Chukat") << i18n("Balak") << + i18n("Pinchas") << i18n("Matot") << i18n("Masei") << + i18n("Devarim") << i18n("Vaetchanan") << i18n("Ekev") << + i18n("Reeh") << i18n("Shoftim") << i18n("Ki Tetze") << + i18n("Ki Tavo") << i18n("Nitzavim") << i18n("Vayelech") << + i18n("Haazinu"); + +// Tables for each of the year types. XX indicates that it is a Holiday, and +// a special parsha is read that week. For some year types, Israel is different +// than the diaspora. +// +// The names indicate the day of the week on which Rosh Hashanah fell, whether +// it is a short/normal/long year (kvia=0,1,2), and whether it is a leap year. +// Some year types also have an _Israel version. +// +// Numbers are indices into the table above for a given week. Numbers > 100 indicate +// a double parsha. E.g. 150 means read both table entries 50 and 51. +// +// These tables were stolen (with some massaging) from the GNU code. + +#define XX 255 + static unsigned const char Sat_short[] = + { XX, 52, XX, XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 121, 23, 24, XX, 25, + 126, 128, 30, 131, 33, 34, 35, 36, 37, 38, 39, 40, 141, 43, 44, + 45, 46, 47, 48, 49, 50, + }; + + static unsigned const char Sat_long[] = + { XX, 52, XX, XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 121, 23, 24, XX, 25, + 126, 128, 30, 131, 33, 34, 35, 36, 37, 38, 39, 40, 141, 43, 44, + 45, 46, 47, 48, 49, 150, + }; + + static unsigned const char Mon_short[] = + { 51, 52, XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 121, 23, 24, XX, 25, 126, + 128, 30, 131, 33, 34, 35, 36, 37, 38, 39, 40, 141, 43, 44, 45, + 46, 47, 48, 49, 150, + }; + + static unsigned const char Mon_long[] = /* split */ + { 51, 52, XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 121, 23, 24, XX, 25, 126, + 128, 30, 131, 33, XX, 34, 35, 36, 37, 138, 40, 141, 43, 44, 45, + 46, 47, 48, 49, 150, + }; + +#define Mon_long_Israel Mon_short + +#define Tue_normal Mon_long +#define Tue_normal_Israel Mon_short + + static unsigned const char Thu_normal[] = + { 52, XX, XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 121, 23, 24, XX, XX, 25, + 126, 128, 30, 131, 33, 34, 35, 36, 37, 38, 39, 40, 141, 43, 44, + 45, 46, 47, 48, 49, 50, + }; + static unsigned const char Thu_normal_Israel[] = + { 52, XX, XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 121, 23, 24, XX, 25, 126, + 128, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 141, 43, 44, + 45, 46, 47, 48, 49, 50, + }; + + static unsigned const char Thu_long[] = + { 52, XX, XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, XX, 25, + 126, 128, 30, 131, 33, 34, 35, 36, 37, 38, 39, 40, 141, 43, 44, + 45, 46, 47, 48, 49, 50, + }; + + static unsigned const char Sat_short_leap[] = + { XX, 52, XX, XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, XX, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 141, 43, 44, 45, 46, 47, 48, 49, 150, + }; + + static unsigned const char Sat_long_leap[] = + { XX, 52, XX, XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, XX, 28, 29, 30, 31, 32, 33, XX, 34, 35, 36, 37, 138, + 40, 141, 43, 44, 45, 46, 47, 48, 49, 150, + }; + +#define Sat_long_leap_Israel Sat_short_leap + + static unsigned const char Mon_short_leap[] = + { 51, 52, XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, XX, 28, 29, 30, 31, 32, 33, XX, 34, 35, 36, 37, 138, 40, + 141, 43, 44, 45, 46, 47, 48, 49, 150, + }; + static unsigned const char Mon_short_leap_Israel[] = + { 51, 52, XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, XX, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 141, 43, 44, 45, 46, 47, 48, 49, 150, + }; + + static unsigned const char Mon_long_leap[] = + { 51, 52, XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, XX, XX, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 141, 43, 44, 45, 46, 47, 48, 49, 50, + }; + static unsigned const char Mon_long_leap_Israel[] = + { 51, 52, XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, XX, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + }; + +#define Tue_normal_leap Mon_long_leap +#define Tue_normal_leap_Israel Mon_long_leap_Israel + + static unsigned const char Thu_short_leap[] = + { 52, XX, XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, XX, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + }; + + static unsigned const char Thu_long_leap[] = + { 52, XX, XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, XX, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 150, + }; + +/* Find the parsha for a given day of the year. daynumber is the day of the year. + * kvia and leap_p refer to the year type. + */ + + int week = daynumber / 7; // week of the year + unsigned const char *array = NULL; + int index; + + // get the appropriate array by exhaustive search into the 14 year types. Since we + // know it's a Shabbat, we can find out what day Rosh Hashanah was on by looking + // at daynumber %7. + if (!leap_p) + { + switch (daynumber % 7) + { + case 1: /* RH was on a Saturday */ + if (kvia == 0) + array = Sat_short; + else if (kvia == 2) + array = Sat_long; + break; + case 6: /* RH was on a Monday */ + if (kvia == 0) + array = Mon_short; + else if (kvia == 2) + array = israel_p ? Mon_long_Israel : Mon_long; + break; + case 5: /* RH was on a Tueday */ + if (kvia == 1) + array = israel_p ? Tue_normal_Israel : Tue_normal; + break; + case 3: /* RH was on a Thu */ + if (kvia == 1) + array = israel_p ? Thu_normal_Israel : Thu_normal; + else if (kvia == 2) + array = Thu_long; + break; + } + } + else /* leap year */ + switch (daynumber % 7) + { + case 1: /* RH was on a Sat */ + if (kvia == 0) + array = Sat_short_leap; + else if (kvia == 2) + array = israel_p ? Sat_long_leap_Israel : Sat_long_leap; + break; + case 6: /* RH was on a Mon */ + if (kvia == 0) + array = israel_p ? Mon_short_leap_Israel : Mon_short_leap; + else if (kvia == 2) + array = israel_p ? Mon_long_leap_Israel : Mon_long_leap; + break; + case 5: /* RH was on a Tue */ + if (kvia == 1) + array = + israel_p ? Tue_normal_leap_Israel : Tue_normal_leap; + break; + case 3: /* RH was on a Thu */ + if (kvia == 0) + array = Thu_short_leap; + else if (kvia == 2) + array = Thu_long_leap; + break; + + } + + QString buffer; + + if (array == NULL) + /* Something is terribly wrong. */ + { + buffer = "??Parsha??"; + return buffer; + } + index = array[week]; + if (index == XX) // no Parsha this week. + { + buffer = ""; + return buffer; + } + else if (index < 100) + { + buffer = parshiot_names[index]; + return buffer; + } + else + { // Create a double parsha + buffer = + parshiot_names[index - 100] + "-" + parshiot_names[index - + 99]; + return buffer; + + } +} diff --git a/korganizer/plugins/hebrew/parsha.h b/korganizer/plugins/hebrew/parsha.h new file mode 100644 index 000000000..aac2625ff --- /dev/null +++ b/korganizer/plugins/hebrew/parsha.h @@ -0,0 +1,33 @@ +/*************************************************************************** + * Copyright (C) 2003 by Jonathan Singer * + * jsinger@leeta.net * + * Calendar routines from Hebrew Calendar by Frank Yellin * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef PARSHA_H +#define PARSHA_H + +#include <qstring.h> +#include <qstringlist.h> + +/** +@author Jonathan Singer +*/ +class Parsha +{ +public: + + Parsha(); + ~Parsha(); + static QString FindParshaName(int daynumber, int kvia, bool leap_p, + bool israel_p); + +private: + static QStringList parshiot_names; +}; + +#endif diff --git a/korganizer/plugins/printing/Makefile.am b/korganizer/plugins/printing/Makefile.am new file mode 100644 index 000000000..5e53a9ff7 --- /dev/null +++ b/korganizer/plugins/printing/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = journal year diff --git a/korganizer/plugins/printing/journal/Makefile.am b/korganizer/plugins/printing/journal/Makefile.am new file mode 100644 index 000000000..6238b1f18 --- /dev/null +++ b/korganizer/plugins/printing/journal/Makefile.am @@ -0,0 +1,14 @@ +INCLUDES = -I$(top_srcdir)/korganizer/interfaces -I$(top_srcdir)/korganizer/printing -I$(top_srcdir) $(all_includes) + +kde_module_LTLIBRARIES = libkorg_journalprint.la + +libkorg_journalprint_la_SOURCES =calprintjournalconfig_base.ui journalprint.cpp +libkorg_journalprint_la_LDFLAGS = -module $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) +libkorg_journalprint_la_LIBADD = $(LIB_KDECORE) $(LIB_KDEUI) $(top_builddir)/korganizer/printing/libkorg_stdprinting.la + +noinst_HEADERS = + +servicedir = $(kde_servicesdir)/korganizer +service_DATA = journalprint.desktop + +METASOURCES = AUTO diff --git a/korganizer/plugins/printing/journal/calprintjournalconfig_base.ui b/korganizer/plugins/printing/journal/calprintjournalconfig_base.ui new file mode 100644 index 000000000..bee91a368 --- /dev/null +++ b/korganizer/plugins/printing/journal/calprintjournalconfig_base.ui @@ -0,0 +1,201 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>CalPrintJournalConfig_Base</class> +<comment>Configuration page for the print journal mode.</comment> +<author>Reinhold Kainhofer <reinhold@kainhofer.com></author> +<widget class="QWidget"> + <property name="name"> + <cstring>CalPrintJournal_Base</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>337</width> + <height>247</height> + </rect> + </property> + <property name="caption"> + <string>CalPrintJournal_Base</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>mDateRangeGroup</cstring> + </property> + <property name="title"> + <string>Date && Time Range</string> + </property> + <property name="selectedId" stdset="0"> + <number>1</number> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton"> + <property name="name"> + <cstring>mAllJournals</cstring> + </property> + <property name="text"> + <string>&All journal entries</string> + </property> + <property name="buttonGroupId"> + <number>0</number> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>mRangeJournals</cstring> + </property> + <property name="focusPolicy"> + <enum>TabFocus</enum> + </property> + <property name="text"> + <string>Date &range:</string> + </property> + <property name="buttonGroupId"> + <number>1</number> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer6</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>15</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel"> + <property name="name"> + <cstring>mFromDateLabel</cstring> + </property> + <property name="text"> + <string>&Start date:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mFromDate</cstring> + </property> + </widget> + <widget class="KDateEdit"> + <property name="name"> + <cstring>mFromDate</cstring> + </property> + <property name="focusPolicy"> + <enum>StrongFocus</enum> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>mToDateLabel</cstring> + </property> + <property name="text"> + <string>&End date:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mToDate</cstring> + </property> + </widget> + <widget class="KDateEdit"> + <property name="name"> + <cstring>mToDate</cstring> + </property> + <property name="focusPolicy"> + <enum>StrongFocus</enum> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>324</width> + <height>21</height> + </size> + </property> + </spacer> + </hbox> + </widget> + </vbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>201</height> + </size> + </property> + </spacer> + </vbox> +</widget> +<customwidgets> + <customwidget> + <class>KDateEdit</class> + <header location="local">libkdepim/kdateedit.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> +</customwidgets> +<images> + <image name="image0"> + <data format="PNG" length="826">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000030149444154789cb59531681b5718c77f0e377c070e3c810a3a70e0041eac51852e0a19e45134830a1d9a4c69a04bc8928e990a693a640e1d0c8642b08742321894c1507991b484c890902bb8701a047760c3bd21701fe4201dde49b6a41a32b8df72dcbbeffdbefffbbfefbd5b1b0c07cce266ebe667ae2006c3c1dada0cdc3be87d6e6c35b0d692a409d9c7ec8b20d65ae29398d19b1114e7e3de4ce98b3f5e10dc0053cf0951b4506496e1b964bf7ce6c585d9054c62d01d617ca48be0596553cf496d8f2c8b01c5f795fc93904e85ec4c01a152857a5d9175d0b2805c872080f18595ccc1499a10a225d4e2fbc2877786fe81253ab6c04c8d106e09db5d43ab0d146e5c64d1a23938fb98a185cea1c33eecfd9eba49eb427dcb201e245365f2b7b2fb5b4a3a31dcb927178afe07d86901df870fefa4842aed6f6b74ba42e52b4014d580e1eb9cbd9d94de7e4aad16d2f9be02d805f0b5e532f927a1ffcacea1777f122a8105b164a7c25faf323a5d9f1f1fd600e1e5bec59e2d4b5c7ef5209d0ad17b8b31864e57c0b3e0815ac3ee33253ab664a770ff5185d1a1cb8d2267d3e58aa1dc7d2508cbe597d0e74fdd269aaaf0f52d414c4ea3e9762c996869e42560d7a72e41c4799a2586e74f95e8d8151481fa86efbe7b3398ac58b1a2b8527589f15451ad303ac2293542ad6648a796278f13a27185e4c4754310facb98c53a79e19a3fdc1426ff28c3d7399d1f7cb25343eb96106cf83c790ce9c4f2eb831855c55485663327992eb6dc8a6259874ed700b0b793323cccb9ffa842b30d6133e3e75fea989ac15a8b16ca76b746b0b92278d919774c5b6d48a78697fb29bbcf52468742a32120909c24e899ce67beed5be2db01e22d1e9485bb620e47f9ee9e606a21bd3f5d3744c7e7c54d55e87443867d8b554515ac5db4620e8e4f62263170fd1cdee90aad7640141992891b0f367c9adfe4049bb07d3b7022bd8c687c0978f46684ee084150b65ac1fcca94591b7a90a496e4c095164fb016a2b192a497795cc0f84817aebe25f7bf70ccc54a575c555c03f78ffa5fc0570d1f0c076bff0232285a0901e2257b0000000049454e44ae426082</data> + </image> +</images> +<tabstops> + <tabstop>mFromDate</tabstop> + <tabstop>mToDate</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kdateedit.h</includehint> + <includehint>kdateedit.h</includehint> +</includehints> +</UI> diff --git a/korganizer/plugins/printing/journal/journalprint.cpp b/korganizer/plugins/printing/journal/journalprint.cpp new file mode 100644 index 000000000..31b1b10b6 --- /dev/null +++ b/korganizer/plugins/printing/journal/journalprint.cpp @@ -0,0 +1,135 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#ifndef KORG_NOPRINTER + +#include "journalprint.h" + +#include "calprintpluginbase.h" +#include <libkcal/journal.h> +#include <libkcal/calendar.h> +#include <libkdepim/kdateedit.h> +#include <kconfig.h> +#include <kdebug.h> + +#include <qbuttongroup.h> + +#include "calprintjournalconfig_base.h" + + +class JournalPrintFactory : public KOrg::PrintPluginFactory { + public: + KOrg::PrintPlugin *create() { return new CalPrintJournal; } +}; + +K_EXPORT_COMPONENT_FACTORY( libkorg_journalprint, JournalPrintFactory ) + + +/************************************************************** + * Print Journal + **************************************************************/ + +QWidget *CalPrintJournal::createConfigWidget( QWidget *w ) +{ + return new CalPrintJournalConfig_Base( w ); +} + +void CalPrintJournal::readSettingsWidget() +{ + CalPrintJournalConfig_Base *cfg = + dynamic_cast<CalPrintJournalConfig_Base*>( mConfigWidget ); + if ( cfg ) { + mFromDate = cfg->mFromDate->date(); + mToDate = cfg->mToDate->date(); + mUseDateRange = (cfg->mDateRangeGroup->selectedId() == 1); + } +} + +void CalPrintJournal::setSettingsWidget() +{ + CalPrintJournalConfig_Base *cfg = + dynamic_cast<CalPrintJournalConfig_Base*>( mConfigWidget ); + if ( cfg ) { + cfg->mFromDate->setDate( mFromDate ); + cfg->mToDate->setDate( mToDate ); + + cfg->mDateRangeGroup->setButton( (mUseDateRange)?1:0 ); + } +} + +void CalPrintJournal::loadConfig() +{ + if ( mConfig ) { + mUseDateRange = mConfig->readBoolEntry( "JournalsInRange", false ); + } + setSettingsWidget(); +} + +void CalPrintJournal::saveConfig() +{ + kdDebug(5850) << "CalPrintJournal::saveConfig()" << endl; + + readSettingsWidget(); + if ( mConfig ) { + mConfig->writeEntry( "JournalsInRange", mUseDateRange ); + } +} + +void CalPrintJournal::setDateRange( const QDate& from, const QDate& to ) +{ + CalPrintPluginBase::setDateRange( from, to ); + CalPrintJournalConfig_Base *cfg = + dynamic_cast<CalPrintJournalConfig_Base*>( mConfigWidget ); + if ( cfg ) { + cfg->mFromDate->setDate( from ); + cfg->mToDate->setDate( to ); + } +} + +void CalPrintJournal::print( QPainter &p, int width, int height ) +{ + int x=0, y=0; + Journal::List journals( mCalendar->journals() ); + if ( mUseDateRange ) { + Journal::List allJournals = journals; + journals.clear(); + Journal::List::Iterator it = allJournals.begin(); + for ( ; it != allJournals.end(); ++it ) { + QDate dt = (*it)->dtStart().date(); + if ( mFromDate <= dt && dt <= mToDate ) { + journals.append( *it ); + } + } + } + + drawHeader( p, i18n("Journal entries"), QDate(), QDate(), QRect( 0, 0, width, headerHeight() ) ); + y = headerHeight() + 15; + + Journal::List::Iterator it = journals.begin(); + for ( ; it != journals.end(); ++it ) { + drawJournal( *it, p, x, y, width, height ); + } +} + +#endif diff --git a/korganizer/plugins/printing/journal/journalprint.desktop b/korganizer/plugins/printing/journal/journalprint.desktop new file mode 100644 index 000000000..081f73d6d --- /dev/null +++ b/korganizer/plugins/printing/journal/journalprint.desktop @@ -0,0 +1,95 @@ +[Desktop Entry] +X-KDE-Library=libkorg_journalprint +Name=Journal Print Style +Name[af]=Joernaal druk styl +Name[bg]=Стил на отпечатване на календар +Name[ca]=Estil d'impressió del diari +Name[cs]=Tiskový styl deníku +Name[da]=Journal udskriftsstil +Name[de]=Journal Druckstil +Name[el]=Στυλ εκτύπωσης χρονικού +Name[eo]=Ĵurnal-Presostilo +Name[es]=Estilo de impresión del diario +Name[et]=Päeviku trükkimise stiil +Name[eu]=Egunkariak inprimatzeko estiloa +Name[fa]=سبک چاپ نشریه +Name[fi]=Päiväkirjan tulostustyyli +Name[fr]=Impression en journal +Name[fy]=Printstyl foar journaals +Name[gl]=Imprimir en Estilo Xornal +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 +Name[ms]=Gaya Cetak Jurnal +Name[nb]=Utskriftsstil for dagbok +Name[nds]=Daagbook-Druckstil +Name[ne]=जर्नल मुद्रण शैली +Name[nl]=Printstijl voor journaals +Name[nn]=Utskriftsstil for dagbok +Name[pl]=Styl drukowania dziennika +Name[pt]=Estilo de Impressão em Diário +Name[pt_BR]=Estilo de Impressão de Diário +Name[ru]=Журнал +Name[sk]=Štýl tlače žurnálu +Name[sl]=Dnevniški slog tiskanja +Name[sr]=Дневнички стил штампе +Name[sr@Latn]=Dnevnički stil štampe +Name[sv]=Journal-utskriftsstil +Name[ta]=செய்தி அச்சுப்பாணி +Name[tr]=Günlük Yazdırma Tarzı +Name[uk]=Стиль друку журналом +Name[zh_CN]=日记打印样式 +Name[zh_TW]=日誌列印風格 +Comment=This plugin allows you to print out journal entries (diary entries). +Comment[af]=Hierdie inprop module maak dit moontlik om joernaal inskrywings (dagboek inskrywings) te druk. +Comment[bg]=Приставката служи за печат на дневника. +Comment[ca]=Aquest endollable us permet imprimir entrades del diari. +Comment[cs]=tento modul umožňuje tisk položek deníku. +Comment[da]=Dette plugin gør at du kan udskrive journalindgange (dagbogsindgange). +Comment[de]=Mit diesem Modul können Journaleinträge (Tagebucheinträge) gedruckt werden. +Comment[el]=Αυτό το πρόσθετο σας επιτρέπει να εκτυπώνετε καταχωρήσεις χρονικού. +Comment[es]=Esta extensión le permite imprimir entradas del diario. +Comment[et]=See plugin võimaldab trükkida päeviku sissekandeid. +Comment[eu]=Plugin honek egunkarien sarrerak (eguneroko sarrerak) inprimatzeko aukera ematen dizu. +Comment[fa]=این وصله، به شما اجازه میدهد که مدخلهای نشریه )مدخلهای روزانه( را چاپ کنید. +Comment[fi]=Tämä liitännäinen mahdollistaa päiväkirjan tulostuksen. +Comment[fr]=Ce module vous permet d'imprimer l'ensemble de vos journaux personnels +Comment[fy]=Dizze plugin makket it mooglik journalen út te printsjen (deiboekitems). +Comment[gl]=Este engadido permítelle imprimir as entradas do xornal (entradas do diario). +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. +Comment[ms]=Plugin ini membenarkan anda mencetak entri jurnal (entri diari). +Comment[nb]=Med dette programtillegget kan du skrive ut oppføringer i dagboka. +Comment[nds]=Mit dit Moduul köönt Daagbook-Indrääg utdruckt warrn. +Comment[ne]=यो प्लगइनले तपाईँलाई जर्नल प्रविष्टि मुद्रण गर्न अनुमति दिन्छ (दैनिक विवरण प्रविष्टि) । +Comment[nl]=Deze plugin maakt het mogelijk om journalen uit te printen (dagboekitems). +Comment[nn]=Dette programtillegget lèt deg skriva ut dagboksoppføringar. +Comment[pl]=Ta wtyczka pozwala drukować wpisy dziennika. +Comment[pt]=Este diário permite-lhe imprimir os itens de diário. +Comment[pt_BR]=Esse estilo lhe permite imprimir entradas de diário +Comment[ru]=Этот модуль позволяет печатать журнал в виде дневника. +Comment[sk]=Tento modul umožní vytlačiť položky žurnálu (denníkové položky). +Comment[sl]=Ta vstavek vam omogoča natis vnosov v dnevnik. +Comment[sr]=Овај прикључак вам омогућава да одштампате уносе из дневника. +Comment[sr@Latn]=Ovaj priključak vam omogućava da odštampate unose iz dnevnika. +Comment[sv]=Det här insticksprogrammet gör att du kan skriva ut journalanteckningar (dagboksanteckningar). +Comment[ta]=இந்த சொருகுப்பொருள் இதழ் உள்ளீடுகளை அச்சிட உங்களை அனுமதிக்கிறது (நாள் குறிப்பேடு உள்ளீடுகள்). +Comment[tr]=Bu eklenti, günlük girişlerinizi yazıcıdan çıkartmanızı sağlar. +Comment[uk]=Цей журнал надає можливість друкувати записи журналу (записи щоденника). +Comment[zh_CN]=此插件允许您打印日记项目。 +Comment[zh_TW]=此外掛程式讓您印出日誌項目。 +Type=Service +ServiceTypes=Calendar/Plugin,KOrganizer/PrintPlugin +X-KDE-KOrganizer-HasSettings=false +X-KDE-PluginInterfaceVersion=2 diff --git a/korganizer/plugins/printing/journal/journalprint.h b/korganizer/plugins/printing/journal/journalprint.h new file mode 100644 index 000000000..fb91759f1 --- /dev/null +++ b/korganizer/plugins/printing/journal/journalprint.h @@ -0,0 +1,63 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef JOURNALPRINT_H +#define JOURNALPRINT_H + +#include <klocale.h> +#include "calprintpluginbase.h" + +#ifndef KORG_NOPRINTER +namespace KCal { +class Calendar; +} + +using namespace KCal; +using namespace KOrg; + +class CalPrintJournal : public CalPrintPluginBase +{ + public: + CalPrintJournal():CalPrintPluginBase() {} + virtual ~CalPrintJournal() {} + virtual QString description() { return i18n("Print &journal"); } + virtual QString info() { return i18n("Prints all journals for a given date range"); } + virtual int sortID() { return CalPrinterBase::Journallist; } + virtual bool enabled() { return true; } + virtual QWidget *createConfigWidget( QWidget* ); + + public: + virtual void print(QPainter &p, int width, int height); + virtual void readSettingsWidget(); + virtual void setSettingsWidget(); + virtual void loadConfig(); + virtual void saveConfig(); + virtual void setDateRange( const QDate& from, const QDate& to ); + + protected: + bool mUseDateRange; +}; + + +#endif +#endif diff --git a/korganizer/plugins/printing/list/Makefile.am b/korganizer/plugins/printing/list/Makefile.am new file mode 100644 index 000000000..cd41be7ed --- /dev/null +++ b/korganizer/plugins/printing/list/Makefile.am @@ -0,0 +1,14 @@ +INCLUDES = -I$(top_srcdir)/korganizer/interfaces -I$(top_srcdir)/korganizer/printing -I$(top_srcdir) $(all_includes) + +kde_module_LTLIBRARIES = libkorg_listprint.la + +libkorg_listprint_la_SOURCES = calprintlistconfig_base.ui listprint.cpp +libkorg_listprint_la_LDFLAGS = -module $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) +libkorg_listprint_la_LIBADD = $(LIB_KDECORE) $(LIB_KDEUI) $(top_builddir)/korganizer/printing/libkorg_stdprinting.la + +noinst_HEADERS = + +servicedir = $(kde_servicesdir)/korganizer +service_DATA = listprint.desktop + +METASOURCES = AUTO diff --git a/korganizer/plugins/printing/list/calprintlistconfig_base.ui b/korganizer/plugins/printing/list/calprintlistconfig_base.ui new file mode 100644 index 000000000..cea873e6a --- /dev/null +++ b/korganizer/plugins/printing/list/calprintlistconfig_base.ui @@ -0,0 +1,186 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>CalPrintListConfig_Base</class> +<comment>Configuration page for the print list mode.</comment> +<author>Reinhold Kainhofer <reinhold@kainhofer.com></author> +<widget class="QWidget"> + <property name="name"> + <cstring>CalPrintList_Base</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>427</width> + <height>171</height> + </rect> + </property> + <property name="caption"> + <string>CalPrintList_Base</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>mDateRangeGroup</cstring> + </property> + <property name="title"> + <string>Date && Time Range</string> + </property> + <property name="selectedId" stdset="0"> + <number>-1</number> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer6</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>15</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel"> + <property name="name"> + <cstring>mFromDateLabel</cstring> + </property> + <property name="text"> + <string>&Start date:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mFromDate</cstring> + </property> + </widget> + <widget class="KDateEdit"> + <property name="name"> + <cstring>mFromDate</cstring> + </property> + <property name="focusPolicy"> + <enum>StrongFocus</enum> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>mToDateLabel</cstring> + </property> + <property name="text"> + <string>&End date:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mToDate</cstring> + </property> + </widget> + <widget class="KDateEdit"> + <property name="name"> + <cstring>mToDate</cstring> + </property> + <property name="focusPolicy"> + <enum>StrongFocus</enum> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>324</width> + <height>21</height> + </size> + </property> + </spacer> + </hbox> + </widget> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox1</cstring> + </property> + <property name="title"> + <string>Print Incidences of Type</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>mEvents</cstring> + </property> + <property name="text"> + <string>&Events</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>mTodos</cstring> + </property> + <property name="text"> + <string>&To-dos</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>mJournals</cstring> + </property> + <property name="text"> + <string>&Journals</string> + </property> + </widget> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>40</height> + </size> + </property> + </spacer> + </vbox> +</widget> +<tabstops> + <tabstop>mFromDate</tabstop> + <tabstop>mToDate</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/korganizer/plugins/printing/list/listprint.cpp b/korganizer/plugins/printing/list/listprint.cpp new file mode 100644 index 000000000..0221f1c67 --- /dev/null +++ b/korganizer/plugins/printing/list/listprint.cpp @@ -0,0 +1,116 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#ifndef KORG_NOPRINTER + +#include "listprint.h" + +#include "calprintpluginbase.h" +#include <libkcal/event.h> +#include <libkcal/todo.h> +#include <libkcal/calendar.h> +#include <libkdepim/kdateedit.h> +#include <kconfig.h> +#include <kdebug.h> + +#include <qbuttongroup.h> + +#include "calprintlistconfig_base.h" + + +class ListPrintFactory : public KOrg::PrintPluginFactory { + public: + KOrg::PrintPlugin *create() { return new CalPrintList; } +}; + +K_EXPORT_COMPONENT_FACTORY( libkorg_listprint, ListPrintFactory ) + + + +/************************************************************** + * Print Day + **************************************************************/ + +QWidget *CalPrintList::createConfigWidget( QWidget *w ) +{ + return new CalPrintListConfig_Base( w ); +} + +void CalPrintList::readSettingsWidget() +{ + CalPrintListConfig_Base *cfg = + dynamic_cast<CalPrintListConfig_Base*>( mConfigWidget ); + if ( cfg ) { + mFromDate = cfg->mFromDate->date(); + mToDate = cfg->mToDate->date(); + mUseDateRange = (cfg->mDateRangeGroup->selectedId() == 1); + } +} + +void CalPrintList::setSettingsWidget() +{ + CalPrintListConfig_Base *cfg = + dynamic_cast<CalPrintListConfig_Base*>( mConfigWidget ); + if ( cfg ) { + cfg->mFromDate->setDate( mFromDate ); + cfg->mToDate->setDate( mToDate ); + + cfg->mDateRangeGroup->setButton( (mUseDateRange)?1:0 ); + } +} + +void CalPrintList::loadConfig() +{ + if ( mConfig ) { + mUseDateRange = mConfig->readBoolEntry( "ListsInRange", false ); + } + setSettingsWidget(); +} + +void CalPrintList::saveConfig() +{ + kdDebug(5850) << "CalPrintList::saveConfig()" << endl; + + readSettingsWidget(); + if ( mConfig ) { + mConfig->writeEntry( "ListsInRange", mUseDateRange ); + } +} + +void CalPrintList::setDateRange( const QDate& from, const QDate& to ) +{ + CalPrintPluginBase::setDateRange( from, to ); + CalPrintListConfig_Base *cfg = + dynamic_cast<CalPrintListConfig_Base*>( mConfigWidget ); + if ( cfg ) { + cfg->mFromDate->setDate( from ); + cfg->mToDate->setDate( to ); + } +} + +void CalPrintList::print( QPainter &p, int width, int height ) +{ +} + +#endif diff --git a/korganizer/plugins/printing/list/listprint.desktop b/korganizer/plugins/printing/list/listprint.desktop new file mode 100644 index 000000000..7688a2c52 --- /dev/null +++ b/korganizer/plugins/printing/list/listprint.desktop @@ -0,0 +1,95 @@ +[Desktop Entry] +X-KDE-Library=libkorg_listprint +Name=List Print Style +Name[af]=Lys druk styl +Name[bg]=Печат като списък +Name[ca]=Estil d'impressió en llista +Name[cs]=Styl deníku - seznam +Name[da]=Listeudskriftsstil +Name[de]=Listen Druckstil +Name[el]=Στυλ εκτύπωσης λίστας +Name[eo]=List-Presostilo +Name[es]=Estilo de impresión de la lista +Name[et]=Nimekirja trükkimise stiil +Name[eu]=Zerrenda inprimatzeko estiloa +Name[fa]=سبک چاپ فهرست +Name[fi]=Listatulostustyyli +Name[fr]=Impression en liste +Name[fy]=Printstyl foar listen +Name[gl]=Imprimir en Estilo de Lista +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 +Name[ms]=Gaya Cetakan Senarai +Name[nb]=Utskriftsstil for liste +Name[nds]=Listen-Druckstil +Name[ne]=सूची मुद्रण शैली +Name[nl]=Printstijl voor lijsten +Name[nn]=Utskriftsstil for dagbøker +Name[pl]=Styl drukowania listy +Name[pt]=Estilo de Impressão em Lista +Name[pt_BR]=Estilo de Impressão em Lista +Name[ru]=Список +Name[sk]=Štýl tlače zoznamu +Name[sl]=Slog tiskanja v obliki list +Name[sr]=Листајући стил штампе +Name[sr@Latn]=Listajući stil štampe +Name[sv]=List-utskriftsstil +Name[ta]=அச்சு பாணியை பட்டியலிடு +Name[tr]=Liste Yazdırma Tarzı +Name[uk]=Стиль друку списком +Name[zh_CN]=列表打印样式 +Name[zh_TW]=清單列印風格 +Comment=This plugin allows you to print out events and to-dos in list form. +Comment[af]=Hierdie inprop module druk afsprake en te-doen items in lys vorm. +Comment[bg]=Приставката служи за печат на събитията и задачите в списъчна форма. +Comment[ca]=Aquest endollable permet imprimir esdeveniments i tasques pendents en forma de llista. +Comment[cs]=tento modul umožňuje tisknout události a úlohy do seznamu. +Comment[da]=Dette plugin gør at du kan udskrive begivenheder og opgaver på en liste. +Comment[de]=Mit diesem Modul können Ereignisse und Aufgaben in Listenform ausgedruckt werden. +Comment[el]=Αυτό το πρόσθετο σας επιτρέπει να εκτυπώνετε λίστες γεγονότων και προς υλοποίηση λίστες σε μορφή λίστας. +Comment[es]=Esta extensión le permite imprimir eventos y tareas pendientes en forma de lista. +Comment[et]=See plugin võimaldab trükkida sündmusi ja ülesandeid nimekirjana. +Comment[eu]=Plugin honek gertaerak eta egitekoak zerrenda moduan inprimatzeko aukera ematen dizu. +Comment[fa]=این وصله به شما اجازه میدهد که رویدادها و کارهای انجامی را در برگۀ فهرست چاپ کنید. +Comment[fi]=Tämä liitännäinen mahdollistaa tapahtumien ja tehtävien tulostuksen listana. +Comment[fr]=Ce module vous permet d'imprimer les évènements et les tâches sous forme de liste +Comment[fy]=Dizze plugin makket it mooglik om eveneminten en taken yn list foar út te printen. +Comment[gl]=Este plugin permítelle imprimir os eventos e as tarefas e forma de lista. +Comment[hu]=Ezzel a modullal listaként kinyomtathatók a feladatok és események. +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. +Comment[ms]=Plugin ini membenarkan anda mencetak peristiwa dan tugasan dalam borang senarai. +Comment[nb]=Med dette programtillegget kan du skrive ut hendelser og gjørelister på liste-form. +Comment[nds]=Mit dit Moduul köönt Begeefnissen un Opgaven as Listen utdruckt warrn. +Comment[ne]=यो प्लगइनले तपाईँलाई घटना मुद्रण गर्न र सूची फारममा गर्नुपर्ने कार्यहरू गर्न अनुमति दिन्छ । +Comment[nl]=Deze plugin maakt het mogelijk om evenementen en taken in lijstvorm uit te printen. +Comment[nn]=Dette programtillegget lèt deg skriva ut hendingar og hugselister på listeform. +Comment[pl]=Ta wtyczka pozwala drukować zdarzenia i zadania w postaci listy. +Comment[pt]=Este 'plugin' permite-lhe imprimir os eventos e os itens por-fazer no formato de uma lista. +Comment[pt_BR]=Este plug-in permite que você imprima eventos e pendências em forma de lista. +Comment[ru]=Этот модуль позволяет печатать список событий и задач. +Comment[sk]=Tento modul umožní vytlačiť udalosti a úlohy vo forme zoznamu. +Comment[sl]=Ta vstavek vam omogoča natis dogodkov in čakajočih opravil v obliki seznama. +Comment[sr]=Овај прикључак вам омогућава да одштампате догађаје и обавезе у облику листе. +Comment[sr@Latn]=Ovaj priključak vam omogućava da odštampate događaje i obaveze u obliku liste. +Comment[sv]=Det här insticksprogrammet gör att du kan skriva ut händelser och uppgifter i en lista. +Comment[ta]=இந்த சொருகுப்பொருள் பட்டியல் படிவத்தில் உள்ள செய்திகள் மற்றும் செய்யவேண்டியவைகளை அச்சிட உங்களை அனுமதிக்கிறது. +Comment[tr]=Bu eklenti, olayları ve yapılacaklar listesini bir liste biçiminde yazdırmanızı sağlar. +Comment[uk]=Цей втулок дозволяє друкувати події і завдання у вигляді списку. +Comment[zh_CN]=此插件允许您以列表格式打印事件和待办事宜。 +Comment[zh_TW]=此外掛程式允許您以清單格式印出事件與待辦事項。 +Type=Service +ServiceTypes=Calendar/Plugin,KOrganizer/PrintPlugin +X-KDE-KOrganizer-HasSettings=false +X-KDE-PluginInterfaceVersion=2 diff --git a/korganizer/plugins/printing/list/listprint.h b/korganizer/plugins/printing/list/listprint.h new file mode 100644 index 000000000..dc370ba86 --- /dev/null +++ b/korganizer/plugins/printing/list/listprint.h @@ -0,0 +1,61 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef LISTPRINT_H +#define LISTPRINT_H + +#include <klocale.h> +#include "calprintpluginbase.h" + +#ifndef KORG_NOPRINTER +namespace KCal { +class Calendar; +} + +using namespace KCal; + +class CalPrintList : public CalPrintPluginBase +{ + public: + CalPrintList():CalPrintPluginBase() {} + virtual ~CalPrintList() {} + virtual QString description() { return i18n("Print list"); } + virtual QString info() { return i18n("Prints a list of events and to-dos"); } + virtual int sortID() { return 950; } + virtual QWidget *createConfigWidget( QWidget* ); + + public: + virtual void print(QPainter &p, int width, int height); + virtual void readSettingsWidget(); + virtual void setSettingsWidget(); + virtual void loadConfig(); + virtual void saveConfig(); + virtual void setDateRange( const QDate& from, const QDate& to ); + + protected: + bool mUseDateRange; +}; + + +#endif +#endif diff --git a/korganizer/plugins/printing/whatsnext/Makefile.am b/korganizer/plugins/printing/whatsnext/Makefile.am new file mode 100644 index 000000000..f1b1d5aab --- /dev/null +++ b/korganizer/plugins/printing/whatsnext/Makefile.am @@ -0,0 +1,14 @@ +INCLUDES = -I$(top_srcdir)/korganizer/interfaces -I$(top_srcdir)/korganizer/printing -I$(top_srcdir) $(all_includes) + +kde_module_LTLIBRARIES = libkorg_whatsnextprint.la + +libkorg_whatsnextprint_la_SOURCES = calprintwhatsnextconfig_base.ui whatsnextprint.cpp +libkorg_whatsnextprint_la_LDFLAGS = -module $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) +libkorg_whatsnextprint_la_LIBADD = $(LIB_KDECORE) $(LIB_KDEUI) $(top_builddir)/korganizer/printing/libkorg_stdprinting.la + +noinst_HEADERS = + +servicedir = $(kde_servicesdir)/korganizer +service_DATA = whatsnextprint.desktop + +METASOURCES = AUTO diff --git a/korganizer/plugins/printing/whatsnext/calprintwhatsnextconfig_base.ui b/korganizer/plugins/printing/whatsnext/calprintwhatsnextconfig_base.ui new file mode 100644 index 000000000..c93e48ed6 --- /dev/null +++ b/korganizer/plugins/printing/whatsnext/calprintwhatsnextconfig_base.ui @@ -0,0 +1,176 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>CalPrintWhatsNextConfig_Base</class> +<comment>Configuration page for the print whatsnext mode.</comment> +<author>Reinhold Kainhofer <reinhold@kainhofer.com></author> +<widget class="QWidget"> + <property name="name"> + <cstring>CalPrintWhatsNext_Base</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>337</width> + <height>247</height> + </rect> + </property> + <property name="caption"> + <string>CalPrintWhatsNext_Base</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>mDateRangeGroup</cstring> + </property> + <property name="title"> + <string>Date && Time Range</string> + </property> + <property name="selectedId" stdset="0"> + <number>-1</number> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer6</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>15</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel"> + <property name="name"> + <cstring>mFromDateLabel</cstring> + </property> + <property name="text"> + <string>&Start date:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mFromDate</cstring> + </property> + </widget> + <widget class="KDateEdit"> + <property name="name"> + <cstring>mFromDate</cstring> + </property> + <property name="focusPolicy"> + <enum>StrongFocus</enum> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>mToDateLabel</cstring> + </property> + <property name="text"> + <string>&End date:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mToDate</cstring> + </property> + </widget> + <widget class="KDateEdit"> + <property name="name"> + <cstring>mToDate</cstring> + </property> + <property name="focusPolicy"> + <enum>StrongFocus</enum> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>324</width> + <height>21</height> + </size> + </property> + </spacer> + </hbox> + </widget> + </vbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>201</height> + </size> + </property> + </spacer> + </vbox> +</widget> +<customwidgets> + <customwidget> + <class>KDateEdit</class> + <header location="local">libkdepim/kdateedit.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> +</customwidgets> +<images> + <image name="image0"> + <data format="PNG" length="826">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000030149444154789cb59531681b5718c77f0e377c070e3c810a3a70e0041eac51852e0a19e45134830a1d9a4c69a04bc8928e990a693a640e1d0c8642b08742321894c1507991b484c890902bb8701a047760c3bd21701fe4201dde49b6a41a32b8df72dcbbeffdbefffbbfefbd5b1b0c07cce266ebe667ae2006c3c1dada0cdc3be87d6e6c35b0d692a409d9c7ec8b20d65ae29398d19b1114e7e3de4ce98b3f5e10dc0053cf0951b4506496e1b964bf7ce6c585d9054c62d01d617ca48be0596553cf496d8f2c8b01c5f795fc93904e85ec4c01a152857a5d9175d0b2805c872080f18595ccc1499a10a225d4e2fbc2877786fe81253ab6c04c8d106e09db5d43ab0d146e5c64d1a23938fb98a185cea1c33eecfd9eba49eb427dcb201e245365f2b7b2fb5b4a3a31dcb927178afe07d86901df870fefa4842aed6f6b74ba42e52b4014d580e1eb9cbd9d94de7e4aad16d2f9be02d805f0b5e532f927a1ffcacea1777f122a8105b164a7c25faf323a5d9f1f1fd600e1e5bec59e2d4b5c7ef5209d0ad17b8b31864e57c0b3e0815ac3ee33253ab664a770ff5185d1a1cb8d2267d3e58aa1dc7d2508cbe597d0e74fdd269aaaf0f52d414c4ea3e9762c996869e42560d7a72e41c4799a2586e74f95e8d8151481fa86efbe7b3398ac58b1a2b8527589f15451ad303ac2293542ad6648a796278f13a27185e4c4754310facb98c53a79e19a3fdc1426ff28c3d7399d1f7cb25343eb96106cf83c790ce9c4f2eb831855c55485663327992eb6dc8a6259874ed700b0b793323cccb9ffa842b30d6133e3e75fea989ac15a8b16ca76b746b0b92278d919774c5b6d48a78697fb29bbcf52468742a32120909c24e899ce67beed5be2db01e22d1e9485bb620e47f9ee9e606a21bd3f5d3744c7e7c54d55e87443867d8b554515ac5db4620e8e4f62263170fd1cdee90aad7640141992891b0f367c9adfe4049bb07d3b7022bd8c687c0978f46684ee084150b65ac1fcca94591b7a90a496e4c095164fb016a2b192a497795cc0f84817aebe25f7bf70ccc54a575c555c03f78ffa5fc0570d1f0c076bff0232285a0901e2257b0000000049454e44ae426082</data> + </image> +</images> +<tabstops> + <tabstop>mFromDate</tabstop> + <tabstop>mToDate</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kdateedit.h</includehint> + <includehint>kdateedit.h</includehint> +</includehints> +</UI> diff --git a/korganizer/plugins/printing/whatsnext/whatsnextprint.cpp b/korganizer/plugins/printing/whatsnext/whatsnextprint.cpp new file mode 100644 index 000000000..48dd30436 --- /dev/null +++ b/korganizer/plugins/printing/whatsnext/whatsnextprint.cpp @@ -0,0 +1,115 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#ifndef KORG_NOPRINTER + +#include "whatsnextprint.h" + +#include "calprintpluginbase.h" +#include <libkcal/event.h> +#include <libkcal/todo.h> +#include <libkcal/calendar.h> +#include <libkdepim/kdateedit.h> +#include <kconfig.h> +#include <kdebug.h> + +#include <qbuttongroup.h> + +#include "calprintwhatsnextconfig_base.h" + + +class WhatsNextPrintFactory : public KOrg::PrintPluginFactory { + public: + KOrg::PrintPlugin *create() { return new CalPrintWhatsNext; } +}; + +K_EXPORT_COMPONENT_FACTORY( libkorg_whatsnextprint, WhatsNextPrintFactory ) + + +/************************************************************** + * Print What's Next + **************************************************************/ + +QWidget *CalPrintWhatsNext::createConfigWidget( QWidget *w ) +{ + return new CalPrintWhatsNextConfig_Base( w ); +} + +void CalPrintWhatsNext::readSettingsWidget() +{ + CalPrintWhatsNextConfig_Base *cfg = + dynamic_cast<CalPrintWhatsNextConfig_Base*>( mConfigWidget ); + if ( cfg ) { + mFromDate = cfg->mFromDate->date(); + mToDate = cfg->mToDate->date(); + mUseDateRange = (cfg->mDateRangeGroup->selectedId() == 1); + } +} + +void CalPrintWhatsNext::setSettingsWidget() +{ + CalPrintWhatsNextConfig_Base *cfg = + dynamic_cast<CalPrintWhatsNextConfig_Base*>( mConfigWidget ); + if ( cfg ) { + cfg->mFromDate->setDate( mFromDate ); + cfg->mToDate->setDate( mToDate ); + + cfg->mDateRangeGroup->setButton( (mUseDateRange)?1:0 ); + } +} + +void CalPrintWhatsNext::loadConfig() +{ + if ( mConfig ) { + mUseDateRange = mConfig->readBoolEntry( "WhatsNextsInRange", false ); + } + setSettingsWidget(); +} + +void CalPrintWhatsNext::saveConfig() +{ + kdDebug(5850) << "CalPrintWhatsNext::saveConfig()" << endl; + + readSettingsWidget(); + if ( mConfig ) { + mConfig->writeEntry( "WhatsNextsInRange", mUseDateRange ); + } +} + +void CalPrintWhatsNext::setDateRange( const QDate& from, const QDate& to ) +{ + CalPrintPluginBase::setDateRange( from, to ); + CalPrintWhatsNextConfig_Base *cfg = + dynamic_cast<CalPrintWhatsNextConfig_Base*>( mConfigWidget ); + if ( cfg ) { + cfg->mFromDate->setDate( from ); + cfg->mToDate->setDate( to ); + } +} + +void CalPrintWhatsNext::print( QPainter &p, int width, int height ) +{ +} + +#endif diff --git a/korganizer/plugins/printing/whatsnext/whatsnextprint.desktop b/korganizer/plugins/printing/whatsnext/whatsnextprint.desktop new file mode 100644 index 000000000..50131734e --- /dev/null +++ b/korganizer/plugins/printing/whatsnext/whatsnextprint.desktop @@ -0,0 +1,95 @@ +[Desktop Entry] +X-KDE-Library=libkorg_whatsnextprint +Name=What's Next Print Style +Name[af]=Wat is volgende - druk styl +Name[bg]=Стил за отпечатване на "Какво следва" +Name[ca]=Estil d'impressió Què toca ara? +Name[cs]=Styl deníku - co je nového +Name[da]=Hvad er det næste-udskriftsstil +Name[de]=Was-kommt-als-nächstes Druckstil +Name[el]=Στυλ εκτύπωσης 'Τί νέο υπάρχει' +Name[eo]="Kio postsekvas"-Presostilo +Name[es]=Estilo de impresión de «Qué es lo siguiente» +Name[et]="Mis järgmiseks?" trükkimise stiil +Name[eu]="Zer da hurrengoa" inprimatzeko estiloa +Name[fa]=سبک چاپ بعدی چیست +Name[fi]=Mitä seuraavaksi -tulostustyyli +Name[fr]=Impression de la suite du programme +Name[fy]=Printstyl foar Wat komt der no +Name[gl]=Imprimir en Estilo Qué Vén Agora +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 +Name[ms]=Gaya Cetak Apa Seterusnya +Name[nb]=Utskriftsstil for Hva Nå +Name[nds]=Druckstil för "Wat kummt nu"-Indrääg +Name[ne]=पछिल्लो मुद्रण शैली कुन हो +Name[nl]=Printstijl voor Wat komt er nu +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[sk]=Štýl tlače Čo nasleduje +Name[sl]=Slog tiskanja v obliki »Kaj je naslednje« +Name[sr]=Стил штампе „Шта је следеће“ +Name[sr@Latn]=Stil štampe „Šta je sledeće“ +Name[sv]=Vad står på tur-utskriftsstil +Name[ta]=அடுத்டு என்ன அச்சுப் பாணி +Name[tr]=Sıradaki Nedir Yazdırma Tarzı +Name[uk]=Стиль друку "Що далі?" +Name[zh_CN]=下步安排打印样式 +Name[zh_TW]=「下一個是什麼」列印風格 +Comment=This plugin allows you to print out a list of all upcoming events and to-dos. +Comment[af]=Hierdie inprop module druk 'n lys van al die opkomende afsprake en te-doen itemme. +Comment[bg]=Приставката служи за печат на бъдещи събития и задачи в списъчна форма. +Comment[ca]=Aquest endollable us permet imprimir una llista de tots els esdeveniments i tasques pendents propers. +Comment[cs]=Tento modul umožňuje tisk seznamu všech budoucích událostí a úkolů. +Comment[da]=Dette plugin gør at du kan udskrive en liste med alle kommende begivenheder og opgaver. +Comment[de]=Mit diesem Modul kann eine Liste der als nächstes anliegenden Ereignisse und Aufgaben gedruckt werden +Comment[el]=Αυτό το πρόσθετο σας επιτρέπει να εκτυπώνετε μία λίστα γεγονότων ή προς υλοποίηση εργασιών. +Comment[es]=Esta extensión le permite imprimir una lista de todos los eventos y tareas pendientes futuros. +Comment[et]=See plugin võimaldab trükkida kõigi eelseisvate sündmuste ja ülesannete nimekirja. +Comment[eu]=Plugin honek gertatuko diren gertaera eta egitekoen zerrenda bat inprimatzeko aukera ematen dizu. +Comment[fa]=این وصله به شما اجازه میدهد که فهرستی از همۀ رویدادها و کارهای انجامی که بالا میآیند را چاپ کنید. +Comment[fi]=Tämä liitännäinen mahdollistaa tulevien tapahtumien ja tehtävien tulostuksen listana. +Comment[fr]=Ce module vous permet d'imprimer la liste des prochaines évènements et des prochaines tâches. +Comment[fy]=Dizze plugin makket it mooglik om in list fan alle kommende eveneminten en taken út te printsjen. +Comment[gl]=Este engadido permítelle imprimir unha lista de todos os eventos e tarefas por vir. +Comment[hu]=Ezzel a modullal kinyomtathatók a rövidesen aktuálissá váló feladatok és események. +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ų. +Comment[ms]=Plugin ini membenarkan anda mencetak senarai semua peristiwa dan tugasan mendatang. +Comment[nb]=Med dette programtillegget kan du skrive ut en liste over kommende hendelser og ting som skal gjøres. +Comment[nds]=Mit dit Moduul kann en List vun de direktemang nakamen Begeefnissen un Opgaven utdruckt warrn. +Comment[ne]=यो प्लगइनले तपाईँलाई सबै पछि हुने घटना र गर्नुपर्ने कार्यहरुको सूचीको मुद्रण गर्न अनुमति दिन्छ । +Comment[nl]=Deze plugin maakt het mogelijk om een lijst van alle komende evenementen en taken uit te printen. +Comment[nn]=Dette programtillegget lèt deg skriva ut ei liste over alle dei komande hendingane og oppføringane i hugselista. +Comment[pl]=Ta wtyczka pozwala wydrukować wszystkie przyszłe zdarzenia i zadania. +Comment[pt]=Este 'plugin' permite-lhe imprimir uma lista com todos os eventos e itens por-fazer próximos. +Comment[pt_BR]=Este plug-in permite que você imprima uma lista de todos os eventos e pendências que estão por vir. +Comment[ru]=Этот модуль позволяет печатать список будущих событий и задач. +Comment[sk]=Tento modul umožní vytlačiť zoznam všetkých nadchádzajúcich udalostí a úloh. +Comment[sl]=Ta vstavek vam omogoča natis seznama vseh prihahajočih dogodkov in čakajočih opravil. +Comment[sr]=Овај прикључак вам омогућава да одштампате листу свих наступајућих догађаја и обавеза. +Comment[sr@Latn]=Ovaj priključak vam omogućava da odštampate listu svih nastupajućih događaja i obaveza. +Comment[sv]=Det här insticksprogrammet gör att du kan skriva ut en lista med alla kommande händelser och uppgifter. +Comment[ta]=இந்த சொருகுப்பொருள் ஒரு வரப்போகும் நிகழ்வுகளின் பட்டியல் மற்றும் செய்யவேண்டியவைகளை அச்சிட உங்களை அனுமதிக்கிறது. +Comment[tr]=Bu eklenti, sıradaki olayları ve yapılacaklar listesini bir liste biçiminde yazdırmanızı sağlar. +Comment[uk]=Цей втулок дозволяє друкувати список всіх майбутніх подій та завдань. +Comment[zh_CN]=此插件允许您打印所有即将到达的事件和代办事宜。 +Comment[zh_TW]=此外掛程式允許您印出即將發生的事件與待辦事項清單。 +Type=Service +ServiceTypes=Calendar/Plugin,KOrganizer/PrintPlugin +X-KDE-KOrganizer-HasSettings=false +X-KDE-PluginInterfaceVersion=2 diff --git a/korganizer/plugins/printing/whatsnext/whatsnextprint.h b/korganizer/plugins/printing/whatsnext/whatsnextprint.h new file mode 100644 index 000000000..bdba1f71b --- /dev/null +++ b/korganizer/plugins/printing/whatsnext/whatsnextprint.h @@ -0,0 +1,61 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef WHATSNEXTPRINT_H +#define WHATSNEXTPRINT_H + +#include <klocale.h> +#include "calprintpluginbase.h" + +#ifndef KORG_NOPRINTER +namespace KCal { +class Calendar; +} + +using namespace KCal; + +class CalPrintWhatsNext : public CalPrintPluginBase +{ + public: + CalPrintWhatsNext():CalPrintPluginBase() {} + virtual ~CalPrintWhatsNext() {} + virtual QString description() { return i18n("Print What's Next"); } + virtual QString info() { return i18n("Prints a list of all upcoming events and todos."); } + virtual int sortID() { return 50; } + virtual QWidget *createConfigWidget( QWidget* ); + + public: + virtual void print(QPainter &p, int width, int height); + virtual void readSettingsWidget(); + virtual void setSettingsWidget(); + virtual void loadConfig(); + virtual void saveConfig(); + virtual void setDateRange( const QDate& from, const QDate& to ); + + protected: + bool mUseDateRange; +}; + + +#endif +#endif diff --git a/korganizer/plugins/printing/year/Makefile.am b/korganizer/plugins/printing/year/Makefile.am new file mode 100644 index 000000000..f51e29e61 --- /dev/null +++ b/korganizer/plugins/printing/year/Makefile.am @@ -0,0 +1,14 @@ +INCLUDES = -I$(top_srcdir)/korganizer/interfaces -I$(top_srcdir)/korganizer/printing -I$(top_srcdir) $(all_includes) + +kde_module_LTLIBRARIES = libkorg_yearlyprint.la + +libkorg_yearlyprint_la_SOURCES =calprintyearconfig_base.ui yearprint.cpp +libkorg_yearlyprint_la_LDFLAGS = -module $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) +libkorg_yearlyprint_la_LIBADD = $(LIB_KDECORE) $(LIB_KDEUI) $(top_builddir)/korganizer/printing/libkorg_stdprinting.la + +noinst_HEADERS = + +servicedir = $(kde_servicesdir)/korganizer +service_DATA = yearprint.desktop + +METASOURCES = AUTO diff --git a/korganizer/plugins/printing/year/calprintyearconfig_base.ui b/korganizer/plugins/printing/year/calprintyearconfig_base.ui new file mode 100644 index 000000000..43d906d6c --- /dev/null +++ b/korganizer/plugins/printing/year/calprintyearconfig_base.ui @@ -0,0 +1,200 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>CalPrintYearConfig_Base</class> +<comment>Configuration page for the yearly print mode.</comment> +<author>Reinhold Kainhofer <reinhold@kainhofer.com></author> +<widget class="QWidget"> + <property name="name"> + <cstring>CalPrintYear_Base</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>340</width> + <height>237</height> + </rect> + </property> + <property name="caption"> + <string>CalPrintYear_Base</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>mDateRangeGroup</cstring> + </property> + <property name="title"> + <string>Yearly print options</string> + </property> + <property name="selectedId" stdset="0"> + <number>-1</number> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>mYearLabel</cstring> + </property> + <property name="text"> + <string>Print &Year:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mYear</cstring> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>mPagesLabel</cstring> + </property> + <property name="text"> + <string>Number of &pages:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mPages</cstring> + </property> + </widget> + <widget class="QSpinBox" row="0" column="1"> + <property name="name"> + <cstring>mYear</cstring> + </property> + <property name="maxValue"> + <number>2500</number> + </property> + <property name="minValue"> + <number>0</number> + </property> + <property name="value"> + <number>2007</number> + </property> + </widget> + <spacer row="0" column="2"> + <property name="name"> + <cstring>spacer4</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>120</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QComboBox" row="1" column="1"> + <property name="name"> + <cstring>mPages</cstring> + </property> + </widget> + <spacer row="1" column="2"> + <property name="name"> + <cstring>spacer5</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>131</width> + <height>21</height> + </size> + </property> + </spacer> + </grid> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>mDisplayOptionsGroup</cstring> + </property> + <property name="title"> + <string>Display Options</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>mSubDaysLabel</cstring> + </property> + <property name="text"> + <string>Show sub-day events as:</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>mHolidaysLabel</cstring> + </property> + <property name="text"> + <string>Show holidays as:</string> + </property> + </widget> + <widget class="QComboBox" row="0" column="1"> + <item> + <property name="text"> + <string>Text</string> + </property> + </item> + <item> + <property name="text"> + <string>Time Boxes</string> + </property> + </item> + <property name="name"> + <cstring>mSubDays</cstring> + </property> + <property name="currentItem"> + <number>1</number> + </property> + </widget> + <widget class="QComboBox" row="1" column="1"> + <item> + <property name="text"> + <string>Text</string> + </property> + </item> + <item> + <property name="text"> + <string>Time Boxes</string> + </property> + </item> + <property name="name"> + <cstring>mHolidays</cstring> + </property> + </widget> + </grid> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>40</height> + </size> + </property> + </spacer> + </vbox> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/korganizer/plugins/printing/year/yearprint.cpp b/korganizer/plugins/printing/year/yearprint.cpp new file mode 100644 index 000000000..d71cd9f08 --- /dev/null +++ b/korganizer/plugins/printing/year/yearprint.cpp @@ -0,0 +1,204 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#ifndef KORG_NOPRINTER + +#include "calprintyearconfig_base.h" +#include "yearprint.h" + +#include <libkcal/calendar.h> + +#include <kconfig.h> +#include <kdebug.h> +#include <kcalendarsystem.h> +#include <klocale.h> + +#include <qcheckbox.h> +#include <qspinbox.h> +#include <qcombobox.h> +#include <qpainter.h> + +class YearPrintFactory : public KOrg::PrintPluginFactory { + public: + KOrg::PrintPlugin *create() { return new CalPrintYear; } +}; + +K_EXPORT_COMPONENT_FACTORY( libkorg_yearlyprint, YearPrintFactory ) + + +/************************************************************** + * Print Year + **************************************************************/ + +QWidget *CalPrintYear::createConfigWidget( QWidget *w ) +{ + return new CalPrintYearConfig_Base( w ); +} + +void CalPrintYear::readSettingsWidget() +{ + CalPrintYearConfig_Base *cfg = + dynamic_cast<CalPrintYearConfig_Base*>( mConfigWidget ); + if ( cfg ) { + mYear = cfg->mYear->value(); + mPages = cfg->mPages->currentText().toInt(); + mSubDaysEvents = (cfg->mSubDays->currentItem()==0)?Text:TimeBoxes; + mHolidaysEvents = (cfg->mHolidays->currentItem()==0)?Text:TimeBoxes; + } +} + +void CalPrintYear::setSettingsWidget() +{ + CalPrintYearConfig_Base *cfg = + dynamic_cast<CalPrintYearConfig_Base*>( mConfigWidget ); + if ( cfg ) { + const KCalendarSystem *calsys = calendarSystem(); + QDate start; + calsys->setYMD( start, mYear, 1, 1 ); + int months = calsys->monthsInYear( start ); + int pages=0, prevPages=0; + for ( int i=1; i<= months; ++i ) { + pages = (months-1)/i + 1; + if ( pages != prevPages ) { + prevPages = pages; + cfg->mPages->insertItem( QString::number( pages ), 0 ); + } + } + + cfg->mYear->setValue( mYear ); + cfg->mPages->setCurrentText( QString::number( mPages ) ); + + cfg->mSubDays->setCurrentItem( (mSubDaysEvents==Text)?0:1 ); + cfg->mHolidays->setCurrentItem( (mHolidaysEvents==Text)?0:1 ); + } +} + +void CalPrintYear::loadConfig() +{ + if ( mConfig ) { + mYear = mConfig->readNumEntry( "Year", 2007 ); + mPages = mConfig->readNumEntry( "Pages", 1 ); + mSubDaysEvents = mConfig->readNumEntry( "ShowSubDayEventsAs", TimeBoxes ); + mHolidaysEvents = mConfig->readNumEntry( "ShowHolidaysAs", Text ); + } + setSettingsWidget(); +} + +void CalPrintYear::saveConfig() +{ + kdDebug(5850) << "CalPrintYear::saveConfig()" << endl; + + readSettingsWidget(); + if ( mConfig ) { + mConfig->writeEntry( "Year", mYear ); + mConfig->writeEntry( "Pages", mPages ); + mConfig->writeEntry( "Pages", mPages ); + mConfig->writeEntry( "ShowSubDayEventsAs", mSubDaysEvents ); + mConfig->writeEntry( "ShowHolidaysAs", mHolidaysEvents ); + } +} + +KPrinter::Orientation CalPrintYear::defaultOrientation() +{ + return ( mPages == 1 )?(KPrinter::Landscape):(KPrinter::Portrait); +} + + +void CalPrintYear::setDateRange( const QDate& from, const QDate& to ) +{ + CalPrintPluginBase::setDateRange( from, to ); + CalPrintYearConfig_Base *cfg = + dynamic_cast<CalPrintYearConfig_Base*>( mConfigWidget ); + if ( cfg ) { + cfg->mYear->setValue( from.year() ); + } +} + +void CalPrintYear::print( QPainter &p, int width, int height ) +{ +kdDebug()<<"CalPrintYear::print, width: "<<width<<", height: "<<height<<endl; + QRect headerBox( 0, 0, width, headerHeight() ); +kdDebug()<<"headerBox: "<<headerBox<<endl; + const KCalendarSystem *calsys = calendarSystem(); + KLocale *locale = KGlobal::locale(); + if ( !calsys || !locale ) return; + + QDate start; + calsys->setYMD( start, mYear, 1, 1 ); + + // Determine the nr of months and the max nr of days per month (dependent on + // calendar system!!!!) + QDate temp( start ); + int months = calsys->monthsInYear( start ); + int maxdays = 1; + for ( int i = 1; i< months; ++i ) { + maxdays = QMAX( maxdays, temp.daysInMonth() ); + temp = calsys->addMonths( temp, 1 ); + } + + // Now determine the months per page so that the printout fits on + // exactly mPages pages + int monthsPerPage = (months-1) / mPages + 1; + int pages = (months-1) / monthsPerPage + 1; + int thismonth = 0; + temp = start; + for ( int page = 0; page < pages; ++page ) { + if ( page > 0 ) { + mPrinter->newPage(); + } + QDate end( calsys->addMonths( start, monthsPerPage ) ); + end = calsys->addDays( end, -1 ); + QString title; + if ( orientation() == KPrinter::Landscape ) { + title = i18n("date from - to", "%1 - %2"); + } else { + title = i18n("date from -\nto", "%1 -\n%2"); + } + drawHeader( p, title + .arg( locale->formatDate( start ) ) + .arg( locale->formatDate( end ) ), + calsys->addMonths( start, -1), calsys->addMonths( start, monthsPerPage ), + headerBox ); + + QRect monthesBox( headerBox ); + monthesBox.setTop( monthesBox.bottom() + padding() ); + monthesBox.setBottom( height ); + + drawBox( p, BOX_BORDER_WIDTH, monthesBox ); + float monthwidth = float(monthesBox.width()) / float( monthsPerPage ); + + for ( int j=0; j<monthsPerPage; ++j ) { + if ( ++thismonth > months ) break; + int xstart = int(j*monthwidth + 0.5); + int xend = int((j+1)*monthwidth + 0.5); + QRect monthBox( xstart, monthesBox.top(), xend-xstart, monthesBox.height() ); + drawMonth( p, temp, monthBox, maxdays, mSubDaysEvents, mHolidaysEvents ); + + temp = calsys->addMonths( temp, 1 ); + } + start = calsys->addMonths( start, monthsPerPage ); + } +} + +#endif diff --git a/korganizer/plugins/printing/year/yearprint.desktop b/korganizer/plugins/printing/year/yearprint.desktop new file mode 100644 index 000000000..5edafedc2 --- /dev/null +++ b/korganizer/plugins/printing/year/yearprint.desktop @@ -0,0 +1,84 @@ +[Desktop Entry] +X-KDE-Library=libkorg_yearlyprint +Name=Yearly Print Style +Name[af]=Druk styl: Jaarliks +Name[bg]=Стил за отпечатване на годишно разписание +Name[ca]=Estil d'impressió anual +Name[cs]=Roční tiskový styl +Name[da]=Yearly udskriftsstil +Name[de]=Jahres-Druckstil +Name[el]=Στυλ ετήσιας εκτύπωσης +Name[eo]=Pojara Presostilo +Name[es]=Estilo de impresión del diario +Name[et]=Aastakalendri trükkimise stiil +Name[fa]=سبک چاپ نشریه +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]=Жылдық басу стилі +Name[km]=រចនាប័ទ្មបោះពុម្ពប្រចាំឆ្នាំ +Name[lt]=Metų spausdinimo stilius +Name[nb]=Utskriftsstil for kalender +Name[nds]=Johrkalenner-Druckstil +Name[ne]=वार्षिक मुद्रण शैली +Name[nl]=Printstijl voor jaarkalender +Name[pl]=Styl drukowania roku +Name[pt]=Estilo de Impressão em Anuário +Name[pt_BR]=Estilo de Impressão de Calendário Anual +Name[ru]=Календарь на год +Name[sk]=Štýl tlače pre rok +Name[sl]=Letni slog tiskanja +Name[sr]=Годишњи стил штампе +Name[sr@Latn]=Godišnji stil štampe +Name[sv]=Årlig utskriftsstil +Name[tr]=Yıllık Yazdırma Stili +Name[uk]=Стиль друку щорічником +Name[zh_CN]=按年打印样式 +Name[zh_TW]=年度列印風格 +Comment=This plugin allows you to print out a yearly calendar. +Comment[af]=Hierdie inprop module maak dit moontlik om 'n kalender vir 'n hele jaar te druk. +Comment[bg]=Приставката служи за печат на годишния календар. +Comment[ca]=Aquest endollable us permet imprimir un calendari anual. +Comment[cs]=Tento modul umožňuje tisk ročního kalendáře. +Comment[da]=Dette plugin gør at du kan udskrive en årlig kalender +Comment[de]=Mit diesem Modul können Jahresübersichten gedruckt werden. +Comment[el]=Αυτό το πρόσθετο σας επιτρέπει να εκτυπώσετε ένα ετήσιο ημερολόγιο. +Comment[es]=Este plugin le permite imprimir entradas del diario. +Comment[et]=See plugin võimaldab trükkida terve aasta kalendri. +Comment[fa]=این وصله، به شما اجازه میدهد که مدخلهای نشریه )مدخلهای روزانه( را چاپ کنید. +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]=Бұл жылдық күнтізбені басып шығаратын модулі. +Comment[km]=កម្មវិធីជំនួយនេះអនុញ្ញាតឲ្យអ្នកបោះពុម្ពប្រតិទិនប្រចាំឆ្នាំ ។ +Comment[lt]=Šis priedas leidžia spausdinti metų kalendorių. +Comment[mk]=Овој приклучок Ви овозможува да испечатите годишен календар. +Comment[nb]=Med dette programtillegget kan du skrive ut en årskalender. +Comment[nds]=Mit dit Moduul kannst Du en Kalenner för't hele Johr utdrucken. +Comment[ne]=यो प्लगइनले तपाईँलाई वार्षिक पात्रो मुद्रण गर्न अनुमति दिन्छ । +Comment[nl]=Deze plugin maakt het mogelijk om een jaarkalender af te drukken. +Comment[pl]=Ta wtyczka pozwala drukować roczny kalendarz. +Comment[pt]=Este 'plugin' permite-lhe imprimir um calendário anual. +Comment[pt_BR]=Este plug-in permite imprimir um calendário anual. +Comment[ru]=Этот модуль позволяет печатать календарь на год. +Comment[sk]=Tento modul vám umožní vytlačiť kalendár na rok. +Comment[sl]=Ta vstavek vam omogoča natis letnega koledarja. +Comment[sr]=Овај прикључак вам омогућава да одштампате годишњи календар. +Comment[sr@Latn]=Ovaj priključak vam omogućava da odštampate godišnji kalendar. +Comment[sv]=Det här insticksprogrammet gör att du kan skriva ut en årlig kalender. +Comment[tr]=Bu eklenti, yıllık takvimi yazıcıdan çıkartmanızı sağlar. +Comment[uk]=Цей журнал надає можливість друкувати щорічний календар. +Comment[zh_CN]=此插件允许您打印年历。 +Comment[zh_TW]=此外掛程式讓您印出年曆。 +Type=Service +ServiceTypes=Calendar/Plugin,KOrganizer/PrintPlugin +X-KDE-KOrganizer-HasSettings=false +X-KDE-PluginInterfaceVersion=2 diff --git a/korganizer/plugins/printing/year/yearprint.h b/korganizer/plugins/printing/year/yearprint.h new file mode 100644 index 000000000..3191150b2 --- /dev/null +++ b/korganizer/plugins/printing/year/yearprint.h @@ -0,0 +1,65 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef YEARPRINT_H +#define YEARPRINT_H + +#include <klocale.h> +#include "calprintpluginbase.h" + +#ifndef KORG_NOPRINTER +namespace KCal { +class Calendar; +} + +using namespace KCal; + +class CalPrintYear : public CalPrintPluginBase +{ + public: + CalPrintYear():CalPrintPluginBase() {} + virtual ~CalPrintYear() {} + virtual QString description() { return i18n("Print &Year"); } + virtual QString info() { return i18n("Prints a calendar for an entire year"); } + virtual int sortID() { return 900; } + virtual bool enabled() { return true; } + virtual QWidget *createConfigWidget( QWidget* ); + virtual KPrinter::Orientation defaultOrientation(); + + public: + virtual void print(QPainter &p, int width, int height); + virtual void readSettingsWidget(); + virtual void setSettingsWidget(); + virtual void loadConfig(); + virtual void saveConfig(); + virtual void setDateRange( const QDate& from, const QDate& to ); + + protected: + int mYear; + int mPages; + int mSubDaysEvents, mHolidaysEvents; +}; + + +#endif +#endif diff --git a/korganizer/plugins/projectview/Makefile.am b/korganizer/plugins/projectview/Makefile.am new file mode 100644 index 000000000..f84cf7089 --- /dev/null +++ b/korganizer/plugins/projectview/Makefile.am @@ -0,0 +1,20 @@ +# $Id$ + +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/korganizer/interfaces \ + -I$(top_srcdir) -I$(top_srcdir)/kgantt/kgantt $(all_includes) + +kde_module_LTLIBRARIES = libkorg_projectview.la + +libkorg_projectview_la_SOURCES = projectview.cpp koprojectview.cpp +libkorg_projectview_la_LDFLAGS = -module $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) +libkorg_projectview_la_LIBADD = $(top_builddir)/kgantt/kgantt/libkgantt.la $(top_builddir)/korganizer/libkorganizer.la $(LIB_KPARTS) + +noinst_HEADERS = projectview.h koprojectview.h + +servicedir = $(kde_servicesdir)/korganizer +service_DATA = projectview.desktop + +rcdir = $(kde_datadir)/korganizer/plugins +rc_DATA = projectviewui.rc diff --git a/korganizer/plugins/projectview/koprojectview.cpp b/korganizer/plugins/projectview/koprojectview.cpp new file mode 100644 index 000000000..0f2601954 --- /dev/null +++ b/korganizer/plugins/projectview/koprojectview.cpp @@ -0,0 +1,366 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include <qlayout.h> +#include <qheader.h> +#include <qpushbutton.h> +#include <qfont.h> +#include <qlabel.h> +#include <qlineedit.h> +#include <qlistbox.h> +#include <qpopupmenu.h> +#include <qstrlist.h> +#include <qlistview.h> + +#include <kapplication.h> +#include <kdebug.h> +#include <klocale.h> +#include <kglobal.h> +#include <kiconloader.h> +#include <kmessagebox.h> +#include <kconfig.h> +#include <kstandarddirs.h> + +#include <libkcal/vcaldrag.h> + +#include "KGantt.h" + +#include "koprojectview.h" + +using namespace KOrg; + +KOProjectViewItem::KOProjectViewItem(Todo *event,KGanttItem* parentTask, + const QString& text, + const QDateTime& start, + const QDateTime& end) : + KGanttItem(parentTask,text,start,end) +{ + mEvent = event; +} + +KOProjectViewItem::~KOProjectViewItem() +{ +} + +Todo *KOProjectViewItem::event() +{ + return mEvent; +} + + +KOProjectView::KOProjectView(Calendar *calendar,QWidget* parent, + const char* name) : + KOrg::BaseView(calendar,parent,name) +{ + QBoxLayout *topLayout = new QVBoxLayout(this); + + QBoxLayout *topBar = new QHBoxLayout; + topLayout->addLayout(topBar); + + QLabel *title = new QLabel(i18n("Project View"),this); + title->setFrameStyle(QFrame::Panel|QFrame::Raised); + topBar->addWidget(title,1); + + QPushButton *zoomIn = new QPushButton(i18n("Zoom In"),this); + topBar->addWidget(zoomIn,0); + connect(zoomIn,SIGNAL(clicked()),SLOT(zoomIn())); + + QPushButton *zoomOut = new QPushButton(i18n("Zoom Out"),this); + topBar->addWidget(zoomOut,0); + connect(zoomOut,SIGNAL(clicked()),SLOT(zoomOut())); + + QPushButton *menuButton = new QPushButton(i18n("Select Mode"),this); + topBar->addWidget(menuButton,0); + connect(menuButton,SIGNAL(clicked()),SLOT(showModeMenu())); + + createMainTask(); + + mGantt = new KGantt(mMainTask,this); + topLayout->addWidget(mGantt,1); + +#if 0 + mGantt->addHoliday(2000, 10, 3); + mGantt->addHoliday(2001, 10, 3); + mGantt->addHoliday(2000, 12, 24); + + for(int i=1; i<7; ++i) + mGantt->addHoliday(2001, 1, i); +#endif +} + +void KOProjectView::createMainTask() +{ + mMainTask = new KGanttItem(0,i18n("main task"), + QDateTime::currentDateTime(), + QDateTime::currentDateTime()); + mMainTask->setMode(KGanttItem::Rubberband); + mMainTask->setStyle(KGanttItem::DrawBorder | KGanttItem::DrawText | + KGanttItem::DrawHandle); +} + +void KOProjectView::readSettings() +{ + kdDebug(5850) << "KOProjectView::readSettings()" << endl; + + //KConfig *config = kapp->config(); + KConfig config( "korganizerrc", true, false); // Open read-only, no kdeglobals + config.setGroup("Views"); + + QValueList<int> sizes = config.readIntListEntry("Separator ProjectView"); + if (sizes.count() == 2) { + mGantt->splitter()->setSizes(sizes); + } +} + +void KOProjectView::writeSettings(KConfig *config) +{ + kdDebug(5850) << "KOProjectView::writeSettings()" << endl; + + config->setGroup("Views"); + + QValueList<int> list = mGantt->splitter()->sizes(); + config->writeEntry("Separator ProjectView",list); +} + + +void KOProjectView::updateView() +{ + kdDebug(5850) << "KOProjectView::updateView()" << endl; + + // Clear Gantt view + QPtrList<KGanttItem> subs = mMainTask->getSubItems(); + KGanttItem *t=subs.first(); + while(t) { + KGanttItem *nt=subs.next(); + delete t; + t = nt; + } + +#if 0 + KGanttItem* t1 = new KGanttItem(mGantt->getMainTask(), "task 1, no subtasks", + QDateTime::currentDateTime().addDays(10), + QDateTime::currentDateTime().addDays(20) ); + + KGanttItem* t2 = new KGanttItem(mGantt->getMainTask(), "task 2, subtasks, no rubberband", + QDateTime(QDate(2000,10,1)), + QDateTime(QDate(2000,10,31)) ); +#endif + + Todo::List todoList = calendar()->todos(); + +/* + kdDebug(5850) << "KOProjectView::updateView(): Todo List:" << endl; + Event *t; + for(t = todoList.first(); t; t = todoList.next()) { + kdDebug(5850) << " " << t->getSummary() << endl; + + if (t->getRelatedTo()) { + kdDebug(5850) << " (related to " << t->getRelatedTo()->getSummary() << ")" << endl; + } + + QPtrList<Event> l = t->getRelations(); + Event *c; + for(c=l.first();c;c=l.next()) { + kdDebug(5850) << " - relation: " << c->getSummary() << endl; + } + } +*/ + + // Put for each Event a KOProjectViewItem in the list view. Don't rely on a + // specific order of events. That means that we have to generate parent items + // recursively for proper hierarchical display of Todos. + mTodoMap.clear(); + Todo::List::ConstIterator it; + for( it = todoList.begin(); it != todoList.end(); ++it ) { + if ( !mTodoMap.contains( *it ) ) { + insertTodoItem( *it ); + } + } +} + +QMap<Todo *,KGanttItem *>::ConstIterator + KOProjectView::insertTodoItem(Todo *todo) +{ +// kdDebug(5850) << "KOProjectView::insertTodoItem(): " << todo->getSummary() << endl; + Todo *relatedTodo = dynamic_cast<Todo *>(todo->relatedTo()); + if (relatedTodo) { +// kdDebug(5850) << " has Related" << endl; + QMap<Todo *,KGanttItem *>::ConstIterator itemIterator; + itemIterator = mTodoMap.find(relatedTodo); + if (itemIterator == mTodoMap.end()) { +// kdDebug(5850) << " related not yet in list" << endl; + itemIterator = insertTodoItem (relatedTodo); + } + KGanttItem *task = createTask(*itemIterator,todo); + return mTodoMap.insert(todo,task); + } else { +// kdDebug(5850) << " no Related" << endl; + KGanttItem *task = createTask(mMainTask,todo); + return mTodoMap.insert(todo,task); + } +} + +KGanttItem *KOProjectView::createTask(KGanttItem *parent,Todo *todo) +{ + QDateTime startDt; + QDateTime endDt; + + if (todo->hasStartDate() && !todo->hasDueDate()) { + // start date but no due date + startDt = todo->dtStart(); + endDt = QDateTime::currentDateTime(); + } else if (!todo->hasStartDate() && todo->hasDueDate()) { + // due date but no start date + startDt = todo->dtDue(); + endDt = todo->dtDue(); + } else if (!todo->hasStartDate() || !todo->hasDueDate()) { + startDt = QDateTime::currentDateTime(); + endDt = QDateTime::currentDateTime(); + } else { + startDt = todo->dtStart(); + endDt = todo->dtDue(); + } + + KGanttItem *task = new KOProjectViewItem(todo,parent,todo->summary(),startDt, + endDt); + connect(task,SIGNAL(changed(KGanttItem*, KGanttItem::Change)), + SLOT(taskChanged(KGanttItem*,KGanttItem::Change))); + if (todo->relations().count() > 0) { + task->setBrush(QBrush(QColor(240,240,240), QBrush::Dense4Pattern)); + } + + return task; +} + +void KOProjectView::updateConfig() +{ + // FIXME: to be implemented. +} + +Incidence::List KOProjectView::selectedIncidences() +{ + Incidence::List selected; + +/* + KOProjectViewItem *item = (KOProjectViewItem *)(mTodoListView->selectedItem()); + if (item) selected.append(item->event()); +*/ + + return selected; +} + +DateList KOProjectView::selectedDates() +{ + DateList selected; + return selected; +} + +void KOProjectView::changeIncidenceDisplay(Incidence *, int) +{ + updateView(); +} + +void KOProjectView::showDates(const QDate &, const QDate &) +{ + updateView(); +} + +void KOProjectView::showIncidences( const Incidence::List & ) +{ + kdDebug(5850) << "KOProjectView::showIncidences( const Incidence::List & ): not yet implemented" << endl; +} + +#if 0 +void KOProjectView::editItem(QListViewItem *item) +{ + emit editIncidenceSignal(((KOProjectViewItem *)item)->event()); +} + +void KOProjectView::showItem(QListViewItem *item) +{ + emit showIncidenceSignal(((KOProjectViewItem *)item)->event()); +} + +void KOProjectView::popupMenu(QListViewItem *item,const QPoint &,int) +{ + mActiveItem = (KOProjectViewItem *)item; + if (item) mItemPopupMenu->popup(QCursor::pos()); + else mPopupMenu->popup(QCursor::pos()); +} + +void KOProjectView::newTodo() +{ + emit newTodoSignal(); +} + +void KOProjectView::newSubTodo() +{ + if (mActiveItem) { + emit newSubTodoSignal(mActiveItem->event()); + } +} + +void KOProjectView::itemClicked(QListViewItem *item) +{ + if (!item) return; + + KOProjectViewItem *todoItem = (KOProjectViewItem *)item; + int completed = todoItem->event()->isCompleted(); // Completed or not? + + if (todoItem->isOn()) { + if (!completed) { + todoItem->event()->setCompleted(true); + } + } else { + if (completed) { + todoItem->event()->setCompleted(false); + } + } +} +#endif + +void KOProjectView::showModeMenu() +{ + mGantt->menu()->popup(QCursor::pos()); +} + +void KOProjectView::taskChanged(KGanttItem *task,KGanttItem::Change change) +{ + if (task == mMainTask) return; + + KOProjectViewItem *item = (KOProjectViewItem *)task; + + if (change == KGanttItem::StartChanged) { + item->event()->setDtStart(task->getStart()); + } else if (change == KGanttItem::EndChanged) { + item->event()->setDtDue(task->getEnd()); + } +} + +void KOProjectView::zoomIn() +{ + mGantt->zoom(2); +} + +void KOProjectView::zoomOut() +{ + mGantt->zoom(0.5); +} + +#include "koprojectview.moc" diff --git a/korganizer/plugins/projectview/koprojectview.h b/korganizer/plugins/projectview/koprojectview.h new file mode 100644 index 000000000..a356fe024 --- /dev/null +++ b/korganizer/plugins/projectview/koprojectview.h @@ -0,0 +1,118 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef KOPROJECTVIEW_H +#define KOPROJECTVIEW_H +/* $Id$ */ + +#include <qptrlist.h> +#include <qfontmetrics.h> + +#include <qmap.h> + +#include <libkcal/calendar.h> +#include <libkcal/event.h> + +#include "korganizer/baseview.h" +#include "KGanttItem.h" + +class KGantt; +class QLineEdit; +class QFont; +class QLabel; +class QPopupMenu; +class QListBox; +class QStrList; +class QListView; + +/** + This class provides an item of the project view. It is a xQTask with + an additional Event attribute. +*/ +class KOProjectViewItem : public KGanttItem { + public: + KOProjectViewItem(Todo *,KGanttItem* parentTask, const QString& text, + const QDateTime& start, const QDateTime& end); + ~KOProjectViewItem(); + + Todo *event(); + + private: + Todo *mEvent; +}; + + +/** + * This class provides a Gantt-like project view on todo items + * + * @short project view on todo items. + * @author Cornelius Schumacher <schumacher@kde.org> + */ +class KOProjectView : public KOrg::BaseView +{ + Q_OBJECT + public: + KOProjectView(Calendar *, QWidget* parent=0, const char* name=0 ); + ~KOProjectView() {} + + Incidence::List selectedIncidences(); + DateList selectedDates(); + + /** Return number of shown dates. */ + int currentDateCount() { return 0; } + + void readSettings(); + void writeSettings(KConfig *); + + public slots: + void updateView(); + void updateConfig(); + + void changeIncidenceDisplay(Incidence *, int); + + void showDates(const QDate &start, const QDate &end); + void showIncidences( const Incidence::List &incidenceList ); + +/* + void editItem(QListViewItem *item); + void showItem(QListViewItem *item); + void popupMenu(QListViewItem *item,const QPoint &,int); + void newTodo(); + void newSubTodo(); + void itemClicked(QListViewItem *); +*/ + + protected slots: + void showModeMenu(); + void zoomIn(); + void zoomOut(); + void taskChanged(KGanttItem *task,KGanttItem::Change change); + + private: + void createMainTask(); + KGanttItem *createTask(KGanttItem *,Todo *); + + KGantt *mGantt; + KGanttItem *mMainTask; + + QMap<Todo *,KGanttItem *>::ConstIterator insertTodoItem(Todo *todo); + + QMap<Todo *,KGanttItem *> mTodoMap; +}; + +#endif diff --git a/korganizer/plugins/projectview/projectview.cpp b/korganizer/plugins/projectview/projectview.cpp new file mode 100644 index 000000000..3fdf84b43 --- /dev/null +++ b/korganizer/plugins/projectview/projectview.cpp @@ -0,0 +1,81 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include <qfile.h> + +#include <kapplication.h> +#include <kconfig.h> +#include <kstandarddirs.h> +#include <klocale.h> +#include <kdebug.h> +#include <kaction.h> +#include <kglobal.h> + +#include "koprojectview.h" + +#include "projectview.h" +using namespace KOrg; +#include "projectview.moc" + +class ProjectViewFactory : public KOrg::PartFactory { + public: + KOrg::Part *create(KOrg::MainWindow *parent, const char *name) + { + KGlobal::locale()->insertCatalogue( "kgantt" ); + return new ProjectView(parent,name); + } +}; + +K_EXPORT_COMPONENT_FACTORY( libkorg_projectview, ProjectViewFactory ) + + +ProjectView::ProjectView(KOrg::MainWindow *parent, const char *name) : + KOrg::Part(parent,name), mView(0) +{ + setInstance( new KInstance( "korganizer" ) ); + + setXMLFile("plugins/projectviewui.rc"); + + new KAction(i18n("&Project"), "project", 0, this, SLOT(showView()), + actionCollection(), "view_project"); +} + +ProjectView::~ProjectView() +{ +} + +QString ProjectView::info() +{ + return i18n("This plugin provides a Gantt diagram as project view."); +} + +QString ProjectView::shortInfo() +{ + return i18n("Project View Plugin"); +} + +void ProjectView::showView() +{ + if (!mView) { + mView = new KOProjectView(mainWindow()->view()->calendar(), + mainWindow()->view()); + mainWindow()->view()->addView(mView); + } + mainWindow()->view()->showView(mView); +} diff --git a/korganizer/plugins/projectview/projectview.desktop b/korganizer/plugins/projectview/projectview.desktop new file mode 100644 index 000000000..e6c3bef7a --- /dev/null +++ b/korganizer/plugins/projectview/projectview.desktop @@ -0,0 +1,110 @@ +[Desktop Entry] +X-KDE-Library=libkorg_projectview +Name=Project View Plugin for KOrganizer +Name[af]=Projek Besigtig Inplak vir Korganizer +Name[az]=KOrganizer Layihə Nümayiş Əlavəsi +Name[bg]=Приставка на организатора за преглед на проекти +Name[br]=Lugent gwell raktres evit KOrganizer +Name[bs]=Preglednik projekata, dodatak za KOrganizer +Name[ca]=Endollable de vista de projectes per a KOrganizer +Name[cs]=Modul projektového pohledu pro KOrganizer +Name[cy]=Ategyn Golwg Cywaith ar gyfer KTrefnydd +Name[da]=Projektvisning-plugin for KOrganizer +Name[de]=Projektbetrachter-Modul für KOrganizer +Name[el]=Πρόσθετο προβολής έργου του KOrganizer +Name[eo]=Projektrigardo-kromaĵo por Organizilo +Name[es]=Plugin de visor de proyectos para KOrganizer +Name[et]=KOrganizeri projektivaate plugin +Name[eu]=KOrganizer-en proiektu ikuspegi plugin-a +Name[fa]=وصلۀ نمای پروژه برای KOrganizer +Name[fi]=Projektinäkymäliitännäinen KOrganizeriin +Name[fr]=Module afficheur de projet pour KOrganizer +Name[fy]=Projektwerjefteplugin foar KOrganizer +Name[gl]=Extensión para Vista de Proxecto para KOrganizer +Name[he]=תוסף תצוגת פרוייקט ל-KOrganizer +Name[hi]=के-आर्गेनाइज़र के लिए परियोजना दृश्य प्लगइन +Name[hr]=KOrganizer dodatak za pogled na projekt +Name[hu]=Projektnézegető bővítőmodul a KOrganizerhez +Name[is]=Verkefnasýnaríforrit fyrir KOrganizer +Name[it]=Plugin di vista dei progetti per KOrganizer +Name[ja]=KOrganizer プロジェクトビュー プラグイン +Name[ka]= KOrganizer-ის პროექტის ხედის მოდული +Name[kk]=KOrganizer-дің жоба көрінісінің модулі +Name[km]=កម្មវិធីជំនួយទិដ្ឋភាពគម្រោងសម្រាប់ KOrganizer +Name[lt]=Projekto peržiūros priedas, skirtas KOrganizer +Name[lv]=Projekta Skatījuma Iespraudnis KOrganaizeram +Name[ms]=Plugin Paparan Projek untuk KOrganizer +Name[nb]=Programtillegg for prosjektvisning i KOrganizer +Name[nds]=Projektkieker-Moduul för KOrganizer +Name[ne]=केडीई आयोजकका लागि परियोजना दृश्य प्लगइन +Name[nl]=Projectenweergaveplugin voor KOrganizer +Name[nn]=Programtillegg for prosjektvising i KOrganizer +Name[nso]=Plugin ya Pono ya Porojeke ya KMmeakanyi +Name[pl]=Wtyczka przeglądania projektów dla Organizatora +Name[pt]='Plugin' de Gestão de Projectos para o KOrganizer +Name[pt_BR]=Plug-in de Visualização de Projetos para o KOrganizer +Name[ro]=Modul vizualizare proiect pentru KOrganizer +Name[ru]=Просмотр проекта +Name[sk]=KOrganizer modul pre projektový pohľad +Name[sl]=Vstavek za projektni prikaz za KOrganizer +Name[sr]=Прикључак KOrganizer-а за приказ пројекта +Name[sr@Latn]=Priključak KOrganizer-a za prikaz projekta +Name[sv]=Projektvyinsticksprogram för Korganizer +Name[ta]=கேஅமைப்பாளருக்கான திட்டக் காட்சி சொருகுப்பொருள் +Name[tg]=Намоиши нақшот +Name[tr]=KOrganizer için Proje Görüntüleme eklentisi +Name[uk]=Втулок перегляду проектів для KOrganizer +Name[ven]=Plugin ya mbonalelo ya phurodzhekiti ya mudzudzanyi wa K +Name[vi]=Plugin xem dự án cho KOrganizer +Name[xh]=Iprojekthi Ijongela KOrganize i Plugin +Name[zh_CN]=KOrganizer 的项目查看插件 +Name[zh_TW]=KOrganizer 專案檢視外掛程式 +Name[zu]=Project Khombisa Iplagi ye KUmgqugquzeli +Comment=This plugin provides a project planning view for KOrganizer (like the to-do or month views). If you enable this plugin, you can switch to the project view and view your to-do list like in a project planner. +Comment[af]=Hierdie inprop module verskaf 'n projek beplanning aansig vir KOrganizer. Dit lyk baie soos die te-doen of maand aansig. As hierdie inprop module geaktiveer is, kan jy na die projek aansig wissel en na jou te-doen in projek beplanner formaat kyk. +Comment[bg]=Приставката служи за планиране и управление на проекти. +Comment[ca]=Aquest endollable proporciona una vista de planificació de projectes per a KOrganizer (com ara les vistes de pendents o mensual). Si habiliteu aquest endollable, podeu canviar a la vista de projecte i veure la llista de tasques pendents com en un planificador de projectes. +Comment[cs]=Tento modul poskytuje projektový pohled pro KOrganizer (podobnějako úkoly nebo měsíční pohled). Pokud jej povolíte, může přepnout do projektového pohledu a prohlížet si úkoly jako v projektovém plánovači. +Comment[da]=Dette plugin sørger for en projektplanvisning i Korganizer (som ligner gøremål eller månedsvisning). Hvis du aktiverer dette plugin kan du skifte til projektvisning og vise din gøremålsliste som i et projektplan-værktøj. +Comment[de]=Mit diesem Modul wird KOrganizer um eine Projektplanungsansicht (ähnlich der Aufgaben- und Monatsansicht) erweitert. Wenn Sie es einschalten, können Sie zur Projektansicht wechseln und sich Ihre Aufgaben wie in einem Projektplaner ansehen. +Comment[el]=Αυτό το πρόσθετο παρέχει μία προβολή σχεδιασμού έργου για το KOrganizer (όπως η προβολή προς υλοποίηση εργασιών και μηνών). Αν το ενεργοποιήσετε, μπορείτε να αλλάξετε στην προβολή έργου και να δείτε τη λίστα των προς υλοποίηση εργασιών σας σαν σε ένα προγραμματιστή έργου. +Comment[es]=Esta extensión proporciona una vista de planificación de proyectos para KOrganizer (como las vistas de tareas pendientes o de mes). Si activa esta extensión, puede pasar a la vista del proyecto y ver la lista de tareas pendientes como en un planificador de proyectos. +Comment[et]=See plugin lisab KOrganizerile projekti planeerimise vaate (nagu ülesannete või kuuvaade). Selle lubamisel saab lülituda projektivaatele ning näha oma ülesannete nimekirja projektiplaneerija moodi. +Comment[eu]=Plugin honek KOrganizer-en proiektuaren plangintza ikuspegi bat eskeintzen du (egiteko edo hilabete ikupegien antzera). Plugin hau gaitzen baduzu, proiektuaren ikuspegira alda zaitezke eta egitekoak proiektu plangintza batean bezala ikus dezakezu. +Comment[fa]=این وصله، برای KOrganizer یک نمای طراحی پروژه )مثل نماهای کارهای انجامی یا ماهانه( فراهم میکند. اگر این وصله را فعال کنید، میتوانید به نمای پروژه سودهی کرده و مانند طراح پروژه، فهرست کارهای انجامی خود را مشاهده کنید. +Comment[fi]=Tämä liitännäinen mahdollistaa projektin suunnittelunäkymän KOrganizeriin (kuten tehtävälista- tai kuukausinäkymän). Jos kytket tämän päälle, voit vaihtaa projektinäkymään ja katsoa tehtävälistaa kuten projektin suunnittelussa. +Comment[fr]=Ce module propose une vue en projet pour KOrganizer. Si vous activez ce module, vous pourrez afficher vos tâches sous la forme d'un planning projet. +Comment[fy]=Dizze plugin jout jo in projektwerjefte foar KOrganizer (krekt as in takenlist of moannewerjefte). Wannear jo dizze plugin ynskeakelje, kinne jo dizze werjefte oansette om jo takenlist te besjen as projektplanner. +Comment[gl]=Este engadido fornece unha vista planificadora de proxectos para KOrganizer (como as vistas de tarefas ou mensuais). Se habilita este engadid, pode trocar á vista de proxecto e ver a súa lista de tarefas nun planificador de proxectos. +Comment[hu]=Ezzel a modullal projekttervező nézet alakítható ki a KOrganizerben (például a feladatokhoz vagy a havi nézetekhez). Ha aktiválja ezt a modult, átválthat projektnézetbe, hogy a feladatok projekttervként legyenek megtekinthetők. +Comment[is]=Þetta íforrit veitir verkskipulagssýn fyrir KOrganizer (svipað og verkþátta eða mánaðarsýn). Ef þú virkjar þetta íforrit, getur þú á einfaldan hátt skipt yfir í verkefnasýn og skoðað verkþáttalistann þinn í skipuleggjara. +Comment[it]=Questo plugin fornisce una vista di pianificazione progetto per KOrganizer (come la vista delle cose da fare o quella mensile). Se abiliti questo plugin, puoi passare dalla vista progetto alla vista delle cose da fare come in un pianificatore di progetti. +Comment[ja]=このプラグインは KOrganizer にプロジェクト計画ビューを提供します (To-Do ビューや月ビューなど)。このプラグインを有効にすると、プロジェクトビューに切り替えて、スケジュール管理ソフトのように To-Do リストを見ることができます。 +Comment[ka]=ეს მოდული უზრუნველყოფს პროექტის დაგეგმარების ხედს KOrganizer-სთვის(მაგ.: დავალებები ან თვიური მიმოხილვა). თუ ამ მოდულს გაააქტიურებთ,შეგიძლიათ გადართოთ პროექტის ხედზე და იხილოთ თქვენი დავალებათა სია პროექტის მგეგმავის სახით. +Comment[kk]=Бұл KOrganizer-нің жобаны жоспарлау көрінісінің модулі. Модулін орнатсаңыз, осы көрініске ауысып жоспар тізімініңізді жоба жоспарлағышындағы түріне келтіре аласыз. +Comment[km]=កម្មវិធីជំនួយនេះផ្ដល់នូវទិដ្ឋភាពរៀបចំគម្រោងសម្រាប់ korganizer (ដូចជា ទិដ្ឋភាពការងារត្រូវធ្វើ ឬ ទិដ្ឋភាពខែជាដើម) ។ បើអ្នកធ្វើឲ្យកម្មវិធីជំនួយនេះប្រើបាន អ្នកនឹងអាចប្ដូរទិដ្ឋភាពគម្រោង ហើយមើលព្រឹត្តិការណ៍របស់អ្នកដូចជានៅក្នុងកម្មវិធីរៀបចំគម្រោងអញ្ចឹងដែរ ។ +Comment[lt]=Šis priedas pateikia KOrganizaer projekto planavimo vaizdą (panašiai kaip darbų ar mėnesio vaizdai). Jei įjungsite šį įskiepį, galėsite peršokti į projekto vaizdą ir peržiūrėti savo darbų sąrašą kaip projektą. +Comment[ms]=Plugin ini menyediakan paparan perancangan projek untuk KOrganizer (seperti tugasan atau paparan bulan). Jika plugin ini diaktifkan, anda boleh beralih ke paparan projek dan paparkan senarai tugasan seperti dalam perancang projek. +Comment[nb]=Dette programtillegget lager en prosjektplan-visning for KOrganizer (som i gjørelister og månedsvisninger). Slår du på dette programtillegget kan du bytte til prosjektvisning og se på gjørelista som i en prosjektplan. +Comment[nds]=Mit dit Moduul kannst Du in KOrganizer en Projektplaan-Ansicht opropen (jüst as de Opgaven- oder Maandansichten). Wenn Du dit Moduul aktiveerst, kannst Du na de Projektansicht wesseln un Dien Opgavenlist as mit en Projektplaner ankieken. +Comment[ne]=यो प्लगइनले केडीई आयोजकका लागि परियोजना योजना दृश्य उपलब्ध गराउछ (जस्तै: कार्य गर्न वा महिना हेर्न) । तपाईँले यो प्लगइन सक्षम पारेमा, परियोजना दृश्यमा स्विच गर्न र परियोजना योजनाकारमा जस्तै तपाईँको कार्य गर्ने सूची हेर्न सक्नुहुन्छ । +Comment[nl]=Deze plugin biedt een projectweergave voor KOrganizer (net zoals een takenlijst of maandweergave). Wanneer u deze plugin aanzet, kunt u deze weergave aanzetten om uw takenlijst te bekijken als een projectplanner. +Comment[nn]=Dette programtillegget lagar ei prosjektplanvising for KOrganizer (slik som oppgåve- eller månadsvisingane). Dersom du brukar dette programtillegget, kan du visa oppgåvelista som i ein prosjektplanleggjar. +Comment[pl]=Ta wtyczka tworzy widok planowania projektu w KOrganizerze (tak jak widok zadań do zrobienia lub widok miesiąca). Po włączeniu tej wtyczki możliwe jest przełączenie się na widok projektu zadań do zrobienia. +Comment[pt]=Este 'plugin' oferece uma vista de planeamento de projectos para o KOrganizer (como as vistas de itens por-fazer ou mensais). Se activar este 'plugin', poderá mudar para a vista de projecto e ver a sua lista de itens por-fazer como num planeador de projectos. +Comment[pt_BR]=Este plug-in fornece uma visão de planejamento de projeto para o KOrganizer (como as visões de pendências ou de mês). Se você ativar este plugin, você pode mudar para a visão de projeto e ver a sua lista de pendências como num software de planejamento de projetos. +Comment[ru]=Этот модуль показывает проект для органайзера KDE. Если вы подключите этот модуль, вы можете посмотреть ваши задачи в виде проекта. +Comment[sk]=Tento modul poskytuje pohľad na plánovanie projektu pre KOrganizer (ako sú úlohy alebo mesačné pohľady). Ak povolíte tento modul, môžete prepínať projektový pohľad a pohľad na zoznam úloh ako plánovač projektu. +Comment[sl]=Ta vstavek prikazuje projektno načrtovanje za KOrganizer (kot prikaz opravil ali mesečni prikaz). Če omogočite ta vstavek, lahko preklopite na projektni prikaz in si ogledate seznam opravil kot v projektnem prikazu. +Comment[sr]=Овај прикључак пружа приказ планирања пројекта за KOrganizer (као месечни или прикази обавеза). Ако укључите овај прикључак, можете се пребацити на приказ пројекта и разгледати своју листу послова у планеру пројекта. +Comment[sr@Latn]=Ovaj priključak pruža prikaz planiranja projekta za KOrganizer (kao mesečni ili prikazi obaveza). Ako uključite ovaj priključak, možete se prebaciti na prikaz projekta i razgledati svoju listu poslova u planeru projekta. +Comment[sv]=Insticksprogrammet tillhandahåller en projektplaneringsvy i Korganizer (som liknar uppgifts- eller månadsvyn). Om du aktiverar insticksprogrammet kan du byta till projektvyn och visa din uppgiftslista som i ett projektplaneringsverktyg. +Comment[ta]=இந்த சொருகுப்பொருள் KOrganizer-க்கான ஒரு திட்டப்பணி செய்யும் காட்சியை வழங்குகிறது. (செய்யவேண்டியது அல்லது மாத காட்சிகள் போன்ற). இது செயலில் இருந்தால், நீங்கள் திட்டக்காட்சிக்கு செல்லலாம் திட்ட அமைப்பான் போன்ற திட்டக் காட்சிக்கும் செல்லலாம். +Comment[tr]=Bu eklenti, KOrganizer için bir proje planı görünümü sağlar (yapılacaklar ve aylık görünüm gibi). Eğer bu eklentiyi aktif hale getirirseniz, proje görünümüne geçebilir ve yapılacaklar listenizi proje planlayıcısı şeklinde görüntüleyebilirsiniz. +Comment[uk]=Цей втулок показує вигляд планування проектів у KOrganizer (подібно до виглядів завдань або місячного). Якщо увімкнути цей втулок, то можна переглядати ваш список завдань у вигляді плановика проектів. +Comment[zh_CN]=此插件为 KOrganizer 提供了项目规划视图(类似于待办或月视图)。如果您启用了此插件,您可以像项目规划程序那样切换到项目视图并查看您的待办清单。 +Comment[zh_TW]=此外掛程式提供 KOrganizer 專案計畫檢視。如果您開啟此外掛程式,您可以切換專案檢視與待辦事項清單。 +Type=Service +ServiceTypes=KOrganizer/Part +X-KDE-KOrganizer-HasSettings=false +X-KDE-PluginInterfaceVersion=2 diff --git a/korganizer/plugins/projectview/projectview.h b/korganizer/plugins/projectview/projectview.h new file mode 100644 index 000000000..acc9a604f --- /dev/null +++ b/korganizer/plugins/projectview/projectview.h @@ -0,0 +1,42 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef KORG_PROJECTVIEW_H +#define KORG_PROJECTVIEW_H +// $Id$ + +#include <korganizer/part.h> +#include <korganizer/calendarviewbase.h> + +class ProjectView : public KOrg::Part { + Q_OBJECT + public: + ProjectView(KOrg::MainWindow *, const char *); + ~ProjectView(); + + QString info(); + QString shortInfo(); + + private slots: + void showView(); + + private: + KOrg::BaseView *mView; +}; + +#endif diff --git a/korganizer/plugins/projectview/projectviewui.rc b/korganizer/plugins/projectview/projectviewui.rc new file mode 100644 index 000000000..50eb28f37 --- /dev/null +++ b/korganizer/plugins/projectview/projectviewui.rc @@ -0,0 +1,15 @@ +<!DOCTYPE kpartgui> +<kpartgui name="projectview" version="2"> + + <MenuBar> + <Menu name="view"><text>&View</text> + <Action name="view_project"/> + </Menu> + </MenuBar> + <ToolBar name="korganizer_toolbar"> + <Action name="view_project"/> + </ToolBar> + + +</kpartgui> + diff --git a/korganizer/plugins/timespanview/Makefile.am b/korganizer/plugins/timespanview/Makefile.am new file mode 100644 index 000000000..a4431c6a5 --- /dev/null +++ b/korganizer/plugins/timespanview/Makefile.am @@ -0,0 +1,20 @@ +# $Id$ + +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/korganizer/interfaces \ + -I$(top_srcdir) -I$(top_srcdir)/korganizer $(all_includes) + +kde_module_LTLIBRARIES = libkorg_timespanview.la + +libkorg_timespanview_la_SOURCES = lineview.cpp timeline.cpp timespanview.cpp timespanwidget.cpp kotimespanview.cpp +libkorg_timespanview_la_LDFLAGS = -module $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) +libkorg_timespanview_la_LIBADD = $(top_builddir)/korganizer/libkorganizer.la $(LIB_KPARTS) + +noinst_HEADERS = timespanview.h timespanwidget.h kotimespanview.h + +servicedir = $(kde_servicesdir)/korganizer +service_DATA = timespanview.desktop + +rcdir = $(kde_datadir)/korganizer/plugins +rc_DATA = timespanviewui.rc diff --git a/korganizer/plugins/timespanview/cr22-action-timespan.png b/korganizer/plugins/timespanview/cr22-action-timespan.png Binary files differnew file mode 100644 index 000000000..cee81a7c8 --- /dev/null +++ b/korganizer/plugins/timespanview/cr22-action-timespan.png diff --git a/korganizer/plugins/timespanview/kotimespanview.cpp b/korganizer/plugins/timespanview/kotimespanview.cpp new file mode 100644 index 000000000..507438a6a --- /dev/null +++ b/korganizer/plugins/timespanview/kotimespanview.cpp @@ -0,0 +1,128 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qlayout.h> + +#include <kconfig.h> +#include <kstandarddirs.h> +#include <kconfig.h> +#include <libkcal/calendar.h> + +#include "timespanwidget.h" +#include "koglobals.h" + +#include "kotimespanview.h" +#include "kotimespanview.moc" + +KOTimeSpanView::KOTimeSpanView(Calendar *calendar, QWidget *parent, + const char *name) : + KOEventView( calendar, parent, name ) +{ + QBoxLayout *topLayout = new QVBoxLayout( this ); + + mTimeSpanWidget = new TimeSpanWidget( this ); + topLayout->addWidget( mTimeSpanWidget ); + + connect( mTimeSpanWidget, SIGNAL( dateRangeChanged() ), SLOT( updateView() ) ); +} + +KOTimeSpanView::~KOTimeSpanView() +{ +} + +void KOTimeSpanView::readSettings() +{ + kdDebug(5850) << "KOTimeSpanView::readSettings()" << endl; + + KConfig config( "korganizerrc", true, false); // Open read-only, no kdeglobals + config.setGroup("Views"); + + QValueList<int> sizes = config.readIntListEntry("Separator TimeSpanView"); + if (sizes.count() == 2) { + mTimeSpanWidget->setSplitterSizes(sizes); + } +} + +void KOTimeSpanView::writeSettings(KConfig *config) +{ +// kdDebug(5850) << "KOTimeSpanView::writeSettings()" << endl; + + config->setGroup("Views"); + + QValueList<int> list = mTimeSpanWidget->splitterSizes(); + config->writeEntry("Separator TimeSpanView",list); +} + +int KOTimeSpanView::maxDatesHint() +{ + return 0; +} + +int KOTimeSpanView::currentDateCount() +{ + return 0; +} + +Incidence::List KOTimeSpanView::selectedIncidences() +{ + Incidence::List selected; + + return selected; +} + +void KOTimeSpanView::updateView() +{ + insertItems( mTimeSpanWidget->startDateTime().date(), + mTimeSpanWidget->endDateTime().date() ); +} + +void KOTimeSpanView::showDates(const QDate &start, const QDate &end) +{ + QDate s = start.addDays( -2 ); + QDate e = end.addDays( 2 ); + + insertItems( s, e ); +} + +void KOTimeSpanView::insertItems(const QDate &start, const QDate &end) +{ + mTimeSpanWidget->clear(); + mTimeSpanWidget->setDateRange( start, end ); + + Event::List events = calendar()->events( start, end ); + Event::List::ConstIterator it; + for( it = events.begin(); it != events.end(); ++it ) { + mTimeSpanWidget->addItem( *it ); + } + + mTimeSpanWidget->updateView(); +} + +void KOTimeSpanView::showIncidences( const Incidence::List & ) +{ +} + +void KOTimeSpanView::changeIncidenceDisplay(Incidence *, int) +{ +} diff --git a/korganizer/plugins/timespanview/kotimespanview.h b/korganizer/plugins/timespanview/kotimespanview.h new file mode 100644 index 000000000..142ba75f4 --- /dev/null +++ b/korganizer/plugins/timespanview/kotimespanview.h @@ -0,0 +1,61 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KOTIMESPANVIEW_H +#define KOTIMESPANVIEW_H + +#include "koeventview.h" + +class KConfig; +class TimeSpanWidget; + +class KOTimeSpanView : public KOEventView +{ + Q_OBJECT + public: + KOTimeSpanView( Calendar *calendar, QWidget *parent = 0, + const char *name = 0 ); + ~KOTimeSpanView(); + + virtual int maxDatesHint(); + virtual int currentDateCount(); + virtual Incidence::List selectedIncidences(); + DateList selectedDates() { return DateList(); } + + void readSettings(); + void writeSettings( KConfig * ); + + public slots: + virtual void updateView(); + virtual void showDates( const QDate &start, const QDate &end ); + virtual void showIncidences( const Incidence::List &incidenceList ); + + void changeIncidenceDisplay(Incidence *, int); + + private: + void insertItems( const QDate &start, const QDate & end ); + + TimeSpanWidget *mTimeSpanWidget; +}; + +#endif diff --git a/korganizer/plugins/timespanview/lineview.cpp b/korganizer/plugins/timespanview/lineview.cpp new file mode 100644 index 000000000..26779bdb3 --- /dev/null +++ b/korganizer/plugins/timespanview/lineview.cpp @@ -0,0 +1,118 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qpainter.h> + +#include <kdebug.h> + +#include "koprefs.h" + +#include "lineview.h" +#include "lineview.moc" + +LineView::LineView( QWidget *parent, const char *name ) : + QScrollView( parent, name ) +{ + mPixelWidth = 1000; + + mLines.setAutoDelete( true ); + + resizeContents( mPixelWidth, contentsHeight() ); + + viewport()->setBackgroundColor(KOPrefs::instance()->mAgendaBgColor); +} + +LineView::~LineView() +{ +} + +int LineView::pixelWidth() +{ + return mPixelWidth; +} + +void LineView::addLine( int start, int end ) +{ + int count = mLines.count(); + + if( start < 0 ) start = 0; + if( end > mPixelWidth) end = mPixelWidth; + + kdDebug(5850) << "LineView::addLine() col: " << count << " start: " << start + << " end: " << end << endl; + + mLines.append( new Line( count, start, end ) ); +} + +void LineView::clear() +{ + mLines.clear(); + update(); +} + +void LineView::drawContents(QPainter* p, int cx, int cy, int cw, int ch) +{ +// kdDebug(5850) << "LineView::drawContents()" << endl; + +// int mGridSpacingX = 10; + int mGridSpacingY = 20; + +#if 0 + // Draw vertical lines of grid + // kdDebug(5850) << "drawContents cx: " << cx << " cy: " << cy << " cw: " << cw << " ch: " << ch << endl; + int x = ((int)(cx/mGridSpacingX))*mGridSpacingX; + while (x < cx + cw) { + p->drawLine(x,cy,x,cy+ch); + x+=mGridSpacingX; + } +#endif + + // Draw horizontal lines of grid + int y = ((int)(cy/mGridSpacingY))*mGridSpacingY + 10; + while (y < cy + ch) { +// kdDebug(5850) << " y: " << y << endl; + p->drawLine(cx,y,cx+cw,y); + y+=mGridSpacingY; + } + + Line *line; + for( line = mLines.first(); line; line = mLines.next() ) { + int ctop = line->column * 20 + 10 - 5; + int cbottom = line->column * 20 + 10 + 5; + int s = line->start; + int e = line->end; +// kdDebug(5850) << " LineView::drawContents(): ctop: " << ctop << " cbottom: " +// << cbottom << " s: " << s << " e: " << e << endl; + if ( ctop <= (cy+ch) && cbottom >= cy && + s <= (cx+cw) && e >= cx ) { + if ( s < cx ) s = cx; + if ( e > (cx+cw) ) e = cx+cw; + if ( ctop < cy ) ctop = cy; + if ( cbottom > (cy+ch) ) cbottom = cy+ch; +// kdDebug(5850) << " drawContents(): ctop: " << ctop << " cbottom: " +// << cbottom << " s: " << s << " e: " << e << endl; + p->fillRect( s, ctop, e - s + 1, cbottom - ctop + 1, QBrush("red") ); + } + } +} diff --git a/korganizer/plugins/timespanview/lineview.h b/korganizer/plugins/timespanview/lineview.h new file mode 100644 index 000000000..0bb1788a7 --- /dev/null +++ b/korganizer/plugins/timespanview/lineview.h @@ -0,0 +1,59 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef LINEVIEW_H +#define LINEVIEW_H + +#include <qscrollview.h> +#include <qptrlist.h> + +class LineView : public QScrollView +{ + Q_OBJECT + public: + LineView( QWidget *parent = 0, const char *name = 0 ); + virtual ~LineView(); + + int pixelWidth(); + + void addLine( int start, int end ); + + void clear(); + + protected: + void drawContents(QPainter* p, int cx, int cy, int cw, int ch); + + private: + struct Line { + Line( int c, int s, int e ) : column( c ), start( s ), end( e ) {} + int column; + int start; + int end; + }; + + QPtrList<Line> mLines; + int mPixelWidth; +}; + +#endif + diff --git a/korganizer/plugins/timespanview/timeline.cpp b/korganizer/plugins/timespanview/timeline.cpp new file mode 100644 index 000000000..0d679e192 --- /dev/null +++ b/korganizer/plugins/timespanview/timeline.cpp @@ -0,0 +1,87 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qpainter.h> + +#include <kdebug.h> + +#include "timeline.h" +#include "timeline.moc" + +TimeLine::TimeLine( QWidget *parent, const char *name ) : + QScrollView( parent, name ) +{ + mPixelWidth = 1000; + + resizeContents( mPixelWidth, 20 ); + + viewport()->setBackgroundMode( PaletteBackground ); + + setHScrollBarMode(AlwaysOff); + setVScrollBarMode(AlwaysOff); +} + +TimeLine::~TimeLine() +{ +} + +void TimeLine::drawContents(QPainter* p, int cx, int cy, int cw, int ch) +{ + int spacingX = mDaySpacing; + int offsetX = mDayOffset; + + // Draw vertical lines of grid +// kdDebug(5850) << "drawContents cx: " << cx << " cy: " << cy << " cw: " << cw << " ch: " << ch << endl; + int cell = int( (cx - ( spacingX - offsetX ) ) / spacingX ); + int x = cell * spacingX + ( spacingX - offsetX ); +// kdDebug(5850) << " x: " << x << endl; + while (x < cx + cw) { +// kdDebug(5850) << " x: " << x << endl; + p->drawLine(x,cy,x,cy+ch); + p->drawText( x + 5, 15, QString::number( mStartDate.addDays( cell + 1 ).date().day() ) ); + + x += spacingX; + cell++; + } +} + +void TimeLine::setDateRange( const QDateTime &start, const QDateTime &end ) +{ + mStartDate = start; + mEndDate = end; + + mSecsPerPixel = mStartDate.secsTo( mEndDate ) / mPixelWidth; + + mDaySpacing = 60 * 60 * 24 / mSecsPerPixel; + + mDayOffset = QDateTime( mStartDate.date() ).secsTo( mStartDate ) / mSecsPerPixel; + + kdDebug(5850) << "TimeLines::setDateRange(): mDaySpacing: " << mDaySpacing << " mDayOffset: " + << mDayOffset << " mSecsPerPixel: " << mSecsPerPixel << endl; +} + +void TimeLine::setContentsPos( int pos ) +{ + QScrollView::setContentsPos ( pos, 0 ); +} diff --git a/korganizer/plugins/timespanview/timeline.h b/korganizer/plugins/timespanview/timeline.h new file mode 100644 index 000000000..7c9bd8689 --- /dev/null +++ b/korganizer/plugins/timespanview/timeline.h @@ -0,0 +1,56 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef TIMELINE_H +#define TIMELINE_H + +#include <qscrollview.h> +#include <qdatetime.h> + +class TimeLine : public QScrollView +{ + Q_OBJECT + public: + TimeLine( QWidget *parent = 0, const char *name = 0 ); + virtual ~TimeLine(); + + void setDateRange( const QDateTime &start, const QDateTime &end ); + + public slots: + void setContentsPos( int pos ); + + protected: + void drawContents(QPainter* p, int cx, int cy, int cw, int ch); + + private: + QDateTime mStartDate; + QDateTime mEndDate; + + int mPixelWidth; + int mDaySpacing; + int mDayOffset; + int mSecsPerPixel; +}; + +#endif + diff --git a/korganizer/plugins/timespanview/timespanview.cpp b/korganizer/plugins/timespanview/timespanview.cpp new file mode 100644 index 000000000..be95a2c8d --- /dev/null +++ b/korganizer/plugins/timespanview/timespanview.cpp @@ -0,0 +1,80 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include <qfile.h> + +#include <kapplication.h> +#include <kconfig.h> +#include <kstandarddirs.h> +#include <klocale.h> +#include <kdebug.h> +#include <kaction.h> +#include <kglobal.h> + +#include "kotimespanview.h" + +#include "timespanview.h" +using namespace KOrg; +#include "timespanview.moc" + +class TimespanViewFactory : public KOrg::PartFactory { + public: + KOrg::Part *create( KOrg::MainWindow *parent, const char *name ) + { + return new TimespanView( parent, name ); + } +}; + +K_EXPORT_COMPONENT_FACTORY( libkorg_timespanview, TimespanViewFactory ) + + +TimespanView::TimespanView(KOrg::MainWindow *parent, const char *name) : + KOrg::Part(parent,name), mView(0) +{ + setInstance( new KInstance( "korganizer" ) ); + + setXMLFile( "plugins/timespanviewui.rc" ); + + new KAction( i18n("&Timespan"), "timespan", 0, this, SLOT( showView() ), + actionCollection(), "view_timespan" ); +} + +TimespanView::~TimespanView() +{ +} + +QString TimespanView::info() +{ + return i18n("This plugin provides a Gantt-like Timespan view."); +} + +QString TimespanView::shortInfo() +{ + return i18n( "Timespan View Plugin" ); +} + +void TimespanView::showView() +{ + if (!mView) { + mView = new KOTimeSpanView( mainWindow()->view()->calendar(), + mainWindow()->view() ); + mainWindow()->view()->addView( mView ); + } + mainWindow()->view()->showView( mView ); +} diff --git a/korganizer/plugins/timespanview/timespanview.desktop b/korganizer/plugins/timespanview/timespanview.desktop new file mode 100644 index 000000000..13654b46a --- /dev/null +++ b/korganizer/plugins/timespanview/timespanview.desktop @@ -0,0 +1,94 @@ +[Desktop Entry] +X-KDE-Library=libkorg_timespanview +Name=Timespan View Plugin for KOrganizer +Name[af]=Tydlyn aansig inprop module vir KOrganizer +Name[bg]=Приставка за разпределението на времето в организатора +Name[ca]=Endollable de vista de període temporal per a KOrganizer +Name[cs]=Modul časového pohledu pro KOrganizer +Name[da]=Timespan-visning-plugin for KOrganizer +Name[de]=Zeitspannenansicht-Modul für KOrganizer +Name[el]=Πρόσθετο προβολής εργασιών του KOrganizer +Name[eo]=Tempgamrigardo-kromaĵo por Organizilo +Name[es]=Extensión de visor de Timespan para KOrganizer +Name[et]=KOrganizeri perioodivaate plugin +Name[eu]=KOrganizer-rako denbora-barruti ukuspegi plugin-a +Name[fa]=وصلۀ نمای گسترۀ زمان برای KOrganizer +Name[fi]=Ajankulkunäkymäliitännäinen Korganizeriin +Name[fr]=Module d'affichage de planification pour KOrganizer +Name[fy]=Tiidspanneplugin foar KOrganizer +Name[gl]=Extensión de Vista en Unidades de Tempo para KOrganizer +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 +Name[ms]=Plugin Paparan Kitar Waktu untuk KOrganizer +Name[nb]=Programtillegg for periodevisning i KOrganizer +Name[nds]=Tietbruuk-Moduul för KOrganizer +Name[ne]=केडीई आयोजकका लागि समयावधि दृश्य प्लगइन +Name[nl]=Tijdspanneplugin voor KOrganizer +Name[nn]=Programtillegg for tidsromsvising i KOrganizer +Name[pl]=Wtyczka widoku zakresu czasu dla KOrganizera +Name[pt]='Plugin' de Vista de Intervalo de Tempo para o KOrganizer +Name[pt_BR]=Plug-in de Visualização de Período de Tempo Para o KOrganizer +Name[ru]=Диаграмма Ганта для KOrganizer +Name[sk]=KOrganizer modul pre projektový pohľad +Name[sl]=Vstavek za časovni prikaz za KOrganizer +Name[sr]=Прикључак KOrganizer-а за приказ временског распона +Name[sr@Latn]=Priključak KOrganizer-a za prikaz vremenskog raspona +Name[sv]=Tidsintervallvyinsticksprogram för Korganizer +Name[ta]=கேஅமைப்பாளருக்கான திட்டக் காட்சி சொருகுப்பொருள் +Name[tr]=KOrganizer için Zaman Dilimi Görünümü Eklentisi +Name[uk]=Втулок перегляду періоду часу для KOrganizer +Name[zh_CN]=KOrganizer 的时间跨度查看插件 +Name[zh_TW]=KOrganizer 時間檢視外掛程式 +Comment=This plugin provides a timespan view for korganizer (like the to-do or month views). If you enable this plugin, you can switch to the timespan view and view your events like in a Gantt diagram. +Comment[af]=Hierdie inprop module verskaf 'n tydlyn aansig vir KOrganizer. Dit lyk baie soos die te-doen of maand aansig. As hierdie inprop module geaktiveer is, kan jy na die tydlyn aansig wissel en na jou te-doen lys in tydlyn formaat kyk. +Comment[bg]=Приставката служи за преглед на събитията и задачите в зададен период от време. +Comment[ca]=Aquest endollable proporciona una vista d'un període temporal per a KOrganizer (com ara les vistes de pendents o mensual). Si habiliteu aquest endollable, podeu canviar a la vista de període temporal i veure els esdeveniments com en un diagrama de Gantt. +Comment[cs]=Tento modul umožňuje časový pohled pro korganizer (podobně jako úkoly nebo měsíční pohled). Pokud ho povolíte, můžete se přepnout na časový pohled a prohlížet si události v Ganttově diagramu. +Comment[da]=Pluginnet sørger for en tidsintervalsvisning i Korganizer (som ligner gøremål eller månedsvisning). Hvis du aktiverer dette plugin kan du skifte til tidsintervalvisning og vise dine begivenheder som i et Gantt-diagram. +Comment[de]=Mit diesem Modul wird KOrganizer um eine Zeitspannenansicht (ähnlich der Aufgaben- und Monatsansicht) erweitert. Wenn Sie es einschalten, können Sie zur Zeitspannenansicht wechseln und sich Ihre Ereignisse wie in einem Gantt-Diagramm ansehen. +Comment[el]=Αυτό το πρόσθετο παρέχει μία προβολή 'ανοίγματος' χρόνου για το korganizer (όπως οι μηνιαίες προβολές των προς υλοποίηση εργασιών). Αν το ενεργοποιήσετε, μπορείτε να αλλάξετε σε προβολή 'ανοίγματος' χρόνου και να δείτε τα γεγονότα σας όπως ένα διάγραμμα του Gantt. +Comment[es]=Esta extensión proporciona una vista de timespan para korganizer (como la vista de tareas pendientes o la mensual). Si activa esta extensión, puede pasar a la vista de timespan y ver sus eventos como un diagrama de Gantt. +Comment[et]=See plugin lisab KOrganizerile perioodivaate (nagu ülesannete või kuuvaade). Selle lubamisel saab lülituda perioodivaatele ning näha oma sündmusi Gantti diagrammina. +Comment[eu]=Plugin honek KOrganizer-entzat denbora barruti ikuspegi bat eskeintzen du. Plugin hau gaitzen baduzu denbora-barruti ikuspegira alda zaitezke gertaerak Gantt diagrama batean bezala ikusi. +Comment[fa]=این وصله، برای KOrganizer یک نمای گسترۀ زمان )مثل نماهای کارهای انجامی یا ماهانه( فراهم میکند. اگر این وصله را فعال کنید، میتوانید به گسترۀ زمان سودهی کرده و مانند نمودار Gantt، رویدادهای خود را مشاهده کنید. +Comment[fi]=Tämä liitännäinen mahdollistaa ajankulkunäkymän KOrganizeriin (kuten tehtävälista- tai kuukausinäkymän). Jos kytket tämän päälle, voit vaihtaa ajankulkunäkymään ja katsoa tapahtumia kuten Gantt-diagrammissa. +Comment[fr]=Ce module vous permet d'avoir une vue de KOrganizer qui affiche les évènements selon l'axe temporel. Si vous activez cette vue, vous verrez vos évènements comme un diagramme de Gantt. +Comment[fy]=Dizze plugin jout in werjefte foar KOrganizer (lykas de takenlist en de moannewerjefte). Wannear jo dizze plugin ynskeakelje kinne jo kieze foar in werjefte wêryn jo eveneminten yn in Gantt-diagram besjen kinne. +Comment[gl]=Esta extensión fornece unha vista en unidades de tempo (como as vistas mensuais e a vista de tarefas). Se habilita esta extensión, pode trocar a vista en unidades de tempo e ver os seus eventos como un diagrama Gantt. +Comment[hu]=Ezzel modullal egy időszakot lehet áttekinteni a KOrganizerben (például a feladatokat vagy a havi nézeteket). Ha aktiválja ezt a modult, átválthat időszakos nézetbe, hogy az események Gantt-diagramon legyenek megtekinthetők. +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. +Comment[ms]=Plugin ini menyediakan paparan kitar waktu untuk korganizer (seperti tugasan atau paparan bulan). Jika plugin ini diaktifkan,anda boleh beralih ke paparan kitar masa dan paparkan peristiwa seperti dalam diagram Gantt. +Comment[nb]=Dette programtillegget lager en periodevisning for korganizer (slik som gjøreliste og månedsvisning). Hvis du slår på dette programtillegget kan du bytte til periodevisning og se hendelser som i et Gantt-diagram. +Comment[nds]=Mit dit Moduul kannst Du in KOrganizer en Tietbruuk-Ansicht opropen (jüst as de Opgaven- oder Maandansichten). Wenn Du dit Moduul aktiveerst, kannst Du na de Tietbruukansicht wesseln un Dien Begeefnissen as Ganntt-Diagramm ankieken. +Comment[ne]=यो प्लगइनले केडीई आयोजकका लागि समयावधि उपलब्ध गराउछ (गर्नुपर्ने कार्य वा महिना दृश्य जस्तो) । तपाईँले यो प्लगइन सक्षम पारेमा, तपाईँले समयावधि दृश्यमा स्वीच गर्न र गान्ट रेखाचित्र जस्तोमा घटना हेर्न सक्नुहुन्छ । +Comment[nl]=Deze plugin biedt een weergave voor KOrganizer (zoals de takenlijst en de maandweergave). Wanneer u deze plugin inschakelt kunt u kiezen voor een weergave waarin u uw evenementen in een Gantt-diagram kunt bekijken. +Comment[pl]=Ta wtyczka tworzy widok zakresu czasu w KOrganizerze (tak jak widok zadań do zrobienia lub widok miesiąca). Po włączeniu tej wtyczki możliwe jest przełączenie się na widok zakresu czasu i przeglądanie zdarzeń jak na diagramie Gantta. +Comment[pt]=Este 'plugin' oferece uma vista de distribuição temporal para o KOrganizer (como as vistas de itens por-fazer ou mensais). Se activar este 'plugin', poderá mudar para a vista de distribuição temporal e ver os seus eventos como num diagrama de Gantt. +Comment[pt_BR]=Este plug-in fornece uma visão de período de tempo para o KOrganizer (como a visão de pendências e do mês). Se você ativar este plugin, você pode mudar para a visão de período de tempo e ver seus eventos como num diagrama de Gantt. +Comment[ru]=Этот модуль показывает диаграмму Ганта для органайзера KDE. Если вы подключите этот модуль, вы можете посмотреть ваши события в виде диаграммы Ганта. +Comment[sk]=Tento modul poskytuje projektový pohľad pre korganizer (ako sú úlohy alebo mesačné pohľady). Ak povolíte tento modul, môžete prepínať projektový pohľad a pohľad na udalosti ako je Gantt diagram. +Comment[sl]=Ta vstavek ponuja časovni prikaz za KOrganizer (kot prikaz opravil ali mesečni prikaz). Če omogočite ta vstavek, lahko preklopite na časovni prikaz in si ogledate dogodke kot v Ganttovem diagramu. +Comment[sr]=Овај прикључак пружа приказ временског распона за KOrganizer (као месечни или прикази обавеза). Ако укључите овај прикључак, можете се пребацити на приказ временског распона и разгледати своје догађаје као у Гантовом дијаграму. +Comment[sr@Latn]=Ovaj priključak pruža prikaz vremenskog raspona za KOrganizer (kao mesečni ili prikazi obaveza). Ako uključite ovaj priključak, možete se prebaciti na prikaz vremenskog raspona i razgledati svoje događaje kao u Gantovom dijagramu. +Comment[sv]=Insticksprogrammet tillhandahåller en tidsintervallvy i Korganizer (som liknar uppgifts- eller månadsvyn). Om du aktiverar insticksprogrammet kan du byta till idsintervallvyn och visa dina händelser som i ett Gantt-diagram. +Comment[ta]=இந்த சொருகுப்பொருள் korganizerக்கான ஒரு குறுகிய நேரத்தை வழங்குகிறது. lசெய்யவேண்டியவை அல்ல்து மாதக் காட்சிகள் போன்ற). இந்த சொருகுப்பொருள் செயலில் இருந்தால், நீங்கள் குறுகிய நேரக் காட்சி மற்ரும் Gantt விளக்க வரைபடத்தில் உள்ளது போன்ற நிகழ்வுகளை பார்க்கலாம். +Comment[tr]=Bu eklenti, KOrganizer için zaman dilimi görünümü sağlar (yapılacaklar listesi ya da aylık görünüm gibi). Eğer bu eklentiyi aktif hale getirirseniz, zaman dilimi görünümüne geçebilir ve olayları Gantt diyagramı şeklinde görüntüleyebilirsiniz. +Comment[uk]=Цей втулок показує вигляд діаграми Ганта для korganizer (подібно до вигляду завдань та місячного). Якщо увімкнути цей втулок, то можна переглядати ваші події у вигляді діаграми Ганта. +Comment[zh_CN]=此插件为 KOrganizer 提供了时间跨度视图(类似于待办或月视图)。如果您启用了此插件,您可以像甘特图程序那样切换到时间跨度视图并查看您的事件。 +Comment[zh_TW]=此外掛程式提供時間檢視模式。如果您開啟此外掛程式,您可以切換時間檢視,讓您使用類似甘特圖的圖形來檢視事件。 +Type=Service +ServiceTypes=KOrganizer/Part +X-KDE-KOrganizer-HasSettings=false +X-KDE-PluginInterfaceVersion=2 diff --git a/korganizer/plugins/timespanview/timespanview.h b/korganizer/plugins/timespanview/timespanview.h new file mode 100644 index 000000000..e88e140c5 --- /dev/null +++ b/korganizer/plugins/timespanview/timespanview.h @@ -0,0 +1,42 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef KORG_PROJECTVIEW_H +#define KORG_PROJECTVIEW_H +// $Id$ + +#include <korganizer/part.h> +#include <korganizer/calendarviewbase.h> + +class TimespanView : public KOrg::Part { + Q_OBJECT + public: + TimespanView(KOrg::MainWindow *, const char *); + ~TimespanView(); + + QString info(); + QString shortInfo(); + + private slots: + void showView(); + + private: + KOrg::BaseView *mView; +}; + +#endif diff --git a/korganizer/plugins/timespanview/timespanviewui.rc b/korganizer/plugins/timespanview/timespanviewui.rc new file mode 100644 index 000000000..62053159b --- /dev/null +++ b/korganizer/plugins/timespanview/timespanviewui.rc @@ -0,0 +1,15 @@ +<!DOCTYPE kpartgui> +<kpartgui name="timespanview" version="2"> + + <MenuBar> + <Menu name="view"> + <Action name="view_timespan"/> + </Menu> + </MenuBar> + + <ToolBar name="korganizer_toolbar"> + <Action name="view_timespan"/> + </ToolBar> + +</kpartgui> + diff --git a/korganizer/plugins/timespanview/timespanwidget.cpp b/korganizer/plugins/timespanview/timespanwidget.cpp new file mode 100644 index 000000000..23d781f45 --- /dev/null +++ b/korganizer/plugins/timespanview/timespanwidget.cpp @@ -0,0 +1,175 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qsplitter.h> +#include <qlistview.h> +#include <qlayout.h> +#include <qheader.h> +#include <qpushbutton.h> + +#include <klocale.h> +#include <kdebug.h> + +#include <libkcal/event.h> + +#include "lineview.h" +#include "timeline.h" + +#include "timespanwidget.h" +#include "timespanwidget.moc" + +TimeSpanWidget::TimeSpanWidget( QWidget *parent, const char *name ) : + QWidget( parent, name ) +{ + QBoxLayout *topLayout = new QVBoxLayout( this ); + + mSplitter = new QSplitter( this ); + topLayout->addWidget( mSplitter ); + + mList = new QListView( mSplitter ); + mList->addColumn( i18n("Summary") ); + + QWidget *rightPane = new QWidget( mSplitter ); + QBoxLayout *rightPaneLayout = new QVBoxLayout( rightPane ); + + mTimeLine = new TimeLine( rightPane ); + mTimeLine->setFixedHeight( mList->header()->height() ); + rightPaneLayout->addWidget( mTimeLine ); + + mLineView = new LineView( rightPane ); + rightPaneLayout->addWidget( mLineView ); + + QBoxLayout *buttonLayout = new QHBoxLayout( rightPaneLayout ); + + QPushButton *zoomInButton = new QPushButton( i18n("Zoom In"), rightPane ); + connect( zoomInButton, SIGNAL( clicked() ), SLOT( zoomIn() ) ); + buttonLayout->addWidget( zoomInButton ); + + QPushButton *zoomOutButton = new QPushButton( i18n("Zoom Out"), rightPane ); + connect( zoomOutButton, SIGNAL( clicked() ), SLOT( zoomOut() ) ); + buttonLayout->addWidget( zoomOutButton ); + + QPushButton *centerButton = new QPushButton( i18n("Center View"), rightPane ); + connect( centerButton, SIGNAL( clicked() ), SLOT( centerView() ) ); + buttonLayout->addWidget( centerButton ); + + connect(mLineView->horizontalScrollBar(),SIGNAL(valueChanged(int)), + mTimeLine,SLOT(setContentsPos(int))); +} + +TimeSpanWidget::~TimeSpanWidget() +{ +} + +QValueList<int> TimeSpanWidget::splitterSizes() +{ + return mSplitter->sizes(); +} + +void TimeSpanWidget::setSplitterSizes( QValueList<int> sizes ) +{ + mSplitter->setSizes( sizes ); +} + +void TimeSpanWidget::addItem( KCal::Event *event ) +{ + new QListViewItem( mList, event->summary() ); + + QDateTime startDt = event->dtStart(); + QDateTime endDt = event->dtEnd(); + +// kdDebug(5850) << "TimeSpanWidget::addItem(): start: " << startDt.toString() +// << " end: " << endDt.toString() << endl; + +// int startSecs = mStartDate.secsTo( startDt ); +// int durationSecs = startDt.secsTo( endDt ); + +// kdDebug(5850) << "--- startSecs: " << startSecs << " dur: " << durationSecs << endl; + + int startX = mStartDate.secsTo( startDt ) / mSecsPerPixel; + int endX = startX + startDt.secsTo( endDt ) / mSecsPerPixel; + +// kdDebug(5850) << "TimeSpanWidget::addItem(): s: " << startX << " e: " << endX << endl; + + mLineView->addLine( startX, endX ); +} + +void TimeSpanWidget::clear() +{ + mList->clear(); + mLineView->clear(); +} + +void TimeSpanWidget::updateView() +{ +#if QT_VERSION >= 300 + mLineView->updateContents(); + mTimeLine->updateContents(); +#else +#endif +} + +void TimeSpanWidget::setDateRange( const QDateTime &start, const QDateTime &end ) +{ + mStartDate = start; + mEndDate = end; + + mTimeLine->setDateRange( start, end ); + + mSecsPerPixel = mStartDate.secsTo( mEndDate ) / mLineView->pixelWidth(); +} + +QDateTime TimeSpanWidget::startDateTime() +{ + return mStartDate; +} + +QDateTime TimeSpanWidget::endDateTime() +{ + return mEndDate; +} + +void TimeSpanWidget::zoomIn() +{ + int span = mStartDate.daysTo( mEndDate ); + setDateRange( mStartDate.addDays( span / 4 ), mEndDate.addDays( span / -4 ) ); + + emit dateRangeChanged(); +} + +void TimeSpanWidget::zoomOut() +{ + int span = mStartDate.daysTo( mEndDate ); + setDateRange( mStartDate.addDays( span / -4 ), mEndDate.addDays( span / 4 ) ); + + emit dateRangeChanged(); +} + +void TimeSpanWidget::centerView() +{ + QScrollBar *scrollBar = mLineView->horizontalScrollBar(); + int min = scrollBar->minValue(); + int max = scrollBar->maxValue(); + scrollBar->setValue( min + (max-min) / 2 ); +} diff --git a/korganizer/plugins/timespanview/timespanwidget.h b/korganizer/plugins/timespanview/timespanwidget.h new file mode 100644 index 000000000..316437023 --- /dev/null +++ b/korganizer/plugins/timespanview/timespanwidget.h @@ -0,0 +1,78 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef TimeSpanWidget_H +#define TimeSpanWidget_H + +#include <qwidget.h> + +namespace KCal { +class Event; +} + +class QSplitter; +class QListView; +class LineView; +class TimeLine; + +class TimeSpanWidget : public QWidget +{ + Q_OBJECT + public: + TimeSpanWidget( QWidget *parent=0, const char *name=0 ); + virtual ~TimeSpanWidget(); + + void addItem( KCal::Event * ); + + QValueList<int> splitterSizes(); + void setSplitterSizes( QValueList<int> ); + + void clear(); + + void setDateRange( const QDateTime &start, const QDateTime &end ); + + QDateTime startDateTime(); + QDateTime endDateTime(); + + public slots: + void updateView(); + + void zoomIn(); + void zoomOut(); + void centerView(); + + signals: + void dateRangeChanged(); + + private: + QSplitter *mSplitter; + QListView *mList; + TimeLine *mTimeLine; + LineView *mLineView; + + QDateTime mStartDate; + QDateTime mEndDate; + int mSecsPerPixel; +}; + +#endif diff --git a/korganizer/printing/Makefile.am b/korganizer/printing/Makefile.am new file mode 100644 index 000000000..2a194bbfa --- /dev/null +++ b/korganizer/printing/Makefile.am @@ -0,0 +1,34 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/korganizer/interfaces \ + -I$(top_srcdir)/korganizer \ + -I$(top_srcdir) \ + -I$(top_builddir) \ + $(all_includes) + + +lib_LTLIBRARIES = libkocorehelper.la libkorg_stdprinting.la + + +libkocorehelper_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) \ + -no-undefined -version-info 1:0 +libkocorehelper_la_LIBADD = $(LIB_KDEUI) +libkocorehelper_la_SOURCES = cellitem.cpp + +libkorg_stdprinting_la_SOURCES = calprinter.cpp calprintpluginbase.cpp \ + calprintdefaultplugins.cpp \ + calprintdayconfig_base.ui calprintmonthconfig_base.ui \ + calprinttodoconfig_base.ui calprintweekconfig_base.ui \ + calprintincidenceconfig_base.ui +libkorg_stdprinting_la_LDFLAGS = $(KDE_RPATH) $(all_libraries) \ + -no-undefined -version-info 1:0 +libkorg_stdprinting_la_LIBADD = $(LIB_KDEUI) libkocorehelper.la \ + $(top_builddir)/libkdepim/libkdepim.la \ + $(top_builddir)/libkcal/libkcal.la \ + -lkdeprint + + +calprintdir = $(includedir)/korganizer +calprint_HEADERS = calprintpluginbase.h calprinter.h +noinst_HEADERS = cellitem.h + diff --git a/korganizer/printing/calprintdayconfig_base.ui b/korganizer/printing/calprintdayconfig_base.ui new file mode 100644 index 000000000..8abfaa1c4 --- /dev/null +++ b/korganizer/printing/calprintdayconfig_base.ui @@ -0,0 +1,257 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>CalPrintDayConfig_Base</class> +<comment>Configuration page for the print day mode.</comment> +<author>Reinhold Kainhofer <reinhold@kainhofer.com></author> +<widget class="QWidget"> + <property name="name"> + <cstring>CalPrintDay_Base</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>386</width> + <height>202</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QCheckBox" row="1" column="0"> + <property name="name"> + <cstring>mIncludeTodos</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Include to-&dos that are due on the printed day(s)</string> + </property> + <property name="whatsThis" stdset="0"> + <string>You should check this option if you want to print to-dos which are due on one of the dates which are in the supplied date range.</string> + </property> + </widget> + <widget class="QGroupBox" row="0" column="0"> + <property name="name"> + <cstring>mDateRangeGroup</cstring> + </property> + <property name="title"> + <string>Date && Time Range</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer row="0" column="4"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>121</width> + <height>21</height> + </size> + </property> + </spacer> + <spacer row="1" column="4"> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>121</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>mFromDateLabel</cstring> + </property> + <property name="text"> + <string>&Start date:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mFromDate</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>If you want to print more days at once, you can define a range of dates with this option and the <i>End date</i> option. This option is used to define the start date.</string> + </property> + </widget> + <widget class="QLabel" row="1" column="2"> + <property name="name"> + <cstring>mToTimeLabel</cstring> + </property> + <property name="text"> + <string>End ti&me:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mToTime</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>It is possible to print only those events which are inside a given timerange. With this time selection box you can define the end of this time range. The start time should be defined with the <i>Start time</i> option. Note you can automatically modify these settings if you check <i>Extend time range to include all events</i>.</string> + </property> + </widget> + <widget class="QTimeEdit" row="1" column="3"> + <property name="name"> + <cstring>mToTime</cstring> + </property> + <property name="time"> + <time> + <hour>18</hour> + <minute>0</minute> + <second>0</second> + </time> + </property> + <property name="display"> + <set>Minutes|Hours</set> + </property> + <property name="whatsThis" stdset="0"> + <string>It's possible to print only those events which are inside a given timerange. With this time selection box you can define the end of this time range. The start time should be defined with the <i>Start time</i> option. Note you can automatically modify these settings if you check <i>Extend time range to include all events</i>.</string> + </property> + </widget> + <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="5"> + <property name="name"> + <cstring>mIncludeAllEvents</cstring> + </property> + <property name="text"> + <string>E&xtend time range to include all events</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Check this option to automatically determine the required time range, so all events will be shown.</string> + </property> + </widget> + <widget class="KDateEdit" row="0" column="1"> + <property name="name"> + <cstring>mFromDate</cstring> + </property> + <property name="focusPolicy"> + <enum>StrongFocus</enum> + </property> + <property name="whatsThis" stdset="0"> + <string>If you want to print more days at once, you can define a range of dates with this option and the <i>End date</i> option. This option is used to define the start date.</string> + </property> + </widget> + <widget class="QTimeEdit" row="0" column="3"> + <property name="name"> + <cstring>mFromTime</cstring> + </property> + <property name="time"> + <time> + <hour>8</hour> + <minute>0</minute> + <second>0</second> + </time> + </property> + <property name="display"> + <set>Minutes|Hours</set> + </property> + <property name="whatsThis" stdset="0"> + <string>It's possible to print only those events which are inside a given timerange. With this time selection box you can define the start of this time range. The end time should be defined with the <i>End time</i> option. Note you can automatically modify these settings if you check <i>Extend time range to include all events</i>.</string> + </property> + </widget> + <widget class="QLabel" row="0" column="2"> + <property name="name"> + <cstring>mFromTimeLabel</cstring> + </property> + <property name="text"> + <string>Start &time:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mFromTime</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>It is possible to print only those events which are inside a given timerange. With this time selection box you can define the start of this time range. The end time should be defined with the <i>End time</i> option. Note you can automatically modify these settings if you check <i>Extend time range to include all events</i>.</string> + </property> + </widget> + <widget class="KDateEdit" row="1" column="1"> + <property name="name"> + <cstring>mToDate</cstring> + </property> + <property name="focusPolicy"> + <enum>StrongFocus</enum> + </property> + <property name="whatsThis" stdset="0"> + <string>If you want to print more days at once, you can define a range of dates with this option and the <i>Start date</i> option. This option is used to define the end date.</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>mToDateLabel</cstring> + </property> + <property name="text"> + <string>&End date:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mToDate</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>If you want to print more days at once, you can define a range of dates with this option and the <i>Start date</i> option. This option is used to define the end date.</string> + </property> + </widget> + </grid> + </widget> + <widget class="QCheckBox" row="2" column="0"> + <property name="name"> + <cstring>mColors</cstring> + </property> + <property name="text"> + <string>&Use colors</string> + </property> + <property name="whatsThis" stdset="0"> + <string>If you want to use colors to distinguish certain categories on the print, check this option.</string> + </property> + </widget> + <spacer row="3" column="0"> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>201</height> + </size> + </property> + </spacer> + </grid> +</widget> +<tabstops> + <tabstop>mFromDate</tabstop> + <tabstop>mFromTime</tabstop> + <tabstop>mToDate</tabstop> + <tabstop>mToTime</tabstop> + <tabstop>mIncludeAllEvents</tabstop> + <tabstop>mIncludeTodos</tabstop> + <tabstop>mColors</tabstop> +</tabstops> +<includes> + <include location="global" impldecl="in declaration">kdateedit.h</include> +</includes> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>libkdepim/kdateedit.h</includehint> + <includehint>libkdepim/kdateedit.h</includehint> +</includehints> +</UI> diff --git a/korganizer/printing/calprintdefaultplugins.cpp b/korganizer/printing/calprintdefaultplugins.cpp new file mode 100644 index 000000000..d12df1e26 --- /dev/null +++ b/korganizer/printing/calprintdefaultplugins.cpp @@ -0,0 +1,1186 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1998 Preston Brown <pbrown@kde.org> + Copyright (c) 2003 Reinhold Kainhofer <reinhold@kainhofer.com> + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#ifndef KORG_NOPRINTER + +#include <qpainter.h> +#include <qdatetimeedit.h> +#include <qcheckbox.h> +#include <qlineedit.h> +#include <qbuttongroup.h> + +#include <kdebug.h> +#include <kconfig.h> +#include <kcalendarsystem.h> +#include <knuminput.h> +#include <kcombobox.h> + +#include "calprintdefaultplugins.h" + +#include "calprintincidenceconfig_base.h" +#include "calprintdayconfig_base.h" +#include "calprintweekconfig_base.h" +#include "calprintmonthconfig_base.h" +#include "calprinttodoconfig_base.h" + + +/************************************************************** + * Print Incidence + **************************************************************/ + +CalPrintIncidence::CalPrintIncidence() : CalPrintPluginBase() +{ +} + +CalPrintIncidence::~CalPrintIncidence() +{ +} + +QWidget *CalPrintIncidence::createConfigWidget( QWidget *w ) +{ + return new CalPrintIncidenceConfig_Base( w ); +} + +void CalPrintIncidence::readSettingsWidget() +{ + CalPrintIncidenceConfig_Base *cfg = + dynamic_cast<CalPrintIncidenceConfig_Base*>( mConfigWidget ); + if ( cfg ) { + mUseColors = cfg->mColors->isChecked(); + mShowOptions = cfg->mShowDetails->isChecked(); + mShowSubitemsNotes = cfg->mShowSubitemsNotes->isChecked(); + mShowAttendees = cfg->mShowAttendees->isChecked(); + mShowAttachments = cfg->mShowAttachments->isChecked(); + } +} + +void CalPrintIncidence::setSettingsWidget() +{ + CalPrintIncidenceConfig_Base *cfg = + dynamic_cast<CalPrintIncidenceConfig_Base*>( mConfigWidget ); + if ( cfg ) { + cfg->mColors->setChecked( mUseColors ); + cfg->mShowDetails->setChecked(mShowOptions); + cfg->mShowSubitemsNotes->setChecked(mShowSubitemsNotes); + cfg->mShowAttendees->setChecked(mShowAttendees); + cfg->mShowAttachments->setChecked(mShowAttachments); + } +} + +void CalPrintIncidence::loadConfig() +{ + if ( mConfig ) { + mUseColors = mConfig->readBoolEntry( "Use Colors", false ); + mShowOptions = mConfig->readBoolEntry( "Show Options", false ); + mShowSubitemsNotes = mConfig->readBoolEntry( "Show Subitems and Notes", false ); + mShowAttendees = mConfig->readBoolEntry( "Use Attendees", false ); + mShowAttachments = mConfig->readBoolEntry( "Use Attachments", false ); + } + setSettingsWidget(); +} + +void CalPrintIncidence::saveConfig() +{ + readSettingsWidget(); + if ( mConfig ) { + mConfig->writeEntry( "Use Colors", mUseColors ); + mConfig->writeEntry( "Show Options", mShowOptions ); + mConfig->writeEntry( "Show Subitems and Notes", mShowSubitemsNotes ); + mConfig->writeEntry( "Use Attendees", mShowAttendees ); + mConfig->writeEntry( "Use Attachments", mShowAttachments ); + } +} + + +class TimePrintStringsVisitor : public IncidenceBase::Visitor +{ + public: + TimePrintStringsVisitor() {} + + bool act( IncidenceBase *incidence ) + { + return incidence->accept( *this ); + } + QString mStartCaption, mStartString; + QString mEndCaption, mEndString; + QString mDurationCaption, mDurationString; + + 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()); + } else { + mStartCaption = i18n("No start date"); + mStartString = QString::null; + } + + if ( event->hasEndDate() ) { + mEndCaption = i18n("End date: "); + mEndString = (event->doesFloat()) ? (event->dtEndDateStr(false)) : (event->dtEndStr()); + } else if ( event->hasDuration() ) { + mEndCaption = i18n("Duration: "); + int mins = event->duration() / 60; + if ( mins >= 60 ) { + mEndString += i18n( "1 hour ", "%n hours ", mins/60 ); + } + if ( mins%60 > 0 ) { + mEndString += i18n( "1 minute ", "%n minutes ", mins%60 ); + } + } else { + mEndCaption = i18n("No end date"); + mEndString = QString::null; + } + return true; + } + 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()); + } else { + mStartCaption = i18n("No start date"); + mStartString = QString::null; + } + + if ( todo->hasDueDate() ) { + mEndCaption = i18n("Due date: "); + mEndString = (todo->doesFloat()) ? (todo->dtDueDateStr(false)) : (todo->dtDueStr()); + } else { + mEndCaption = i18n("No due date"); + mEndString = QString::null; + } + 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()); + mEndCaption = QString::null; + mEndString = QString::null; + return true; + } +}; + +int CalPrintIncidence::printCaptionAndText( QPainter &p, const QRect &box, const QString &caption, const QString &text, QFont captionFont, QFont textFont ) +{ + QFontMetrics captionFM( captionFont ); + int textWd = captionFM.width( caption ); + QRect textRect( box ); + + QFont oldFont( p.font() ); + p.setFont( captionFont ); + p.drawText( box, Qt::AlignLeft|Qt::AlignTop|Qt::SingleLine, caption ); + + if ( !text.isEmpty() ) { + textRect.setLeft( textRect.left() + textWd ); + p.setFont( textFont ); + p.drawText( textRect, Qt::AlignLeft|Qt::AlignTop|Qt::SingleLine, text ); + } + p.setFont( oldFont ); + return textRect.bottom(); +} + +#include <qfontdatabase.h> +void CalPrintIncidence::print( QPainter &p, int width, int height ) +{ + KLocale *local = KGlobal::locale(); + + QFont oldFont(p.font()); + QFont textFont( "sans-serif", 11, QFont::Normal ); + QFont captionFont( "sans-serif", 11, QFont::Bold ); + p.setFont( textFont ); + int lineHeight = p.fontMetrics().lineSpacing(); + QString cap, txt; + + + Incidence::List::ConstIterator it; + for ( it=mSelectedIncidences.begin(); it!=mSelectedIncidences.end(); ++it ) { + // don't do anything on a 0-pointer! + if ( !(*it) ) continue; + if ( it != mSelectedIncidences.begin() ) mPrinter->newPage(); + + + // PAGE Layout (same for landscape and portrait! astonishingly, it looks good with both!): + // +-----------------------------------+ + // | Header: Summary | + // +===================================+ + // | start: ______ end: _________ | + // | repeats: ___________________ | + // | reminder: __________________ | + // +-----------------------------------+ + // | Location: ______________________ | + // +------------------------+----------+ + // | Description: | Notes or | + // | | Subitems | + // | | | + // | | | + // | | | + // | | | + // | | | + // | | | + // | | | + // | | | + // +------------------------+----------+ + // | Attachments: | Settings | + // | | | + // +------------------------+----------+ + // | Attendees: | + // | | + // +-----------------------------------+ + // | Categories: _____________________ | + // +-----------------------------------+ + + QRect box( 0, 0, width, height ); + QRect titleBox( box ); + titleBox.setHeight( headerHeight() ); + // Draw summary as header, no small calendars in title bar, expand height if needed + int titleBottom = drawHeader( p, (*it)->summary(), QDate(), QDate(), titleBox, true ); + titleBox.setBottom( titleBottom ); + + QRect timesBox( titleBox ); + timesBox.setTop( titleBox.bottom() + padding() ); + timesBox.setHeight( height / 8 ); + + TimePrintStringsVisitor stringVis; + int h = timesBox.top(); + if ( stringVis.act(*it) ) { + QRect textRect( timesBox.left()+padding(), timesBox.top()+padding(), 0, lineHeight ); + textRect.setRight( timesBox.center().x() ); + h = printCaptionAndText( p, textRect, stringVis.mStartCaption, stringVis.mStartString, captionFont, textFont ); + + textRect.setLeft( textRect.right() ); + textRect.setRight( timesBox.right() - padding() ); + h = QMAX( printCaptionAndText( p, textRect, stringVis.mEndCaption, stringVis.mEndString, captionFont, textFont ), h ); + } + + + if ( (*it)->doesRecur() ) { + QRect recurBox( timesBox.left()+padding(), h+padding(), timesBox.right()-padding(), lineHeight ); + // TODO: Convert the recurrence to a string and print it out! + QString recurString( "TODO: Convert Repeat to String!" ); + h = QMAX( printCaptionAndText( p, recurBox, i18n("Repeats: "), recurString, captionFont, textFont ), h ); + } + + QRect alarmBox( timesBox.left()+padding(), h+padding(), timesBox.right()-padding(), lineHeight ); + Alarm::List alarms = (*it)->alarms(); + if ( alarms.count() == 0 ) { + cap = i18n("No reminders"); + txt = QString::null; + } else { + cap = i18n("Reminder: ", "%n reminders: ", alarms.count() ); + + QStringList alarmStrings; + KCal::Alarm::List::ConstIterator it; + for ( it = alarms.begin(); it != alarms.end(); ++it ) { + Alarm *alarm = *it; + + // Alarm offset, copied from koeditoralarms.cpp: + QString offsetstr; + int offset = 0; + if ( alarm->hasStartOffset() ) { + offset = alarm->startOffset().asSeconds(); + 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"); + } + } else if ( alarm->hasEndOffset() ) { + offset = alarm->endOffset().asSeconds(); + if ( offset < 0 ) { + 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"); + } + } + + offset = offset / 60; // make minutes + int useoffset = offset; + + if ( offset % (24*60) == 0 && offset>0 ) { // divides evenly into days? + useoffset = offset / (24*60); + offsetstr = offsetstr.arg( i18n("1 day", "%n days", useoffset ) ); + } else if (offset % 60 == 0 && offset>0 ) { // divides evenly into hours? + useoffset = offset / 60; + offsetstr = offsetstr.arg( i18n("1 hour", "%n hours", useoffset ) ); + } else { + useoffset = offset; + offsetstr = offsetstr.arg( i18n("1 minute", "%n minutes", useoffset ) ); + } + alarmStrings << offsetstr; + } + txt = alarmStrings.join( i18n("Spacer for the joined list of categories", ", ") ); + + } + h = QMAX( printCaptionAndText( p, alarmBox, cap, txt, captionFont, textFont ), h ); + + + QRect 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 ); + + + QRect locationBox( timesBox ); + locationBox.setTop( timesBox.bottom() + padding() ); + locationBox.setHeight( 0 ); + int locationBottom = drawBoxWithCaption( p, locationBox, i18n("Location: "), + (*it)->location(), /*sameLine=*/true, /*expand=*/true, captionFont, textFont ); + locationBox.setBottom( locationBottom ); + + + // Now start constructing the boxes from the bottom: + QRect categoriesBox( locationBox ); + categoriesBox.setBottom( box.bottom() ); + categoriesBox.setTop( categoriesBox.bottom() - lineHeight - 2*padding() ); + + + QRect attendeesBox( box.left(), categoriesBox.top()-padding()-box.height()/9, box.width(), box.height()/9 ); + if ( !mShowAttendees ) { + attendeesBox.setTop( categoriesBox.top() ); + } + QRect attachmentsBox( box.left(), attendeesBox.top()-padding()-box.height()/9, box.width()*3/4 - padding(), box.height()/9 ); + QRect optionsBox( attachmentsBox.right() + padding(), attachmentsBox.top(), 0, 0 ); + optionsBox.setRight( box.right() ); + optionsBox.setBottom( attachmentsBox.bottom() ); + QRect 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; + + + QRect descriptionBox( notesBox ); + descriptionBox.setLeft( box.left() ); + descriptionBox.setRight( mShowOptions?(attachmentsBox.right()):(box.right()) ); + + 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:"), + QString::null, /*sameLine=*/false, /*expand=*/false, + captionFont, textFont ); + QPen oldPen( p.pen() ); + p.setPen( Qt::DotLine ); + while ( (notesPosition += int(1.5*lineHeight)) < notesBox.bottom() ) { + p.drawLine( notesBox.left()+padding(), notesPosition, notesBox.right()-padding(), notesPosition ); + } + p.setPen( oldPen ); + } else { + int subitemsStart = 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:"), QString::null, /*sameLine=*/false, + /*expand=*/false, captionFont, textFont ); + // TODO: Print out the attachments somehow + } + + if ( mShowAttendees ) { + Attendee::List attendees = (*it)->attendees(); + QString attendeeCaption; + if ( attendees.count() == 0 ) + attendeeCaption = i18n("No Attendees"); + else + attendeeCaption = i18n("1 Attendee:", "%n Attendees:", attendees.count() ); + QString attendeeString; + for ( Attendee::List::ConstIterator ait = attendees.begin(); ait != attendees.end(); ++ait ) { + if ( !attendeeString.isEmpty() ) attendeeString += "\n"; + attendeeString += i18n("Formatting of an attendee: " + "'Name (Role): Status', e.g. 'Reinhold Kainhofer " + "<reinhold@kainhofer.com> (Participant): Awaiting Response'", + "%1 (%2): %3") + .arg( (*ait)->fullName() ) + .arg( (*ait)->roleStr() ).arg( (*ait)->statusStr() ); + } + drawBoxWithCaption( p, attendeesBox, i18n("Attendees:"), attendeeString, + /*sameLine=*/false, /*expand=*/false, captionFont, textFont ); + } + + if ( mShowOptions ) { + QString optionsString; + if ( !(*it)->statusStr().isEmpty() ) { + optionsString += i18n("Status: %1").arg( (*it)->statusStr() ); + optionsString += "\n"; + } + if ( !(*it)->secrecyStr().isEmpty() ) { + optionsString += i18n("Secrecy: %1").arg( (*it)->secrecyStr() ); + optionsString += "\n"; + } + if ( (*it)->type() == "Event" ) { + Event *e = static_cast<Event*>(*it); + if ( e->transparency() == Event::Opaque ) { + optionsString += i18n("Show as: Busy"); + } else { + optionsString += i18n("Show as: Free"); + } + optionsString += "\n"; + } else if ( (*it)->type() == "Todo" ) { + Todo *t = static_cast<Todo*>(*it); + if ( t->isOverdue() ) { + optionsString += i18n("This task is overdue!"); + optionsString += "\n"; + } + } else if ( (*it)->type() == "Journal" ) { + //TODO: Anything Journal-specific? + } + 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 ); + } + p.setFont( oldFont ); +} + +/************************************************************** + * Print Day + **************************************************************/ + +CalPrintDay::CalPrintDay() : CalPrintPluginBase() +{ +} + +CalPrintDay::~CalPrintDay() +{ +} + +QWidget *CalPrintDay::createConfigWidget( QWidget *w ) +{ + return new CalPrintDayConfig_Base( w ); +} + +void CalPrintDay::readSettingsWidget() +{ + CalPrintDayConfig_Base *cfg = + dynamic_cast<CalPrintDayConfig_Base*>( mConfigWidget ); + if ( cfg ) { + mFromDate = cfg->mFromDate->date(); + mToDate = cfg->mToDate->date(); + + mStartTime = cfg->mFromTime->time(); + mEndTime = cfg->mToTime->time(); + mIncludeAllEvents = cfg->mIncludeAllEvents->isChecked(); + + mIncludeTodos = cfg->mIncludeTodos->isChecked(); + mUseColors = cfg->mColors->isChecked(); + } +} + +void CalPrintDay::setSettingsWidget() +{ + CalPrintDayConfig_Base *cfg = + dynamic_cast<CalPrintDayConfig_Base*>( mConfigWidget ); + if ( cfg ) { + cfg->mFromDate->setDate( mFromDate ); + cfg->mToDate->setDate( mToDate ); + + cfg->mFromTime->setTime( mStartTime ); + cfg->mToTime->setTime( mEndTime ); + cfg->mIncludeAllEvents->setChecked( mIncludeAllEvents ); + + cfg->mIncludeTodos->setChecked( mIncludeTodos ); + cfg->mColors->setChecked( mUseColors ); + } +} + +void CalPrintDay::loadConfig() +{ + if ( mConfig ) { + QDate dt; + QTime tm1( dayStart() ); + QDateTime startTm( dt, tm1 ); + QDateTime endTm( dt, tm1.addSecs( 12 * 60 * 60 ) ); + mStartTime = mConfig->readDateTimeEntry( "Start time", &startTm ).time(); + mEndTime = mConfig->readDateTimeEntry( "End time", &endTm ).time(); + mIncludeTodos = mConfig->readBoolEntry( "Include todos", false ); + mIncludeAllEvents = mConfig->readBoolEntry( "Include all events", false ); + } + setSettingsWidget(); +} + +void CalPrintDay::saveConfig() +{ + readSettingsWidget(); + if ( mConfig ) { + mConfig->writeEntry( "Start time", QDateTime( QDate(), mStartTime ) ); + mConfig->writeEntry( "End time", QDateTime( QDate(), mEndTime ) ); + mConfig->writeEntry( "Include todos", mIncludeTodos ); + mConfig->writeEntry( "Include all events", mIncludeAllEvents ); + } +} + +void CalPrintDay::setDateRange( const QDate& from, const QDate& to ) +{ + CalPrintPluginBase::setDateRange( from, to ); + CalPrintDayConfig_Base *cfg = + dynamic_cast<CalPrintDayConfig_Base*>( mConfigWidget ); + if ( cfg ) { + cfg->mFromDate->setDate( from ); + cfg->mToDate->setDate( to ); + } +} + +void CalPrintDay::print( QPainter &p, int width, int height ) +{ + QDate curDay( mFromDate ); + + do { + QTime curStartTime( mStartTime ); + QTime curEndTime( mEndTime ); + + // For an invalid time range, simply show one hour, starting at the hour + // before the given start time + if ( curEndTime <= curStartTime ) { + curStartTime = QTime( curStartTime.hour(), 0, 0 ); + curEndTime = curStartTime.addSecs( 3600 ); + } + + KLocale *local = KGlobal::locale(); + QRect headerBox( 0, 0, width, headerHeight() ); + drawHeader( p, local->formatDate( curDay ), curDay, QDate(), headerBox ); + + + Event::List eventList = mCalendar->events( curDay, + EventSortStartDate, + SortDirectionAscending ); + + p.setFont( QFont( "sans-serif", 12 ) ); + + // TODO: Find a good way to determine the height of the all-day box + QRect allDayBox( TIMELINE_WIDTH + padding(), headerBox.bottom() + padding(), + 0, height / 20 ); + allDayBox.setRight( width ); + int allDayHeight = drawAllDayBox( p, eventList, curDay, true, allDayBox ); + + QRect dayBox( allDayBox ); + dayBox.setTop( allDayHeight /*allDayBox.bottom()*/ ); + dayBox.setBottom( height ); + drawAgendaDayBox( p, eventList, curDay, mIncludeAllEvents, + curStartTime, curEndTime, dayBox ); + + QRect tlBox( dayBox ); + tlBox.setLeft( 0 ); + tlBox.setWidth( TIMELINE_WIDTH ); + drawTimeLine( p, curStartTime, curEndTime, tlBox ); + curDay = curDay.addDays( 1 ); + if ( curDay <= mToDate ) mPrinter->newPage(); + } while ( curDay <= mToDate ); +} + + + +/************************************************************** + * Print Week + **************************************************************/ + +CalPrintWeek::CalPrintWeek() : CalPrintPluginBase() +{ +} + +CalPrintWeek::~CalPrintWeek() +{ +} + +QWidget *CalPrintWeek::createConfigWidget( QWidget *w ) +{ + return new CalPrintWeekConfig_Base( w ); +} + +void CalPrintWeek::readSettingsWidget() +{ + CalPrintWeekConfig_Base *cfg = + dynamic_cast<CalPrintWeekConfig_Base*>( mConfigWidget ); + if ( cfg ) { + mFromDate = cfg->mFromDate->date(); + mToDate = cfg->mToDate->date(); + + mWeekPrintType = (eWeekPrintType)( cfg->mPrintType->id( + cfg->mPrintType->selected() ) ); + + mStartTime = cfg->mFromTime->time(); + mEndTime = cfg->mToTime->time(); + + mIncludeTodos = cfg->mIncludeTodos->isChecked(); + mUseColors = cfg->mColors->isChecked(); + } +} + +void CalPrintWeek::setSettingsWidget() +{ + CalPrintWeekConfig_Base *cfg = + dynamic_cast<CalPrintWeekConfig_Base*>( mConfigWidget ); + if ( cfg ) { + cfg->mFromDate->setDate( mFromDate ); + cfg->mToDate->setDate( mToDate ); + + cfg->mPrintType->setButton( mWeekPrintType ); + + cfg->mFromTime->setTime( mStartTime ); + cfg->mToTime->setTime( mEndTime ); + + cfg->mIncludeTodos->setChecked( mIncludeTodos ); + cfg->mColors->setChecked( mUseColors ); + } +} + +void CalPrintWeek::loadConfig() +{ + if ( mConfig ) { + QDate dt; + QTime tm1( dayStart() ); + QDateTime startTm( dt, tm1 ); + QDateTime endTm( dt, tm1.addSecs( 43200 ) ); + mStartTime = mConfig->readDateTimeEntry( "Start time", &startTm ).time(); + mEndTime = mConfig->readDateTimeEntry( "End time", &endTm ).time(); + mIncludeTodos = mConfig->readBoolEntry( "Include todos", false ); + mWeekPrintType =(eWeekPrintType)( mConfig->readNumEntry( "Print type", (int)Filofax ) ); + } + setSettingsWidget(); +} + +void CalPrintWeek::saveConfig() +{ + readSettingsWidget(); + if ( mConfig ) { + mConfig->writeEntry( "Start time", QDateTime( QDate(), mStartTime ) ); + mConfig->writeEntry( "End time", QDateTime( QDate(), mEndTime ) ); + mConfig->writeEntry( "Include todos", mIncludeTodos ); + mConfig->writeEntry( "Print type", int( mWeekPrintType ) ); + } +} + +KPrinter::Orientation CalPrintWeek::defaultOrientation() +{ + if ( mWeekPrintType == Filofax ) return KPrinter::Portrait; + else if ( mWeekPrintType == SplitWeek ) return KPrinter::Portrait; + else return KPrinter::Landscape; +} + +void CalPrintWeek::setDateRange( const QDate &from, const QDate &to ) +{ + CalPrintPluginBase::setDateRange( from, to ); + CalPrintWeekConfig_Base *cfg = + dynamic_cast<CalPrintWeekConfig_Base*>( mConfigWidget ); + if ( cfg ) { + cfg->mFromDate->setDate( from ); + cfg->mToDate->setDate( to ); + } +} + +void CalPrintWeek::print( QPainter &p, int width, int height ) +{ + QDate curWeek, fromWeek, toWeek; + + // correct begin and end to first and last day of week + int weekdayCol = weekdayColumn( mFromDate.dayOfWeek() ); + fromWeek = mFromDate.addDays( -weekdayCol ); + weekdayCol = weekdayColumn( mFromDate.dayOfWeek() ); + toWeek = mToDate.addDays( 6 - weekdayCol ); + + curWeek = fromWeek.addDays( 6 ); + KLocale *local = KGlobal::locale(); + + QString line1, line2, title; + QRect headerBox( 0, 0, width, headerHeight() ); + QRect weekBox( headerBox ); + weekBox.setTop( headerBox.bottom() + padding() ); + weekBox.setBottom( height ); + + switch ( mWeekPrintType ) { + case Filofax: + do { + line1 = local->formatDate( curWeek.addDays( -6 ) ); + line2 = local->formatDate( curWeek ); + if ( orientation() == KPrinter::Landscape ) { + title = i18n("date from-to", "%1 - %2"); + } else { + title = i18n("date from-\nto", "%1 -\n%2");; + } + title = title.arg( line1 ).arg( line2 ); + drawHeader( p, title, curWeek.addDays( -6 ), QDate(), headerBox ); + drawWeek( p, curWeek, weekBox ); + curWeek = curWeek.addDays( 7 ); + if ( curWeek <= toWeek ) + mPrinter->newPage(); + } while ( curWeek <= toWeek ); + break; + + case Timetable: + default: + do { + line1 = local->formatDate( curWeek.addDays( -6 ) ); + line2 = local->formatDate( curWeek ); + if ( orientation() == KPrinter::Landscape ) { + title = i18n("date from - to (week number)", "%1 - %2 (Week %3)"); + } else { + title = i18n("date from -\nto (week number)", "%1 -\n%2 (Week %3)"); + } + title = title.arg( line1 ).arg( line2 ).arg( curWeek.weekNumber() ); + drawHeader( p, title, curWeek, QDate(), headerBox ); + QRect weekBox( headerBox ); + weekBox.setTop( headerBox.bottom() + padding() ); + weekBox.setBottom( height ); + + drawTimeTable( p, fromWeek, curWeek, mStartTime, mEndTime, weekBox ); + fromWeek = fromWeek.addDays( 7 ); + curWeek = fromWeek.addDays( 6 ); + if ( curWeek <= toWeek ) + mPrinter->newPage(); + } while ( curWeek <= toWeek ); + break; + + case SplitWeek: { + QRect weekBox1( weekBox ); + // On the left side there are four days (mo-th) plus the timeline, + // on the right there are only three days (fr-su) plus the timeline. Don't + // use the whole width, but rather give them the same width as on the left. + weekBox1.setRight( int( ( width - TIMELINE_WIDTH ) * 3. / 4. + TIMELINE_WIDTH ) ); + do { + QDate endLeft( fromWeek.addDays( 3 ) ); + int hh = headerHeight(); + + drawTimeTable( p, fromWeek, endLeft, + mStartTime, mEndTime, weekBox ); + mPrinter->newPage(); + drawSplitHeaderRight( p, fromWeek, curWeek, QDate(), width, hh ); + drawTimeTable( p, endLeft.addDays( 1 ), curWeek, + mStartTime, mEndTime, weekBox1 ); + + fromWeek = fromWeek.addDays( 7 ); + curWeek = fromWeek.addDays( 6 ); + if ( curWeek <= toWeek ) + mPrinter->newPage(); + } while ( curWeek <= toWeek ); + } + break; + } +} + + + + +/************************************************************** + * Print Month + **************************************************************/ + +CalPrintMonth::CalPrintMonth() : CalPrintPluginBase() +{ +} + +CalPrintMonth::~CalPrintMonth() +{ +} + +QWidget *CalPrintMonth::createConfigWidget( QWidget *w ) +{ + return new CalPrintMonthConfig_Base( w ); +} + +void CalPrintMonth::readSettingsWidget() +{ + CalPrintMonthConfig_Base *cfg = + dynamic_cast<CalPrintMonthConfig_Base *>( mConfigWidget ); + if ( cfg ) { + mFromDate = QDate( cfg->mFromYear->value(), cfg->mFromMonth->currentItem()+1, 1 ); + mToDate = QDate( cfg->mToYear->value(), cfg->mToMonth->currentItem()+1, 1 ); + + mWeekNumbers = cfg->mWeekNumbers->isChecked(); + mRecurDaily = cfg->mRecurDaily->isChecked(); + mRecurWeekly = cfg->mRecurWeekly->isChecked(); + mIncludeTodos = cfg->mIncludeTodos->isChecked(); +// mUseColors = cfg->mColors->isChecked(); + } +} + +void CalPrintMonth::setSettingsWidget() +{ + CalPrintMonthConfig_Base *cfg = + dynamic_cast<CalPrintMonthConfig_Base *>( mConfigWidget ); + setDateRange( mFromDate, mToDate ); + if ( cfg ) { + cfg->mWeekNumbers->setChecked( mWeekNumbers ); + cfg->mRecurDaily->setChecked( mRecurDaily ); + cfg->mRecurWeekly->setChecked( mRecurWeekly ); + cfg->mIncludeTodos->setChecked( mIncludeTodos ); +// cfg->mColors->setChecked( mUseColors ); + } +} + +void CalPrintMonth::loadConfig() +{ + if ( mConfig ) { + mWeekNumbers = mConfig->readBoolEntry( "Print week numbers", true ); + mRecurDaily = mConfig->readBoolEntry( "Print daily incidences", true ); + mRecurWeekly = mConfig->readBoolEntry( "Print weekly incidences", true ); + mIncludeTodos = mConfig->readBoolEntry( "Include todos", false ); + } + setSettingsWidget(); +} + +void CalPrintMonth::saveConfig() +{ + readSettingsWidget(); + if ( mConfig ) { + mConfig->writeEntry( "Print week numbers", mWeekNumbers ); + mConfig->writeEntry( "Print daily incidences", mRecurDaily ); + mConfig->writeEntry( "Print weekly incidences", mRecurWeekly ); + mConfig->writeEntry( "Include todos", mIncludeTodos ); + } +} + +void CalPrintMonth::setDateRange( const QDate &from, const QDate &to ) +{ + CalPrintPluginBase::setDateRange( from, to ); + CalPrintMonthConfig_Base *cfg = + dynamic_cast<CalPrintMonthConfig_Base *>( mConfigWidget ); + const KCalendarSystem *calSys = calendarSystem(); + if ( cfg && calSys ) { + cfg->mFromMonth->clear(); + for ( int i=0; i<calSys->monthsInYear( mFromDate ); ++i ) { + cfg->mFromMonth->insertItem( calSys->monthName( i+1, mFromDate.year() ) ); + } + cfg->mToMonth->clear(); + for ( int i=0; i<calSys->monthsInYear( mToDate ); ++i ) { + cfg->mToMonth->insertItem( calSys->monthName( i+1, mToDate.year() ) ); + } + } + if ( cfg ) { + cfg->mFromMonth->setCurrentItem( from.month()-1 ); + cfg->mFromYear->setValue( to.year() ); + cfg->mToMonth->setCurrentItem( mToDate.month()-1 ); + cfg->mToYear->setValue( mToDate.year() ); + } +} + +void CalPrintMonth::print( QPainter &p, int width, int height ) +{ + QDate curMonth, fromMonth, toMonth; + + fromMonth = mFromDate.addDays( -( mFromDate.day() - 1 ) ); + toMonth = mToDate.addDays( mToDate.daysInMonth() - mToDate.day() ); + + curMonth = fromMonth; + const KCalendarSystem *calSys = calendarSystem(); + if ( !calSys ) return; + + QRect headerBox( 0, 0, width, headerHeight() ); + QRect monthBox( 0, 0, width, height ); + monthBox.setTop( headerBox.bottom() + padding() ); + + do { + QString title( i18n("monthname year", "%1 %2") ); + title = title.arg( calSys->monthName( curMonth ) ) + .arg( curMonth.year() ); + QDate tmp( fromMonth ); + int weekdayCol = weekdayColumn( tmp.dayOfWeek() ); + tmp = tmp.addDays( -weekdayCol ); + + drawHeader( p, title, curMonth.addMonths( -1 ), curMonth.addMonths( 1 ), + headerBox ); + drawMonthTable( p, curMonth, mWeekNumbers, mRecurDaily, mRecurWeekly, monthBox ); + curMonth = curMonth.addDays( curMonth.daysInMonth() ); + if ( curMonth <= toMonth ) mPrinter->newPage(); + } while ( curMonth <= toMonth ); + +} + + + + +/************************************************************** + * Print Todos + **************************************************************/ + +CalPrintTodos::CalPrintTodos() : CalPrintPluginBase() +{ + mTodoSortField = TodoFieldUnset; + mTodoSortDirection = TodoDirectionUnset; +} + +CalPrintTodos::~CalPrintTodos() +{ +} + +QWidget *CalPrintTodos::createConfigWidget( QWidget *w ) +{ + return new CalPrintTodoConfig_Base( w ); +} + +void CalPrintTodos::readSettingsWidget() +{ + CalPrintTodoConfig_Base *cfg = + dynamic_cast<CalPrintTodoConfig_Base *>( mConfigWidget ); + if ( cfg ) { + mPageTitle = cfg->mTitle->text(); + + mTodoPrintType = (eTodoPrintType)( cfg->mPrintType->id( + cfg->mPrintType->selected() ) ); + + mFromDate = cfg->mFromDate->date(); + mToDate = cfg->mToDate->date(); + + mIncludeDescription = cfg->mDescription->isChecked(); + mIncludePriority = cfg->mPriority->isChecked(); + mIncludeDueDate = cfg->mDueDate->isChecked(); + mIncludePercentComplete = cfg->mPercentComplete->isChecked(); + mConnectSubTodos = cfg->mConnectSubTodos->isChecked(); + mStrikeOutCompleted = cfg->mStrikeOutCompleted->isChecked(); + + mTodoSortField = (eTodoSortField)cfg->mSortField->currentItem(); + mTodoSortDirection = (eTodoSortDirection)cfg->mSortDirection->currentItem(); + } +} + +void CalPrintTodos::setSettingsWidget() +{ +// kdDebug(5850) << "CalPrintTodos::setSettingsWidget" << endl; + + CalPrintTodoConfig_Base *cfg = + dynamic_cast<CalPrintTodoConfig_Base *>( mConfigWidget ); + if ( cfg ) { + cfg->mTitle->setText( mPageTitle ); + + cfg->mPrintType->setButton( mTodoPrintType ); + + cfg->mFromDate->setDate( mFromDate ); + cfg->mToDate->setDate( mToDate ); + + cfg->mDescription->setChecked( mIncludeDescription ); + cfg->mPriority->setChecked( mIncludePriority ); + cfg->mDueDate->setChecked( mIncludeDueDate ); + cfg->mPercentComplete->setChecked( mIncludePercentComplete ); + cfg->mConnectSubTodos->setChecked( mConnectSubTodos ); + cfg->mStrikeOutCompleted->setChecked( mStrikeOutCompleted ); + + if ( mTodoSortField != TodoFieldUnset ) { + // do not insert if already done so. + cfg->mSortField->insertItem( i18n("Summary") ); + cfg->mSortField->insertItem( i18n("Start Date") ); + cfg->mSortField->insertItem( i18n("Due Date") ); + cfg->mSortField->insertItem( i18n("Priority") ); + cfg->mSortField->insertItem( i18n("Percent Complete") ); + cfg->mSortField->setCurrentItem( (int)mTodoSortField ); + } + + if ( mTodoSortDirection != TodoDirectionUnset ) { + // do not insert if already done so. + cfg->mSortDirection->insertItem( i18n("Ascending") ); + cfg->mSortDirection->insertItem( i18n("Descending") ); + cfg->mSortDirection->setCurrentItem( (int)mTodoSortDirection ); + } + } +} + +void CalPrintTodos::loadConfig() +{ + if ( mConfig ) { + mPageTitle = mConfig->readEntry( "Page title", i18n("To-do list") ); + mTodoPrintType = (eTodoPrintType)mConfig->readNumEntry( "Print type", (int)TodosAll ); + mIncludeDescription = mConfig->readBoolEntry( "Include description", true ); + mIncludePriority = mConfig->readBoolEntry( "Include priority", true ); + mIncludeDueDate = mConfig->readBoolEntry( "Include due date", true ); + mIncludePercentComplete = mConfig->readBoolEntry( "Include percentage completed", true ); + mConnectSubTodos = mConfig->readBoolEntry( "Connect subtodos", true ); + mStrikeOutCompleted = mConfig->readBoolEntry( "Strike out completed summaries", true ); + mTodoSortField = (eTodoSortField)mConfig->readNumEntry( "Sort field", (int)TodoFieldSummary ); + mTodoSortDirection = (eTodoSortDirection)mConfig->readNumEntry( "Sort direction", (int)TodoDirectionAscending ); + } + setSettingsWidget(); +} + +void CalPrintTodos::saveConfig() +{ + readSettingsWidget(); + if ( mConfig ) { + mConfig->writeEntry( "Page title", mPageTitle ); + mConfig->writeEntry( "Print type", int( mTodoPrintType ) ); + mConfig->writeEntry( "Include description", mIncludeDescription ); + mConfig->writeEntry( "Include priority", mIncludePriority ); + mConfig->writeEntry( "Include due date", mIncludeDueDate ); + mConfig->writeEntry( "Include percentage completed", mIncludePercentComplete ); + mConfig->writeEntry( "Connect subtodos", mConnectSubTodos ); + mConfig->writeEntry( "Strike out completed summaries", mStrikeOutCompleted ); + mConfig->writeEntry( "Sort field", mTodoSortField ); + mConfig->writeEntry( "Sort direction", mTodoSortDirection ); + } +} + +void CalPrintTodos::print( QPainter &p, int width, int height ) +{ + // TODO: Find a good way to guarantee a nicely designed output + int pospriority = 10; + int possummary = 60; + int posdue = width - 65; + int poscomplete = posdue - 70; //Complete column is to right of the Due column + int lineSpacing = 15; + int fontHeight = 10; + + // Draw the First Page Header + drawHeader( p, mPageTitle, mFromDate, QDate(), + QRect( 0, 0, width, headerHeight() ) ); + + // Draw the Column Headers + int mCurrentLinePos = headerHeight() + 5; + QString outStr; + QFont oldFont( p.font() ); + + p.setFont( QFont( "sans-serif", 10, QFont::Bold ) ); + lineSpacing = p.fontMetrics().lineSpacing(); + mCurrentLinePos += lineSpacing; + if ( mIncludePriority ) { + outStr += i18n( "Priority" ); + p.drawText( pospriority, mCurrentLinePos - 2, outStr ); + } else { + possummary = 10; + pospriority = -1; + } + + outStr.truncate( 0 ); + outStr += i18n( "Summary" ); + p.drawText( possummary, mCurrentLinePos - 2, outStr ); + + if ( mIncludePercentComplete ) { + if ( !mIncludeDueDate ) //move Complete column to the right + poscomplete = posdue; //if not print the Due Date column + outStr.truncate( 0 ); + outStr += i18n( "Complete" ); + p.drawText( poscomplete, mCurrentLinePos - 2, outStr ); + } else { + poscomplete = -1; + } + + if ( mIncludeDueDate ) { + outStr.truncate( 0 ); + outStr += i18n( "Due" ); + p.drawText( posdue, mCurrentLinePos - 2, outStr ); + } else { + posdue = -1; + } + + p.setFont( QFont( "sans-serif", 10 ) ); + fontHeight = p.fontMetrics().height(); + + Todo::List todoList; + Todo::List tempList; + Todo::List::ConstIterator it; + + // Convert sort options to the corresponding enums + TodoSortField sortField = TodoSortSummary; + switch( mTodoSortField ) { + case TodoFieldSummary: + sortField = TodoSortSummary; break; + case TodoFieldStartDate: + sortField = TodoSortStartDate; break; + case TodoFieldDueDate: + sortField = TodoSortDueDate; break; + case TodoFieldPriority: + sortField = TodoSortPriority; break; + case TodoFieldPercentComplete: + sortField = TodoSortPercentComplete; break; + case TodoFieldUnset: + break; + } + + SortDirection sortDirection; + switch( mTodoSortDirection ) { + case TodoDirectionAscending: + sortDirection = SortDirectionAscending; break; + case TodoDirectionDescending: + sortDirection = SortDirectionDescending; break; + case TodoDirectionUnset: + break; + } + + // Create list of to-dos which will be printed + todoList = mCalendar->todos( sortField, sortDirection ); + switch( mTodoPrintType ) { + case TodosAll: + break; + case TodosUnfinished: + for( it = todoList.begin(); it!= todoList.end(); ++it ) { + if ( !(*it)->isCompleted() ) + tempList.append( *it ); + } + todoList = tempList; + break; + case TodosDueRange: + for( it = todoList.begin(); it!= todoList.end(); ++it ) { + if ( (*it)->hasDueDate() ) { + if ( (*it)->dtDue().date() >= mFromDate && + (*it)->dtDue().date() <= mToDate ) + tempList.append( *it ); + } else { + tempList.append( *it ); + } + } + todoList = tempList; + break; + } + + // Print to-dos + int count = 0; + for ( it=todoList.begin(); it!=todoList.end(); ++it ) { + Todo *currEvent = *it; + + // Skip sub-to-dos. They will be printed recursively in drawTodo() + if ( !currEvent->relatedTo() ) { + count++; + drawTodo( count, currEvent, p, + sortField, sortDirection, + mConnectSubTodos, + mStrikeOutCompleted, mIncludeDescription, + pospriority, possummary, posdue, poscomplete, + 0, 0, mCurrentLinePos, width, height, todoList ); + } + } + p.setFont( oldFont ); +} + + +#endif diff --git a/korganizer/printing/calprintdefaultplugins.h b/korganizer/printing/calprintdefaultplugins.h new file mode 100644 index 000000000..463312ff2 --- /dev/null +++ b/korganizer/printing/calprintdefaultplugins.h @@ -0,0 +1,209 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1998 Preston Brown <pbrown@kde.org> + Copyright (c) 2003 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef CALPRINTDEFAULTPLUGINS_H +#define CALPRINTDEFAULTPLUGINS_H + + +#include <klocale.h> +#include "calprintpluginbase.h" + +#ifndef KORG_NOPRINTER +namespace KCal { +class Calendar; +} + +using namespace KCal; +using namespace KOrg; + +class CalPrintIncidence : public CalPrintPluginBase +{ + public: + CalPrintIncidence(); + virtual ~CalPrintIncidence(); + virtual QString description() { return i18n("Print &incidence"); } + virtual QString 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 ) { + return true; + } else { + return false; + } + } + virtual QWidget *createConfigWidget(QWidget*); + virtual KPrinter::Orientation defaultOrientation() + { return KPrinter::Portrait; } + + public: + void print( QPainter &p, int width, int height ); + virtual void readSettingsWidget(); + virtual void setSettingsWidget(); + virtual void loadConfig(); + virtual void saveConfig(); + protected: + int printCaptionAndText( QPainter &p, const QRect &box, const QString &caption, + const QString &text, QFont captionFont, QFont textFont ); + + + protected: + bool mShowOptions; + bool mShowSubitemsNotes; + bool mShowAttendees; + bool mShowAttachments; +}; + + +class CalPrintDay : public CalPrintPluginBase +{ + public: + CalPrintDay(); + virtual ~CalPrintDay(); + virtual QString description() { return i18n("Print da&y"); } + virtual QString 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 QWidget *createConfigWidget( QWidget* ); + + public: + void print(QPainter &p, int width, int height); + virtual void readSettingsWidget(); + virtual void setSettingsWidget(); + virtual void loadConfig(); + virtual void saveConfig(); + virtual void setDateRange( const QDate& from, const QDate& to ); + + protected: + QTime mStartTime, mEndTime; + bool mIncludeTodos; + bool mIncludeAllEvents; +}; + +class CalPrintWeek : public CalPrintPluginBase +{ + public: + CalPrintWeek(); + virtual ~CalPrintWeek(); + virtual QString description() { return i18n("Print &week"); } + virtual QString info() { return i18n("Prints all events of one week on one page"); } + virtual int sortID() { return CalPrinterBase::Week; } + virtual bool enabled() { return true; } + virtual QWidget *createConfigWidget(QWidget*); + /** + Returns the default orientation for the eWeekPrintType. + */ + virtual KPrinter::Orientation defaultOrientation(); + + public: + void print(QPainter &p, int width, int height); + virtual void readSettingsWidget(); + virtual void setSettingsWidget(); + virtual void loadConfig(); + virtual void saveConfig(); + virtual void setDateRange( const QDate& from, const QDate& to ); + + protected: + enum eWeekPrintType { Filofax=0, Timetable, SplitWeek } mWeekPrintType; + QTime mStartTime, mEndTime; + bool mIncludeTodos; +}; + +class CalPrintMonth : public CalPrintPluginBase +{ + public: + CalPrintMonth(); + virtual ~CalPrintMonth(); + virtual QString description() { return i18n("Print mont&h"); } + virtual QString info() { return i18n("Prints all events of one month on one page"); } + virtual int sortID() { return CalPrinterBase::Month; } + virtual bool enabled() { return true; } + virtual QWidget *createConfigWidget(QWidget*); + virtual KPrinter::Orientation defaultOrientation() { return KPrinter::Landscape; } + + public: + void print(QPainter &p, int width, int height); + virtual void readSettingsWidget(); + virtual void setSettingsWidget(); + virtual void loadConfig(); + virtual void saveConfig(); + virtual void setDateRange( const QDate& from, const QDate& to ); + + protected: + bool mWeekNumbers; + bool mRecurDaily; + bool mRecurWeekly; + bool mIncludeTodos; +}; + +class CalPrintTodos : public CalPrintPluginBase +{ + public: + CalPrintTodos(); + virtual ~CalPrintTodos(); + virtual QString description() { return i18n("Print to-&dos"); } + virtual QString info() { return i18n("Prints all to-dos in a (tree-like) list"); } + virtual int sortID() { return CalPrinterBase::Todolist; } + virtual bool enabled() { return true; } + virtual QWidget *createConfigWidget(QWidget*); + + public: + void print( QPainter &p, int width, int height ); + virtual void readSettingsWidget(); + virtual void setSettingsWidget(); + virtual void loadConfig(); + virtual void saveConfig(); + + protected: + QString mPageTitle; + + enum eTodoPrintType { + TodosAll = 0, TodosUnfinished, TodosDueRange + } mTodoPrintType; + + enum eTodoSortField { + TodoFieldSummary=0, + TodoFieldStartDate, TodoFieldDueDate, + TodoFieldPriority, TodoFieldPercentComplete, + TodoFieldUnset + } mTodoSortField; + + enum eTodoSortDirection { + TodoDirectionAscending=0, TodoDirectionDescending, + TodoDirectionUnset + } mTodoSortDirection; + + bool mIncludeDescription; + bool mIncludePriority; + bool mIncludeDueDate; + bool mIncludePercentComplete; + bool mConnectSubTodos; + bool mStrikeOutCompleted; + bool mSortField; + bool mSortDirection; +}; + +#endif +#endif diff --git a/korganizer/printing/calprinter.cpp b/korganizer/printing/calprinter.cpp new file mode 100644 index 000000000..066c9c296 --- /dev/null +++ b/korganizer/printing/calprinter.cpp @@ -0,0 +1,278 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1998 Preston Brown <pbrown@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qvbuttongroup.h> +#include <qwidgetstack.h> +#include <qradiobutton.h> +#include <qlayout.h> +#include <qpushbutton.h> +#include <qcombobox.h> +#include <qlabel.h> +#include <qvbox.h> +#include <qsplitter.h> + +#include <kprinter.h> +#include <ksimpleconfig.h> +#include <kdebug.h> +#include <kdeversion.h> + +#include "korganizer/corehelper.h" + +#include "calprinter.h" +#ifndef KORG_NOPRINTER +#include "calprinter.moc" + +#include "calprintdefaultplugins.h" + +CalPrinter::CalPrinter( QWidget *parent, Calendar *calendar, KOrg::CoreHelper *helper ) + : QObject( parent, "CalPrinter" ) +{ + mParent = parent; + mConfig = new KSimpleConfig( "korganizer_printing.rc" ); + mCoreHelper = helper; + + init( calendar ); +} + +CalPrinter::~CalPrinter() +{ + kdDebug(5850) << "~CalPrinter()" << endl; + + mPrintPlugins.clear(); + + delete mConfig; +} + +void CalPrinter::init( Calendar *calendar ) +{ + mCalendar = calendar; + + mPrintPlugins.clear(); + mPrintPlugins.setAutoDelete( true ); + + mPrintPlugins = mCoreHelper->loadPrintPlugins(); + mPrintPlugins.prepend( new CalPrintTodos() ); + mPrintPlugins.prepend( new CalPrintMonth() ); + mPrintPlugins.prepend( new CalPrintWeek() ); + mPrintPlugins.prepend( new CalPrintDay() ); + mPrintPlugins.prepend( new CalPrintIncidence() ); + + KOrg::PrintPlugin::List::Iterator it = mPrintPlugins.begin(); + for ( ; it != mPrintPlugins.end(); ++it ) { + if ( *it ) { + (*it)->setConfig( mConfig ); + (*it)->setCalendar( mCalendar ); + (*it)->setKOrgCoreHelper( mCoreHelper ); + (*it)->doLoadConfig(); + } + } +} + +void CalPrinter::setDateRange( const QDate &fd, const QDate &td ) +{ + KOrg::PrintPlugin::List::Iterator it = mPrintPlugins.begin(); + for ( ; it != mPrintPlugins.end(); ++it ) { + (*it)->setDateRange( fd, td ); + } +} + +void CalPrinter::print( int type, const QDate &fd, const QDate &td, + Incidence::List selectedIncidences, bool preview ) +{ + KOrg::PrintPlugin::List::Iterator it = mPrintPlugins.begin(); + for ( it = mPrintPlugins.begin(); it != mPrintPlugins.end(); ++it ) { + (*it)->setSelectedIncidences( selectedIncidences ); + } + CalPrintDialog printDialog( mPrintPlugins, mParent ); + printDialog.setOrientation( CalPrinter::ePrintOrientation( mConfig->readNumEntry("Orientation", 1 ) ) ); + printDialog.setPreview( preview ); + printDialog.setPrintType( type ); + setDateRange( fd, td ); + + if ( printDialog.exec() == QDialog::Accepted ) { + mConfig->writeEntry( "Orientation", printDialog.orientation() ); + + // Save all changes in the dialog + for ( it = mPrintPlugins.begin(); it != mPrintPlugins.end(); ++it ) { + (*it)->doSaveConfig(); + } + doPrint( printDialog.selectedPlugin(), printDialog.orientation(), preview ); + } + for ( it = mPrintPlugins.begin(); it != mPrintPlugins.end(); ++it ) { + (*it)->setSelectedIncidences( Incidence::List() ); + } +} + +void CalPrinter::doPrint( KOrg::PrintPlugin *selectedStyle, + CalPrinter::ePrintOrientation dlgorientation, bool preview ) +{ + if ( !selectedStyle ) { + KMessageBox::error( mParent, + i18n("Unable to print, no valid print style was returned."), + i18n("Printing error") ); + return; + } + KPrinter printer; + + printer.setPreviewOnly( preview ); + switch ( dlgorientation ) { + case eOrientPlugin: + printer.setOrientation( selectedStyle->defaultOrientation() ); + break; + case eOrientPortrait: + printer.setOrientation( KPrinter::Portrait ); + break; + case eOrientLandscape: + printer.setOrientation( KPrinter::Landscape ); + break; + case eOrientPrinter: + default: + break; + } + + if ( preview || printer.setup( mParent, i18n("Print Calendar") ) ) { + selectedStyle->doPrint( &printer ); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void CalPrinter::updateConfig() +{ +} + + + +/****************************************************************************/ + +CalPrintDialog::CalPrintDialog( KOrg::PrintPlugin::List plugins, + QWidget *parent, const char *name ) + : KDialogBase( parent, name, /*modal*/true, i18n("Print"), Ok | Cancel ) +{ + QVBox *page = makeVBoxMainWidget(); + + QSplitter *splitter = new QSplitter( page ); + splitter->setOrientation( QSplitter::Horizontal ); + + mTypeGroup = new QVButtonGroup( i18n("Print Style"), splitter, "buttonGroup" ); + // use the minimal width possible = max width of the radio buttons, not extensible +/* mTypeGroup->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)4, + (QSizePolicy::SizeType)5, 0, 0, + mTypeGroup->sizePolicy().hasHeightForWidth() ) );*/ + + QWidget *splitterRight = new QWidget( splitter, "splitterRight" ); + QGridLayout *splitterRightLayout = new QGridLayout( splitterRight ); + splitterRightLayout->setMargin( marginHint() ); + splitterRightLayout->setSpacing( spacingHint() ); + + mConfigArea = new QWidgetStack( splitterRight, "configWidgetStack" ); + splitterRightLayout->addMultiCellWidget( mConfigArea, 0,0, 0,1 ); + + QLabel *orientationLabel = new QLabel( i18n("Page &orientation:"), + splitterRight, "orientationLabel" ); + splitterRightLayout->addWidget( orientationLabel, 1, 0 ); + + mOrientationSelection = new QComboBox( splitterRight, "orientationCombo" ); + mOrientationSelection->insertItem( i18n("Use Default Orientation of Selected Style") ); + mOrientationSelection->insertItem( i18n("Use Printer Default") ); + mOrientationSelection->insertItem( i18n("Portrait") ); + mOrientationSelection->insertItem( i18n("Landscape") ); + splitterRightLayout->addWidget( mOrientationSelection, 1, 1 ); + + // signals and slots connections + connect( mTypeGroup, SIGNAL( clicked( int ) ), SLOT( setPrintType( int ) ) ); + orientationLabel->setBuddy( mOrientationSelection ); + + // First insert the config widgets into the widget stack. This possibly assigns + // proper ids (when two plugins have the same sortID), so store them in a map + // and use these new IDs to later sort the plugins for the type selection. + for ( KOrg::PrintPlugin::List::Iterator it = plugins.begin(); + it != plugins.end(); ++it ) { + int newid = mConfigArea->addWidget( (*it)->configWidget( mConfigArea ), (*it)->sortID() ); + mPluginIDs[newid] = (*it); + } + // Insert all plugins with in sorted order; plugins with clashing IDs will be first... + QMap<int, KOrg::PrintPlugin*>::ConstIterator mapit; + for ( mapit = mPluginIDs.begin(); mapit != mPluginIDs.end(); ++mapit ) { + KOrg::PrintPlugin *p = mapit.data(); + QRadioButton *radioButton = new QRadioButton( p->description(), mTypeGroup ); + radioButton->setEnabled( p->enabled() ); + mTypeGroup->insert( radioButton, mapit.key() ); +// radioButton->setMinimumHeight( radioButton->sizeHint().height() - 5 ); + } + + setMinimumSize( minimumSizeHint() ); + resize( minimumSizeHint() ); +} + +CalPrintDialog::~CalPrintDialog() +{ +} + +void CalPrintDialog::setPreview(bool preview) +{ +#if KDE_IS_VERSION( 3, 1, 93 ) + setButtonOK( preview ? i18n("&Preview") : KStdGuiItem::print() ); +#else + setButtonOKText( preview ? i18n("&Preview") : i18n("&Print...") ); +#endif +} + +void CalPrintDialog::setPrintType( int i ) +{ + mTypeGroup->setButton( i ); + mConfigArea->raiseWidget( i ); +} + +void CalPrintDialog::setOrientation( CalPrinter::ePrintOrientation orientation ) +{ + mOrientation = orientation; + mOrientationSelection->setCurrentItem( mOrientation ); +} + +KOrg::PrintPlugin *CalPrintDialog::selectedPlugin() +{ + int id = mTypeGroup->selectedId(); + if ( mPluginIDs.contains( id ) ) { + return mPluginIDs[id]; + } else { + return 0; + } +} + +void CalPrintDialog::slotOk() +{ + mOrientation = (CalPrinter::ePrintOrientation)mOrientationSelection->currentItem(); + + QMap<int, KOrg::PrintPlugin*>::Iterator it = mPluginIDs.begin(); + for ( ; it != mPluginIDs.end(); ++it ) { + if ( it.data() ) + it.data()->readSettingsWidget(); + } + + KDialogBase::slotOk(); +} + +#endif diff --git a/korganizer/printing/calprinter.h b/korganizer/printing/calprinter.h new file mode 100644 index 000000000..e05073e58 --- /dev/null +++ b/korganizer/printing/calprinter.h @@ -0,0 +1,136 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1998 Preston Brown <pbrown@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef _CALPRINTER_H +#define _CALPRINTER_H + +#ifndef KORG_NOPRINTER + +#include <qptrlist.h> +#include <kdialogbase.h> +#include <korganizer/baseview.h> +#include <korganizer/printplugin.h> +#include <kdepimmacros.h> + +namespace KOrg { +class CoreHelper; +} +using namespace KCal; + +class QVButtonGroup; +class QWidgetStack; +class CalPrintDialog; +class KConfig; +class QComboBox; +class QLabel; + +/** + CalPrinter is a class for printing Calendars. It can print in several + different formats (day, week, month). It also provides a way for setting + up the printer and remembering these preferences. +*/ +class KDE_EXPORT CalPrinter : public QObject, public KOrg::CalPrinterBase +{ + Q_OBJECT + + public: + enum ePrintOrientation { + eOrientPlugin=0, + eOrientPrinter, + eOrientPortrait, + eOrientLandscape + }; + public: + /** + \param par parent widget for dialogs + \param cal calendar to be printed + \param helper is a pointer to the KOrg::CoreHelper object + */ + CalPrinter( QWidget *par, Calendar *cal, KOrg::CoreHelper *helper ); + virtual ~CalPrinter(); + + void init( Calendar *calendar ); + + /** + Set date range to be printed. + + \param start Start date + \param end End date + */ + void setDateRange( const QDate &start, const QDate &end ); + + public slots: + void updateConfig(); + + private slots: + void doPrint( KOrg::PrintPlugin *selectedStyle, CalPrinter::ePrintOrientation dlgorientation, bool preview = false ); + + public: + void print( int type, const QDate &fd, const QDate &td, + Incidence::List selectedIncidences = Incidence::List(), bool preview = false ); + + Calendar *calendar() const; + KConfig *config() const; + + protected: + KOrg::PrintPlugin::List mPrintPlugins; + + private: + Calendar *mCalendar; + QWidget *mParent; + KConfig *mConfig; + KOrg::CoreHelper *mCoreHelper; +}; + +class CalPrintDialog : public KDialogBase +{ + Q_OBJECT + public: + CalPrintDialog( KOrg::PrintPlugin::List plugins, + QWidget *parent = 0, const char *name = 0 ); + virtual ~CalPrintDialog(); + KOrg::PrintPlugin *selectedPlugin(); + void setOrientation( CalPrinter::ePrintOrientation orientation ); + CalPrinter::ePrintOrientation orientation() { return mOrientation; } + + public slots: + void setPrintType( int ); + void setPreview( bool ); + + protected slots: + void slotOk(); + + private: + QVButtonGroup *mTypeGroup; + QWidgetStack *mConfigArea; + QMap<int, KOrg::PrintPlugin*> mPluginIDs; + QString mPreviewText; + QComboBox *mOrientationSelection; + + CalPrinter::ePrintOrientation mOrientation; +}; + +#endif + +#endif diff --git a/korganizer/printing/calprintincidenceconfig_base.ui b/korganizer/printing/calprintincidenceconfig_base.ui new file mode 100644 index 000000000..5a85fb714 --- /dev/null +++ b/korganizer/printing/calprintincidenceconfig_base.ui @@ -0,0 +1,103 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>CalPrintIncidenceConfig_Base</class> +<comment>Configuration page for printing incidences.</comment> +<author>Reinhold Kainhofer <reinhold@kainhofer.com></author> +<widget class="QWidget"> + <property name="name"> + <cstring>CalPrintIncidence_Base</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>277</width> + <height>206</height> + </rect> + </property> + <property name="caption"> + <string>CalPrintIncidence_Base</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>mComponentsGroup</cstring> + </property> + <property name="title"> + <string>Include Information</string> + </property> + <property name="selectedId" stdset="0"> + <number>-1</number> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>mShowDetails</cstring> + </property> + <property name="text"> + <string>Detai&ls (visiblility, secrecy, etc.)</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>mShowSubitemsNotes</cstring> + </property> + <property name="text"> + <string>&Notes, Subitems</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>mShowAttendees</cstring> + </property> + <property name="text"> + <string>&Attendees</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>mShowAttachments</cstring> + </property> + <property name="text"> + <string>Attach&ments</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>mColors</cstring> + </property> + <property name="text"> + <string>&Use colors</string> + </property> + <property name="whatsThis" stdset="0"> + <string>If you want to use colors to distinguish certain categories on the print, check this option.</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>201</height> + </size> + </property> + </spacer> + </vbox> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/korganizer/printing/calprintmonthconfig_base.ui b/korganizer/printing/calprintmonthconfig_base.ui new file mode 100644 index 000000000..001729582 --- /dev/null +++ b/korganizer/printing/calprintmonthconfig_base.ui @@ -0,0 +1,210 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>CalPrintMonthConfig_Base</class> +<comment>Configuration page for the print day mode.</comment> +<author>Reinhold Kainhofer <reinhold@kainhofer.com></author> +<widget class="QWidget"> + <property name="name"> + <cstring>CalPrintMonth_Base</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>463</width> + <height>161</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <spacer row="5" column="0"> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QGroupBox" row="0" column="0"> + <property name="name"> + <cstring>mDateRangeGroup</cstring> + </property> + <property name="title"> + <string>Date && Time Range</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>mFromDateLabel</cstring> + </property> + <property name="text"> + <string>&Start month:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mFromMonth</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>When you want to print more months at once, you can define a month range. This option defines the first month to be printed. Use the option <i>End month</i> to define the last month in this range.</string> + </property> + </widget> + <widget class="KComboBox"> + <property name="name"> + <cstring>mFromMonth</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>When you want to print more months at once, you can define a month range. This option defines the first month to be printed. Use the on <i>End month</i> to define the last month in this range.</string> + </property> + </widget> + <widget class="KIntSpinBox"> + <property name="name"> + <cstring>mFromYear</cstring> + </property> + <property name="maxValue"> + <number>3000</number> + </property> + <property name="value"> + <number>2007</number> + </property> + <property name="whatsThis" stdset="0"> + <string>When you want to print more months at once, you can define a month range. This option defines the first month to be printed. Use the on <i>End month</i> to define the last month in this range.</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>mToDateLabel</cstring> + </property> + <property name="text"> + <string>&End month:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mToMonth</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>When you want to print more months at once, you can define a month range. This option defines the last month to be printed. Use the option <i>Start month</i> to define the first month in this range.</string> + </property> + </widget> + <widget class="KComboBox"> + <property name="name"> + <cstring>mToMonth</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>When you want to print more months at once, you can define a month range. This option defines the last month to be printed. Use the option <i>Start month</i> to define the first month in this range.</string> + </property> + </widget> + <widget class="KIntSpinBox"> + <property name="name"> + <cstring>mToYear</cstring> + </property> + <property name="maxValue"> + <number>3000</number> + </property> + <property name="value"> + <number>2007</number> + </property> + <property name="whatsThis" stdset="0"> + <string>When you want to print more months at once, you can define a month range. This option defines the last month to be printed. Use the option <i>Start month</i> to define the first month in this range.</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>17</width> + <height>21</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <widget class="QCheckBox" row="4" column="0"> + <property name="name"> + <cstring>mIncludeTodos</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Include to-&dos that are due on the printed day(s)</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Check this option if you want to have to-dos on the print, placed by their due date.</string> + </property> + </widget> + <widget class="QCheckBox" row="1" column="0"> + <property name="name"> + <cstring>mWeekNumbers</cstring> + </property> + <property name="text"> + <string>Print week &numbers</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Enable this to print week numbers at the left of each row.</string> + </property> + </widget> + <widget class="QCheckBox" row="2" column="0"> + <property name="name"> + <cstring>mRecurDaily</cstring> + </property> + <property name="text"> + <string>Print daily re&curring to-dos and events</string> + </property> + <property name="whatsThis" stdset="0"> + <string>With this option it is possible to leave out the daily recurring to-dos and events in the print. They take a lot of space and make the month view needlessly complicated.</string> + </property> + </widget> + <widget class="QCheckBox" row="3" column="0"> + <property name="name"> + <cstring>mRecurWeekly</cstring> + </property> + <property name="text"> + <string>Print weekl&y recurring to-dos and events</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Similar to "Print daily recurring to-dos and events". Weekly to-dos and events will be omitted when making a print of the selected month.</string> + </property> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<tabstops> + <tabstop>mWeekNumbers</tabstop> + <tabstop>mRecurDaily</tabstop> + <tabstop>mRecurWeekly</tabstop> + <tabstop>mIncludeTodos</tabstop> +</tabstops> +<includes> + <include location="global" impldecl="in declaration">kdateedit.h</include> +</includes> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kcombobox.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>knuminput.h</includehint> +</includehints> +</UI> diff --git a/korganizer/printing/calprintpluginbase.cpp b/korganizer/printing/calprintpluginbase.cpp new file mode 100644 index 000000000..44739db48 --- /dev/null +++ b/korganizer/printing/calprintpluginbase.cpp @@ -0,0 +1,1674 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1998 Preston Brown <pbrown@kde.org> + Copyright (c) 2003 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qpainter.h> +#include <qlayout.h> +#include <qframe.h> +#include <qlabel.h> + +#include <kdebug.h> +#include <kconfig.h> +#include <kcalendarsystem.h> +#include <kwordwrap.h> + +#include "calprintpluginbase.h" +#include "cellitem.h" + +#ifndef KORG_NOPRINTER + +inline int round(const double x) + { + return int(x > 0.0 ? x + 0.5 : x - 0.5); + } +/****************************************************************** + ** The Todo positioning structure ** + ******************************************************************/ +class CalPrintPluginBase::TodoParentStart +{ + public: + TodoParentStart( QRect pt = QRect(), bool page = true ) + : mRect( pt ), mSamePage( page ) {} + + QRect mRect; + bool mSamePage; +}; + + +/****************************************************************** + ** The Print item ** + ******************************************************************/ + + +class PrintCellItem : public KOrg::CellItem +{ + public: + PrintCellItem( Event *event, const QDateTime &start, const QDateTime &end ) + : mEvent( event ), mStart( start), mEnd( end ) + { + } + + Event *event() const { return mEvent; } + + QString label() const { return mEvent->summary(); } + + QDateTime start() const { return mStart; } + QDateTime end() const { return mEnd; } + + /** Calculate the start and end date/time of the recurrence that + happens on the given day */ + bool overlaps( KOrg::CellItem *o ) const + { + PrintCellItem *other = static_cast<PrintCellItem *>( o ); + +#if 0 + kdDebug(5850) << "PrintCellItem::overlaps() " << event()->summary() + << " <-> " << other->event()->summary() << endl; + kdDebug(5850) << " start : " << start.toString() << endl; + kdDebug(5850) << " end : " << end.toString() << endl; + kdDebug(5850) << " otherStart: " << otherStart.toString() << endl; + kdDebug(5850) << " otherEnd : " << otherEnd.toString() << endl; +#endif + + return !( other->start() >= end() || other->end() <= start() ); + } + + private: + Event *mEvent; + QDateTime mStart, mEnd; +}; + + + + +/****************************************************************** + ** The Print plugin ** + ******************************************************************/ + + +CalPrintPluginBase::CalPrintPluginBase() : PrintPlugin(), mUseColors( true ), + mHeaderHeight(-1), mSubHeaderHeight( SUBHEADER_HEIGHT ), + mMargin( MARGIN_SIZE ), mPadding( PADDING_SIZE), mCalSys( 0 ) +{ +} +CalPrintPluginBase::~CalPrintPluginBase() +{ +} + + + +QWidget *CalPrintPluginBase::createConfigWidget( QWidget *w ) +{ + QFrame *wdg = new QFrame( w ); + QVBoxLayout *layout = new QVBoxLayout( wdg ); + + QLabel *title = new QLabel( description(), wdg ); + QFont titleFont( title->font() ); + titleFont.setPointSize( 20 ); + titleFont.setBold( true ); + title->setFont( titleFont ); + + layout->addWidget( title ); + layout->addWidget( new QLabel( info(), wdg ) ); + layout->addSpacing( 20 ); + layout->addWidget( new QLabel( i18n("This printing style does not " + "have any configuration options."), + wdg ) ); + layout->addStretch(); + return wdg; +} + +void CalPrintPluginBase::doPrint( KPrinter *printer ) +{ + if ( !printer ) return; + mPrinter = printer; + QPainter p; + + mPrinter->setColorMode( mUseColors?(KPrinter::Color):(KPrinter::GrayScale) ); + + p.begin( mPrinter ); + // TODO: Fix the margins!!! + // the painter initially begins at 72 dpi per the Qt docs. + // we want half-inch margins. + int margins = margin(); + p.setViewport( margins, margins, + p.viewport().width() - 2*margins, + p.viewport().height() - 2*margins ); +// QRect vp( p.viewport() ); +// vp.setRight( vp.right()*2 ); +// vp.setBottom( vp.bottom()*2 ); +// p.setWindow( vp ); + int pageWidth = p.window().width(); + int pageHeight = p.window().height(); +// int pageWidth = p.viewport().width(); +// int pageHeight = p.viewport().height(); + + print( p, pageWidth, pageHeight ); + + p.end(); + mPrinter = 0; +} + +void CalPrintPluginBase::doLoadConfig() +{ + if ( mConfig ) { + KConfigGroupSaver saver( mConfig, description() ); + mConfig->sync(); + QDateTime currDate( QDate::currentDate() ); + mFromDate = mConfig->readDateTimeEntry( "FromDate", &currDate ).date(); + mToDate = mConfig->readDateTimeEntry( "ToDate" ).date(); + mUseColors = mConfig->readBoolEntry( "UseColors", true ); + setUseColors( mUseColors ); + loadConfig(); + } else { + kdDebug(5850) << "No config available in loadConfig!!!!" << endl; + } +} + +void CalPrintPluginBase::doSaveConfig() +{ + if ( mConfig ) { + KConfigGroupSaver saver( mConfig, description() ); + saveConfig(); + mConfig->writeEntry( "FromDate", QDateTime( mFromDate ) ); + mConfig->writeEntry( "ToDate", QDateTime( mToDate ) ); + mConfig->writeEntry( "UseColors", mUseColors ); + mConfig->sync(); + } else { + kdDebug(5850) << "No config available in saveConfig!!!!" << endl; + } +} + + + + +void CalPrintPluginBase::setKOrgCoreHelper( KOrg::CoreHelper*helper ) +{ + PrintPlugin::setKOrgCoreHelper( helper ); + if ( helper ) + setCalendarSystem( helper->calendarSystem() ); +} + +bool CalPrintPluginBase::useColors() const +{ + return mUseColors; +} +void CalPrintPluginBase::setUseColors( bool useColors ) +{ + mUseColors = useColors; +} + +KPrinter::Orientation CalPrintPluginBase::orientation() const +{ + return (mPrinter)?(mPrinter->orientation()):(KPrinter::Portrait); +} + + + +QTime CalPrintPluginBase::dayStart() +{ + QTime start( 8,0,0 ); + if ( mCoreHelper ) start = mCoreHelper->dayStart(); + return start; +} + +void CalPrintPluginBase::setCategoryColors( QPainter &p, Incidence *incidence ) +{ + QColor bgColor = categoryBgColor( incidence ); + if ( bgColor.isValid() ) + p.setBrush( bgColor ); + QColor tColor( textColor( bgColor ) ); + if ( tColor.isValid() ) + p.setPen( tColor ); +} + +QColor CalPrintPluginBase::categoryBgColor( Incidence *incidence ) +{ + if (mCoreHelper && incidence) + return mCoreHelper->categoryColor( incidence->categories() ); + else + return QColor(); +} + +QColor CalPrintPluginBase::textColor( const QColor &color ) +{ + return (mCoreHelper)?(mCoreHelper->textColor( color )):QColor(); +} + +bool CalPrintPluginBase::isWorkingDay( const QDate &dt ) +{ + return (mCoreHelper)?( mCoreHelper->isWorkingDay( dt ) ):true; +} + +QString CalPrintPluginBase::holidayString( const QDate &dt ) +{ + return (mCoreHelper)?(mCoreHelper->holidayString(dt)):(QString::null); +} + + +Event *CalPrintPluginBase::holiday( const QDate &dt ) +{ + QString hstring( holidayString( dt ) ); + if ( !hstring.isEmpty() ) { + Event*holiday=new Event(); + holiday->setSummary( hstring ); + holiday->setDtStart( dt ); + holiday->setDtEnd( dt ); + holiday->setFloats( true ); + holiday->setCategories( i18n("Holiday") ); + return holiday; + } + return 0; +} + +const KCalendarSystem *CalPrintPluginBase::calendarSystem() const +{ + return mCalSys; +} +void CalPrintPluginBase::setCalendarSystem( const KCalendarSystem *calsys ) +{ + mCalSys = calsys; +} + +int CalPrintPluginBase::headerHeight() const +{ + if ( mHeaderHeight >= 0 ) + return mHeaderHeight; + else if ( orientation() == KPrinter::Portrait ) + return PORTRAIT_HEADER_HEIGHT; + else + return LANDSCAPE_HEADER_HEIGHT; +} +void CalPrintPluginBase::setHeaderHeight( const int height ) +{ + mHeaderHeight = height; +} + +int CalPrintPluginBase::subHeaderHeight() const +{ + return mSubHeaderHeight; +} +void CalPrintPluginBase::setSubHeaderHeight( const int height ) +{ + mSubHeaderHeight = height; +} + +int CalPrintPluginBase::margin() const +{ + return mMargin; +} +void CalPrintPluginBase::setMargin( const int margin ) +{ + mMargin = margin; +} + +int CalPrintPluginBase::padding() const +{ + return mPadding; +} +void CalPrintPluginBase::setPadding( const int padding ) +{ + mPadding = padding; +} + +int CalPrintPluginBase::borderWidth() const +{ + return mBorder; +} +void CalPrintPluginBase::setBorderWidth( const int borderwidth ) +{ + mBorder = borderwidth; +} + + + + +void CalPrintPluginBase::drawBox( QPainter &p, int linewidth, const QRect &rect ) +{ + QPen pen( p.pen() ); + QPen oldpen( pen ); + pen.setWidth( linewidth ); + p.setPen( pen ); + p.drawRect( rect ); + p.setPen( oldpen ); +} + +void CalPrintPluginBase::drawShadedBox( QPainter &p, int linewidth, const QBrush &brush, const QRect &rect ) +{ + QBrush oldbrush( p.brush() ); + p.setBrush( brush ); + drawBox( p, linewidth, rect ); + p.setBrush( oldbrush ); +} + +void CalPrintPluginBase::printEventString( QPainter &p, const QRect &box, const QString &str, int flags ) +{ + QRect newbox( box ); + newbox.addCoords( 3, 1, -1, -1 ); + p.drawText( newbox, (flags==-1)?(Qt::AlignTop | Qt::AlignJustify | Qt::BreakAnywhere):flags, str ); +} + + +void CalPrintPluginBase::showEventBox( QPainter &p, const QRect &box, Incidence *incidence, const QString &str, int flags ) +{ + QPen oldpen( p.pen() ); + QBrush oldbrush( p.brush() ); + QColor bgColor( categoryBgColor( incidence ) ); + if ( mUseColors & bgColor.isValid() ) { + p.setBrush( bgColor ); + } else { + p.setBrush( QColor( 232, 232, 232 ) ); + } + drawBox( p, EVENT_BORDER_WIDTH, box ); + + if ( mUseColors && bgColor.isValid() ) { + p.setPen( textColor( bgColor ) ); + } + printEventString( p, box, str, flags ); + p.setPen( oldpen ); + p.setBrush( oldbrush ); +} + + +void CalPrintPluginBase::drawSubHeaderBox(QPainter &p, const QString &str, + const QRect &box ) +{ + drawShadedBox( p, BOX_BORDER_WIDTH, QColor( 232, 232, 232 ), box ); + QFont oldfont( p.font() ); + p.setFont( QFont( "sans-serif", 10, QFont::Bold ) ); + p.drawText( box, Qt::AlignCenter | Qt::AlignVCenter, str ); + p.setFont( oldfont ); +} + +void CalPrintPluginBase::drawVerticalBox( QPainter &p, const QRect &box, const QString &str ) +{ + p.save(); + p.rotate( -90 ); + QRect rotatedBox( -box.top()-box.height(), box.left(), box.height(), box.width() ); + showEventBox( p, rotatedBox, 0, str, Qt::AlignLeft | Qt::AlignVCenter | Qt::SingleLine ); + + p.restore(); +} + + + +/////////////////////////////////////////////////////////////////////////////// +// Return value: If expand, bottom of the printed box, otherwise vertical end +// of the printed contents inside the box. + +int CalPrintPluginBase::drawBoxWithCaption( QPainter &p, const QRect &allbox, + const QString &caption, const QString &contents, bool sameLine, bool expand, const QFont &captionFont, const QFont &textFont ) +{ + QFont oldFont( p.font() ); +// QFont captionFont( "sans-serif", 11, QFont::Bold ); +// QFont textFont( "sans-serif", 11, QFont::Normal ); +// QFont captionFont( "Tahoma", 11, QFont::Bold ); +// QFont textFont( "Tahoma", 11, QFont::Normal ); + + + QRect box( allbox ); + + // Bounding rectangle for caption, single-line, clip on the right + QRect 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() ) + captionBox.setRight( box.right() ); + 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 + QRect textBox( captionBox ); + if ( !contents.isEmpty() ) { + if ( sameLine ) { + textBox.setLeft( captionBox.right() + padding() ); + } else { + textBox.setTop( captionBox.bottom() + padding() ); + } + textBox.setRight( box.right() ); + textBox.setHeight( 0 ); + p.setFont( textFont ); + textBox = p.boundingRect( textBox, Qt::WordBreak | Qt::AlignTop | Qt::AlignLeft, contents ); + p.setFont( oldFont ); + if ( textBox.bottom() + padding() > box.bottom() ) { + if ( expand ) { + box.setBottom( textBox.bottom() + padding() ); + } else { + textBox.setBottom( box.bottom() ); + } + } + } + + drawBox( p, BOX_BORDER_WIDTH, box ); + p.setFont( captionFont ); + p.drawText( captionBox, Qt::AlignLeft | Qt::AlignTop | Qt::SingleLine, caption ); + if ( !contents.isEmpty() ) { + p.setFont( textFont ); + p.drawText( textBox, Qt::WordBreak | Qt::AlignTop | Qt::AlignLeft, contents ); + } + p.setFont( oldFont ); + + if ( expand ) { + return box.bottom(); + } else { + return textBox.bottom(); + } +} + + +/////////////////////////////////////////////////////////////////////////////// + +int CalPrintPluginBase::drawHeader( QPainter &p, QString title, + const QDate &month1, const QDate &month2, const QRect &allbox, bool expand ) +{ + // print previous month for month view, print current for to-do, day and week + int smallMonthWidth = (allbox.width()/4) - 10; + if (smallMonthWidth>100) smallMonthWidth=100; + + int right = allbox.right(); + if ( month1.isValid() ) right -= (20+smallMonthWidth); + if ( month2.isValid() ) right -= (20+smallMonthWidth); + QRect box( allbox ); + QRect textRect( allbox ); + textRect.addCoords( 5, 0, 0, 0 ); + textRect.setRight( right ); + + + QFont oldFont( p.font() ); + QFont newFont("sans-serif", (textRect.height()<60)?16:18, QFont::Bold); + if ( expand ) { + p.setFont( newFont ); + QRect boundingR = p.boundingRect( textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::WordBreak, title ); + p.setFont( oldFont ); + int h = boundingR.height(); + if ( h > allbox.height() ) { + box.setHeight( h ); + textRect.setHeight( h ); + } + } + + drawShadedBox( p, BOX_BORDER_WIDTH, QColor( 232, 232, 232 ), box ); + + QRect monthbox( box.right()-10-smallMonthWidth, box.top(), smallMonthWidth, box.height() ); + if (month2.isValid()) { + drawSmallMonth( p, QDate(month2.year(), month2.month(), 1), monthbox ); + monthbox.moveBy( -20 - smallMonthWidth, 0 ); + } + if (month1.isValid()) { + drawSmallMonth( p, QDate(month1.year(), month1.month(), 1), monthbox ); + monthbox.moveBy( -20 - smallMonthWidth, 0 ); + } + + // Set the margins + p.setFont( newFont ); + p.drawText( textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::WordBreak, title ); + p.setFont( oldFont ); + + return textRect.bottom(); +} + + +void CalPrintPluginBase::drawSmallMonth(QPainter &p, const QDate &qd, + const QRect &box ) +{ + + int weekdayCol = weekdayColumn( qd.dayOfWeek() ); + int month = qd.month(); + QDate monthDate(QDate(qd.year(), qd.month(), 1)); + // correct begin of week + QDate monthDate2( monthDate.addDays( -weekdayCol ) ); + + double cellWidth = double(box.width())/double(7); + int rownr = 3 + ( qd.daysInMonth() + weekdayCol - 1 ) / 7; + // 3 Pixel after month name, 2 after day names, 1 after the calendar + double cellHeight = (box.height() - 5) / rownr; + QFont oldFont( p.font() ); + p.setFont(QFont("sans-serif", int(cellHeight-1), QFont::Normal)); + + // draw the title + if ( mCalSys ) { + QRect titleBox( box ); + titleBox.setHeight( int(cellHeight+1) ); + p.drawText( titleBox, Qt::AlignTop | Qt::AlignHCenter, mCalSys->monthName( qd ) ); + } + + // draw days of week + QRect wdayBox( box ); + wdayBox.setTop( int( box.top() + 3 + cellHeight ) ); + wdayBox.setHeight( int(2*cellHeight)-int(cellHeight) ); + + if ( mCalSys ) { + for (int col = 0; col < 7; ++col) { + QString tmpStr = mCalSys->weekDayName( monthDate2 )[0].upper(); + wdayBox.setLeft( int(box.left() + col*cellWidth) ); + wdayBox.setRight( int(box.left() + (col+1)*cellWidth) ); + p.drawText( wdayBox, Qt::AlignCenter, tmpStr ); + monthDate2 = monthDate2.addDays( 1 ); + } + } + + // draw separator line + int calStartY = wdayBox.bottom() + 2; + p.drawLine( box.left(), calStartY, box.right(), calStartY ); + monthDate = monthDate.addDays( -weekdayCol ); + + for ( int row = 0; row < (rownr-2); row++ ) { + for ( int col = 0; col < 7; col++ ) { + if ( monthDate.month() == month ) { + QRect dayRect( int( box.left() + col*cellWidth ), int( calStartY + row*cellHeight ), 0, 0 ); + dayRect.setRight( int( box.left() + (col+1)*cellWidth ) ); + dayRect.setBottom( int( calStartY + (row+1)*cellHeight ) ); + p.drawText( dayRect, Qt::AlignCenter, QString::number( monthDate.day() ) ); + } + monthDate = monthDate.addDays(1); + } + } + p.setFont( oldFont ); +} + + + + + +/////////////////////////////////////////////////////////////////////////////// + +/* + * This routine draws a header box over the main part of the calendar + * containing the days of the week. + */ +void CalPrintPluginBase::drawDaysOfWeek(QPainter &p, + const QDate &fromDate, const QDate &toDate, const QRect &box ) +{ + double cellWidth = double(box.width()) / double(fromDate.daysTo( toDate )+1); + QDate cellDate( fromDate ); + QRect dateBox( box ); + int i = 0; + + while ( cellDate <= toDate ) { + dateBox.setLeft( box.left() + int(i*cellWidth) ); + dateBox.setRight( box.left() + int((i+1)*cellWidth) ); + drawDaysOfWeekBox(p, cellDate, dateBox ); + cellDate = cellDate.addDays(1); + i++; + } +} + + +void CalPrintPluginBase::drawDaysOfWeekBox(QPainter &p, const QDate &qd, + const QRect &box ) +{ + drawSubHeaderBox( p, (mCalSys)?(mCalSys->weekDayName( qd )):(QString::null), box ); +} + + +void CalPrintPluginBase::drawTimeLine(QPainter &p, + const QTime &fromTime, const QTime &toTime, + const QRect &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(); + // TODO: Don't use half of the width, but less, for the minutes! + int xcenter = box.left()+box.width()/2; + + QTime curTime( fromTime ); + QTime endTime( toTime ); + if ( fromTime.minute() > 30 ) + curTime = QTime( fromTime.hour()+1, 0, 0 ); + else if ( fromTime.minute() > 0 ) { + curTime = QTime( fromTime.hour(), 30, 0 ); + float yy = currY + minlen*(float)fromTime.secsTo( curTime )/60.; + p.drawLine( xcenter, (int)yy, box.right(), (int)yy ); + curTime = QTime( fromTime.hour()+1, 0, 0 ); + } + 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.); + QString numStr; + if ( newY < box.bottom() ) { + QFont 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(QFont("sans-serif", 16, QFont::Bold)); + } else { + p.setFont(QFont("sans-serif", 12, QFont::Bold)); + } + p.drawText( box.left()+2, (int)currY+2, box.width()/2-2, (int)cellHeight, + Qt::AlignTop | Qt::AlignRight, numStr); + p.setFont(QFont("sans-serif", 10, QFont::Normal)); + p.drawText( xcenter, (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); + QTime time( curTime.hour(), 0 ); + numStr = KGlobal::locale()->formatTime( time ); + if ( box.width() < 60 ) { + p.setFont(QFont("sans-serif", 8, QFont::Bold)); // for weekprint + } else { + p.setFont(QFont("sans-serif", 12, QFont::Bold)); // for dayprint + } + p.drawText(box.left()+2, (int)currY+2, box.width()-4, (int)cellHeight/2-3, + Qt::AlignTop|Qt::AlignLeft, numStr); + } + 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; + } // 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 ", ". +*/ +int CalPrintPluginBase::drawAllDayBox(QPainter &p, Event::List &eventList, + const QDate &qd, bool expandable, const QRect &box ) +{ + Event::List::Iterator it, itold; + + int offset=box.top(); + + QString multiDayStr; + + Event*hd = holiday( qd ); + if ( hd ) eventList.prepend( hd ); + + it = eventList.begin(); + Event *currEvent = 0; + // First, print all floating events + while( it!=eventList.end() ) { + currEvent=*it; + itold=it; + ++it; + if ( currEvent && currEvent->doesFloat() ) { + // set the colors according to the categories + if ( expandable ) { + QRect eventBox( box ); + eventBox.setTop( offset ); + showEventBox( p, eventBox, currEvent, currEvent->summary() ); + offset += box.height(); + } else { + if ( !multiDayStr.isEmpty() ) multiDayStr += ", "; + multiDayStr += currEvent->summary(); + } + eventList.remove( itold ); + } + } + if ( hd ) delete hd; + + int ret = box.height(); + QRect eventBox( box ); + if (!expandable) { + if (!multiDayStr.isEmpty()) { + drawShadedBox( p, BOX_BORDER_WIDTH, QColor( 128, 128, 128 ), eventBox ); + printEventString( p, eventBox, multiDayStr ); + } else { + drawBox( p, BOX_BORDER_WIDTH, eventBox ); + } + } else { + ret = offset - box.top(); + eventBox.setBottom( ret ); + drawBox( p, BOX_BORDER_WIDTH, eventBox ); + } + return ret; +} + + +void CalPrintPluginBase::drawAgendaDayBox( QPainter &p, Event::List &events, + const QDate &qd, bool expandable, + QTime &fromTime, QTime &toTime, + const QRect &oldbox ) +{ + if ( !isWorkingDay( qd ) ) { + drawShadedBox( p, BOX_BORDER_WIDTH, QColor( 232, 232, 232 ), oldbox ); + } else { + drawBox( p, BOX_BORDER_WIDTH, oldbox ); + } + QRect box( oldbox ); + // Account for the border with and cut away that margin from the interior +// box.setRight( box.right()-BOX_BORDER_WIDTH ); + + Event *event; + + if ( expandable ) { + // Adapt start/end times to include complete events + Event::List::ConstIterator it; + for ( it = events.begin(); it != events.end(); ++it ) { + event = *it; + if ( event->dtStart().time() < fromTime ) + fromTime = event->dtStart().time(); + if ( event->dtEnd().time() > toTime ) + toTime = event->dtEnd().time(); + } + } + + // Show at least one hour +// if ( fromTime.secsTo( toTime ) < 3600 ) { +// fromTime = QTime( fromTime.hour(), 0, 0 ); +// toTime = fromTime.addSecs( 3600 ); +// } + + // calculate the height of a cell and of a minute + int totalsecs = fromTime.secsTo( toTime ); + float minlen = box.height() * 60. / totalsecs; + float cellHeight = 60. * minlen; + float currY = box.top(); + + // print grid: + QTime curTime( QTime( fromTime.hour(), 0, 0 ) ); + currY += fromTime.secsTo( curTime ) * minlen / 60; + + while ( curTime < toTime && curTime.isValid() ) { + if ( currY > box.top() ) + p.drawLine( box.left(), int( currY ), box.right(), int( currY ) ); + currY += cellHeight / 2; + if ( ( currY > box.top() ) && ( currY < box.bottom() ) ) { + // enough space for half-hour line + QPen oldPen( p.pen() ); + p.setPen( QColor( 192, 192, 192 ) ); + p.drawLine( box.left(), int( currY ), box.right(), int( currY ) ); + p.setPen( oldPen ); + } + if ( curTime.secsTo( toTime ) > 3600 ) + curTime = curTime.addSecs( 3600 ); + else curTime = toTime; + currY += cellHeight / 2; + } + + QDateTime startPrintDate = QDateTime( qd, fromTime ); + QDateTime endPrintDate = QDateTime( qd, toTime ); + + // Calculate horizontal positions and widths of events taking into account + // overlapping events + + QPtrList<KOrg::CellItem> cells; + cells.setAutoDelete( true ); + + Event::List::ConstIterator itEvents; + for( itEvents = events.begin(); itEvents != events.end(); ++itEvents ) { + QValueList<QDateTime> times = (*itEvents)->startDateTimesForDate( qd ); + for ( QValueList<QDateTime>::ConstIterator it = times.begin(); + it != times.end(); ++it ) { + cells.append( new PrintCellItem( *itEvents, (*it), (*itEvents)->endDateForStart( *it ) ) ); + } + } + + QPtrListIterator<KOrg::CellItem> it1( cells ); + for( it1.toFirst(); it1.current(); ++it1 ) { + KOrg::CellItem *placeItem = it1.current(); + KOrg::CellItem::placeItem( cells, placeItem ); + } + +// p.setFont( QFont( "sans-serif", 10 ) ); + + for( it1.toFirst(); it1.current(); ++it1 ) { + PrintCellItem *placeItem = static_cast<PrintCellItem *>( it1.current() ); + drawAgendaItem( placeItem, p, startPrintDate, endPrintDate, minlen, box ); + } +// p.setFont( oldFont ); +} + + + +void CalPrintPluginBase::drawAgendaItem( PrintCellItem *item, QPainter &p, + const QDateTime &startPrintDate, + const QDateTime &endPrintDate, + float minlen, const QRect &box ) +{ + Event *event = item->event(); + + // start/end of print area for event + QDateTime startTime = item->start(); + QDateTime endTime = item->end(); + if ( ( startTime < endPrintDate && endTime > startPrintDate ) || + ( endTime > startPrintDate && startTime < endPrintDate ) ) { + if ( startTime < startPrintDate ) startTime = startPrintDate; + if ( endTime > endPrintDate ) endTime = endPrintDate; + int currentWidth = box.width() / item->subCells(); + int currentX = box.left() + item->subCell() * currentWidth; + int currentYPos = int( box.top() + startPrintDate.secsTo( startTime ) * + minlen / 60. ); + int currentHeight = int( box.top() + startPrintDate.secsTo( endTime ) * minlen / 60. ) - currentYPos; + + QRect eventBox( currentX, currentYPos, currentWidth, currentHeight ); + showEventBox( p, eventBox, event, event->summary() ); + } +} + +//TODO TODO TODO +void CalPrintPluginBase::drawDayBox( QPainter &p, const QDate &qd, + const QRect &box, + bool fullDate, bool printRecurDaily, bool printRecurWeekly ) +{ + QString dayNumStr; + QString ampm; + const KLocale*local = KGlobal::locale(); + + + // This has to be localized + if ( fullDate && mCalSys ) { + + dayNumStr = i18n("weekday month date", "%1 %2 %3") + .arg( mCalSys->weekDayName( qd ) ) + .arg( mCalSys->monthName( qd ) ) + .arg( qd.day() ); +// dayNumStr = local->formatDate(qd); + } else { + dayNumStr = QString::number( qd.day() ); + } + + QRect subHeaderBox( box ); + subHeaderBox.setHeight( mSubHeaderHeight ); + drawShadedBox( p, BOX_BORDER_WIDTH, p.backgroundColor(), box ); + drawShadedBox( p, 0, QColor( 232, 232, 232 ), subHeaderBox ); + drawBox( p, BOX_BORDER_WIDTH, box ); + QString hstring( holidayString( qd ) ); + QFont oldFont( p.font() ); + + QRect headerTextBox( subHeaderBox ); + headerTextBox.setLeft( subHeaderBox.left()+5 ); + headerTextBox.setRight( subHeaderBox.right()-5 ); + if (!hstring.isEmpty()) { + p.setFont( QFont( "sans-serif", 8, QFont::Bold, true ) ); + + p.drawText( headerTextBox, Qt::AlignLeft | Qt::AlignVCenter, hstring ); + } + p.setFont(QFont("sans-serif", 10, QFont::Bold)); + p.drawText( headerTextBox, Qt::AlignRight | Qt::AlignVCenter, dayNumStr); + + Event::List eventList = mCalendar->events( qd, + EventSortStartDate, + SortDirectionAscending ); + QString text; + p.setFont( QFont( "sans-serif", 8 ) ); + + int textY=mSubHeaderHeight+3; // gives the relative y-coord of the next printed entry + Event::List::ConstIterator it; + + for( it = eventList.begin(); it != eventList.end() && textY<box.height(); ++it ) { + 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() ); + + drawIncidence( p, box, text, currEvent->summary(), textY ); + } + + 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 ) { + Todo *todo = *it2; + if ( ( !printRecurDaily && todo->recurrenceType() == Recurrence::rDaily ) || + ( !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 ); + } + } + + p.setFont( oldFont ); +} + +// TODO TODO TODO +void CalPrintPluginBase::drawIncidence( QPainter &p, const QRect &dayBox, const QString &time, const QString &summary, int &textY ) +{ + kdDebug(5850) << "summary = " << summary << endl; + + int flags = Qt::AlignLeft; + QFontMetrics fm = p.fontMetrics(); + QRect timeBound = p.boundingRect( dayBox.x() + 5, dayBox.y() + textY, + dayBox.width() - 10, fm.lineSpacing(), + flags, time ); + p.drawText( timeBound, flags, time ); + + int summaryWidth = time.isEmpty() ? 0 : timeBound.width() + 4; + QRect summaryBound = QRect( dayBox.x() + 5 + summaryWidth, dayBox.y() + textY, + dayBox.width() - summaryWidth -5, dayBox.height() ); + + KWordWrap *ww = KWordWrap::formatText( fm, summaryBound, flags, summary ); + ww->drawText( &p, dayBox.x() + 5 + summaryWidth, dayBox.y() + textY, flags ); + + textY += ww->boundingRect().height(); + + delete ww; +} + + +/////////////////////////////////////////////////////////////////////////////// + +void CalPrintPluginBase::drawWeek(QPainter &p, const QDate &qd, const QRect &box ) +{ + QDate weekDate = qd; + bool portrait = ( box.height() > box.width() ); + int cellWidth, cellHeight; + int vcells; + if (portrait) { + cellWidth = box.width()/2; + vcells=3; + } else { + cellWidth = box.width()/6; + vcells=1; + } + cellHeight = box.height()/vcells; + + // correct begin of week + int weekdayCol = weekdayColumn( qd.dayOfWeek() ); + weekDate = qd.addDays( -weekdayCol ); + + for (int i = 0; i < 7; i++, weekDate = weekDate.addDays(1)) { + // Saturday and sunday share a cell, so we have to special-case sunday + int hpos = ((i<6)?i:(i-1)) / vcells; + int vpos = ((i<6)?i:(i-1)) % vcells; + QRect dayBox( box.left()+cellWidth*hpos, box.top()+cellHeight*vpos + ((i==6)?(cellHeight/2):0), + cellWidth, (i<5)?(cellHeight):(cellHeight/2) ); + drawDayBox(p, weekDate, dayBox, true); + } // for i through all weekdays +} + + +void CalPrintPluginBase::drawTimeTable(QPainter &p, + const QDate &fromDate, const QDate &toDate, + QTime &fromTime, QTime &toTime, + const QRect &box) +{ + // timeline is 1 hour: + int alldayHeight = (int)( 3600.*box.height()/(fromTime.secsTo(toTime)+3600.) ); + int timelineWidth = TIMELINE_WIDTH; + + QRect dowBox( box ); + dowBox.setLeft( box.left() + timelineWidth ); + dowBox.setHeight( mSubHeaderHeight ); + drawDaysOfWeek( p, fromDate, toDate, dowBox ); + + QRect tlBox( box ); + tlBox.setWidth( timelineWidth ); + tlBox.setTop( dowBox.bottom() + BOX_BORDER_WIDTH + alldayHeight ); + drawTimeLine( p, fromTime, toTime, tlBox ); + + // draw each day + QDate curDate(fromDate); + int i=0; + double cellWidth = double(dowBox.width()) / double(fromDate.daysTo(toDate)+1); + while (curDate<=toDate) { + QRect allDayBox( dowBox.left()+int(i*cellWidth), dowBox.bottom() + BOX_BORDER_WIDTH, + int((i+1)*cellWidth)-int(i*cellWidth), alldayHeight ); + QRect dayBox( allDayBox ); + dayBox.setTop( tlBox.top() ); + dayBox.setBottom( box.bottom() ); + Event::List eventList = mCalendar->events(curDate, + EventSortStartDate, + SortDirectionAscending); + alldayHeight = drawAllDayBox( p, eventList, curDate, false, allDayBox ); + drawAgendaDayBox( p, eventList, curDate, false, fromTime, toTime, dayBox ); + i++; + curDate=curDate.addDays(1); + } + +} + + +/////////////////////////////////////////////////////////////////////////////// + +class MonthEventStruct +{ + public: + MonthEventStruct() : event(0) {} + MonthEventStruct( const QDateTime &s, const QDateTime &e, Event *ev) + { + event = ev; + start = s; + end = e; + if ( event->doesFloat() ) { + start = QDateTime( start.date(), QTime(0,0,0) ); + end = QDateTime( end.date().addDays(1), QTime(0,0,0) ).addSecs(-1); + } + } + bool operator<(const MonthEventStruct &mes) { return start < mes.start; } + QDateTime start; + QDateTime end; + Event *event; +}; + +void CalPrintPluginBase::drawMonth( QPainter &p, const QDate &dt, const QRect &box, int maxdays, int subDailyFlags, int holidaysFlags ) +{ + const KCalendarSystem *calsys = calendarSystem(); + QRect subheaderBox( box ); + subheaderBox.setHeight( subHeaderHeight() ); + QRect borderBox( box ); + borderBox.setTop( subheaderBox.bottom()+1 ); + drawSubHeaderBox( p, calsys->monthName(dt), subheaderBox ); + // correct for half the border width + int correction = (BOX_BORDER_WIDTH/*-1*/)/2; + QRect daysBox( borderBox ); + daysBox.addCoords( correction, correction, -correction, -correction ); + + int daysinmonth = calsys->daysInMonth( dt ); + if ( maxdays <= 0 ) maxdays = daysinmonth; + + int d; + float dayheight = float(daysBox.height()) / float( maxdays ); + + QColor holidayColor( 240, 240, 240 ); + QColor 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 ) { + QRect dayBox( box.left(), daysBox.top() + round(dayheight*daysinmonth), box.width(), 0 ); + dayBox.setBottom( daysBox.bottom() ); + p.fillRect( dayBox, Qt::DiagCrossPattern ); + } + // Backgrounded boxes for each day, plus day numbers + QBrush oldbrush( p.brush() ); + for ( d = 0; d < daysinmonth; ++d ) { + QDate day; + calsys->setYMD( day, dt.year(), dt.month(), d+1 ); + QRect 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 ); + QRect dateBox( dayBox ); + dateBox.setWidth( dayNrWidth+3 ); + p.drawText( dateBox, Qt::AlignRight | Qt::AlignVCenter | Qt::SingleLine, + QString::number(d+1) ); + } + p.setBrush( oldbrush ); + int xstartcont = box.left() + dayNrWidth + 5; + + QDate start, end; + calsys->setYMD( start, dt.year(), dt.month(), 1 ); + end = calsys->addMonths( start, 1 ); + end = calsys->addDays( end, -1 ); + + Event::List events = mCalendar->events( start, end ); + QMap<int, QStringList> textEvents; + QPtrList<KOrg::CellItem> timeboxItems; + timeboxItems.setAutoDelete( true ); + + + // 1) For multi-day events, show boxes spanning several cells, use CellItem + // print the summary vertically + // 2) For sub-day events, print the concated summaries into the remaining + // space of the box (optional, depending on the given flags) + // 3) Draw some kind of timeline showing free and busy times + + // Holidays + Event::List holidays; + holidays.setAutoDelete( true ); + for ( QDate d(start); d <= end; d = d.addDays(1) ) { + Event *e = holiday( d ); + if ( e ) { + holidays.append( e ); + if ( holidaysFlags & TimeBoxes ) { + timeboxItems.append( new PrintCellItem( e, QDateTime(d, QTime(0,0,0) ), + QDateTime( d.addDays(1), QTime(0,0,0) ) ) ); + } + if ( holidaysFlags & Text ) { + textEvents[ d.day() ] << e->summary(); + } + } + } + + QValueList<MonthEventStruct> monthentries; + + 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 + // month, so obtain the start date before the beginning of the month + QValueList<QDateTime> starttimes = e->startDateTimesForDate( start ); + QValueList<QDateTime>::ConstIterator it = starttimes.begin(); + for ( ; it != starttimes.end(); ++it ) { + 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 + // also return events that have started earlier. These start dates + // however, have already been treated! + Recurrence *recur = e->recurrence(); + QDate d1( start.addDays(1) ); + while ( d1 <= end ) { + if ( recur->recursOn(d1) ) { + TimeList times( recur->recurTimesOn( d1 ) ); + for ( TimeList::ConstIterator it = times.begin(); + it != times.end(); ++it ) { + QDateTime d1start( d1, *it ); + monthentries.append( MonthEventStruct( d1start, e->endDateForStart( d1start ), e ) ); + } + } + d1 = d1.addDays(1); + } + } else { + monthentries.append( MonthEventStruct( e->dtStart(), e->dtEnd(), e ) ); + } + } + qHeapSort( monthentries ); + + QValueList<MonthEventStruct>::ConstIterator mit = monthentries.begin(); + QDateTime endofmonth( end, QTime(0,0,0) ); + endofmonth = endofmonth.addDays(1); + for ( ; mit != monthentries.end(); ++mit ) { + if ( (*mit).start.date() == (*mit).end.date() ) { + // Show also single-day events as time line boxes + if ( subDailyFlags & TimeBoxes ) { + timeboxItems.append( new PrintCellItem( (*mit).event, (*mit).start, (*mit).end ) ); + } + // Show as text in the box + if ( subDailyFlags & Text ) { + textEvents[ (*mit).start.date().day() ] << (*mit).event->summary(); + } + } else { + // Multi-day events are always shown as time line boxes + QDateTime thisstart( (*mit).start ); + QDateTime thisend( (*mit).end ); + if ( thisstart.date()<start ) thisstart = start; + if ( thisend>endofmonth ) thisend = endofmonth; + timeboxItems.append( new PrintCellItem( (*mit).event, thisstart, thisend ) ); + } + } + + // For Multi-day events, line them up nicely so that the boxes don't overlap + QPtrListIterator<KOrg::CellItem> it1( timeboxItems ); + for( it1.toFirst(); it1.current(); ++it1 ) { + KOrg::CellItem *placeItem = it1.current(); + KOrg::CellItem::placeItem( timeboxItems, placeItem ); + } + QDateTime starttime( start, QTime( 0, 0, 0 ) ); + int newxstartcont = xstartcont; + + QFont oldfont( p.font() ); + p.setFont( QFont( "sans-serif", 7 ) ); + for( it1.toFirst(); it1.current(); ++it1 ) { + PrintCellItem *placeItem = static_cast<PrintCellItem *>( it1.current() ); + int minsToStart = starttime.secsTo( placeItem->start() )/60; + int minsToEnd = starttime.secsTo( placeItem->end() )/60; + + QRect 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() ); + newxstartcont = QMAX( newxstartcont, eventBox.right() ); + } + xstartcont = newxstartcont; + + // For Single-day events, simply print their summaries into the remaining + // space of the day's cell + for ( int d=0; d<daysinmonth; ++d ) { + QStringList dayEvents( textEvents[d+1] ); + QString txt = dayEvents.join(", "); + QRect dayBox( xstartcont, daysBox.top()+round(dayheight*d), 0, 0 ); + dayBox.setRight( box.right() ); + dayBox.setBottom( daysBox.top()+round(dayheight*(d+1)) ); + printEventString(p, dayBox, txt, Qt::AlignTop | Qt::AlignLeft | Qt::BreakAnywhere ); + } + p.setFont( oldfont ); +// p.setBrush( Qt::NoBrush ); + drawBox( p, BOX_BORDER_WIDTH, borderBox ); + p.restore(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void CalPrintPluginBase::drawMonthTable(QPainter &p, const QDate &qd, bool weeknumbers, + bool recurDaily, bool recurWeekly, + const QRect &box) +{ + int yoffset = mSubHeaderHeight; + int xoffset = 0; + QDate monthDate(QDate(qd.year(), qd.month(), 1)); + QDate monthFirst(monthDate); + QDate monthLast(monthDate.addMonths(1).addDays(-1)); + + + int weekdayCol = weekdayColumn( monthDate.dayOfWeek() ); + monthDate = monthDate.addDays(-weekdayCol); + + if (weeknumbers) { + xoffset += 14; + } + + int rows=(weekdayCol + qd.daysInMonth() - 1)/7 +1; + double cellHeight = ( box.height() - yoffset ) / (1.*rows); + double cellWidth = ( box.width() - xoffset ) / 7.; + + // Precalculate the grid... + // rows is at most 6, so using 8 entries in the array is fine, too! + int coledges[8], rowedges[8]; + for ( int i = 0; i <= 7; i++ ) { + rowedges[i] = int( box.top() + yoffset + i*cellHeight ); + coledges[i] = int( box.left() + xoffset + i*cellWidth ); + } + + if (weeknumbers) { + QFont oldFont(p.font()); + QFont newFont(p.font()); + newFont.setPointSize(6); + p.setFont(newFont); + QDate weekDate(monthDate); + for (int row = 0; row<rows; ++row ) { + int calWeek = weekDate.weekNumber(); + QRect rc( box.left(), rowedges[row], coledges[0] - 3 - box.left(), rowedges[row+1]-rowedges[row] ); + p.drawText( rc, Qt::AlignRight | Qt::AlignVCenter, QString::number( calWeek ) ); + weekDate = weekDate.addDays( 7 ); + } + p.setFont( oldFont ); + } + + QRect daysOfWeekBox( box ); + daysOfWeekBox.setHeight( mSubHeaderHeight ); + daysOfWeekBox.setLeft( box.left()+xoffset ); + drawDaysOfWeek( p, monthDate, monthDate.addDays( 6 ), daysOfWeekBox ); + + QColor back = p.backgroundColor(); + bool darkbg = false; + for ( int row = 0; row < rows; ++row ) { + for ( int col = 0; col < 7; ++col ) { + // show days from previous/next month with a grayed background + if ( (monthDate < monthFirst) || (monthDate > monthLast) ) { + p.setBackgroundColor( back.dark( 120 ) ); + darkbg = true; + } + QRect dayBox( coledges[col], rowedges[row], coledges[col+1]-coledges[col], rowedges[row+1]-rowedges[row] ); + drawDayBox(p, monthDate, dayBox, false, recurDaily, recurWeekly ); + if ( darkbg ) { + p.setBackgroundColor( back ); + darkbg = false; + } + monthDate = monthDate.addDays(1); + } + } +} + + +/////////////////////////////////////////////////////////////////////////////// + +void CalPrintPluginBase::drawTodo( int &count, Todo *todo, QPainter &p, + TodoSortField sortField, SortDirection sortDir, + bool connectSubTodos, bool strikeoutCompleted, + bool desc, int posPriority, int posSummary, + int posDueDt, int posPercentComplete, + int level, int x, int &y, int width, + int pageHeight, const Todo::List &todoList, + TodoParentStart *r ) +{ + QString outStr; + const KLocale *local = KGlobal::locale(); + QRect rect; + TodoParentStart startpt; + + // This list keeps all starting points of the parent to-dos so the connection + // lines of the tree can easily be drawn (needed if a new page is started) + static QPtrList<TodoParentStart> startPoints; + if ( level < 1 ) { + startPoints.clear(); + } + + // Compute the right hand side of the to-do box + int rhs = posPercentComplete; + if ( rhs < 0 ) rhs = posDueDt; //not printing percent completed + if ( rhs < 0 ) rhs = x+width; //not printing due dates either + + // size of to-do + outStr=todo->summary(); + int left = posSummary + ( level*10 ); + rect = p.boundingRect( left, y, ( rhs-left-5 ), -1, Qt::WordBreak, outStr ); + if ( !todo->description().isEmpty() && desc ) { + outStr = todo->description(); + rect = p.boundingRect( left+20, rect.bottom()+5, width-(left+10-x), -1, + Qt::WordBreak, outStr ); + } + // if too big make new page + if ( rect.bottom() > pageHeight ) { + // first draw the connection lines from parent to-dos: + if ( level > 0 && connectSubTodos ) { + TodoParentStart *rct; + for ( rct = startPoints.first(); rct; rct = startPoints.next() ) { + int start; + int center = rct->mRect.left() + (rct->mRect.width()/2); + int to = p.viewport().bottom(); + + // draw either from start point of parent or from top of the page + if ( rct->mSamePage ) + start = rct->mRect.bottom() + 1; + else + start = p.viewport().top(); + p.moveTo( center, start ); + p.lineTo( center, to ); + rct->mSamePage = false; + } + } + y=0; + mPrinter->newPage(); + } + + // If this is a sub-to-do, r will not be 0, and we want the LH side + // of the priority line up to the RH side of the parent to-do's priority + bool showPriority = posPriority>=0; + int lhs = posPriority; + if ( r ) { + lhs = r->mRect.right() + 1; + } + + outStr.setNum( todo->priority() ); + rect = p.boundingRect( lhs, y + 10, 5, -1, Qt::AlignCenter, outStr ); + // Make it a more reasonable size + rect.setWidth(18); + rect.setHeight(18); + + // Draw a checkbox + p.setBrush( QBrush( Qt::NoBrush ) ); + p.drawRect( rect ); + if ( todo->isCompleted() ) { + // cross out the rectangle for completed to-dos + p.drawLine( rect.topLeft(), rect.bottomRight() ); + p.drawLine( rect.topRight(), rect.bottomLeft() ); + } + lhs = rect.right() + 3; + + // Priority + if ( todo->priority() > 0 && showPriority ) { + p.drawText( rect, Qt::AlignCenter, outStr ); + } + startpt.mRect = rect; //save for later + + // Connect the dots + if ( level > 0 && connectSubTodos ) { + int bottom; + int center( r->mRect.left() + (r->mRect.width()/2) ); + if ( r->mSamePage ) + bottom = r->mRect.bottom() + 1; + else + bottom = 0; + int to( rect.top() + (rect.height()/2) ); + int endx( rect.left() ); + p.moveTo( center, bottom ); + p.lineTo( center, to ); + p.lineTo( endx, to ); + } + + // summary + outStr=todo->summary(); + rect = p.boundingRect( lhs, rect.top(), (rhs-(left + rect.width() + 5)), + -1, Qt::WordBreak, outStr ); + + QRect newrect; + //FIXME: the following code prints underline rather than strikeout text +#if 0 + QFont f( p.font() ); + if ( todo->isCompleted() && strikeoutCompleted ) { + f.setStrikeOut( true ); + p.setFont( f ); + } + p.drawText( rect, Qt::WordBreak, outStr, -1, &newrect ); + f.setStrikeOut( false ); + p.setFont( f ); +#endif + //TODO: Remove this section when the code above is fixed + p.drawText( rect, Qt::WordBreak, outStr, -1, &newrect ); + if ( todo->isCompleted() && strikeoutCompleted ) { + // strike out the summary text if to-do is complete + // Note: we tried to use a strike-out font and for unknown reasons the + // result was underline instead of strike-out, so draw the lines ourselves. + int delta = p.fontMetrics().lineSpacing(); + int lines = ( rect.height() / delta ) + 1; + for ( int i=0; i<lines; i++ ) { + p.moveTo( rect.left(), rect.top() + ( delta/2 ) + ( i*delta ) ); + p.lineTo( rect.right(), rect.top() + ( delta/2 ) + ( i*delta ) ); + } + } + + // due date + if ( todo->hasDueDate() && posDueDt>=0 ) { + outStr = local->formatDate( todo->dtDue().date(), true ); + rect = p.boundingRect( posDueDt, y, x + width, -1, + Qt::AlignTop | Qt::AlignLeft, outStr ); + p.drawText( rect, Qt::AlignTop | Qt::AlignLeft, outStr ); + } + + // percentage completed + bool showPercentComplete = posPercentComplete>=0; + if ( showPercentComplete ) { + int lwidth = 24; + int lheight = 12; + //first, draw the progress bar + int progress = (int)(( lwidth*todo->percentComplete())/100.0 + 0.5); + + p.setBrush( QBrush( Qt::NoBrush ) ); + p.drawRect( posPercentComplete, y+3, lwidth, lheight ); + if ( progress > 0 ) { + p.setBrush( QColor( 128, 128, 128 ) ); + p.drawRect( posPercentComplete, y+3, progress, lheight ); + } + + //now, write the percentage + outStr = i18n( "%1%" ).arg( todo->percentComplete() ); + rect = p.boundingRect( posPercentComplete+lwidth+3, y, x + width, -1, + Qt::AlignTop | Qt::AlignLeft, outStr ); + p.drawText( rect, Qt::AlignTop | Qt::AlignLeft, outStr ); + } + + // description + if ( !todo->description().isEmpty() && desc ) { + y = newrect.bottom() + 5; + outStr = todo->description(); + rect = p.boundingRect( left+20, y, x+width-(left+10), -1, + Qt::WordBreak, outStr ); + p.drawText( rect, Qt::WordBreak, outStr, -1, &newrect ); + } + + // Set the new line position + y = newrect.bottom() + 10; //set the line position + + // If the to-do has sub-to-dos, we need to call ourselves recursively +#if 0 + Incidence::List l = todo->relations(); + Incidence::List::ConstIterator it; + startPoints.append( &startpt ); + for( it = l.begin(); it != l.end(); ++it ) { + count++; + // In the future, to-dos might also be related to events + // Manually check if the sub-to-do is in the list of to-dos to print + // The problem is that relations() does not apply filters, so + // we need to compare manually with the complete filtered list! + Todo* subtodo = dynamic_cast<Todo *>( *it ); + if (subtodo && todoList.contains( subtodo ) ) { + drawTodo( count, subtodo, p, connectSubTodos, strikeoutCompleted, + desc, posPriority, posSummary, posDueDt, posPercentComplete, + level+1, x, y, width, pageHeight, todoList, &startpt ); + } + } +#endif + // Make a list of all the sub-to-dos related to this to-do. + Todo::List t; + Incidence::List l = todo->relations(); + Incidence::List::ConstIterator it; + for( it=l.begin(); it!=l.end(); ++it ) { + // In the future, to-dos might also be related to events + // Manually check if the sub-to-do is in the list of to-dos to print + // The problem is that relations() does not apply filters, so + // we need to compare manually with the complete filtered list! + Todo* subtodo = dynamic_cast<Todo *>( *it ); + if ( subtodo && todoList.contains( subtodo ) ) { + t.append( subtodo ); + } + } + + // Sort the sub-to-dos and then print them + Todo::List sl = mCalendar->sortTodos( &t, sortField, sortDir ); + Todo::List::ConstIterator isl; + startPoints.append( &startpt ); + for( isl = sl.begin(); isl != sl.end(); ++isl ) { + count++; + drawTodo( count, ( *isl ), p, sortField, sortDir, + connectSubTodos, strikeoutCompleted, + desc, posPriority, posSummary, posDueDt, posPercentComplete, + level+1, x, y, width, pageHeight, todoList, &startpt ); + } + startPoints.remove( &startpt ); +} + +int CalPrintPluginBase::weekdayColumn( int weekday ) +{ + return ( weekday + 7 - KGlobal::locale()->weekStartDay() ) % 7; +} + +void CalPrintPluginBase::drawJournalField( QPainter &p, QString field, QString text, + int x, int &y, int width, int pageHeight ) +{ + if ( text.isEmpty() ) return; + + QString entry( field.arg( text ) ); + + QRect rect( p.boundingRect( x, y, width, -1, Qt::WordBreak, entry) ); + if ( rect.bottom() > pageHeight) { + // Start new page... + // FIXME: If it's a multi-line text, draw a few lines on this page, and the + // remaining lines on the next page. + y=0; + mPrinter->newPage(); + rect = p.boundingRect( x, y, width, -1, Qt::WordBreak, entry); + } + QRect newrect; + p.drawText( rect, Qt::WordBreak, entry, -1, &newrect ); + y = newrect.bottom() + 7; +} + +void CalPrintPluginBase::drawJournal( Journal * journal, QPainter &p, int x, int &y, + int width, int pageHeight ) +{ + QFont oldFont( p.font() ); + p.setFont( QFont( "sans-serif", 15 ) ); + QString headerText; + QString dateText( KGlobal::locale()-> + formatDate( journal->dtStart().date(), false ) ); + + if ( journal->summary().isEmpty() ) { + headerText = dateText; + } else { + headerText = i18n("Description - date", "%1 - %2") + .arg( journal->summary() ) + .arg( dateText ); + } + + QRect rect( p.boundingRect( x, y, width, -1, Qt::WordBreak, headerText) ); + if ( rect.bottom() > pageHeight) { + // Start new page... + y=0; + mPrinter->newPage(); + rect = p.boundingRect( x, y, width, -1, Qt::WordBreak, headerText ); + } + QRect newrect; + p.drawText( rect, Qt::WordBreak, headerText, -1, &newrect ); + p.setFont( oldFont ); + + y = newrect.bottom() + 4; + + p.drawLine( x + 3, y, x + width - 6, y ); + y += 5; + + drawJournalField( p, i18n("Person: %1"), journal->organizer().fullName(), x, y, width, pageHeight ); + drawJournalField( p, i18n("%1"), journal->description(), x, y, width, pageHeight ); + y += 10; +} + + +void CalPrintPluginBase::drawSplitHeaderRight( QPainter &p, const QDate &fd, + const QDate &td, + const QDate &, + int width, int ) +{ + QFont oldFont( p.font() ); + + QPen oldPen( p.pen() ); + QPen pen( Qt::black, 4 ); + + QString title; + if ( mCalSys ) { + if ( fd.month() == td.month() ) { + title = i18n("Date range: Month dayStart - dayEnd", "%1 %2 - %3") + .arg( mCalSys->monthName( fd.month(), false ) ) + .arg( mCalSys->dayString( fd, false ) ) + .arg( mCalSys->dayString( td, false ) ); + } else { + title = i18n("Date range: monthStart dayStart - monthEnd dayEnd", "%1 %2 - %3 %4") + .arg( mCalSys->monthName( fd.month(), false ) ) + .arg( mCalSys->dayString( fd, false ) ) + .arg( mCalSys->monthName( td.month(), false ) ) + .arg( mCalSys->dayString( td, false ) ); + } + } + + QFont serifFont("Times", 30); + p.setFont(serifFont); + + int lineSpacing = p.fontMetrics().lineSpacing(); + p.drawText( 0, lineSpacing * 0, width, lineSpacing, + Qt::AlignRight | Qt::AlignTop, title ); + + title.truncate(0); + + p.setPen( pen ); + p.drawLine(300, lineSpacing * 1, width, lineSpacing * 1); + p.setPen( oldPen ); + + p.setFont(QFont("Times", 20, QFont::Bold, TRUE)); + int newlineSpacing = p.fontMetrics().lineSpacing(); + title += QString::number(fd.year()); + p.drawText( 0, lineSpacing * 1 + 4, width, newlineSpacing, + Qt::AlignRight | Qt::AlignTop, title ); + + p.setFont( oldFont ); +} + +#endif diff --git a/korganizer/printing/calprintpluginbase.h b/korganizer/printing/calprintpluginbase.h new file mode 100644 index 000000000..9312d0042 --- /dev/null +++ b/korganizer/printing/calprintpluginbase.h @@ -0,0 +1,514 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1998 Preston Brown <pbrown@kde.org> + Copyright (c) 2003 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef CALPRINTPLUGINBASE_H +#define CALPRINTPLUGINBASE_H +// #define KORG_NOPRINTER + +#ifndef KORG_NOPRINTER + +#include <qdatetime.h> +#include <kprinter.h> +#include <kdepimmacros.h> +#include <libkcal/calendar.h> +#include <libkcal/event.h> +#include <libkcal/todo.h> +#include "korganizer/printplugin.h" +#include "korganizer/corehelper.h" + + +class PrintCellItem; + +class QWidget; + +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 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 +#define EVENT_BORDER_WIDTH 0 // with of the border of all incidence boxes + +#define TIMELINE_WIDTH 50 // width of timeline (day and timetable) + +/** + Base class for KOrganizer printing classes. Each sub class represents one + calendar print format. +*/ +class KDE_EXPORT CalPrintPluginBase : public KOrg::PrintPlugin +{ + public: + enum DisplayFlags { + Text=0x0001, + TimeBoxes=0x0002 + }; + + public: + /** + Constructor + */ + CalPrintPluginBase(); + virtual ~CalPrintPluginBase(); + + /** + Returns widget for configuring the print format. + */ + virtual QWidget *createConfigWidget( QWidget * ); + + /** + Actually do the printing. + + \param p QPainter the print result is painted to + \param width Width of printable area + \param height Height of printable area + */ + virtual void print( QPainter &p, int width, int height ) = 0; + /** + Start printing. + */ + virtual void doPrint( KPrinter *printer ); + + /** + Load print format configuration from config file. + */ + virtual void loadConfig() = 0; + /** + Write print format configuration to config file. + */ + virtual void saveConfig() = 0; + + /** + Load complete config. This also calls loadConfig() of the derived class. + */ + void doLoadConfig(); + /** + Save complete config. This also calls saveConfig() of the derived class. + */ + void doSaveConfig(); + + /** HELPER FUNCTIONS */ + public: + void setKOrgCoreHelper( KOrg::CoreHelper*helper ); + bool useColors() const; + void setUseColors( bool useColors ); + + /** Helper functions to hide the KOrg::CoreHelper */ + QColor categoryBgColor( Incidence *incidence ); + QColor textColor( const QColor &color ); + QTime dayStart(); + bool isWorkingDay( const QDate &dt ); + QString holidayString( const QDate &dt ); + Event *holiday( const QDate &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. + \param weekday Index of the weekday + */ + static int weekdayColumn( int weekday ); + void setCategoryColors( QPainter &p, Incidence *incidence ); + + 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 + default value based on the printer orientation. + \return height of the page header of the printout + */ + int headerHeight() const; + void setHeaderHeight( const int height ); + + int subHeaderHeight() const; + void setSubHeaderHeight( 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 ); + + const KCalendarSystem *calendarSystem() const; + void setCalendarSystem( const KCalendarSystem *calsys ); + + + /***************************************************************** + ** PRINTING HELPER FUNCTIONS ** + *****************************************************************/ + public: + /** + Draw a box with given width at the given coordinates. + \param p The printer to be used + \param linewidth The border width of the box + \param rect The rectangle of the box + */ + static void drawBox( QPainter &p, int linewidth, const QRect &rect ); + /** + Draw a shaded box with given width at the given coordinates. + \param p The printer to be used + \param linewidth The border width of the box + \param brush The brush to fill the box + \param rect The rectangle of the box + */ + static void drawShadedBox( QPainter &p, int linewidth, const QBrush &brush, const QRect &rect ); + + /** + Print the given string (event summary) in the given rectangle. Margins + and justification (centered or not) are automatically adjusted. + \param p QPainter of the printout + \param box Coordinates of the surrounding event box + \param str The text to be printed in the box + */ + void printEventString( QPainter &p, const QRect &box, const QString &str, int flags = -1 ); + + /** + Print the box for the given event with the given string. + \param p QPainer of the printout + \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 + */ + void showEventBox( QPainter &p, const QRect &box, Incidence *incidence, const QString &str, int flags = -1 ); + + /** + Draw a subheader box with a shaded background and the given string + \param p QPainter of the printout + \param str Text to be printed inside the box + \param box Coordinates of the box + */ + void drawSubHeaderBox(QPainter &p, const QString &str, const QRect &box ); + + /** + Draw an event box with vertical text. + \param p QPainter of the printout + \param box Coordinates of the box + \param str ext to be printed inside the box + */ + void drawVerticalBox( QPainter &p, const QRect &box, const QString &str ); + + /** + Draw a component box with a heading (printed in bold). + \param p QPainter of the printout + \param box Coordinates of the box + \param caption Caption string to be printed inside the box + \param contents Normal text contents of the box. If contents.isNull(), + 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 + next line (no indentation of the contents) + \param expand Whether to expand the box vertically to fit the + whole text in it. + \return The bottom of the printed box. If expand==true, the bottom of + the drawn box is returned, if expand==false, the vertical + end of the printed contents inside the box is returned. + If you want to print some custom graphics or text below + the contents, use the return value as the top-value of your + custom contents in that case. + */ + int drawBoxWithCaption( QPainter &p, const QRect &box, const QString &caption, + const QString &contents, + bool sameLine, bool expand, const QFont &captionFont, const QFont &textFont ); + + /** + Draw the gray header bar of the printout to the QPainter. + It prints the given text and optionally one or two small + month views, as specified by the two QDate. The printed + text can also contain a line feed. + If month2 is invalid, only the month that contains month1 + is printed. + E.g. the filofax week view draws just the current month, + while the month view draws the previous and the next month. + \param p QPainter of the printout + \param title The string printed as the title of the page + (e.g. the date, date range or todo list title) + \param month1 Date specifying the month for the left one of + the small month views in the title bar. If left + empty, only month2 will be printed (or none, + it that is invalid as well). + \param month2 Date specifying the month for the right one of + the small month views in the title bar. If left + empty, only month1 will be printed (or none, + it that is invalid as well). + \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 + is box.bottom, otherwise it is larger than box.bottom + and matches the y-coordinate of the surrounding rectangle. + */ + int drawHeader( QPainter &p, QString title, + const QDate &month1, const QDate &month2, + const QRect &box, bool expand = false ); + /** + Draw a small calendar with the days of a month into the given area. + Used for example in the title bar of the sheet. + \param p QPainter of the printout + \param qd Arbitrary Date within the month to be printed. + \param box coordinates of the small calendar + */ + void drawSmallMonth( QPainter &p, const QDate &qd, const QRect &box ); + + /** + Draw a horizontal bar with the weekday names of the given date range + in the given area of the painter. + This is used for the weekday-bar on top of the timetable view and the month view. + \param p QPainter of the printout + \param fromDate First date of the printed dates + \param toDate Last date of the printed dates + \param box coordinates of the box for the days of the week + */ + void drawDaysOfWeek( QPainter &p, + const QDate &fromDate, const QDate &toDate, + const QRect &box ); + /** + Draw a single weekday name in a box inside the given area of the painter. + This is called in a loop by drawDaysOfWeek. + \param p QPainter of the printout + \param qd Date of the printed day + \param box coordinates of the weekbox + */ + void drawDaysOfWeekBox( QPainter &p, const QDate &qd, const QRect &box ); + /** + Draw a (vertical) time scale from time fromTime to toTime inside the given area of the painter. + Every hour will have a one-pixel line over the whole width, every + half-hour the line will only span the left half of the width. + This is used in the day and timetable print styles + \param p QPainter of the printout + \param fromTime Start time of the time range to display + \param toTime End time of the time range to display + \param box coordinates of the timeline + */ + void drawTimeLine( QPainter &p, + const QTime &fromTime, const QTime &toTime, + const QRect &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, + 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 ", ". + \param p QPainter of the printout + \param eventList The list of all-day events that are supposed to be printed + inside this box + \param qd The date of the currently printed day + \param expandable If true, height is the height of one single cell, the printout + will use as many cells as events in the list and return the total height + needed for all of them. If false, height specifies the total height + allowed for all events, and the events are displayed in one cell, + with their summaries concatenated by ", ". + \param box coordinates of the all day box. + \return The height used for the all-day box. + */ + int drawAllDayBox( QPainter &p, Event::List &eventList, + const QDate &qd, bool expandable, + const QRect &box ); + /** + Draw the agenda box for the day print style (the box showing all events of that day). + Also draws a grid with half-hour spacing of the grid lines. + \param p QPainter of the printout + \param eventList The list of the events that are supposed to be printed + inside this box + \param qd The date of the currently printed day + \param expandable If true, the start and end times are adjusted to include + the whole range of all events of that day, not just of the given time range. + The height of the box will not be affected by this (but the height + of one hour will be scaled down so that the whole range fits into + the box. fromTime and toTime receive the actual time range printed + by this function). + \param fromTime Start of the time range to be printed. Might be adjusted + to include all events if expandable==true + \param toTime End of the time range to be printed. Might be adjusted + to include all events if expandable==true + \param box coordinates of the agenda day box. + */ + void drawAgendaDayBox( QPainter &p, Event::List &eventList, + const QDate &qd, bool expandable, + QTime &fromTime, QTime &toTime, + const QRect &box ); + + void drawAgendaItem( PrintCellItem *item, QPainter &p, + const QDateTime &startPrintDate, + const QDateTime &endPrintDate, + float minlen, const QRect &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. + \param p QPainter of the printout + \param qd The date of the currently printed day. All events of the calendar + that appear on that day will be printed. + \param box coordinates of the day box. + \param fullDate Whether the title bar of the box should contain the full + date string or just a short. + \param printRecurDaily Whether daily recurring incidences should be printed. + \param printRecurWeekly Whether weekly recurring incidences should be printed. + */ + void drawDayBox( QPainter &p, const QDate &qd, + const QRect &box, + bool fullDate = false, bool printRecurDaily = true, + bool printRecurWeekly = true ); + /** + Draw the week (filofax) table of the week containing the date qd. The first + three days of the week will be shown in the first column (using drawDayBox), + the remaining four in the second column, where the last two days of the week + (typically Saturday and Sunday) only get half the height of the other day boxes. + \param p QPainter of the printout + \param qd Arbitrary date within the week to be printed. + \param box coordinates of the week box. + */ + void drawWeek( QPainter &p, const QDate &qd, + const QRect &box ); + /** + Draw the timetable view of the given time range from fromDate to toDate. + On the left side the time scale is printed (using drawTimeLine), then each + day gets one column (printed using drawAgendaDayBox), + and the events are displayed as boxes (like in korganizer's day/week view). + The first cell of each column contains the all-day events (using + drawAllDayBox with expandable=false). + The given time range cannot be expanded to include all events. + \param p QPainter of the printout + \param fromDate First day to be included in the page + \param toDate Last day to be included in the page + \param fromTime Start time of the displayed time range + \param toTime End time of the displayed time range + \param box coordinates of the time table. + */ + void drawTimeTable( QPainter &p, const QDate &fromDate, const QDate &toDate, + QTime &fromTime, QTime &toTime, + const QRect &box ); + + /** + Draw the month table of the month containing the date qd. Each day gets one + box (using drawDayBox) that contains a list of all events on that day. They are arranged + in a matrix, with the first column being the first day of the + week (so it might display some days of the previous and the next month). + Above the matrix there is a bar showing the weekdays (drawn using drawDaysOfWeek). + \param p QPainter of the printout + \param qd Arbitrary date within the month to be printed. + \param recurDaily Whether daily recurring incidences should be printed. + \param recurWeekly Whether weekly recurring incidences should be printed. + \param weeknumbers Whether the week numbers are printed left of each row of the matrix + \param box coordinates of the month. + */ + void drawMonthTable( QPainter &p, const QDate &qd, bool weeknumbers, + bool recurDaily, bool recurWeekly, + const QRect &box ); + /** + Draw a vertical representation of the month containing the date dt. Each + day gets one line. + \param p QPainter of the printout + \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 + 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. + \param holidaysFlags Bitfield consisting of DisplayFlags flags to determine + how holidays should be printed. + */ + void drawMonth( QPainter &p, const QDate &dt, const QRect &box, int maxdays = -1, int subDailyFlags = TimeBoxes, int holidaysFlags = Text ); + + /** + Internal class representing the start of a todo. + */ + class TodoParentStart; + + /** + Draws single to-do and its (intented) sub-to-dos, optionally connects them by a tree-like line, and optionally shows due date, summary, description and priority. + \param count The number of the currently printed to-do (count will be incremented for each to-do drawn) + \param todo The to-do to be printed. It's sub-to-dos are recursively drawn, so drawTodo should only be called on the to-dos of the highest level. + \param p QPainter of the printout + \param sortField Specifies on which attribute of the todo you want to sort. + \param sortDir Specifies if you want to sort ascending or descending. + \param connectSubTodos Whether sub-to-dos shall be connected with their parent by a line (tree-like). + \param strikeoutCompleted Whether completed to-dos should be printed with strike-out summaries. + \param desc Whether to print the whole description of the to-do (the summary is always printed). + \param posPriority x-coordinate where the priority is supposed to be printed. If <0, no priority will be printed. + \param posSummary x-coordinate where the summary of the to-do is supposed to be printed. + \param posDueDt x-coordinate where the due date is supposed to the be printed. If <0, no due date will be printed. + \param posPercentComplete x-coordinate where the percentage complete is supposed to be printed. If <0, percentage complete will not be printed. + \param level Level of the current to-do in the to-do hierarchy (0 means highest level of printed to-dos, 1 are their sub-to-dos, etc.) + \param x x-coordinate of the upper left coordinate of the first to-do. + \param y y-coordinate of the upper left coordinate of the first to-do. + \param width width of the whole to-do list. + \param pageHeight Total height allowed for the to-do list on a page. If an to-do would be below that line, a new page is started. + \param todoList Contains a list of sub-todos for the specified @p todo . + \param r Internal (used when printing sub-to-dos to give information about its parent) + */ + void drawTodo( int &count, Todo *todo, QPainter &p, + TodoSortField sortField, SortDirection sortDir, + bool connectSubTodos, bool strikeoutCompleted, bool desc, + int posPriority, int posSummary, int posDueDt, + int posPercentComplete, int level, int x, int &y, + int width, int pageHeight, + const Todo::List &todoList, TodoParentStart *r = 0 ); + + /** + Draws single journal item. + \param journal The item to be printed. + \param p QPainter of the printout + \param x x-coordinate of the upper left coordinate of the first item + \param y y-coordinate of the upper left coordinate of the first item + \param width width of the whole list + \param pageHeight Total height allowed for the list on a page. If an item + would be below that line, a new page is started. + */ + void drawJournal( Journal * journal, QPainter &p, int x, int &y, + int width, int pageHeight ); + void drawJournalField( QPainter &p, QString field, QString text, + int x, int &y, int width, int pageHeight ); + + void drawSplitHeaderRight( QPainter &p, const QDate &fd, const QDate &td, + const QDate &cd, int width, int height ); + + + protected: + void drawIncidence( QPainter &p, const QRect &dayBox, const QString &time, + const QString &summary, int &textY ); + + protected: + bool mUseColors; + int mHeaderHeight; + int mSubHeaderHeight; + int mMargin; + int mPadding; + int mBorder; + const KCalendarSystem *mCalSys; + + public: +}; + +#endif + +#endif diff --git a/korganizer/printing/calprinttodoconfig_base.ui b/korganizer/printing/calprinttodoconfig_base.ui new file mode 100644 index 000000000..53fd3bfba --- /dev/null +++ b/korganizer/printing/calprinttodoconfig_base.ui @@ -0,0 +1,455 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>CalPrintTodoConfig_Base</class> +<comment>Configuration page for the print day mode.</comment> +<author>Reinhold Kainhofer <reinhold@kainhofer.com></author> +<widget class="QWidget"> + <property name="name"> + <cstring>CalPrintTodoConfig_Base</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>410</width> + <height>459</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>mTitleLabel</cstring> + </property> + <property name="text"> + <string>&Title:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mTitle</cstring> + </property> + </widget> + <widget class="QLineEdit" row="0" column="1"> + <property name="name"> + <cstring>mTitle</cstring> + </property> + <property name="text"> + <string>To-do List</string> + </property> + </widget> + <widget class="QButtonGroup" row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>mPrintType</cstring> + </property> + <property name="title"> + <string>To-dos to Print</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton"> + <property name="name"> + <cstring>mPrintAll</cstring> + </property> + <property name="text"> + <string>Print &all to-dos</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>mPrintUnfinished</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>Print &unfinished to-dos only</string> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>mPrintDueRange</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>Print only to-dos due in the &range:</string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>16</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel"> + <property name="name"> + <cstring>mFromDateLabel</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Start date:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mFromDate</cstring> + </property> + </widget> + <widget class="KDateEdit"> + <property name="name"> + <cstring>mFromDate</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="focusPolicy"> + <enum>StrongFocus</enum> + </property> + <property name="whatsThis" stdset="0"> + <string>If you want to print more days at once, you can define a range of dates with this option and the <i>End date</i> option. This option is used to define the start date.</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>mToDateLabel</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&End date:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mToDate</cstring> + </property> + </widget> + <widget class="KDateEdit"> + <property name="name"> + <cstring>mToDate</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="focusPolicy"> + <enum>StrongFocus</enum> + </property> + <property name="whatsThis" stdset="0"> + <string>If you want to print more days at once, you can define a range of dates with this option and the <i>Start date</i> option. This option is used to define the end date.</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>16</width> + <height>21</height> + </size> + </property> + </spacer> + </hbox> + </widget> + </vbox> + </widget> + <widget class="QButtonGroup" row="2" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>includeInfoBox</cstring> + </property> + <property name="title"> + <string>Include Information</string> + </property> + <property name="checkable"> + <bool>false</bool> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox" row="1" column="0"> + <property name="name"> + <cstring>mPriority</cstring> + </property> + <property name="text"> + <string>&Priority</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QCheckBox" row="0" column="0"> + <property name="name"> + <cstring>mDescription</cstring> + </property> + <property name="text"> + <string>&Description</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QCheckBox" row="0" column="1"> + <property name="name"> + <cstring>mDueDate</cstring> + </property> + <property name="text"> + <string>Due date</string> + </property> + <property name="accel"> + <string></string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QCheckBox" row="1" column="1"> + <property name="name"> + <cstring>mPercentComplete</cstring> + </property> + <property name="text"> + <string>Per&centage completed</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </grid> + </widget> + <spacer row="5" column="1"> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + <widget class="QGroupBox" row="3" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>sortingOptionsBox</cstring> + </property> + <property name="title"> + <string>Sorting Options</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>sortFieldLabel</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>Sort field:</string> + </property> + </widget> + <widget class="QComboBox" row="0" column="1"> + <property name="name"> + <cstring>mSortField</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>sortDirectionLabel</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>Sort direction:</string> + </property> + </widget> + <widget class="QComboBox" row="1" column="1"> + <property name="name"> + <cstring>mSortDirection</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + </widget> + <spacer row="0" column="2"> + <property name="name"> + <cstring>spacer4</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>121</width> + <height>20</height> + </size> + </property> + </spacer> + <spacer row="1" column="2"> + <property name="name"> + <cstring>spacer5</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>121</width> + <height>20</height> + </size> + </property> + </spacer> + </grid> + </widget> + <widget class="QButtonGroup" row="4" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>otherOptionsBox</cstring> + </property> + <property name="title"> + <string>Other Options</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>mConnectSubTodos</cstring> + </property> + <property name="text"> + <string>Co&nnect sub-to-dos with its parent</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>mStrikeOutCompleted</cstring> + </property> + <property name="text"> + <string>Strike &out completed to-do summaries</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </vbox> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>mPrintDueRange</sender> + <signal>toggled(bool)</signal> + <receiver>mFromDateLabel</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>mPrintDueRange</sender> + <signal>toggled(bool)</signal> + <receiver>mFromDate</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>mPrintDueRange</sender> + <signal>toggled(bool)</signal> + <receiver>mToDate</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>mPrintDueRange</sender> + <signal>toggled(bool)</signal> + <receiver>mToDateLabel</receiver> + <slot>setEnabled(bool)</slot> + </connection> +</connections> +<tabstops> + <tabstop>mTitle</tabstop> + <tabstop>mPrintAll</tabstop> + <tabstop>mFromDate</tabstop> + <tabstop>mToDate</tabstop> + <tabstop>mDescription</tabstop> + <tabstop>mDueDate</tabstop> + <tabstop>mPriority</tabstop> + <tabstop>mPercentComplete</tabstop> + <tabstop>mSortField</tabstop> + <tabstop>mSortDirection</tabstop> + <tabstop>mConnectSubTodos</tabstop> + <tabstop>mStrikeOutCompleted</tabstop> +</tabstops> +<includes> + <include location="global" impldecl="in declaration">kdateedit.h</include> +</includes> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>libkdepim/kdateedit.h</includehint> + <includehint>libkdepim/kdateedit.h</includehint> +</includehints> +</UI> diff --git a/korganizer/printing/calprintweekconfig_base.ui b/korganizer/printing/calprintweekconfig_base.ui new file mode 100644 index 000000000..a14013cee --- /dev/null +++ b/korganizer/printing/calprintweekconfig_base.ui @@ -0,0 +1,300 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>CalPrintWeekConfig_Base</class> +<comment>Configuration page for the print week mode.</comment> +<author>Reinhold Kainhofer <reinhold@kainhofer.com></author> +<widget class="QWidget"> + <property name="name"> + <cstring>CalPrintWeek_Base</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>386</width> + <height>262</height> + </rect> + </property> + <property name="caption"> + <string>CalPrintWeek_Base</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <spacer row="4" column="0"> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>27</height> + </size> + </property> + </spacer> + <widget class="QGroupBox" row="0" column="0"> + <property name="name"> + <cstring>mDateRangeGroup</cstring> + </property> + <property name="title"> + <string>Date && Time Range</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer row="0" column="4"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>16</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>mFromDateLabel</cstring> + </property> + <property name="text"> + <string>&Start date:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mFromDate</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can choose which events should be printed based on their date. This check enables you to enter the start date of the date range. Use the <i>End date</i> to enter the end date of the daterange.</string> + </property> + </widget> + <widget class="KDateEdit" row="0" column="1"> + <property name="name"> + <cstring>mFromDate</cstring> + </property> + <property name="focusPolicy"> + <enum>StrongFocus</enum> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can choose which events should be printed based on their date. This check enables you to enter the start date of the date range. Use the <i>End date</i> to enter the end date of the daterange.</string> + </property> + </widget> + <widget class="QLabel" row="1" column="2"> + <property name="name"> + <cstring>mToTimeLabel</cstring> + </property> + <property name="text"> + <string>End ti&me:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mToTime</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>All events which start later than the given time will not be printed.</string> + </property> + </widget> + <spacer row="1" column="4"> + <property name="name"> + <cstring>spacer4</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>110</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QTimeEdit" row="1" column="3"> + <property name="name"> + <cstring>mToTime</cstring> + </property> + <property name="time"> + <time> + <hour>18</hour> + <minute>0</minute> + <second>0</second> + </time> + </property> + <property name="display"> + <set>Minutes|Hours</set> + </property> + <property name="whatsThis" stdset="0"> + <string>All events which start later than the given time will not be printed.</string> + </property> + </widget> + <widget class="QLabel" row="0" column="2"> + <property name="name"> + <cstring>mFromTimeLabel</cstring> + </property> + <property name="text"> + <string>Start &time:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mFromTime</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>All events which start earlier than the given time will not be printed.</string> + </property> + </widget> + <widget class="QTimeEdit" row="0" column="3"> + <property name="name"> + <cstring>mFromTime</cstring> + </property> + <property name="time"> + <time> + <hour>8</hour> + <minute>0</minute> + <second>0</second> + </time> + </property> + <property name="display"> + <set>Minutes|Hours</set> + </property> + <property name="whatsThis" stdset="0"> + <string>All events which start earlier than the given time will not be printed.</string> + </property> + </widget> + <widget class="KDateEdit" row="1" column="1"> + <property name="name"> + <cstring>mToDate</cstring> + </property> + <property name="focusPolicy"> + <enum>StrongFocus</enum> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can choose which events should be printed based on their date. This check enables you to enter the end date of the date range. Use the <i>Start date</i> to enter the start date of the daterange.</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>mToDateLabel</cstring> + </property> + <property name="text"> + <string>&End date:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>mToDate</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can choose which events should be printed based on their date. This check enables you to enter the end date of the date range. Use the <i>Start date</i> to enter the start date of the daterange.</string> + </property> + </widget> + </grid> + </widget> + <widget class="QCheckBox" row="3" column="0"> + <property name="name"> + <cstring>mColors</cstring> + </property> + <property name="text"> + <string>&Use colors</string> + </property> + <property name="whatsThis" stdset="0"> + <string>The timetable view supports colors. If you want to make use of colors you should check this option. The category colors will be used.</string> + </property> + </widget> + <widget class="QButtonGroup" row="1" column="0"> + <property name="name"> + <cstring>mPrintType</cstring> + </property> + <property name="title"> + <string>Print Layout</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton" row="0" column="0" rowspan="1" colspan="5"> + <property name="name"> + <cstring>mPrintTypeButton1</cstring> + </property> + <property name="text"> + <string>Print as &Filofax page</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + <property name="whatsThis" stdset="0"> + <string>The Filofax view prints one week per page, so all days have a large surface.</string> + </property> + </widget> + <widget class="QRadioButton" row="1" column="0" rowspan="1" colspan="5"> + <property name="name"> + <cstring>mPrintTypeButton2</cstring> + </property> + <property name="text"> + <string>Print as &timetable view</string> + </property> + <property name="whatsThis" stdset="0"> + <string>This view is similar to the weekview in KOrganizer. The week is printed in landscape layout. You can even use the same colors for the items if you check <i>Use Colors</i>.</string> + </property> + </widget> + <widget class="QRadioButton" row="2" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>mPrintTypeButton3</cstring> + </property> + <property name="text"> + <string>Print as split week view</string> + </property> + <property name="whatsThis" stdset="0"> + <string>This view is similar to the week view in KOrganizer. The only difference with the timetable view is the page layout. Timetables are printed in landscape, the split week view in portrait.</string> + </property> + </widget> + </grid> + </widget> + <widget class="QCheckBox" row="2" column="0"> + <property name="name"> + <cstring>mIncludeTodos</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Include to-&dos that are due on the printed day(s)</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Check this option if you want to have to-dos on the print, placed by their due date.</string> + </property> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<tabstops> + <tabstop>mFromDate</tabstop> + <tabstop>mFromTime</tabstop> + <tabstop>mToDate</tabstop> + <tabstop>mToTime</tabstop> + <tabstop>mPrintTypeButton1</tabstop> + <tabstop>mIncludeTodos</tabstop> + <tabstop>mColors</tabstop> +</tabstops> +<includes> + <include location="global" impldecl="in declaration">kdateedit.h</include> +</includes> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>libkdepim/kdateedit.h</includehint> + <includehint>libkdepim/kdateedit.h</includehint> +</includehints> +</UI> diff --git a/korganizer/printing/cellitem.cpp b/korganizer/printing/cellitem.cpp new file mode 100644 index 000000000..67e52c58e --- /dev/null +++ b/korganizer/printing/cellitem.cpp @@ -0,0 +1,98 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "cellitem.h" + +#include <klocale.h> +#include <kdebug.h> + +#include <qintdict.h> + +using namespace KOrg; + +QString CellItem::label() const +{ + return i18n("<undefined>"); +} + +QPtrList<CellItem> CellItem::placeItem( QPtrList<CellItem> cells, + CellItem *placeItem ) +{ + kdDebug(5855) << "Placing " << placeItem->label() << endl; + + QPtrList<KOrg::CellItem> conflictItems; + int maxSubCells = 0; + QIntDict<KOrg::CellItem> subCellDict; + + // Find all items which are in same cell + QPtrListIterator<KOrg::CellItem> it2( cells ); + for( it2.toFirst(); it2.current(); ++it2 ) { + KOrg::CellItem *item = it2.current(); + if ( item == placeItem ) continue; + + if ( item->overlaps( placeItem ) ) { + kdDebug(5855) << " Overlaps: " << item->label() << endl; + + conflictItems.append( item ); + if ( item->subCells() > maxSubCells ) maxSubCells = item->subCells(); + subCellDict.insert( item->subCell(), item ); + } + } + + if ( conflictItems.count() > 0 ) { + // Look for unused sub cell and insert item + int i; + for( i = 0; i < maxSubCells; ++i ) { + kdDebug(5855) << " Trying subcell " << i << endl; + if ( !subCellDict.find( i ) ) { + kdDebug(5855) << " Use subcell " << i << endl; + placeItem->setSubCell( i ); + break; + } + } + if ( i == maxSubCells ) { + kdDebug(5855) << " New subcell " << i << endl; + placeItem->setSubCell( maxSubCells ); + maxSubCells++; // add new item to number of sub cells + } + + kdDebug(5855) << " Sub cells: " << maxSubCells << endl; + + // Write results to item to be placed + conflictItems.append( placeItem ); + placeItem->setSubCells( maxSubCells ); + + QPtrListIterator<KOrg::CellItem> it3( conflictItems ); + for( it3.toFirst(); it3.current(); ++it3 ) { + (*it3)->setSubCells( maxSubCells ); + } + // Todo: Adapt subCells of items conflicting with conflicting items + } else { + kdDebug(5855) << " no conflicts" << endl; + placeItem->setSubCell( 0 ); + placeItem->setSubCells( 1 ); + } + + return conflictItems; +} diff --git a/korganizer/printing/cellitem.h b/korganizer/printing/cellitem.h new file mode 100644 index 000000000..fa708147e --- /dev/null +++ b/korganizer/printing/cellitem.h @@ -0,0 +1,68 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KORG_CELLITEM_H +#define KORG_CELLITEM_H + +#include <qstring.h> +#include <qptrlist.h> + +#include <kdepimmacros.h> + +namespace KOrg { + +class KDE_EXPORT CellItem +{ + public: + CellItem() + : mSubCells( 0 ), mSubCell( -1 ) + { + } + + void setSubCells( int v ) { mSubCells = v; } + int subCells() const { return mSubCells; } + + void setSubCell( int v ) { mSubCell = v; } + int subCell() const { return mSubCell; } + + virtual bool overlaps( CellItem *other ) const = 0; + + virtual QString label() const; + + /** + Place item \arg placeItem into stripe containing items \arg cells in a + way that items don't overlap. + + \return Placed items + */ + static QPtrList<CellItem> placeItem( QPtrList<CellItem> cells, + CellItem *placeItem ); + + private: + int mSubCells; + int mSubCell; +}; + +} + +#endif diff --git a/korganizer/publishdialog.cpp b/korganizer/publishdialog.cpp new file mode 100644 index 000000000..a6d0881eb --- /dev/null +++ b/korganizer/publishdialog.cpp @@ -0,0 +1,168 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qlineedit.h> +#include <qpushbutton.h> +#include <kdebug.h> +#include <qlistview.h> + +#include <kglobal.h> +#include <klocale.h> +#ifndef KORG_NOKABC +#include <kabc/addresseedialog.h> +#endif +#include <libkcal/attendee.h> + +#include "koprefs.h" +#include "publishdialog.h" +#include "publishdialog_base.h" + +PublishDialog::PublishDialog( QWidget* parent, const char* name, + bool modal ) + : KDialogBase( parent, name, modal, + i18n("Select Addresses"), Ok|Cancel|Help, Ok, true ) +{ + mWidget = new PublishDialog_base( this, "PublishFreeBusy" ); + setMainWidget( mWidget ); + mWidget->mNameLineEdit->setEnabled( false ); + mWidget->mEmailLineEdit->setEnabled( false ); + connect( mWidget->mAddressListView, SIGNAL( selectionChanged(QListViewItem *) ), + SLOT(updateInput())); + connect( mWidget->mNew, SIGNAL( clicked() ), + SLOT( addItem() ) ); + connect( mWidget->mRemove, SIGNAL( clicked() ), + SLOT( removeItem() ) ); + connect( mWidget->mSelectAddressee, SIGNAL( clicked() ), + SLOT( openAddressbook() ) ); + connect( mWidget->mNameLineEdit, SIGNAL( textChanged(const QString&) ), + SLOT( updateItem() ) ); + connect( mWidget->mEmailLineEdit, SIGNAL( textChanged(const QString&) ), + SLOT( updateItem() ) ); +} + +PublishDialog::~PublishDialog() +{ +} + +void PublishDialog::addAttendee( Attendee *attendee ) +{ + mWidget->mNameLineEdit->setEnabled( true ); + mWidget->mEmailLineEdit->setEnabled( true ); + QListViewItem *item = new QListViewItem( mWidget->mAddressListView ); + item->setText( 0, attendee->name() ); + item->setText( 1, attendee->email() ); + mWidget->mAddressListView->insertItem( item ); +} + +QString PublishDialog::addresses() +{ + QString to = ""; + QListViewItem *item; + int i, count; + count = mWidget->mAddressListView->childCount(); + for ( i=0; i<count; i++ ) { + item = mWidget->mAddressListView->firstChild(); + mWidget->mAddressListView->takeItem( item ); + to += item->text( 1 ); + if ( i < count-1 ) { + to += ", "; + } + } + return to; +} + +void PublishDialog::addItem() +{ + mWidget->mNameLineEdit->setEnabled( true ); + mWidget->mEmailLineEdit->setEnabled( true ); + QListViewItem *item = new QListViewItem( mWidget->mAddressListView ); + mWidget->mAddressListView->insertItem( item ); + mWidget->mAddressListView->setSelected( item, true ); + mWidget->mNameLineEdit->setText( i18n("(EmptyName)") ); + mWidget->mEmailLineEdit->setText( i18n("(EmptyEmail)") ); +} + +void PublishDialog::removeItem() +{ + QListViewItem *item; + item = mWidget->mAddressListView->selectedItem(); + if (!item) return; + mWidget->mAddressListView->takeItem( item ); + item = mWidget->mAddressListView->selectedItem(); + if ( !item ) { + mWidget->mNameLineEdit->setText( "" ); + mWidget->mEmailLineEdit->setText( "" ); + mWidget->mNameLineEdit->setEnabled( false ); + mWidget->mEmailLineEdit->setEnabled( false ); + } + if ( mWidget->mAddressListView->childCount() == 0 ) { + mWidget->mNameLineEdit->setEnabled( false ); + mWidget->mEmailLineEdit->setEnabled( false ); + } +} + +void PublishDialog::openAddressbook() +{ +#ifndef KORG_NOKABC + KABC::Addressee::List addressList; + addressList = KABC::AddresseeDialog::getAddressees( this ); + //KABC::Addressee a = KABC::AddresseeDialog::getAddressee(this); + KABC::Addressee a = addressList.first(); + if ( !a.isEmpty() ) { + uint i; + for ( i=0; i<addressList.size(); i++ ) { + a = addressList[i]; + mWidget->mNameLineEdit->setEnabled( true ); + mWidget->mEmailLineEdit->setEnabled( true ); + QListViewItem *item = new QListViewItem( mWidget->mAddressListView ); + mWidget->mAddressListView->setSelected( item, true ); + mWidget->mNameLineEdit->setText( a.realName() ); + mWidget->mEmailLineEdit->setText( a.preferredEmail() ); + mWidget->mAddressListView->insertItem( item ); + } + } +#endif +} + +void PublishDialog::updateItem() +{ + QListViewItem *item; + item = mWidget->mAddressListView->selectedItem(); + if (!item) return; + item->setText( 0, mWidget->mNameLineEdit->text() ); + item->setText( 1, mWidget->mEmailLineEdit->text() ); +} + +void PublishDialog::updateInput() +{ + QListViewItem *item; + item = mWidget->mAddressListView->selectedItem(); + if (!item) return; + mWidget->mNameLineEdit->setEnabled( true ); + mWidget->mEmailLineEdit->setEnabled( true ); + QString mail = item->text( 1 ); + mWidget->mNameLineEdit->setText( item->text( 0 ) ); + mWidget->mEmailLineEdit->setText( mail ); +} + +#include "publishdialog.moc" diff --git a/korganizer/publishdialog.h b/korganizer/publishdialog.h new file mode 100644 index 000000000..cbe6fc809 --- /dev/null +++ b/korganizer/publishdialog.h @@ -0,0 +1,58 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef PUBLISHDIALOG_H +#define PUBLISHDIALOG_H + +#include <kdialogbase.h> +namespace KCal { +class Attendee; +} +using namespace KCal; + +class PublishDialog_base; + +class PublishDialog : public KDialogBase +{ + Q_OBJECT + public: + PublishDialog(QWidget* parent=0,const char* name=0, + bool modal=true ); + ~PublishDialog(); + + void addAttendee(Attendee *attendee); + QString addresses(); + + signals: + void numMessagesChanged(int); + + protected slots: + void addItem(); + void removeItem(); + void openAddressbook(); + void updateItem(); + void updateInput(); + protected: + PublishDialog_base *mWidget; +}; + +#endif // OUTGOINGDIALOG_H diff --git a/korganizer/publishdialog_base.ui b/korganizer/publishdialog_base.ui new file mode 100644 index 000000000..e6574be6b --- /dev/null +++ b/korganizer/publishdialog_base.ui @@ -0,0 +1,133 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>PublishDialog_base</class> +<widget class="QWidget"> + <property name="name"> + <cstring>PublishDialog_base</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>420</width> + <height>379</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QListView" row="0" column="0" rowspan="4" colspan="2"> + <column> + <property name="text"> + <string>Name</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Email</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>mAddressListView</cstring> + </property> + </widget> + <widget class="QLabel" row="4" column="0"> + <property name="name"> + <cstring>TextLabel1</cstring> + </property> + <property name="text"> + <string>Name:</string> + </property> + </widget> + <widget class="QLabel" row="5" column="0"> + <property name="name"> + <cstring>TextLabel2</cstring> + </property> + <property name="text"> + <string>Email:</string> + </property> + </widget> + <widget class="QLineEdit" row="5" column="1"> + <property name="name"> + <cstring>mEmailLineEdit</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QLineEdit" row="4" column="1"> + <property name="name"> + <cstring>mNameLineEdit</cstring> + </property> + </widget> + <widget class="QPushButton" row="0" column="2"> + <property name="name"> + <cstring>mNew</cstring> + </property> + <property name="text"> + <string>&New</string> + </property> + </widget> + <widget class="QPushButton" row="2" column="2"> + <property name="name"> + <cstring>mSelectAddressee</cstring> + </property> + <property name="text"> + <string>Select &Addressee...</string> + </property> + </widget> + <widget class="QPushButton" row="1" column="2"> + <property name="name"> + <cstring>mRemove</cstring> + </property> + <property name="text"> + <string>&Remove</string> + </property> + </widget> + <spacer row="3" column="2" rowspan="3" colspan="1"> + <property name="name"> + <cstring>spacer102</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>241</height> + </size> + </property> + </spacer> + </grid> +</widget> +<tabstops> + <tabstop>mAddressListView</tabstop> + <tabstop>mNameLineEdit</tabstop> + <tabstop>mEmailLineEdit</tabstop> + <tabstop>mNew</tabstop> + <tabstop>mRemove</tabstop> + <tabstop>mSelectAddressee</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/korganizer/resourceview.cpp b/korganizer/resourceview.cpp new file mode 100644 index 000000000..53b8e6495 --- /dev/null +++ b/korganizer/resourceview.cpp @@ -0,0 +1,721 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2003,2004 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "resourceview.h" + +#include <kcolordialog.h> +#include <kdialog.h> +#include <klistview.h> +#include <klocale.h> +#include <kdebug.h> +#include <kglobal.h> +#include <kmessagebox.h> +#include <kinputdialog.h> +#include <kiconloader.h> +#include <kresources/resource.h> +#include <kresources/configdialog.h> +#include <libkcal/calendarresources.h> + +#include <qhbox.h> +#include <qheader.h> +#include <qlayout.h> +#include <qlabel.h> +#include <qpainter.h> +#include <qpushbutton.h> +#include <qpopupmenu.h> +#include <qtooltip.h> +#include <qwhatsthis.h> + +#include "koprefs.h" + +using namespace KCal; + +ResourceViewFactory::ResourceViewFactory( KCal::CalendarResources *calendar, + CalendarView *view ) + : mCalendar( calendar ), mView( view ), mResourceView( 0 ) +{ +} + +CalendarViewExtension *ResourceViewFactory::create( QWidget *parent ) +{ + mResourceView = new ResourceView( mCalendar, parent ); + + QObject::connect( mResourceView, SIGNAL( resourcesChanged() ), + mView, SLOT( resourcesChanged() ) ); + QObject::connect( mResourceView, SIGNAL( resourcesChanged() ), + mView, SLOT( updateCategories() ) ); + + QObject::connect( mCalendar, + SIGNAL( signalResourceAdded( ResourceCalendar * ) ), + mResourceView, + SLOT( addResourceItem( ResourceCalendar * ) ) ); + QObject::connect( mCalendar, + SIGNAL( signalResourceModified( ResourceCalendar * ) ), + mResourceView, + SLOT( updateResourceItem( ResourceCalendar * ) ) ); + QObject::connect( mCalendar, SIGNAL( signalResourceAdded( ResourceCalendar * ) ), + mView, SLOT( updateCategories() ) ); + QObject::connect( mCalendar, SIGNAL( signalResourceModified( ResourceCalendar * ) ), + mView, SLOT( updateCategories() ) ); + + return mResourceView; +} + +ResourceView *ResourceViewFactory::resourceView() const +{ + return mResourceView; +} + +ResourceItem::ResourceItem( ResourceCalendar *resource, ResourceView *view, + KListView *parent ) + : QCheckListItem( parent, resource->resourceName(), CheckBox ), + mResource( resource ), mView( view ), mBlockStateChange( false ), + mIsSubresource( false ), mResourceIdentifier( QString::null ), + mSubItemsCreated( false ), mIsStandardResource( false ) +{ + mResourceColor = QColor(); + setGuiState(); + + if ( mResource->isActive() ) { + createSubresourceItems(); + } +} + +void ResourceItem::createSubresourceItems() +{ + const QStringList subresources = mResource->subresources(); + if ( !subresources.isEmpty() ) { + setOpen( true ); + setExpandable( true ); + // This resource has subresources + QStringList::ConstIterator it; + for ( it=subresources.begin(); it!=subresources.end(); ++it ) { + ResourceItem *item = new ResourceItem( mResource, *it, mResource->labelForSubresource( *it ), + mView, this ); + QColor resourceColor = *KOPrefs::instance()->resourceColor( *it ); + item->setResourceColor( resourceColor ); + item->update(); + } + } + mSubItemsCreated = true; +} + +ResourceItem::ResourceItem( KCal::ResourceCalendar *resource, + const QString& sub, const QString& label, + ResourceView *view, ResourceItem* parent ) + + : QCheckListItem( parent, label, CheckBox ), mResource( resource ), + mView( view ), mBlockStateChange( false ), mIsSubresource( true ), + mSubItemsCreated( false ), mIsStandardResource( false ) +{ + mResourceColor = QColor(); + mResourceIdentifier = sub; + setGuiState(); +} + +void ResourceItem::setGuiState() +{ + mBlockStateChange = true; + if ( mIsSubresource ) + setOn( mResource->subresourceActive( mResourceIdentifier ) ); + else + setOn( mResource->isActive() ); + mBlockStateChange = false; +} + +void ResourceItem::stateChange( bool active ) +{ + if ( mBlockStateChange ) return; + + if ( mIsSubresource ) { + mResource->setSubresourceActive( mResourceIdentifier, active ); + } else { + if ( active ) { + if ( mResource->load() ) { + mResource->setActive( true ); + if ( !mSubItemsCreated ) + createSubresourceItems(); + } + } else { + if ( mResource->save() ) mResource->setActive( false ); + mView->requestClose( mResource ); + } + + setOpen( mResource->isActive() && childCount() > 0 ); + + setGuiState(); + } + + mView->emitResourcesChanged(); +} + +void ResourceItem::update() +{ + setGuiState(); +} + +void ResourceItem::setResourceColor(QColor& color) +{ + if ( color.isValid() ) { + if ( mResourceColor != color ) { + QPixmap px(height()-4,height()-4); + mResourceColor = color; + px.fill(color); + setPixmap(0,px); + } + } else { + mResourceColor = color ; + setPixmap(0,0); + } +} + +void ResourceItem::setStandardResource( bool std ) +{ + if ( mIsStandardResource != std ) { + mIsStandardResource = std; + repaint(); + } +} + +void ResourceItem::paintCell(QPainter *p, const QColorGroup &cg, + int column, int width, int alignment) +{ + QFont oldFont = p->font(); + QFont newFont = oldFont; + newFont.setBold( mIsStandardResource && !mIsSubresource ); + p->setFont( newFont ); + QCheckListItem::paintCell( p, cg, column, width, alignment ); + p->setFont( oldFont ); +/* QColorGroup _cg = cg; + if(!mResource) return; + _cg.setColor(QColorGroup::Base, getTextColor(mResourceColor));*/ +} + + +ResourceView::ResourceView( KCal::CalendarResources *calendar, + QWidget *parent, const char *name ) + : CalendarViewExtension( parent, name ), mCalendar( calendar ) +{ + QBoxLayout *topLayout = new QVBoxLayout( this, 0, KDialog::spacingHint() ); + + QHBoxLayout *buttonBox = new QHBoxLayout(); + buttonBox->setSpacing( KDialog::spacingHint() ); + topLayout->addLayout( buttonBox ); + + QLabel *calLabel = new QLabel( i18n( "Calendar" ), this ); + buttonBox->addWidget( calLabel ); + buttonBox->addStretch( 1 ); + + mAddButton = new QPushButton( this, "add" ); + mAddButton->setIconSet( SmallIconSet( "add" ) ); + buttonBox->addWidget( mAddButton ); + QToolTip::add( mAddButton, i18n( "Add calendar" ) ); + QWhatsThis::add( mAddButton, + i18n( "<qt><p>Press this button to add a resource to " + "KOrganizer.</p>" + "<p>Events, journal entries and to-dos are retrieved " + "and stored on resources. Available " + "resources include groupware servers, local files, " + "journal entries as blogs on a server, etc... </p>" + "<p>If you have more than one active resource, " + "when creating incidents you will either automatically " + "use the default resource or be prompted " + "to select the resource to use.</p></qt>" ) ); + mEditButton = new QPushButton( this, "edit" ); + mEditButton->setIconSet( SmallIconSet( "edit" ) ); + buttonBox->addWidget( mEditButton ); + QToolTip::add( mEditButton, i18n( "Edit calendar settings" ) ); + QWhatsThis::add( mEditButton, + i18n( "Press this button to edit the resource currently " + "selected on the KOrganizer resources list above." ) ); + mDeleteButton = new QPushButton( this, "del" ); + mDeleteButton->setIconSet( SmallIconSet( "remove" ) ); + buttonBox->addWidget( mDeleteButton ); + QToolTip::add( mDeleteButton, i18n( "Remove calendar" ) ); + QWhatsThis::add( mDeleteButton, + i18n( "Press this button to delete the resource currently " + "selected on the KOrganizer resources list above." ) ); + mDeleteButton->setDisabled( true ); + mEditButton->setDisabled( true ); + + mListView = new KListView( this ); + mListView->header()->hide(); + QWhatsThis::add( mListView, + i18n( "<qt><p>Select on this list the active KOrganizer " + "resources. Check the resource box to make it " + "active. Press the \"Add...\" button below to add new " + "resources to the list.</p>" + "<p>Events, journal entries and to-dos are retrieved " + "and stored on resources. Available " + "resources include groupware servers, local files, " + "journal entries as blogs on a server, etc...</p>" + "<p>If you have more than one active resource, " + "when creating incidents you will either automatically " + "use the default resource or be prompted " + "to select the resource to use.</p></qt>" ) ); + mListView->addColumn( i18n("Calendar") ); + mListView->setResizeMode( QListView::LastColumn ); + topLayout->addWidget( mListView ); + + connect( mListView, SIGNAL( clicked( QListViewItem * ) ), + SLOT( currentChanged( QListViewItem * ) ) ); + connect( mAddButton, SIGNAL( clicked() ), SLOT( addResource() ) ); + connect( mDeleteButton, SIGNAL( clicked() ), SLOT( removeResource() ) ); + connect( mEditButton, SIGNAL( clicked() ), SLOT( editResource() ) ); + connect( mListView, SIGNAL( doubleClicked ( QListViewItem *, const QPoint &, + int ) ), + SLOT( editResource() ) ); + connect( mListView, SIGNAL( contextMenuRequested ( QListViewItem *, + const QPoint &, int ) ), + SLOT( contextMenuRequested( QListViewItem *, const QPoint &, + int ) ) ); + + updateView(); +} + +ResourceView::~ResourceView() +{ +} + +void ResourceView::updateView() +{ + mListView->clear(); + + KCal::CalendarResourceManager *manager = mCalendar->resourceManager(); + + KCal::CalendarResourceManager::Iterator it; + for( it = manager->begin(); it != manager->end(); ++it ) { + addResourceItem( *it ); + } +} + +void ResourceView::emitResourcesChanged() +{ + mCalendar->resourceManager()->writeConfig(); + emit resourcesChanged(); +} + +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 QString folderName = KInputDialog::getText( i18n( "Add Subresource" ), + i18n( "Please enter a name for the new subresource" ), QString::null, + &ok, this ); + if ( !ok ) + return; + const QString parentId = i->isSubresource() ? i->resourceIdentifier() : QString:: null; + if ( !i->resource()->addSubresource( folderName, parentId ) ) { + KMessageBox::error( this, i18n("<qt>Unable to create subresource <b>%1</b>.</qt>") + .arg( folderName ) ); + } + return; + } + + QStringList types = manager->resourceTypeNames(); + QStringList descs = manager->resourceTypeDescriptions(); + QString desc = KInputDialog::getItem( i18n( "Resource Configuration" ), + i18n( "Please select type of the new resource:" ), descs, 0, false, &ok, + this ); + if ( !ok ) + return; + + QString 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 ) ); + return; + } + + resource->setResourceName( i18n("%1 resource").arg( type ) ); + + KRES::ConfigDialog *dlg = new KRES::ConfigDialog( this, QString("calendar"), resource, + "KRES::ConfigDialog" ); + + bool success = true; + if ( !dlg || !dlg->exec() ) + success = false; + + if ( success ) { + resource->setTimeZoneId( KOPrefs::instance()->mTimeZoneId ); + 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 ) ); + success = false; + } + } + + if ( success ) { + manager->add( resource ); + // we have to call resourceAdded manually, because for in-process changes + // the dcop signals are not connected, so the resource's signals would not + // be connected otherwise + mCalendar->resourceAdded( resource ); + } + + if ( !success ) + delete resource; + + delete dlg; + + //### maybe only do this if ( success ) + emitResourcesChanged(); +} + +void ResourceView::addResourceItem( ResourceCalendar *resource ) +{ + + ResourceItem *item=new ResourceItem( resource, this, mListView ); + + // assign a color, but only if this is a resource that actually + // hold items at top level + if ( !resource->canHaveSubresources() || resource->subresources().isEmpty() ) { + QColor resourceColor = *KOPrefs::instance()->resourceColor(resource->identifier()); + item->setResourceColor(resourceColor); + item->update(); + } + + connect( resource, SIGNAL( signalSubresourceAdded( ResourceCalendar *, + const QString &, + const QString &, + const QString & ) ), + SLOT( slotSubresourceAdded( ResourceCalendar *, const QString &, + const QString &, const QString & ) ) ); + + connect( resource, SIGNAL( signalSubresourceRemoved( ResourceCalendar *, + const QString &, + const QString & ) ), + SLOT( slotSubresourceRemoved( ResourceCalendar *, const QString &, + const QString & ) ) ); + + connect( resource, SIGNAL( resourceSaved( ResourceCalendar * ) ), + SLOT( closeResource( ResourceCalendar * ) ) ); + + updateResourceList(); + emit resourcesChanged(); +} + +// Add a new entry +void ResourceView::slotSubresourceAdded( ResourceCalendar *calendar, + const QString& /*type*/, + const QString& resource, + const QString& label) +{ + QListViewItem *i = mListView->findItem( calendar->resourceName(), 0 ); + if ( !i ) + // Not found + return; + + if ( findItemByIdentifier( resource ) ) return; + + ResourceItem *item = static_cast<ResourceItem *>( i ); + ResourceItem *newItem = new ResourceItem( calendar, resource, label, this, item ); + QColor resourceColor = *KOPrefs::instance()->resourceColor( resource ); + newItem->setResourceColor( resourceColor ); +} + +// Remove an entry +void ResourceView::slotSubresourceRemoved( ResourceCalendar * /*calendar*/, + const QString &/*type*/, + const QString &resource ) +{ + delete findItemByIdentifier( resource ); + emit resourcesChanged(); +} + +void ResourceView::closeResource( ResourceCalendar *r ) +{ + if ( mResourcesToClose.find( r ) >= 0 ) { + r->close(); + mResourcesToClose.remove( r ); + } +} + +void ResourceView::updateResourceItem( ResourceCalendar *resource ) +{ + ResourceItem *item = findItem( resource ); + if ( item ) { + item->update(); + } +} + +ResourceItem *ResourceView::currentItem() +{ + QListViewItem *item = mListView->currentItem(); + ResourceItem *rItem = static_cast<ResourceItem *>( item ); + return rItem; +} + +void ResourceView::removeResource() +{ + ResourceItem *item = currentItem(); + if ( !item ) return; + + const QString 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." ) ); + 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() ) ); + return; + } else { + mCalendar->resourceManager()->remove( item->resource() ); + } + mListView->takeItem( item ); + delete item; + + updateResourceList(); + emit resourcesChanged(); +} + +void ResourceView::editResource() +{ + ResourceItem *item = currentItem(); + if (!item) return; + ResourceCalendar *resource = item->resource(); + + KRES::ConfigDialog dlg( this, QString("calendar"), resource, + "KRES::ConfigDialog" ); + + if ( dlg.exec() ) { + item->setText( 0, resource->resourceName() ); + + mCalendar->resourceManager()->change( resource ); + } + emitResourcesChanged(); +} + +void ResourceView::currentChanged( QListViewItem *item ) +{ + ResourceItem *i = currentItem(); + if ( !item || i->isSubresource() ) { + mDeleteButton->setEnabled( false ); + mEditButton->setEnabled( false ); + } else { + mDeleteButton->setEnabled( true ); + mEditButton->setEnabled( true ); + } +} + +ResourceItem *ResourceView::findItem( ResourceCalendar *r ) +{ + QListViewItem *item; + ResourceItem *i = 0; + for( item = mListView->firstChild(); item; item = item->nextSibling() ) { + i = static_cast<ResourceItem *>( item ); + if ( i->resource() == r ) break; + } + return i; +} + +ResourceItem *ResourceView::findItemByIdentifier( const QString& id ) +{ + QListViewItem *item; + ResourceItem *i = 0; + for( item = mListView->firstChild(); item; item = item->itemBelow() ) { + i = static_cast<ResourceItem *>( item ); + if ( i->resourceIdentifier() == id ) + return i; + } + return 0; +} + + +void ResourceView::contextMenuRequested ( QListViewItem *i, + const QPoint &pos, int ) +{ + KCal::CalendarResourceManager *manager = mCalendar->resourceManager(); + ResourceItem *item = static_cast<ResourceItem *>( i ); + + QPopupMenu *menu = new QPopupMenu( this ); + connect( menu, SIGNAL( aboutToHide() ), menu, SLOT( deleteLater() ) ); + if ( item ) { + int reloadId = menu->insertItem( i18n("Re&load"), this, + SLOT( reloadResource() ) ); + menu->setItemEnabled( reloadId, item->resource()->isActive() ); + int saveId = menu->insertItem( i18n("&Save"), this, + SLOT( saveResource() ) ); + menu->setItemEnabled( saveId, item->resource()->isActive() ); + menu->insertSeparator(); + + menu->insertItem( i18n("Show &Info"), this, SLOT( showInfo() ) ); + //FIXME: This is better on the resource dialog + if ( KOPrefs::instance()->agendaViewColors() != KOPrefs::CategoryOnly ) { + QPopupMenu *assignMenu= new QPopupMenu( menu ); + assignMenu->insertItem( i18n( "&Assign Color" ), this, SLOT( assignColor() ) ); + if ( item->resourceColor().isValid() ) + assignMenu->insertItem( i18n( "&Disable Color" ), this, SLOT( disableColor() ) ); + menu->insertItem( i18n( "Resources Colors" ), assignMenu ); + } + + menu->insertItem( i18n("&Edit..."), this, SLOT( editResource() ) ); + menu->insertItem( i18n("&Remove"), this, SLOT( removeResource() ) ); + if ( item->resource() != manager->standardResource() ) { + menu->insertSeparator(); + menu->insertItem( i18n("Use as &Default Calendar"), this, + SLOT( setStandard() ) ); + } + + menu->insertSeparator(); + } + menu->insertItem( i18n("&Add..."), this, SLOT( addResource() ) ); + + menu->popup( pos ); +} + +void ResourceView::assignColor() +{ + ResourceItem *item = currentItem(); + if ( !item ) + return; + // A color without initialized is a color invalid + QColor myColor; + KCal::ResourceCalendar *cal = item->resource(); + + QString identifier = cal->identifier(); + if ( item->isSubresource() ) + identifier = item->resourceIdentifier(); + + QColor defaultColor =*KOPrefs::instance()->resourceColor( identifier ); + + int result = KColorDialog::getColor( myColor,defaultColor); + + if ( result == KColorDialog::Accepted ) { + KOPrefs::instance()->setResourceColor( identifier, myColor ); + item->setResourceColor( myColor ); + item->update(); + emitResourcesChanged(); + } +} + +void ResourceView::disableColor() +{ + ResourceItem *item = currentItem(); + if ( !item ) + return; + QColor colorInvalid; + KCal::ResourceCalendar *cal = item->resource(); + QString identifier = cal->identifier(); + if ( item->isSubresource() ) + identifier = item->resourceIdentifier(); + KOPrefs::instance()->setResourceColor( identifier, colorInvalid ); + item->setResourceColor( colorInvalid ); + item->update(); + emitResourcesChanged(); +} +void ResourceView::showInfo() +{ + ResourceItem *item = currentItem(); + if ( !item ) return; + + QString txt = "<qt>" + item->resource()->infoText() + "</qt>"; + KMessageBox::information( this, txt ); +} + +void ResourceView::reloadResource() +{ + ResourceItem *item = currentItem(); + if ( !item ) return; + + ResourceCalendar *r = item->resource(); + r->load(); +} + +void ResourceView::saveResource() +{ + ResourceItem *item = currentItem(); + if ( !item ) return; + + ResourceCalendar *r = item->resource(); + r->save(); +} + +void ResourceView::setStandard() +{ + ResourceItem *item = currentItem(); + if ( !item ) return; + + ResourceCalendar *r = item->resource(); + KCal::CalendarResourceManager *manager = mCalendar->resourceManager(); + manager->setStandardResource( r ); + updateResourceList(); +} + +void ResourceView::updateResourceList() +{ + QListViewItemIterator it( mListView ); + ResourceCalendar* stdRes = mCalendar->resourceManager()->standardResource(); + while ( it.current() ) { + ResourceItem *item = static_cast<ResourceItem *>( it.current() ); + item->setStandardResource( item->resource() == stdRes ); + ++it; + } +} + +void ResourceView::showButtons( bool visible ) +{ + if ( visible ) { + mAddButton->show(); + mDeleteButton->show(); + mEditButton->show(); + } else { + mAddButton->hide(); + mDeleteButton->hide(); + mEditButton->hide(); + } +} + +void ResourceView::requestClose( ResourceCalendar *r ) +{ + mResourcesToClose.append( r ); +} + +#include "resourceview.moc" diff --git a/korganizer/resourceview.h b/korganizer/resourceview.h new file mode 100644 index 000000000..c8c6a6c66 --- /dev/null +++ b/korganizer/resourceview.h @@ -0,0 +1,162 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2003,2004 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KORG_RESOURCEVIEW_H +#define KORG_RESOURCEVIEW_H + +#include "calendarview.h" + +#include <libkcal/resourcecalendar.h> +#include <qlistview.h> + +namespace KCal { +class CalendarResources; +} +using namespace KCal; +class KListView; +class ResourceView; +class QPushButton; + +class ResourceViewFactory : public CalendarViewExtension::Factory +{ + public: + ResourceViewFactory( KCal::CalendarResources *calendar, + CalendarView *view ); + + CalendarViewExtension *create( QWidget * ); + + ResourceView *resourceView() const; + + private: + KCal::CalendarResources *mCalendar; + CalendarView *mView; + ResourceView *mResourceView; +}; + + +class ResourceItem : public QCheckListItem +{ + public: + ResourceItem( KCal::ResourceCalendar *resource, ResourceView *view, + KListView *parent ); + ResourceItem( KCal::ResourceCalendar *resource, const QString& sub, + const QString& label, ResourceView *view, + ResourceItem* parent ); + + KCal::ResourceCalendar *resource() { return mResource; } + const QString& resourceIdentifier() { return mResourceIdentifier; } + bool isSubresource() const { return mIsSubresource; } + void createSubresourceItems(); + void setStandardResource( bool std ); + + void update(); + + virtual void paintCell(QPainter *p, const QColorGroup &cg, + int column, int width, int alignment); + + void setResourceColor(QColor& color); + QColor &resourceColor() {return mResourceColor;} + protected: + void stateChange( bool active ); + + void setGuiState(); + QColor mResourceColor; + + private: + KCal::ResourceCalendar *mResource; + ResourceView *mView; + bool mBlockStateChange; + bool mIsSubresource; + QString mResourceIdentifier; + bool mSubItemsCreated; + bool mIsStandardResource; +}; + +/** + This class provides a view of calendar resources. +*/ +class ResourceView : public CalendarViewExtension +{ + Q_OBJECT + public: + ResourceView( KCal::CalendarResources *calendar, QWidget *parent = 0, + const char *name = 0 ); + ~ResourceView(); + + KCal::CalendarResources *calendar() const { return mCalendar; } + + void updateView(); + + void emitResourcesChanged(); + + void requestClose( ResourceCalendar * ); + + void showButtons( bool visible ); + + public slots: + void addResourceItem( ResourceCalendar * ); + void updateResourceItem( ResourceCalendar * ); + + signals: + void resourcesChanged(); + + protected: + ResourceItem *findItem( ResourceCalendar * ); + ResourceItem *findItemByIdentifier( const QString& id ); + ResourceItem *currentItem(); + + protected slots: + void addResource(); + void removeResource(); + void editResource(); + void currentChanged( QListViewItem* ); + void slotSubresourceAdded( ResourceCalendar *, const QString &, + const QString &resource,const QString& label ); + + void slotSubresourceRemoved( ResourceCalendar *, const QString &, + const QString & ); + void closeResource( ResourceCalendar * ); + + void contextMenuRequested ( QListViewItem *i, const QPoint &pos, int ); + + void assignColor(); + void disableColor(); + void showInfo(); + + void reloadResource(); + void saveResource(); + + void setStandard(); + void updateResourceList(); + + private: + KListView *mListView; + KCal::CalendarResources *mCalendar; + QPushButton *mAddButton; + QPushButton *mDeleteButton; + QPushButton *mEditButton; + QPtrList<ResourceCalendar> mResourcesToClose; +}; + +#endif diff --git a/korganizer/searchdialog.cpp b/korganizer/searchdialog.cpp new file mode 100644 index 000000000..082a6eacc --- /dev/null +++ b/korganizer/searchdialog.cpp @@ -0,0 +1,261 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1998 Preston Brown <pbrown@kde.org> + Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qlayout.h> +#include <qcheckbox.h> +#include <qgroupbox.h> +#include <qhbuttongroup.h> +#include <qlabel.h> +#include <qlineedit.h> + +#include <klocale.h> +#include <kmessagebox.h> + +#include <libkcal/calendar.h> + +#include <libkdepim/kdateedit.h> + +#include "koglobals.h" +#include "koprefs.h" +#include "kolistview.h" + +#include "searchdialog.h" +#include "searchdialog.moc" + +SearchDialog::SearchDialog(Calendar *calendar,QWidget *parent) + : KDialogBase(Plain,i18n("Find Events"),User1|Close,User1,parent,0,false,false, + KGuiItem( i18n("&Find"), "find") ) +{ + mCalendar = calendar; + + QFrame *topFrame = plainPage(); + QVBoxLayout *layout = new QVBoxLayout(topFrame,0,spacingHint()); + + // Search expression + QHBoxLayout *subLayout = new QHBoxLayout(); + layout->addLayout(subLayout); + + searchEdit = new QLineEdit( "*", topFrame ); // Find all events by default + searchLabel = new QLabel( searchEdit, i18n("&Search for:"), topFrame ); + subLayout->addWidget( searchLabel ); + subLayout->addWidget( searchEdit ); + searchEdit->setFocus(); + connect( searchEdit, SIGNAL( textChanged( const QString & ) ), + this, SLOT( searchTextChanged( const QString & ) ) ); + + + QHButtonGroup *itemsGroup = new QHButtonGroup( i18n("Search For"), topFrame ); + layout->addWidget( itemsGroup ); + mEventsCheck = new QCheckBox( i18n("&Events"), itemsGroup ); + mTodosCheck = new QCheckBox( i18n("To-&dos"), itemsGroup ); + mJournalsCheck = new QCheckBox( i18n("&Journal entries"), itemsGroup ); + mEventsCheck->setChecked( true ); + mTodosCheck->setChecked( true ); + + // Date range + QGroupBox *rangeGroup = new QGroupBox( 1, Horizontal, i18n( "Date Range" ), + topFrame ); + layout->addWidget( rangeGroup ); + + QWidget *rangeWidget = new QWidget( rangeGroup ); + QHBoxLayout *rangeLayout = new QHBoxLayout( rangeWidget, 0, spacingHint() ); + + mStartDate = new KDateEdit( rangeWidget ); + rangeLayout->addWidget( new QLabel( mStartDate, i18n("Fr&om:"), rangeWidget ) ); + rangeLayout->addWidget( mStartDate ); + + mEndDate = new KDateEdit( rangeWidget ); + rangeLayout->addWidget( new QLabel( mEndDate, i18n("&To:"), rangeWidget ) ); + mEndDate->setDate( QDate::currentDate().addDays( 365 ) ); + rangeLayout->addWidget( mEndDate ); + + mInclusiveCheck = new QCheckBox( i18n("E&vents have to be completely included"), + rangeGroup ); + mInclusiveCheck->setChecked( false ); + mIncludeUndatedTodos = new QCheckBox( i18n("Include to-dos &without due date"), rangeGroup ); + mIncludeUndatedTodos->setChecked( true ); + + // Subjects to search + QHButtonGroup *subjectGroup = new QHButtonGroup( i18n("Search In"), topFrame ); + layout->addWidget(subjectGroup); + + mSummaryCheck = new QCheckBox( i18n("Su&mmaries"), subjectGroup ); + mSummaryCheck->setChecked( true ); + mDescriptionCheck = new QCheckBox( i18n("Desc&riptions"), subjectGroup ); + mCategoryCheck = new QCheckBox( i18n("Cate&gories"), subjectGroup ); + + + // Results list view + listView = new KOListView( mCalendar, topFrame ); + listView->showDates(); + layout->addWidget( listView ); + + if ( KOPrefs::instance()->mCompactDialogs ) { + KOGlobals::fitDialogToScreen( this, true ); + } + + connect( this,SIGNAL(user1Clicked()),SLOT(doSearch())); + + // Propagate edit and delete event signals from event list view + connect( listView, SIGNAL( showIncidenceSignal( Incidence * ) ), + SIGNAL( showIncidenceSignal( Incidence *) ) ); + connect( listView, SIGNAL( editIncidenceSignal( Incidence * ) ), + SIGNAL( editIncidenceSignal( Incidence * ) ) ); + connect( listView, SIGNAL( deleteIncidenceSignal( Incidence * ) ), + SIGNAL( deleteIncidenceSignal( Incidence * ) ) ); +} + +SearchDialog::~SearchDialog() +{ +} + +void SearchDialog::searchTextChanged( const QString &_text ) +{ + enableButton( KDialogBase::User1, !_text.isEmpty() ); +} + +void SearchDialog::doSearch() +{ + QRegExp re; + + re.setWildcard( true ); // most people understand these better. + re.setCaseSensitive( false ); + re.setPattern( searchEdit->text() ); + if ( !re.isValid() ) { + KMessageBox::sorry( this, + i18n("Invalid search expression, cannot perform " + "the search. Please enter a search expression " + "using the wildcard characters '*' and '?' " + "where needed." ) ); + return; + } + + search( re ); + + listView->showIncidences( mMatchedEvents ); + + if ( mMatchedEvents.count() == 0 ) { + KMessageBox::information( this, + i18n("No events were found matching your search expression."), + "NoSearchResults" ); + } +} + +void SearchDialog::updateView() +{ + QRegExp re; + re.setWildcard( true ); // most people understand these better. + re.setCaseSensitive( false ); + re.setPattern( searchEdit->text() ); + if ( re.isValid() ) { + search( re ); + } else { + mMatchedEvents.clear(); + } + + listView->showIncidences( mMatchedEvents ); +} + +void SearchDialog::search( const QRegExp &re ) +{ + QDate startDt = mStartDate->date(); + QDate endDt = mEndDate->date(); + + Event::List events; + if (mEventsCheck->isChecked()) { + events = mCalendar->events( startDt, endDt, mInclusiveCheck->isChecked() ); + } + Todo::List todos; + if (mTodosCheck->isChecked()) { + if ( mIncludeUndatedTodos->isChecked() ) { + Todo::List alltodos = mCalendar->todos(); + Todo::List::iterator it; + Todo *todo; + for (it=alltodos.begin(); it!=alltodos.end(); ++it) { + todo = *it; + if ( (!todo->hasStartDate() && !todo->hasDueDate() ) || // undated + ( todo->hasStartDate() && (todo->dtStart()>=startDt) && (todo->dtStart()<=endDt) ) || // start dt in range + ( todo->hasDueDate() && (todo->dtDue().date()>=startDt) && (todo->dtDue()<=endDt) ) || // due dt in range + ( todo->hasCompletedDate() && (todo->completed().date()>=startDt) && (todo->completed()<=endDt) ) ) { // completed dt in range + todos.append( todo ); + } + } + } else { + QDate dt = startDt; + while ( dt <= endDt ) { + todos += mCalendar->todos( dt ); + dt = dt.addDays( 1 ); + } + } + } + + Journal::List journals; + if (mJournalsCheck->isChecked()) { + QDate dt = startDt; + while ( dt <= endDt ) { + journals += mCalendar->journals( dt ); + dt = dt.addDays( 1 ); + } + } + + Incidence::List allIncidences = Calendar::mergeIncidenceList( events, todos, journals ); + + mMatchedEvents.clear(); + Incidence::List::ConstIterator it; + for( it = allIncidences.begin(); it != allIncidences.end(); ++it ) { + Incidence *ev = *it; + if ( mSummaryCheck->isChecked() ) { +#if QT_VERSION >= 300 + if ( re.search( ev->summary() ) != -1 ) { +#else + if ( re.match( ev->summary() ) != -1 ) { +#endif + mMatchedEvents.append( ev ); + continue; + } + } + if ( mDescriptionCheck->isChecked() ) { +#if QT_VERSION >= 300 + if ( re.search( ev->description() ) != -1 ) { +#else + if ( re.match( ev->description() ) != -1 ) { +#endif + mMatchedEvents.append( ev ); + continue; + } + } + if ( mCategoryCheck->isChecked() ) { +#if QT_VERSION >= 300 + if ( re.search( ev->categoriesStr() ) != -1 ) { +#else + if ( re.match( ev->categoriesStr() ) != -1 ) { +#endif + mMatchedEvents.append( ev ); + continue; + } + } + } +} diff --git a/korganizer/searchdialog.h b/korganizer/searchdialog.h new file mode 100644 index 000000000..3876ba212 --- /dev/null +++ b/korganizer/searchdialog.h @@ -0,0 +1,93 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1998 Preston Brown <pbrown@kde.org> + Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef SEARCHDIALOG_H +#define SEARCHDIALOG_H + +#include <qregexp.h> + +#include <kdialogbase.h> + +#include <libkcal/incidence.h> + +namespace KCal { +class Calendar; +} +class KDateEdit; +class QCheckBox; +class QLineEdit; +class QLabel; +class KOListView; + +using namespace KCal; + +class SearchDialog : public KDialogBase +{ + Q_OBJECT + public: + SearchDialog(Calendar *calendar,QWidget *parent=0); + virtual ~SearchDialog(); + + void updateView(); + + public slots: + void changeIncidenceDisplay(Incidence *, int) { updateView(); } + + protected slots: + void doSearch(); + void searchTextChanged( const QString &_text ); + + signals: + void showIncidenceSignal(Incidence *); + void editIncidenceSignal(Incidence *); + void deleteIncidenceSignal(Incidence *); + + private: + void search(const QRegExp &); + + Calendar *mCalendar; + + Incidence::List mMatchedEvents; + + QLabel *searchLabel; + QLineEdit *searchEdit; + KOListView *listView; + + QCheckBox *mEventsCheck; + QCheckBox *mTodosCheck; + QCheckBox *mJournalsCheck; + + KDateEdit *mStartDate; + KDateEdit *mEndDate; + + QCheckBox *mInclusiveCheck; + QCheckBox *mIncludeUndatedTodos; + + QCheckBox *mSummaryCheck; + QCheckBox *mDescriptionCheck; + QCheckBox *mCategoryCheck; +}; + +#endif diff --git a/korganizer/sounds/Makefile.am b/korganizer/sounds/Makefile.am new file mode 100644 index 000000000..8fa73c026 --- /dev/null +++ b/korganizer/sounds/Makefile.am @@ -0,0 +1,7 @@ + +soundsdir = $(kde_datadir)/korganizer/sounds + +sounds_DATA = alert.wav icemag.wav lightmag.wav onscreen.wav \ + spinout.wav + + diff --git a/korganizer/sounds/alert.wav b/korganizer/sounds/alert.wav Binary files differnew file mode 100644 index 000000000..b13c1c62d --- /dev/null +++ b/korganizer/sounds/alert.wav diff --git a/korganizer/sounds/icemag.wav b/korganizer/sounds/icemag.wav Binary files differnew file mode 100644 index 000000000..48f199fb5 --- /dev/null +++ b/korganizer/sounds/icemag.wav diff --git a/korganizer/sounds/lightmag.wav b/korganizer/sounds/lightmag.wav Binary files differnew file mode 100644 index 000000000..c1ca482d9 --- /dev/null +++ b/korganizer/sounds/lightmag.wav diff --git a/korganizer/sounds/onscreen.wav b/korganizer/sounds/onscreen.wav Binary files differnew file mode 100644 index 000000000..cf165cb48 --- /dev/null +++ b/korganizer/sounds/onscreen.wav diff --git a/korganizer/sounds/spinout.wav b/korganizer/sounds/spinout.wav Binary files differnew file mode 100644 index 000000000..3923ff097 --- /dev/null +++ b/korganizer/sounds/spinout.wav diff --git a/korganizer/statusdialog.cpp b/korganizer/statusdialog.cpp new file mode 100644 index 000000000..8422957ba --- /dev/null +++ b/korganizer/statusdialog.cpp @@ -0,0 +1,74 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include <qlabel.h> +#include <qstringlist.h> +#include <qlayout.h> +#include <qcombobox.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kpushbutton.h> +#include <kstdguiitem.h> + +#include "statusdialog.h" +#include "statusdialog.moc" + +StatusDialog::StatusDialog(QWidget* parent, const char* name) : + KDialog(parent,name,true) +{ + setCaption(i18n("Set Your Status")); + + QBoxLayout *topLayout = new QVBoxLayout( this ); + topLayout->setSpacing( spacingHint() ); + topLayout->setMargin( marginHint() ); + + QBoxLayout *statusLayout = new QHBoxLayout( topLayout ); + + QLabel *text = new QLabel(i18n("Set your status"),this); + statusLayout->addWidget( text ); + + mStatus = new QComboBox(false,this); + mStatus->insertStringList(Attendee::statusList()); + statusLayout->addWidget( mStatus ); + + QBoxLayout *buttonLayout = new QHBoxLayout( topLayout ); + + QPushButton *ok = new KPushButton(KStdGuiItem::ok(), this); + connect ( ok,SIGNAL(clicked()), this,SLOT(accept()) ); + buttonLayout->addWidget( ok ); + + QPushButton *cancel = new KPushButton(KStdGuiItem::cancel(), this); + connect ( cancel,SIGNAL(clicked()), this,SLOT(reject()) ); + buttonLayout->addWidget( cancel ); +} + +StatusDialog::~StatusDialog() +{ +} + +Attendee::PartStat StatusDialog::status() +{ + return Attendee::PartStat( mStatus->currentItem() ) ; +} diff --git a/korganizer/statusdialog.h b/korganizer/statusdialog.h new file mode 100644 index 000000000..66a9d364d --- /dev/null +++ b/korganizer/statusdialog.h @@ -0,0 +1,42 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef STATUSDIALOG_H +#define STATUSDIALOG_H + +#include <kdialog.h> + +#include <libkcal/attendee.h> +using namespace KCal; + +class QComboBox; + +class StatusDialog : public KDialog +{ + Q_OBJECT + public: + StatusDialog(QWidget* parent=0,const char* name=0); + ~StatusDialog(); + + Attendee::PartStat status(); + + private: + QComboBox *mStatus; +}; + +#endif diff --git a/korganizer/stdcalendar.cpp b/korganizer/stdcalendar.cpp new file mode 100644 index 000000000..55b47d56e --- /dev/null +++ b/korganizer/stdcalendar.cpp @@ -0,0 +1,109 @@ +/* + This file is part of libkcal. + + Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "stdcalendar.h" + +#include <libkcal/resourcecalendar.h> +#include <libkdepim/kpimprefs.h> + +#include <kstaticdeleter.h> +#include <kconfig.h> +#include <kstandarddirs.h> +#include <klocale.h> +#include <kurl.h> + +using namespace KOrg; + +static KStaticDeleter<StdCalendar> selfDeleter; + +StdCalendar *StdCalendar::mSelf = 0; + +StdCalendar *StdCalendar::self() +{ + if ( !mSelf ) { + selfDeleter.setObject( mSelf, new StdCalendar() ); + } + return mSelf; +} + +StdCalendar::StdCalendar() + : CalendarResources( KPimPrefs::timezone() ) +{ + readConfig(); + + KCal::CalendarResourceManager *manager = resourceManager(); + if ( manager->isEmpty() ) { + KConfig config( "korganizerrc" ); + config.setGroup( "General" ); + QString fileName = config.readPathEntry( "Active Calendar" ); + + QString resourceName; + QString resoruceType; + KCal::ResourceCalendar *defaultResource = 0; + if ( !fileName.isEmpty() ) { + KURL url( fileName ); + if ( url.isLocalFile() ) { + kdDebug(5850) << "Local resource at " << url << endl; + defaultResource = manager->createResource( "file" ); + if ( defaultResource ) + defaultResource->setValue( "File", url.path() ); + } else { + kdDebug(5850) << "Remote Resource at " << url << endl; + defaultResource = manager->createResource( "remote" ); + if ( defaultResource ) + defaultResource->setValue( "URL", url.url() ); + } + resourceName = i18n( "Active Calendar" ); + } + // No resource created, i.e. no path found in config => use default path + if ( !defaultResource ) { + fileName = locateLocal( "data", "korganizer/std.ics" ); + kdDebug(5850) << "Creating new default local resource at " << fileName << endl; + defaultResource = manager->createResource( "file" ); + if ( defaultResource ) + defaultResource->setValue( "File", fileName ); + resourceName = i18n( "Default Calendar" ); + } + + if ( defaultResource ) { + defaultResource->setTimeZoneId( KPimPrefs::timezone() ); + defaultResource->setResourceName( resourceName ); + manager->add( defaultResource ); + manager->setStandardResource( defaultResource ); + } + + // By default, also create a birthday resource + KCal::ResourceCalendar *bdayResource = manager->createResource( "birthdays" ); + if ( bdayResource ) { + kdDebug(5850) << "Adding Birthdays resource" << endl; + bdayResource->setTimeZoneId( KPimPrefs::timezone() ); + bdayResource->setResourceName( i18n("Birthdays") ); + manager->add( bdayResource ); + } else { + kdDebug(5850) << "Unable to add a Birthdays resource" << endl; + } + } +} + +StdCalendar::~StdCalendar() +{ + mSelf = 0; +} diff --git a/korganizer/stdcalendar.h b/korganizer/stdcalendar.h new file mode 100644 index 000000000..0b91d6112 --- /dev/null +++ b/korganizer/stdcalendar.h @@ -0,0 +1,42 @@ +/* + This file is part of libkcal. + + Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef KORG_STDCALENDAR_H +#define KORG_STDCALENDAR_H + +#include <libkcal/calendarresources.h> + +namespace KOrg { + +class KDE_EXPORT StdCalendar : public KCal::CalendarResources +{ + public: + static StdCalendar *self(); + ~StdCalendar(); + + private: + StdCalendar(); + + static StdCalendar *mSelf; +}; + +} + +#endif diff --git a/korganizer/template_management_dialog_base.ui b/korganizer/template_management_dialog_base.ui new file mode 100644 index 000000000..093ff3c5a --- /dev/null +++ b/korganizer/template_management_dialog_base.ui @@ -0,0 +1,93 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>TemplateManagementDialog_base</class> +<widget class="QWidget"> + <property name="name"> + <cstring>TemplateManagementDialog_base</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>355</width> + <height>272</height> + </rect> + </property> + <property name="caption"> + <string>Template Management</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="KListBox" row="1" column="0" rowspan="3" colspan="1"> + <property name="name"> + <cstring>m_listBox</cstring> + </property> + </widget> + <widget class="QPushButton" row="1" column="1"> + <property name="name"> + <cstring>m_buttonAdd</cstring> + </property> + <property name="text"> + <string>&New</string> + </property> + </widget> + <widget class="QPushButton" row="2" column="1"> + <property name="name"> + <cstring>m_buttonDelete</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Delete</string> + </property> + </widget> + <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>m_introLabel</cstring> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="text"> + <string>Select a template and click <b>Apply Template</b> to apply it to the current event or task. Click <b>New</b> to create a new template based on the current event or task.</string> + </property> + </widget> + <widget class="QPushButton" row="4" column="0"> + <property name="name"> + <cstring>m_buttonApply</cstring> + </property> + <property name="text"> + <string>Apply Template</string> + </property> + </widget> + <spacer row="3" column="1"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>51</height> + </size> + </property> + </spacer> + </grid> +</widget> +<customwidgets> +</customwidgets> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>klistbox.h</includehint> +</includehints> +</UI> diff --git a/korganizer/templatemanagementdialog.cpp b/korganizer/templatemanagementdialog.cpp new file mode 100644 index 000000000..5d31f7fb1 --- /dev/null +++ b/korganizer/templatemanagementdialog.cpp @@ -0,0 +1,133 @@ +/******************************************************************************* +** +** Filename : templatemanagementdialog.cpp +** Created on : 05 June, 2005 +** Copyright : (c) 2005 Till Adam +** Email : <adam@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. +** +** It is distributed in the hope that it will be useful, but +** WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +** +** In addition, as a special exception, the copyright holders give +** permission to link the code of this program with any edition of +** the Qt library by Trolltech AS, Norway (or with modified versions +** of Qt that use the same license as Qt), and distribute linked +** combinations including the two. You must obey the GNU General +** Public License in all respects for all of the code used other than +** Qt. If you modify this file, you may extend this exception to +** your version of the file, but you are not obligated to do so. If +** you do not wish to do so, delete this exception statement from +** your version. +** +*******************************************************************************/ +#include "templatemanagementdialog.h" + +#include <qstringlist.h> +#include <qtimer.h> + +#include <kpushbutton.h> +#include <kinputdialog.h> +#include <klocale.h> +#include <kmessagebox.h> + +TemplateManagementDialog::TemplateManagementDialog(QWidget *parent, const QStringList &templates ) + :KDialogBase( parent, "template_management_dialog", true, + i18n("Manage Templates"), Ok|Cancel, Ok, true , i18n("Apply Template")), + m_templates( templates ), m_newTemplate( QString::null ), m_changed( false ) +{ + m_base = new TemplateManagementDialog_base( this, "template_management_dialog_base" ); + setMainWidget( m_base ); + connect( m_base->m_buttonAdd, SIGNAL( clicked() ), + SLOT( slotAddTemplate() ) ); + connect( m_base->m_buttonDelete, SIGNAL( clicked() ), + SLOT( slotDeleteTemplate() ) ); + m_base->m_listBox->insertStringList( m_templates ); + connect( m_base->m_listBox, SIGNAL( selectionChanged( QListBoxItem * ) ), + SLOT( slotUpdateDeleteButton( QListBoxItem * ) ) ); + connect( m_base->m_buttonApply, SIGNAL( clicked() ), + SLOT( slotApplyTemplate() ) ); + +} + +void TemplateManagementDialog::slotAddTemplate() +{ + bool ok; + bool duplicate = false; + const QString newTemplate = KInputDialog::getText( i18n("Template Name"), + i18n("Please enter a name for the new template:"), + i18n("New Template"), &ok ); + if ( newTemplate.isEmpty() || !ok ) return; + if ( m_templates.find( newTemplate) != m_templates.end() ) { + int rc = KMessageBox::warningContinueCancel( this, i18n("A template with that name already exists, do you want to overwrite it?."), i18n("Duplicate Template Name"), i18n("Overwrite")); + if ( rc == KMessageBox::Cancel ) { + QTimer::singleShot(0, this, SLOT( slotAddTemplate() ) ); + return; + } + duplicate = true; + } + if ( !duplicate ) { + m_templates.append( newTemplate ); + m_base->m_listBox->clear(); + m_base->m_listBox->insertStringList( m_templates ); + } + m_newTemplate = newTemplate; + m_changed = true; + // From this point on we need to keep the original event around until the user has + // closed the dialog, applying a template would make little sense + m_base->m_buttonApply->setEnabled( false ); + // neither does adding it again + m_base->m_buttonAdd->setEnabled( false ); +} + +void TemplateManagementDialog::slotDeleteTemplate() +{ + QListBoxItem *const item = m_base->m_listBox->selectedItem(); + if ( !item ) return; // can't happen (TM) + unsigned int current = m_base->m_listBox->index(item); + m_templates.remove( item->text() ); + m_base->m_listBox->removeItem( m_base->m_listBox->currentItem() ); + m_changed = true; + m_base->m_listBox->setSelected(QMAX(current -1, 0), true); +} + +void TemplateManagementDialog::slotUpdateDeleteButton( QListBoxItem *item ) +{ + m_base->m_buttonDelete->setEnabled( item != 0 ); +} + +void TemplateManagementDialog::slotApplyTemplate() +{ + // Once the user has applied the current template to the event, it makes no sense to add it again + m_base->m_buttonAdd->setEnabled( false ); + const QString &cur = m_base->m_listBox->currentText(); + if ( !cur.isEmpty() && cur != m_newTemplate ) + emit loadTemplate( cur ); +} + +void TemplateManagementDialog::slotOk() +{ + // failure is not an option *cough* + if ( !m_newTemplate.isEmpty() ) + emit saveTemplate( m_newTemplate ); + if ( m_changed ) + emit templatesChanged( m_templates ); + KDialogBase::slotOk(); +} + + +#include "templatemanagementdialog.moc" diff --git a/korganizer/templatemanagementdialog.h b/korganizer/templatemanagementdialog.h new file mode 100644 index 000000000..5e0a4a616 --- /dev/null +++ b/korganizer/templatemanagementdialog.h @@ -0,0 +1,77 @@ +/******************************************************************************* +** +** Filename : templatemanagerdialog.h +** Created on : 05 June, 2005 +** Copyright : (c) 2005 Till Adam +** Email : <adam@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. +** +** It is distributed in the hope that it will be useful, but +** WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +** +** In addition, as a special exception, the copyright holders give +** permission to link the code of this program with any edition of +** the Qt library by Trolltech AS, Norway (or with modified versions +** of Qt that use the same license as Qt), and distribute linked +** combinations including the two. You must obey the GNU General +** Public License in all respects for all of the code used other than +** Qt. If you modify this file, you may extend this exception to +** your version of the file, but you are not obligated to do so. If +** you do not wish to do so, delete this exception statement from +** your version. +** +*******************************************************************************/ +#ifndef TEMPLATEMANAGEMENTDIALOG_H +#define TEMPLATEMANAGEMENTDIALOG_H + +#include <qstringlist.h> + +#include "template_management_dialog_base.h" + +#include <kdialogbase.h> + +class TemplateManagementDialog: public KDialogBase { +Q_OBJECT + public: + TemplateManagementDialog( QWidget *parent, const QStringList& templates ); + + signals: + /* Emitted whenever the user hits apply, indicating that the currently selected template + should be loaded into to the incidence editor which triggered this. */ + void loadTemplate( const QString& templateName ); + /* Emitted whenever the user wants to add teh current incidence as a template + with the given name. */ + void saveTemplate( const QString& templateName ); + /* Emitted when the dialog changed the list of templates. Calling code can the replace + the list that was handed in with the one this signal transports. */ + void templatesChanged( const QStringList& templates ); + + protected slots: + void slotAddTemplate(); + void slotDeleteTemplate(); + void slotApplyTemplate(); + void slotUpdateDeleteButton( QListBoxItem *item ); + void slotOk(); + + private: + TemplateManagementDialog_base *m_base; + QStringList m_templates; + QString m_newTemplate; + bool m_changed; +}; + +#endif diff --git a/korganizer/timelabels.cpp b/korganizer/timelabels.cpp new file mode 100644 index 000000000..792c270da --- /dev/null +++ b/korganizer/timelabels.cpp @@ -0,0 +1,241 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "timelabels.h" + +#include <qhbox.h> +#include <qvbox.h> +#include <qlabel.h> +#include <qframe.h> +#include <qlayout.h> +#include <qfont.h> +#include <qfontmetrics.h> +#include <qpainter.h> +#include <qstringlist.h> +#include <qdatetime.h> + +#include <kglobal.h> + +#include "koglobals.h" +#include "kocore.h" +#include "koprefs.h" +#include "koagenda.h" + +TimeLabels::TimeLabels(int rows,QWidget *parent,const char *name,WFlags f) : + QScrollView(parent,name,f) +{ + mRows = rows; + mMiniWidth = 0; + + mCellHeight = KOPrefs::instance()->mHourSize*4; + + enableClipper(true); + + setHScrollBarMode(AlwaysOff); + setVScrollBarMode(AlwaysOff); + + resizeContents(50, int(mRows * mCellHeight) ); + + viewport()->setBackgroundMode( PaletteBackground ); + + mMousePos = new QFrame(this); + mMousePos->setLineWidth(0); + mMousePos->setMargin(0); + mMousePos->setBackgroundColor(Qt::red); + mMousePos->setFixedSize(width(), 1); + addChild(mMousePos, 0, 0); +} + +void TimeLabels::mousePosChanged(const QPoint &pos) +{ + moveChild(mMousePos, 0, pos.y()); +} + +void TimeLabels::showMousePos() +{ + mMousePos->show(); +} + +void TimeLabels::hideMousePos() +{ + mMousePos->hide(); +} + +void TimeLabels::setCellHeight(double height) +{ + mCellHeight = height; +} + +/* + Optimization so that only the "dirty" portion of the scroll view + is redrawn. Unfortunately, this is not called by default paintEvent() method. +*/ +void TimeLabels::drawContents(QPainter *p,int cx, int cy, int cw, int ch) +{ + // bug: the parameters cx and cw are the areas that need to be + // redrawn, not the area of the widget. unfortunately, this + // code assumes the latter... + + // now, for a workaround... + cx = contentsX() + frameWidth()*2; + cw = contentsWidth() ; + // end of workaround + + int cell = ((int)(cy/mCellHeight)); + double y = cell * mCellHeight; + QFontMetrics fm = fontMetrics(); + QString hour; + QString suffix = "am"; + int timeHeight = fm.ascent(); + QFont nFont = font(); + p->setFont( font() ); + + if (!KGlobal::locale()->use12Clock()) { + suffix = "00"; + } else + if (cell > 11) suffix = "pm"; + + if ( timeHeight > mCellHeight ) { + timeHeight = int(mCellHeight-1); + int pointS = nFont.pointSize(); + while ( pointS > 4 ) { + nFont.setPointSize( pointS ); + fm = QFontMetrics( nFont ); + if ( fm.ascent() < mCellHeight ) + break; + -- pointS; + } + fm = QFontMetrics( nFont ); + timeHeight = fm.ascent(); + } + //timeHeight -= (timeHeight/4-2); + QFont sFont = nFont; + sFont.setPointSize( sFont.pointSize()/2 ); + QFontMetrics fmS( sFont ); + int startW = mMiniWidth - frameWidth()-2 ; + int tw2 = fmS.width(suffix); + int divTimeHeight = (timeHeight-1) /2 - 1; + //testline + //p->drawLine(0,0,0,contentsHeight()); + while (y < cy + ch+mCellHeight) { + // hour, full line + p->drawLine( cx, int(y), cw+2, int(y) ); + hour.setNum(cell); + // handle 24h and am/pm time formats + if (KGlobal::locale()->use12Clock()) { + if (cell == 12) suffix = "pm"; + if (cell == 0) hour.setNum(12); + if (cell > 12) hour.setNum(cell - 12); + } + + // center and draw the time label + int timeWidth = fm.width(hour); + int offset = startW - timeWidth - tw2 -1 ; + p->setFont( nFont ); + p->drawText( offset, int(y+timeHeight), hour); + p->setFont( sFont ); + offset = startW - tw2; + p->drawText( offset, int(y+timeHeight-divTimeHeight), suffix); + + // increment indices + y += mCellHeight; + cell++; + } + +} + +/** + Calculates the minimum width. +*/ +int TimeLabels::minimumWidth() const +{ + return mMiniWidth; +} + +/** updates widget's internal state */ +void TimeLabels::updateConfig() +{ + setFont(KOPrefs::instance()->mTimeBarFont); + + QString test = "20"; + if ( KGlobal::locale()->use12Clock() ) + test = "12"; + mMiniWidth = fontMetrics().width( test ); + if ( KGlobal::locale()->use12Clock() ) + test = "pm"; + else { + test = "00"; + } + QFont sFont = font(); + sFont.setPointSize( sFont.pointSize()/2 ); + QFontMetrics fmS( sFont ); + mMiniWidth += fmS.width( test ) + frameWidth()*2+4 ; + // update geometry restrictions based on new settings + setFixedWidth( mMiniWidth ); + + // update HourSize + mCellHeight = KOPrefs::instance()->mHourSize*4; + // 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() ) + mCellHeight = 4*mAgenda->gridSpacingY(); + resizeContents( mMiniWidth, int(mRows * mCellHeight+1) ); +} + +/** update time label positions */ +void TimeLabels::positionChanged() +{ + int adjustment = mAgenda->contentsY(); + setContentsPos(0, adjustment); +} + +void TimeLabels::positionChanged( int pos ) +{ + setContentsPos( 0, pos ); +} + +/** */ +void TimeLabels::setAgenda(KOAgenda* agenda) +{ + mAgenda = agenda; + + connect(mAgenda, SIGNAL(mousePosSignal(const QPoint &)), this, SLOT(mousePosChanged(const QPoint &))); + connect(mAgenda, SIGNAL(enterAgenda()), this, SLOT(showMousePos())); + connect(mAgenda, SIGNAL(leaveAgenda()), this, SLOT(hideMousePos())); + connect(mAgenda, SIGNAL(gridSpacingYChanged( double ) ), this, SLOT( setCellHeight( double ) ) ); +} + + +/** This is called in response to repaint() */ +void TimeLabels::paintEvent(QPaintEvent*) +{ +// kdDebug(5850) << "paintevent..." << endl; + // this is another hack! +// QPainter painter(this); + //QString c + repaintContents(contentsX(), contentsY(), visibleWidth(), visibleHeight()); +} + +#include "timelabels.moc" diff --git a/korganizer/timelabels.h b/korganizer/timelabels.h new file mode 100644 index 000000000..fe0a1aeb0 --- /dev/null +++ b/korganizer/timelabels.h @@ -0,0 +1,84 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2000,2001,2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.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 Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef TIMELABELS_H +#define TIMELABELS_H + +#include <qscrollview.h> +#include <qlabel.h> + +class QHBox; +class QPushButton; +class QBoxLayout; + +class KOAgenda; +class KOAgendaItem; +class KConfig; + +class TimeLabels : public QScrollView +{ + Q_OBJECT + public: + TimeLabels( int rows, QWidget *parent = 0, const char *name = 0, + WFlags f = 0 ); + + /** Calculates the minimum width */ + virtual int minimumWidth() const; + + /** updates widget's internal state */ + void updateConfig(); + + /** */ + void setAgenda( KOAgenda *agenda ); + + /** */ + virtual void paintEvent( QPaintEvent *e ); + + public slots: + /** update time label positions */ + void positionChanged(); + void positionChanged( int pos ); + + protected: + void drawContents( QPainter *p, int cx, int cy, int cw, int ch ); + + private slots: + /** update the position of the marker showing the mouse position */ + void mousePosChanged(const QPoint &pos); + + void showMousePos(); + void hideMousePos(); + + void setCellHeight( double height ); + + private: + int mRows; + double mCellHeight; + int mMiniWidth; + KOAgenda* mAgenda; + + QFrame *mMousePos; // shows a marker for the current mouse position in y direction +}; + +#endif diff --git a/korganizer/timelineitem.cpp b/korganizer/timelineitem.cpp new file mode 100644 index 000000000..ed057de9d --- /dev/null +++ b/korganizer/timelineitem.cpp @@ -0,0 +1,159 @@ +/* + 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 "timelineitem.h" + +#include "kohelper.h" + +#define protected public +#include <kdgantt/KDGanttViewSubwidgets.h> +#undef public + +#include <libkcal/calendar.h> +#include <libkcal/incidenceformatter.h> +#include <libkcal/resourcecalendar.h> + +using namespace KOrg; +using namespace KCal; + +TimelineItem::TimelineItem( const QString &label, KDGanttView * parent) : + KDGanttViewTaskItem( parent ) +{ + setListViewText( 0, label ); + setDisplaySubitemsAsGroup( true ); + if ( listView() ) + listView()->setRootIsDecorated( false ); +} + +void TimelineItem::insertIncidence(KCal::Incidence * incidence, const QDateTime & _start, const QDateTime & _end) +{ + QDateTime start = incidence->dtStart(), end = incidence->dtEnd(); + if ( _start.isValid() ) + start = _start; + if ( _end.isValid() ) + end = _end; + if ( incidence->doesFloat() ) + end = end.addDays( 1 ); + + typedef QValueList<TimelineSubItem*> ItemList; + ItemList list = mItemMap[incidence]; + for ( ItemList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it ) + if ( (*it)->startTime() == start && (*it)->endTime() == end ) + return; + + TimelineSubItem * item = new TimelineSubItem( incidence, this ); + QColor c1, c2, c3; + colors( c1, c2, c3 ); + item->setColors( c1, c2, c3 ); + + item->setStartTime( start ); + item->setOriginalStart( start ); + item->setEndTime( end ); + + mItemMap[incidence].append( item ); +} + +void TimelineItem::removeIncidence(KCal::Incidence * incidence) +{ + typedef QValueList<TimelineSubItem*> ItemList; + ItemList list = mItemMap[incidence]; + for ( ItemList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it ) + delete *it; + mItemMap.remove( incidence ); +} + +void TimelineItem::moveItems(KCal::Incidence * incidence, int delta, int duration) +{ + typedef QValueList<TimelineSubItem*> ItemList; + ItemList list = mItemMap[incidence]; + for ( ItemList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it ) { + QDateTime start = (*it)->originalStart(); + start = start.addSecs( delta ); + (*it)->setStartTime( start ); + (*it)->setOriginalStart( start ); + (*it)->setEndTime( start.addSecs( duration ) ); + } +} + + +TimelineSubItem::TimelineSubItem(KCal::Incidence * incidence, TimelineItem * parent) : + KDGanttViewTaskItem( parent ), + mIncidence( incidence ), + mLeft( 0 ), + mRight( 0 ), + mMarkerWidth( 0 ) +{ + setTooltipText( IncidenceFormatter::toolTipString( incidence ) ); + if ( !incidence->isReadOnly() ) { + setMoveable( true ); + setResizeable( true ); + } +} + +TimelineSubItem::~TimelineSubItem() +{ + delete mLeft; + delete mRight; +} + +void TimelineSubItem::showItem(bool show, int coordY) +{ + KDGanttViewTaskItem::showItem( show, coordY ); + int y; + if ( coordY != 0 ) + y = coordY; + else + y = getCoordY(); + int startX = myGanttView->timeHeaderWidget()->getCoordX(myStartTime); + int endX = myGanttView->timeHeaderWidget()->getCoordX(myEndTime); + + const int mw = QMAX( 1, QMIN( 4, endX - startX ) ); + if ( !mLeft || mw != mMarkerWidth ) { + if ( !mLeft ) { + mLeft = new KDCanvasPolygon( myGanttView->timeTableWidget(), this, Type_is_KDGanttViewItem ); + mLeft->setBrush( Qt::black ); + } + QPointArray a = QPointArray( 4 ); + a.setPoint( 0, 0, -mw -myItemSize/2 - 2 ); + a.setPoint( 1, mw, -myItemSize/2 - 2 ); + a.setPoint( 2, mw, myItemSize/2 + 2 ); + a.setPoint( 3, 0, myItemSize/2 + mw + 2 ); + mLeft->setPoints( a ); + } + if ( !mRight || mw != mMarkerWidth ) { + if ( !mRight ) { + mRight = new KDCanvasPolygon( myGanttView->timeTableWidget(), this, Type_is_KDGanttViewItem ); + mRight->setBrush( Qt::black ); + } + QPointArray a = QPointArray( 4 ); + a.setPoint( 0, -mw, -myItemSize/2 - 2 ); + a.setPoint( 1, 0, -myItemSize/2 - mw - 2 ); + a.setPoint( 2, 0, myItemSize/2 + mw + 2 ); + a.setPoint( 3, -mw, myItemSize/2 + 2 ); + mRight->setPoints( a ); + } + mMarkerWidth = mw; + mLeft->setX( startX ); + mLeft->setY( y ); + mLeft->setZ( startShape->z() - 1 ); + mLeft->show(); + mRight->setX( endX ); + mRight->setY( y ); + mRight->setZ( startShape->z() - 1 ); + mRight->show(); +} diff --git a/korganizer/timelineitem.h b/korganizer/timelineitem.h new file mode 100644 index 000000000..c4f35af24 --- /dev/null +++ b/korganizer/timelineitem.h @@ -0,0 +1,81 @@ +/* + 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 KORG_TIMELINEITEM_H +#define KORG_TIMELINEITEM_H + +#define private protected +#include <kdgantt/KDGanttViewTaskItem.h> +#undef protected + +#include <qmap.h> +#include <qvaluelist.h> + +class KDGanttView; +class KDCanvasPolygon; + +namespace KCal { + class Calendar; + class ResourceCalendar; + class Incidence; +} + +namespace KOrg { + +class TimelineSubItem; + +class TimelineItem : public KDGanttViewTaskItem +{ + public: + TimelineItem( const QString &label, KDGanttView* parent ); + + void insertIncidence( KCal::Incidence *incidence, + const QDateTime &start = QDateTime(), + const QDateTime &end = QDateTime() ); + void removeIncidence( KCal::Incidence *incidence ); + + void moveItems( KCal::Incidence* incidence, int delta, int duration ); + + private: + QMap<KCal::Incidence*, QValueList<TimelineSubItem*> > mItemMap; +}; + +class TimelineSubItem : public KDGanttViewTaskItem +{ + public: + TimelineSubItem( KCal::Incidence *incidence, TimelineItem *parent ); + ~TimelineSubItem(); + + KCal::Incidence* incidence() const { return mIncidence; } + + QDateTime originalStart() const { return mStart; } + void setOriginalStart( const QDateTime &dt ) { mStart = dt; } + + private: + void showItem( bool show = true, int coordY = 0 ); + + private: + KCal::Incidence *mIncidence; + QDateTime mStart; + KDCanvasPolygon *mLeft, *mRight; + int mMarkerWidth; +}; + +} + +#endif diff --git a/korganizer/timezone.cpp b/korganizer/timezone.cpp new file mode 100644 index 000000000..8fdfcae21 --- /dev/null +++ b/korganizer/timezone.cpp @@ -0,0 +1,63 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2000 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#include <time.h> + +#include <qdatetime.h> + +#include <kaboutdata.h> +#include <kapplication.h> +#include <kdebug.h> +#include <klocale.h> +#include <kcmdlineargs.h> +#include <kglobal.h> + +#include "koprefs.h" + +int main(int argc,char **argv) +{ + KAboutData aboutData("timezone",I18N_NOOP("KOrganizer Timezone Test"),"0.1"); + KCmdLineArgs::init(argc,argv,&aboutData); + + KApplication app; + + kdDebug(5850) << "KOrganizer TimezoneId: " << KOPrefs::instance()->mTimeZoneId + << endl; + + time_t ltime; + ::time( <ime ); + tm *t = localtime( <ime ); + + kdDebug(5850) << "localtime: " << t->tm_hour << ":" << t->tm_min << endl; + + kdDebug(5850) << "tzname: " << tzname[0] << " " << tzname[1] << endl; + kdDebug(5850) << "timezone: " << timezone/3600 << endl; + + QTime qtime = QTime::currentTime(); + + kdDebug(5850) << "QDateTime::currentTime(): " + << qtime.toString( Qt::ISODate ) << endl; + + kdDebug(5850) << "KLocale::formatTime(): " + << KGlobal::locale()->formatTime( qtime ) << endl; +} diff --git a/korganizer/tips b/korganizer/tips new file mode 100644 index 000000000..50430aadc --- /dev/null +++ b/korganizer/tips @@ -0,0 +1,105 @@ +<tip category="KOrganizer|General"> +<html> +<p>...that you can synchronize your calendar data with the data on a Palm Pilot by using <a href="http://www.slac.com/pilone/kpilot_home">KPilot</a>? +</p> +</html> +</tip> + +<tip category="KOrganizer|General"> +<html> +<p>...that it is possible to show the current time in the calendar? Enable the current time line in the dialog which appears after selecting <b>Settings</b>, <b>Configure KOrganizer...</b> from the menu bar. +</p> +</html> +</tip> + +<tip category="KOrganizer|General"> +<html> +<p>...that KOrganizer supports Microsoft Exchange? Add the <b>Microsoft® Exchange 2000 resource</b> using the <b>Resource View</b> from the KOrganizer sidebar. +</p> +</html> +</tip> + +<tip category="KOrganizer|General"> +<html> +<p>...that you can select whether the week starts on Monday or on Sunday in the KDE Control Center? KOrganizer uses this setting. Look at Regional & Accessibility->Country/Region & Languages in the KDE Control Center, or select <b>Settings</b>, +<b>Configure Date & Time...</b> from the menu bar. Select the Time & Dates tab. +</p> +</html> +</tip> + +<tip category="KOrganizer|General"> +<html> +<p>...that you can edit to-dos quickly by right clicking on the property you wish to change; like the priority, the category or the date? +</p> +</html> +</tip> + +<tip category="KOrganizer|General"> +<html> +<p>...that you can view and edit a calendar from the shell with konsolekalendar? Run <b>konsolekalendar --help</b> for the available options. +</p> +</html> +</tip> + +<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> +</html> +</tip> + +<tip category="KOrganizer|General"> +<html> +<p>...that you can store your calendar on an FTP server? Use the standard file dialog to save the calendar to a URL like <b>ftp://username@ftpserver/filename</b>. You can make your calendar active and load and save it as if it were local, or add it permanently to your resources list, using the remote file resource. Just make sure that no two KOrganizer applications are working on the same file, at the same time. +</p> +</html> +</tip> + +<tip category="KOrganizer|General"> +<html> +<p>...that you can create hierarchical to-dos by clicking with the right mouse button on an existing to-do and selecting <b>New Sub-to-do</b> from the context menu? +</p> +</html> +</tip> + +<tip category="KOrganizer|General"> +<html> +<p>...that a color can be assigned to each category? Events with a certain category will be shown in that color. You can assign these in the section <b>Colors</b> within the dialog which appears after selecting <b>Settings</b>, <b>Configure KOrganizer...</b> from the menu bar. +</p> +</html> +</tip> + +<tip category="KOrganizer|General"> +<html> +<p>...that you can view and edit a calendar with Konqueror? Just click on the calendar file to make Konqueror open it. +</p> +</html> +</tip> + +<tip category="KOrganizer|General"> +<html> +<p>...that it is possible to add an attachment to an event or to-do? To do so, add a link to the <b>Attachments</b> tab within the <b>Edit Event</b> or <b>Edit To-do</b> dialog. +</p> +</html> +</tip> + +<tip category="KOrganizer|General"> +<html> +<p>...that you can export your calendar to HTML? Select <b>File</b>, <b>Export</b>, <b>Export Web Page...</b> from the menu bar to open the <b>Export calendar as web page</b> dialog. +</p> +</html> +</tip> + +<tip category="KOrganizer|General"> +<html> +<p>...that you can purge completed to-dos in one step? Go to the <b>File</b> menu and choose <b>Purge Completed</b>. +</html> +</p> +</tip> + +<tip category="KOrganizer|General"> +<html> +<p>...that you can create a new sub-to-do by pasting a to-do while another one is selected? +</p> +</html> +</tip> diff --git a/korganizer/uninstall.desktop b/korganizer/uninstall.desktop new file mode 100644 index 000000000..e1e3e1732 --- /dev/null +++ b/korganizer/uninstall.desktop @@ -0,0 +1,2 @@ +[Desktop Entry] +Hidden=true diff --git a/korganizer/urihandler.cpp b/korganizer/urihandler.cpp new file mode 100644 index 000000000..6bbd45d2f --- /dev/null +++ b/korganizer/urihandler.cpp @@ -0,0 +1,94 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ + +#include "urihandler.h" + +#ifndef KORG_NODCOP +#include <dcopclient.h> +#include "kmailIface_stub.h" +#endif + +#include <kiconloader.h> +#include <krun.h> +#include <kapplication.h> +#include <kprocess.h> +#include <kdebug.h> + +bool UriHandler::process( const QString &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"); + + // parse string, show + int colon = uri.find( ':' ); + // extract 'number' from 'kmail:<number>/<id>' + QString serialNumberStr = uri.mid( colon + 1 ); + serialNumberStr = serialNumberStr.left( serialNumberStr.find( '/' ) ); + + KMailIface_stub kmailIface( "kmail", "KMailIface" ); + kmailIface.showMail( serialNumberStr.toUInt(), QString() ); + return true; + } else if ( uri.startsWith( "mailto:" ) ) { + KApplication::kApplication()->invokeMailer( uri.mid(7), QString::null ); + return true; + } else if ( uri.startsWith( "uid:" ) ) { + DCOPClient *client = KApplication::kApplication()->dcopClient(); + const QByteArray noParamData; + const QByteArray paramData; + QByteArray replyData; + QCString replyTypeStr; + bool foundAbbrowser = client->call( "kaddressbook", "KAddressBookIface", + "interfaces()", noParamData, + replyTypeStr, replyData ); + if ( foundAbbrowser ) { + //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 ) ); + 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 + */ + QString iconPath = KGlobal::iconLoader()->iconPath( "go", KIcon::Small ); + QString tmpStr = "kaddressbook --editor-only --uid "; + tmpStr += KProcess::quote( uri.mid( 6 ) ); + KRun::runCommand( tmpStr, "KAddressBook", iconPath ); + return true; + } + } + else { // no special URI, let KDE handle it + new KRun(KURL( uri )); + } +#endif + + return false; +} diff --git a/korganizer/urihandler.h b/korganizer/urihandler.h new file mode 100644 index 000000000..7b3d22375 --- /dev/null +++ b/korganizer/urihandler.h @@ -0,0 +1,39 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef URIHANDLER_H +#define URIHANDLER_H + +#include <qstring.h> +#include <kdepimmacros.h> + +class KDE_EXPORT UriHandler +{ + public: + /** + Process URI. Return true if handler handled the URI, otherwise false. + */ + static bool process( const QString &uri ); +}; + +#endif diff --git a/korganizer/version.h b/korganizer/version.h new file mode 100644 index 000000000..63a1b3a59 --- /dev/null +++ b/korganizer/version.h @@ -0,0 +1,58 @@ +/* + This file is part of KOrganizer. + + Copyright (c) 1998-1999 Preston Brown <pbrown@kde.org> + Copyright (c) 2000-2004 Cornelius Schumacher <schumacher@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + As a special exception, permission is given to link this program + with any edition of Qt, and distribute the resulting executable, + without including the source code for Qt in the source distribution. +*/ +#ifndef KORG_VERSION_H +#define KORG_VERSION_H + +/* + Version scheme: "x.y.z build". + + x is the version number. + y is the major release number. + z is the minor release number. + + "x.y.z" follow the kdelibs version KOrganizer is released with. + + If "z" is 0, it the version is "x.y" + + "build" is empty for final versions. For development versions "build" is + something like "pre", "alpha1", "alpha2", "beta1", "beta2", "rc1", "rc2". + + Examples in chronological order: + + 3.0 + 3.0.1 + 3.1 alpha1 + 3.1 beta1 + 3.1 beta2 + 3.1 rc1 + 3.1 + 3.1.1 + 3.2 pre + 3.2 alpha1 +*/ + +static const char korgVersion[] = "3.5.9"; + +#endif diff --git a/korganizer/webcal.protocol b/korganizer/webcal.protocol new file mode 100644 index 000000000..953f3eac0 --- /dev/null +++ b/korganizer/webcal.protocol @@ -0,0 +1,10 @@ +[Protocol] +exec=kio_http +protocol=webcal +input=none +output=filesystem +reading=true +defaultMimetype=application/octet-stream +determineMimetypeFromExtension=true +Icon=www +maxInstances=3 |