Removed old commented-out code.
[CleverRabbit.git] / RTKVerse.m
blob6e422ae0d2a0f5297136897c48b1039898fbdd63
1 //
2 //   RTKVerse.m
3 //   (CleverRabbit.app)
4 //
5 //   Copyright (c) 2005 A. Karl Keller (http://karlk.net)
6 //
7 //   This code is open-source, free software, made available without warranty under
8 //   the terms of the GNU General Public License, either version 2 or later (see 
9 //   http://www.gnu.org/licenses/gpl.html or included copy); as such, it may be 
10 //   redistributed and/or modified in accordance with that document.
13 #import "RTKVerse.h"
14 #import "RTKRevision.h"
15 #import "RTKMutableArrayCategory.h"
16 #import "RTKArrayCategory.h"
17 #import "RTKStringCategory.h"
18 #import "RTKMutableAttributedStringCategory.h"
20 #import "Chomp/Chomp.h"
22 @implementation RTKVerse
24 - (id)init
26     if(self = [super init]) {
27         revisions = [[NSMutableArray alloc] init];
28         [self setReference:@""];
29         [self setPreUSFMType:@""];
30                 [self setType:@"\\v"];
31                 locked = NO;
32         [revisions addObject:[[RTKRevision alloc] init]];
33         currentRevisionIndex = 0;
34         
35         [self setDictionary:[NSDictionary dictionary]];
36     }
37     return self;
40 - (id)initWithDictionary:(NSDictionary *)dict
42     if(self = [self init]) {
43         [self setRevisions: (NSMutableArray *)
44          [[RTKRevision collectSelf] revisionWithDictionary:
45           [[dict objectForKey:@"revisions"] each]]];
46         
47         [self setReference:[dict objectForKey:@"reference"]];
48                 
49         [self setType:[dict objectForKey:@"usfmType"]];
50         if(!type) {
51                         [self setType:[dict objectForKey:@"type"]];
52                 }
53                 [self setPreUSFMType:[dict objectForKey:@"type"]];
54         if(!type)
55             [self setType:@"\\v"];
56                 
57         [self setCurrentRevisionIndex:[[dict objectForKey:@"currentRevisionIndex"] intValue]];
58         [self setLocked:[[dict objectForKey:@"locked"] intValue]];
59         
60         [self setDictionary:dict];
61     }
62     return self;
65 + (RTKVerse *)verseWithDictionary:dict
67     return [[[RTKVerse alloc] initWithDictionary:dict] autorelease];
70 - (void)dealloc
72     [reference release];
73     [type release];
74     [revisions release];
75     [dictionary release];
76     
77     [super dealloc];
80 - (id)deepCopy
82     RTKVerse * copy = [[[RTKVerse alloc] init] autorelease];
83     
84     // Should be safe, since NSString is immutable.
85     [copy setReference:reference];
86     [copy setCurrentRevisionIndex:currentRevisionIndex];
87     [copy setRevisions:[revisions deepCopy]];
88     [copy setLocked:locked];
89         [copy setType:type];
90     
91     [copy setDictionary:dictionary];
92         
93     
94     return copy;
97 - (NSMutableDictionary *)dictionaryRepresentation
99     NSMutableDictionary * dict = [NSMutableDictionary dictionaryWithDictionary:dictionary];
100     
101     NSArray * revisionsArray = (NSArray *) [[revisions collect] dictionaryRepresentation];
102     
103     [dict setObject:revisionsArray
104              forKey:@"revisions"];
105     
106     [dict setObject:reference
107              forKey:@"reference"];
108         
109     [dict setObject:preUSFMType
110              forKey:@"type"];
111         
112     [dict setObject:type
113              forKey:@"usfmType"];
114     
115     [dict setObject:[NSNumber numberWithInt:currentRevisionIndex]
116              forKey:@"currentRevisionIndex"];
117         
118         [dict setObject:[NSNumber numberWithInt:locked] forKey:@"locked"];
119     
120     return dict;
123 - (id)initWithString:(NSString *)string
125     if(self = [self init]) {
126         [revisions removeAllObjects];
127         [revisions addObject:[RTKRevision revisionWithString:string]];
128         [self setCurrentRevisionIndex:0];
129     }
130     return self;
133 + (RTKVerse *)verseWithString:string
135     return [[[RTKVerse alloc] initWithString:string] autorelease];
138 - (id)initWithSFMString:(NSString *)string
139            andStateDict:(NSMutableDictionary *)dict
141     if(self = [self init]) {
142         NSMutableArray * strings = [[string componentsSeparatedByString:@" "] mutableCopy];
143         int stringCount = [strings count];
144         
145         // Discard leading 0x20 space characters.
146         while(stringCount > 0 && [[strings objectAtIndex:0] length] == 0) {
147             [strings removeObjectAtIndex:0];
148             stringCount --;
149         }
150         
151         NSString * formatMarker = (stringCount > 0 ? [strings objectAtIndex:0] : @"");
152         NSString * formatMarkerData = (stringCount > 1 ? [strings objectAtIndex:1] : @"");        
153         
154         if([formatMarker isEqualToString:@"\\id"]) {
155             [dict setObject:formatMarkerData forKey:@"book"];
156             [dict setObject:@"1" forKey:@"chapter"];
157             [strings removeObjectsInRange:NSMakeRange(0,2)];
158         } else if([formatMarker isEqualToString:@"\\c"]) {
159             [dict setObject:formatMarkerData forKey:@"chapter"];
160             [dict setObject:@"1" forKey:@"verse"];
161             [strings removeObjectsInRange:NSMakeRange(0,2)];
162         } else if([formatMarker isEqualToString:@"\\v"]) {
163             [dict setObject:formatMarkerData forKey:@"verse"];
164             [strings removeObjectsInRange:NSMakeRange(0,2)];
165         } else if([formatMarker isEqualToString:@"\\mt"]) {
166             if([[dict objectForKey:@"preceding format marker"] isEqualToString:@"\\v"])
167                 [dict setObject:[NSString stringWithFormat:@"%i", 
168                                  [[[[dict objectForKey:@"verse"] componentsSeparatedByString:@"-"] lastObject] intValue] + 1] forKey:@"verse"];
169             if([formatMarkerData intValue] > 0) { // A numbered major title size.
170                 formatMarker = [NSString stringWithFormat:@"%@ %@", formatMarker, formatMarkerData];
171                 [strings removeObjectAtIndex:0];
172             }
173             [strings removeObjectAtIndex:0];
174         } else {
175             if([[dict objectForKey:@"preceding format marker"] isEqualToString:@"\\v"])
176                 [dict setObject:[NSString stringWithFormat:@"%i", 
177                                  [[[[dict objectForKey:@"verse"] componentsSeparatedByString:@"-"] lastObject] intValue] + 1] forKey:@"verse"];
178             [strings removeObjectAtIndex:0];   
179         }
180         
181         [self setType:formatMarker];
182         [self setReference:[NSString stringWithFormat:@"%@ %@:%@", 
183                             [dict objectForKey:@"book"],
184                             [dict objectForKey:@"chapter"],
185                             [dict objectForKey:@"verse"]]];
186         string = [strings componentsJoinedByString:@" "];
187         
188         [revisions removeAllObjects];
189         [revisions addObject:[RTKRevision revisionWithSFMString:string]];
190         [self setCurrentRevisionIndex:0];
191         
192         [dict setObject:formatMarker forKey:@"preceding format marker"];
193     }
194     return self;
197 + (RTKVerse *)verseWithSFMString:string
198                     andStateDict:dict
200     return [[[RTKVerse alloc] initWithSFMString:string
201                                    andStateDict:dict] autorelease];
204 - (void)updateTypeFieldToUSFM
206         [self setPreUSFMType:type];
207         
208         if([type isEqualToString:@"Text"]) {
209                 type = @"\\v";
210         } else if([type isEqualToString:@"Paragraph Break"]) {
211                 type = @"\\p";
212         } else if([type isEqualToString:@"Section Title"]) {
213                 type = @"\\s1";
214         } else if([type isEqualToString:@"Major Title"]) {
215                 type = @"\\mt1";
216         } else if([type isEqualToString:@"Chapter Number"]) {
217                 type = @"\\c";
218         }
221 - (void)appendLine:(NSString *)line
223     [(RTKRevision *)[self currentRevision] appendLine:line];
226 - (NSString *)string
228     NSMutableString * string = [NSMutableString new];
229     
230     RTKRevision * revision = [self currentRevision];
231     
232     NSString * outputReference = nil;
233     if([type isEqualToString:@"\\v"]) {
234         outputReference = [NSString stringWithFormat:@"(%@) ", [reference verse]];
235     } else if([type isEqualToString:@"\\c"]) {
236         outputReference = [NSString stringWithFormat:@"(%@) ", reference];;
237     }
238     
239     [string appendString:
240      [revision stringWithVerseNumber:outputReference]];
241     
242     return string;
245 - (NSString *)sfmString
247     RTKRevision * revision = [self currentRevision];
248     
249     NSString * marker = [[type componentsSeparatedByString:@" "] objectAtIndex:0];
250     
251     if ([marker isEqualToString:@"\\v"]) {
252         return [NSString stringWithFormat:@"%@ %@ %@", type, [reference verse], [revision roman]];
253     } else if ([marker isEqualToString:@"\\c"]) {
254         return [NSString stringWithFormat:@"%@ %@", type, [reference chapter]];
255     } else if ([marker isEqualToString:@"\\mt"]) {
256         return [NSString stringWithFormat:@"%@ %@", type, [revision roman]];
257     } else if ([marker isEqualToString:@"\\id"]) {
258         return [NSString stringWithFormat:@"%@ %@ %@", type, [reference book], [revision roman]];
259     }
260     return [NSString stringWithFormat:@"%@ %@", type, [revision roman]];
263 // TODO: Check for retain problems. Should be autoreleasing more stuff here.
264 - (NSMutableAttributedString *)mutableAttributedString:(BOOL)romanString
266     RTKRevision * revision = [self currentRevision];
267     NSMutableArray * strings = [[[NSMutableArray alloc] init] autorelease];
268     id string;
269     
270     NSMutableAttributedString *newLineString = [[[NSMutableAttributedString alloc] initWithString:@"\n"] autorelease];
271     [newLineString normalFontSize];
272     
273     NSMutableAttributedString *spaceString = [[[NSMutableAttributedString alloc] initWithString:@" "] autorelease];
274     [spaceString normalFontSize];
275     
276     
277     if([type isEqualToString:@"\\v"]) {
278         string = [[NSMutableAttributedString alloc] initWithString:[reference verse]];
279         
280         [string addAttribute:@"RTKVerseComponent" value:@"Verse Reference"];
281         
282         [string superscript];
283         [string smallFontSize];
284         
285         [strings addObject:string];
286         [strings addObject:spaceString];
287         
288         string = [revision mutableAttributedString:romanString];
289         [string addAttribute:@"RTKVerseComponent" value:@"Verse Text"];
290         [string normalFontSize];
291         
292         [strings addObject:string];
293         [strings addObject:spaceString];
294         
295     } else if([type isEqualToString:@"\\p"]) {
296         [strings addObject:newLineString]; [strings addObject:newLineString];
297     } else if([type isEqualToString:@"\\s1"]) {
298         string = [revision mutableAttributedString:romanString];
299         [string addAttribute:@"RTKVerseComponent" value:@"Verse Text"];
300         [string largeFontSize];
301         [strings addObject:newLineString]; [strings addObject:newLineString];
302         [strings addObject:string];
303         [strings addObject:newLineString]; [strings addObject:newLineString];
304     } else if([type isEqualToString:@"\\mt1"]) {
305         string = [revision mutableAttributedString:romanString];
306         [string addAttribute:@"RTKVerseComponent" value:@"Verse Text"];
307         [string largeFontSize];
308         [strings addObject:newLineString];
309         [strings addObject:string];
310         [strings addObject:newLineString];
311     } else if([type isEqualToString:@"\\c"]) {
312         string = [[NSMutableAttributedString alloc] initWithString:[reference chapter]];
313         [string addAttribute:@"RTKVerseComponent" value:@"Chapter Reference"];
314         
315         [string largeFontSize];
316         [strings addObject:newLineString];
317         [strings addObject:string];
318         [strings addObject:newLineString];
319     }
320     NSMutableAttributedString * outputString = [strings mutableAttributedStringFromComponents];
321     [outputString addAttribute:@"RTKVerse" value:self];
322     return outputString;
325 - (BOOL)updateWithAttributedString:(NSAttributedString *)string 
326                            atIndex:(NSUInteger)index
328     NSRange componentRange;
329     NSString *component = [string attribute:@"RTKVerseComponent" 
330                                     atIndex:index 
331                       longestEffectiveRange:&componentRange
332                                     inRange:NSMakeRange(0, [string length])];
333     
334     if(!component) // If it didn't find the component, check one character back.
335         component = [string attribute:@"RTKVerseComponent" 
336                               atIndex:(index-1) 
337                 longestEffectiveRange:&componentRange
338                               inRange:NSMakeRange(0, [string length])];
339     NSAttributedString *componentString = [string attributedSubstringFromRange:componentRange];
340     
341     if([component isEqualToString:@"Verse Text"]) {
342         [[self currentRevision] setRoman:[componentString string]];
343         
344         NSLog(@"%@", [componentString string]);
345         
346         return YES; // Verse accepted change.
347     }
348     return NO; // Verse rejected change.
352 - (void)setDictionary:(NSDictionary *)theDictionary
354     [theDictionary retain];
355     [dictionary release];
356     dictionary = theDictionary;
359 - (NSDictionary *)dictionary
361     return dictionary;
364 - (void)setReference:(NSString *)theReference
366     [theReference retain];
367     [reference release];
368     reference = theReference;
369     
370     [[NSNotificationCenter defaultCenter] postNotificationName:@"RTKVerseSetReference" object:self userInfo:nil];
373 - (NSString *)reference
375     return reference;
378 - (void)setPreUSFMType:(NSString *)theType
380     [theType retain];
381     [preUSFMType release];
382     preUSFMType = theType;
383     
384     [[NSNotificationCenter defaultCenter] postNotificationName:@"RTKVerseSetPreUSFMType" object:self userInfo:nil];
387 - (NSString *)preUSFMType
389     return preUSFMType;
392 - (void)setType:(NSString *)theType
394     [theType retain];
395     [type release];
396     type = theType;
397     
398     [[NSNotificationCenter defaultCenter] postNotificationName:@"RTKVerseSetType" object:self userInfo:nil];
401 - (NSString *)type
403     return type;
406 - (void)setLocked:(BOOL)state
408     locked = state;
409     
410     [[NSNotificationCenter defaultCenter] postNotificationName:@"RTKVerseSetLocked" object:self userInfo:nil];
413 - (BOOL)locked
415         return locked;
418 #pragma mark - revision management
420 - (void)setRevisions:(NSMutableArray *)theRevisions
422     [theRevisions retain];
423     [revisions release];
424     revisions = theRevisions;
425     
426     [[NSNotificationCenter defaultCenter] postNotificationName:@"RTKVerseSetRevisions" object:self userInfo:nil];
429 - (NSMutableArray *)revisions
431     return revisions;
434 - (int)revisionCount
436     return [revisions count];
439 - (void)setCurrentRevisionIndex:(int)index
441     currentRevisionIndex = index;
442     
443     [[NSNotificationCenter defaultCenter] postNotificationName:@"RTKVerseSetCurrentRevisionIndex" object:self userInfo:nil];
446 - (int)currentRevisionIndex
448     return currentRevisionIndex;
451 // Just a convenience method.
452 - (RTKRevision *)currentRevision
454     if([revisions count])
455         return [revisions objectAtIndex:currentRevisionIndex];
456     else
457         return nil;
460 // Another convenience method
461 - (BOOL)blank
463     NSEnumerator * e = [revisions objectEnumerator];
464     RTKRevision * revision;
465     while(revision = [e nextObject]) {
466         if(![revision blank])
467             return NO;
468     }
469     if(![type isEqualToString:@"\\v"])
470                 return NO;
471         if(locked)
472         return NO;
473     return YES;
476 - (BOOL)matchesString:(NSString *)string
478     if([reference containsCaseInsensitiveSubstring:string])
479         return YES;
480     if([type containsCaseInsensitiveSubstring:string])
481         return YES;
482     
483     NSEnumerator * e = [revisions objectEnumerator];
484     RTKRevision * revision;
485     while(revision = [e nextObject]) {
486         if([revision matchesString:string])
487             return YES;
488     }
489     return NO;
492 @end