adium 2420:896e41f9c172: Throttle Growl messages. Fixes #12133.
commits at adium.im
commits at adium.im
Sun May 31 16:17:16 UTC 2009
details: http://hg.adium.im/adium/rev/896e41f9c172
revision: 2420:896e41f9c172
author: Zachary West <zacw at adium.im>
date: Sun May 31 12:17:07 2009 -0400
Throttle Growl messages. Fixes #12133.
We throttle messages every 0.5 seconds; every incoming message pushes the "clear" point back, preventing a huge rush of notifications at any one point in time.
Adds a "description for combined event" to all AIEventHandlers. Mostly they ignore the listObject and chat options for their descriptions, since the title is going to be the chat or listObject where appropriate in the Growl notification; other things might not necessarily have this requirement, so the option's there.
diffs (730 lines):
diff -r 5bd931f5aa4e -r 896e41f9c172 Frameworks/Adium Framework/Source/AIContactAlertsControllerProtocol.h
--- a/Frameworks/Adium Framework/Source/AIContactAlertsControllerProtocol.h Sun May 31 02:14:06 2009 -0400
+++ b/Frameworks/Adium Framework/Source/AIContactAlertsControllerProtocol.h Sun May 31 12:17:07 2009 -0400
@@ -8,7 +8,7 @@
#import <Adium/AIControllerProtocol.h>
- at class AIListObject, AIModularPane;
+ at class AIListObject, AIChat, AIModularPane;
@protocol AIEventHandler, AIActionHandler;
@@ -139,6 +139,22 @@
*/
- (NSImage *)imageForEventID:(NSString *)eventID;
+/*!
+ * @brief The description for multiple combined events.
+ *
+ * @param eventID The event
+ * @param listObject The object for which the event references
+ * @param chat The chat for which the event references
+ * @param count The count of combined events
+ *
+ * @return The description of the event
+ *
+ */
+- (NSString *)descriptionForCombinedEventID:(NSString *)eventID
+ forListObject:(AIListObject *)listObject
+ forChat:(AIChat *)chat
+ withCount:(NSUInteger)count;
+
#pragma mark Event types
/*!
* @brief Is the passed event a message event?
@@ -310,6 +326,23 @@
* @brief Return an image icon for the specified eventID.
*/
- (NSImage *)imageForEventID:(NSString *)eventID;
+
+/*!
+ * @brief The description for multiple combined events.
+ *
+ * @param eventID The event
+ * @param listObject The object for which the event references
+ * @param chat The chat for which the event references
+ * @param count The count of combined events
+ *
+ * @return The description of the event
+ *
+ */
+- (NSString *)descriptionForCombinedEventID:(NSString *)eventID
+ forListObject:(AIListObject *)listObject
+ forChat:(AIChat *)chat
+ withCount:(NSUInteger)count;
+
@end
/*!
diff -r 5bd931f5aa4e -r 896e41f9c172 Frameworks/Adium Framework/Source/AdiumAuthorization.m
--- a/Frameworks/Adium Framework/Source/AdiumAuthorization.m Sun May 31 02:14:06 2009 -0400
+++ b/Frameworks/Adium Framework/Source/AdiumAuthorization.m Sun May 31 12:17:07 2009 -0400
@@ -174,4 +174,12 @@
return eventImage;
}
+- (NSString *)descriptionForCombinedEventID:(NSString *)eventID
+ forListObject:(AIListObject *)listObject
+ forChat:(AIChat *)chat
+ withCount:(NSUInteger)count
+{
+ return [NSString stringWithFormat:AILocalizedString(@"%u authorization requests", nil), count];
+}
+
@end
diff -r 5bd931f5aa4e -r 896e41f9c172 Plugins/Error Message Handler/ErrorMessageHandlerPlugin.m
--- a/Plugins/Error Message Handler/ErrorMessageHandlerPlugin.m Sun May 31 02:14:06 2009 -0400
+++ b/Plugins/Error Message Handler/ErrorMessageHandlerPlugin.m Sun May 31 12:17:07 2009 -0400
@@ -205,4 +205,12 @@
return eventImage;
}
+- (NSString *)descriptionForCombinedEventID:(NSString *)eventID
+ forListObject:(AIListObject *)listObject
+ forChat:(AIChat *)chat
+ withCount:(NSUInteger)count
+{
+ return [NSString stringWithFormat:AILocalizedString(@"%u events", nil), count];
+}
+
@end
diff -r 5bd931f5aa4e -r 896e41f9c172 Plugins/Nudge and Buzz Handler/AINudgeBuzzHandlerPlugin.m
--- a/Plugins/Nudge and Buzz Handler/AINudgeBuzzHandlerPlugin.m Sun May 31 02:14:06 2009 -0400
+++ b/Plugins/Nudge and Buzz Handler/AINudgeBuzzHandlerPlugin.m Sun May 31 12:17:07 2009 -0400
@@ -371,4 +371,12 @@
return eventImage;
}
+- (NSString *)descriptionForCombinedEventID:(NSString *)eventID
+ forListObject:(AIListObject *)listObject
+ forChat:(AIChat *)chat
+ withCount:(NSUInteger)count
+{
+ return [NSString stringWithFormat:AILocalizedString(@"%u attention requests", nil), count];
+}
+
@end
diff -r 5bd931f5aa4e -r 896e41f9c172 Source/AIContactStatusEventsPlugin.m
--- a/Source/AIContactStatusEventsPlugin.m Sun May 31 02:14:06 2009 -0400
+++ b/Source/AIContactStatusEventsPlugin.m Sun May 31 12:17:07 2009 -0400
@@ -309,6 +309,38 @@
return eventImage;
}
+- (NSString *)descriptionForCombinedEventID:(NSString *)eventID
+ forListObject:(AIListObject *)listObject
+ forChat:(AIChat *)chat
+ withCount:(NSUInteger)count
+{
+ NSString *format = nil;
+
+ if ([eventID isEqualToString:CONTACT_STATUS_ONLINE_YES]) {
+ format = AILocalizedString(@"%u contacts connected", nil);
+ } else if ([eventID isEqualToString:CONTACT_STATUS_ONLINE_NO]) {
+ format = AILocalizedString(@"%u contacts disconnected", nil);
+ } else if ([eventID isEqualToString:CONTACT_STATUS_AWAY_YES]) {
+ format = AILocalizedString(@"%u contacts went away", nil);
+ } else if ([eventID isEqualToString:CONTACT_STATUS_AWAY_NO]) {
+ format = AILocalizedString(@"%u contacts came back", nil);
+ } else if ([eventID isEqualToString:CONTACT_STATUS_IDLE_YES]) {
+ format = AILocalizedString(@"%u contacts went idle", nil);
+ } else if ([eventID isEqualToString:CONTACT_STATUS_IDLE_NO]) {
+ format = AILocalizedString(@"%u contacts became active", nil);
+ } else if ([eventID isEqualToString:CONTACT_SEEN_ONLINE_YES]) {
+ format = AILocalizedString(@"%u contacts are seen", nil);
+ } else if ([eventID isEqualToString:CONTACT_SEEN_ONLINE_NO]) {
+ format = AILocalizedString(@"%u contacts are no longer seen", nil);
+ } else if([eventID isEqualToString:CONTACT_STATUS_MOBILE_YES]) {
+ format = AILocalizedString(@"%u contacts went mobile", nil);
+ } else if([eventID isEqualToString:CONTACT_STATUS_MOBILE_NO]) {
+ format = AILocalizedString(@"%u contacts returned from mobile", nil);
+ }
+
+ return format ? [NSString stringWithFormat:format, count] : @"";
+}
+
#pragma mark Caching and event generation
/*!
* @brief Cache list object updates
diff -r 5bd931f5aa4e -r 896e41f9c172 Source/AIPreferenceContainer.m
--- a/Source/AIPreferenceContainer.m Sun May 31 02:14:06 2009 -0400
+++ b/Source/AIPreferenceContainer.m Sun May 31 12:17:07 2009 -0400
@@ -390,6 +390,8 @@
*/
- (void)save
{
+ return;
+
if (object) {
//For an object's pref changes, batch all changes in a SAVE_OBJECT_PREFS_DELAY second period. We'll force an immediate save if Adium quits.
if (*myTimerForSavingGlobalPrefs) {
diff -r 5bd931f5aa4e -r 896e41f9c172 Source/AdiumChatEvents.m
--- a/Source/AdiumChatEvents.m Sun May 31 02:14:06 2009 -0400
+++ b/Source/AdiumChatEvents.m Sun May 31 12:17:07 2009 -0400
@@ -227,4 +227,22 @@
return eventImage;
}
+- (NSString *)descriptionForCombinedEventID:(NSString *)eventID
+ forListObject:(AIListObject *)listObject
+ forChat:(AIChat *)chat
+ withCount:(NSUInteger)count
+{
+ NSString *format = nil;
+
+ if ([eventID isEqualToString:CONTENT_CONTACT_JOINED_CHAT]) {
+ format = AILocalizedString(@"%u contacts joined", nil);
+ } else if ([eventID isEqualToString:CONTENT_CONTACT_LEFT_CHAT]) {
+ format = AILocalizedString(@"%u contacts left", nil);
+ } else if ([eventID isEqualToString:CONTENT_GROUP_CHAT_INVITE]) {
+ format = AILocalizedString(@"%u invites to a group chat", nil);
+ }
+
+ return format ? [NSString stringWithFormat:format, count] : @"";
+}
+
@end
diff -r 5bd931f5aa4e -r 896e41f9c172 Source/AdiumMessageEvents.m
--- a/Source/AdiumMessageEvents.m Sun May 31 02:14:06 2009 -0400
+++ b/Source/AdiumMessageEvents.m Sun May 31 12:17:07 2009 -0400
@@ -404,4 +404,26 @@
return eventImage;
}
+- (NSString *)descriptionForCombinedEventID:(NSString *)eventID
+ forListObject:(AIListObject *)listObject
+ forChat:(AIChat *)chat
+ withCount:(NSUInteger)count
+{
+ NSString *format = nil;
+
+ if ([eventID isEqualToString:CONTENT_MESSAGE_SENT]) {
+ format = AILocalizedString(@"%u messages sent",nil);
+ } else if ([eventID isEqualToString:CONTENT_MESSAGE_RECEIVED] ||
+ [eventID isEqualToString:CONTENT_MESSAGE_RECEIVED_FIRST] ||
+ [eventID isEqualToString:CONTENT_MESSAGE_RECEIVED_BACKGROUND] ||
+ [eventID isEqualToString:CONTENT_MESSAGE_RECEIVED_GROUP] ||
+ [eventID isEqualToString:CONTENT_MESSAGE_RECEIVED_BACKGROUND_GROUP]) {
+ format = AILocalizedString(@"%u messages received", nil);
+ } else if ([eventID isEqualToString:CONTENT_GROUP_CHAT_MENTION]) {
+ format = AILocalizedString(@"%u mentions received", nil);
+ }
+
+ return format ? [NSString stringWithFormat:format, count] : @"";
+}
+
@end
diff -r 5bd931f5aa4e -r 896e41f9c172 Source/ESAccountEvents.m
--- a/Source/ESAccountEvents.m Sun May 31 02:14:06 2009 -0400
+++ b/Source/ESAccountEvents.m Sun May 31 12:17:07 2009 -0400
@@ -176,6 +176,24 @@
return eventImage;
}
+- (NSString *)descriptionForCombinedEventID:(NSString *)eventID
+ forListObject:(AIListObject *)listObject
+ forChat:(AIChat *)chat
+ withCount:(NSUInteger)count
+{
+ NSString *format;
+
+ if ([eventID isEqualToString:ACCOUNT_CONNECTED]) {
+ format = AILocalizedString(@"%u accounts connected",nil);
+ } else if ([eventID isEqualToString:ACCOUNT_DISCONNECTED]) {
+ format = AILocalizedString(@"%u accounts disconnected",nil);
+ } else if ([eventID isEqualToString:ACCOUNT_RECEIVED_EMAIL]) {
+ format = AILocalizedString(@"%u accounts received new email",nil);
+ }
+
+ return format ? [NSString stringWithFormat:format, count] : @"";
+}
+
#pragma mark Aggregation and event generation
/*!
* @brief Update list object
diff -r 5bd931f5aa4e -r 896e41f9c172 Source/ESContactAlertsController.m
--- a/Source/ESContactAlertsController.m Sun May 31 02:14:06 2009 -0400
+++ b/Source/ESContactAlertsController.m Sun May 31 12:17:07 2009 -0400
@@ -479,6 +479,25 @@
return @"";
}
+- (NSString *)descriptionForCombinedEventID:(NSString *)eventID
+ forListObject:(AIListObject *)listObject
+ forChat:(AIChat *)chat
+ withCount:(NSUInteger)count
+{
+ id <AIEventHandler> eventHandler;
+
+ eventHandler = [eventHandlers objectForKey:eventID];
+ if (!eventHandler) eventHandler = [globalOnlyEventHandlers objectForKey:eventID];
+
+ if (eventHandler) {
+ return [eventHandler descriptionForCombinedEventID:eventID
+ forListObject:listObject
+ forChat:chat
+ withCount:count];
+ }
+
+ return @"";
+}
//Actions --------------------------------------------------------------------------------------------------------------
#pragma mark Actions
diff -r 5bd931f5aa4e -r 896e41f9c172 Source/ESFileTransferController.m
--- a/Source/ESFileTransferController.m Sun May 31 02:14:06 2009 -0400
+++ b/Source/ESFileTransferController.m Sun May 31 12:17:07 2009 -0400
@@ -832,6 +832,32 @@
return eventImage;
}
+- (NSString *)descriptionForCombinedEventID:(NSString *)eventID
+ forListObject:(AIListObject *)listObject
+ forChat:(AIChat *)chat
+ withCount:(NSUInteger)count
+{
+ NSString *format = nil;
+
+ if ([eventID isEqualToString:FILE_TRANSFER_REQUEST]) {
+ format = AILocalizedString(@"%u incoming file transfers",nil);
+ } else if ([eventID isEqualToString:FILE_TRANSFER_CHECKSUMMING]) {
+ format = AILocalizedString(@"%u files being checksummed prior to sending",nil);
+ } else if ([eventID isEqualToString:FILE_TRANSFER_WAITING_REMOTE]) {
+ format = AILocalizedString(@"%u files offered to send",nil);
+ } else if ([eventID isEqualToString:FILE_TRANSFER_BEGAN]) {
+ format = AILocalizedString(@"%u files began transferring",nil);
+ } else if ([eventID isEqualToString:FILE_TRANSFER_CANCELLED]) {
+ format = AILocalizedString(@"%u files cancelled remotely",nil);
+ } else if ([eventID isEqualToString:FILE_TRANSFER_COMPLETE]) {
+ format = AILocalizedString(@"%u files completed successfully",nil);
+ } else if ([eventID isEqualToString:FILE_TRANSFER_FAILED]) {
+ format = AILocalizedString(@"%u file transfers failed",nil);
+ }
+
+ return format ? [NSString stringWithFormat:format, count] : @"";
+}
+
#pragma mark Strings for sizes
#define ZERO_BYTES AILocalizedString(@"Zero bytes", "no file size")
diff -r 5bd931f5aa4e -r 896e41f9c172 Source/NEHGrowlPlugin.h
--- a/Source/NEHGrowlPlugin.h Sun May 31 02:14:06 2009 -0400
+++ b/Source/NEHGrowlPlugin.h Sun May 31 12:17:07 2009 -0400
@@ -17,12 +17,15 @@
#import <Adium/AIContactAlertsControllerProtocol.h>
#import <Growl-WithInstaller/GrowlApplicationBridge.h>
-#define KEY_GROWL_ALERT_STICKY @"Growl Sticky"
+#define KEY_GROWL_ALERT_STICKY @"Growl Sticky"
+#define GROWL_QUEUE_WAIT 0.5 // Seconds to wait before clearing an event type's queue
@protocol GrowlApplicationBridgeDelegate;
@interface NEHGrowlPlugin : AIPlugin <AIActionHandler, GrowlApplicationBridgeDelegate> {
BOOL showWhileAway;
+
+ NSMutableDictionary *queuedEvents;
}
@end
diff -r 5bd931f5aa4e -r 896e41f9c172 Source/NEHGrowlPlugin.m
--- a/Source/NEHGrowlPlugin.m Sun May 31 02:14:06 2009 -0400
+++ b/Source/NEHGrowlPlugin.m Sun May 31 12:17:07 2009 -0400
@@ -34,6 +34,7 @@
#import <AIUtilities/AIImageAdditions.h>
#import <AIUtilities/AIStringAdditions.h>
#import <AIUtilities/AIMutableStringAdditions.h>
+#import <AIUtilities/AIObjectAdditions.h>
#import <Growl-WithInstaller/Growl.h>
//#define GROWL_DEBUG 1
@@ -57,6 +58,19 @@
@interface NEHGrowlPlugin ()
- (NSAttributedString *)_growlInformationForUpdate:(BOOL)isUpdate;
+- (NSString *)eventQueueKeyForEventID:(NSString *)eventID
+ inChat:(AIChat *)chat;
+
+- (void)postSingleEventID:(NSString *)eventID
+ forListObject:(AIListObject *)listObject
+ withDetails:(NSDictionary *)details
+ userInfo:(id)userInfo;
+
+- (void)postMultipleEventID:(NSString *)eventID
+ sticky:(BOOL)sticky
+ forListObject:(AIListObject *)listObject
+ forChat:(AIChat *)chat
+ withCount:(NSUInteger)count;
@end
/*!
@@ -78,6 +92,15 @@
selector:@selector(adiumFinishedLaunching:)
name:AIApplicationDidFinishLoadingNotification
object:nil];
+
+ queuedEvents = [[NSMutableDictionary alloc] init];
+}
+
+- (void)dealloc
+{
+ [queuedEvents release]; queuedEvents = nil;
+
+ [super dealloc];
}
/*!
@@ -165,16 +188,148 @@
*/
- (BOOL)performActionID:(NSString *)actionID forListObject:(AIListObject *)listObject withDetails:(NSDictionary *)details triggeringEventID:(NSString *)eventID userInfo:(id)userInfo
{
+ // Don't show growl notifications if we're silencing growl.
+ if ([adium.statusController.activeStatusState silencesGrowl]) {
+ return NO;
+ }
+
+ // Get the chat if it's appropriate.
+ AIChat *chat = nil;
+
+ if ([userInfo respondsToSelector:@selector(objectForKey:)]) {
+ chat = [userInfo objectForKey:@"AIChat"];
+ AIContentObject *contentObject = [userInfo objectForKey:@"AIContentObject"];
+ if (contentObject.source) {
+ listObject = contentObject.source;
+ }
+ }
+
+ // Add this event to the queue.
+ NSString *queueKey = [self eventQueueKeyForEventID:eventID inChat:chat];
+
+ NSMutableArray *events = [queuedEvents objectForKey:queueKey];
+
+ if (!events)
+ events = [NSMutableArray array];
+
+ [events addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:
+ listObject, @"AIListObject",
+ details, @"Details",
+ userInfo, @"UserInfo", nil]];
+
+ [queuedEvents setValue:events forKey:queueKey];
+
+ // wtb cancelPreviousPerformRequestsWithTarget:selector:object:object:
+ NSDictionary *queueCall = [NSDictionary dictionaryWithObjectsAndKeys:eventID, @"EventID", chat, @"AIChat", nil];
+
+ // Trigger the queue to be cleared in GROWL_QUEUE_WAIT seconds.
+ [NSObject cancelPreviousPerformRequestsWithTarget:self
+ selector:@selector(clearQueue:)
+ object:[NSDictionary dictionaryWithObjectsAndKeys:eventID, @"EventID", chat, @"AIChat", nil]];
+
+ [self performSelector:@selector(clearQueue:)
+ withObject:queueCall
+ afterDelay:GROWL_QUEUE_WAIT];
+
+ return YES;
+}
+
+/*!
+ * @brief Returns our details pane, an instance of <tt>CBGrowlAlertDetailPane</tt>
+ */
+- (AIModularPane *)detailsPaneForActionID:(NSString *)actionID
+{
+ return [CBGrowlAlertDetailPane actionDetailsPane];
+}
+
+/*!
+ * @brief Allow multiple actions?
+ *
+ * This action should not be performed multiple times for the same triggering event.
+ */
+- (BOOL)allowMultipleActionsWithID:(NSString *)actionID
+{
+ return NO;
+}
+
+#pragma mark Event Queue
+- (NSString *)eventQueueKeyForEventID:(NSString *)eventID
+ inChat:(AIChat *)chat
+{
+ if (chat) {
+ return [NSString stringWithFormat:@"%@-%@", eventID, chat.internalObjectID];
+ } else {
+ return eventID;
+ }
+}
+
+- (void)clearQueue:(NSDictionary *)callDict
+{
+ // Grab our actual arguments.
+ NSString *eventID = [callDict objectForKey:@"EventID"];
+ AIChat *chat = [callDict objectForKey:@"AIChat"];
+
+ // Look for events.
+ NSString *queueKey = [self eventQueueKeyForEventID:eventID inChat:chat];
+ NSMutableArray *events = [queuedEvents objectForKey:queueKey];
+
+ // If for some reason we don't have any events, bail.
+ if (!events.count) {
+ AILogWithSignature(@"Called to clear queue with no events. EventID: %@ chat: %@", eventID, chat);
+ return;
+ }
+
+ if (events.count <= 2) {
+ // If we only have a few events, just post them individually.
+
+ for (NSDictionary *event in events) {
+ [self postSingleEventID:eventID
+ forListObject:[event objectForKey:@"AIListObject"]
+ withDetails:[event objectForKey:@"Details"]
+ userInfo:[event objectForKey:@"UserInfo"]];
+ }
+
+ } else {
+ // We have multiple events; let's combine them.
+ AIListObject *overallListObject = nil;
+
+ // If all events are from the same listObject, let's use that one in the message.
+ for (AIListObject *listObject in [events valueForKeyPath:@"@unionOfObjects.AIListObject"]) {
+ if (!overallListObject) {
+ overallListObject = listObject;
+ } else if (overallListObject != listObject) {
+ overallListObject = nil;
+ break;
+ }
+ }
+
+ AILog(@"Posting multiple event - %@ %@ %@ %d", eventID, overallListObject, chat);
+
+ // Use any random event for sticky.
+ BOOL sticky = [[[[events objectAtIndex:0] objectForKey:@"Details"] objectForKey:KEY_GROWL_ALERT_STICKY] boolValue];
+
+ // Post the events combined. Use any random event to see if sticky.
+ [self postMultipleEventID:eventID
+ sticky:sticky
+ forListObject:overallListObject
+ forChat:chat
+ withCount:events.count];
+ }
+
+ // Clear our queue; we're done.
+ [queuedEvents setValue:nil forKey:queueKey];
+}
+
+- (void)postSingleEventID:(NSString *)eventID
+ forListObject:(AIListObject *)listObject
+ withDetails:(NSDictionary *)details
+ userInfo:(id)userInfo
+{
NSString *title, *description;
AIChat *chat = nil;
NSData *iconData = nil;
NSMutableDictionary *clickContext = [NSMutableDictionary dictionary];
NSString *identifier = nil;
-
- // Don't show growl notifications if we're silencing growl.
- if ([adium.statusController.activeStatusState silencesGrowl]) {
- return NO;
- }
//For a message event, listObject should become whoever sent the message
if ([adium.contactAlertsController isMessageEvent:eventID] &&
@@ -183,13 +338,13 @@
AIContentObject *contentObject = [userInfo objectForKey:@"AIContentObject"];
AIListObject *source = [contentObject source];
chat = [userInfo objectForKey:@"AIChat"];
-
+
if (source) listObject = source;
}
-
+
[clickContext setObject:eventID
forKey:@"eventID"];
-
+
if (listObject) {
if ([listObject isKindOfClass:[AIListContact class]]) {
//Use the parent
@@ -216,20 +371,20 @@
[eventID isEqualToString:FILE_TRANSFER_COMPLETE]) {
[clickContext setObject:[(ESFileTransfer *)userInfo uniqueID]
forKey:KEY_FILE_TRANSFER_ID];
-
+
} else {
[clickContext setObject:listObject.internalObjectID
forKey:KEY_LIST_OBJECT_ID];
}
}
-
+
} else {
if (chat) {
- title = chat.name;
-
+ title = chat.displayName;
+
[clickContext setObject:chat.uniqueChatID
forKey:KEY_CHAT_ID];
-
+
//If we have no listObject or we have a name, we are a group chat and
//should use the account's service icon
iconData = [[AIServiceIcons serviceIconForObject:chat.account
@@ -242,22 +397,22 @@
}
description = [adium.contactAlertsController naturalLanguageDescriptionForEventID:eventID
- listObject:listObject
- userInfo:userInfo
- includeSubject:NO];
-
+ listObject:listObject
+ userInfo:userInfo
+ includeSubject:NO];
+
if (([eventID isEqualToString:CONTACT_STATUS_ONLINE_YES] ||
- [eventID isEqualToString:CONTACT_STATUS_ONLINE_NO] ||
- [eventID isEqualToString:CONTACT_STATUS_AWAY_YES] ||
- [eventID isEqualToString:CONTACT_SEEN_ONLINE_YES] ||
- [eventID isEqualToString:CONTACT_SEEN_ONLINE_NO]) &&
+ [eventID isEqualToString:CONTACT_STATUS_ONLINE_NO] ||
+ [eventID isEqualToString:CONTACT_STATUS_AWAY_YES] ||
+ [eventID isEqualToString:CONTACT_SEEN_ONLINE_YES] ||
+ [eventID isEqualToString:CONTACT_SEEN_ONLINE_NO]) &&
[(AIListContact *)listObject contactListStatusMessage]) {
NSString *statusMessage = [[adium.contentController filterAttributedString:[(AIListContact *)listObject contactListStatusMessage]
- usingFilterType:AIFilterContactList
- direction:AIFilterIncoming
- context:listObject] string];
+ usingFilterType:AIFilterContactList
+ direction:AIFilterIncoming
+ context:listObject] string];
statusMessage = [[[statusMessage stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] mutableCopy] autorelease];
-
+
/* If the message contains line breaks, start it on a new line */
description = [NSString stringWithFormat:@"%@:%@%@",
description,
@@ -268,7 +423,7 @@
if (listObject && [adium.contactAlertsController isContactStatusEvent:eventID]) {
identifier = listObject.internalObjectID;
}
-
+
NSAssert5((title || description),
@"Growl notify error: EventID %@, listObject %@, userInfo %@\nGave Title \"%@\" description \"%@\"",
eventID,
@@ -288,26 +443,94 @@
isSticky:[[details objectForKey:KEY_GROWL_ALERT_STICKY] boolValue]
clickContext:clickContext
identifier:identifier];
-
- return YES;
}
-/*!
- * @brief Returns our details pane, an instance of <tt>CBGrowlAlertDetailPane</tt>
- */
-- (AIModularPane *)detailsPaneForActionID:(NSString *)actionID
+- (void)postMultipleEventID:(NSString *)eventID
+ sticky:(BOOL)sticky
+ forListObject:(AIListObject *)listObject
+ forChat:(AIChat *)chat
+ withCount:(NSUInteger)count
{
- return [CBGrowlAlertDetailPane actionDetailsPane];
-}
-
-/*!
- * @brief Allow multiple actions?
- *
- * This action should not be performed multiple times for the same triggering event.
- */
-- (BOOL)allowMultipleActionsWithID:(NSString *)actionID
-{
- return NO;
+ NSString *title, *description;
+ NSData *iconData = nil;
+ NSMutableDictionary *clickContext = [NSMutableDictionary dictionary];
+ NSString *identifier = nil;
+
+ [clickContext setObject:eventID
+ forKey:@"eventID"];
+
+ if (listObject) {
+ if ([listObject isKindOfClass:[AIListContact class]]) {
+ //Use the parent
+ listObject = [(AIListContact *)listObject parentContact];
+ title = [listObject longDisplayName];
+ } else {
+ title = listObject.displayName;
+ }
+
+ iconData = [listObject userIconData];
+
+ if (!iconData) {
+ iconData = [[AIServiceIcons serviceIconForObject:listObject
+ type:AIServiceIconLarge
+ direction:AIIconNormal] TIFFRepresentation];
+ }
+
+ if (chat) {
+ [clickContext setObject:chat.uniqueChatID
+ forKey:KEY_CHAT_ID];
+
+ } else {
+ [clickContext setObject:listObject.internalObjectID
+ forKey:KEY_LIST_OBJECT_ID];
+ }
+
+ } else {
+ if (chat) {
+ title = chat.displayName;
+
+ [clickContext setObject:chat.uniqueChatID
+ forKey:KEY_CHAT_ID];
+
+ //If we have no listObject or we have a name, we are a group chat and
+ //should use the account's service icon
+ iconData = [[AIServiceIcons serviceIconForObject:chat.account
+ type:AIServiceIconLarge
+ direction:AIIconNormal] TIFFRepresentation];
+
+ } else {
+ title = @"Adium";
+ }
+ }
+
+ description = [adium.contactAlertsController descriptionForCombinedEventID:eventID
+ forListObject:listObject
+ forChat:chat
+ withCount:count];
+
+ if (listObject && [adium.contactAlertsController isContactStatusEvent:eventID]) {
+ identifier = listObject.internalObjectID;
+ }
+
+ NSAssert5((title || description),
+ @"Growl notify error: EventID %@, listObject %@, chat %@\nGave Title \"%@\" description \"%@\"",
+ eventID,
+ listObject,
+ chat,
+ title,
+ description);
+
+ AILog(@"Posting combined Growl notification: Event ID: %@, listObject: %@, chat: %@, description: %@",
+ eventID, listObject, chat, description);
+
+ [GrowlApplicationBridge notifyWithTitle:title
+ description:description
+ notificationName:eventID
+ iconData:iconData
+ priority:0
+ isSticky:sticky
+ clickContext:clickContext
+ identifier:identifier];
}
#pragma mark Growl
More information about the commits
mailing list