Use initialize, not load, wherever possible.
[adiumx.git] / Source / Logorrhea / Chat.mm
blob358b51c013f271dc452136f8ae492c9ddb635edd
1 //
2 //  Chat.m
3 //  Logtastic
4 //
5 //  Created by Jan Van Tol on Sat Dec 14 2002.
6 //  Copyright (c) 2002 Spiny Software. All rights reserved.
7 //
9 #import "Chat.h"
10 #import "InstantMessage.h"
11 #import "FileAttributes.h"
12 #import "AddressBookUtils.h"
14 @implementation Chat
16 - (id)initWithBuddy:(Buddy *)buddy path:(NSString *)path
18     self = [super init];
19     
20     myBuddy = [buddy retain];
21         creationDate = [[FileAttributes getCreationDateForPath:path] retain];
22     myPath = [path retain];
23     
24     return self;
27 - (void)setCreationDate:(NSDate *)date
29     creationDate = date;
30     [creationDate retain];
33 //Accessor methods.
34 - (NSDate *)creationDate
36     return creationDate;
39 - (Buddy *)buddy
40
41     return myBuddy;
44 - (NSString *)path
46     return myPath;
49 //Opens in iChat.
50 - (void)open
52     [[NSWorkspace sharedWorkspace] openFile:[myPath stringByExpandingTildeInPath] withApplication:@"iChat"];
55 //Returns a description of the Chat - a nicely formatted date string. We strip the leading zero on the hour so it'll look cleaner.
56 - (NSString *)description
58     NSCalendarDate *createdDate = [creationDate dateWithCalendarFormat:@"%c" timeZone:nil];
59     NSString *hourWithoutLeadingZero;
60     if ([[[createdDate descriptionWithCalendarFormat:@"%I"] substringToIndex:1] isEqualToString:@"0"])
61         {
62         hourWithoutLeadingZero = [[createdDate descriptionWithCalendarFormat:@"%I"] substringFromIndex:1];
63     }
64         else
65         {
66         hourWithoutLeadingZero = [createdDate descriptionWithCalendarFormat:@"%I"];
67     }
68     
69     NSString *dateDescription = [createdDate descriptionWithCalendarFormat:@"%a %b %e %Y, "];
70     dateDescription = [dateDescription stringByAppendingString: hourWithoutLeadingZero];
71     dateDescription = [dateDescription stringByAppendingString: [createdDate descriptionWithCalendarFormat:@":%M %p"]];
72     
73     return dateDescription;
76 //Comparison method for sorting by date
77 - (NSComparisonResult)compareByDate:(Chat *)otherChat
79     return (NSComparisonResult) - [creationDate compare:[otherChat creationDate]];
82 //Comparison method for sorting by buddy name
83 - (NSComparisonResult)compareByBuddy:(Chat *)otherChat
85     return [[myBuddy description] compare:[[otherChat buddy] description]];
88 - (void) loadContents
90         if (chatContents == nil)
91         {
92                 NSData *chatLog = [[NSData alloc] initWithContentsOfMappedFile:myPath];
93                 if ([myPath hasSuffix:@".ichat"]) // check for tiger-style chat transcript
94                 {
95                         NS_DURING
96                                 chatContents = [[NSKeyedUnarchiver unarchiveObjectWithData:chatLog] retain];
97                         NS_HANDLER
98                                 NSLog(@"Caught exception from NSKeyedUnarchiver - %@", [localException reason]);
99                                 chatContents = nil;
100                         NS_ENDHANDLER
101                         [chatLog release];
102                 }
103                 else
104                 {
105                         NS_DURING
106                                 chatContents = [[NSUnarchiver unarchiveObjectWithData:chatLog] retain];
107                         NS_HANDLER
108                                 NSLog(@"Caught exception from NSUnarchiver - %@", [localException reason]);
109                                 chatContents = nil;
110                         NS_ENDHANDLER
111                         [chatLog release];
112                 }
113                 
114                 if (![chatContents isKindOfClass:[NSArray class]])
115                 {
116                         [chatContents release];
117                         chatContents = nil;
118                 }
119                 
120                 if (chatContents != nil)
121                 {
122                         for (unsigned int i=0; i < [chatContents count]; i++)
123                         {
124                                 id obj = [chatContents objectAtIndex:i];
125                                 if ([obj isKindOfClass:[NSArray class]])
126                                 {
127                                         instantMessages = [obj retain];
128                                         break;
129                                 }
130                         }
131                 }
132         }
135 //Search method.
136 - (BOOL)logContainsString:(NSString *)string
139         [self loadContents];
140         
141         if (instantMessages != nil)
142         {
143                 //Divide into an array of terms, so we don't search for phrases only. TO DO: More advanced searching, allowing quotes around terms to search for a phrase, and more.
144                 NSArray *searchTerms = [string componentsSeparatedByString:@" "];
146                 int foundCount = 0;
148                 int searchTermsCount = [searchTerms count];
149                 for (int i=0; i < searchTermsCount; i++)
150                 {
151                         NSString *searchTerm = [searchTerms objectAtIndex:i];
152                         
153                         for (unsigned int j=0; j < [instantMessages count]; j++)
154                         {
155                                 InstantMessage *im = [instantMessages objectAtIndex:j];
156                                 
157                                 if (im)
158                                 {
159                                         NSString *searchString = [[im text] string];
160                                         //We use a case-insensitive search, but there could be an option to control this.
161                                         if ([searchString rangeOfString:searchTerm options:NSCaseInsensitiveSearch].location != NSNotFound)
162                                         {
163                                                 foundCount++;
164                                                 break;
165                                         }
166                                 }
167                         }
168                         
169                         if (foundCount >= searchTermsCount)
170                         {
171                                 return YES;
172                         }
173                 }
174         }
175         
176     return NO;
179 - (NSAttributedString *) getFormattedContentsWithSearchTermsHilighted:(NSString *) searchTermsStr firstFoundIndex:(int *) foundIndex
181         BOOL firstFound = false;
182         
183         NSAttributedString *ret = [self getFormattedContents];
184         if (searchTermsStr && [searchTermsStr length] > 0)
185         {
186                 NSArray *searchTerms = [searchTermsStr componentsSeparatedByString:@" "];
188                 NSMutableAttributedString *retWithHilite = [[NSMutableAttributedString alloc] initWithAttributedString:ret];
189                 NSString *retAsString = [retWithHilite string];
190                 NSDictionary *colorAttrib = [NSDictionary dictionaryWithObject:[NSColor yellowColor] forKey:NSBackgroundColorAttributeName];
191                 
192                 for (unsigned int i=0; i < [searchTerms count]; i++)
193                 {
194                         unsigned int strLength = [retAsString length];
195                         NSString *searchTerm = [searchTerms objectAtIndex:i];
196                 
197                         NSRange searchRange = NSMakeRange(0, strLength);
198                         
199                         while (true && (searchRange.location + searchRange.length) <= strLength)
200                         {
201                                 NSRange foundRange = [retAsString rangeOfString:searchTerm options:NSCaseInsensitiveSearch range:searchRange];
202                                 if (foundRange.location == NSNotFound)
203                                         break;
204                                 else
205                                 {                                       
206                                         searchRange.location = foundRange.location + 1;
207                                         searchRange.length = strLength - searchRange.location;
208                                         
209                                         [retWithHilite addAttributes:colorAttrib range:foundRange];
211                                         if (!firstFound)
212                                         {
213                                                 *foundIndex = searchRange.location;
214                                                 firstFound = true;
215                                         }
216                                 }
217                         }
218                 }
219                 
220                 return [retWithHilite autorelease];
221         }
222         else
223         {
224                 return ret;
225         }
228 - (NSAttributedString *) getFormattedContents
230         [self loadContents];
231         NSMutableAttributedString *buf = [[NSMutableAttributedString alloc] initWithString:@""];
232         NSDictionary *gapAttrib = [NSDictionary dictionaryWithObject:[NSFont userFontOfSize:3.0] forKey:NSFontAttributeName];
233         NSAttributedString *gap = [[NSAttributedString alloc] initWithString:@"\n" attributes:gapAttrib];
235         [buf appendAttributedString:gap];
236         
237         for (unsigned int i=0; i < [instantMessages count]; i++)
238         {
239                 InstantMessage *im = [instantMessages objectAtIndex:i];
240                 Presentity *sender = [im sender];
241                 NSAttributedString *text = [im text];
242                 
243                 NSDictionary *attribsOfText = nil;
244                 
245                 if (text && [text length] > 0)
246                         attribsOfText = [text attributesAtIndex:0 effectiveRange:nil];
247                 
248                 if (sender)
249                 {
250                         NSString *realName = [AddressBookUtils lookupRealNameForIMNick:[sender senderID]];
251                         if (!realName)
252                                 realName = [sender senderID];
253                         
254                         NSString *formattedName = [realName stringByAppendingString:@": "];
255                         NSAttributedString *senderName = [[NSAttributedString alloc] initWithString:formattedName attributes:attribsOfText];
256                         [buf appendAttributedString:senderName];
257                         [senderName release];
258                 }
259                 [buf appendAttributedString:text];
260                                 
261                 NSAttributedString *lineBreak = [[NSAttributedString alloc] initWithString:@"\n" attributes:attribsOfText];
262                 [buf appendAttributedString:lineBreak];
263                 [lineBreak release];
264                 
265                 [buf appendAttributedString:gap];
266         }
268         [gap release];
269         
270                                                                                 
271         //[buf addAttributes:baselineAttrib range:NSMakeRange(0, [[buf string] length])];
272         
273         return [buf autorelease];
276 //Get tab delimited text version of chat
277 - (NSString *) exportableContents
279     [self loadContents];
280     NSMutableString *buf = [[NSMutableString alloc] initWithString:@""];
281     
282     for (unsigned int i=0; i < [instantMessages count]; i++)
283         {
284         InstantMessage *im = [instantMessages objectAtIndex:i];
285         Presentity *sender = [im sender];
286                 NSAttributedString *text = [im text];
287                 NSDate *date = [im date];
288         if (sender)
289                 {
290             [buf appendString:[[NSArray arrayWithObjects:
291                 [self buddy],
292                 [sender senderID],
293                 [date descriptionWithCalendarFormat:@"%m/%d/%Y" timeZone:nil locale:nil],
294                 [date descriptionWithCalendarFormat:@"%H:%M:%S" timeZone:nil locale:nil],
295                 [text string],nil]
296                   componentsJoinedByString:@"\t"]];
297             [buf appendString:@"\r"];
298         }
299     }
300     return [buf autorelease];
303 - (NSArray *) participants
305         NSMutableSet *participantSet = [[NSMutableSet alloc] init];
306         
307     for (unsigned int i=0; i < [instantMessages count]; i++)
308         {
309         InstantMessage *im = [instantMessages objectAtIndex:i];
310         Presentity *sender = [im sender];
311                 [participantSet addObject:[sender senderID]];
312     }
313         
314         return [participantSet allObjects];
317 @end