+2005-03-01 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * 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 <helge.hess@opengroupware.org>
* OCSFolder.m: added support for storing content and quick info in
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 \
#include "common.h"
#include <SaxObjC/SaxObjC.h>
#include <NGiCal/NGiCal.h>
+#include "iCalRepeatableEntityObject+OCS.h"
@implementation OCSiCalFieldExtractor
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"];
AD0CF977071FE18800E72147 = {
children = (
AD0CF97E071FE18800E72147,
- AD0CF97D071FE18800E72147,
- AD0CF978071FE18800E72147,
- AD0CF979071FE18800E72147,
- AD0CF97A071FE18800E72147,
- AD0CF97B071FE18800E72147,
- AD0CF97C071FE18800E72147,
- AD0CF97F071FE18800E72147,
- AD0CF980071FE18800E72147,
- AD0CF981071FE18800E72147,
- AD0CF982071FE18800E72147,
- AD0CF983071FE18800E72147,
+ ADB79C3707D4B7AA00CA782A,
+ ADB79C3A07D4B7B800CA782A,
);
isa = PBXGroup;
name = SQL;
AD0CF960071FE18800E72147,
AD0CF952071FE18800E72147,
AD0CF954071FE18800E72147,
+ ADB79C6A07D4B92B00CA782A,
);
indentWidth = 2;
isa = PBXGroup;
AD0CF95F071FE18800E72147,
AD0CF951071FE18800E72147,
AD0CF953071FE18800E72147,
+ ADB79C6907D4B92B00CA782A,
);
indentWidth = 2;
isa = PBXGroup;
refType = 4;
sourceTree = "<group>";
};
+ ADB79C3207D4B7A200CA782A = {
+ fileEncoding = 5;
+ isa = PBXFileReference;
+ lastKnownFileType = text;
+ path = "folderinfo-create.sqlite";
+ refType = 4;
+ sourceTree = "<group>";
+ };
+ ADB79C3307D4B7A200CA782A = {
+ fileEncoding = 5;
+ isa = PBXFileReference;
+ lastKnownFileType = text;
+ path = "foldertablecreate-helge-privcal.sqlite";
+ refType = 4;
+ sourceTree = "<group>";
+ };
+ ADB79C3407D4B7A200CA782A = {
+ fileEncoding = 5;
+ isa = PBXFileReference;
+ lastKnownFileType = text.script.sh;
+ path = "generate-folderinfo-sql-for-users-sqlite.sh";
+ refType = 4;
+ sourceTree = "<group>";
+ };
+ ADB79C3707D4B7AA00CA782A = {
+ children = (
+ ADB79C3207D4B7A200CA782A,
+ ADB79C3307D4B7A200CA782A,
+ ADB79C3407D4B7A200CA782A,
+ );
+ isa = PBXGroup;
+ name = SQLite;
+ refType = 4;
+ sourceTree = "<group>";
+ };
+ ADB79C3A07D4B7B800CA782A = {
+ children = (
+ AD0CF97D071FE18800E72147,
+ AD0CF978071FE18800E72147,
+ AD0CF979071FE18800E72147,
+ AD0CF97A071FE18800E72147,
+ AD0CF97B071FE18800E72147,
+ AD0CF97C071FE18800E72147,
+ AD0CF97F071FE18800E72147,
+ AD0CF980071FE18800E72147,
+ AD0CF981071FE18800E72147,
+ AD0CF982071FE18800E72147,
+ AD0CF983071FE18800E72147,
+ );
+ isa = PBXGroup;
+ name = PostgreSQL;
+ refType = 4;
+ sourceTree = "<group>";
+ };
+ ADB79C6907D4B92B00CA782A = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ lastKnownFileType = sourcecode.c.h;
+ path = "iCalRepeatableEntityObject+OCS.h";
+ refType = 4;
+ sourceTree = "<group>";
+ };
+ ADB79C6A07D4B92B00CA782A = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ lastKnownFileType = sourcecode.c.objc;
+ path = "iCalRepeatableEntityObject+OCS.m";
+ refType = 4;
+ sourceTree = "<group>";
+ };
};
rootObject = AD0CF947071FE16800E72147;
}
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
sqlType = "INT";
allowsNull = NO;
},
+ {
+ columnName = cylceenddate;
+ sqlType = "INT";
+ allowsNull = YES;
+ },
{
columnName = title;
sqlType = "VARCHAR(1000)";
sqlType = "INT";
allowsNull = YES;
},
+ {
+ columnName = cycleinfo;
+ sqlType = "VARCHAR(1000)";
+ allowsNull = YES;
+ },
{
columnName = ispublic;
sqlType = "INT";
--- /dev/null
+/*
+ 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 <NGiCal/NGiCal.h>
+
+@interface iCalRepeatableEntityObject (OCS)
+
+- (NSString *)cycleInfo;
+
+@end
+
+#endif /* __OGoContentStore_iCalRepeatableEntityObject_OCS_H_ */
--- /dev/null
+/*
+ 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
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
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 */
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 */
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
refType = 4;
sourceTree = "<group>";
};
- AD86234407CA03D9004CD707 = {
- fileEncoding = 5;
- isa = PBXFileReference;
- lastKnownFileType = text.xml;
- path = UIxMailEditor.wox;
- refType = 4;
- sourceTree = "<group>";
- };
- AD86234507CA03D9004CD707 = {
- fileEncoding = 5;
- isa = PBXFileReference;
- lastKnownFileType = text.xml;
- path = UIxMailEditorAttach.wox;
- refType = 4;
- sourceTree = "<group>";
- };
- AD86234607CA03D9004CD707 = {
- fileEncoding = 5;
- isa = PBXFileReference;
- lastKnownFileType = text.xml;
- path = UIxMailFilterPanel.wox;
- refType = 4;
- sourceTree = "<group>";
- };
- AD86234707CA03D9004CD707 = {
- fileEncoding = 5;
- isa = PBXFileReference;
- lastKnownFileType = text.xml;
- path = UIxMailListView.wox;
- refType = 4;
- sourceTree = "<group>";
- };
- AD86234807CA03D9004CD707 = {
- fileEncoding = 5;
- isa = PBXFileReference;
- lastKnownFileType = text.xml;
- path = UIxMailMainFrame.wox;
- refType = 4;
- sourceTree = "<group>";
- };
- AD86234907CA03D9004CD707 = {
- fileEncoding = 5;
- isa = PBXFileReference;
- lastKnownFileType = text.xml;
- path = UIxMailMoveToPopUp.wox;
- refType = 4;
- sourceTree = "<group>";
- };
- AD86234A07CA03D9004CD707 = {
- fileEncoding = 5;
- isa = PBXFileReference;
- lastKnownFileType = text.xml;
- path = UIxMailPartAlternativeViewer.wox;
- refType = 4;
- sourceTree = "<group>";
- };
- AD86234B07CA03D9004CD707 = {
- fileEncoding = 5;
- isa = PBXFileReference;
- lastKnownFileType = text.xml;
- path = UIxMailPartHTMLViewer.wox;
- refType = 4;
- sourceTree = "<group>";
- };
- AD86234C07CA03D9004CD707 = {
- fileEncoding = 5;
- isa = PBXFileReference;
- lastKnownFileType = text.xml;
- path = UIxMailPartICalViewer.wox;
- refType = 4;
- sourceTree = "<group>";
- };
- AD86234D07CA03D9004CD707 = {
- fileEncoding = 5;
- isa = PBXFileReference;
- lastKnownFileType = text.xml;
- path = UIxMailPartImageViewer.wox;
- refType = 4;
- sourceTree = "<group>";
- };
- AD86234E07CA03D9004CD707 = {
- fileEncoding = 5;
- isa = PBXFileReference;
- lastKnownFileType = text.xml;
- path = UIxMailPartLinkViewer.wox;
- refType = 4;
- sourceTree = "<group>";
- };
- AD86234F07CA03D9004CD707 = {
- fileEncoding = 5;
- isa = PBXFileReference;
- lastKnownFileType = text.xml;
- path = UIxMailPartMessageViewer.wox;
- refType = 4;
- sourceTree = "<group>";
- };
- AD86235007CA03D9004CD707 = {
- fileEncoding = 5;
- isa = PBXFileReference;
- lastKnownFileType = text.xml;
- path = UIxMailPartMixedViewer.wox;
- refType = 4;
- sourceTree = "<group>";
- };
- AD86235107CA03D9004CD707 = {
- fileEncoding = 5;
- isa = PBXFileReference;
- lastKnownFileType = text.xml;
- path = UIxMailPartTextViewer.wox;
- refType = 4;
- sourceTree = "<group>";
- };
- AD86235207CA03D9004CD707 = {
- fileEncoding = 5;
- isa = PBXFileReference;
- lastKnownFileType = text.xml;
- path = UIxMailSortableTableHeader.wox;
- refType = 4;
- sourceTree = "<group>";
- };
- AD86235307CA03D9004CD707 = {
- fileEncoding = 5;
- isa = PBXFileReference;
- lastKnownFileType = text.xml;
- path = UIxMailToolbar.wox;
- refType = 4;
- sourceTree = "<group>";
- };
AD86235407CA03D9004CD707 = {
fileEncoding = 5;
isa = PBXFileReference;
refType = 4;
sourceTree = "<group>";
};
- AD86235507CA03D9004CD707 = {
- fileEncoding = 5;
- isa = PBXFileReference;
- lastKnownFileType = text.xml;
- path = UIxMailTree.wox;
- refType = 4;
- sourceTree = "<group>";
- };
- AD86235607CA03D9004CD707 = {
- fileEncoding = 5;
- isa = PBXFileReference;
- lastKnownFileType = text.xml;
- path = UIxMailView.wox;
- refType = 4;
- sourceTree = "<group>";
- };
- AD86235707CA03D9004CD707 = {
- fileEncoding = 5;
- isa = PBXFileReference;
- lastKnownFileType = text.xml;
- path = UIxMailWindowCloser.wox;
- refType = 4;
- sourceTree = "<group>";
- };
AD86235807CA03D9004CD707 = {
fileEncoding = 5;
isa = PBXFileReference;
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;
refType = 4;
sourceTree = "<group>";
};
+ ADB79CAD07D4BF1600CA782A = {
+ fileEncoding = 5;
+ indentWidth = 8;
+ isa = PBXFileReference;
+ lastKnownFileType = text;
+ path = ChangeLog;
+ refType = 4;
+ sourceTree = "<group>";
+ tabWidth = 8;
+ usesTabs = 1;
+ };
ADBE3C490726AF4C000FEA6A = {
fileEncoding = 5;
indentWidth = 2;
};
E87206090692E3D00099CBBD = {
children = (
+ ADB79CAD07D4BF1600CA782A,
E872064B0692E3D00099CBBD,
E87206420692E3D00099CBBD,
ADDF4BE606DCF5E200C4E7F8,
+2005-03-01 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * 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 <helge.hess@skyrix.com>
* SOGoAppointmentFolder.m: minor code cleanups (v0.9.27)
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];
}
}
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;
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
to:(NSCalendarDate *)_endDate
{
EOQualifier *qualifier;
+ NSMutableArray *fields, *ma = nil;
NSArray *records;
NSString *sql;
NGCalendarDateRange *r;
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 */
{
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];
}
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
{
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
# 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
+2005-03-01 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * UIxCalDateLabel.m: fixed heuristics for month label (v0.9.117)
+
2005-02-21 Marcus Mueller <znek@mulle-kybernetik.com>
* v0.9.116
- (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]];
}
# Version file
-SUBMINOR_VERSION:=116
+SUBMINOR_VERSION:=117
# v0.9.115 requires NGiCal v4.5.44
# v0.9.113 requires libSOGo v0.9.30