summaryrefslogtreecommitdiffabout
Side-by-side diff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--bin/kdepim/WhatsNew.txt22
-rw-r--r--kmicromail/libetpan/maildir/maildir.c25
-rw-r--r--kmicromail/libetpan/mh/mailmh.c12
-rw-r--r--korganizer/calendarview.cpp4
-rw-r--r--korganizer/kotodoview.cpp1
-rw-r--r--korganizer/kotodoviewitem.cpp2
-rw-r--r--libkcal/sharpformat.cpp7
-rw-r--r--version2
8 files changed, 60 insertions, 15 deletions
diff --git a/bin/kdepim/WhatsNew.txt b/bin/kdepim/WhatsNew.txt
index 4905631..eb7cf13 100644
--- a/bin/kdepim/WhatsNew.txt
+++ b/bin/kdepim/WhatsNew.txt
@@ -1,589 +1,611 @@
Info about the changes in new versions of KDE-Pim/Pi
+********** VERSION 1.9.14 ************
+
+Fixed some problems with the dialog sizes when switching
+portrait/landscape mode on 640x480 PDA display.
+
+Fixed some other small bugs.
+
+Fixed an ugly bug in KOpieMail:
+KOpieMail was not able to write files (mails) to MSDOS file system,
+like on an usual preformatted SD card. That should work now.
+To save your mail data on the Sd card do the following:
+Create a dir on the SD card:
+mkdir /mnt/card/localmail
+Go to your home dir:
+cd
+Go to kopiemail data storage dir:
+cd kdepim/apps/kopiemail
+Create a symlink to the SD card:
+ls -s /mnt/card/localmail
+Now KOpieMail will store all mails on the SD card.
+
+
********** VERSION 1.9.13 ************
Fixed nasty PwM/Pi file reading bug, when
the used hash algo of file is different then the global
hash algo.
Added KA/Pi support for opie mailit mailapplication.
Fixed some bugs in OM/Pi.
Now character conversion tables are available for the Zaurus
to make OM/Pi working properly.
To get the character conversion in OM/Pi working, please download
at the sourceforge project site the package
sr-character-conversion_SharpROM_arm.ipk.zip
(or oz-character-conversion_OZ-gcc3xx_arm.ipk.zip for OZ roms)
from the section "general files for KDE/Pim"
Instructions how to install this package are in a ReadMe in this file.
Fixed the orientation change problem in KA/Pi when switching
portrait/landscape mode.
French translation available for KA/Pi and OM/Pi.
Fixed some problems with categories in KO/Pi in DTM sync.
Added selection dialog for export to phone in KA/Pi.
If in KO/Pi is an attendee selected to add to a meeting and this
attendee is already in the list of attendees, this person is not added
again.
Some menu cleanup in KA/Pi.
********** VERSION 1.9.12 ************
Fix for the bug in KO/Pi What's Next view of version 1.9.11.
Bugfix: Licence file is now shown again.
OM/Pi now supports Unicode (utf8 charset).
Fixed some bugs in OM/Pi.
KA/Pi has more German translation.
********** VERSION 1.9.11 ************
Fixed several problems in PWM/Pi, like
asking the user, if unsaved changed are pending
when closing the app.
And PwM/Pi handles now different texts for the
fields Description, Username, Password, configurable per category.
Fixed a crash in KO/Pi , when importing/loading vcs files
which have an entry with an attendee with state:
NEEDS ACTION
Fixed some problems in the German translation of OM/Pi,
which makes some dialogs not fitting on the screen
of the Z 5500.
Fixed Qtopia crash, when disabling/deinstalling
KO/Pi alarm applet.
Implemented direct KDE<->KA/Pi sync for KA/Pi running
on Linux desktop.
Added feature "remove sync info" to sync menu.
Tweaked the KO/Pi What's next view a bit, added
setting to hide events that are done.
Disabled "beam receive enabled" on startup to
avoid problems if Fastload is enabled.
Please set "beam receive enabled",
if you want to receive data via IR.
Fixed bug in direct KDE<->KO/Pi sync for KO/Pi running
on Linux desktop.
Made in KA/Pi scrolling possible, if details view is selected.
(The keyboard focus is set automatically to the search line)
Fixed a bug in DMT sync, that a new entry in DTM was added
on every sync to Kx/Pi.
Fixed missing writing of KA/Pi categories to DMT entries when syncing.
Fixed a bug in DMT sync with todos created in KO/Pi containing
non-latin1 characters.
Rearranged package contents of Sharp-ipks and made all
packages installable on SD again.
Fixed the writing of addressbook data in DTM sync.
Empty fields in KA/Pi were not removed.
Added better category handling in KA/Pi:
Added item
Edit Categories and
Manage new categories
to the settings menu.
Possible to configure a view to display categories.
Added detailed "KDE Sync Howto" and "Multi Sync Howto" to Help menu.
Fixed displaying of "free" days and time in KO Monthview and Agendaview.
... and many other bugfixes.
********** VERSION 1.9.10 ************
Many internal small bugfixes.
And fix of the "big" bug in KO/Pi,
that after Syncing the appointments had an offset by several hours.
That was a problem with the internal timezone setting,
introduced by the changed timezone configuration settings.
German translation for OM/Pi is now available.
********** VERSION 1.9.9 ************
KDE-Pim/Pi has a new Member!
It is called PWM/Pi (Passwordmanager/platform-independent)
and it is available for the Zaurus.
It is planned, that it will be available later for Windows.
(And for Linux, of course).
It is a port of the Passwordmanager of KDE.
It will need the MicroKDElibs to run.
Made loading of addressbooks in KA/Pi up to 7 times faster!
The bigger your addressbook file, the more starting speed
will you gain. (relatively)
The Qtopia addressbook connector is now platform independend
as well and should work on any platform for importing/exporting
Qtopia and Opie XML files.
Added a +30min feature to the timezone settings to make
KDE-Pim/Pi useable in Australia and other parts on the
world with strange timezones ;-)
German "Umlaute" should now be sorted correctly on the Z in KA/Pi.
It is now possible to disable the
"receive data via infrared" feature, such that syncing with
Outlook is now possible again with Kx/Pi runing.
Please disable it, before syncing Sharp DTM with Outlook.
For your convenience, the "receive data via infrared" feature
is disabled automatically, if you sync Kx/Pi with DTM.
You have to enable it again manually after syncing.
Enabling this feature makes it impossible to start the
Sharp DTM apps. If this feature is enabled, you will only get the
alarm notification from KO/Pi and not from the Sharp calendar.
This is very useful if you sync KO/Pi with Sharp DTM,
because after syncing you usually would get notified about
an alarm by KO/Pi and the Sharp Calendar.
Together with the Linux desktop version of KO/Pi
it is now possible to sync KO/Pi on the Zaurus
with the complete KDE-desktop (3.3 or later)
calendar data easily.
That makes it possible to sync the Z with one
click of a mouse with the KDE-Desktop.
This feature it available for all Zaurus platforms KO/Pi
is running on.
The only thing needed is a running KO/Pi on Linux and
a compiled version of the small
KDE-Pim/Pi<->KDE-Desktop access command line program,
which is in the KDE-Pim/Pi sources available.
The "KDE-desktop" syncing feature for KA/Pi will follow
in the next releases.
Fixed the vcard export bug, which had the version 1.9.8.
Added missing GERMAN translation to KO/Pi.
Hi PsionX, could you add the missing french translation?Thx!
Translation files for KA/Pi are available as well.
GERMAN translation will be available in the next release.
PsionX ( yres, you again ;-) ), could you start translating
KA/Pi? Thx!
You can download the version 1.9.9 at
http://sourceforge.net/project/showfiles.php?group_id=104103&package_id=112604
Note:
To run the mail program OM/Pi you need libopenssl.
A link to a download loaction is available at
ZSI at www.killefiz.de
********** VERSION 1.9.8 ************
Fixed character decoding in OM/Pi.
(e.g. German "Umlaute" were not displayed properly.)
Made is possible to reparent todos in KO/Pi.
Use contextmenu or keys (look at Help-Keys + Colors) for that.
Added the missing Sync-Howto and WhatsNew to the packages.
KO/Pi on Linux desktop can now sync with KDE desktop.
That means: When using KO/Pi on Linux desktop for syncing with
KDE desktop and the Zaurus, the Zaurus can be synced now
with all KDE-Calendar resources, not only with one local file.
(That makes it possible to sync the Zaurus with the
calendar data on a Kolab server)
KA/Pi syncing with KDE desktop will be available in the next version.
********** VERSION 1.9.7 ************
KO/Pi - KA/Pi on Windows:
Now a directory can be defined by the user, where the
application/config data should be saved.
Define your desired path in the evironment variable
MICROKDEHOME
before starting KO/Pi or KA/Pi.
An easy Kx/Pi to Kx/Pi syncing is now possible
(it is called Pi-Sync) via network.
Please look at the Sync Howto.
Exporting of calendar data and contacts to mobile phones is now possible.
The SyncHowto is updated with information howto
access/sync mobile phones.
Please look at the Sync Howto.
Now KO/Pi and KA/Pi on the Zaurus can receive data via infrared directly.
Please disable Fastload for the original contact/calendar applications
and close them.
KO/Pi and KA/Pi must be running in order to receive the data.
(KO/Pi and KA/Pi are always running if Fastload for them is enabled!)
In the KA/Pi details view are now the preferred tel. numbers displayed on top
of the other data ( emails/tel.numbers/addresses)
Fixed some syncing problems in KA/Pi.
Added font settings for the KA/Pi details view.
Added fields "children's name" and "gender" to KA/Pi.
Made searching in KA/Pi better:
Now the first item in a view is selected after a search automatically and
the views can be scrolled up/down when the search input field has the keyboard focus.
And, of course, fixed a bunch of reported bugs in KO/Pi and KA/Pi.
********** VERSION 1.9.6 ************
Changes in the external application communication on the Zaurus
in order to use less RAM when the apps are running.
First syncing of addressbooks (KA/Pi) is possible.
********** VERSION 1.9.5a ************
Fixed a bug in KO/Pi in the SharpDTM sync of version 1.9.5.
Fixed some small bugs.
KA/Pi shows now the birthday in summary view.
Now OM/Pi and KA/Pi are using the date format defined in KO/Pi
for displaying dates.
********** VERSION 1.9.5 ************
There is still no Addressbook syncing!
New in 1.9.5:
Many bugfixes.
Better searching in KA/Pi.
You can configure in KA/Pi if you want to search only after
<return> key pressed.
Better mail downloading in OM/Pi.
First experimental alpha version of sync of KO/Pi with mobile phones.
See gammu documentation for supported phones.
You need to install the package kammu_1.9.5_arm.ipk for sync of KO/Pi with mobile phones. kammu_1.9.5_arm.ipk needs libbluetooth and libsdp.
Quick hint how to use:
NOTE: MOBILE PHONE SYNC IS EXPERIMENTAL!
Install kammu_1.9.5_arm.ipk , libbluetooth and libsdp.
Create syncprofile - mobile device
Remove entry for model. (Leave empty ).
Enable infrared on Zaurus and your Phone.
Sync.
To get a more detailed log, start kopi from konsole.
********** VERSION 1.9.4 ************
This is the version 1.9.4 of KDE-Pim/Pi for the Zaurus.
WARNING:
PLEASE BACKUP ALL YOUR DATA!
We have changed a lot and maybe there are some unknown problems.
SYNC HANDLING HAS CHANGED!
Such that, if you sync now with an already synded device, you will duplicated entries after the first sync.
(This change was introduced to make it possible to sync with mobile phones, which will be available later (maybe in 4 weeks).
You need the kmicrokdelibs_1.9.4_arm.ipk as a base for the other programs.
If you get the error: "Install only possible in main memory", just try it again to install it on SD card. That worked for me. And it was reported that rebooting Qtopia did help in this case as well.
As programs are available:
KO/Pi (korganizer ipk) - a calendar program.
KA/Pi (kaddressbook ipk ) - an addressbook
OM/Pi (kopiemail ipk ) an email program with pop/smtp and IMAP support.
An alarm notification program ( korganizer-alarm ipk ) for KO/Pi that notifies you about alarms, even if the Zaurus is in suspend mode.
(If you do not see an icon in the taskbar after installing korganizer-alarm, please restart Qtopia)
All the applications are installed in a "Pim" TAB.
If this TAB is new on your system, you can get an icon in this TAB by installing pim_TAB_icon_1.9.4_arm.ipk
All the application are integrated.
Such that you can choose in KO/Pi the attendees of a meeting from the addresses in KA/Pi. When you click in KA/Pi on the email address, OM/Pi is started to write the mail.
HINT:
If you install KPhone/Pi 0.9.7, it will be called, if you click in KA/Pi on a phone number.
What's new?
SYNC HANDLING HAS CHANGED!
Such that, if you sync now with an already synded device, you will duplicated entries after the first sync.
(This change was introduced to make it possible to sync with mobile phones, which will be available later (maybe in 4 weeks).
New in OM/Pi:
When copying(i.e. downloading mails) , you can specify, that only mails of a given size should be downloaded. Added mail copy possibility for selected mails.
New in KO/Pi:
French is now available for KO/Pi.
Choose menu:Actions - Configure:TAB locale
Syncing has changed.
Phone sync available soon.
Not much changes, I cannot remember them ...
New in KA/Pi:
Beaming possible.
Sharp DTM readonly access possible( create a new DTM resource );
Better searching possible.
Search is performed only after pressing the return key.
Use wildcard * to specify parts of a name.
Better name/email selection dialog (called from KO/Pi or OM/Pi). In this dialog, now searching is possible. Like in KA/Pi, use return key and wildcard * .
A big improvement is the new management of the contact access.
In version 1.9.3, every application was using their own addressbook access data.
That means, the addressbook was loaded up to three times in the memory, when accessed by KA/Pi, KO/Pi and OM/Pi.
That was wasting of memory, if you had several hundreds of contacts.
Now only KA/Pi accesses the addressbook.
If KO/Pi or OM/Pi want to get some name/email data, they request KA/Pi to open the name/email selection dialog and send it back to them.
If you click on an attendee in a meeting, its contact data is displayed in KA/Pi directly.
That means, if KO/Pi or OM/Pi want to access contact data, KA/Pi is started first.
New in the KO/Pi alarm applet:
Configure your own timer popup menu!
(Text and minutes for timer countdown)
Just edit the file
(yourhomedir)/.kopialarmtimerrc
and start/stop a timer to get a new menu with the data of this file.
********** VERSION 1.9.3 ************
1)
Now KO/Pi on Windows imports directly the calendar data of
an installed Outlook. Should work with OL version >= 2000.
********** VERSION 1.9.2 ************
1)
KDE-Pim/Pi has got a new member:
KmicroMail (KM/Pi) is a mail program,
which can handle IMAP and POP mail access.
It is based on Opie-Mail v3.
All dependencies to the Opie libraries ar removed,
such that no additional Opie lib is needed.
It is already integrated in KO/Pi and KA/Pi.
It it now available for the Zaurus,probably it
will be available for other platforms later.
Hint:
Create your own contact (name + email)
in KA/Pi, select this contact and choose menu:
Settings - Set Who Am I.
Now the settings of this contact are used as
the sender data in KM/Pi.
2)
KDE-Pim/Pi is split up in five different
packages now precompiled for Sharp Zaurus:
--kmicrokdelibs_1.9.2_arm.ipk
The libs are needed for any
of the following programs:
--kaddressbook_1.9.2_arm.ipk
--kmicromail_1.9.2_arm.ipk
--korganizer_1.9.2_arm.ipk
Independ from that, there is the alarm applet
available for KO/Pi, which also offers
quick access for a new mail or
showing the addressbook.:
--korganizer-alarm_1.9.2_arm.ipk
Independend means, that the alarm applet
does not need any of the libs or programs above to run.
But it would be quite useless without these programs.
NOTE:
If you get a
"This application depends on other programs"
during installation of
--kmicrokdelibs_1.9.2_arm.ipk
you probably do not have to care about that.
kmicrokdelibs_1.9.2 will come with some
resource plugins, which needs additional libraries.
(E.g. libopie1, if you want to use the
opie resource connector in KA/Pi).
If you do not have this libraries installed,
you simply cannot use the resource.
To make it clear:
If the libraries are missing, the applications
using kmicrokdelibs will start,
because the resources are plugins.
3)
KO/Pi and friends are now installable on SD-Card!
It is recommended to install all libs and apps
on the SD card or all in the internal storage.
There may be problems, if this is mixed.
4)
Fixed two bugs in the alarm notification on Windows.
5)
Great improvement!
KO/Pi uses now the latest version of libical.
Libical is the library which actually reads
the calendar files and extract the data from it.
With the old version, there were problems
(crashes or program hangs) when licical did read
files, which were not stored from KO/Pi.
I do not know, if the new libical works perfect,
but actually it works much better than
the old version.
There are no problems with compatibility with
old calendar files of KO/Pi, of course!
6)
New in KA/Pi:
Opie addressbook resource connector available!
You will need libopie1 and the opie addressbook,
of course.
With the Opie addressbook resource connector,
you can access the Opie addressbook readonly in KA/Pi.
If you want to edit or import the data into KA/Pi,
do this:
a) Create an Opie resource.
(Menu: Settings-Configure Resources).
After configuration and restarting KA/Pi you should see
the Opie contacts in KA/Pi.
b) Select some or all Opie contacts.
(NOTE: +++++
To know exactly, what contacts are Opie contacts,
do this: Choose menu:
View-Modify View - TAB Fields.
Select in the above list "Resource" and click
down arrow to add it to the "Selected fields".
Click OK.
Now you have a new column "Resource" in your list,
where you can see, what an Opie resource is.
++++ NOTE end.)
Ok, we do have now some Opie contacts seleted.
(Use SHIFT or CTRL key in order to multiple select).
c) Choose menu: Edit-Copy.
d) Choose menu: Edit-Paste.
e) Select the resource, you want to add the contacts to.
Congrats! Now you have read/write access to the copied
opie contacts as "real" KA/Pi contacts.
********** VERSION 1.9.1 ************
1)
+++ IMPORTANT 1 +++
The storing place of the default calendar
file has changed!
The default calendar file was
Applications/korganizer/mycalendar.ics
on Zaurus and
(yourHomeDir)/korganizer/mycalendar.ics
on Windows/Linux desktop. Now it is
(yourHomeDir)/kdepim/korganizer/mycalendar.ics
on Zaurus, Windows and Linux.
To load the old file, choose menu
File-Load calendar backup.
(It should be loaded automatically
at startup with a warning message displayed).
The place of the configuration file has changed too.
If you want to use your old KO/Pi config,
copy it to
(yourHomeDir)/kdepim/config/korganizerrc
Please read VERSION 1.9.0 - topic 3) as well!
+++ IMPORTANT 2 +++
Because of the new paths, you will need
a new version of the KO/Pi alarm applet
for Zaurus.
Use version >= 1.9.1
2)
Now the QWhat'sThis Icon works for items
in the month view as well.
(See VERSION 1.7.8 Topic 1) ).
3)
You can import birtsdays/anniversaries
from KA/Pi into KO/Pi.
Choose menu File-Import birthdays.
If you import twice, already imported items
will not be imported again, if they
have not been changed in KO/Pi.
4)
When syncing with sharp DTM, now a progress
is shown, when the data is written back.
If there is much data in KO/Pi and no data
in DTM, that can take a long time.
(But only for the first time ).
5)
In the search dialog, you can search
now for the name/email of an attendee
of an event/todo.
To get more space for displaying
search results, the buttons
for "search" and "close" on the
bottom are removed in the PDA version.
You have to click OK in the top right
corner to do a search.
6)
Now it is possible to disable the displaying
of todo items in the Allday part of the Agenda.
Choose Menu Action-Configure,
TAB Todo View, checkbox
"Allday Agenda view shows todos"
7)
If FastLoad is enabled, now the settings and the
calendar data are saved, when KO/Pi is closed.
(If no Fastload is enabled, KO/Pi saves
the data as well, of course)
8)
The Agenda View has a minimize-splitter now,
such that the height of the allday part can be
changed quickly.
********** VERSION 1.9.0 ************
1)
KO/Pi is now merged with the new microKDE from KA/Pi.
KO/Pi accesses now KA/Pi as the addressbook.
The other ddressbook-plugins are not working any longer.
(It is planned, that later KA/Pi itself uses these plugins)
New versions of KO/Pi are only available
together with KA/Pi as the KDE-Pim/Pi package.
2)
If you click on an attendee of a meeting in the
event viewer, a detailed summary of the
attendee is shown.
3)
The place of the configuration file has changed.
If you want to use your old KO/Pi config, copy
Applications/korganizer/config_korganizerrc
to
Applications/korganizer/config/korganizerrc
********** VERSION 1.7.8 ************
1)
Now the QWhat'sThis ist working.
Enable the QWhat'sThis icon in the toolbar.
(You have to restart to reload the changed toolbar config).
Now click on the QWhat'sThis Icon
in the top right corner of KO/Pi.
Then click on an item in the Agenda View:
You will get a detailed display of the items content.
2)
Some other very minor changes.
But I have forgotten the details ...
For that reason I start this log here:
To document my changes, when I am doing it.
********** VERSION 1.7.7 ************
Stable Version of KO/Pi
diff --git a/kmicromail/libetpan/maildir/maildir.c b/kmicromail/libetpan/maildir/maildir.c
index 0e038b1..1ef0b7a 100644
--- a/kmicromail/libetpan/maildir/maildir.c
+++ b/kmicromail/libetpan/maildir/maildir.c
@@ -1,729 +1,740 @@
/*
* libEtPan! -- a mail stuff library
*
* Copyright (C) 2001 - 2003 - DINH Viet Hoa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the libEtPan! project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id$
*/
#include "maildir.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/mman.h>
#ifdef LIBETPAN_SYSTEM_BASENAME
#include <libgen.h>
#endif
/*
We suppose the maildir mailbox remains on one unique filesystem.
*/
struct maildir * maildir_new(const char * path)
{
struct maildir * md;
md = malloc(sizeof(* md));
if (md == NULL)
goto err;
md->mdir_counter = 0;
md->mdir_mtime_new = (time_t) -1;
md->mdir_mtime_cur = (time_t) -1;
md->mdir_pid = getpid();
gethostname(md->mdir_hostname, sizeof(md->mdir_hostname));
strncpy(md->mdir_path, path, sizeof(md->mdir_path));
md->mdir_path[PATH_MAX - 1] = '\0';
md->mdir_msg_list = carray_new(128);
if (md->mdir_msg_list == NULL)
goto free;
md->mdir_msg_hash = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYNONE);
if (md->mdir_msg_hash == NULL)
goto free_msg_list;
return md;
free_msg_list:
carray_free(md->mdir_msg_list);
free:
free(md);
err:
return NULL;
}
static void maildir_flush(struct maildir * md, int msg_new);
void maildir_free(struct maildir * md)
{
maildir_flush(md, 0);
maildir_flush(md, 1);
chash_free(md->mdir_msg_hash);
carray_free(md->mdir_msg_list);
free(md);
}
#define MAX_TRY_ALLOC 32
static char * maildir_get_new_message_filename(struct maildir * md,
char * tmpfile)
{
char filename[PATH_MAX];
char basename[PATH_MAX];
int k;
time_t now;
-
+ struct stat f_stat;
now = time(NULL);
k = 0;
+
+ fprintf(stderr,"maildir_get_new_message_filename: %s \n", tmpfile);
while (k < MAX_TRY_ALLOC) {
snprintf(basename, sizeof(basename), "%lu.%u_%u.%s",
(unsigned long) now, md->mdir_pid, md->mdir_counter, md->mdir_hostname);
snprintf(filename, sizeof(filename), "%s/tmp/%s",
md->mdir_path, basename);
-
- if (link(tmpfile, filename) == 0) {
+ fprintf(stderr,"filename %s \n", filename);
+ // LR changed following lines
+ if ( stat( filename, &f_stat ) == -1 ) {
+ //if (link(tmpfile, filename) == 0) {
char * dup_filename;
dup_filename = strdup(filename);
if (dup_filename == NULL) {
- unlink(filename);
+ //unlink(filename);
return NULL;
}
-
- unlink(tmpfile);
+ fprintf(stderr,"filename %s %s \n", tmpfile,dup_filename);
+ //unlink(tmpfile);
+ rename (tmpfile,dup_filename );
md->mdir_counter ++;
return dup_filename;
}
md->mdir_counter ++;
k ++;
}
return NULL;
}
static void msg_free(struct maildir_msg * msg)
{
free(msg->msg_uid);
free(msg->msg_filename);
free(msg);
}
/*
msg_new()
filename is given without path
*/
static struct maildir_msg * msg_new(char * filename, int new_msg)
{
struct maildir_msg * msg;
char * p;
int flags;
size_t uid_len;
char * begin_uid;
/* name of file : xxx-xxx_xxx-xxx:2,SRFT */
msg = malloc(sizeof(* msg));
if (msg == NULL)
goto err;
msg->msg_filename = strdup(filename);
if (msg->msg_filename == NULL)
goto free;
begin_uid = filename;
uid_len = strlen(begin_uid);
flags = 0;
p = strstr(filename, ":2,");
if (p != NULL) {
uid_len = p - begin_uid;
p += 3;
/* parse flags */
while (* p != '\0') {
switch (* p) {
case 'S':
flags |= MAILDIR_FLAG_SEEN;
break;
case 'R':
flags |= MAILDIR_FLAG_REPLIED;
break;
case 'F':
flags |= MAILDIR_FLAG_FLAGGED;
break;
case 'T':
flags |= MAILDIR_FLAG_TRASHED;
break;
}
p ++;
}
}
if (new_msg)
flags |= MAILDIR_FLAG_NEW;
msg->msg_flags = flags;
msg->msg_uid = malloc(uid_len + 1);
if (msg->msg_uid == NULL)
goto free_filename;
strncpy(msg->msg_uid, begin_uid, uid_len);
msg->msg_uid[uid_len] = '\0';
return msg;
free_filename:
free(msg->msg_filename);
free:
free(msg);
err:
return NULL;
}
static void maildir_flush(struct maildir * md, int msg_new)
{
unsigned int i;
i = 0;
while (i < carray_count(md->mdir_msg_list)) {
struct maildir_msg * msg;
int delete;
msg = carray_get(md->mdir_msg_list, i);
if (msg_new) {
delete = 0;
if ((msg->msg_flags & MAILDIR_FLAG_NEW) != 0)
delete = 1;
}
else {
delete = 1;
if ((msg->msg_flags & MAILDIR_FLAG_NEW) != 0)
delete = 0;
}
if (delete) {
chashdatum key;
key.data = msg->msg_uid;
key.len = strlen(msg->msg_uid);
chash_delete(md->mdir_msg_hash, &key, NULL);
carray_delete(md->mdir_msg_list, i);
msg_free(msg);
}
else {
i ++;
}
}
}
static int add_message(struct maildir * md,
char * filename, int is_new)
{
struct maildir_msg * msg;
chashdatum key;
chashdatum value;
unsigned int i;
int res;
int r;
+ fprintf(stderr,"add_message filename: %s \n", filename);
msg = msg_new(filename, is_new);
if (msg == NULL) {
res = MAILDIR_ERROR_MEMORY;
goto err;
}
r = carray_add(md->mdir_msg_list, msg, &i);
if (r < 0) {
res = MAILDIR_ERROR_MEMORY;
goto free_msg;
}
key.data = msg->msg_uid;
key.len = strlen(msg->msg_uid);
value.data = msg;
value.len = 0;
r = chash_set(md->mdir_msg_hash, &key, &value, NULL);
if (r < 0) {
res = MAILDIR_ERROR_MEMORY;
goto delete;
}
return MAILDIR_NO_ERROR;
delete:
carray_delete(md->mdir_msg_list, i);
free_msg:
msg_free(msg);
err:
return res;
}
static int add_directory(struct maildir * md, char * path, int is_new)
{
DIR * d;
struct dirent * entry;
int res;
int r;
char filename[PATH_MAX];
d = opendir(path);
if (d == NULL) {
res = MAILDIR_ERROR_DIRECTORY;
goto err;
}
while ((entry = readdir(d)) != NULL) {
struct stat stat_info;
snprintf(filename, sizeof(filename), "%s/%s", path, entry->d_name);
r = stat(filename, &stat_info);
if (r < 0)
continue;
if (S_ISDIR(stat_info.st_mode))
continue;
r = add_message(md, entry->d_name, is_new);
if (r != MAILDIR_NO_ERROR) {
/* ignore errors */
}
}
closedir(d);
return MAILDIR_NO_ERROR;
err:
return res;
}
int maildir_update(struct maildir * md)
{
struct stat stat_info;
char path_new[PATH_MAX];
char path_cur[PATH_MAX];
int r;
int res;
snprintf(path_new, sizeof(path_new), "%s/new", md->mdir_path);
snprintf(path_cur, sizeof(path_cur), "%s/cur", md->mdir_path);
/* did new/ changed ? */
r = stat(path_new, &stat_info);
if (r < 0) {
res = MAILDIR_ERROR_DIRECTORY;
goto free;
}
if (md->mdir_mtime_new != stat_info.st_mtime) {
md->mdir_mtime_new = stat_info.st_mtime;
maildir_flush(md, 1);
/* messages in new */
r = add_directory(md, path_new, 1);
if (r != MAILDIR_NO_ERROR) {
res = r;
goto free;
}
}
/* did cur/ changed ? */
r = stat(path_cur, &stat_info);
if (r < 0) {
res = MAILDIR_ERROR_DIRECTORY;
goto free;
}
if (md->mdir_mtime_cur != stat_info.st_mtime) {
md->mdir_mtime_cur = stat_info.st_mtime;
maildir_flush(md, 0);
/* messages in cur */
r = add_directory(md, path_cur, 0);
if (r != MAILDIR_NO_ERROR) {
res = r;
goto free;
}
}
return MAILDIR_NO_ERROR;
free:
maildir_flush(md, 0);
maildir_flush(md, 1);
md->mdir_mtime_cur = (time_t) -1;
md->mdir_mtime_new = (time_t) -1;
return res;
}
#ifndef LIBETPAN_SYSTEM_BASENAME
static char * libetpan_basename(char * filename)
{
char * next;
char * p;
p = filename;
next = strchr(p, '/');
while (next != NULL) {
p = next;
next = strchr(p + 1, '/');
}
if (p == filename)
return filename;
else
return p + 1;
}
#else
#define libetpan_basename(a) basename(a)
#endif
int maildir_message_add_uid(struct maildir * md,
const char * message, size_t size,
char * uid, size_t max_uid_len)
{
char path_new[PATH_MAX];
char tmpname[PATH_MAX];
int fd;
int r;
char * mapping;
char * delivery_tmp_name;
char * delivery_tmp_basename;
char delivery_new_name[PATH_MAX];
char * delivery_new_basename;
int res;
struct stat stat_info;
+ fprintf(stderr,"maildir_message_add_uid for uid: %s \n", uid);
r = maildir_update(md);
if (r != MAILDIR_NO_ERROR) {
res = r;
goto err;
}
/* write to tmp/ with a classic temporary file */
snprintf(tmpname, sizeof(tmpname), "%s/tmp/etpan-maildir-XXXXXX",
md->mdir_path);
fd = mkstemp(tmpname);
if (fd < 0) {
res = MAILDIR_ERROR_FILE;
goto err;
}
r = ftruncate(fd, size);
if (r < 0) {
res = MAILDIR_ERROR_FILE;
goto close;
}
mapping = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (mapping == MAP_FAILED) {
res = MAILDIR_ERROR_FILE;
goto close;
}
memcpy(mapping, message, size);
msync(mapping, size, MS_SYNC);
munmap(mapping, size);
close(fd);
/* write to tmp/ with maildir standard name */
delivery_tmp_name = maildir_get_new_message_filename(md, tmpname);
if (delivery_tmp_name == NULL) {
res = MAILDIR_ERROR_FILE;
goto unlink;
}
/* write to new/ with maildir standard name */
strncpy(tmpname, delivery_tmp_name, sizeof(tmpname));
tmpname[sizeof(tmpname) - 1] = '\0';
delivery_tmp_basename = libetpan_basename(tmpname);
snprintf(delivery_new_name, sizeof(delivery_new_name), "%s/new/%s",
md->mdir_path, delivery_tmp_basename);
r = link(delivery_tmp_name, delivery_new_name);
if (r < 0) {
res = MAILDIR_ERROR_FILE;
goto unlink_tmp;
}
snprintf(path_new, sizeof(path_new), "%s/new", md->mdir_path);
r = stat(path_new, &stat_info);
if (r < 0) {
unlink(delivery_new_name);
res = MAILDIR_ERROR_FILE;
goto unlink_tmp;
}
md->mdir_mtime_new = stat_info.st_mtime;
delivery_new_basename = libetpan_basename(delivery_new_name);
r = add_message(md, delivery_new_basename, 1);
if (r != MAILDIR_NO_ERROR) {
unlink(delivery_new_name);
res = MAILDIR_ERROR_FILE;
goto unlink_tmp;
}
if (uid != NULL)
strncpy(uid, delivery_new_basename, max_uid_len);
unlink(delivery_tmp_name);
free(delivery_tmp_name);
return MAILDIR_NO_ERROR;
unlink_tmp:
unlink(delivery_tmp_name);
free(delivery_tmp_name);
goto err;
close:
close(fd);
unlink:
unlink(tmpname);
err:
return res;
}
int maildir_message_add(struct maildir * md,
const char * message, size_t size)
{
return maildir_message_add_uid(md, message, size,
NULL, 0);
}
int maildir_message_add_file_uid(struct maildir * md, int fd,
char * uid, size_t max_uid_len)
{
char * message;
struct stat buf;
int r;
+ fprintf(stderr,"maildir_message_add_file_uid: %s \n", uid);
if (fstat(fd, &buf) == -1)
return MAILDIR_ERROR_FILE;
message = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (message == MAP_FAILED)
return MAILDIR_ERROR_FILE;
r = maildir_message_add_uid(md, message, buf.st_size, uid, max_uid_len);
munmap(message, buf.st_size);
return r;
}
int maildir_message_add_file(struct maildir * md, int fd)
{
+ fprintf(stderr,"maildir_message_add_file \n");
return maildir_message_add_file_uid(md, fd,
NULL, 0);
}
char * maildir_message_get(struct maildir * md, const char * uid)
{
chashdatum key;
chashdatum value;
char filename[PATH_MAX];
char * dup_filename;
struct maildir_msg * msg;
char * dir;
int r;
+ fprintf(stderr,"maildir_message_get for uid: %s \n", uid);
key.data = (void *) uid;
key.len = strlen(uid);
r = chash_get(md->mdir_msg_hash, &key, &value);
if (r < 0)
return NULL;
msg = value.data;
if ((msg->msg_flags & MAILDIR_FLAG_NEW) != 0)
dir = "new";
else
dir = "cur";
snprintf(filename, sizeof(filename), "%s/%s/%s",
md->mdir_path, dir, msg->msg_filename);
dup_filename = strdup(filename);
if (dup_filename == NULL)
return NULL;
return dup_filename;
}
int maildir_message_remove(struct maildir * md, const char * uid)
{
chashdatum key;
chashdatum value;
char filename[PATH_MAX];
struct maildir_msg * msg;
char * dir;
int r;
int res;
+ fprintf(stderr,"maildir_message_remove for uid: %s \n", uid);
key.data = (void *) uid;
key.len = strlen(uid);
r = chash_get(md->mdir_msg_hash, &key, &value);
if (r < 0) {
res = MAILDIR_ERROR_NOT_FOUND;
goto err;
}
msg = value.data;
if ((msg->msg_flags & MAILDIR_FLAG_NEW) != 0)
dir = "new";
else
dir = "cur";
snprintf(filename, sizeof(filename), "%s/%s/%s",
md->mdir_path, dir, msg->msg_filename);
r = unlink(filename);
if (r < 0) {
res = MAILDIR_ERROR_FILE;
goto err;
}
return MAILDIR_NO_ERROR;
err:
return res;
}
int maildir_message_change_flags(struct maildir * md,
const char * uid, int new_flags)
{
chashdatum key;
chashdatum value;
char filename[PATH_MAX];
struct maildir_msg * msg;
char * dir;
int r;
char new_filename[PATH_MAX];
char flag_str[5];
size_t i;
int res;
-
+ fprintf(stderr,"maildir_message_change_flags for uid: %s \n", uid);
key.data = (void *) uid;
key.len = strlen(uid);
r = chash_get(md->mdir_msg_hash, &key, &value);
if (r < 0) {
res = MAILDIR_ERROR_NOT_FOUND;
goto err;
}
msg = value.data;
if ((msg->msg_flags & MAILDIR_FLAG_NEW) != 0)
dir = "new";
else
dir = "cur";
snprintf(filename, sizeof(filename), "%s/%s/%s",
md->mdir_path, dir, msg->msg_filename);
if ((new_flags & MAILDIR_FLAG_NEW) != 0)
dir = "new";
else
dir = "cur";
i = 0;
if ((new_flags & MAILDIR_FLAG_SEEN) != 0) {
flag_str[i] = 'S';
i ++;
}
if ((new_flags & MAILDIR_FLAG_REPLIED) != 0) {
flag_str[i] = 'R';
i ++;
}
if ((new_flags & MAILDIR_FLAG_FLAGGED) != 0) {
flag_str[i] = 'F';
i ++;
}
if ((new_flags & MAILDIR_FLAG_TRASHED) != 0) {
flag_str[i] = 'T';
i ++;
}
flag_str[i] = 0;
if (flag_str[0] == '\0')
snprintf(new_filename, sizeof(new_filename), "%s/%s/%s",
md->mdir_path, dir, msg->msg_uid);
else
snprintf(new_filename, sizeof(new_filename), "%s/%s/%s:2,%s",
md->mdir_path, dir, msg->msg_uid, flag_str);
if (strcmp(filename, new_filename) == 0)
return MAILDIR_NO_ERROR;
r = link(filename, new_filename);
if (r < 0) {
res = MAILDIR_ERROR_FILE;
goto err;
}
unlink(filename);
return MAILDIR_NO_ERROR;
err:
return res;
}
diff --git a/kmicromail/libetpan/mh/mailmh.c b/kmicromail/libetpan/mh/mailmh.c
index 119f217..5e2b4cc 100644
--- a/kmicromail/libetpan/mh/mailmh.c
+++ b/kmicromail/libetpan/mh/mailmh.c
@@ -1,981 +1,985 @@
/*
* libEtPan! -- a mail stuff library
*
* Copyright (C) 2001, 2002 - DINH Viet Hoa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the libEtPan! project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id$
*/
#include "mailmh.h"
/*
perfs :
/net/home/dinh/Mail/inbox/sylpheed 686
2724 /net/home/dinh/Mail/inbox/sylpheed
bart:~/LibEtPan/libetpan/tests> time ./mhtest >/dev/null
real 0m0.385s
user 0m0.270s
sys 0m0.110s
*/
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libetpan-config.h"
struct mailmh * mailmh_new(const char * foldername)
{
struct mailmh * f;
f = malloc(sizeof(*f));
if (f == NULL)
return NULL;
f->mh_main = mailmh_folder_new(NULL, foldername);
if (f->mh_main == NULL) {
free(f);
return NULL;
}
return f;
}
void mailmh_free(struct mailmh * f)
{
mailmh_folder_free(f->mh_main);
free(f);
}
struct mailmh_msg_info * mailmh_msg_info_new(uint32_t index, size_t size,
time_t mtime)
{
struct mailmh_msg_info * msg_info;
msg_info = malloc(sizeof(* msg_info));
if (msg_info == NULL)
return NULL;
msg_info->msg_index = index;
msg_info->msg_size = size;
msg_info->msg_mtime = mtime;
msg_info->msg_array_index = 0;
return msg_info;
}
void mailmh_msg_info_free(struct mailmh_msg_info * msg_info)
{
free(msg_info);
}
struct mailmh_folder * mailmh_folder_new(struct mailmh_folder * parent,
const char * name)
{
char * filename;
char * parent_filename;
struct mailmh_folder * folder;
folder = malloc(sizeof(* folder));
if (folder == NULL)
goto err;
if (parent == NULL) {
filename = strdup(name);
if (filename == NULL)
goto free_folder;
}
else {
parent_filename = parent->fl_filename;
filename = malloc(strlen(parent_filename) + strlen(name) + 2);
if (filename == NULL)
goto free_folder;
strcpy(filename, parent_filename);
strcat(filename, MAIL_DIR_SEPARATOR_S);
strcat(filename, name);
}
folder->fl_filename = filename;
folder->fl_name = strdup(name);
if (folder->fl_name == NULL)
goto free_filename;
folder->fl_msgs_tab = carray_new(128);
if (folder->fl_msgs_tab == NULL)
goto free_name;
#if 0
folder->fl_msgs_hash = cinthash_new(128);
if (folder->fl_msgs_hash == NULL)
goto free_msgs_tab;
#endif
folder->fl_msgs_hash = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
if (folder->fl_msgs_hash == NULL)
goto free_msgs_tab;
folder->fl_subfolders_tab = carray_new(128);
if (folder->fl_subfolders_tab == NULL)
goto free_msgs_hash;
folder->fl_subfolders_hash = chash_new(128, CHASH_COPYNONE);
if (folder->fl_subfolders_hash == NULL)
goto free_subfolders_tab;
folder->fl_mtime = 0;
folder->fl_parent = parent;
folder->fl_max_index = 0;
return folder;
free_subfolders_tab:
carray_free(folder->fl_subfolders_tab);
free_msgs_hash:
#if 0
cinthash_free(folder->fl_msgs_hash);
#endif
chash_free(folder->fl_msgs_hash);
free_msgs_tab:
carray_free(folder->fl_msgs_tab);
free_name:
free(folder->fl_name);
free_filename:
free(folder->fl_filename);
free_folder:
free(folder);
err:
return NULL;
}
void mailmh_folder_free(struct mailmh_folder * folder)
{
unsigned int i;
for(i = 0 ; i < carray_count(folder->fl_subfolders_tab) ; i++) {
struct mailmh_folder * subfolder;
subfolder = carray_get(folder->fl_subfolders_tab, i);
if (subfolder != NULL)
mailmh_folder_free(subfolder);
}
carray_free(folder->fl_subfolders_tab);
chash_free(folder->fl_subfolders_hash);
for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i++) {
struct mailmh_msg_info * msg_info;
msg_info = carray_get(folder->fl_msgs_tab, i);
if (msg_info != NULL)
mailmh_msg_info_free(msg_info);
}
carray_free(folder->fl_msgs_tab);
chash_free(folder->fl_msgs_hash);
#if 0
cinthash_free(folder->fl_msgs_hash);
#endif
free(folder->fl_filename);
free(folder->fl_name);
free(folder);
}
struct mailmh_folder * mailmh_folder_find(struct mailmh_folder * root,
const char * filename)
{
int r;
char pathname[PATH_MAX];
char * p;
chashdatum key;
chashdatum data;
struct mailmh_folder * folder;
char * start;
if (strcmp(root->fl_filename, filename) == 0)
return root;
#if 0
r = mailmh_folder_update(root);
if (r != MAILMH_NO_ERROR)
return NULL;
#endif
#if 0
for(i = 0 ; i < root->fl_subfolders_tab->len ; i++) {
struct mailmh_folder * subfolder;
subfolder = carray_get(root->fl_subfolders_tab, i);
if (subfolder != NULL)
if (strncmp(subfolder->fl_filename, filename,
strlen(subfolder->fl_filename)) == 0)
return mailmh_folder_find(subfolder, filename);
}
#endif
strncpy(pathname, filename, PATH_MAX);
pathname[PATH_MAX - 1] = 0;
start = pathname + strlen(root->fl_filename) + 1;
p = strchr(start, MAIL_DIR_SEPARATOR);
if (p != NULL) {
* p = 0;
root = mailmh_folder_find(root, pathname);
if (root != NULL) {
folder = mailmh_folder_find(root, filename);
if (folder == NULL)
return NULL;
return folder;
}
return NULL;
}
else {
key.data = pathname;
key.len = strlen(pathname);
r = chash_get(root->fl_subfolders_hash, &key, &data);
if (r < 0)
return NULL;
return data.data;
}
}
int mailmh_folder_update(struct mailmh_folder * folder)
{
DIR * d;
struct dirent * ent;
struct stat buf;
char * mh_seq;
char filename[PATH_MAX];
int res;
int r;
uint32_t max_index;
#if 0
int add_folder;
#endif
unsigned int i;
if (stat(folder->fl_filename, &buf) == -1) {
res = MAILMH_ERROR_FOLDER;
goto err;
}
if (folder->fl_mtime == buf.st_mtime) {
res = MAILMH_NO_ERROR;
goto err;
}
folder->fl_mtime = buf.st_mtime;
d = opendir(folder->fl_filename);
if (d == NULL) {
res = MAILMH_ERROR_FOLDER;
goto err;
}
max_index = 0;
#if 0
if (folder->fl_subfolders_tab->len == 0)
add_folder = 1;
else
add_folder = 0;
#endif
/* clear the message list */
for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i ++) {
struct mailmh_msg_info * msg_info;
chashdatum key;
msg_info = carray_get(folder->fl_msgs_tab, i);
if (msg_info == NULL)
continue;
#if 0
cinthash_remove(folder->fl_msgs_hash, msg_info->msg_index);
#endif
key.data = &msg_info->msg_index;
key.len = sizeof(msg_info->msg_index);
chash_delete(folder->fl_msgs_hash, &key, NULL);
mailmh_msg_info_free(msg_info);
}
carray_set_size(folder->fl_msgs_tab, 0);
do {
uint32_t index;
ent = readdir(d);
if (ent != NULL) {
snprintf(filename, PATH_MAX,
"%s%c%s", folder->fl_filename, MAIL_DIR_SEPARATOR, ent->d_name);
if (stat(filename, &buf) == -1)
continue;
if (S_ISREG(buf.st_mode)) {
index = strtoul(ent->d_name, NULL, 10);
if (index != 0) {
struct mailmh_msg_info * msg_info;
unsigned int array_index;
chashdatum key;
chashdatum data;
msg_info = mailmh_msg_info_new(index, buf.st_size, buf.st_mtime);
if (msg_info == NULL) {
res = MAILMH_ERROR_MEMORY;
goto closedir;
}
r = carray_add(folder->fl_msgs_tab, msg_info, &array_index);
if (r < 0) {
mailmh_msg_info_free(msg_info);
res = MAILMH_ERROR_MEMORY;
goto closedir;
}
msg_info->msg_array_index = array_index;
if (index > max_index)
max_index = index;
#if 0
r = cinthash_add(folder->fl_msgs_hash, msg_info->msg_index, msg_info);
#endif
key.data = &msg_info->msg_index;
key.len = sizeof(msg_info->msg_index);
data.data = msg_info;
data.len = 0;
r = chash_set(folder->fl_msgs_hash, &key, &data, NULL);
if (r < 0) {
carray_delete_fast(folder->fl_msgs_tab, msg_info->msg_array_index);
mailmh_msg_info_free(msg_info);
res = MAILMH_ERROR_MEMORY;
goto closedir;
}
}
}
else if (S_ISDIR(buf.st_mode)) {
struct mailmh_folder * subfolder;
unsigned int array_index;
chashdatum key;
chashdatum data;
if (ent->d_name[0] == '.') {
if (ent->d_name[1] == 0)
continue;
if ((ent->d_name[1] == '.') && (ent->d_name[2] == 0))
continue;
}
key.data = ent->d_name;
key.len = strlen(ent->d_name);
r = chash_get(folder->fl_subfolders_hash, &key, &data);
if (r < 0) {
subfolder = mailmh_folder_new(folder, ent->d_name);
if (subfolder == NULL) {
res = MAILMH_ERROR_MEMORY;
goto closedir;
}
r = carray_add(folder->fl_subfolders_tab, subfolder, &array_index);
if (r < 0) {
mailmh_folder_free(subfolder);
res = MAILMH_ERROR_MEMORY;
goto closedir;
}
subfolder->fl_array_index = array_index;
key.data = subfolder->fl_filename;
key.len = strlen(subfolder->fl_filename);
data.data = subfolder;
data.len = 0;
r = chash_set(folder->fl_subfolders_hash, &key, &data, NULL);
if (r < 0) {
carray_delete_fast(folder->fl_subfolders_tab, subfolder->fl_array_index);
mailmh_folder_free(subfolder);
res = MAILMH_ERROR_MEMORY;
goto closedir;
}
}
}
}
}
while (ent != NULL);
folder->fl_max_index = max_index;
mh_seq = malloc(strlen(folder->fl_filename) + 2 + sizeof(".mh_sequences"));
if (mh_seq == NULL) {
res = MAILMH_ERROR_MEMORY;
goto closedir;
}
strcpy(mh_seq, folder->fl_filename);
strcat(mh_seq, MAIL_DIR_SEPARATOR_S);
strcat(mh_seq, ".mh_sequences");
if (stat(mh_seq, &buf) == -1) {
int fd;
fd = creat(mh_seq, S_IRUSR | S_IWUSR);
if (fd != -1)
close(fd);
}
free(mh_seq);
closedir(d);
return MAILMH_NO_ERROR;
closedir:
closedir(d);
err:
return res;
}
int mailmh_folder_add_subfolder(struct mailmh_folder * parent,
const char * name)
{
char * foldername;
int r;
struct mailmh_folder * folder;
unsigned int array_index;
chashdatum key;
chashdatum data;
foldername = malloc(strlen(parent->fl_filename) + strlen(name) + 2);
if (foldername == NULL)
return MAILMH_ERROR_MEMORY;
strcpy(foldername, parent->fl_filename);
strcat(foldername, MAIL_DIR_SEPARATOR_S);
strcat(foldername, name);
r = mkdir(foldername, 0700);
free(foldername);
if (r < 0)
return MAILMH_ERROR_FOLDER;
folder = mailmh_folder_new(parent, name);
if (folder == NULL)
return MAILMH_ERROR_MEMORY;
r = carray_add(parent->fl_subfolders_tab, folder, &array_index);
if (r < 0) {
mailmh_folder_free(folder);
return MAILMH_ERROR_MEMORY;
}
folder->fl_array_index = array_index;
key.data = folder->fl_filename;
key.len = strlen(folder->fl_filename);
data.data = folder;
data.len = 0;
r = chash_set(parent->fl_subfolders_hash, &key, &data, NULL);
if (r < 0) {
carray_delete_fast(folder->fl_subfolders_tab, folder->fl_array_index);
mailmh_folder_free(folder);
return MAILMH_ERROR_MEMORY;
}
return MAILMH_NO_ERROR;
}
int mailmh_folder_remove_subfolder(struct mailmh_folder * folder)
{
struct mailmh_folder * parent;
chashdatum key;
chashdatum data;
int r;
parent = folder->fl_parent;
key.data = folder->fl_filename;
key.len = strlen(folder->fl_filename);
r = chash_get(parent->fl_subfolders_hash, &key, &data);
if (r < 0)
return MAILMH_ERROR_FOLDER;
chash_delete(parent->fl_subfolders_hash, &key, NULL);
carray_delete_fast(parent->fl_subfolders_tab, folder->fl_array_index);
mailmh_folder_free(folder);
return MAILMH_NO_ERROR;
}
int mailmh_folder_rename_subfolder(struct mailmh_folder * src_folder,
struct mailmh_folder * dst_folder,
const char * new_name)
{
int r;
struct mailmh_folder * folder;
struct mailmh_folder * parent;
char * new_foldername;
parent = src_folder->fl_parent;
if (parent == NULL)
return MAILMH_ERROR_RENAME;
new_foldername = malloc(strlen(dst_folder->fl_filename) + 2 + strlen(new_name));
if (new_foldername == NULL)
return MAILMH_ERROR_MEMORY;
strcpy(new_foldername, dst_folder->fl_filename);
strcat(new_foldername, MAIL_DIR_SEPARATOR_S);
strcat(new_foldername, new_name);
r = rename(src_folder->fl_filename, new_foldername);
free(new_foldername);
if (r < 0)
return MAILMH_ERROR_RENAME;
r = mailmh_folder_remove_subfolder(src_folder);
if (r != MAILMH_NO_ERROR)
return r;
folder = mailmh_folder_new(dst_folder, new_name);
if (folder == NULL)
return MAILMH_ERROR_MEMORY;
r = carray_add(parent->fl_subfolders_tab, folder, NULL);
if (r < 0) {
mailmh_folder_free(folder);
return MAILMH_ERROR_MEMORY;
}
return MAILMH_NO_ERROR;
}
#define MAX_TRY_ALLOC 32
/* initial file MUST be in the same directory */
static int mailmh_folder_alloc_msg(struct mailmh_folder * folder,
char * filename, uint32_t * result)
{
uint32_t max;
uint32_t k;
char * new_filename;
size_t len;
+ struct stat f_stat;
len = strlen(folder->fl_filename) + 20;
new_filename = malloc(len);
if (new_filename == NULL)
return MAILMH_ERROR_MEMORY;
max = folder->fl_max_index + 1;
+ //fprintf(stderr,"mailmh_folder_alloc_msg filename: %s \n", filename);
k = 0;
while (k < MAX_TRY_ALLOC) {
snprintf(new_filename, len, "%s%c%lu", folder->fl_filename,
MAIL_DIR_SEPARATOR, (unsigned long) (max + k));
-
- if (link(filename, new_filename) == 0) {
+ //fprintf(stderr,"mailmh_folder_alloc_msg new_filename: %s \n", new_filename);
+ if ( stat( new_filename, &f_stat ) == -1 ) {
+ // if (link(filename, new_filename) == 0) {
int r;
-
+ //fprintf(stderr,"filename found \n");
+ //unlink(filename);
+ rename (filename,new_filename );
free(new_filename);
- unlink(filename);
if (k > MAX_TRY_ALLOC / 2) {
r = mailmh_folder_update(folder);
/* ignore errors */
}
* result = max + k;
folder->fl_max_index = max + k;
return MAILMH_NO_ERROR;
}
else if (errno == EXDEV) {
free(filename);
return MAILMH_ERROR_FOLDER;
}
k ++;
}
free(new_filename);
return MAILMH_ERROR_FOLDER;
}
int mailmh_folder_get_message_filename(struct mailmh_folder * folder,
uint32_t index, char ** result)
{
char * filename;
int len;
#if 0
r = mailmh_folder_update(folder);
if (r != MAILMH_NO_ERROR)
return r;
#endif
len = strlen(folder->fl_filename) + 20;
filename = malloc(len);
if (filename == NULL)
return MAILMH_ERROR_MEMORY;
snprintf(filename, len, "%s%c%lu", folder->fl_filename, MAIL_DIR_SEPARATOR,
(unsigned long) index);
* result = filename;
return MAILMH_NO_ERROR;;
}
int mailmh_folder_get_message_fd(struct mailmh_folder * folder,
uint32_t index, int flags, int * result)
{
char * filename;
int fd;
int r;
#if 0
r = mailmh_folder_update(folder);
if (r != MAILMH_NO_ERROR)
return r;
#endif
r = mailmh_folder_get_message_filename(folder, index, &filename);
if (r != MAILMH_NO_ERROR)
return r;
fd = open(filename, flags);
free(filename);
if (fd == -1)
return MAILMH_ERROR_MSG_NOT_FOUND;
* result = fd;
return MAILMH_NO_ERROR;
}
int mailmh_folder_get_message_size(struct mailmh_folder * folder,
uint32_t index, size_t * result)
{
int r;
char * filename;
struct stat buf;
r = mailmh_folder_get_message_filename(folder, index, &filename);
if (r != MAILMH_NO_ERROR)
return r;
r = stat(filename, &buf);
free(filename);
if (r < 0)
return MAILMH_ERROR_FILE;
* result = buf.st_size;
return MAILMH_NO_ERROR;
}
int mailmh_folder_add_message_uid(struct mailmh_folder * folder,
const char * message, size_t size,
uint32_t * pindex)
{
char * tmpname;
int fd;
size_t namesize;
size_t left;
ssize_t res;
struct mailmh_msg_info * msg_info;
uint32_t index;
int error;
int r;
unsigned int array_index;
struct stat buf;
chashdatum key;
chashdatum data;
#if 0
r = mailmh_folder_update(folder);
if (r != MAILMH_NO_ERROR) {
error = r;
goto err;
}
#endif
namesize = strlen(folder->fl_filename) + 20;
tmpname = malloc(namesize);
snprintf(tmpname, namesize, "%s%ctmpXXXXXX",
folder->fl_filename, MAIL_DIR_SEPARATOR);
fd = mkstemp(tmpname);
if (fd < 0) {
error = MAILMH_ERROR_FILE;
goto free;
}
left = size;
while (left > 0) {
res = write(fd, message, left);
if (res == -1) {
close(fd);
error = MAILMH_ERROR_FILE;
goto free;
}
left -= res;
}
close(fd);
r = stat(tmpname, &buf);
if (r < 0) {
error = MAILMH_ERROR_FILE;
goto free;
}
r = mailmh_folder_alloc_msg(folder, tmpname, &index);
if (r != MAILMH_NO_ERROR) {
unlink(tmpname);
error = MAILMH_ERROR_COULD_NOT_ALLOC_MSG;
goto free;
}
free(tmpname);
msg_info = mailmh_msg_info_new(index, size, buf.st_mtime);
if (msg_info == NULL) {
mailmh_folder_remove_message(folder, index);
error = MAILMH_ERROR_MEMORY;
goto err;
}
r = carray_add(folder->fl_msgs_tab, msg_info, &array_index);
if (r < 0) {
mailmh_folder_remove_message(folder, index);
mailmh_msg_info_free(msg_info);
error = MAILMH_ERROR_MEMORY;
goto err;
}
msg_info->msg_array_index = array_index;
#if 0
r = cinthash_add(folder->fl_msgs_hash, index, msg_info);
#endif
key.data = &index;
key.len = sizeof(index);
data.data = msg_info;
data.len = 0;
if (pindex != NULL)
* pindex = index;
r = chash_set(folder->fl_msgs_hash, &key, &data, NULL);
if (r < 0) {
carray_delete_fast(folder->fl_msgs_tab, msg_info->msg_array_index);
mailmh_msg_info_free(msg_info);
error = MAILMH_ERROR_MEMORY;
goto err;
}
return MAILMH_NO_ERROR;
free:
free(tmpname);
err:
return error;
}
int mailmh_folder_add_message(struct mailmh_folder * folder,
const char * message, size_t size)
{
return mailmh_folder_add_message_uid(folder, message, size, NULL);
}
int mailmh_folder_add_message_file_uid(struct mailmh_folder * folder,
int fd, uint32_t * pindex)
{
char * message;
struct stat buf;
int r;
#if 0
r = mailmh_folder_update(folder);
if (r != MAILMH_NO_ERROR)
return r;
#endif
if (fstat(fd, &buf) == -1)
return MAILMH_ERROR_FILE;
message = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (message == MAP_FAILED)
return MAILMH_ERROR_FILE;
r = mailmh_folder_add_message_uid(folder, message, buf.st_size, pindex);
munmap(message, buf.st_size);
return r;
}
int mailmh_folder_add_message_file(struct mailmh_folder * folder,
int fd)
{
return mailmh_folder_add_message_file_uid(folder, fd, NULL);
}
int mailmh_folder_remove_message(struct mailmh_folder * folder,
uint32_t index)
{
char * filename;
struct mailmh_msg_info * msg_info;
int res;
int r;
chashdatum key;
chashdatum data;
#if 0
r = mailmh_folder_update(folder);
if (r != MAILMH_NO_ERROR) {
res = r;
goto err;
}
#endif
r = mailmh_folder_get_message_filename(folder, index, &filename);
if (filename == NULL) {
res = r;
goto err;
}
if (unlink(filename) == -1) {
res = MAILMH_ERROR_FILE;
goto free;
}
key.data = &index;
key.len = sizeof(index);
r = chash_get(folder->fl_msgs_hash, &key, &data);
#if 0
msg_info = cinthash_find(folder->fl_msgs_hash, index);
#endif
if (r == 0) {
msg_info = data.data;
carray_delete_fast(folder->fl_msgs_tab, msg_info->msg_array_index);
#if 0
cinthash_remove(folder->fl_msgs_hash, index);
#endif
chash_delete(folder->fl_msgs_hash, &key, NULL);
}
return MAILMH_NO_ERROR;
free:
free(filename);
err:
return res;
}
int mailmh_folder_move_message(struct mailmh_folder * dest_folder,
struct mailmh_folder * src_folder,
uint32_t index)
{
int fd;
char * filename;
int r;
#if 0
r = mailmh_folder_update(dest_folder);
if (r != MAILMH_NO_ERROR)
return r;
r = mailmh_folder_update(src_folder);
if (r != MAILMH_NO_ERROR)
return r;
#endif
/* move on the same filesystem */
r = mailmh_folder_get_message_filename(src_folder, index, &filename);
if (r != MAILMH_NO_ERROR)
return r;
r = mailmh_folder_alloc_msg(dest_folder, filename, &index);
free(filename);
if (r == MAILMH_NO_ERROR)
return MAILMH_NO_ERROR;
/* move on the different filesystems */
r = mailmh_folder_get_message_fd(src_folder, index, O_RDONLY, &fd);
if (r != MAILMH_NO_ERROR)
return r;
r = mailmh_folder_add_message_file(dest_folder, fd);
if (r != MAILMH_NO_ERROR) {
close(fd);
return r;
}
close(fd);
r = mailmh_folder_remove_message(src_folder, index);
return MAILMH_NO_ERROR;
}
unsigned int mailmh_folder_get_message_number(struct mailmh_folder * folder)
{
unsigned int i;
unsigned int count;
count = 0;
for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i ++)
if (carray_get(folder->fl_msgs_tab, i) != NULL)
count ++;
return count;
}
diff --git a/korganizer/calendarview.cpp b/korganizer/calendarview.cpp
index 2321087..3908dbb 100644
--- a/korganizer/calendarview.cpp
+++ b/korganizer/calendarview.cpp
@@ -1682,1544 +1682,1548 @@ bool CalendarView::checkFileVersion(QString fn)
int km = KMessageBox::warningYesNoCancel(this, i18n("\nThe file on disk has changed!\nFile size: %1 bytes.\nLast modified: %2\nDo you want to:\n\n - Save and overwrite file?\n - Sync with file, then save?\n - Cancel without saving? \n").arg( QString::number( finf.size())).arg( KGlobal::locale()->formatDateTime(finf.lastModified (), true, true)) ,
i18n("KO/Pi Warning"),i18n("Overwrite"),
i18n("Sync+save"));
if ( km == KMessageBox::Cancel )
return false;
if ( km == KMessageBox::Yes )
return true;
setSyncDevice("deleteaftersync" );
mSyncManager->mAskForPreferences = true;
mSyncManager->mSyncAlgoPrefs = 3;
mSyncManager->mWriteBackFile = false;
mSyncManager->mWriteBackExistingOnly = false;
mSyncManager->mShowSyncSummary = false;
syncCalendar( fn, 3 );
Event * e = getLastSyncEvent();
mCalendar->deleteEvent ( e );
updateView();
return true;
}
bool CalendarView::saveCalendar( QString filename )
{
// Store back all unsaved data into calendar object
// qDebug("file %s %d ", filename.latin1() , mViewManager->currentView() );
if ( mViewManager->currentView() )
mViewManager->currentView()->flushView();
QDateTime lfv = QDateTime::currentDateTime().addSecs( -2);
mStorage->setSaveFormat( new ICalFormat() );
mStorage->setFileName( filename );
bool success;
success = mStorage->save();
if ( !success ) {
return false;
}
if ( filename == MainWindow::defaultFileName() ) {
setLoadedFileVersion( lfv );
watchSavedFile();
}
return true;
}
void CalendarView::closeCalendar()
{
// child windows no longer valid
emit closingDown();
mCalendar->close();
setModified(false);
updateView();
}
void CalendarView::archiveCalendar()
{
mDialogManager->showArchiveDialog();
}
void CalendarView::readSettings()
{
// mViewManager->showAgendaView();
QString str;
//qDebug("CalendarView::readSettings() ");
// read settings from the KConfig, supplying reasonable
// defaults where none are to be found
KConfig *config = KOGlobals::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");
if ( ( mResourceView && sizes.count() == 4 ) ||
( !mResourceView && sizes.count() == 3 ) ) {
mLeftSplitter->setSizes(sizes);
}
#endif
globalFlagBlockAgenda = 1;
mViewManager->showAgendaView();
//mViewManager->readSettings( config );
mTodoList->restoreLayout(config,QString("Todo Layout"));
readFilterSettings(config);
config->setGroup( "Views" );
int dateCount = config->readNumEntry( "ShownDatesCount", 7 );
if ( dateCount == 5 ) mNavigator->selectWorkWeek();
else if ( dateCount == 7 ) mNavigator->selectWeek();
else mNavigator->selectDates( dateCount );
// mViewManager->readSettings( config );
updateConfig();
globalFlagBlockAgenda = 2;
mViewManager->readSettings( config );
#ifdef DESKTOP_VERSION
config->setGroup("WidgetLayout");
QStringList list;
list = config->readListEntry("MainLayout");
int x,y,w,h;
if ( ! list.isEmpty() ) {
x = list[0].toInt();
y = list[1].toInt();
w = list[2].toInt();
h = list[3].toInt();
topLevelWidget()->setGeometry(x,y,w,h);
} else {
topLevelWidget()->setGeometry( 40 ,40 , 640, 440);
}
list = config->readListEntry("EditEventLayout");
if ( ! list.isEmpty() ) {
x = list[0].toInt();
y = list[1].toInt();
w = list[2].toInt();
h = list[3].toInt();
mEventEditor->setGeometry(x,y,w,h);
}
list = config->readListEntry("EditTodoLayout");
if ( ! list.isEmpty() ) {
x = list[0].toInt();
y = list[1].toInt();
w = list[2].toInt();
h = list[3].toInt();
mTodoEditor->setGeometry(x,y,w,h);
}
list = config->readListEntry("ViewerLayout");
if ( ! list.isEmpty() ) {
x = list[0].toInt();
y = list[1].toInt();
w = list[2].toInt();
h = list[3].toInt();
getEventViewerDialog()->setGeometry(x,y,w,h);
}
#endif
}
void CalendarView::writeSettings()
{
// kdDebug() << "CalendarView::writeSettings" << endl;
KConfig *config = KOGlobals::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
mViewManager->writeSettings( config );
mTodoList->saveLayout(config,QString("Todo Layout"));
mDialogManager->writeSettings( config );
//KOPrefs::instance()->usrWriteConfig();
KOPrefs::instance()->writeConfig();
writeFilterSettings(config);
config->setGroup( "Views" );
config->writeEntry( "ShownDatesCount", mNavigator->selectedDates().count() );
#ifdef DESKTOP_VERSION
config->setGroup("WidgetLayout");
QStringList list ;//= config->readListEntry("MainLayout");
int x,y,w,h;
QWidget* wid;
wid = topLevelWidget();
x = wid->geometry().x();
y = wid->geometry().y();
w = wid->width();
h = wid->height();
list.clear();
list << QString::number( x );
list << QString::number( y );
list << QString::number( w );
list << QString::number( h );
config->writeEntry("MainLayout",list );
wid = mEventEditor;
x = wid->geometry().x();
y = wid->geometry().y();
w = wid->width();
h = wid->height();
list.clear();
list << QString::number( x );
list << QString::number( y );
list << QString::number( w );
list << QString::number( h );
config->writeEntry("EditEventLayout",list );
wid = mTodoEditor;
x = wid->geometry().x();
y = wid->geometry().y();
w = wid->width();
h = wid->height();
list.clear();
list << QString::number( x );
list << QString::number( y );
list << QString::number( w );
list << QString::number( h );
config->writeEntry("EditTodoLayout",list );
wid = getEventViewerDialog();
x = wid->geometry().x();
y = wid->geometry().y();
w = wid->width();
h = wid->height();
list.clear();
list << QString::number( x );
list << QString::number( y );
list << QString::number( w );
list << QString::number( h );
config->writeEntry("ViewerLayout",list );
wid = mDialogManager->getSearchDialog();
if ( wid ) {
x = wid->geometry().x();
y = wid->geometry().y();
w = wid->width();
h = wid->height();
list.clear();
list << QString::number( x );
list << QString::number( y );
list << QString::number( w );
list << QString::number( h );
config->writeEntry("SearchLayout",list );
}
#endif
config->sync();
}
void CalendarView::readFilterSettings(KConfig *config)
{
// kdDebug() << "CalendarView::readFilterSettings()" << endl;
mFilters.clear();
config->setGroup("General");
QStringList filterList = config->readListEntry("CalendarFilters");
QStringList::ConstIterator it = filterList.begin();
QStringList::ConstIterator end = filterList.end();
while(it != end) {
// kdDebug() << " filter: " << (*it) << endl;
CalFilter *filter;
filter = new CalFilter(*it);
config->setGroup("Filter_" + (*it));
//qDebug("readFilterSettings %d ",config->readNumEntry("Criteria",0) );
filter->setCriteria(config->readNumEntry("Criteria",0));
filter->setCategoryList(config->readListEntry("CategoryList"));
mFilters.append(filter);
++it;
}
if (mFilters.count() == 0) {
CalFilter *filter = new CalFilter(i18n("Default"));
mFilters.append(filter);
}
mFilterView->updateFilters();
config->setGroup("FilterView");
mFilterView->blockSignals(true);
mFilterView->setFiltersEnabled(config->readBoolEntry("FilterEnabled"));
mFilterView->setSelectedFilter(config->readEntry("Current Filter"));
mFilterView->blockSignals(false);
// We do it manually to avoid it being done twice by the above calls
updateFilter();
}
void CalendarView::writeFilterSettings(KConfig *config)
{
// kdDebug() << "CalendarView::writeFilterSettings()" << endl;
QStringList filterList;
CalFilter *filter = mFilters.first();
while(filter) {
// kdDebug() << " fn: " << filter->name() << endl;
filterList << filter->name();
config->setGroup("Filter_" + filter->name());
config->writeEntry("Criteria",filter->criteria());
config->writeEntry("CategoryList",filter->categoryList());
filter = mFilters.next();
}
config->setGroup("General");
config->writeEntry("CalendarFilters",filterList);
config->setGroup("FilterView");
config->writeEntry("FilterEnabled",mFilterView->filtersEnabled());
config->writeEntry("Current Filter",mFilterView->selectedFilter()->name());
}
void CalendarView::goToday()
{
mNavigator->selectToday();
}
void CalendarView::goNext()
{
mNavigator->selectNext();
}
void CalendarView::goPrevious()
{
mNavigator->selectPrevious();
}
void CalendarView::goNextMonth()
{
mNavigator->selectNextMonth();
}
void CalendarView::goPreviousMonth()
{
mNavigator->selectPreviousMonth();
}
void CalendarView::writeLocale()
{
//KPimGlobalPrefs::instance()->setGlobalConfig();
#if 0
KGlobal::locale()->setHore24Format( !KOPrefs::instance()->mPreferredTime );
KGlobal::locale()->setWeekStartMonday( !KOPrefs::instance()->mWeekStartsOnSunday );
KGlobal::locale()->setIntDateFormat( (KLocale::IntDateFormat)KOPrefs::instance()->mPreferredDate );
KGlobal::locale()->setLanguage( KOPrefs::instance()->mPreferredLanguage );
QString dummy = KOPrefs::instance()->mUserDateFormatLong;
KGlobal::locale()->setDateFormat(dummy.replace( QRegExp("K"), QString(",") ));
dummy = KOPrefs::instance()->mUserDateFormatShort;
KGlobal::locale()->setDateFormatShort(dummy.replace( QRegExp("K"), QString(",") ));
KGlobal::locale()->setDaylightSaving( KOPrefs::instance()->mUseDaylightsaving,
KOPrefs::instance()->mDaylightsavingStart,
KOPrefs::instance()->mDaylightsavingEnd );
KGlobal::locale()->setTimezone( KPimGlobalPrefs::instance()->mTimeZoneId );
#endif
}
void CalendarView::updateConfig()
{
writeLocale();
if ( KOPrefs::instance()->mUseAppColors )
QApplication::setPalette( QPalette (KOPrefs::instance()->mAppColor1, KOPrefs::instance()->mAppColor2), true );
emit configChanged();
mTodoList->updateConfig();
// mDateNavigator->setFont ( KOPrefs::instance()->mDateNavigatorFont);
mCalendar->setTimeZoneId(KPimGlobalPrefs::instance()->mTimeZoneId);
// To make the "fill window" configurations work
//mViewManager->raiseCurrentView();
}
void CalendarView::eventChanged(Event *event)
{
changeEventDisplay(event,KOGlobals::EVENTEDITED);
//updateUnmanagedViews();
}
void CalendarView::eventAdded(Event *event)
{
changeEventDisplay(event,KOGlobals::EVENTADDED);
}
void CalendarView::eventToBeDeleted(Event *)
{
kdDebug() << "CalendarView::eventToBeDeleted(): to be implemented" << endl;
}
void CalendarView::eventDeleted()
{
changeEventDisplay(0,KOGlobals::EVENTDELETED);
}
void CalendarView::changeTodoDisplay(Todo *which, int action)
{
changeIncidenceDisplay((Incidence *)which, action);
mDateNavigator->updateView(); //LR
//mDialogManager->updateSearchDialog();
if (which) {
mViewManager->updateWNview();
//mTodoList->updateView();
}
}
void CalendarView::changeIncidenceDisplay(Incidence *which, int action)
{
updateUnmanagedViews();
//qDebug(" CalendarView::changeIncidenceDisplay++++++++++++++++++++++++++ %d %d ",which, action );
if ( action == KOGlobals::EVENTDELETED ) { //delete
mCalendar->checkAlarmForIncidence( 0, true );
if ( mEventViewerDialog )
mEventViewerDialog->hide();
}
else
mCalendar->checkAlarmForIncidence( which , false );
}
// most of the changeEventDisplays() right now just call the view's
// total update mode, but they SHOULD be recoded to be more refresh-efficient.
void CalendarView::changeEventDisplay(Event *which, int action)
{
// kdDebug() << "CalendarView::changeEventDisplay" << endl;
changeIncidenceDisplay((Incidence *)which, action);
mDateNavigator->updateView();
//mDialogManager->updateSearchDialog();
if (which) {
// If there is an event view visible update the display
mViewManager->currentView()->changeEventDisplay(which,action);
// TODO: check, if update needed
// if (which->getTodoStatus()) {
mTodoList->updateView();
// }
} else {
mViewManager->currentView()->updateView();
}
}
void CalendarView::updateTodoViews()
{
mTodoList->updateView();
mViewManager->currentView()->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()
{
return KMessageBox::warningContinueCancel(this,
i18n("This item will be\npermanently deleted."),
i18n("KO/Pi Confirmation"),i18n("Delete"));
}
void CalendarView::edit_cut()
{
Event *anEvent=0;
Incidence *incidence = mViewManager->currentView()->selectedIncidences().first();
if (mViewManager->currentView()->isEventView()) {
if ( incidence && incidence->type() == "Event" ) {
anEvent = static_cast<Event *>(incidence);
}
}
if (!anEvent) {
KNotifyClient::beep();
return;
}
DndFactory factory( mCalendar );
factory.cutEvent(anEvent);
changeEventDisplay(anEvent, KOGlobals::EVENTDELETED);
}
void CalendarView::edit_copy()
{
Event *anEvent=0;
Incidence *incidence = mViewManager->currentView()->selectedIncidences().first();
if (mViewManager->currentView()->isEventView()) {
if ( incidence && incidence->type() == "Event" ) {
anEvent = static_cast<Event *>(incidence);
}
}
if (!anEvent) {
KNotifyClient::beep();
return;
}
DndFactory factory( mCalendar );
factory.copyEvent(anEvent);
}
void CalendarView::edit_paste()
{
QDate date = mNavigator->selectedDates().first();
DndFactory factory( mCalendar );
Event *pastedEvent = factory.pasteEvent( date );
changeEventDisplay( pastedEvent, KOGlobals::EVENTADDED );
}
void CalendarView::edit_options()
{
mDialogManager->showOptionsDialog();
//writeSettings();
}
void CalendarView::slotSelectPickerDate( QDate d)
{
mDateFrame->hide();
if ( mDatePickerMode == 1 ) {
mNavigator->slotDaySelect( d );
} else if ( mDatePickerMode == 2 ) {
if ( mMoveIncidence->type() == "Todo" ) {
Todo * to = (Todo *) mMoveIncidence;
QTime tim;
if ( to->hasDueDate() )
tim = to->dtDue().time();
else {
tim = QTime ( 0,0,0 );
to->setFloats( true );
to->setHasDueDate( true );
}
QDateTime dt ( d,tim );
to->setDtDue( dt );
todoChanged( to );
} else {
QTime tim = mMoveIncidence->dtStart().time();
int secs = mMoveIncidence->dtStart().secsTo( mMoveIncidence->dtEnd());
QDateTime dt ( d,tim );
mMoveIncidence->setDtStart( dt );
((Event*)mMoveIncidence)->setDtEnd( dt.addSecs( secs ) );
changeEventDisplay((Event*)mMoveIncidence, KOGlobals::EVENTEDITED);
}
mMoveIncidence->setRevision( mMoveIncidence->revision()+1 );
}
}
void CalendarView::removeCategories()
{
QPtrList<Incidence> incList = mCalendar->rawIncidences();
QStringList catList = KOPrefs::instance()->mCustomCategories;
QStringList catIncList;
QStringList newCatList;
Incidence* inc = incList.first();
int i;
int count = 0;
while ( inc ) {
newCatList.clear();
catIncList = inc->categories() ;
for( i = 0; i< catIncList.count(); ++i ) {
if ( catList.contains (catIncList[i]))
newCatList.append( catIncList[i] );
}
newCatList.sort();
inc->setCategories( newCatList.join(",") );
inc = incList.next();
}
}
int CalendarView::addCategories()
{
QPtrList<Incidence> incList = mCalendar->rawIncidences();
QStringList catList = KOPrefs::instance()->mCustomCategories;
QStringList catIncList;
Incidence* inc = incList.first();
int i;
int count = 0;
while ( inc ) {
catIncList = inc->categories() ;
for( i = 0; i< catIncList.count(); ++i ) {
if ( !catList.contains (catIncList[i])) {
catList.append( catIncList[i] );
//qDebug("add cat %s ", catIncList[i].latin1());
++count;
}
}
inc = incList.next();
}
catList.sort();
KOPrefs::instance()->mCustomCategories = catList;
return count;
}
void CalendarView::manageCategories()
{
KOCatPrefs* cp = new KOCatPrefs();
cp->show();
int w =cp->sizeHint().width() ;
int h = cp->sizeHint().height() ;
int dw = QApplication::desktop()->width();
int dh = QApplication::desktop()->height();
cp->setGeometry( (dw-w)/2, (dh - h )/2 ,w,h );
if ( !cp->exec() ) {
delete cp;
return;
}
int count = 0;
if ( cp->addCat() ) {
count = addCategories();
if ( count ) {
topLevelWidget()->setCaption(QString::number( count )+ i18n(" Categories added to list! "));
writeSettings();
} else
topLevelWidget()->setCaption(QString::number( 0 )+ i18n(" Categories added to list! "));
} else {
removeCategories();
updateView();
}
delete cp;
}
void CalendarView::beamIncidence(Incidence * Inc)
{
QPtrList<Incidence> delSel ;
delSel.append(Inc);
beamIncidenceList( delSel );
}
void CalendarView::beamCalendar()
{
QPtrList<Incidence> delSel = mCalendar->rawIncidences();
//qDebug("beamCalendar() ");
beamIncidenceList( delSel );
}
void CalendarView::beamFilteredCalendar()
{
QPtrList<Incidence> delSel = mCalendar->incidences();
//qDebug("beamFilteredCalendar() ");
beamIncidenceList( delSel );
}
void CalendarView::beamIncidenceList(QPtrList<Incidence> delSel )
{
if ( beamDialog->exec () == QDialog::Rejected )
return;
#ifdef DESKTOP_VERSION
QString fn = locateLocal( "tmp", "kopibeamfile" );
#else
QString fn = "/tmp/kopibeamfile";
#endif
QString mes;
bool createbup = true;
if ( createbup ) {
QString description = "\n";
CalendarLocal* cal = new CalendarLocal();
if ( beamDialog->beamLocal() )
cal->setLocalTime();
else
cal->setTimeZoneId(KPimGlobalPrefs::instance()->mTimeZoneId);
Incidence *incidence = delSel.first();
bool addText = false;
if ( delSel.count() < 10 )
addText = true;
else {
description.sprintf(i18n(" %d items?"),delSel.count() );
}
while ( incidence ) {
Incidence *in = incidence->clone();
if ( ! in->summary().isEmpty() ) {
in->setDescription("");
} else {
in->setSummary( in->description().left(20));
in->setDescription("");
}
if ( addText )
description += in->summary() + "\n";
cal->addIncidence( in );
incidence = delSel.next();
}
if ( beamDialog->beamVcal() ) {
fn += ".vcs";
FileStorage storage( cal, fn, new VCalFormat );
storage.save();
} else {
fn += ".ics";
FileStorage storage( cal, fn, new ICalFormat( ) );
storage.save();
}
delete cal;
mes = i18n("KO/Pi: Ready for beaming");
topLevelWidget()->setCaption(mes);
KApplication::convert2latin1( fn );
#ifndef DESKTOP_VERSION
Ir *ir = new Ir( this );
connect( ir, SIGNAL( done( Ir * ) ), this, SLOT( beamDone( Ir * ) ) );
ir->send( fn, description, "text/x-vCalendar" );
#endif
}
}
void CalendarView::beamDone( Ir *ir )
{
#ifndef DESKTOP_VERSION
delete ir;
#endif
topLevelWidget()->setCaption( i18n("KO/Pi: Beaming done.") );
topLevelWidget()->raise();
}
void CalendarView::moveIncidence(Incidence * inc )
{
if ( !inc ) return;
// qDebug("showDatePickerForIncidence( ) ");
if ( mDateFrame->isVisible() )
mDateFrame->hide();
else {
int w =mDatePicker->sizeHint().width()+2*mDateFrame->lineWidth() ;
int h = mDatePicker->sizeHint().height()+2*mDateFrame->lineWidth() ;
int dw = QApplication::desktop()->width();
int dh = QApplication::desktop()->height();
mDateFrame->setGeometry( (dw-w)/2, (dh - h )/2 ,w,h );
mDateFrame->show();
}
mDatePickerMode = 2;
mMoveIncidence = inc ;
QDate da;
if ( mMoveIncidence->type() == "Todo" ) {
Todo * to = (Todo *) mMoveIncidence;
if ( to->hasDueDate() )
da = to->dtDue().date();
else
da = QDate::currentDate();
} else {
da = mMoveIncidence->dtStart().date();
}
mDatePicker->setDate( da );
}
void CalendarView::showDatePicker( )
{
//qDebug("CalendarView::showDatePicker( ) ");
if ( mDateFrame->isVisible() )
mDateFrame->hide();
else {
int w =mDatePicker->sizeHint().width() ;
int h = mDatePicker->sizeHint().height() ;
int dw = QApplication::desktop()->width();
int dh = QApplication::desktop()->height();
mDateFrame->setGeometry( (dw-w)/2, (dh - h )/2 ,w,h );
mDateFrame->show();
}
mDatePickerMode = 1;
mDatePicker->setDate( mNavigator->selectedDates().first() );
}
void CalendarView::showEventEditor()
{
#ifdef DESKTOP_VERSION
mEventEditor->show();
#else
+ if ( mEventEditor->width() != QApplication::desktop()->width() )
+ mEventEditor->hide();
mEventEditor->showMaximized();
#endif
}
void CalendarView::showTodoEditor()
{
#ifdef DESKTOP_VERSION
mTodoEditor->show();
#else
+ if ( mTodoEditor->width() != QApplication::desktop()->width() )
+ mTodoEditor->hide();
mTodoEditor->showMaximized();
#endif
}
void CalendarView::cloneIncidence()
{
Incidence *incidence = currentSelection();
if ( !incidence ) incidence = mTodoList->selectedIncidences().first();
if ( incidence ) {
cloneIncidence(incidence);
}
}
void CalendarView::moveIncidence()
{
Incidence *incidence = currentSelection();
if ( !incidence ) incidence = mTodoList->selectedIncidences().first();
if ( incidence ) {
moveIncidence(incidence);
}
}
void CalendarView::beamIncidence()
{
Incidence *incidence = currentSelection();
if ( !incidence ) incidence = mTodoList->selectedIncidences().first();
if ( incidence ) {
beamIncidence(incidence);
}
}
void CalendarView::toggleCancelIncidence()
{
Incidence *incidence = currentSelection();
if ( !incidence ) incidence = mTodoList->selectedIncidences().first();
if ( incidence ) {
cancelIncidence(incidence);
}
}
void CalendarView::cancelIncidence(Incidence * inc )
{
inc->setCancelled( ! inc->cancelled() );
changeIncidenceDisplay( inc,KOGlobals::EVENTEDITED );
updateView();
}
void CalendarView::cloneIncidence(Incidence * orgInc )
{
Incidence * newInc = orgInc->clone();
newInc->recreate();
if ( newInc->type() == "Todo" ) {
Todo* t = (Todo*) newInc;
mTodoEditor->editTodo( t );
showTodoEditor();
if ( mTodoEditor->exec() ) {
mCalendar->addTodo( t );
updateView();
} else {
delete t;
}
}
else {
Event* e = (Event*) newInc;
mEventEditor->editEvent( e );
showEventEditor();
if ( mEventEditor->exec() ) {
mCalendar->addEvent( e );
updateView();
} else {
delete e;
}
}
}
void CalendarView::newEvent()
{
// TODO: Replace this code by a common eventDurationHint of KOBaseView.
KOAgendaView *aView = mViewManager->agendaView();
if (aView) {
if (aView->selectionStart().isValid()) {
if (aView->selectedIsAllDay()) {
newEvent(aView->selectionStart(),aView->selectionEnd(),true);
} else {
newEvent(aView->selectionStart(),aView->selectionEnd());
}
return;
}
}
QDate date = mNavigator->selectedDates().first();
QDateTime current = QDateTime::currentDateTime();
if ( date <= current.date() ) {
int hour = current.time().hour() +1;
newEvent( QDateTime( current.date(), QTime( hour, 0, 0 ) ),
QDateTime( current.date(), QTime( hour+ KOPrefs::instance()->mDefaultDuration, 0, 0 ) ) );
} else
newEvent( QDateTime( date, QTime( KOPrefs::instance()->mStartTime, 0, 0 ) ),
QDateTime( date, QTime( KOPrefs::instance()->mStartTime +
KOPrefs::instance()->mDefaultDuration, 0, 0 ) ) );
}
void CalendarView::newEvent(QDateTime fh)
{
newEvent(fh,
QDateTime(fh.addSecs(3600*KOPrefs::instance()->mDefaultDuration)));
}
void CalendarView::newEvent(QDate dt)
{
newEvent(QDateTime(dt, QTime(0,0,0)),
QDateTime(dt, QTime(0,0,0)), true);
}
void CalendarView::newEvent(QDateTime fromHint, QDateTime toHint, bool allDay)
{
mEventEditor->newEvent(fromHint,toHint,allDay);
if ( mFilterView->filtersEnabled() ) {
CalFilter *filter = mFilterView->selectedFilter();
if (filter && filter->showCategories()) {
mEventEditor->setCategories(filter->categoryList().join(",") );
}
if ( filter )
mEventEditor->setSecrecy( filter->getSecrecy() );
}
showEventEditor();
}
void CalendarView::todoAdded(Todo * t)
{
changeTodoDisplay ( t ,KOGlobals::EVENTADDED);
updateTodoViews();
}
void CalendarView::todoChanged(Todo * t)
{
emit todoModified( t, 4 );
// updateTodoViews();
}
void CalendarView::todoToBeDeleted(Todo *)
{
//qDebug("todoToBeDeleted(Todo *) ");
updateTodoViews();
}
void CalendarView::todoDeleted()
{
//qDebug(" todoDeleted()");
updateTodoViews();
}
void CalendarView::newTodo()
{
mTodoEditor->newTodo(QDateTime::currentDateTime().addDays(7),0,true);
if ( mFilterView->filtersEnabled() ) {
CalFilter *filter = mFilterView->selectedFilter();
if (filter && filter->showCategories()) {
mTodoEditor->setCategories(filter->categoryList().join(",") );
}
if ( filter )
mTodoEditor->setSecrecy( filter->getSecrecy() );
}
showTodoEditor();
}
void CalendarView::newSubTodo()
{
Todo *todo = selectedTodo();
if ( todo ) newSubTodo( todo );
}
void CalendarView::newSubTodo(Todo *parentEvent)
{
mTodoEditor->newTodo(QDateTime::currentDateTime().addDays(7),parentEvent,true);
showTodoEditor();
}
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 );
}
void CalendarView::editEvent( Event *event )
{
if ( !event ) return;
if ( event->isReadOnly() ) {
showEvent( event );
return;
}
mEventEditor->editEvent( event , mFlagEditDescription);
showEventEditor();
}
void CalendarView::editJournal( Journal *jour )
{
if ( !jour ) return;
mDialogManager->hideSearchDialog();
mViewManager->showJournalView();
mNavigator->slotDaySelect( jour->dtStart().date() );
}
void CalendarView::editTodo( Todo *todo )
{
if ( !todo ) return;
if ( todo->isReadOnly() ) {
showTodo( todo );
return;
}
mTodoEditor->editTodo( todo ,mFlagEditDescription);
showTodoEditor();
}
KOEventViewerDialog* CalendarView::getEventViewerDialog()
{
if ( !mEventViewerDialog ) {
mEventViewerDialog = new KOEventViewerDialog(this);
connect( mEventViewerDialog, SIGNAL( editIncidence( Incidence* )), this, SLOT(editIncidence( Incidence* ) ) );
connect( this, SIGNAL(configChanged()), mEventViewerDialog, SLOT(updateConfig()));
connect( mEventViewerDialog, SIGNAL(jumpToTime( const QDate &)),
dateNavigator(), SLOT( selectWeek( const QDate & ) ) );
connect( mEventViewerDialog, SIGNAL(showAgendaView( bool ) ),
viewManager(), SLOT( showAgendaView( bool ) ) );
mEventViewerDialog->resize( 640, 480 );
}
return mEventViewerDialog;
}
void CalendarView::showEvent(Event *event)
{
getEventViewerDialog()->setEvent(event);
getEventViewerDialog()->showMe();
}
void CalendarView::showTodo(Todo *event)
{
getEventViewerDialog()->setTodo(event);
getEventViewerDialog()->showMe();
}
void CalendarView::showJournal( Journal *jour )
{
getEventViewerDialog()->setJournal(jour);
getEventViewerDialog()->showMe();
}
// void CalendarView::todoModified (Todo *event, int changed)
// {
// // if (mDialogList.find (event) != mDialogList.end ()) {
// // kdDebug() << "Todo modified and open" << endl;
// // KOTodoEditor* temp = (KOTodoEditor *) mDialogList[event];
// // temp->modified (changed);
// // }
// mViewManager->updateView();
// }
void CalendarView::appointment_show()
{
Event *anEvent = 0;
Incidence *incidence = mViewManager->currentView()->selectedIncidences().first();
if (mViewManager->currentView()->isEventView()) {
if ( incidence && incidence->type() == "Event" ) {
anEvent = static_cast<Event *>(incidence);
}
}
if (!anEvent) {
KNotifyClient::beep();
return;
}
showEvent(anEvent);
}
void CalendarView::appointment_edit()
{
Event *anEvent = 0;
Incidence *incidence = mViewManager->currentView()->selectedIncidences().first();
if (mViewManager->currentView()->isEventView()) {
if ( incidence && incidence->type() == "Event" ) {
anEvent = static_cast<Event *>(incidence);
}
}
if (!anEvent) {
KNotifyClient::beep();
return;
}
editEvent(anEvent);
}
void CalendarView::appointment_delete()
{
Event *anEvent = 0;
Incidence *incidence = mViewManager->currentView()->selectedIncidences().first();
if (mViewManager->currentView()->isEventView()) {
if ( incidence && incidence->type() == "Event" ) {
anEvent = static_cast<Event *>(incidence);
}
}
if (!anEvent) {
KNotifyClient::beep();
return;
}
deleteEvent(anEvent);
}
void CalendarView::todo_resub( Todo * parent, Todo * sub )
{
if (!sub) return;
if (!parent) return;
if ( sub->relatedTo() )
sub->relatedTo()->removeRelation(sub);
sub->setRelatedTo(parent);
sub->setRelatedToUid(parent->uid());
parent->addRelation(sub);
sub->updated();
parent->updated();
setModified(true);
updateView();
}
void CalendarView::todo_unsub(Todo *anTodo )
{
// Todo *anTodo = selectedTodo();
if (!anTodo) return;
if (!anTodo->relatedTo()) return;
anTodo->relatedTo()->removeRelation(anTodo);
anTodo->setRelatedTo(0);
anTodo->updated();
anTodo->setRelatedToUid("");
setModified(true);
updateView();
}
void CalendarView::deleteTodo(Todo *todo)
{
if (!todo) {
KNotifyClient::beep();
return;
}
if (KOPrefs::instance()->mConfirm) {
switch (msgItemDelete()) {
case KMessageBox::Continue: // OK
if (!todo->relations().isEmpty()) {
KMessageBox::sorry(this,i18n("Cannot delete To-Do\nwhich has children."),
i18n("Delete To-Do"));
} else {
checkExternalId( todo );
calendar()->deleteTodo(todo);
changeTodoDisplay( todo,KOGlobals::EVENTDELETED );
updateView();
}
break;
} // switch
} else {
if (!todo->relations().isEmpty()) {
KMessageBox::sorry(this,i18n("Cannot delete To-Do\nwhich has children."),
i18n("Delete To-Do"));
} else {
checkExternalId( todo );
mCalendar->deleteTodo(todo);
changeTodoDisplay( todo,KOGlobals::EVENTDELETED );
updateView();
}
}
emit updateSearchDialog();
}
void CalendarView::deleteJournal(Journal *jour)
{
if (!jour) {
KNotifyClient::beep();
return;
}
if (KOPrefs::instance()->mConfirm) {
switch (msgItemDelete()) {
case KMessageBox::Continue: // OK
calendar()->deleteJournal(jour);
updateView();
break;
} // switch
} else {
calendar()->deleteJournal(jour);;
updateView();
}
emit updateSearchDialog();
}
void CalendarView::deleteEvent(Event *anEvent)
{
if (!anEvent) {
KNotifyClient::beep();
return;
}
if (anEvent->recurrence()->doesRecur()) {
QDate itemDate = mViewManager->currentSelectionDate();
int km;
if (!itemDate.isValid()) {
//kdDebug() << "Date Not Valid" << endl;
if (KOPrefs::instance()->mConfirm) {
km = KMessageBox::warningContinueCancel(this,anEvent->summary() +
i18n("\nThis event recurs\nover multiple dates.\nAre you sure you want\nto delete this event\nand all its recurrences?"),
i18n("KO/Pi Confirmation"),i18n("Delete All"));
if ( km == KMessageBox::Continue )
km = KMessageBox::No; // No = all below
} else
km = KMessageBox::No;
} else {
km = KMessageBox::warningYesNoCancel(this,anEvent->summary() +
i18n("\nThis event recurs\nover multiple dates.\nDo you want to delete\nall it's recurrences,\nor only the current one on:\n")+
KGlobal::locale()->formatDate(itemDate)+i18n(" ?\n\nDelete:\n"),
i18n("KO/Pi Confirmation"),i18n("Current"),
i18n("All"));
}
switch(km) {
case KMessageBox::No: // Continue // all
//qDebug("KMessageBox::No ");
if (anEvent->organizer()==KOPrefs::instance()->email() && anEvent->attendeeCount()>0)
schedule(Scheduler::Cancel,anEvent);
checkExternalId( anEvent);
mCalendar->deleteEvent(anEvent);
changeEventDisplay(anEvent,KOGlobals::EVENTDELETED);
break;
// Disabled because it does not work
//#if 0
case KMessageBox::Yes: // just this one
//QDate qd = mNavigator->selectedDates().first();
//if (!qd.isValid()) {
// kdDebug() << "no date selected, or invalid date" << endl;
// KNotifyClient::beep();
// return;
//}
//while (!anEvent->recursOn(qd)) qd = qd.addDays(1);
if (itemDate!=QDate(1,1,1) || itemDate.isValid()) {
anEvent->addExDate(itemDate);
int duration = anEvent->recurrence()->duration();
if ( duration > 0 ) {
anEvent->recurrence()->setDuration( duration - 1 );
}
changeEventDisplay(anEvent, KOGlobals::EVENTEDITED);
}
break;
//#endif
} // switch
} else {
if (KOPrefs::instance()->mConfirm) {
switch (KMessageBox::warningContinueCancel(this,anEvent->summary() +
i18n("\nAre you sure you want\nto delete this event?"),
i18n("KO/Pi Confirmation"),i18n("Delete"))) {
case KMessageBox::Continue: // OK
if (anEvent->organizer()==KOPrefs::instance()->email() && anEvent->attendeeCount()>0)
schedule(Scheduler::Cancel,anEvent);
checkExternalId( anEvent);
mCalendar->deleteEvent(anEvent);
changeEventDisplay(anEvent, KOGlobals::EVENTDELETED);
break;
} // switch
} else {
if (anEvent->organizer()==KOPrefs::instance()->email() && anEvent->attendeeCount()>0)
schedule(Scheduler::Cancel,anEvent);
checkExternalId( anEvent);
mCalendar->deleteEvent(anEvent);
changeEventDisplay(anEvent, KOGlobals::EVENTDELETED);
}
} // if-else
emit updateSearchDialog();
}
bool CalendarView::deleteEvent(const QString &uid)
{
Event *ev = mCalendar->event(uid);
if (ev) {
deleteEvent(ev);
return true;
} else {
return false;
}
}
/*****************************************************************************/
void CalendarView::action_mail()
{
#ifndef KORG_NOMAIL
KOMailClient mailClient;
Incidence *incidence = currentSelection();
if (!incidence) {
KMessageBox::sorry(this,i18n("Can't generate mail:\nNo event selected."));
return;
}
if(incidence->attendeeCount() == 0 ) {
KMessageBox::sorry(this,
i18n("Can't generate mail:\nNo attendees defined.\n"));
return;
}
CalendarLocal cal_tmp;
Event *event = 0;
Event *ev = 0;
if ( incidence && incidence->type() == "Event" ) {
event = static_cast<Event *>(incidence);
ev = new Event(*event);
cal_tmp.addEvent(ev);
}
ICalFormat mForm();
QString attachment = mForm.toString( &cal_tmp );
if (ev) delete(ev);
mailClient.mailAttendees(currentSelection(), attachment);
#endif
#if 0
Event *anEvent = 0;
if (mViewManager->currentView()->isEventView()) {
anEvent = dynamic_cast<Event *>((mViewManager->currentView()->selectedIncidences()).first());
}
if (!anEvent) {
KMessageBox::sorry(this,i18n("Can't generate mail:\nNo event selected."));
return;
}
if(anEvent->attendeeCount() == 0 ) {
KMessageBox::sorry(this,
i18n("Can't generate mail:\nNo attendees defined.\n"));
return;
}
mailobject.emailEvent(anEvent);
#endif
}
void CalendarView::schedule_publish(Incidence *incidence)
{
Event *event = 0;
Todo *todo = 0;
if (incidence == 0) {
incidence = mViewManager->currentView()->selectedIncidences().first();
if (incidence == 0) {
incidence = mTodoList->selectedIncidences().first();
}
}
if ( incidence && incidence->type() == "Event" ) {
event = static_cast<Event *>(incidence);
} else {
if ( incidence && incidence->type() == "Todo" ) {
todo = static_cast<Todo *>(incidence);
}
}
if (!event && !todo) {
KMessageBox::sorry(this,i18n("No event selected."));
return;
}
PublishDialog *publishdlg = new PublishDialog();
if (incidence->attendeeCount()>0) {
QPtrList<Attendee> attendees = incidence->attendees();
attendees.first();
while ( attendees.current()!=0 ) {
publishdlg->addAttendee(attendees.current());
attendees.next();
}
}
bool send = true;
if ( KOPrefs::instance()->mMailClient == KOPrefs::MailClientSendmail ) {
if ( publishdlg->exec() != QDialog::Accepted )
send = false;
}
if ( send ) {
OutgoingDialog *dlg = mDialogManager->outgoingDialog();
if ( event ) {
Event *ev = new Event(*event);
ev->registerObserver(0);
ev->clearAttendees();
if (!dlg->addMessage(ev,Scheduler::Publish,publishdlg->addresses())) {
delete(ev);
}
} else {
if ( todo ) {
Todo *ev = new Todo(*todo);
ev->registerObserver(0);
ev->clearAttendees();
if (!dlg->addMessage(ev,Scheduler::Publish,publishdlg->addresses())) {
delete(ev);
}
}
}
}
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_publish_freebusy(int daysToPublish)
{
QDateTime start = QDateTime::currentDateTime();
QDateTime end = start.addDays(daysToPublish);
FreeBusy *freebusy = new FreeBusy(mCalendar, start, end);
freebusy->setOrganizer(KOPrefs::instance()->email());
PublishDialog *publishdlg = new PublishDialog();
if ( publishdlg->exec() == QDialog::Accepted ) {
OutgoingDialog *dlg = mDialogManager->outgoingDialog();
if (!dlg->addMessage(freebusy,Scheduler::Publish,publishdlg->addresses())) {
delete(freebusy);
}
}
delete publishdlg;
}
void CalendarView::schedule(Scheduler::Method method, Incidence *incidence)
{
Event *event = 0;
Todo *todo = 0;
if (incidence == 0) {
incidence = mViewManager->currentView()->selectedIncidences().first();
if (incidence == 0) {
incidence = mTodoList->selectedIncidences().first();
}
}
if ( incidence && incidence->type() == "Event" ) {
event = static_cast<Event *>(incidence);
}
if ( incidence && incidence->type() == "Todo" ) {
todo = static_cast<Todo *>(incidence);
}
if (!event && !todo) {
KMessageBox::sorry(this,i18n("No event selected."));
return;
}
if( incidence->attendeeCount() == 0 && method != Scheduler::Publish ) {
KMessageBox::sorry(this,i18n("The event has no attendees."));
return;
}
Event *ev = 0;
if (event) ev = new Event(*event);
Todo *to = 0;
if (todo) to = new Todo(*todo);
if (method == Scheduler::Reply || method == Scheduler::Refresh) {
Attendee *me = incidence->attendeeByMails(KOPrefs::instance()->mAdditionalMails,KOPrefs::instance()->email());
if (!me) {
KMessageBox::sorry(this,i18n("Could not find your attendee entry.\nPlease check the emails."));
return;
}
if (me->status()==Attendee::NeedsAction && me->RSVP() && method==Scheduler::Reply) {
StatusDialog *statdlg = new StatusDialog(this);
if (!statdlg->exec()==QDialog::Accepted) return;
me->setStatus( statdlg->status() );
delete(statdlg);
}
Attendee *menew = new Attendee(*me);
if (ev) {
ev->clearAttendees();
ev->addAttendee(menew,false);
} else {
if (to) {
todo->clearAttendees();
todo->addAttendee(menew,false);
}
}
}
OutgoingDialog *dlg = mDialogManager->outgoingDialog();
if (ev) {
if ( !dlg->addMessage(ev,method) ) delete(ev);
} else {
if (to) {
if ( !dlg->addMessage(to,method) ) delete(to);
}
}
}
void CalendarView::openAddressbook()
{
KRun::runCommand("kaddressbook");
}
void CalendarView::setModified(bool modified)
{
if ( modified )
emit signalmodified();
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;
}
diff --git a/korganizer/kotodoview.cpp b/korganizer/kotodoview.cpp
index a12acd1..9cafc60 100644
--- a/korganizer/kotodoview.cpp
+++ b/korganizer/kotodoview.cpp
@@ -1,1118 +1,1119 @@
/*
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 <qvbox.h>
#include <kdebug.h>
#include "koprefs.h"
#include <klocale.h>
#include <kglobal.h>
#include <kiconloader.h>
#include <kmessagebox.h>
#include <libkcal/icaldrag.h>
#include <libkcal/vcaldrag.h>
#include <libkcal/calfilter.h>
#include <libkcal/dndfactory.h>
#include <libkcal/calendarresources.h>
#include <libkcal/resourcecalendar.h>
#include <kresources/resourceselectdialog.h>
#ifndef DESKTOP_VERSION
#include <qpe/qpeapplication.h>
#else
#include <qapplication.h>
#endif
#ifndef KORG_NOPRINTER
#include "calprinter.h"
#endif
#include "docprefs.h"
#include "kotodoview.h"
using namespace KOrg;
KOTodoListView::KOTodoListView(Calendar *calendar,QWidget *parent,
const char *name) :
KListView(parent,name)
{
mName = QString ( name );
mCalendar = calendar;
#ifndef DESKTOP_VERSION
QPEApplication::setStylusOperation(viewport(), QPEApplication::RightOnHold );
#endif
mOldCurrent = 0;
mMousePressed = false;
setAcceptDrops(true);
viewport()->setAcceptDrops(true);
int size = 16;
if (qApp->desktop()->width() < 300 )
size = 12;
setTreeStepSize( size + 6 );
}
void KOTodoListView::contentsDragEnterEvent(QDragEnterEvent *e)
{
#ifndef KORG_NODND
// kdDebug() << "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() << "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() << "KOTodoListView::contentsDragLeaveEvent" << endl;
setCurrentItem(mOldCurrent);
setSelected(mOldCurrent,true);
#endif
}
void KOTodoListView::contentsDropEvent(QDropEvent *e)
{
#ifndef KORG_NODND
// kdDebug() << "KOTodoListView::contentsDropEvent" << endl;
if ( !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() << "Drop existing Todo" << endl;
Incidence *to = destinationEvent;
while(to) {
if (to->uid() == todo->uid()) {
KMessageBox::sorry(this,
i18n("Cannot move To-Do to itself or a child of itself"),
i18n("Drop To-Do"));
delete todo;
return;
}
to = to->relatedTo();
}
existingTodo->setRelatedTo(destinationEvent);
emit todoDropped(todo);
delete todo;
} else {
// kdDebug() << "Drop new Todo" << endl;
todo->setRelatedTo(destinationEvent);
mCalendar->addTodo(todo);
emit todoDropped(todo);
}
}
else {
QString text;
if (QTextDrag::decode(e,text)) {
//QListViewItem *qlvi = itemAt( contentsToViewport(e->pos()) );
KOTodoViewItem *todoi = static_cast<KOTodoViewItem *>(itemAt( contentsToViewport(e->pos()) ));
kdDebug() << "Dropped : " << text << endl;
QStringList emails = QStringList::split(",",text);
for(QStringList::ConstIterator it = emails.begin();it!=emails.end();++it) {
kdDebug() << " Email: " << (*it) << endl;
int pos = (*it).find("<");
QString name = (*it).left(pos);
QString email = (*it).mid(pos);
if (!email.isEmpty() && todoi) {
todoi->todo()->addAttendee(new Attendee(name,email));
}
}
}
else {
kdDebug() << "KOTodoListView::contentsDropEvent(): Todo from drop not decodable" << endl;
e->ignore();
}
}
#endif
}
void KOTodoListView::contentsMousePressEvent(QMouseEvent* e)
{
QListView::contentsMousePressEvent(e);
#ifndef KORG_NODND
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;
}
}
}
#endif
}
void KOTodoListView::contentsMouseMoveEvent(QMouseEvent* e)
{
#ifndef KORG_NODND
// kdDebug() << "KOTodoListView::contentsMouseMoveEvent()" << endl;
QListView::contentsMouseMoveEvent(e);
if (mMousePressed && (mPressPos - e->pos()).manhattanLength() >
QApplication::startDragDistance()) {
mMousePressed = false;
QListViewItem *item = itemAt(contentsToViewport(mPressPos));
if (item) {
// kdDebug() << "Start Drag for item " << item->text(0) << endl;
DndFactory factory( mCalendar );
ICalDrag *vd = factory.createDragTodo(
((KOTodoViewItem *)item)->todo(),viewport());
if (vd->drag()) {
kdDebug() << "KOTodoListView::contentsMouseMoveEvent(): Delete drag source" << endl;
}
/*
QString source = fullPath(item);
if ( QFile::exists(source) ) {
QUriDrag* ud = new QUriDrag(viewport());
ud->setFilenames( source );
if ( ud->drag() )
QMessageBox::information( this, "Drag source",
QString("Delete ")+source, "Not implemented" );
*/
}
}
#endif
}
void KOTodoListView::keyPressEvent ( QKeyEvent * e )
{
QListViewItem* cn;
if ( e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter ) {
cn = currentItem();
if ( cn ) {
KOTodoViewItem* ci = (KOTodoViewItem*)( cn );
if ( ci ){
if ( e->state() == ShiftButton )
ci->setOn( false );
else
ci->setOn( true );
cn = cn->nextSibling();
if ( cn ) {
setCurrentItem ( cn );
ensureItemVisible ( cn );
}
}
}
return;
}
// qDebug("KOTodoListView::keyPressEvent ");
if ( e->state() == Qt::ControlButton || e->state() == Qt::ShiftButton || mName != "todolistsmall" ) {
switch ( e->key() ) {
case Qt::Key_Down:
case Qt::Key_Up:
QListView::keyPressEvent ( e );
break;
case Qt::Key_Left:
case Qt::Key_Right:
QListView::keyPressEvent ( e );
e->accept();
return;
break;
default:
e->ignore();
break;
}
return;
}
e->ignore();
}
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);
emit double_Clicked(item);
if (!item) return;
emit doubleClicked(item,vp,0);
}
/////////////////////////////////////////////////////////////////////////////
KOQuickTodo::KOQuickTodo(QWidget *parent) :
QLineEdit(parent)
{
setText(i18n("Click to add a new Todo"));
}
void KOQuickTodo::focusInEvent(QFocusEvent *ev)
{
if ( text()==i18n("Click to add a new Todo") )
setText("");
QLineEdit::focusInEvent(ev);
}
void KOQuickTodo::focusOutEvent(QFocusEvent *ev)
{
setText(i18n("Click to add a new Todo"));
QLineEdit::focusOutEvent(ev);
}
/////////////////////////////////////////////////////////////////////////////
KOTodoView::KOTodoView(Calendar *calendar,QWidget* parent,const char* name) :
KOrg::BaseView(calendar,parent,name)
{
QBoxLayout *topLayout = new QVBoxLayout(this);
mName = QString ( name );
mBlockUpdate = false;
mQuickAdd = new KOQuickTodo(this);
topLayout->addWidget(mQuickAdd);
if ( !KOPrefs::instance()->mEnableQuickTodo ) mQuickAdd->hide();
mTodoListView = new KOTodoListView(calendar,this, name );
topLayout->addWidget(mTodoListView);
//mTodoListView->header()->setMaximumHeight(30);
mTodoListView->setRootIsDecorated(true);
mTodoListView->setAllColumnsShowFocus(true);
mTodoListView->setShowSortIndicator(true);
mTodoListView->addColumn(i18n("Todo"));
mTodoListView->addColumn(i18n("Prio"));
mTodoListView->setColumnAlignment(1,AlignHCenter);
mTodoListView->addColumn(i18n("Complete"));
mTodoListView->setColumnAlignment(2,AlignHCenter);
mTodoListView->addColumn(i18n("Due Date"));
mTodoListView->setColumnAlignment(3,AlignLeft);
mTodoListView->addColumn(i18n("Due Time"));
mTodoListView->setColumnAlignment(4,AlignHCenter);
mTodoListView->addColumn(i18n("Cancelled"));
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->setColumnWidth( 0, 120 );
mTodoListView->setColumnWidthMode(0, QListView::Manual);
mTodoListView->setColumnWidthMode(1, QListView::Manual);
mTodoListView->setColumnWidthMode(2, QListView::Manual);
mTodoListView->setColumnWidthMode(3, QListView::Manual);
mTodoListView->setColumnWidthMode(4, QListView::Manual);
mTodoListView->setColumnWidthMode(5, QListView::Manual);
+ mTodoListView->setColumnWidthMode(6, QListView::Manual);
mTodoListView->setColumnAlignment( 2, AlignCenter );
#if 0
mTodoListView->setColumnWidthMode(6, QListView::Manual);
#endif
mPriorityPopupMenu = new QPopupMenu(this);
for (int i = 1; i <= 5; i++) {
QString label = QString ("%1").arg (i);
mPriority[mPriorityPopupMenu->insertItem (label)] = i;
}
connect (mPriorityPopupMenu, SIGNAL(activated (int)), SLOT (setNewPriority(int)));
mPercentageCompletedPopupMenu = new QPopupMenu(this);
for (int i = 0; i <= 100; i+=20) {
QString label = QString ("%1 %").arg (i);
mPercentage[mPercentageCompletedPopupMenu->insertItem (label)] = i;
}
connect (mPercentageCompletedPopupMenu, SIGNAL (activated (int)), SLOT (setNewPercentage (int)));
mItemPopupMenu = new QPopupMenu(this);
mItemPopupMenu->insertItem(i18n("Show..."), this,
SLOT (showTodo()));
mItemPopupMenu->insertItem(i18n("Edit..."), this,
SLOT (editTodo()));
mItemPopupMenu->insertItem( i18n("Delete"), this,
SLOT (deleteTodo()));
mItemPopupMenu->insertItem( i18n("Clone..."), this,
SLOT (cloneTodo()));
mItemPopupMenu->insertItem( i18n("Move..."), this,
SLOT (moveTodo()));
mItemPopupMenu->insertItem( i18n("Beam..."), this,
SLOT (beamTodo()));
mItemPopupMenu->insertItem( i18n("Toggle Cancel"), this,
SLOT (cancelTodo()));
mItemPopupMenu->insertSeparator();
mItemPopupMenu->insertItem( i18n("New Todo..."), this,
SLOT (newTodo()));
mItemPopupMenu->insertItem(i18n("New Sub-Todo..."), this,
SLOT (newSubTodo()));
mItemPopupMenu->insertItem(i18n("Unparent Todo"), this,
SLOT (unparentTodo()),0,21);
mItemPopupMenu->insertItem(i18n("Reparent Todo"), this,
SLOT (reparentTodo()),0,22);
mItemPopupMenu->insertSeparator();
mItemPopupMenu->insertItem(i18n("Delete completed To-Dos","Purge Completed"),
this, SLOT( purgeCompleted() ) );
mItemPopupMenu->insertItem(i18n("toggle completed To-Dos","Show Completed"),
this, SLOT( toggleCompleted() ),0, 33 );
mItemPopupMenu->insertItem(i18n("toggle quick todo","Show Quick Todo"),
this, SLOT( toggleQuickTodo() ),0, 34 );
mPopupMenu = new QPopupMenu(this);
mPopupMenu->insertItem(SmallIconSet("todo"), i18n("New Todo..."), this,
SLOT (newTodo()),0,1);
mPopupMenu->insertItem(i18n("delete completed To-Dos","Purge Completed"),
this, SLOT(purgeCompleted()),0,2);
mPopupMenu->insertItem(i18n("Show Completed"),
this, SLOT( toggleCompleted() ),0,3 );
mPopupMenu->insertItem(i18n("toggle quick todo","Show Quick Todo"),
this, SLOT( toggleQuickTodo() ),0,4 );
mDocPrefs = new DocPrefs( name );
mPopupMenu->setCheckable( true );
mItemPopupMenu->setCheckable( true );
// Double clicking conflicts with opening/closing the subtree
connect( mTodoListView, SIGNAL( doubleClicked( QListViewItem *) ),
SLOT( editItem( QListViewItem *) ) );
/*
connect( mTodoListView, SIGNAL( rightButtonClicked ( QListViewItem *,
const QPoint &,int ) ),
SLOT( popupMenu( QListViewItem *, const QPoint & ,int) ) );
*/
connect( mTodoListView, SIGNAL( contextRequest ( QListViewItem *,
const QPoint &,int ) ),
SLOT( popupMenu( QListViewItem *, const QPoint & ,int) ) );
connect( mTodoListView, SIGNAL( clicked( QListViewItem * ) ),
SLOT( itemClicked( QListViewItem * ) ) );
connect( mTodoListView, SIGNAL( double_Clicked( QListViewItem * ) ),
SLOT( itemDoubleClicked( QListViewItem * ) ) );
connect( mTodoListView, SIGNAL( todoDropped( Todo * ) ),
SLOT( updateView() ) );
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() ) );
// if ( QApplication::desktop()->width() < 480 ) {
// setNarrow();
// mTodoListView->setColumnWidth( 0, 100 );
// }
}
KOTodoView::~KOTodoView()
{
delete mDocPrefs;
}
void KOTodoView::jumpToDate ()
{
// if (mActiveItem) {
// mActiveItem->todo());
// if ( mActiveItem->todo()->hasDueDate() )
// emit mActiveItem->todo()jumpToTime( mTodo->dtDue().date() );
}
void KOTodoView::setNarrow()
{
//mTodoListView->setColumnWidth( 0, 120 );
mTodoListView->setColumnWidth( 1, 35 );
mTodoListView->setColumnWidth( 2, 40 );
mTodoListView->setColumnWidth( 3, 80 );
mTodoListView->setColumnWidth( 4, 40 );
mTodoListView->setColumnWidth( 5, 90 );
}
void KOTodoView::updateView()
{
pendingSubtodo = 0;
if ( mBlockUpdate ) {
//qDebug("blocked ");
return;
}
//qDebug("update ");
// kdDebug() << "KOTodoView::updateView()" << endl;
QFont fo = KOPrefs::instance()->mTodoViewFont;
mTodoListView->clear();
if ( mName == "todolistsmall" ) {
if ( KOPrefs::instance()->mTodoViewUsesSmallFont ) {
int ps = fo.pointSize() -2;
if ( ps > 12 )
ps -= 2;
fo.setPointSize( ps );
}
}
mTodoListView->setFont( fo );
// QFontMetrics fm ( KOPrefs::instance()->mTodoViewFont );
//mTodoListView->header()->setMaximumHeight(fm.height());
QPtrList<Todo> todoList = calendar()->todos();
/*
kdDebug() << "KOTodoView::updateView(): Todo List:" << endl;
Event *t;
for(t = todoList.first(); t; t = todoList.next()) {
kdDebug() << " " << t->getSummary() << endl;
if (t->getRelatedTo()) {
kdDebug() << " (related to " << t->getRelatedTo()->getSummary() << ")" << endl;
}
QPtrList<Event> l = t->getRelations();
Event *c;
for(c=l.first();c;c=l.next()) {
kdDebug() << " - 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 *todo;
todo = todoList.first();// todo; todo = todoList.next()) {
while ( todo ) {
bool next = true;
// qDebug("todo %s ", todo->summary().latin1());
Incidence *incidence = todo->relatedTo();
while ( incidence ) {
if ( incidence->type() == "Todo") {
//qDebug("related %s ",incidence->summary().latin1() );
if ( !(todoList.contains ( ((Todo* )incidence ) ) )) {
//qDebug("related not found ");
todoList.remove( );
todo = todoList.current();
next = false;
incidence = 0;
} else {
//qDebug("related found ");
incidence = incidence->relatedTo();
}
} else
incidence = 0;
}
if ( next )
todo = todoList.next();
}
// qDebug("again .... ");
// for(todo = todoList.first(); todo; todo = todoList.next()) {
// qDebug("yytodo %s ", todo->summary().latin1());
// }
//qDebug("for ");
for(todo = todoList.first(); todo; todo = todoList.next()) {
if (!mTodoMap.contains(todo) && ( KOPrefs::instance()->mShowCompletedTodo || !todo->isCompleted() ) )
{
insertTodoItem(todo);
}
}
//qDebug("for end ");
// Restore opened/closed state
mTodoListView->blockSignals( true );
if( mDocPrefs ) restoreItemState( mTodoListView->firstChild() );
mTodoListView->blockSignals( false );
mTodoListView->setFocus();
processSelectionChange();
}
void KOTodoView::restoreItemState( QListViewItem *item )
{
pendingSubtodo = 0;
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() << "KOTodoView::insertTodoItem(): " << todo->getSummary() << endl;
// TODO: Check, if dynmaic cast is necessary
pendingSubtodo = 0;
Incidence *incidence = todo->relatedTo();
if (incidence && incidence->type() == "Todo") {
Todo *relatedTodo = static_cast<Todo *>(incidence);
// kdDebug() << " has Related" << endl;
QMap<Todo *,KOTodoViewItem *>::ConstIterator itemIterator;
itemIterator = mTodoMap.find(relatedTodo);
if (itemIterator == mTodoMap.end()) {
// kdDebug() << " 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 = new KOTodoViewItem(*itemIterator,todo,this);
return mTodoMap.insert(todo,todoItem);
} else {
// kdDebug() << " no Related" << endl;
// see above -zecke
KOTodoViewItem *todoItem = new KOTodoViewItem(mTodoListView,todo,this);
return mTodoMap.insert(todo,todoItem);
}
}
void KOTodoView::updateConfig()
{
updateView();
mTodoListView->repaintContents();
}
QPtrList<Incidence> KOTodoView::selectedIncidences()
{
QPtrList<Incidence> selected;
KOTodoViewItem *item = (KOTodoViewItem *)(mTodoListView->selectedItem());
// if (!item) item = mActiveItem;
if (item) selected.append(item->todo());
return selected;
}
QPtrList<Todo> KOTodoView::selectedTodos()
{
QPtrList<Todo> selected;
KOTodoViewItem *item = (KOTodoViewItem *)(mTodoListView->selectedItem());
// if (!item) item = mActiveItem;
if (item) selected.append(item->todo());
return selected;
}
void KOTodoView::changeEventDisplay(Event *, int)
{
updateView();
}
void KOTodoView::showDates(const QDate &, const QDate &)
{
}
void KOTodoView::showEvents(QPtrList<Event>)
{
kdDebug() << "KOTodoView::selectEvents(): not yet implemented" << endl;
}
void KOTodoView::printPreview(CalPrinter *calPrinter, const QDate &fd,
const QDate &td)
{
#ifndef KORG_NOPRINTER
calPrinter->preview(CalPrinter::Todolist, fd, td);
#endif
}
void KOTodoView::editItem(QListViewItem *item )
{
// qDebug("editItem(QListViewItem *item ) ");
emit editTodoSignal(((KOTodoViewItem *)item)->todo());
}
void KOTodoView::showItem(QListViewItem *item,const QPoint &,int)
{
emit showTodoSignal(((KOTodoViewItem *)item)->todo());
}
void KOTodoView::popupMenu(QListViewItem *item,const QPoint &,int column)
{
pendingSubtodo = 0;
mActiveItem = (KOTodoViewItem *)item;
if (item) {
switch (column){
case 1:
mPriorityPopupMenu->popup(QCursor::pos ()); break;
case 2:
mPercentageCompletedPopupMenu->popup(QCursor::pos ()); break;
case 3:
moveTodo();
break;
case 6:
getCategoryPopupMenu((KOTodoViewItem *)item)->popup(QCursor::pos ()); break;
default:
mItemPopupMenu->popup(QCursor::pos());
}
} else mPopupMenu->popup(QCursor::pos());
}
void KOTodoView::newTodo()
{
emit newTodoSignal();
}
void KOTodoView::newSubTodo()
{
if (mActiveItem) {
emit newSubTodoSignal(mActiveItem->todo());
}
}
void KOTodoView::unparentTodo()
{
if (mActiveItem) {
emit unparentTodoSignal(mActiveItem->todo());
}
}
void KOTodoView::reparentTodo()
{
if (mActiveItem) {
qDebug("KOTodoView::reparentTodo() ");
topLevelWidget()->setCaption(i18n("Click on new parent item"));
pendingSubtodo = mActiveItem;
}
}
void KOTodoView::editTodo()
{
if (mActiveItem) {
emit editTodoSignal(mActiveItem->todo());
}
}
void KOTodoView::cloneTodo()
{
if (mActiveItem) {
emit cloneTodoSignal((Incidence*)mActiveItem->todo());
}
}
void KOTodoView::cancelTodo()
{
if (mActiveItem) {
emit cancelTodoSignal((Incidence*)mActiveItem->todo());
}
}
void KOTodoView::moveTodo()
{
if (mActiveItem) {
emit moveTodoSignal((Incidence*)mActiveItem->todo());
}
}
void KOTodoView::beamTodo()
{
if (mActiveItem) {
emit beamTodoSignal((Incidence*)mActiveItem->todo());
}
}
void KOTodoView::showTodo()
{
if (mActiveItem) {
emit showTodoSignal(mActiveItem->todo());
}
}
void KOTodoView::deleteTodo()
{
if (mActiveItem) {
if (mActiveItem->childCount()) {
KMessageBox::sorry(this,i18n("Cannot delete To-Do which has children."),
i18n("Delete To-Do"));
} else {
emit deleteTodoSignal(mActiveItem->todo());
}
}
}
void KOTodoView::setNewPriority(int index)
{
if (mActiveItem && !mActiveItem->todo()->isReadOnly ()) {
mActiveItem->todo()->setPriority(mPriority[index]);
mActiveItem->construct();
todoModified (mActiveItem->todo(), KOGlobals::PRIORITY_MODIFIED);
mActiveItem->todo()->setRevision( mActiveItem->todo()->revision()+1 );
}
}
void KOTodoView::setNewPercentage(int index)
{
if (mActiveItem && !mActiveItem->todo()->isReadOnly ()) {
if (mPercentage[index] == 100) {
mActiveItem->todo()->setCompleted(QDateTime::currentDateTime());
} else {
mActiveItem->todo()->setCompleted(false);
}
mActiveItem->todo()->setPercentComplete(mPercentage[index]);
mActiveItem->construct();
todoModified (mActiveItem->todo (), KOGlobals::COMPLETION_MODIFIED);
mActiveItem->todo()->setRevision( mActiveItem->todo()->revision()+1 );
}
}
QPopupMenu * KOTodoView::getCategoryPopupMenu (KOTodoViewItem *todoItem)
{
QPopupMenu* tempMenu = new QPopupMenu (this);
QStringList checkedCategories = todoItem->todo()->categories ();
tempMenu->setCheckable (true);
for (QStringList::Iterator 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 && !mActiveItem->todo()->isReadOnly ()) {
QStringList categories = mActiveItem->todo()->categories ();
if (categories.find (mCategory[index]) != categories.end ())
categories.remove (mCategory[index]);
else
categories.insert (categories.end(), mCategory[index]);
categories.sort ();
mActiveItem->todo()->setCategories (categories);
mActiveItem->construct();
mActiveItem->todo()->setRevision( mActiveItem->todo()->revision()+1 );
todoModified (mActiveItem->todo (), KOGlobals::CATEGORY_MODIFIED);
}
}
void KOTodoView::itemDoubleClicked(QListViewItem *item)
{
if ( pendingSubtodo != 0 ) {
topLevelWidget()->setCaption(i18n("Reparenting aborted!"));
}
pendingSubtodo = 0;
if (!item) {
newTodo();
return;
}
if ( KOPrefs::instance()->mEditOnDoubleClick )
editItem( item );
else
showItem( item , QPoint(), 0 );
}
void KOTodoView::itemClicked(QListViewItem *item)
{
if (!item) {
if ( pendingSubtodo != 0 ) {
topLevelWidget()->setCaption(i18n("Reparenting aborted!"));
}
pendingSubtodo = 0;
return;
}
KOTodoViewItem *todoItem = (KOTodoViewItem *)item;
if ( pendingSubtodo != 0 ) {
bool allowReparent = true;
QListViewItem *par = item;
while ( par ) {
if ( par == pendingSubtodo ) {
allowReparent = false;
break;
}
par = par->parent();
}
if ( !allowReparent ) {
topLevelWidget()->setCaption(i18n("Recursive reparenting not possible!"));
qDebug("Recursive reparenting not possible ");
pendingSubtodo = 0;
} else {
Todo* newParent = todoItem->todo();
Todo* newSub = pendingSubtodo->todo();
pendingSubtodo = 0;
emit reparentTodoSignal( newParent,newSub );
return;
}
}
int completed = todoItem->todo()->isCompleted(); // Completed or not?
if (todoItem->isOn()) {
if (!completed) {
todoItem->todo()->setCompleted(QDateTime::currentDateTime());
}
} else {
if (completed) {
todoItem->todo()->setCompleted(false);
}
}
}
void KOTodoView::setDocumentId( const QString &id )
{
kdDebug() << "KOTodoView::setDocumentId()" << endl;
mDocPrefs->setDoc( id );
}
void KOTodoView::itemStateChanged( QListViewItem *item )
{
if (!item) return;
KOTodoViewItem *todoItem = (KOTodoViewItem *)item;
// kdDebug() << "KOTodoView::itemStateChanged(): " << todoItem->todo()->summary() << endl;
if( mDocPrefs ) mDocPrefs->writeEntry( todoItem->todo()->uid(), todoItem->isOpen() );
}
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() << "KOTodoView::processSelectionChange()" << endl;
KOTodoViewItem *item =
static_cast<KOTodoViewItem *>( mTodoListView->selectedItem() );
if ( !item ) {
emit incidenceSelected( 0 );
} else {
emit incidenceSelected( item->todo() );
}
}
void KOTodoView::modified(bool b)
{
emit isModified(b);
}
void KOTodoView::setTodoModified( Todo* todo )
{
todoModified( todo, KOGlobals::UNKNOWN_MODIFIED );
}
void KOTodoView::clearSelection()
{
mTodoListView->selectAll( false );
}
void KOTodoView::purgeCompleted()
{
emit purgeCompletedSignal();
}
void KOTodoView::toggleQuickTodo()
{
if ( mQuickAdd->isVisible() ) {
mQuickAdd->hide();
KOPrefs::instance()->mEnableQuickTodo = false;
}
else {
mQuickAdd->show();
KOPrefs::instance()->mEnableQuickTodo = true;
}
mPopupMenu->setItemChecked(4,KOPrefs::instance()->mEnableQuickTodo);
mItemPopupMenu->setItemChecked( 34 , KOPrefs::instance()->mEnableQuickTodo );
}
void KOTodoView::toggleCompleted()
{
KOPrefs::instance()->mShowCompletedTodo = !KOPrefs::instance()->mShowCompletedTodo;
mPopupMenu->setItemChecked( 3,KOPrefs::instance()->mShowCompletedTodo );
mItemPopupMenu->setItemChecked( 33 , KOPrefs::instance()->mShowCompletedTodo );
updateView();
}
void KOTodoView::addQuickTodo()
{
Todo *todo = new Todo();
todo->setSummary(mQuickAdd->text());
todo->setOrganizer(KOPrefs::instance()->email());
CalFilter * cf = mCalendar->filter();
if ( cf ) {
if ( cf->isEnabled()&& cf->showCategories()) {
todo->setCategories(cf->categoryList());
}
if ( cf->isEnabled() )
todo->setSecrecy( cf->getSecrecy());
}
mCalendar->addTodo(todo);
mQuickAdd->setText("");
todoModified (todo, KOGlobals::EVENTADDED );
updateView();
}
void KOTodoView::keyPressEvent ( QKeyEvent * e )
{
// e->ignore();
//return;
//qDebug("KOTodoView::keyPressEvent ");
switch ( e->key() ) {
case Qt::Key_Down:
case Qt::Key_Up:
QWidget::keyPressEvent ( e );
break;
case Qt::Key_Q:
toggleQuickTodo();
break;
case Qt::Key_U:
if ( e->state() == Qt::ControlButton|| e->state() == Qt::ShiftButton ) {
mActiveItem = (KOTodoViewItem*)mTodoListView->currentItem();
unparentTodo();
e->accept();
} else
e->ignore();
break;
case Qt::Key_S:
if ( e->state() == Qt::ControlButton|| e->state() == Qt::ShiftButton ) {
mActiveItem = (KOTodoViewItem*)mTodoListView->currentItem();
reparentTodo();
e->accept();
} else
e->ignore();
break;
case Qt::Key_P:
if ( e->state() == Qt::ControlButton|| e->state() == Qt::ShiftButton ) {
mActiveItem = (KOTodoViewItem*)mTodoListView->currentItem();
if ( pendingSubtodo )
itemClicked(mActiveItem);
e->accept();
} else
e->ignore();
break;
case Qt::Key_Escape:
if ( pendingSubtodo ) {
itemClicked(0);
e->accept();
} else
e->ignore();
break;
default:
e->ignore();
}
if ( true ) {
if ( e->key() == Qt::Key_I ) {
KOTodoViewItem*cn = (KOTodoViewItem*)mTodoListView->currentItem();
if ( cn ) {
mActiveItem = cn;
KOTodoViewItem* ci = (KOTodoViewItem*)( cn );
if ( ci ){
showTodo();
cn = (KOTodoViewItem*)cn->itemBelow();
if ( cn ) {
mTodoListView->setCurrentItem ( cn );
mTodoListView->ensureItemVisible ( cn );
}
}
}
e->accept();
}
}
}
void KOTodoView::updateTodo( Todo * t, int type )
{
if ( mBlockUpdate)
return;
QMap<Todo *,KOTodoViewItem *>::ConstIterator itemIterator;
itemIterator = mTodoMap.find(t);
if (itemIterator != mTodoMap.end()) {
(*itemIterator)->construct();
} else {
if ( type == KOGlobals::EVENTADDED ) {
insertTodoItem( t );
}
}
}
void KOTodoView::todoModified(Todo * t , int p )
{
mBlockUpdate = true;
emit todoModifiedSignal ( t, p );
mBlockUpdate = false;
}
diff --git a/korganizer/kotodoviewitem.cpp b/korganizer/kotodoviewitem.cpp
index 85647b1..ae0b334 100644
--- a/korganizer/kotodoviewitem.cpp
+++ b/korganizer/kotodoviewitem.cpp
@@ -1,432 +1,432 @@
/*
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <klocale.h>
#include <kdebug.h>
#include <qapp.h>
#include <kiconloader.h>
#include "kotodoviewitem.h"
#include "kotodoview.h"
#include "koprefs.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();
}
QString KOTodoViewItem::key(int column,bool) const
{
QMap<int,QString>::ConstIterator it = mKeyMap.find(column);
if (it == mKeyMap.end()) {
- return text(column);
+ return text(column).lower();
} else {
return *it;
}
}
void KOTodoViewItem:: setup()
{
int h = 20;
if ( listView () ) {
QFontMetrics fm ( listView ()->font () );
h = fm.height();
}
setHeight( h );
}
void KOTodoViewItem::setSortKey(int column,const QString &key)
{
mKeyMap.insert(column,key);
}
#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()
{
// qDebug("KOTodoViewItem::construct() ");
m_init = true;
QString keyd = "==";
QString keyt = "==";
setOn(mTodo->isCompleted());
setText(0,mTodo->summary());
setText(1,QString::number(mTodo->priority()));
setText(2,i18n("%1 %").arg(QString::number(mTodo->percentComplete())));
if (mTodo->percentComplete()<100) {
if (mTodo->isCompleted()) setSortKey(2,QString::number(999));
else setSortKey(2,QString::number(mTodo->percentComplete()));
}
else {
if (mTodo->isCompleted()) setSortKey(2,QString::number(999));
else setSortKey(2,QString::number(99));
}
if (mTodo->hasDueDate()) {
setText(3, mTodo->dtDueDateStr());
QDate d = mTodo->dtDue().date();
keyd.sprintf("%04d%02d%02d",d.year(),d.month(),d.day());
setSortKey(3,keyd);
if (mTodo->doesFloat()) {
setText(4,"");
}
else {
setText(4,mTodo->dtDueTimeStr());
QTime t = mTodo->dtDue().time();
keyt.sprintf("%02d%02d",t.hour(),t.minute());
setSortKey(4,keyt);
}
} else {
setText(3,"");
setText(4,"");
}
setSortKey(3,keyd);
setSortKey(4,keyt);
if (mTodo->isCompleted()) setSortKey(1,"6" + QString::number(mTodo->priority())+keyd+keyt);
else setSortKey(1,QString::number(mTodo->priority())+keyd+keyt);
setText(5,mTodo->cancelled() ? i18n("Yes") : i18n("No"));
setText(6,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(6,"");
} else {
QString str = mTodo->description().mid(pos+1);
str.stripWhiteSpace();
setText(6,str);
}
#endif
m_known = false;
m_init = false;
setMyPixmap();
}
void KOTodoViewItem::setMyPixmap()
{
int size = 5;
QPixmap pixi = QPixmap( 1, 1 );
// if ( !mTodo->isCompleted() && mTodo->hasDueDate() && mTodo->dtDue() < QDateTime::currentDateTime() ) {
// pixi = SmallIcon("redcross16");
// } else {
QPainter p;
int pixSize = 0;
QPixmap pPix = QPixmap( size, size );
if ( mTodo->description().length() > 0 ) {
pixi.resize(size, pixSize+size);
pPix.fill( Qt::darkGreen );
p.begin( &pixi );
p. drawPixmap ( 0, pixSize, pPix);
p.end();
pixSize += size;
}
if ( mTodo->isAlarmEnabled() ) {
pixi.resize(size, pixSize+size);
pPix.fill( Qt::red );
p.begin( &pixi );
p. drawPixmap ( 0, pixSize, pPix);
p.end();
pixSize += size;
}
// }
if ( pixi.width() > 1 ) {
setPixmap ( 0,pixi ) ;
}
}
void KOTodoViewItem::stateChange(bool state)
{
// qDebug("KOTodoViewItem::stateChange ");
// do not change setting on startup
if ( m_init ) return;
kdDebug() << "State changed, modified " << state << endl;
QString keyd = "==";
QString keyt = "==";
if (state) mTodo->setCompleted(state);
else mTodo->setPercentComplete(0);
if (isOn()!=state) {
setOn(state);
}
if (mTodo->hasDueDate()) {
setText(3, mTodo->dtDueDateStr());
QDate d = mTodo->dtDue().date();
keyd.sprintf("%04d%02d%02d",d.year(),d.month(),d.day());
setSortKey(3,keyd);
if (mTodo->doesFloat()) {
setText(4,"");
}
else {
setText(4,mTodo->dtDueTimeStr());
QTime t = mTodo->dtDue().time();
keyt.sprintf("%02d%02d",t.hour(),t.minute());
setSortKey(4,keyt);
}
}
if (mTodo->isCompleted()) setSortKey(1,QString::number(9)+keyd+keyt);
else setSortKey(1,QString::number(mTodo->priority())+keyd+keyt);
setText(2,i18n("%1 %").arg(QString::number(mTodo->percentComplete())));
if (mTodo->percentComplete()<100) {
if (mTodo->isCompleted()) setSortKey(2,QString::number(999));
else setSortKey(2,QString::number(mTodo->percentComplete()));
}
else {
if (mTodo->isCompleted()) setSortKey(2,QString::number(999));
else setSortKey(2,QString::number(99));
}
QListViewItem * myChild = firstChild();
KOTodoViewItem *item;
while( myChild ) {
item = static_cast<KOTodoViewItem*>(myChild);
item->stateChange(state);
myChild = myChild->nextSibling();
}
mTodoView->modified(true);
mTodoView->setTodoModified( mTodo );
setMyPixmap();
}
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;
QColorGroup::ColorRole role;
if ( KOPrefs::instance()->mTodoViewUsesForegroundColor )
role = QColorGroup::Text;
else
role = QColorGroup::Base;
//#ifndef KORG_NOLVALTERNATION
// if (isAlternate())
// _cg.setColor(QColorGroup::Base, static_cast< KOTodoListView* >(listView())->alternateBackground());
bool setColor = KOPrefs::instance()->mTodoViewUsesCatColors;
QColor colorToSet;
if ( setColor ) {
QStringList categories = mTodo->categories();
QString cat = categories.first();
if ( !cat.isEmpty()) {
colorToSet = *(KOPrefs::instance()->categoryColor(cat) );
} else
setColor = false;
}
if (mTodo->hasDueDate()) {
if (mTodo->dtDue().date()==QDate::currentDate() &&
!mTodo->isCompleted()) {
//_cg.setColor( role , KOPrefs::instance()->mTodoDueTodayColor);
colorToSet = KOPrefs::instance()->mTodoDueTodayColor;
setColor = true;
}
if (mTodo->dtDue().date() < QDate::currentDate() &&
!mTodo->isCompleted()) {
//_cg.setColor( role, KOPrefs::instance()->mTodoOverdueColor);
colorToSet = KOPrefs::instance()->mTodoOverdueColor;
setColor = true;
}
}
if ( setColor ) {
_cg.setColor(role,colorToSet );
if ( role == QColorGroup::Base) {
int rgb = colorToSet.red();
rgb += colorToSet.blue()/2;
rgb += colorToSet.green();
if ( rgb < 200 )
_cg.setColor(QColorGroup::Text,Qt::white );
}
}
//#endif
if ( column > 0 ){
if ( column == 2 && !KOPrefs::instance()->mTodoViewShowsPercentage ) {
p->save();
int progress = (int)(( (width-6)*mTodo->percentComplete())/100.0 + 0.5);
p->fillRect( 0, 0, width, height(), _cg.base() ); // background
// p->setPen(Qt::black ); //border
// p->setBrush( KOPrefs::instance()->mHighlightColorKGlobalSettings::baseColor() ); //filling
QColor fc = KOPrefs::instance()->mHighlightColor;
if ( mTodo->percentComplete() == 100 )
fc = darkGreen;
p->drawRect( 2, 2, width-4, height()-4);
p->fillRect( 3, 3, progress, height()-6,
fc );
p->restore();
} else {
QCheckListItem::paintCell(p, _cg, column, width, alignment);
}
return;
}
int align = alignment;
if ( !p )
return;
p->fillRect( 0, 0, width, height(), _cg.brush( QColorGroup::Base ) );
QListView *lv = listView();
if ( !lv )
return;
int marg = 2;//lv->itemMargin();
int r = 0;
QCheckListItem::Type myType = QCheckListItem::CheckBox;
int BoxSize = 20;
int boxOffset = 2;
int xOffset = 2;
if (qApp->desktop()->width() < 300 ) {
BoxSize = 14;
boxOffset = -1;
xOffset = 1;
// marg = 0;
}
if ( height() < BoxSize ) {
boxOffset = boxOffset - ((BoxSize - height())/2) ;
// qDebug("boxOffset %d height %d", boxOffset, height() );
BoxSize = height();
}
//bool winStyle = lv->style() == WindowsStyle;
int lineStart = 5;
if ( myType == Controller ) {
if ( !pixmap( 0 ) )
r += BoxSize + 4;
} else {
ASSERT( lv ); //###
// QFontMetrics fm( lv->font() );
// int d = fm.height();
int x = 0;
int y = (height() - BoxSize) / 2;
// p->setPen( QPen( _cg.text(), winStyle ? 2 : 1 ) );
if ( myType == CheckBox ) {
if ( isEnabled() )
p->setPen( QPen( _cg.text(), 1 ) );
else
p->setPen( QPen( listView()->palette().color( QPalette::Disabled, QColorGroup::Text ), 1 ) );
p->drawRect( x+marg, y+2, BoxSize-4, BoxSize-4 );
lineStart = x+marg;
/////////////////////
x++;
y++;
if ( isOn() ) {
QPointArray a( 7*2 );
int i, xx, yy;
xx = x+xOffset+marg+(boxOffset/2);
yy = y+5+boxOffset;
for ( i=0; i<3; i++ ) {
a.setPoint( 2*i, xx, yy );
a.setPoint( 2*i+1, xx, yy+2 );
// qDebug(" ");
xx++; yy++;
}
yy -= 2;
for ( i=3; i<7; i++ ) {
a.setPoint( 2*i, xx, yy );
a.setPoint( 2*i+1, xx, yy+2 );
xx++; yy--;
}
p->setPen( darkGreen );
p->drawLineSegments( a );
}
////////////////////////
}
r += BoxSize + 4;
}
p->translate( r, 0 );
p->setPen( QPen( _cg.text() ) );
QListViewItem::paintCell( p, _cg, column, width - r, align );
if ( mTodo->cancelled () ) {
p->setPen( black );
QRect br = p->boundingRect( 1,1,1,1,0,mTodo->summary() );
int wid = br.width() +lineStart;
if ( wid > width-3 )
wid = width-3;
p->drawLine( lineStart, height()/2+1, wid, height()/2+1 );
}
}
diff --git a/libkcal/sharpformat.cpp b/libkcal/sharpformat.cpp
index 24b8349..c2ee2c9 100644
--- a/libkcal/sharpformat.cpp
+++ b/libkcal/sharpformat.cpp
@@ -1,1009 +1,1012 @@
/*
This file is part of libkcal.
Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
#include <qdatetime.h>
#include <qstring.h>
#include <qapplication.h>
#include <qptrlist.h>
#include <qregexp.h>
#include <qmessagebox.h>
#include <qclipboard.h>
#include <qfile.h>
#include <qtextstream.h>
#include <qtextcodec.h>
#include <qxml.h>
#include <qlabel.h>
#include <kdebug.h>
#include <klocale.h>
#include <kglobal.h>
#include "calendar.h"
#include "alarm.h"
#include "recurrence.h"
#include "calendarlocal.h"
#include "sharpformat.h"
#include "syncdefines.h"
using namespace KCal;
//CARDID,CATEGORY,DSRP,PLCE,MEM1,TIM1,TIM2,ADAY,ARON,ARMN,ARSD,RTYP,RFRQ,RPOS,RDYS,REND,REDT,ALSD,ALED,MDAY
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
//ARSD silentalarm = 0
// 11 RTYP 225 no /0 dialy/ 1 weekly/ 3 month by date/ 2 month by day(pos)/ yearly
// 12 RFRQ
// 13 RPOS pos = 4. monday in month
// 14 RDYS days: 1 mon/ 2 tue .. 64 sun
// 15 REND 0 = no end/ 1 = end
// 16 REDT rec end dt
//ALSD
//ALED
//MDAY
class SharpParser : public QObject
{
public:
SharpParser( Calendar *calendar ) : mCalendar( calendar ) {
}
bool startElement( Calendar *existingCalendar, const QStringList & attList, QString qName )
{
int i = 1;
bool skip = true;
int max = attList.count() -2;
while ( i < max ) {
if ( !attList[i].isEmpty() ) {
skip = false;
break;
}
++i ;
}
if ( skip )
return false;
ulong cSum = SharpFormat::getCsum(attList );
if ( qName == "Event" ) {
Event *event;
event = existingCalendar->event( "Sharp_DTM",attList[0] );
if ( event )
event = (Event*)event->clone();
else
event = new Event;
event->setID("Sharp_DTM", attList[0] );
event->setCsum( "Sharp_DTM", QString::number( cSum ));
event->setTempSyncStat(SYNC_TEMPSTATE_NEW_EXTERNAL );
event->setSummary( attList[2] );
event->setLocation( attList[3] );
event->setDescription( attList[4] );
if ( attList[7] == "1" ) {
event->setDtStart( QDateTime(fromString( attList[17]+"T000000", false ).date(),QTime(0,0,0 ) ));
event->setDtEnd( QDateTime(fromString( attList[18]+"T000000", false ).date(),QTime(0,0,0 )));
event->setFloats( true );
} else {
event->setFloats( false );
event->setDtStart( fromString( attList[5] ) );
event->setDtEnd( fromString( attList[6] ));
}
QString rtype = attList[11];
if ( rtype != "255" ) {
// qDebug("recurs ");
QDate startDate = event->dtStart().date();
QString freqStr = attList[12];
int freq = freqStr.toInt();
QString hasEndDateStr = attList[15] ;
bool hasEndDate = hasEndDateStr == "1";
QString endDateStr = attList[16];
QDate endDate = fromString( endDateStr ).date();
QString weekDaysStr = attList[14];
uint weekDaysNum = weekDaysStr.toInt();
QBitArray weekDays( 7 );
int i;
int bb = 1;
for( i = 1; i <= 7; ++i ) {
weekDays.setBit( i - 1, ( bb & weekDaysNum ));
bb = 2 << (i-1);
//qDebug(" %d bit %d ",i-1,weekDays.at(i-1) );
}
// qDebug("next ");
QString posStr = attList[13];
int pos = posStr.toInt();
Recurrence *r = event->recurrence();
if ( rtype == "0" ) {
if ( hasEndDate ) r->setDaily( freq, endDate );
else r->setDaily( freq, -1 );
} else if ( rtype == "1" ) {
if ( hasEndDate ) r->setWeekly( freq, weekDays, endDate );
else r->setWeekly( freq, weekDays, -1 );
} else if ( rtype == "3" ) {
if ( hasEndDate )
r->setMonthly( Recurrence::rMonthlyDay, freq, endDate );
else
r->setMonthly( Recurrence::rMonthlyDay, freq, -1 );
r->addMonthlyDay( startDate.day() );
} else if ( rtype == "2" ) {
if ( hasEndDate )
r->setMonthly( Recurrence::rMonthlyPos, freq, endDate );
else
r->setMonthly( Recurrence::rMonthlyPos, freq, -1 );
QBitArray days( 7 );
days.fill( false );
days.setBit( startDate.dayOfWeek() - 1 );
r->addMonthlyPos( pos, days );
} else if ( rtype == "4" ) {
if ( hasEndDate )
r->setYearly( Recurrence::rYearlyMonth, freq, endDate );
else
r->setYearly( Recurrence::rYearlyMonth, freq, -1 );
r->addYearlyNum( startDate.month() );
}
} else {
event->recurrence()->unsetRecurs();
}
QString categoryList = attList[1] ;
event->setCategories( categoryList );
// strange 0 semms to mean: alarm enabled
if ( attList[8] == "0" ) {
Alarm *alarm;
if ( event->alarms().count() > 0 )
alarm = event->alarms().first();
else {
alarm = new Alarm( event );
event->addAlarm( alarm );
alarm->setType( Alarm::Audio );
}
//alarm->setType( Alarm::Audio );
alarm->setEnabled( true );
int alarmOffset = attList[9].toInt();
alarm->setStartOffset( alarmOffset * -60 );
} else {
Alarm *alarm;
if ( event->alarms().count() > 0 ) {
alarm = event->alarms().first();
alarm->setType( Alarm::Audio );
alarm->setStartOffset( -60*15 );
alarm->setEnabled( false );
}
}
mCalendar->addEvent( event);
} else if ( qName == "Todo" ) {
Todo *todo;
todo = existingCalendar->todo( "Sharp_DTM", attList[0] );
if (todo )
todo = (Todo*)todo->clone();
else
todo = new Todo;
//CARDID,CATEGORY,ETDY,LTDY,FNDY,MARK,PRTY,TITL,MEM1
// 0 1 2 3 4 5 6 7 8
//1,,,,,1,4,Loch zumachen,""
//3,Privat,20040317T000000,20040318T000000,20040319T000000,0,5,Call bbb,"notes123 bbb gggg ""bb "" "
//2,"Familie,Freunde,Holiday",20040318T000000,20040324T000000,20040317T000000,1,2,tod2,notes
todo->setID( "Sharp_DTM", attList[0]);
todo->setCsum( "Sharp_DTM", QString::number( cSum ));
todo->setTempSyncStat( SYNC_TEMPSTATE_NEW_EXTERNAL );
todo->setSummary( attList[7] );
todo->setDescription( attList[8]);
int priority = attList[6].toInt();
if ( priority == 0 ) priority = 3;
todo->setPriority( priority );
QString categoryList = attList[1];
todo->setCategories( categoryList );
QString hasDateStr = attList[3]; // due
if ( !hasDateStr.isEmpty() ) {
if ( hasDateStr.right(6) == "000000" ) {
todo->setDtDue( QDateTime(fromString( hasDateStr, false ).date(), QTime(0,0,0 )) );
todo->setFloats( true );
}
else {
todo->setDtDue( fromString( hasDateStr ) );
todo->setFloats( false );
}
todo->setHasDueDate( true );
}
hasDateStr = attList[2];//start
if ( !hasDateStr.isEmpty() ) {
todo->setDtStart( fromString( hasDateStr ) );
todo->setHasStartDate( true);
} else
todo->setHasStartDate( false );
hasDateStr = attList[4];//completed
if ( !hasDateStr.isEmpty() ) {
todo->setCompleted(fromString( hasDateStr ) );
}
QString completedStr = attList[5];
if ( completedStr == "0" )
todo->setCompleted( true );
- else
- todo->setCompleted( false );
+ else {
+ // do not change percent complete
+ if ( todo->isCompleted() )
+ todo->setCompleted( false );
+ }
mCalendar->addTodo( todo );
} else if ( qName == "Category" ) {
/*
QString id = attributes.value( "id" );
QString name = attributes.value( "name" );
setCategory( id, name );
*/
}
//qDebug("end ");
return true;
}
QDateTime fromString ( QString s, bool useTz = true ) {
QDateTime dt;
int y,m,t,h,min,sec;
y = s.mid(0,4).toInt();
m = s.mid(4,2).toInt();
t = s.mid(6,2).toInt();
h = s.mid(9,2).toInt();
min = s.mid(11,2).toInt();
sec = s.mid(13,2).toInt();
dt = QDateTime(QDate(y,m,t), QTime(h,min,sec));
int offset = KGlobal::locale()->localTimeOffset( dt );
if ( useTz )
dt = dt.addSecs ( offset*60);
return dt;
}
protected:
QDateTime toDateTime( const QString &value )
{
QDateTime dt;
dt.setTime_t( value.toUInt() );
return dt;
}
private:
Calendar *mCalendar;
};
SharpFormat::SharpFormat()
{
}
SharpFormat::~SharpFormat()
{
}
ulong SharpFormat::getCsum( const QStringList & attList)
{
int max = attList.count() -1;
ulong cSum = 0;
int j,k,i;
int add;
for ( i = 1; i < max ; ++i ) {
QString s = attList[i];
if ( ! s.isEmpty() ){
j = s.length();
for ( k = 0; k < j; ++k ) {
int mul = k +1;
add = s[k].unicode ();
if ( k < 16 )
mul = mul * mul;
add = add * mul *i*i*i;
cSum += add;
}
}
}
return cSum;
}
#include <stdlib.h>
#define DEBUGMODE false
//#define DEBUGMODE true
bool SharpFormat::load( Calendar *calendar, Calendar *existngCal )
{
bool debug = DEBUGMODE;
QString text;
QString codec = "utf8";
QLabel status ( i18n("Reading events ..."), 0 );
int w = status.sizeHint().width()+20 ;
if ( w < 200 ) w = 200;
int h = status.sizeHint().height()+20 ;
int dw = QApplication::desktop()->width();
int dh = QApplication::desktop()->height();
status.setCaption(i18n("Reading DTM Data") );
status.setGeometry( (dw-w)/2, (dh - h )/2 ,w,h );
status.show();
status.raise();
qApp->processEvents();
QString fileName;
if ( ! debug ) {
fileName = "/tmp/kopitempout";
QString command ="db2file datebook -r -c "+ codec + " > " + fileName;
system ( command.latin1() );
} else {
fileName = "/tmp/events.txt";
}
QFile file( fileName );
if (!file.open( IO_ReadOnly ) ) {
return false;
}
QTextStream ts( &file );
ts.setCodec( QTextCodec::codecForName("utf8") );
text = ts.read();
file.close();
status.setText( i18n("Processing events ...") );
status.raise();
qApp->processEvents();
fromString2Cal( calendar, existngCal, text, "Event" );
status.setText( i18n("Reading todos ...") );
qApp->processEvents();
if ( ! debug ) {
fileName = "/tmp/kopitempout";
QString command = "db2file todo -r -c " + codec+ " > " + fileName;
system ( command.latin1() );
} else {
fileName = "/tmp/todo.txt";
}
file.setName( fileName );
if (!file.open( IO_ReadOnly ) ) {
return false;
}
ts.setDevice( &file );
text = ts.read();
file.close();
status.setText( i18n("Processing todos ...") );
status.raise();
qApp->processEvents();
fromString2Cal( calendar, existngCal, text, "Todo" );
return true;
}
int SharpFormat::getNumFromRecord( QString answer, Incidence* inc )
{
int retval = -1;
QStringList templist;
QString tempString;
int start = 0;
int len = answer.length();
int end = answer.find ("\n",start)+1;
bool ok = true;
start = end;
int ccc = 0;
while ( start > 0 ) {
templist.clear();
ok = true;
int loopCount = 0;
while ( ok ) {
++loopCount;
if ( loopCount > 25 ) {
qDebug("KO: Error in while loop");
ok = false;
start = 0;
break;
}
if ( ok )
tempString = getPart( answer, ok, start );
if ( start >= len || start == 0 ) {
start = 0;
ok = false;
}
if ( tempString.right(1) =="\n" )
tempString = tempString.left( tempString.length()-1);
templist.append( tempString );
}
++ccc;
if ( ccc == 2 && loopCount < 25 ) {
start = 0;
bool ok;
int newnum = templist[0].toInt( &ok );
if ( ok && newnum > 0) {
retval = newnum;
inc->setID( "Sharp_DTM",templist[0] );
inc->setCsum( "Sharp_DTM", QString::number( getCsum( templist ) ));
inc->setTempSyncStat( SYNC_TEMPSTATE_NEW_ID );
}
if ( ok && newnum == -1 ) {
qDebug("Error writing back %s ", inc->summary().latin1());
}
}
}
//qDebug("getNumFromRecord returning : %d ", retval);
return retval;
}
bool SharpFormat::save( Calendar *calendar)
{
QLabel status ( i18n("Processing/adding events ..."), 0 );
int w = status.sizeHint().width()+20 ;
if ( w < 200 ) w = 200;
int h = status.sizeHint().height()+20 ;
int dw = QApplication::desktop()->width();
int dh = QApplication::desktop()->height();
status.setCaption(i18n("Writing DTM Data") );
status.setGeometry( (dw-w)/2, (dh - h )/2 ,w,h );
status.show();
status.raise();
qApp->processEvents();
bool debug = DEBUGMODE;
QString codec = "utf8";
QString answer;
QString ePrefix = "CARDID,CATEGORY,DSRP,PLCE,MEM1,TIM1,TIM2,ADAY,ARON,ARMN,ARSD,RTYP,RFRQ,RPOS,RDYS,REND,REDT,ALSD,ALED,MDAY\n";
QString tPrefix = "CARDID,CATEGORY,ETDY,LTDY,FNDY,MARK,PRTY,TITL,MEM1\n";
QString command;
QPtrList<Event> er = calendar->rawEvents();
Event* ev = er.first();
QString fileName = "/tmp/kopitempout";
int i = 0;
QString changeString = ePrefix;
QString deleteString = ePrefix;
bool deleteEnt = false;
bool changeEnt = false;
QString message = i18n("Processing event # ");
int procCount = 0;
while ( ev ) {
//qDebug("i %d ", ++i);
if ( ev->tempSyncStat() != SYNC_TEMPSTATE_NEW_EXTERNAL ) {
status.setText ( message + QString::number ( ++procCount ) );
qApp->processEvents();
QString eString = getEventString( ev );
if ( ev->tempSyncStat() == SYNC_TEMPSTATE_DELETE ) { // delete
// deleting empty strings does not work.
// we write first and x and then delete the record with the x
eString = eString.replace( QRegExp(",\"\""),",\"x\"" );
changeString += eString + "\n";
deleteString += eString + "\n";
deleteEnt = true;
changeEnt = true;
}
else if ( ev->getID("Sharp_DTM").isEmpty() ) { // add new
QString fileNameIn = "/tmp/kopitempin";
QFile fileIn( fileNameIn );
if (!fileIn.open( IO_WriteOnly ) ) {
return false;
}
QTextStream tsIn( &fileIn );
tsIn.setCodec( QTextCodec::codecForName("utf8") );
tsIn << ePrefix << eString ;
fileIn.close();
//command = "(echo \"" + ePrefix + eString + "\" ) | db2file datebook -w -g -c " + codec+ " > "+ fileName;
command = "(cat /tmp/kopitempin | db2file datebook -w -g -c " + codec+ ") > "+ fileName;
//qDebug("command ++++++++ ");
//qDebug("%s ",command.latin1());
//qDebug("command -------- ");
system ( command.utf8() );
QFile file( fileName );
if (!file.open( IO_ReadOnly ) ) {
return false;
}
QTextStream ts( &file );
ts.setCodec( QTextCodec::codecForName("utf8") );
answer = ts.read();
file.close();
//qDebug("answer \n%s ", answer.latin1());
getNumFromRecord( answer, ev ) ;
}
else { // change existing
//qDebug("canging %d %d",ev->zaurusStat() ,ev->zaurusId() );
//command = "(echo \"" + ePrefix + eString + "\" ) | db2file datebook -w -g -c " + codec+ " > "+ fileName;
changeString += eString + "\n";
changeEnt = true;
}
}
ev = er.next();
}
status.setText ( i18n("Changing events ...") );
qApp->processEvents();
//qDebug("changing... ");
if ( changeEnt ) {
QFile file( fileName );
if (!file.open( IO_WriteOnly ) ) {
return false;
}
QTextStream ts( &file );
ts.setCodec( QTextCodec::codecForName("utf8") );
ts << changeString ;
file.close();
command = "db2file datebook -w -g -c " + codec+ " < "+ fileName;
system ( command.latin1() );
//qDebug("command %s file :\n%s ", command.latin1(), changeString.latin1());
}
status.setText ( i18n("Deleting events ...") );
qApp->processEvents();
//qDebug("deleting... ");
if ( deleteEnt ) {
QFile file( fileName );
if (!file.open( IO_WriteOnly ) ) {
return false;
}
QTextStream ts( &file );
ts.setCodec( QTextCodec::codecForName("utf8") );
ts << deleteString;
file.close();
command = "db2file datebook -d -c " + codec+ " < "+ fileName;
system ( command.latin1() );
// qDebug("command %s file :\n%s ", command.latin1(), deleteString.latin1());
}
changeString = tPrefix;
deleteString = tPrefix;
status.setText ( i18n("Processing todos ...") );
qApp->processEvents();
QPtrList<Todo> tl = calendar->rawTodos();
Todo* to = tl.first();
i = 0;
message = i18n("Processing todo # ");
procCount = 0;
while ( to ) {
if ( to->tempSyncStat() != SYNC_TEMPSTATE_NEW_EXTERNAL ) {
status.setText ( message + QString::number ( ++procCount ) );
qApp->processEvents();
QString eString = getTodoString( to );
if ( to->tempSyncStat() == SYNC_TEMPSTATE_DELETE ) { // delete
// deleting empty strings does not work.
// we write first and x and then delete the record with the x
eString = eString.replace( QRegExp(",\"\""),",\"x\"" );
changeString += eString + "\n";
deleteString += eString + "\n";
deleteEnt = true;
changeEnt = true;
}
else if ( to->getID("Sharp_DTM").isEmpty() ) { // add new
QString fileNameIn = "/tmp/kopitempin";
QFile fileIn( fileNameIn );
if (!fileIn.open( IO_WriteOnly ) ) {
return false;
}
QTextStream tsIn( &fileIn );
tsIn.setCodec( QTextCodec::codecForName("utf8") );
tsIn << tPrefix << eString ;
fileIn.close();
command = "(cat /tmp/kopitempin | db2file todo -w -g -c " + codec+ ") > "+ fileName;
system ( command.utf8() );
QFile file( fileName );
if (!file.open( IO_ReadOnly ) ) {
return false;
}
QTextStream ts( &file );
ts.setCodec( QTextCodec::codecForName("utf8") );
answer = ts.read();
file.close();
//qDebug("answer \n%s ", answer.latin1());
getNumFromRecord( answer, to ) ;
}
else { // change existing
//qDebug("canging %d %d",to->zaurusStat() ,to->zaurusId() );
//command = "(echo \"" + ePrefix + eString + "\" ) | db2file datebook -w -g -c " + codec+ " > "+ fileName;
changeString += eString + "\n";
changeEnt = true;
}
}
to = tl.next();
}
status.setText ( i18n("Changing todos ...") );
qApp->processEvents();
//qDebug("changing... ");
if ( changeEnt ) {
QFile file( fileName );
if (!file.open( IO_WriteOnly ) ) {
return false;
}
QTextStream ts( &file );
ts.setCodec( QTextCodec::codecForName("utf8") );
ts << changeString ;
file.close();
command = "db2file todo -w -g -c " + codec+ " < "+ fileName;
system ( command.latin1() );
//qDebug("command %s file :\n%s ", command.latin1(), changeString.latin1());
}
status.setText ( i18n("Deleting todos ...") );
qApp->processEvents();
//qDebug("deleting... ");
if ( deleteEnt ) {
QFile file( fileName );
if (!file.open( IO_WriteOnly ) ) {
return false;
}
QTextStream ts( &file );
ts.setCodec( QTextCodec::codecForName("utf8") );
ts << deleteString;
file.close();
command = "db2file todo -d -c " + codec+ " < "+ fileName;
system ( command.latin1() );
// qDebug("command %s file :\n%s ", command.latin1(), deleteString.latin1());
}
return true;
}
QString SharpFormat::dtToString( const QDateTime& dti, bool useTZ )
{
QString datestr;
QString timestr;
int offset = KGlobal::locale()->localTimeOffset( dti );
QDateTime dt;
if (useTZ)
dt = dti.addSecs ( -(offset*60));
else
dt = dti;
if(dt.date().isValid()){
const QDate& date = dt.date();
datestr.sprintf("%04d%02d%02d",
date.year(), date.month(), date.day());
}
if(dt.time().isValid()){
const QTime& time = dt.time();
timestr.sprintf("T%02d%02d%02d",
time.hour(), time.minute(), time.second());
}
return datestr + timestr;
}
QString SharpFormat::getEventString( Event* event )
{
QStringList list;
list.append( event->getID("Sharp_DTM") );
list.append( event->categories().join(",") );
if ( !event->summary().isEmpty() )
list.append( event->summary() );
else
list.append("" );
if ( !event->location().isEmpty() )
list.append( event->location() );
else
list.append("" );
if ( !event->description().isEmpty() )
list.append( event->description() );
else
list.append( "" );
if ( event->doesFloat () ) {
list.append( dtToString( QDateTime(event->dtStart().date(), QTime(0,0,0)), false ));
list.append( dtToString( QDateTime(event->dtEnd().date(),QTime(23,59,59)), false )); //6
list.append( "1" );
}
else {
list.append( dtToString( event->dtStart()) );
list.append( dtToString( event->dtEnd()) ); //6
list.append( "0" );
}
bool noAlarm = true;
if ( event->alarms().count() > 0 ) {
Alarm * al = event->alarms().first();
if ( al->enabled() ) {
noAlarm = false;
list.append( "0" ); // yes, 0 == alarm
list.append( QString::number( al->startOffset().asSeconds()/(-60) ) );
if ( al->type() == Alarm::Audio )
list.append( "1" ); // type audio
else
list.append( "0" ); // type silent
}
}
if ( noAlarm ) {
list.append( "1" ); // yes, 1 == no alarm
list.append( "0" ); // no alarm offset
list.append( "1" ); // type
}
// next is: 11
// next is: 11-16 are recurrence
Recurrence* rec = event->recurrence();
bool writeEndDate = false;
switch ( rec->doesRecur() )
{
case Recurrence::rDaily: // 0
list.append( "0" );
list.append( QString::number( rec->frequency() ));//12
list.append( "0" );
list.append( "0" );
writeEndDate = true;
break;
case Recurrence::rWeekly:// 1
list.append( "1" );
list.append( QString::number( rec->frequency()) );//12
list.append( "0" );
{
int days = 0;
QBitArray weekDays = rec->days();
int i;
for( i = 1; i <= 7; ++i ) {
if ( weekDays[i-1] ) {
days += 1 << (i-1);
}
}
list.append( QString::number( days ) );
}
//pending weekdays
writeEndDate = true;
break;
case Recurrence::rMonthlyPos:// 2
list.append( "2" );
list.append( QString::number( rec->frequency()) );//12
writeEndDate = true;
{
int count = 1;
QPtrList<Recurrence::rMonthPos> rmp;
rmp = rec->monthPositions();
if ( rmp.first()->negative )
count = 5 - rmp.first()->rPos - 1;
else
count = rmp.first()->rPos - 1;
list.append( QString::number( count ) );
}
list.append( "0" );
break;
case Recurrence::rMonthlyDay:// 3
list.append( "3" );
list.append( QString::number( rec->frequency()) );//12
list.append( "0" );
list.append( "0" );
writeEndDate = true;
break;
case Recurrence::rYearlyMonth://4
list.append( "4" );
list.append( QString::number( rec->frequency()) );//12
list.append( "0" );
list.append( "0" );
writeEndDate = true;
break;
default:
list.append( "255" );
list.append( QString() );
list.append( "0" );
list.append( QString() );
list.append( "0" );
list.append( "20991231T000000" );
break;
}
if ( writeEndDate ) {
if ( rec->endDate().isValid() ) { // 15 + 16
list.append( "1" );
list.append( dtToString( rec->endDate()) );
} else {
list.append( "0" );
list.append( "20991231T000000" );
}
}
if ( event->doesFloat () ) {
list.append( dtToString( event->dtStart(), false ).left( 8 ));
list.append( dtToString( event->dtEnd(), false ).left( 8 )); //6
}
else {
list.append( QString() );
list.append( QString() );
}
if (event->dtStart().date() == event->dtEnd().date() )
list.append( "0" );
else
list.append( "1" );
for(QStringList::Iterator it=list.begin();
it!=list.end(); ++it){
QString& s = (*it);
s.replace(QRegExp("\""), "\"\"");
if(s.contains(QRegExp("[,\"\r\n]")) || s.stripWhiteSpace() != s){
s.prepend('\"');
s.append('\"');
} else if(s.isEmpty() && !s.isNull()){
s = "\"\"";
}
}
return list.join(",");
}
QString SharpFormat::getTodoString( Todo* todo )
{
QStringList list;
list.append( todo->getID("Sharp_DTM") );
list.append( todo->categories().join(",") );
if ( todo->hasStartDate() ) {
list.append( dtToString( todo->dtStart()) );
} else
list.append( QString() );
if ( todo->hasDueDate() ) {
QTime tim;
if ( todo->doesFloat()) {
list.append( dtToString( QDateTime(todo->dtDue().date(),QTime( 0,0,0 )), false)) ;
} else {
list.append( dtToString(todo->dtDue() ) );
}
} else
list.append( QString() );
if ( todo->isCompleted() ) {
list.append( dtToString( todo->completed()) );
list.append( "0" ); // yes 0 == completed
} else {
list.append( dtToString( todo->completed()) );
list.append( "1" );
}
list.append( QString::number( todo->priority() ));
if( ! todo->summary().isEmpty() )
list.append( todo->summary() );
else
list.append( "" );
if (! todo->description().isEmpty() )
list.append( todo->description() );
else
list.append( "" );
for(QStringList::Iterator it=list.begin();
it!=list.end(); ++it){
QString& s = (*it);
s.replace(QRegExp("\""), "\"\"");
if(s.contains(QRegExp("[,\"\r\n]")) || s.stripWhiteSpace() != s){
s.prepend('\"');
s.append('\"');
} else if(s.isEmpty() && !s.isNull()){
s = "\"\"";
}
}
return list.join(",");
}
QString SharpFormat::getPart( const QString & text, bool &ok, int &start )
{
//qDebug("start %d ", start);
QString retval ="";
if ( text.at(start) == '"' ) {
if ( text.mid( start,2) == "\"\"" && !( text.mid( start+2,1) == "\"")) {
start = start +2;
if ( text.mid( start,1) == "," ) {
start += 1;
}
retval = "";
if ( text.mid( start,1) == "\n" ) {
start += 1;
ok = false;
}
return retval;
}
int hk = start+1;
hk = text.find ('"',hk);
while ( text.at(hk+1) == '"' )
hk = text.find ('"',hk+2);
retval = text.mid( start+1, hk-start-1);
start = hk+1;
retval.replace( QRegExp("\"\""), "\"");
if ( text.mid( start,1) == "," ) {
start += 1;
}
if ( text.mid( start,1) == "\n" ) {
start += 1;
ok = false;
}
//qDebug("retval***%s*** ",retval.latin1() );
return retval;
} else {
int nl = text.find ("\n",start);
int kom = text.find (',',start);
if ( kom < nl ) {
// qDebug("kom < nl %d ", kom);
retval = text.mid(start, kom-start);
start = kom+1;
return retval;
} else {
if ( nl == kom ) {
// qDebug(" nl == kom ");
start = 0;
ok = false;
return "0";
}
// qDebug(" nl < kom ", nl);
retval = text.mid( start, nl-start);
ok = false;
start = nl+1;
return retval;
}
}
}
bool SharpFormat::fromString( Calendar *calendar, const QString & text)
{
return false;
}
bool SharpFormat::fromString2Cal( Calendar *calendar,Calendar *existingCalendar, const QString & text, const QString & type)
{
// qDebug("test %s ", text.latin1());
QStringList templist;
QString tempString;
int start = 0;
int len = text.length();
int end = text.find ("\n",start)+1;
bool ok = true;
start = end;
SharpParser handler( calendar );
// handler.setCategoriesList( mCategories );
while ( start > 0 ) {
templist.clear();
ok = true;
while ( ok ) {
tempString = getPart( text, ok, start );
if ( start >= len || start == 0 ) {
start = 0;
ok = false;
}
if ( tempString.right(1) =="\n" )
tempString = tempString.left( tempString.length()-1);
//if ( ok )
templist.append( tempString );
//qDebug("%d ---%s---", templist.count(),tempString.latin1() );
}
handler.startElement( existingCalendar, templist, type );
}
return false;
}
QString SharpFormat::toString( Calendar * )
{
return QString::null;
}
diff --git a/version b/version
index c4fe6e2..0343cbb 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-version = "1.9.13";
+version = "1.9.14";