From: znek Date: Tue, 1 Mar 2005 17:08:11 +0000 (+0000) Subject: bugfixes and performance upgrade for recurrent events X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d91b31e3d9d89db9c3575970be832d4bd5442344;p=scalable-opengroupware.org bugfixes and performance upgrade for recurrent events git-svn-id: http://svn.opengroupware.org/SOGo/trunk@617 d1b88da0-ebda-0310-925b-ed51d893ca5b --- diff --git a/OGoContentStore/ChangeLog b/OGoContentStore/ChangeLog index 40b29c3b..0fd38dc9 100644 --- a/OGoContentStore/ChangeLog +++ b/OGoContentStore/ChangeLog @@ -1,3 +1,23 @@ +2005-03-01 Marcus Mueller + + * v0.9.22 + + * appointment.ocs: added 'cycleenddate' and 'cycleinfo' to address + previous performance issues + + * OCSiCalFieldExtractor.m: set 'cycleenddate' and 'cycleinfo' for + recurrent events. Reverted setting of 'enddate' to the previous + behaviour since 'cycleenddate' is dedicated to the task now + + * iCalRepeatableEntityObject+OCS.[hm]: new category used by the + OCSiCalFieldExtractor to extract cycleInfo in an appropriate format + + * sql/generate-folderinfo-sql-for-users.sh, + sql/foldertablecreate-helge-privcal.psql, + sql/foldertablecreate-helge-privcal.sqlite, + sql/generate-folderinfo-sql-for-users-sqlite.sh: adjusted to new + schema + 2005-03-01 Helge Hess * OCSFolder.m: added support for storing content and quick info in diff --git a/OGoContentStore/GNUmakefile b/OGoContentStore/GNUmakefile index d69c3574..2d07b7a1 100644 --- a/OGoContentStore/GNUmakefile +++ b/OGoContentStore/GNUmakefile @@ -11,35 +11,37 @@ TYPEMODELS_DIR = $(GNUSTEP_USER_ROOT)/Library/OCSTypeModels/ libOGoContentStore_HEADER_FILES_DIR = . libOGoContentStore_HEADER_FILES_INSTALL_DIR = /OGoContentStore -libOGoContentStore_HEADER_FILES += \ - NSURL+OCS.h \ - EOAdaptorChannel+OCS.h \ +libOGoContentStore_HEADER_FILES += \ + NSURL+OCS.h \ + EOAdaptorChannel+OCS.h \ + iCalRepeatableEntityObject+OCS.h \ \ - OCSContext.h \ - OCSFieldInfo.h \ - OCSFolder.h \ - OCSFolderManager.h \ - OCSFolderType.h \ - OCSChannelManager.h \ - OCSFieldExtractor.h \ - OCSiCalFieldExtractor.h \ - OCSStringFormatter.h \ - -libOGoContentStore_OBJC_FILES += \ - NSURL+OCS.m \ - EOAdaptorChannel+OCS.m \ - EOQualifier+OCS.m \ + OCSContext.h \ + OCSFieldInfo.h \ + OCSFolder.h \ + OCSFolderManager.h \ + OCSFolderType.h \ + OCSChannelManager.h \ + OCSFieldExtractor.h \ + OCSiCalFieldExtractor.h \ + OCSStringFormatter.h \ + +libOGoContentStore_OBJC_FILES += \ + NSURL+OCS.m \ + EOAdaptorChannel+OCS.m \ + EOQualifier+OCS.m \ + iCalRepeatableEntityObject+OCS.m \ \ - OCSContext.m \ - OCSFieldInfo.m \ - OCSFolder.m \ - OCSFolderManager.m \ - OCSFolderType.m \ - OCSChannelManager.m \ - OCSFieldExtractor.m \ - OCSiCalFieldExtractor.m \ - OCSContactFieldExtractor.m \ - OCSStringFormatter.m \ + OCSContext.m \ + OCSFieldInfo.m \ + OCSFolder.m \ + OCSFolderManager.m \ + OCSFolderType.m \ + OCSChannelManager.m \ + OCSFieldExtractor.m \ + OCSiCalFieldExtractor.m \ + OCSContactFieldExtractor.m \ + OCSStringFormatter.m \ libOGoContentStore_TYPEMODELS += \ appointment.ocs \ diff --git a/OGoContentStore/OCSiCalFieldExtractor.m b/OGoContentStore/OCSiCalFieldExtractor.m index cefa04ba..27ea7dcb 100644 --- a/OGoContentStore/OCSiCalFieldExtractor.m +++ b/OGoContentStore/OCSiCalFieldExtractor.m @@ -23,6 +23,7 @@ #include "common.h" #include #include +#include "iCalRepeatableEntityObject+OCS.h" @implementation OCSiCalFieldExtractor @@ -124,21 +125,20 @@ static NSNumber *distantFutureNumber = nil; if ([startDate isNotNull]) [row setObject:[self numberForDate:startDate] forKey:@"startdate"]; - if (![_event isRecurrent]) { - if ([endDate isNotNull]) - [row setObject:[self numberForDate:endDate] forKey:@"enddate"]; - } - else { + if ([endDate isNotNull]) + [row setObject:[self numberForDate:endDate] forKey:@"enddate"]; + + if ([_event isRecurrent]) { NSCalendarDate *date; date = [_event lastPossibleRecurrenceStartDate]; if (!date) { - /* date might be nil, indicating an unbound recurrence - we substitute - this with a very distant date since 'enddate' is not allowed to be - NULL */ + /* this could also be *nil*, but in the end it makes the fetchspecs + more complex - thus we set it to a "reasonable" distant future */ date = distantFuture; } - [row setObject:[self numberForDate:date] forKey:@"enddate"]; + [row setObject:[self numberForDate:date] forKey:@"cycleenddate"]; + [row setObject:[_event cycleInfo] forKey:@"cycleinfo"]; } if ([participants length] > 0) [row setObject:participants forKey:@"participants"]; diff --git a/OGoContentStore/OGoContentStore.xcode/project.pbxproj b/OGoContentStore/OGoContentStore.xcode/project.pbxproj index 1266e6a7..deacbec9 100644 --- a/OGoContentStore/OGoContentStore.xcode/project.pbxproj +++ b/OGoContentStore/OGoContentStore.xcode/project.pbxproj @@ -450,17 +450,8 @@ AD0CF977071FE18800E72147 = { children = ( AD0CF97E071FE18800E72147, - AD0CF97D071FE18800E72147, - AD0CF978071FE18800E72147, - AD0CF979071FE18800E72147, - AD0CF97A071FE18800E72147, - AD0CF97B071FE18800E72147, - AD0CF97C071FE18800E72147, - AD0CF97F071FE18800E72147, - AD0CF980071FE18800E72147, - AD0CF981071FE18800E72147, - AD0CF982071FE18800E72147, - AD0CF983071FE18800E72147, + ADB79C3707D4B7AA00CA782A, + ADB79C3A07D4B7B800CA782A, ); isa = PBXGroup; name = SQL; @@ -656,6 +647,7 @@ AD0CF960071FE18800E72147, AD0CF952071FE18800E72147, AD0CF954071FE18800E72147, + ADB79C6A07D4B92B00CA782A, ); indentWidth = 2; isa = PBXGroup; @@ -677,6 +669,7 @@ AD0CF95F071FE18800E72147, AD0CF951071FE18800E72147, AD0CF953071FE18800E72147, + ADB79C6907D4B92B00CA782A, ); indentWidth = 2; isa = PBXGroup; @@ -703,6 +696,76 @@ refType = 4; sourceTree = ""; }; + ADB79C3207D4B7A200CA782A = { + fileEncoding = 5; + isa = PBXFileReference; + lastKnownFileType = text; + path = "folderinfo-create.sqlite"; + refType = 4; + sourceTree = ""; + }; + ADB79C3307D4B7A200CA782A = { + fileEncoding = 5; + isa = PBXFileReference; + lastKnownFileType = text; + path = "foldertablecreate-helge-privcal.sqlite"; + refType = 4; + sourceTree = ""; + }; + ADB79C3407D4B7A200CA782A = { + fileEncoding = 5; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + path = "generate-folderinfo-sql-for-users-sqlite.sh"; + refType = 4; + sourceTree = ""; + }; + ADB79C3707D4B7AA00CA782A = { + children = ( + ADB79C3207D4B7A200CA782A, + ADB79C3307D4B7A200CA782A, + ADB79C3407D4B7A200CA782A, + ); + isa = PBXGroup; + name = SQLite; + refType = 4; + sourceTree = ""; + }; + ADB79C3A07D4B7B800CA782A = { + children = ( + AD0CF97D071FE18800E72147, + AD0CF978071FE18800E72147, + AD0CF979071FE18800E72147, + AD0CF97A071FE18800E72147, + AD0CF97B071FE18800E72147, + AD0CF97C071FE18800E72147, + AD0CF97F071FE18800E72147, + AD0CF980071FE18800E72147, + AD0CF981071FE18800E72147, + AD0CF982071FE18800E72147, + AD0CF983071FE18800E72147, + ); + isa = PBXGroup; + name = PostgreSQL; + refType = 4; + sourceTree = ""; + }; + ADB79C6907D4B92B00CA782A = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "iCalRepeatableEntityObject+OCS.h"; + refType = 4; + sourceTree = ""; + }; + ADB79C6A07D4B92B00CA782A = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "iCalRepeatableEntityObject+OCS.m"; + refType = 4; + sourceTree = ""; + }; }; rootObject = AD0CF947071FE16800E72147; } diff --git a/OGoContentStore/Version b/OGoContentStore/Version index 2c5bdd60..d237ea4c 100644 --- a/OGoContentStore/Version +++ b/OGoContentStore/Version @@ -2,7 +2,7 @@ MAJOR_VERSION=0 MINOR_VERSION=9 -SUBMINOR_VERSION:=21 +SUBMINOR_VERSION:=22 # v0.9.19 requires libNGiCal v4.5.40 # v0.9.18 requires libNGiCal v4.5.38 diff --git a/OGoContentStore/appointment.ocs b/OGoContentStore/appointment.ocs index 6435f954..95bbc555 100644 --- a/OGoContentStore/appointment.ocs +++ b/OGoContentStore/appointment.ocs @@ -19,6 +19,11 @@ sqlType = "INT"; allowsNull = NO; }, + { + columnName = cylceenddate; + sqlType = "INT"; + allowsNull = YES; + }, { columnName = title; sqlType = "VARCHAR(1000)"; @@ -39,6 +44,11 @@ sqlType = "INT"; allowsNull = YES; }, + { + columnName = cycleinfo; + sqlType = "VARCHAR(1000)"; + allowsNull = YES; + }, { columnName = ispublic; sqlType = "INT"; diff --git a/OGoContentStore/iCalRepeatableEntityObject+OCS.h b/OGoContentStore/iCalRepeatableEntityObject+OCS.h new file mode 100644 index 00000000..0fa62e15 --- /dev/null +++ b/OGoContentStore/iCalRepeatableEntityObject+OCS.h @@ -0,0 +1,35 @@ +/* + Copyright (C) 2004-2005 SKYRIX Software AG + + This file is part of OpenGroupware.org. + + OGo is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + OGo is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with OGo; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ +// $Id$ + + +#ifndef __OGoContentStore_iCalRepeatableEntityObject_OCS_H_ +#define __OGoContentStore_iCalRepeatableEntityObject_OCS_H_ + +#include + +@interface iCalRepeatableEntityObject (OCS) + +- (NSString *)cycleInfo; + +@end + +#endif /* __OGoContentStore_iCalRepeatableEntityObject_OCS_H_ */ diff --git a/OGoContentStore/iCalRepeatableEntityObject+OCS.m b/OGoContentStore/iCalRepeatableEntityObject+OCS.m new file mode 100644 index 00000000..d36f9cbe --- /dev/null +++ b/OGoContentStore/iCalRepeatableEntityObject+OCS.m @@ -0,0 +1,89 @@ +/* + Copyright (C) 2004-2005 SKYRIX Software AG + + This file is part of OpenGroupware.org. + + OGo is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + OGo is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with OGo; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ +// $Id$ + +#include "iCalRepeatableEntityObject+OCS.h" +#include "common.h" + +@implementation iCalRepeatableEntityObject (OCS) + +- (NSString *)cycleInfo { + NSMutableDictionary *cycleInfo; + NSMutableArray *ma; + NSArray *a; + unsigned count; + + if (![self isRecurrent]) + return nil; + + cycleInfo = [NSMutableDictionary dictionaryWithCapacity:3]; + + /* rules */ + a = [self recurrenceRules]; + count = [a count]; + if (count > 0) { + unsigned i; + + ma = [NSMutableArray arrayWithCapacity:count]; + for (i = 0; i < count; i++) { + iCalRecurrenceRule *rule; + + rule = [a objectAtIndex:i]; + [ma addObject:[rule iCalRepresentation]]; + } + [cycleInfo setObject:ma forKey:@"rules"]; + } + + /* exception rules */ + a = [self exceptionRules]; + count = [a count]; + if (count > 0) { + unsigned i; + + ma = [NSMutableArray arrayWithCapacity:count]; + for (i = 0; i < count; i++) { + iCalRecurrenceRule *rule; + + rule = [a objectAtIndex:i]; + [ma addObject:[rule iCalRepresentation]]; + } + [cycleInfo setObject:ma forKey:@"exRules"]; + } + + /* exception dates */ + a = [self exceptionDates]; + count = [a count]; + if (count > 0) { + unsigned i; + + ma = [NSMutableArray arrayWithCapacity:count]; + for (i = 0; i < count; i++) { + NSCalendarDate *date; + + date = [a objectAtIndex:i]; + [ma addObject:[date icalString]]; + } + [cycleInfo setObject:ma forKey:@"exDates"]; + } + + return [cycleInfo description]; +} +@end diff --git a/OGoContentStore/sql/foldertablecreate-helge-privcal.psql b/OGoContentStore/sql/foldertablecreate-helge-privcal.psql index 710c6587..2877ae51 100644 --- a/OGoContentStore/sql/foldertablecreate-helge-privcal.psql +++ b/OGoContentStore/sql/foldertablecreate-helge-privcal.psql @@ -10,7 +10,9 @@ CREATE TABLE SOGo_helge_privcal_quick ( uid VARCHAR(256) NOT NULL, startdate INT NOT NULL, enddate INT NOT NULL, + cycleenddate INT NULL, -- enddate for cyclic events title VARCHAR(1000) NOT NULL, + cycleinfo VARCHAR(1000) NULL, -- property list with cycle infos participants VARCHAR(100000) NOT NULL, -- the CNs of the participants isallday INT NULL, iscycle INT NULL, -- client needs to fetch to resolve diff --git a/OGoContentStore/sql/foldertablecreate-helge-privcal.sqlite b/OGoContentStore/sql/foldertablecreate-helge-privcal.sqlite index af9cf747..ed208274 100644 --- a/OGoContentStore/sql/foldertablecreate-helge-privcal.sqlite +++ b/OGoContentStore/sql/foldertablecreate-helge-privcal.sqlite @@ -10,7 +10,9 @@ CREATE TABLE SOGo_helge_privcal_quick ( uid VARCHAR(256) NOT NULL, startdate INT NOT NULL, enddate INT NOT NULL, + cycleenddate INT NULL, /* enddate for cyclic events */ title VARCHAR(1000) NOT NULL, + cycleinfo VARCHAR(1000) NULL, /* property list with cycle infos */ participants VARCHAR(100000) NOT NULL, /* the CNs of the participants */ isallday INT NULL, iscycle INT NULL, /* client needs to fetch to resolve */ diff --git a/OGoContentStore/sql/generate-folderinfo-sql-for-users-sqlite.sh b/OGoContentStore/sql/generate-folderinfo-sql-for-users-sqlite.sh index 22b4b3df..00b49f5a 100755 --- a/OGoContentStore/sql/generate-folderinfo-sql-for-users-sqlite.sh +++ b/OGoContentStore/sql/generate-folderinfo-sql-for-users-sqlite.sh @@ -61,7 +61,9 @@ CREATE TABLE SOGo_${USER_TABLE}_privcal_quick ( uid VARCHAR(256) NOT NULL, startdate INT NOT NULL, enddate INT NOT NULL, + cycleenddate INT NULL, /* enddate for cyclic events */ title VARCHAR(1000) NOT NULL, + cycleinfo VARCHAR(1000) NULL, /* property list with cycle infos */ participants VARCHAR(100000) NOT NULL, /* the CNs of the participants */ isallday INT NULL, iscycle INT NULL, /* client needs to fetch to resolve */ diff --git a/OGoContentStore/sql/generate-folderinfo-sql-for-users.sh b/OGoContentStore/sql/generate-folderinfo-sql-for-users.sh index 2b054a3a..1e6984c3 100755 --- a/OGoContentStore/sql/generate-folderinfo-sql-for-users.sh +++ b/OGoContentStore/sql/generate-folderinfo-sql-for-users.sh @@ -72,7 +72,9 @@ CREATE TABLE SOGo_${USER_TABLE}_privcal_quick ( uid VARCHAR(256) NOT NULL, startdate INT NOT NULL, enddate INT NOT NULL, + cycleenddate INT NULL, -- enddate for cyclic events title VARCHAR(1000) NOT NULL, + cycleinfo VARCHAR(1000) NULL, -- property list with cycle infos participants VARCHAR(100000) NOT NULL, -- the CNs of the participants isallday INT NULL, iscycle INT NULL, -- client needs to fetch to resolve diff --git a/SOGo/SOGo.xcode/project.pbxproj b/SOGo/SOGo.xcode/project.pbxproj index 962d4362..17025ebd 100644 --- a/SOGo/SOGo.xcode/project.pbxproj +++ b/SOGo/SOGo.xcode/project.pbxproj @@ -1932,134 +1932,6 @@ refType = 4; sourceTree = ""; }; - AD86234407CA03D9004CD707 = { - fileEncoding = 5; - isa = PBXFileReference; - lastKnownFileType = text.xml; - path = UIxMailEditor.wox; - refType = 4; - sourceTree = ""; - }; - AD86234507CA03D9004CD707 = { - fileEncoding = 5; - isa = PBXFileReference; - lastKnownFileType = text.xml; - path = UIxMailEditorAttach.wox; - refType = 4; - sourceTree = ""; - }; - AD86234607CA03D9004CD707 = { - fileEncoding = 5; - isa = PBXFileReference; - lastKnownFileType = text.xml; - path = UIxMailFilterPanel.wox; - refType = 4; - sourceTree = ""; - }; - AD86234707CA03D9004CD707 = { - fileEncoding = 5; - isa = PBXFileReference; - lastKnownFileType = text.xml; - path = UIxMailListView.wox; - refType = 4; - sourceTree = ""; - }; - AD86234807CA03D9004CD707 = { - fileEncoding = 5; - isa = PBXFileReference; - lastKnownFileType = text.xml; - path = UIxMailMainFrame.wox; - refType = 4; - sourceTree = ""; - }; - AD86234907CA03D9004CD707 = { - fileEncoding = 5; - isa = PBXFileReference; - lastKnownFileType = text.xml; - path = UIxMailMoveToPopUp.wox; - refType = 4; - sourceTree = ""; - }; - AD86234A07CA03D9004CD707 = { - fileEncoding = 5; - isa = PBXFileReference; - lastKnownFileType = text.xml; - path = UIxMailPartAlternativeViewer.wox; - refType = 4; - sourceTree = ""; - }; - AD86234B07CA03D9004CD707 = { - fileEncoding = 5; - isa = PBXFileReference; - lastKnownFileType = text.xml; - path = UIxMailPartHTMLViewer.wox; - refType = 4; - sourceTree = ""; - }; - AD86234C07CA03D9004CD707 = { - fileEncoding = 5; - isa = PBXFileReference; - lastKnownFileType = text.xml; - path = UIxMailPartICalViewer.wox; - refType = 4; - sourceTree = ""; - }; - AD86234D07CA03D9004CD707 = { - fileEncoding = 5; - isa = PBXFileReference; - lastKnownFileType = text.xml; - path = UIxMailPartImageViewer.wox; - refType = 4; - sourceTree = ""; - }; - AD86234E07CA03D9004CD707 = { - fileEncoding = 5; - isa = PBXFileReference; - lastKnownFileType = text.xml; - path = UIxMailPartLinkViewer.wox; - refType = 4; - sourceTree = ""; - }; - AD86234F07CA03D9004CD707 = { - fileEncoding = 5; - isa = PBXFileReference; - lastKnownFileType = text.xml; - path = UIxMailPartMessageViewer.wox; - refType = 4; - sourceTree = ""; - }; - AD86235007CA03D9004CD707 = { - fileEncoding = 5; - isa = PBXFileReference; - lastKnownFileType = text.xml; - path = UIxMailPartMixedViewer.wox; - refType = 4; - sourceTree = ""; - }; - AD86235107CA03D9004CD707 = { - fileEncoding = 5; - isa = PBXFileReference; - lastKnownFileType = text.xml; - path = UIxMailPartTextViewer.wox; - refType = 4; - sourceTree = ""; - }; - AD86235207CA03D9004CD707 = { - fileEncoding = 5; - isa = PBXFileReference; - lastKnownFileType = text.xml; - path = UIxMailSortableTableHeader.wox; - refType = 4; - sourceTree = ""; - }; - AD86235307CA03D9004CD707 = { - fileEncoding = 5; - isa = PBXFileReference; - lastKnownFileType = text.xml; - path = UIxMailToolbar.wox; - refType = 4; - sourceTree = ""; - }; AD86235407CA03D9004CD707 = { fileEncoding = 5; isa = PBXFileReference; @@ -2068,30 +1940,6 @@ refType = 4; sourceTree = ""; }; - AD86235507CA03D9004CD707 = { - fileEncoding = 5; - isa = PBXFileReference; - lastKnownFileType = text.xml; - path = UIxMailTree.wox; - refType = 4; - sourceTree = ""; - }; - AD86235607CA03D9004CD707 = { - fileEncoding = 5; - isa = PBXFileReference; - lastKnownFileType = text.xml; - path = UIxMailView.wox; - refType = 4; - sourceTree = ""; - }; - AD86235707CA03D9004CD707 = { - fileEncoding = 5; - isa = PBXFileReference; - lastKnownFileType = text.xml; - path = UIxMailWindowCloser.wox; - refType = 4; - sourceTree = ""; - }; AD86235807CA03D9004CD707 = { fileEncoding = 5; isa = PBXFileReference; @@ -2186,26 +2034,7 @@ AD86234107CA03D9004CD707, AD86234207CA03D9004CD707, AD86234307CA03D9004CD707, - AD86234407CA03D9004CD707, - AD86234507CA03D9004CD707, - AD86234607CA03D9004CD707, - AD86234707CA03D9004CD707, - AD86234807CA03D9004CD707, - AD86234907CA03D9004CD707, - AD86234A07CA03D9004CD707, - AD86234B07CA03D9004CD707, - AD86234C07CA03D9004CD707, - AD86234D07CA03D9004CD707, - AD86234E07CA03D9004CD707, - AD86234F07CA03D9004CD707, - AD86235007CA03D9004CD707, - AD86235107CA03D9004CD707, - AD86235207CA03D9004CD707, - AD86235307CA03D9004CD707, AD86235407CA03D9004CD707, - AD86235507CA03D9004CD707, - AD86235607CA03D9004CD707, - AD86235707CA03D9004CD707, AD86235A07CA03D9004CD707, ); isa = PBXGroup; @@ -2387,6 +2216,17 @@ refType = 4; sourceTree = ""; }; + ADB79CAD07D4BF1600CA782A = { + fileEncoding = 5; + indentWidth = 8; + isa = PBXFileReference; + lastKnownFileType = text; + path = ChangeLog; + refType = 4; + sourceTree = ""; + tabWidth = 8; + usesTabs = 1; + }; ADBE3C490726AF4C000FEA6A = { fileEncoding = 5; indentWidth = 2; @@ -3925,6 +3765,7 @@ }; E87206090692E3D00099CBBD = { children = ( + ADB79CAD07D4BF1600CA782A, E872064B0692E3D00099CBBD, E87206420692E3D00099CBBD, ADDF4BE606DCF5E200C4E7F8, diff --git a/SOGo/SoObjects/Appointments/ChangeLog b/SOGo/SoObjects/Appointments/ChangeLog index 16cf5827..00736319 100644 --- a/SOGo/SoObjects/Appointments/ChangeLog +++ b/SOGo/SoObjects/Appointments/ChangeLog @@ -1,3 +1,10 @@ +2005-03-01 Marcus Mueller + + * SOGoAppointmentFolder.m: significantly changed handling of cyclic + events. Information for cyclic event calculation is now contained + in the quick info, making full fetches obsolete - performance + should improve significantly this way (v0.9.28) + 2005-02-22 Helge Hess * SOGoAppointmentFolder.m: minor code cleanups (v0.9.27) diff --git a/SOGo/SoObjects/Appointments/SOGoAppointmentFolder.m b/SOGo/SoObjects/Appointments/SOGoAppointmentFolder.m index 92c93901..7b62a578 100644 --- a/SOGo/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SOGo/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -141,65 +141,89 @@ static NSTimeZone *MET = nil; md = [[_record mutableCopy] autorelease]; - if (![[_record valueForKey:@"iscycle"] intValue]) { - if ((tmp = [_record objectForKey:@"startdate"])) { - tmp = [[NSCalendarDate alloc] initWithTimeIntervalSince1970: - (NSTimeInterval)[tmp unsignedIntValue]]; - [tmp setTimeZone:[self viewTimeZone]]; - if (tmp) [md setObject:tmp forKey:@"startDate"]; - [tmp release]; - } - else - [self logWithFormat:@"missing 'startdate' in record?"]; - - if ((tmp = [_record objectForKey:@"enddate"])) { - tmp = [[NSCalendarDate alloc] initWithTimeIntervalSince1970: - (NSTimeInterval)[tmp unsignedIntValue]]; - [tmp setTimeZone:[self viewTimeZone]]; - if (tmp) [md setObject:tmp forKey:@"endDate"]; - [tmp release]; - } - else - [self logWithFormat:@"missing 'enddate' in record?"]; - } - else { - /* cycle is in _r */ - tmp = [_r startDate]; + if ((tmp = [_record objectForKey:@"startdate"])) { + tmp = [[NSCalendarDate alloc] initWithTimeIntervalSince1970: + (NSTimeInterval)[tmp unsignedIntValue]]; [tmp setTimeZone:[self viewTimeZone]]; - [md setObject:tmp forKey:@"startDate"]; - tmp = [_r endDate]; + if (tmp) [md setObject:tmp forKey:@"startDate"]; + [tmp release]; + } + else + [self logWithFormat:@"missing 'startdate' in record?"]; + + if ((tmp = [_record objectForKey:@"enddate"])) { + tmp = [[NSCalendarDate alloc] initWithTimeIntervalSince1970: + (NSTimeInterval)[tmp unsignedIntValue]]; [tmp setTimeZone:[self viewTimeZone]]; - [md setObject:tmp forKey:@"endDate"]; + if (tmp) [md setObject:tmp forKey:@"endDate"]; + [tmp release]; } + else + [self logWithFormat:@"missing 'enddate' in record?"]; + return md; } -- (void)_flattenCycleRecord:(NSDictionary *)row +- (NSMutableDictionary *)fixupCycleRecord:(NSDictionary *)_record + cycleRange:(NGCalendarDateRange *)_r +{ + NSMutableDictionary *md; + id tmp; + + md = [[_record mutableCopy] autorelease]; + + /* cycle is in _r */ + tmp = [_r startDate]; + [tmp setTimeZone:[self viewTimeZone]]; + [md setObject:tmp forKey:@"startDate"]; + tmp = [_r endDate]; + [tmp setTimeZone:[self viewTimeZone]]; + [md setObject:tmp forKey:@"endDate"]; + + return md; +} + +- (void)_flattenCycleRecord:(NSDictionary *)_row forRange:(NGCalendarDateRange *)_r - intoArray:(NSMutableArray *)ma + intoArray:(NSMutableArray *)_ma { - NSString *uid; - id aptObject; - iCalEvent *apt; - NSArray *ranges; - unsigned k, rCount; - - uid = [row valueForKey:@"uid"]; - -#warning FIXME: lookup done by name, not by UID - // TODO: this is wrong, we need to lookup the appointment by UID, not name - aptObject = [self appointmentWithName:uid inContext:nil]; - - apt = [aptObject event]; - ranges = [apt recurrenceRangesWithinCalendarDateRange:_r]; - rCount = [ranges count]; - for (k = 0; k < rCount; k++) { + NSMutableDictionary *row; + NSDictionary *cycleinfo; + NSCalendarDate *startDate, *endDate; + NGCalendarDateRange *fir; + NSArray *rules, *exRules, *exDates, *ranges; + unsigned i, count; + + cycleinfo = [[_row objectForKey:@"cycleinfo"] propertyList]; + if (cycleinfo == nil) { + [self errorWithFormat:@"cyclic record doesn't have cycleinfo -> %@", _row]; + return; + } + + row = [self fixupRecord:_row fetchRange:_r]; + [row removeObjectForKey:@"cycleinfo"]; + + startDate = [row objectForKey:@"startDate"]; + endDate = [row objectForKey:@"endDate"]; + fir = [NGCalendarDateRange calendarDateRangeWithStartDate:startDate + endDate:endDate]; + rules = [cycleinfo objectForKey:@"rules"]; + exRules = [cycleinfo objectForKey:@"exRules"]; + exDates = [cycleinfo objectForKey:@"exDates"]; + + ranges = [iCalRecurrenceCalculator recurrenceRangesWithinCalendarDateRange:_r + firstInstanceCalendarDateRange:fir + recurrenceRules:rules + exceptionRules:exRules + exceptionDates:exDates]; + count = [ranges count]; + for (i = 0; i < count; i++) { NGCalendarDateRange *rRange; id fixedRow; - rRange = [ranges objectAtIndex:k]; - fixedRow = [self fixupRecord:row fetchRange:rRange]; - if (fixedRow != nil) [ma addObject:fixedRow]; + rRange = [ranges objectAtIndex:i]; + fixedRow = [self fixupCycleRecord:row cycleRange:rRange]; + if (fixedRow != nil) [_ma addObject:fixedRow]; } } @@ -207,7 +231,6 @@ static NSTimeZone *MET = nil; fetchRange:(NGCalendarDateRange *)_r { // TODO: is the result supposed to be sorted by date? - // TODO: move cycle handling out of fixup NSMutableArray *ma; unsigned i, count; @@ -215,24 +238,37 @@ static NSTimeZone *MET = nil; if ((count = [_records count]) == 0) return _records; - // TODO: inefficient, does a lot of fetches for cycles, separate cycle - // handling from fixup! ma = [NSMutableArray arrayWithCapacity:count]; for (i = 0; i < count; i++) { id row; // TODO: what is the type of the record? row = [_records objectAtIndex:i]; - if ([[row valueForKey:@"iscycle"] intValue] != 0) { - [self _flattenCycleRecord:row forRange:_r intoArray:ma]; - } - else { - row = [self fixupRecord:row fetchRange:_r]; - if (row != nil) [ma addObject:row]; - } + row = [self fixupRecord:row fetchRange:_r]; + if (row != nil) [ma addObject:row]; } return ma; } +- (NSArray *)fixupCyclicRecords:(NSArray *)_records + fetchRange:(NGCalendarDateRange *)_r +{ + // TODO: is the result supposed to be sorted by date? + NSMutableArray *ma; + unsigned i, count; + + if (_records == nil) return nil; + if ((count = [_records count]) == 0) + return _records; + + ma = [NSMutableArray arrayWithCapacity:count]; + for (i = 0; i < count; i++) { + id row; // TODO: what is the type of the record? + + row = [_records objectAtIndex:i]; + [self _flattenCycleRecord:row forRange:_r intoArray:ma]; + } + return ma; +} - (NSArray *)fetchFields:(NSArray *)_fields fromFolder:(OCSFolder *)_folder @@ -240,6 +276,7 @@ static NSTimeZone *MET = nil; to:(NSCalendarDate *)_endDate { EOQualifier *qualifier; + NSMutableArray *fields, *ma = nil; NSArray *records; NSString *sql; NGCalendarDateRange *r; @@ -253,24 +290,56 @@ static NSTimeZone *MET = nil; r = [NGCalendarDateRange calendarDateRangeWithStartDate:_startDate endDate:_endDate]; + /* prepare mandatory fields */ + + fields = [NSMutableArray arrayWithArray:_fields]; + [fields addObject:@"uid"]; + [fields addObject:@"startdate"]; + [fields addObject:@"enddate"]; + if (debugOn) [self debugWithFormat:@"should fetch (%@=>%@) ...", _startDate, _endDate]; - sql = [NSString stringWithFormat:@"(startdate < %d) AND (enddate > %d)", + sql = [NSString stringWithFormat:@"(startdate < %d) AND (enddate > %d)" + @" AND (iscycle = 0)", + (unsigned int)[_endDate timeIntervalSince1970], + (unsigned int)[_startDate timeIntervalSince1970]]; + + /* fetch non-recurrent apts first */ + qualifier = [EOQualifier qualifierWithQualifierFormat:sql]; + + records = [_folder fetchFields:fields matchingQualifier:qualifier]; + if (records != nil) { + records = [self fixupRecords:records fetchRange:r]; + if (debugOn) + [self logWithFormat:@"fetched %i records: %@", [records count], records]; + ma = [NSMutableArray arrayWithArray:records]; + } + + /* fetch recurrent apts now */ + sql = [NSString stringWithFormat:@"(startdate < %d) AND (cycleenddate > %d)" + @" AND (iscycle = 1)", (unsigned int)[_endDate timeIntervalSince1970], (unsigned int)[_startDate timeIntervalSince1970]]; qualifier = [EOQualifier qualifierWithQualifierFormat:sql]; - records = [_folder fetchFields:_fields matchingQualifier:qualifier]; - if (records == nil) { + [fields addObject:@"cycleinfo"]; + + records = [_folder fetchFields:fields matchingQualifier:qualifier]; + if (records != nil) { + if (debugOn) + [self logWithFormat:@"fetched %i cyclic records: %@", + [records count], records]; + records = [self fixupCyclicRecords:records fetchRange:r]; + if (!ma) ma = [NSMutableArray arrayWithCapacity:[records count]]; + [ma addObjectsFromArray:records]; + } + else if (ma == nil) { [self errorWithFormat:@"(%s): fetch failed!", __PRETTY_FUNCTION__]; return nil; } - - records = [self fixupRecords:records fetchRange:r]; - if (debugOn) - [self logWithFormat:@"fetched %i records: %@", [records count], records]; - return records; + + return ma; } /* override this in subclasses */ @@ -295,8 +364,7 @@ static NSTimeZone *MET = nil; { static NSArray *infos = nil; // TODO: move to a plist file if (infos == nil) { - infos = [[NSArray alloc] initWithObjects:@"uid", @"startdate", @"enddate", - nil]; + infos = [[NSArray alloc] init]; } return [self fetchFields:infos from:_startDate to:_endDate]; } @@ -308,9 +376,9 @@ static NSTimeZone *MET = nil; static NSArray *infos = nil; // TODO: move to a plist file if (infos == nil) { infos = [[NSArray alloc] initWithObjects: - @"uid", @"startdate", @"enddate", @"title", - @"location", @"orgmail", @"status", @"ispublic", - @"iscycle", @"isallday", nil]; + @"title", + @"location", @"orgmail", @"status", @"ispublic", + @"isallday", nil]; } return [self fetchFields:infos from:_startDate @@ -322,13 +390,12 @@ static NSTimeZone *MET = nil; { static NSArray *infos = nil; // TODO: move to a plist file if (infos == nil) { - infos = [[NSArray alloc] initWithObjects:@"uid", @"startdate", @"enddate", + infos = [[NSArray alloc] initWithObjects: @"title", @"location", @"orgmail", - @"status", @"ispublic", @"iscycle", + @"status", @"ispublic", @"isallday", @"isopaque", @"participants", @"partmails", - @"partstates", @"sequence", - nil]; + @"partstates", @"sequence", nil]; } return [self fetchFields:infos from:_startDate diff --git a/SOGo/SoObjects/Appointments/Version b/SOGo/SoObjects/Appointments/Version index 00d21930..78c27fd9 100644 --- a/SOGo/SoObjects/Appointments/Version +++ b/SOGo/SoObjects/Appointments/Version @@ -1,7 +1,8 @@ # Version file -SUBMINOR_VERSION:=27 +SUBMINOR_VERSION:=28 +# v0.9.28 requires NGiCal v4.5.47 # v0.9.26 requires libSOGo v0.9.30 # v0.9.19 requires NGiCal v4.5.36 # v0.9.13 requires libSOGo v0.9.26 diff --git a/SOGo/UI/Scheduler/ChangeLog b/SOGo/UI/Scheduler/ChangeLog index d9d5a784..29b175f8 100644 --- a/SOGo/UI/Scheduler/ChangeLog +++ b/SOGo/UI/Scheduler/ChangeLog @@ -1,3 +1,7 @@ +2005-03-01 Marcus Mueller + + * UIxCalDateLabel.m: fixed heuristics for month label (v0.9.117) + 2005-02-21 Marcus Mueller * v0.9.116 diff --git a/SOGo/UI/Scheduler/UIxCalDateLabel.m b/SOGo/UI/Scheduler/UIxCalDateLabel.m index 3e31cec5..d594afc7 100644 --- a/SOGo/UI/Scheduler/UIxCalDateLabel.m +++ b/SOGo/UI/Scheduler/UIxCalDateLabel.m @@ -109,8 +109,18 @@ - (NSString *)monthLabel { NSString *l; + unsigned diff; - l = [self localizedNameForMonthOfYear:[self->startDate monthOfYear]]; + diff = [self->startDate monthsBetweenDate:self->endDate]; + if (diff == 0) { + l = [self localizedNameForMonthOfYear:[self->startDate monthOfYear]]; + } + else { + NSCalendarDate *date; + + date = [self->startDate dateByAddingYears:0 months:0 days:15]; + l = [self localizedNameForMonthOfYear:[date monthOfYear]]; + } return [NSString stringWithFormat:@"%@ %d", l, [self->startDate yearOfCommonEra]]; } diff --git a/SOGo/UI/Scheduler/Version b/SOGo/UI/Scheduler/Version index 73dc879d..90947965 100644 --- a/SOGo/UI/Scheduler/Version +++ b/SOGo/UI/Scheduler/Version @@ -1,6 +1,6 @@ # Version file -SUBMINOR_VERSION:=116 +SUBMINOR_VERSION:=117 # v0.9.115 requires NGiCal v4.5.44 # v0.9.113 requires libSOGo v0.9.30