From 6d1fee088f0339f7a40e20e95253c8f2732cbe98 Mon Sep 17 00:00:00 2001 From: znek Date: Wed, 1 Sep 2004 21:52:57 +0000 Subject: [PATCH] new differ and accompanied functionality git-svn-id: http://svn.opengroupware.org/SOPE/trunk@102 e4a50df8-12e2-0310-a44c-efbce7f8a7e3 --- sope-ical/NGiCal/ChangeLog | 12 + sope-ical/NGiCal/GNUmakefile | 2 + sope-ical/NGiCal/NGiCal.h | 2 + sope-ical/NGiCal/NGiCal.xcode/project.pbxproj | 35 ++- sope-ical/NGiCal/Version | 2 +- sope-ical/NGiCal/common.h | 16 ++ sope-ical/NGiCal/iCalEvent.h | 4 +- sope-ical/NGiCal/iCalEvent.m | 8 + sope-ical/NGiCal/iCalEventChanges.h | 62 +++++ sope-ical/NGiCal/iCalEventChanges.m | 212 ++++++++++++++++++ sope-ical/NGiCal/iCalPerson.h | 3 + sope-ical/NGiCal/iCalPerson.m | 38 ++++ 12 files changed, 393 insertions(+), 3 deletions(-) create mode 100644 sope-ical/NGiCal/iCalEventChanges.h create mode 100644 sope-ical/NGiCal/iCalEventChanges.m diff --git a/sope-ical/NGiCal/ChangeLog b/sope-ical/NGiCal/ChangeLog index bbce5a3e..47f63a9d 100644 --- a/sope-ical/NGiCal/ChangeLog +++ b/sope-ical/NGiCal/ChangeLog @@ -1,3 +1,15 @@ +2004-09-01 Marcus Mueller + + * v4.3.29 + + * iCalEventChanges.[hm]: new class for tracking changes between + two given events + + * iCalEvent.[hm]: new API to generate iCalEventChanges objects. + + * common.h: inline function and macro for "safe" comparison of + object values + 2004-09-01 Helge Hess * GNUmakefile.postamble: copy sax-model to FHS_INSTALL_ROOT + diff --git a/sope-ical/NGiCal/GNUmakefile b/sope-ical/NGiCal/GNUmakefile index 6691770b..63458c49 100644 --- a/sope-ical/NGiCal/GNUmakefile +++ b/sope-ical/NGiCal/GNUmakefile @@ -25,6 +25,7 @@ libNGiCal_HEADER_FILES = \ iCalDuration.h \ iCalTrigger.h \ iCalDataSource.h \ + iCalEventChanges.h \ # IcalResponse.h \ @@ -45,6 +46,7 @@ libNGiCal_OBJC_FILES = \ iCalDuration.m \ iCalTrigger.m \ iCalDataSource.m \ + iCalEventChanges.m \ # NSString+ICal.m \ # IcalElements.m diff --git a/sope-ical/NGiCal/NGiCal.h b/sope-ical/NGiCal/NGiCal.h index 5d4e21c1..e35a4a5f 100644 --- a/sope-ical/NGiCal/NGiCal.h +++ b/sope-ical/NGiCal/NGiCal.h @@ -35,4 +35,6 @@ #include #include +#include + #endif /* __NGiCal_H__ */ diff --git a/sope-ical/NGiCal/NGiCal.xcode/project.pbxproj b/sope-ical/NGiCal/NGiCal.xcode/project.pbxproj index 8d38d37a..17585f44 100644 --- a/sope-ical/NGiCal/NGiCal.xcode/project.pbxproj +++ b/sope-ical/NGiCal/NGiCal.xcode/project.pbxproj @@ -5,6 +5,36 @@ }; objectVersion = 39; objects = { + ADD1FC9906E4D6D400E387F0 = { + fileEncoding = 5; + indentWidth = 2; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = iCalEventChanges.h; + refType = 4; + sourceTree = ""; + }; + ADD1FC9A06E4D6D400E387F0 = { + fileEncoding = 5; + indentWidth = 2; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = iCalEventChanges.m; + refType = 4; + sourceTree = ""; + }; + ADD1FC9B06E4D6D400E387F0 = { + fileRef = ADD1FC9906E4D6D400E387F0; + isa = PBXBuildFile; + settings = { + }; + }; + ADD1FC9C06E4D6D400E387F0 = { + fileRef = ADD1FC9A06E4D6D400E387F0; + isa = PBXBuildFile; + settings = { + }; + }; ADDF4E5106DE4FC600C4E7F8 = { children = ( ADDF4F3E06DE513D00C4E7F8, @@ -91,6 +121,7 @@ ADDF4F6406DE513D00C4E7F8, ADDF4F6606DE513D00C4E7F8, ADDF4F6806DE513D00C4E7F8, + ADD1FC9B06E4D6D400E387F0, ); isa = PBXHeadersBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -128,6 +159,7 @@ ADDF4F6306DE513D00C4E7F8, ADDF4F6506DE513D00C4E7F8, ADDF4F6906DE513D00C4E7F8, + ADD1FC9C06E4D6D400E387F0, ); isa = PBXSourcesBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -165,7 +197,6 @@ GCC_WARN_UNKNOWN_PRAGMAS = NO; INFOPLIST_FILE = "NGiCal-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - OPTIMIZATION_CFLAGS = ""; OTHER_CFLAGS = ""; OTHER_LDFLAGS = "-seg1addr 0xC1E00000 -headerpad_max_install_names"; OTHER_REZFLAGS = ""; @@ -973,6 +1004,7 @@ ADDF4F3406DE513D00C4E7F8, ADDF4F3606DE513D00C4E7F8, ADDF4F3A06DE513D00C4E7F8, + ADD1FC9906E4D6D400E387F0, ); isa = PBXGroup; name = Headers; @@ -997,6 +1029,7 @@ ADDF4F3506DE513D00C4E7F8, ADDF4F3706DE513D00C4E7F8, ADDF4F3B06DE513D00C4E7F8, + ADD1FC9A06E4D6D400E387F0, ); isa = PBXGroup; name = Classes; diff --git a/sope-ical/NGiCal/Version b/sope-ical/NGiCal/Version index d077e9f9..21126fa7 100644 --- a/sope-ical/NGiCal/Version +++ b/sope-ical/NGiCal/Version @@ -2,4 +2,4 @@ MAJOR_VERSION=4 MINOR_VERSION=3 -SUBMINOR_VERSION:=28 +SUBMINOR_VERSION:=29 diff --git a/sope-ical/NGiCal/common.h b/sope-ical/NGiCal/common.h index 1633aa18..3c451451 100644 --- a/sope-ical/NGiCal/common.h +++ b/sope-ical/NGiCal/common.h @@ -27,4 +27,20 @@ #include #include +#define IS_EQUAL(a, b, sel) \ + _iCalSafeCompareObjects(a, b, @selector(sel)) + +static __inline__ BOOL _iCalSafeCompareObjects(id a, id b, SEL comparator) { + id va = a; + id vb = b; + BOOL (*compm)(id, SEL, id); + + if((va == nil && vb != nil) || (va != nil && vb == nil)) + return NO; + else if(va == vb) + return YES; + compm = (BOOL (*)( id, SEL, id))[va methodForSelector:comparator]; + return compm(va, comparator, vb); +} + #endif /* __ICal_common_H__ */ diff --git a/sope-ical/NGiCal/iCalEvent.h b/sope-ical/NGiCal/iCalEvent.h index 1559038f..19f74fcb 100644 --- a/sope-ical/NGiCal/iCalEvent.h +++ b/sope-ical/NGiCal/iCalEvent.h @@ -34,7 +34,7 @@ */ @class NSString, NSMutableArray, NSCalendarDate; -@class iCalPerson; +@class iCalPerson, iCalEventChanges; @interface iCalEvent : iCalEntityObject { @@ -53,6 +53,8 @@ - (BOOL)hasDuration; - (NSTimeInterval)durationAsTimeInterval; +- (iCalEventChanges *)getChangesRelativeToEvent:(iCalEvent *)_event; + @end #endif /* __NGiCal_iCalEvent_H__ */ diff --git a/sope-ical/NGiCal/iCalEvent.m b/sope-ical/NGiCal/iCalEvent.m index b97cbc13..b88259e5 100644 --- a/sope-ical/NGiCal/iCalEvent.m +++ b/sope-ical/NGiCal/iCalEvent.m @@ -22,6 +22,7 @@ #include "iCalEvent.h" #include "iCalPerson.h" +#include "iCalEventChanges.h" #include "common.h" @interface NSString(DurationTimeInterval) @@ -136,6 +137,13 @@ return ms; } +/* changes */ + +- (iCalEventChanges *)getChangesRelativeToEvent:(iCalEvent *)_event { + return [iCalEventChanges changesFromEvent:_event + toEvent:self]; +} + @end /* iCalEvent */ @implementation NSString(DurationTimeInterval) diff --git a/sope-ical/NGiCal/iCalEventChanges.h b/sope-ical/NGiCal/iCalEventChanges.h new file mode 100644 index 00000000..c7614105 --- /dev/null +++ b/sope-ical/NGiCal/iCalEventChanges.h @@ -0,0 +1,62 @@ +/* + Copyright (C) 2004 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$ +// Created by znek on 31.08.04. + +#ifndef __NGiCal_iCalEventChanges_H_ +#define __NGiCal_iCalEventChanges_H_ + +#include + +@class iCalEvent, NSArray, NSMutableArray; + +@interface iCalEventChanges : NSObject +{ + NSMutableArray *insertedAttendees; + NSMutableArray *deletedAttendees; + NSMutableArray *updatedAttendees; + NSMutableArray *insertedAlarms; + NSMutableArray *deletedAlarms; + NSMutableArray *updatedAlarms; + NSMutableArray *updatedProperties; +} + ++ (id)changesFromEvent:(iCalEvent *)_old toEvent:(iCalEvent *)_to; +- (id)initWithFromEvent:(iCalEvent *)_from toEvent:(iCalEvent *)_to; + +- (BOOL)hasChanges; + +- (BOOL)hasAttendeeChanges; +- (NSArray *)insertedAttendees; +- (NSArray *)deletedAttendees; +- (NSArray *)updatedAttendees; + +- (BOOL)hasAlarmChanges; +- (NSArray *)insertedAlarms; +- (NSArray *)deletedAlarms; +- (NSArray *)updatedAlarms; + +- (BOOL)hasPropertyChanges; +- (NSArray *)updatedProperties; + +@end + +#endif /* __NGiCal_iCalEventChanges_H_ */ diff --git a/sope-ical/NGiCal/iCalEventChanges.m b/sope-ical/NGiCal/iCalEventChanges.m new file mode 100644 index 00000000..f8eec4b8 --- /dev/null +++ b/sope-ical/NGiCal/iCalEventChanges.m @@ -0,0 +1,212 @@ +/* + Copyright (C) 2004 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 "iCalEventChanges.h" +#include "iCalEvent.h" +#include "iCalPerson.h" +#include "common.h" + +@interface iCalEventChanges (PrivateAPI) +- (void)_trackAttendeeChanges:(iCalEvent *)_from :(iCalEvent *)_to; +- (void)_trackAlarmChanges:(iCalEvent *)_from :(iCalEvent *)_to; +- (void)_trackPropertyChanges:(iCalEvent *)_from :(iCalEvent *)_to; +@end + +@implementation iCalEventChanges + ++ (id)changesFromEvent:(iCalEvent *)_from toEvent:(iCalEvent *)_to { + return [[[self alloc] initWithFromEvent:_from toEvent:_to] autorelease]; +} + +- (id)initWithFromEvent:(iCalEvent *)_from toEvent:(iCalEvent *)_to { + self = [super init]; + if(self) { + self->insertedAttendees = [[NSMutableArray alloc] init]; + self->deletedAttendees = [[NSMutableArray alloc] init]; + self->updatedAttendees = [[NSMutableArray alloc] init]; + self->insertedAlarms = [[NSMutableArray alloc] init]; + self->deletedAlarms = [[NSMutableArray alloc] init]; + self->updatedAlarms = [[NSMutableArray alloc] init]; + self->updatedProperties = [[NSMutableArray alloc] init]; + [self _trackAttendeeChanges:_from :_to]; + [self _trackPropertyChanges:_from :_to]; + } + return self; +} + +- (void)dealloc { + [self->insertedAttendees release]; + [self->deletedAttendees release]; + [self->updatedAttendees release]; + [self->insertedAlarms release]; + [self->deletedAlarms release]; + [self->updatedAlarms release]; + [self->updatedProperties release]; + [super dealloc]; +} + +- (void)_trackAttendeeChanges:(iCalEvent *)_from :(iCalEvent *)_to { + unsigned f, t, fcount, tcount; + NSArray *fromAttendees, *toAttendees; + + fromAttendees = [_from attendees]; + fcount = [fromAttendees count]; + toAttendees = [_to attendees]; + tcount = [toAttendees count]; + for(f = 0; f < fcount; f++) { + iCalPerson *fp; + BOOL found = NO; + + fp = [fromAttendees objectAtIndex:f]; + + for(t = 0; t < tcount; t++) { + iCalPerson *tp; + + tp = [toAttendees objectAtIndex:t]; + if([fp hasSameEmailAddress:tp]) { + found = YES; + if(![fp isEqualToPerson:tp]) { + [self->updatedAttendees addObject:tp]; + } + break; + } + } + if(!found) { + [self->deletedAttendees addObject:fp]; + } + } + for(t = 0; t < tcount; t++) { + iCalPerson *tp; + BOOL found = NO; + + tp = [toAttendees objectAtIndex:t]; + for(f = 0; f < fcount; f++) { + iCalPerson *fp; + + fp = [fromAttendees objectAtIndex:f]; + if([tp hasSameEmailAddress:fp]) { + found = YES; + break; + } + } + if(!found) + [self->insertedAttendees addObject:tp]; + } +} + +- (void)_trackAlarmChanges:(iCalEvent *)_from :(iCalEvent *)_to { +} + +- (void)_trackPropertyChanges:(iCalEvent *)_from :(iCalEvent *)_to { + if(!IS_EQUAL([_from startDate], [_to startDate], isEqualToDate:)) + [self->updatedProperties addObject:@"startDate"]; + if(!IS_EQUAL([_from endDate], [_to endDate], isEqualToDate:)) + [self->updatedProperties addObject:@"endDate"]; + if(!IS_EQUAL([_from created], [_to created], isEqualToDate:)) + [self->updatedProperties addObject:@"created"]; + if(!IS_EQUAL([_from lastModified], [_to lastModified], isEqualToDate:)) + [self->updatedProperties addObject:@"lastModified"]; + if(![_from durationAsTimeInterval] == [_to durationAsTimeInterval]) + [self->updatedProperties addObject:@"duration"]; + if(!IS_EQUAL([_from summary], [_to summary], isEqualToString:)) + [self->updatedProperties addObject:@"summary"]; + if(!IS_EQUAL([_from location], [_to location], isEqualToString:)) + [self->updatedProperties addObject:@"location"]; + if(!IS_EQUAL([_from comment], [_to comment], isEqualToString:)) + [self->updatedProperties addObject:@"comment"]; + if(!IS_EQUAL([_from priority], [_to priority], isEqualToString:)) + [self->updatedProperties addObject:@"priority"]; + if(!IS_EQUAL([_from status], [_to status], isEqualToString:)) + [self->updatedProperties addObject:@"status"]; + if(!IS_EQUAL([_from accessClass], [_to accessClass], isEqualToString:)) + [self->updatedProperties addObject:@"accessClass"]; + if(!IS_EQUAL([_from sequence], [_to sequence], isEqualToNumber:)) + [self->updatedProperties addObject:@"sequence"]; + if(!IS_EQUAL([_from organizer], [_to organizer], isEqual:)) + [self->updatedProperties addObject:@"organizer"]; +} + +- (BOOL)hasChanges { + return [self hasAttendeeChanges] || + [self hasAlarmChanges] || + [self hasPropertyChanges]; +} + +- (BOOL)hasAttendeeChanges { + return [[self insertedAttendees] count] > 0 || + [[self deletedAttendees] count] > 0 || + [[self updatedAttendees] count] > 0; +} + +- (BOOL)hasAlarmChanges { + return [[self insertedAlarms] count] > 0 || + [[self deletedAlarms] count] > 0 || + [[self updatedAlarms] count] > 0; +} + +- (BOOL)hasPropertyChanges { + return [[self updatedProperties] count] > 0; +} + +- (NSArray *)insertedAttendees { + return self->insertedAttendees; +} +- (NSArray *)deletedAttendees { + return self->deletedAttendees; +} +- (NSArray *)updatedAttendees { + return self->updatedAttendees; +} + +- (NSArray *)insertedAlarms { + return self->insertedAlarms; +} +- (NSArray *)deletedAlarms { + return self->deletedAlarms; +} +- (NSArray *)updatedAlarms { + return self->updatedAlarms; +} + +- (NSArray *)updatedProperties { + return self->updatedProperties; +} + +/* descriptions */ + +- (NSString *)description { + NSMutableString *ms; + + ms = [NSMutableString stringWithCapacity:128]; + [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])]; + + [ms appendFormat:@" updatedProperties=%@", self->updatedProperties]; + [ms appendFormat:@" insertedAttendees=%@", self->insertedAttendees]; + [ms appendFormat:@" deletedAttendees=%@", self->deletedAttendees]; + [ms appendFormat:@" updatedAttendees=%@", self->updatedAttendees]; + + [ms appendString:@">"]; + return ms; +} + +@end diff --git a/sope-ical/NGiCal/iCalPerson.h b/sope-ical/NGiCal/iCalPerson.h index 7b670c70..2fb6bf87 100644 --- a/sope-ical/NGiCal/iCalPerson.h +++ b/sope-ical/NGiCal/iCalPerson.h @@ -55,6 +55,9 @@ - (void)setPartStat:(NSString *)_s; - (NSString *)partStat; +- (BOOL)isEqualToPerson:(iCalPerson *)_other; +- (BOOL)hasSameEmailAddress:(iCalPerson *)_other; + @end #endif /* __NGiCal_iCalPerson_H__ */ diff --git a/sope-ical/NGiCal/iCalPerson.m b/sope-ical/NGiCal/iCalPerson.m index a537156e..0b707356 100644 --- a/sope-ical/NGiCal/iCalPerson.m +++ b/sope-ical/NGiCal/iCalPerson.m @@ -79,6 +79,44 @@ return self->partStat; } +/* comparison */ + +- (unsigned)hash { + if([self email]) + return [[self email] hash]; + return [super hash]; +} + +- (BOOL)isEqual:(id)_other { + if(_other == nil) + return NO; + if([_other class] != self->isa) + return NO; + if([_other hash] != [self hash]) + return NO; + return [self isEqualToPerson:_other]; +} + +- (BOOL)isEqualToPerson:(iCalPerson *)_other { + if(![self hasSameEmailAddress:_other]) + return NO; + if(!IS_EQUAL([self cn], [_other cn], isEqualToString:)) + return NO; + if(!IS_EQUAL([self rsvp], [_other rsvp], isEqualToString:)) + return NO; + if(!IS_EQUAL([self partStat], [_other partStat], isEqualToString:)) + return NO; + if(!IS_EQUAL([self role], [_other role], isEqualToString:)) + return NO; + if(!IS_EQUAL([self xuid], [_other xuid], isEqualToString:)) + return NO; + return YES; +} + +- (BOOL)hasSameEmailAddress:(iCalPerson *)_other { + return IS_EQUAL([self email], [_other email], isEqualToString:); +} + /* descriptions */ - (NSString *)description { -- 2.39.5