* Adium is the legal property of its developers, whose names are listed in the copyright file included * with this source distribution. * This program is free software; you can redistribute it and/or modify it under the terms of the GNU * General Public License as published by the Free Software Foundation; either version 2 of the License, * or (at your option) any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * Public License for more details. * You should have received a copy of the GNU General Public License along with this program; if not, * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #import "AISoundController.h" #import <Adium/AIContactAlertsControllerProtocol.h> #import "ESGlobalEventsPreferences.h" #import "ESGlobalEventsPreferencesPlugin.h" #import <AIUtilities/AIDictionaryAdditions.h> #import <AIUtilities/AIStringAdditions.h> #import <AIUtilities/AIArrayAdditions.h> #import <Adium/AISoundSet.h> #define NEW_PRESET_NAME AILocalizedString(@"New Event Set",nil) #define KEY_STORED_EVENT_PRESETS @"Event Presets" #define KEY_EVENT_SET_NAME @"Name" #define KEY_ORDER_INDEX @"OrderIndex" #define KEY_NEXT_ORDER_INDEX @"NextOrderIndex" #define EVENT_SOUNDS_DEFAULT_PREFS @"EventSoundDefaults" @interface ESGlobalEventsPreferencesPlugin () - (void)_activateSet:(NSArray *)setArray withActionID:(NSString *)actionID alertGenerationSelector:(SEL)selector; - (void)adiumFinishedLaunching:(NSNotification *)notification; @implementation ESGlobalEventsPreferencesPlugin NSString *activeEventSet; builtInEventPresets = [[NSDictionary dictionaryNamed:@"BuiltInEventPresets" forClass:[self class]] retain]; storedEventPresets = [[adium.preferenceController preferenceForKey:KEY_STORED_EVENT_PRESETS group:PREF_GROUP_EVENT_PRESETS] mutableCopy]; if (!storedEventPresets) storedEventPresets = [[NSMutableDictionary alloc] init]; /* If there is no active event set, or the active event set is not present in our built in or stored event sets * then we are in one of two conditions: either this is a first-launch, or the user has deleted the event preferences. * Either way, we want to set ourselves to the default notification set before proceeding. activeEventSet = [adium.preferenceController preferenceForKey:KEY_ACTIVE_EVENT_SET group:PREF_GROUP_EVENT_PRESETS]; if (!activeEventSet || (![builtInEventPresets objectForKey:activeEventSet] && ![storedEventPresets objectForKey:activeEventSet])) { [self setEventPreset:[builtInEventPresets objectForKey:@"Default Notifications"]]; [adium.preferenceController registerDefaults:[NSDictionary dictionaryNamed:EVENT_SOUNDS_DEFAULT_PREFS forGroup:PREF_GROUP_SOUNDS]; //Install our preference view preferences = [(ESGlobalEventsPreferences *)[ESGlobalEventsPreferences preferencePaneForPlugin:self] retain]; //Wait for Adium to finish launching before we perform further actions [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(adiumFinishedLaunching:) name:AIApplicationDidFinishLoadingNotification //Uninstall our observers [[NSNotificationCenter defaultCenter] removeObserver:preferences]; [[NSNotificationCenter defaultCenter] removeObserver:preferences]; - (void)adiumFinishedLaunching:(NSNotification *)notification [[NSNotificationCenter defaultCenter] removeObserver:self name:AIApplicationDidFinishLoadingNotification //Called when the preferences change, reregister for the notifications - (void)preferencesChangedForGroup:(NSString *)group key:(NSString *)key object:(AIListObject *)object preferenceDict:(NSDictionary *)prefDict firstTime:(BOOL)firstTime + (NSDictionary *)soundAlertForKey:(NSString *)key inSoundsDict:(NSDictionary *)sounds NSDictionary *soundAlert = nil; (event = [adium.contactAlertsController eventIDForEnglishDisplayName:key])) { soundAlert = [NSDictionary dictionaryWithObjectsAndKeys:event, KEY_EVENT_ID, SOUND_ALERT_IDENTIFIER, KEY_ACTION_ID, [NSDictionary dictionaryWithObject:[sounds objectForKey:key] forKey: KEY_ALERT_SOUND_PATH], KEY_ACTION_DETAILS, * @brief Apply a sound set - (void)applySoundSet:(AISoundSet *)soundSet [adium.preferenceController delayPreferenceChangedNotifications:YES]; //Clear out old global sound alerts [adium.contactAlertsController removeAllGlobalAlertsWithActionID:SOUND_ALERT_IDENTIFIER]; AILog(@"Applying sound set %@",soundSet); NSDictionary *sounds = [soundSet sounds]; for (NSString *key in sounds) { NSDictionary *soundAlert = [ESGlobalEventsPreferencesPlugin soundAlertForKey:key [adium.contactAlertsController addGlobalAlert:soundAlert]; [adium.preferenceController delayPreferenceChangedNotifications:NO]; #pragma mark All simple presets - (void)_activateSet:(NSArray *)setArray withActionID:(NSString *)actionID alertGenerationSelector:(SEL)selector NSDictionary *dictionary; //Clear out old global dock behavior alerts [adium.contactAlertsController removeAllGlobalAlertsWithActionID:actionID]; for (dictionary in setArray) { [adium.contactAlertsController addGlobalAlert:[self performSelector:selector - (void)setEventPreset:(NSDictionary *)eventPreset [adium.preferenceController delayPreferenceChangedNotifications:YES]; [adium.contactAlertsController setAllGlobalAlerts:[eventPreset objectForKey:@"Events"]]; /* For a built in set, we now should apply the sound set it specified. User-created sets already include the * soundset as individual events. if ([eventPreset objectForKey:@"Built In"] && [[eventPreset objectForKey:@"Built In"] boolValue]) { NSString *soundSet = [eventPreset objectForKey:KEY_EVENT_SOUND_SET]; [self applySoundSet:(soundSet ? [AISoundSet soundSetWithContentsOfFile:[soundSet stringByExpandingBundlePath]] : nil)]; [adium.preferenceController delayPreferenceChangedNotifications:NO]; //Set the name of the now-active event set, which includes sounds and all other events [adium.preferenceController setPreference:[eventPreset objectForKey:KEY_EVENT_SET_NAME] forKey:KEY_ACTIVE_EVENT_SET group:PREF_GROUP_EVENT_PRESETS]; - (CGFloat)nextOrderIndex NSNumber *nextOrderIndexNumber = [adium.preferenceController preferenceForKey:KEY_NEXT_ORDER_INDEX group:PREF_GROUP_EVENT_PRESETS]; nextOrderIndex = (nextOrderIndexNumber ? (CGFloat)[nextOrderIndexNumber doubleValue] : 1.0f); [adium.preferenceController setPreference:[NSNumber numberWithDouble:(nextOrderIndex + 1)] forKey:KEY_NEXT_ORDER_INDEX group:PREF_GROUP_EVENT_PRESETS]; * @brief Save an event preset * This will assign an order index to the preset if necessary and then save it to the stored event presets dictionary. * If a preset with the same name exists, it will be overwritten - (void)saveEventPreset:(NSMutableDictionary *)eventPreset NSString *name = [eventPreset objectForKey:KEY_EVENT_SET_NAME]; //Assign the next order index to this preset if it doesn't have one yet if (![eventPreset objectForKey:KEY_ORDER_INDEX]) { [eventPreset setObject:[NSNumber numberWithDouble:[self nextOrderIndex]] //If we don't have a name at this point, simply assign one //Make sure we're not using a name which is already in use if ([storedEventPresets objectForKey:name]) { name = [NEW_PRESET_NAME stringByAppendingFormat:@" (%lu)",i]; while ([storedEventPresets objectForKey:name] != nil) { name = [NEW_PRESET_NAME stringByAppendingFormat:@" (%lu)",i]; NSAssert(name != nil, @"name is nil"); [eventPreset setObject:name forKey:KEY_EVENT_SET_NAME]; NSAssert(eventPreset != nil, @"eventPreset is nil"); [storedEventPresets setObject:eventPreset [adium.preferenceController setPreference:storedEventPresets forKey:KEY_STORED_EVENT_PRESETS group:PREF_GROUP_EVENT_PRESETS]; * @brief Delete an event preset - (void)deleteEventPreset:(NSDictionary *)eventPreset [storedEventPresets removeObjectForKey:[eventPreset objectForKey:KEY_EVENT_SET_NAME]]; [adium.preferenceController setPreference:storedEventPresets forKey:KEY_STORED_EVENT_PRESETS group:PREF_GROUP_EVENT_PRESETS]; - (NSDictionary *)builtInEventPresets return builtInEventPresets; - (NSDictionary *)storedEventPresets return storedEventPresets; NSInteger eventPresetsSort(id eventPresetA, id eventPresetB, void *context) CGFloat orderIndexA = (CGFloat)[[eventPresetA objectForKey:KEY_ORDER_INDEX] doubleValue]; CGFloat orderIndexB = (CGFloat)[[eventPresetB objectForKey:KEY_ORDER_INDEX] doubleValue]; if (orderIndexA > orderIndexB) { return NSOrderedDescending; } else if (orderIndexA < orderIndexB) { return NSOrderedAscending; return [[eventPresetA objectForKey:KEY_EVENT_SET_NAME] caseInsensitiveCompare:[eventPresetB objectForKey:KEY_EVENT_SET_NAME]]; - (NSArray *)storedEventPresetsArray return [[storedEventPresets allValues] sortedArrayUsingFunction:eventPresetsSort - (NSArray *)builtInEventPresetsArray return [[builtInEventPresets allValues] sortedArrayUsingFunction:eventPresetsSort