root/trunk/lilypad/Sources/LPMessageCenter.m @ 166

Revision 166, 21.2 KB (checked in by jppavao, 5 years ago)

Added a badge to the app dock icon that displays the number of unread offline messages. Also added a dock menu. References #24 and #76.

Line 
1//
2//  LPMessageCenter.m
3//  Lilypad
4//
5//      Copyright (C) 2006-2007 PT.COM,  All rights reserved.
6//      Author: Joao Pavao <jppavao@criticalsoftware.com>
7//
8//      For more information on licensing, read the README file.
9//      Para mais informações sobre o licenciamento, leia o ficheiro README.
10//
11
12#import "LPMessageCenter.h"
13#import "LPAccount.h"
14#import "LPRoster.h"
15#import "LPPresenceSubscription.h"
16#import "LPContact.h"
17#import "LPContactEntry.h"
18#import "LPEventNotificationsHandler.h"
19
20
21#define CURRENT_VERSION_NR 2
22
23
24@implementation LPSapoNotificationChannel
25
26- (void)awakeFromFetch
27{
28        if ([[self valueForKey:@"unreadCount"] intValue] == 0) {
29                // Make sure the unread count is correct. We may be migrating from an older data store
30                // that didn't have this key yet.
31               
32                NSPredicate *pred = [NSPredicate predicateWithFormat:@"unread == YES"];
33                int realUnreadCount = [[[[self valueForKey:@"notifications"] allObjects] filteredArrayUsingPredicate:pred] count];
34               
35                if (realUnreadCount > 0)
36                        [self setValue:[NSNumber numberWithInt:realUnreadCount] forKey:@"unreadCount"];
37        }
38}
39
40- (void)addToUnreadCount:(int)increment
41{
42        int currentCount = [[self valueForKey:@"unreadCount"] intValue];
43        [self setValue:[NSNumber numberWithInt:(currentCount + increment)] forKey:@"unreadCount"];
44}
45
46@end
47
48
49@implementation LPSapoNotification
50
51+ (void)initialize
52{
53        [self setKeys:[NSArray arrayWithObjects:@"subject", @"body", @"itemURL", nil]
54                  triggerChangeNotificationsForDependentKey:@"attributedStringDescription"];
55}
56
57- (NSAttributedString *)attributedStringDescription
58{
59        NSMutableAttributedString *resultingStr = [[NSMutableAttributedString alloc] init];
60       
61        NSFont *boldFont = [NSFont boldSystemFontOfSize:10];
62        NSFont *plainFont = [NSFont systemFontOfSize:10];
63       
64        // Subject
65        [resultingStr appendAttributedString:
66                [[[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@\n\n", [self valueForKey:@"subject"]]
67                                                                                 attributes:[NSDictionary dictionaryWithObject:boldFont forKey:NSFontAttributeName]] autorelease]];
68       
69        // Body
70        [resultingStr appendAttributedString:
71                [[[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@\n\n", [self valueForKey:@"body"]]
72                                                                                 attributes:[NSDictionary dictionaryWithObject:plainFont forKey:NSFontAttributeName]] autorelease]];
73       
74        // URL
75        [resultingStr appendAttributedString:
76                [[[NSAttributedString alloc] initWithString:[self valueForKey:@"itemURL"]
77                                                                                 attributes:[NSDictionary dictionaryWithObjectsAndKeys:
78                                                                                         plainFont, NSFontAttributeName,
79                                                                                         [self valueForKey:@"itemURL"], NSLinkAttributeName,
80                                                                                         [NSCursor pointingHandCursor], NSCursorAttributeName,
81                                                                                         nil]] autorelease]];
82       
83        return [resultingStr autorelease];
84}
85
86- (void)markAsRead
87{
88        if ([[self valueForKey:@"unread"] boolValue]) {
89                [self setValue:[NSNumber numberWithBool:NO] forKey:@"unread"];
90                [[self valueForKey:@"channel"] addToUnreadCount:(-1)];
91        }
92}
93
94@end
95
96
97#pragma mark -
98
99
100@interface LPMessageCenter (Private)
101+ (NSManagedObjectModel *)p_managedObjectModelWithVersionNr:(unsigned int)version;
102+ (void)p_migrateOfflineMessagesFromManagedObjectContext:(NSManagedObjectContext *)sourceContext toContext:(NSManagedObjectContext *)targetContext;
103+ (void)p_migrateSapoNotificationsFromManagedObjectContext:(NSManagedObjectContext *)sourceContext toContext:(NSManagedObjectContext *)targetContext;
104+ (BOOL)p_shouldMigrateFromXMLFilePath:(NSString *)xmlFilePath toSQLiteFilePath:(NSString *)sqliteFilePath;
105+ (NSString *)p_migratePersistentStoreWithURL:(NSURL *)storeURL storeType:(NSString *)storeType fromVersion:(int)storeVersionNr;
106- (NSPersistentStoreCoordinator *)p_persistentStoreCoordinator;
107
108- (void)p_updateUnreadOfflineMessagesCountFromManagedObjectsContextEmittingKVONotification:(BOOL)emitNotification;
109- (void)p_setUnreadOfflineMessagesCount:(int)count emitKVONotification:(BOOL)emitNotification;
110
111- (void)p_managedObjectContextObjectsDidChange:(NSNotification *)notif;
112@end
113
114
115#pragma mark -
116
117
118@implementation LPMessageCenter
119
120- init
121{
122        if (self = [super init]) {
123                m_presenceSubscriptionsByJID = [[NSMutableDictionary alloc] init];
124                m_presenceSubscriptions = [[NSMutableArray alloc] init];
125               
126                // Mark the offline messages count as uninitialized
127                m_unreadOfflineMessagesCount = -1;
128        }
129        return self;
130}
131
132- (void)dealloc
133{
134        [[NSNotificationCenter defaultCenter] removeObserver:self];
135       
136        [m_presenceSubscriptionsByJID release];
137        [m_presenceSubscriptions release];
138       
139        [m_managedObjectModel release];
140        [m_persistentStoreCoordinator release];
141        [m_managedObjectContext release];
142        [m_sapoNotifChannels release];
143       
144        [super dealloc];
145}
146
147
148#pragma mark -
149#pragma mark Presence Subscriptions
150
151
152- (NSArray *)presenceSubscriptions
153{
154        return [[m_presenceSubscriptions retain] autorelease];
155}
156
157- (void)addReceivedPresenceSubscription:(LPPresenceSubscription *)presSub
158{
159        [m_presenceSubscriptionsByJID setValue:presSub forKey:[[presSub contactEntry] address]];
160       
161        NSIndexSet *indexes = [NSIndexSet indexSetWithIndex:[m_presenceSubscriptions count]];
162        [self willChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:@"presenceSubscriptions"];
163        [m_presenceSubscriptions addObject:presSub];
164        [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:@"presenceSubscriptions"];
165       
166        // Notify the user
167        [[LPEventNotificationsHandler defaultHandler] notifyReceptionOfPresenceSubscription:presSub];
168}
169
170
171#pragma mark -
172#pragma mark CoreData Stuff
173
174
175+ (NSManagedObjectModel *)p_managedObjectModelWithVersionNr:(unsigned int)version
176{
177        NSString        *filename = [NSString stringWithFormat:@"MessageCenter_v%d", version];
178        NSString        *objectModelPath = [[NSBundle mainBundle] pathForResource:filename ofType:@"mom"];
179        NSURL           *objectModelURL = [NSURL fileURLWithPath:objectModelPath];
180       
181        return [[[NSManagedObjectModel alloc] initWithContentsOfURL:objectModelURL] autorelease];
182}
183
184
185+ (void)p_migrateOfflineMessagesFromManagedObjectContext:(NSManagedObjectContext *)sourceContext toContext:(NSManagedObjectContext *)targetContext
186{
187        NSError *error;
188       
189        NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
190        [request setEntity:[NSEntityDescription entityForName:@"LPOfflineMessage" inManagedObjectContext:sourceContext]];
191       
192        NSArray *oldObjs = [sourceContext executeFetchRequest:request error:&error];
193       
194        NSEnumerator *objEnum = [oldObjs objectEnumerator];
195        id oldObj;
196        while (oldObj = [objEnum nextObject]) {
197                id newObj = [NSEntityDescription insertNewObjectForEntityForName:@"LPOfflineMessage" inManagedObjectContext:targetContext];
198                [newObj setValuesForKeysWithDictionary:
199                        [oldObj dictionaryWithValuesForKeys:
200                                [NSArray arrayWithObjects:
201                                        @"contactName", @"jid", @"nickname", @"plainTextBody", @"subject", @"timestamp", @"unread", @"xhtmlBody", nil]]];
202        }
203       
204        [targetContext save:&error];
205}
206
207
208+ (void)p_migrateSapoNotificationsFromManagedObjectContext:(NSManagedObjectContext *)sourceContext toContext:(NSManagedObjectContext *)targetContext
209{
210        NSError *error;
211       
212        NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
213        [request setEntity:[NSEntityDescription entityForName:@"LPSapoNotificationChannel" inManagedObjectContext:sourceContext]];
214       
215        NSArray *oldChannels = [sourceContext executeFetchRequest:request error:&error];
216       
217        NSEnumerator *channelEnum = [oldChannels objectEnumerator];
218        id oldChannel;
219        while (oldChannel = [channelEnum nextObject]) {
220                id newChannel = [NSEntityDescription insertNewObjectForEntityForName:@"LPSapoNotificationChannel" inManagedObjectContext:targetContext];
221                int unreadCount = 0;
222               
223                // Migrate this channel's notifications
224                NSEnumerator *notifEnum = [[oldChannel valueForKey:@"notifications"] objectEnumerator];
225                id oldNotif;
226                while (oldNotif = [notifEnum nextObject]) {
227                        id newNotif = [NSEntityDescription insertNewObjectForEntityForName:@"LPSapoNotification" inManagedObjectContext:targetContext];
228                        [newNotif setValuesForKeysWithDictionary:
229                                [oldNotif dictionaryWithValuesForKeys:
230                                        [NSArray arrayWithObjects:
231                                                @"body", @"date", @"flashURL", @"iconURL", @"itemURL", @"subject", @"unread", nil]]];
232                        [newNotif setValue:newChannel forKey:@"channel"];
233                       
234                        if ([[newNotif valueForKey:@"unread"] boolValue])
235                                ++unreadCount;
236                }
237               
238                [newChannel setValue:[oldChannel valueForKey:@"name"] forKey:@"name"];
239                [newChannel setValue:[NSNumber numberWithInt:unreadCount] forKey:@"unreadCount"];
240        }
241       
242        [targetContext save:&error];
243}
244
245
246+ (BOOL)p_shouldMigrateFromXMLFilePath:(NSString *)xmlFilePath toSQLiteFilePath:(NSString *)sqliteFilePath
247{
248        NSFileManager *fm = [NSFileManager defaultManager];
249        BOOL migrateXMLFile = NO;
250       
251        if ([fm fileExistsAtPath:xmlFilePath]) {
252                if ([fm fileExistsAtPath:sqliteFilePath]) {
253                        NSDate *xmlModifDate = [[fm fileAttributesAtPath:xmlFilePath traverseLink:YES] objectForKey:NSFileModificationDate];
254                        NSDate *sqliteModifDate = [[fm fileAttributesAtPath:sqliteFilePath traverseLink:YES] objectForKey:NSFileModificationDate];
255                       
256                        // Migrate only if the XML file is more recent than the SQLite database
257                        migrateXMLFile = ([xmlModifDate compare:sqliteModifDate] == NSOrderedDescending);
258                } else {
259                        migrateXMLFile = YES;
260                }
261        }
262        return migrateXMLFile;
263}
264
265
266+ (NSString *)p_migratePersistentStoreWithURL:(NSURL *)storeURL storeType:(NSString *)storeType fromVersion:(int)storeVersionNr
267{
268        NSString        *bundleID = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"];
269        NSString        *tempDir = [NSTemporaryDirectory() stringByAppendingPathComponent:bundleID];
270       
271        [[NSFileManager defaultManager] createDirectoryAtPath:tempDir attributes:nil];
272       
273        NSString        *tempFilePath = [tempDir stringByAppendingPathComponent:@"MessageCenterStore_migrated.sqlite"];
274        NSURL           *tempURL = [NSURL fileURLWithPath:tempFilePath];
275       
276        // Remove any existing file with this pathname that may have been left hanging around
277        NSFileManager *fm = [NSFileManager defaultManager];
278        [fm removeFileAtPath:tempFilePath handler:nil];
279       
280        NSError *error;
281       
282        // Setup the persistence stacks
283        NSManagedObjectModel                    *originalMOM = [self p_managedObjectModelWithVersionNr:storeVersionNr];
284        NSPersistentStoreCoordinator    *originalPSC = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:originalMOM];
285        NSManagedObjectContext                  *originalMOC = [[NSManagedObjectContext alloc] init];
286       
287        [originalPSC addPersistentStoreWithType:storeType configuration:nil URL:storeURL options:nil error:&error];
288        [originalMOC setPersistentStoreCoordinator:originalPSC];
289       
290        NSManagedObjectModel                    *migratedMOM = [self p_managedObjectModelWithVersionNr:CURRENT_VERSION_NR];
291        NSPersistentStoreCoordinator    *migratedPSC = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:migratedMOM];
292        NSManagedObjectContext                  *migratedMOC = [[NSManagedObjectContext alloc] init];
293       
294        id store = [migratedPSC addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:tempURL options:nil error:&error];
295        [migratedMOC setPersistentStoreCoordinator:migratedPSC];
296       
297        // Copy the objects over to the new stack
298        [self p_migrateOfflineMessagesFromManagedObjectContext:originalMOC toContext:migratedMOC];
299        [self p_migrateSapoNotificationsFromManagedObjectContext:originalMOC toContext:migratedMOC];
300       
301        // Set the version number for the new store in its metadata
302        NSNumber *newStoreVersion = [NSNumber numberWithInt:CURRENT_VERSION_NR];
303        NSDictionary *newMetadata = [NSDictionary dictionaryWithObject:newStoreVersion forKey:@"LPModelVersion"];
304       
305        [migratedPSC setMetadata:newMetadata forPersistentStore:store];
306        [migratedMOC save:&error];
307       
308        [migratedMOC release];
309        [migratedPSC release];
310        [originalMOC release];
311        [originalPSC release];
312       
313        return tempFilePath;
314}
315
316
317- (NSPersistentStoreCoordinator *)p_persistentStoreCoordinator
318{
319    if (m_persistentStoreCoordinator == nil) {
320                [LPMessageCenter migrateMessageCenterStoreIfNeeded];
321               
322                // Add the SQLite store file to the stack
323                m_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:
324                        [LPMessageCenter p_managedObjectModelWithVersionNr:CURRENT_VERSION_NR]];
325               
326                NSString        *applicationSupportFolder = LPOurApplicationSupportFolderPath();
327                NSString        *sqliteFilePath = [applicationSupportFolder stringByAppendingPathComponent:@"MessageCenterStore.sqlite"];
328                NSURL           *sqliteURL = [NSURL fileURLWithPath:sqliteFilePath];
329                NSError         *error;
330               
331                id store = [m_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
332                                                                                                                          configuration:nil URL:sqliteURL
333                                                                                                                                        options:nil error:&error];
334                if (store) {
335                        // Make sure the store has the version number set correctly
336                        NSNumber *newStoreVersion = [NSNumber numberWithInt:CURRENT_VERSION_NR];
337                        NSDictionary *newMetadata = [NSDictionary dictionaryWithObject:newStoreVersion forKey:@"LPModelVersion"];
338                        [m_persistentStoreCoordinator setMetadata:newMetadata forPersistentStore:store];
339                } else {
340                        [[NSApplication sharedApplication] presentError:error];
341                }
342        }
343       
344        return m_persistentStoreCoordinator;
345}
346
347
348#pragma mark -
349
350
351+ (BOOL)needsToMigrateMessageCenterStore
352{
353        NSString        *applicationSupportFolder = LPOurApplicationSupportFolderPath();
354        NSString        *xmlFilePath = [applicationSupportFolder stringByAppendingPathComponent:@"MessageCenterStore.xml"];
355        NSString        *sqliteFilePath = [applicationSupportFolder stringByAppendingPathComponent:@"MessageCenterStore.sqlite"];
356        NSURL           *sqliteURL = [NSURL fileURLWithPath:sqliteFilePath];
357       
358        BOOL            needsToMigrate = NO;
359        NSError         *error;
360       
361        if ([self p_shouldMigrateFromXMLFilePath:xmlFilePath toSQLiteFilePath:sqliteFilePath]) {
362                needsToMigrate = YES;
363        }
364        else {
365                NSDictionary *metadata = [NSPersistentStoreCoordinator metadataForPersistentStoreWithURL:sqliteURL error:&error];
366               
367                if (metadata != nil) {
368                        NSNumber *storeVersion = [metadata objectForKey:@"LPModelVersion"];
369                        int storeVersionNr = (storeVersion ? [storeVersion intValue] : 1);
370                       
371                        needsToMigrate = (storeVersionNr < CURRENT_VERSION_NR);
372                }
373        }
374       
375        return needsToMigrate;
376}
377
378
379+ (void)migrateMessageCenterStoreIfNeeded
380{
381        NSString        *applicationSupportFolder = LPOurApplicationSupportFolderPath();
382        NSString        *xmlFilePath = [applicationSupportFolder stringByAppendingPathComponent:@"MessageCenterStore.xml"];
383        NSString        *sqliteFilePath = [applicationSupportFolder stringByAppendingPathComponent:@"MessageCenterStore.sqlite"];
384        NSURL           *sqliteURL = [NSURL fileURLWithPath:sqliteFilePath];
385       
386        NSString        *originalStoreType = nil;
387        NSURL           *originalStoreURL = nil;
388        NSError         *error;
389       
390        if ([self p_shouldMigrateFromXMLFilePath:xmlFilePath toSQLiteFilePath:sqliteFilePath]) {
391                originalStoreType = NSXMLStoreType;
392                originalStoreURL = [NSURL fileURLWithPath:xmlFilePath];
393        }
394        else {
395                originalStoreType = NSSQLiteStoreType;
396                originalStoreURL = sqliteURL;
397        }
398       
399        NSDictionary *metadata = [NSPersistentStoreCoordinator metadataForPersistentStoreWithURL:originalStoreURL error:&error];
400       
401        if (metadata != nil) {
402                NSNumber *storeVersion = [metadata objectForKey:@"LPModelVersion"];
403                int storeVersionNr = (storeVersion ? [storeVersion intValue] : 1);
404               
405                if (storeVersionNr < CURRENT_VERSION_NR || originalStoreType == NSXMLStoreType) {
406                        NSString *migratedFilePath = [self p_migratePersistentStoreWithURL:originalStoreURL
407                                                                                                                                         storeType:originalStoreType
408                                                                                                                                   fromVersion:storeVersionNr];
409                       
410                        // Put the migrated file in the right place
411                        NSFileManager *fm = [NSFileManager defaultManager];
412                        [fm removeFileAtPath:sqliteFilePath handler:nil];
413                        [fm movePath:migratedFilePath toPath:sqliteFilePath handler:nil];
414                }
415        }
416}
417
418
419- (NSManagedObjectContext *)managedObjectContext
420{
421    if (m_managedObjectContext == nil) {
422                NSPersistentStoreCoordinator *coordinator = [self p_persistentStoreCoordinator];
423                if (coordinator != nil) {
424                        m_managedObjectContext = [[NSManagedObjectContext alloc] init];
425                        [m_managedObjectContext setPersistentStoreCoordinator: coordinator];
426                }
427               
428                [[NSNotificationCenter defaultCenter] addObserver:self
429                                                                                                 selector:@selector(p_managedObjectContextObjectsDidChange:)
430                                                                                                         name:NSManagedObjectContextObjectsDidChangeNotification
431                                                                                                   object:m_managedObjectContext];
432        }
433       
434        return m_managedObjectContext;
435}
436
437
438#pragma mark -
439#pragma mark Sapo Notifications
440
441
442- (NSArray *)sapoNotificationsChannels
443{
444        if (m_sapoNotifChannels == nil) {
445                // Fetch the existing channels
446                NSManagedObjectContext  *context = [self managedObjectContext];
447                NSEntityDescription             *channelEntity = [NSEntityDescription entityForName:@"LPSapoNotificationChannel" inManagedObjectContext:context];
448               
449                NSFetchRequest  *fetchRequest = [[NSFetchRequest alloc] init];
450                NSError                 *error;
451               
452                // No predicate, fetch them all.
453                [fetchRequest setEntity:channelEntity];
454               
455                NSArray *result = [context executeFetchRequest:fetchRequest error:&error];
456                [fetchRequest release];
457               
458                m_sapoNotifChannels = [result mutableCopy];
459        }
460        return m_sapoNotifChannels;
461}
462
463
464- (void)addReceivedSapoNotificationFromChannel:(NSString *)channelName subject:(NSString *)subject body:(NSString *)body itemURL:(NSString *)itemURL flashURL:(NSString *)flashURL iconURL:(NSString *)iconURL
465{
466        NSManagedObjectContext  *context = [self managedObjectContext];
467        LPSapoNotification              *newSapoNotif = [NSEntityDescription insertNewObjectForEntityForName:@"LPSapoNotification"
468                                                                                                                                                  inManagedObjectContext:context];
469       
470        [newSapoNotif setValue:[NSDate date] forKey:@"date"];
471        [newSapoNotif setValue:subject forKey:@"subject"];
472        [newSapoNotif setValue:body forKey:@"body"];
473        [newSapoNotif setValue:itemURL forKey:@"itemURL"];
474        [newSapoNotif setValue:flashURL forKey:@"flashURL"];
475        [newSapoNotif setValue:iconURL forKey:@"iconURL"];
476       
477        // See if there's already a channel object
478        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name == %@", channelName];
479        NSArray         *result = [[self sapoNotificationsChannels] filteredArrayUsingPredicate:predicate];
480       
481        LPSapoNotificationChannel *channel;
482       
483        if ([result count] > 0) {
484                channel = [result objectAtIndex:0];
485        } else {
486                channel = [NSEntityDescription insertNewObjectForEntityForName:@"LPSapoNotificationChannel"
487                                                                                                inManagedObjectContext:context];
488                [channel setValue:channelName forKey:@"name"];
489                [m_sapoNotifChannels addObject:channel];
490        }
491       
492        [newSapoNotif setValue:channel forKey:@"channel"];
493        [channel addToUnreadCount:1];
494       
495        NSError *error;
496        [context save:&error];
497       
498       
499        // Notify the user
500        [[LPEventNotificationsHandler defaultHandler] notifyReceptionOfHeadlineMessage:newSapoNotif];
501}
502
503
504#pragma mark -
505#pragma mark Offline Messages
506
507
508- (void)p_updateUnreadOfflineMessagesCountFromManagedObjectsContextEmittingKVONotification:(BOOL)emitNotification
509{
510        NSManagedObjectContext  *context = [self managedObjectContext];
511        NSEntityDescription             *msgEntity = [NSEntityDescription entityForName:@"LPOfflineMessage" inManagedObjectContext:context];
512       
513        NSFetchRequest  *fetchRequest = [[NSFetchRequest alloc] init];
514        NSError                 *error;
515       
516        // No predicate, fetch them all.
517        [fetchRequest setEntity:msgEntity];
518        [fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"unread == YES"]];
519       
520        NSArray *result = [context executeFetchRequest:fetchRequest error:&error];
521        [fetchRequest release];
522       
523       
524        [self p_setUnreadOfflineMessagesCount:[result count] emitKVONotification:emitNotification];
525}
526
527
528- (int)unreadOfflineMessagesCount
529{
530        // Is the unread messages count initialized yet?
531        if (m_unreadOfflineMessagesCount < 0)
532                [self p_updateUnreadOfflineMessagesCountFromManagedObjectsContextEmittingKVONotification:NO];
533       
534        return m_unreadOfflineMessagesCount;
535}
536
537- (void)p_setUnreadOfflineMessagesCount:(int)count emitKVONotification:(BOOL)emitNotification
538{
539        if (count != m_unreadOfflineMessagesCount) {
540                if (emitNotification)
541                        [self willChangeValueForKey:@"unreadOfflineMessagesCount"];
542               
543                m_unreadOfflineMessagesCount = count;
544               
545                if (emitNotification)
546                        [self didChangeValueForKey:@"unreadOfflineMessagesCount"];
547        }
548}
549
550
551- (void)addReceivedOfflineMessageFromJID:(NSString *)fromJID account:(LPAccount *)account nick:(NSString *)nick timestamp:(NSString *)timestamp subject:(NSString *)subject plainTextVariant:(NSString *)plainTextVariant XHTMLVariant:(NSString *)xhtmlVariant URLs:(NSArray *)urls
552{
553        NSManagedObjectContext  *context = [self managedObjectContext];
554        NSManagedObject                 *newOfflineMessage = [NSEntityDescription insertNewObjectForEntityForName:@"LPOfflineMessage"
555                                                                                                                                                           inManagedObjectContext:context];
556       
557        NSString *urlsStr = [[urls valueForKey:@"absoluteString"] componentsJoinedByString:@" "];
558        NSString *bodyWithURLs = ( [urlsStr length] > 0 ?
559                                                           [plainTextVariant stringByAppendingFormat:@" | URLs: %@", urlsStr] :
560                                                           plainTextVariant );
561       
562        LPContactEntry *entry = [[account roster] contactEntryForAddress:fromJID account:account];
563        LPContact *contact = [entry contact];
564       
565        NSCalendarDate *timestampDate = [NSDate dateWithNaturalLanguageString:timestamp];
566       
567        [newOfflineMessage setValue:[contact name] forKey:@"contactName"];
568        [newOfflineMessage setValue:fromJID forKey:@"jid"];
569        [newOfflineMessage setValue:nick forKey:@"nickname"];
570        [newOfflineMessage setValue:timestampDate forKey:@"timestamp"];
571        [newOfflineMessage setValue:subject forKey:@"subject"];
572        [newOfflineMessage setValue:bodyWithURLs forKey:@"plainTextBody"];
573        [newOfflineMessage setValue:xhtmlVariant forKey:@"xhtmlBody"];
574       
575        NSError *error;
576        [context save:&error];
577       
578       
579        // Notify the user
580        [[LPEventNotificationsHandler defaultHandler] notifyReceptionOfOfflineMessage:newOfflineMessage];
581}
582
583
584#pragma mark -
585#pragma mark NSManagedObjectContext Notifications
586
587- (void)p_managedObjectContextObjectsDidChange:(NSNotification *)notif
588{
589        [self p_updateUnreadOfflineMessagesCountFromManagedObjectsContextEmittingKVONotification:YES];
590}
591
592
593@end
Note: See TracBrowser for help on using the browser.