]> err.no Git - sope/blob - sope-ical/NGiCal/iCalCalendar.m
fixed NSCopying *sigh*
[sope] / sope-ical / NGiCal / iCalCalendar.m
1 /*
2   Copyright (C) 2000-2005 SKYRIX Software AG
3
4   This file is part of SOPE.
5
6   SOPE is free software; you can redistribute it and/or modify it under
7   the terms of the GNU Lesser General Public License as published by the
8   Free Software Foundation; either version 2, or (at your option) any
9   later version.
10
11   SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12   WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14   License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with SOPE; see the file COPYING.  If not, write to the
18   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, USA.
20 */
21
22 #include "iCalCalendar.h"
23 #include <SaxObjC/SaxObjC.h>
24 #include "iCalEntityObject.h"
25 #include "common.h"
26
27 @interface iCalCalendar(Privates)
28 - (void)addToEvents:(iCalEvent *)_event;
29 - (void)addToTimezones:(id)_tz;
30 - (void)addToTodos:(iCalToDo *)_todo;
31 - (void)addToJournals:(iCalJournal *)_obj;
32 - (void)addToFreeBusys:(iCalFreeBusy *)_obj;
33 @end
34
35 @implementation iCalCalendar
36
37 static id<NSObject,SaxXMLReader> parser  = nil; // THREAD
38 static SaxObjectDecoder          *sax    = nil; // THREAD
39
40 + (int)version {
41   return [super version] + 0 /* v0 */;
42 }
43 + (void)initialize {
44   NSAssert2([super version] == 0,
45             @"invalid superclass (%@) version %i !",
46             NSStringFromClass([self superclass]), [super version]);
47 }
48
49 + (id<NSObject,SaxXMLReader>)iCalParser {
50   if (sax == nil) {
51     sax = [[SaxObjectDecoder alloc] initWithMappingNamed:@"NGiCal"];;
52     if (sax == nil) {
53       NSLog(@"ERROR(%s): could not create iCal SAX handler!",
54             __PRETTY_FUNCTION__);
55     }
56   }
57   if (sax != nil && parser == nil) {
58     parser =
59       [[[SaxXMLReaderFactory standardXMLReaderFactory] 
60                              createXMLReaderForMimeType:@"text/calendar"]
61                              retain];
62     if (parser == nil) {
63       NSLog(@"ERROR(%s): did not find a parser for text/calendar!",
64             __PRETTY_FUNCTION__);
65       return nil;
66     }
67     
68     [parser setContentHandler:sax];
69     [parser setErrorHandler:sax];
70   }
71   return parser;
72 }
73
74 + (iCalCalendar *)parseCalendarFromSource:(id)_src {
75   static id<NSObject,SaxXMLReader> parser;
76   id root, cal;
77   
78   if ((parser = [self iCalParser]) == nil)
79     return nil;
80   
81   [parser parseFromSource:_src];
82   root = [[sax rootObject] retain];
83   [sax reset];
84   
85   if (root == nil)
86     return nil;
87   if ([root isKindOfClass:self])
88     return [root autorelease];
89   
90   if (![root isKindOfClass:[iCalEntityObject class]]) {
91     NSLog(@"ERROR(%s): parsed object is of an unexpected class %@: %@",
92           __PRETTY_FUNCTION__, NSStringFromClass([root class]), root);
93     [root release];
94     return nil;
95   }
96   
97   /* so we just got an iCalEntityObject, wrap that manually into a cal */
98   cal = [[[self alloc] initWithEntityObject:root] autorelease];
99   [root release]; root = nil;
100   return cal;
101 }
102
103 - (id)initWithEntityObject:(iCalEntityObject *)_entityObject {
104   if ((self = [self init])) {
105     if ([_entityObject isKindOfClass:[iCalEvent class]])
106       [self addToEvents:(iCalEvent *)_entityObject];
107     else if ([_entityObject isKindOfClass:[iCalToDo class]])
108       [self addToTodos:(iCalToDo *)_entityObject];
109     else if ([_entityObject isKindOfClass:[iCalJournal class]])
110       [self addToJournals:(iCalJournal *)_entityObject];
111     else if ([_entityObject isKindOfClass:[iCalFreeBusy class]])
112       [self addToFreeBusys:(iCalFreeBusy *)_entityObject];
113     else if ([_entityObject isNotNull]) {
114       [self errorWithFormat:@"Unexpected entity object: %@", _entityObject];
115       [self release];
116       return nil;
117     }
118   }
119   return self;
120 }
121
122 - (void)dealloc {
123   [self->version   release];
124   [self->calscale  release];
125   [self->prodId    release];
126   [self->method    release];
127
128   [self->todos     release];
129   [self->events    release];
130   [self->journals  release];
131   [self->freeBusys release];
132   [self->timezones release];
133   [super dealloc];
134 }
135
136 /* NSCopying */
137
138 - (id)copyWithZone:(NSZone *)_zone {
139   iCalCalendar *new;
140   
141   new = [super copyWithZone:_zone];
142
143   new->version   = [self->version  copyWithZone:_zone];
144   new->calscale  = [self->calscale copyWithZone:_zone];
145   new->prodId    = [self->prodId   copyWithZone:_zone];
146   new->method    = [self->method   copyWithZone:_zone];
147
148   new->todos      = [self->todos     copyWithZone:_zone];
149   new->events     = [self->events    copyWithZone:_zone];
150   new->journals   = [self->journals  copyWithZone:_zone];
151   new->freeBusys  = [self->freeBusys copyWithZone:_zone];
152   new->timezones  = [self->timezones copyWithZone:_zone];
153
154   return new;
155 }
156
157 /* accessors */
158
159 - (void)setCalscale:(NSString *)_value {
160   ASSIGNCOPY(self->calscale, _value);
161 }
162 - (NSString *)calscale {
163   return self->calscale;
164 }
165 - (void)setVersion:(NSString *)_value {
166   ASSIGNCOPY(self->version, _value);
167 }
168 - (NSString *)version {
169   return self->version;
170 }
171 - (void)setProdId:(NSString *)_value {
172   ASSIGNCOPY(self->prodId, _value);
173 }
174 - (NSString *)prodId {
175   return self->prodId;
176 }
177 - (void)setMethod:(NSString *)_method {
178   ASSIGNCOPY(self->method, _method);
179 }
180 - (NSString *)method {
181   return self->method;
182 }
183
184 - (void)addToEvents:(iCalEvent *)_event {
185   if (_event == nil) return;
186   if (self->events == nil)
187     self->events = [[NSMutableArray alloc] initWithCapacity:4];
188   [self->events addObject:_event];
189 }
190 - (NSArray *)events {
191   return self->events;
192 }
193
194 - (void)addToTimezones:(id)_tz {
195   NSString *tzid;
196   
197   if (_tz == nil) return;
198   if (self->timezones == nil)
199     self->timezones = [[NSMutableDictionary alloc] initWithCapacity:4];
200   
201   if ((tzid = [_tz valueForKey:@"tzid"]) == nil) {
202     [self logWithFormat:@"ERROR: missing timezone-id in timezone: %@", _tz];
203     return;
204   }
205   [self->timezones setObject:_tz forKey:tzid];
206 }
207 - (NSArray *)timezones {
208   return [self->timezones allValues];
209 }
210
211 - (void)addToTodos:(iCalToDo *)_todo {
212   if (_todo == nil) return;
213   if (self->todos == nil)
214     self->todos = [[NSMutableArray alloc] initWithCapacity:4];
215   [self->todos addObject:_todo];
216 }
217 - (NSArray *)todos {
218   return self->todos;
219 }
220
221 - (void)addToJournals:(iCalJournal *)_obj {
222   if (_obj == nil) return;
223   if (self->journals == nil)
224     self->journals = [[NSMutableArray alloc] initWithCapacity:4];
225   [self->journals addObject:_obj];
226 }
227 - (NSArray *)journals {
228   return self->journals;
229 }
230
231 - (void)addToFreeBusys:(iCalFreeBusy *)_obj {
232   if (_obj == nil) return;
233   if (self->freeBusys == nil)
234     self->freeBusys = [[NSMutableArray alloc] initWithCapacity:4];
235   [self->freeBusys addObject:_obj];
236 }
237 - (NSArray *)freeBusys {
238   return self->freeBusys;
239 }
240
241 /* collection */
242
243 - (NSArray *)allObjects {
244   NSMutableArray *ma;
245   
246   ma = [NSMutableArray arrayWithCapacity:32];
247   if (self->events)    [ma addObjectsFromArray:self->events];
248   if (self->todos)     [ma addObjectsFromArray:self->todos];
249   if (self->freeBusys) [ma addObjectsFromArray:self->freeBusys];
250   if (self->journals)  [ma addObjectsFromArray:self->journals];
251   return ma;
252 }
253 - (NSEnumerator *)objectEnumerator {
254   return [[self allObjects] objectEnumerator];
255 }
256
257 /* ical typing */
258
259 - (NSString *)entityName {
260   return @"vcalendar";
261 }
262
263 /* descriptions */
264
265 - (NSString *)description {
266   NSMutableString *ms;
267
268   ms = [NSMutableString stringWithCapacity:128];
269   [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
270
271   if (self->version)  [ms appendFormat:@" v%@",         self->version];
272   if (self->method)   [ms appendFormat:@" method=%@",   self->method];
273   if (self->prodId)   [ms appendFormat:@" product=%@",  self->prodId];
274   if (self->calscale) [ms appendFormat:@" calscale=%@", self->calscale];
275
276   if ([self->events count] > 0)
277     [ms appendFormat:@" events=%@", self->events];
278   if ([self->todos count] > 0)
279     [ms appendFormat:@" todos=%@", self->todos];
280   if ([self->freeBusys count] > 0)
281     [ms appendFormat:@" fb=%@", self->freeBusys];
282   if ([self->journals count] > 0)
283     [ms appendFormat:@" journals=%@", self->journals];
284
285   if ([self->timezones count] > 0)
286     [ms appendFormat:@" tzs=%@", [self->timezones allKeys]];
287   
288   [ms appendString:@">"];
289   return ms;
290 }
291
292 @end /* iCalCalendar */