Frameworks/Adium Framework/Source/AIServiceIcons.m
author Zachary West <zacw@adium.im>
Sat Oct 17 17:20:24 2009 -0400 (2009-10-17)
changeset 2741 545ce4868ddd
parent 2188 9432f1ab12de
child 2742 2b36c67b4a96
permissions -rw-r--r--
When loading a service icon from service ID and the pack doesn't specify one, ask the first service with that ID for it.

This also will return 'nil' instead of a dead path for service icons which are not supported by an icon pack, but which a service specifies as a default. Refs #12697. (We don't know the paths of default service icons, yet)
David@0
     1
/* 
David@0
     2
 * Adium is the legal property of its developers, whose names are listed in the copyright file included
David@0
     3
 * with this source distribution.
David@0
     4
 * 
David@0
     5
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
David@0
     6
 * General Public License as published by the Free Software Foundation; either version 2 of the License,
David@0
     7
 * or (at your option) any later version.
David@0
     8
 * 
David@0
     9
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
David@0
    10
 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
David@0
    11
 * Public License for more details.
David@0
    12
 * 
David@0
    13
 * You should have received a copy of the GNU General Public License along with this program; if not,
David@0
    14
 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
David@0
    15
 */
David@0
    16
David@0
    17
#import <Adium/AIListObject.h>
David@0
    18
#import <Adium/AIService.h>
David@0
    19
#import <Adium/AIServiceIcons.h>
zacw@2741
    20
#import <Adium/AIAccountControllerProtocol.h>
David@0
    21
David@0
    22
static NSMutableDictionary	*serviceIcons[NUMBER_OF_SERVICE_ICON_TYPES][NUMBER_OF_ICON_DIRECTIONS];
David@0
    23
David@0
    24
static NSString				*serviceIconBasePath = nil;
David@0
    25
static NSDictionary			*serviceIconNames[NUMBER_OF_SERVICE_ICON_TYPES];
David@0
    26
David@84
    27
@interface AIServiceIcons ()
David@0
    28
+ (NSImage *)defaultServiceIconForType:(AIServiceIconType)type serviceID:(NSString *)serviceID;
David@0
    29
@end
David@0
    30
David@0
    31
@implementation AIServiceIcons
David@0
    32
David@0
    33
+ (void)initialize
David@0
    34
{
David@0
    35
	if (self == [AIServiceIcons class]) {
David@0
    36
		int i, j;
David@0
    37
David@0
    38
		//Allocate our service icon cache
David@0
    39
		for (i = 0; i < NUMBER_OF_SERVICE_ICON_TYPES; i++) {
David@0
    40
			for (j = 0; j < NUMBER_OF_ICON_DIRECTIONS; j++) {
David@0
    41
				serviceIcons[i][j] = [[NSMutableDictionary alloc] init];
David@0
    42
			}
David@0
    43
		}
David@0
    44
	}
David@0
    45
}
David@0
    46
David@0
    47
//Retrive the correct service icon for a contact
David@0
    48
+ (NSImage *)serviceIconForObject:(AIListObject *)inObject type:(AIServiceIconType)iconType direction:(AIIconDirection)iconDirection
David@0
    49
{
David@837
    50
	return [self serviceIconForService:inObject.service type:iconType direction:iconDirection];
David@0
    51
}
David@0
    52
David@0
    53
//Retrieve the correct service icon for a service
David@0
    54
+ (NSImage *)serviceIconForService:(AIService *)service type:(AIServiceIconType)iconType direction:(AIIconDirection)iconDirection
David@0
    55
{
David@715
    56
	NSImage	*serviceIcon = [self serviceIconForServiceID:service.serviceID type:iconType direction:iconDirection];
David@0
    57
David@0
    58
	if (!serviceIcon && service) {
David@0
    59
		//If the icon pack doesn't supply a service icon, query the service itself
David@0
    60
		serviceIcon = [service defaultServiceIconOfType:iconType];
David@0
    61
David@0
    62
		if (serviceIcon) {
David@0
    63
			if (iconDirection == AIIconFlipped) [serviceIcon setFlipped:YES];
David@715
    64
			[serviceIcons[iconType][iconDirection] setObject:serviceIcon forKey:service.serviceID];
David@0
    65
		}
David@0
    66
	}
David@0
    67
	return serviceIcon;
David@0
    68
}
David@0
    69
David@0
    70
+ (NSString *)pathForServiceIconForServiceID:(NSString *)serviceID type:(AIServiceIconType)iconType
David@0
    71
{
zacw@2741
    72
	NSString *iconName = [serviceIconNames[iconType] objectForKey:serviceID];
zacw@2741
    73
	
zacw@2741
    74
	if (iconName) {
zacw@2741
    75
		return [serviceIconBasePath stringByAppendingPathComponent:iconName];
zacw@2741
    76
	} else {
zacw@2741
    77
		return nil;
zacw@2741
    78
	}
David@0
    79
}
David@0
    80
David@0
    81
//Retrieve the correct service icon for a service by ID
David@0
    82
+ (NSImage *)serviceIconForServiceID:(NSString *)serviceID type:(AIServiceIconType)iconType direction:(AIIconDirection)iconDirection
David@0
    83
{
David@0
    84
	NSImage				*serviceIcon;
David@0
    85
David@0
    86
	//Retrieve the service icon from our cache
David@0
    87
	serviceIcon = [serviceIcons[iconType][iconDirection] objectForKey:serviceID];
David@0
    88
David@0
    89
	//Load the service icon if necessary
David@0
    90
	if (!serviceIcon) {
David@0
    91
		NSString	*path = [self pathForServiceIconForServiceID:serviceID type:iconType];
David@0
    92
David@0
    93
		if (path) {
David@0
    94
			serviceIcon = [[NSImage alloc] initWithContentsOfFile:path];
zacw@2741
    95
		} else {
zacw@2741
    96
			AIService *service = [adium.accountController firstServiceWithServiceID:serviceID];
zacw@2741
    97
			if (service) {
zacw@2741
    98
				serviceIcon = [service defaultServiceIconOfType:iconType];
zacw@2741
    99
			}
zacw@2741
   100
		}
David@0
   101
zacw@2741
   102
		if (serviceIcon) {
zacw@2741
   103
			if (iconDirection == AIIconFlipped) [serviceIcon setFlipped:YES];
zacw@2741
   104
			[serviceIcons[iconType][iconDirection] setObject:serviceIcon forKey:serviceID];
zacw@2741
   105
			[serviceIcon release];
zacw@2741
   106
		} else {
zacw@2741
   107
			//Attempt to load the default service icon
zacw@2741
   108
			serviceIcon = [self defaultServiceIconForType:iconType serviceID:serviceID];
David@0
   109
			if (serviceIcon) {
zacw@2741
   110
				//Cache the default service icon (until the pack is changed) so we have it immediately next time
David@0
   111
				if (iconDirection == AIIconFlipped) [serviceIcon setFlipped:YES];
David@0
   112
				[serviceIcons[iconType][iconDirection] setObject:serviceIcon forKey:serviceID];
David@0
   113
			}
David@0
   114
		}
David@0
   115
	}
David@0
   116
David@0
   117
	return serviceIcon;
David@0
   118
}
David@0
   119
David@0
   120
//Set the active service icon pack
David@0
   121
+ (BOOL)setActiveServiceIconsFromPath:(NSString *)inPath
David@0
   122
{
David@0
   123
	NSDictionary	*serviceIconDict = [NSDictionary dictionaryWithContentsOfFile:[inPath stringByAppendingPathComponent:@"Icons.plist"]];
David@0
   124
David@0
   125
	if (serviceIconDict && [[serviceIconDict objectForKey:@"AdiumSetVersion"] intValue] == 1) {
David@0
   126
		[serviceIconBasePath release];
David@0
   127
		serviceIconBasePath = [inPath retain];
David@0
   128
David@0
   129
		[serviceIconNames[AIServiceIconSmall] release];
David@0
   130
		serviceIconNames[AIServiceIconSmall] = [[serviceIconDict objectForKey:@"Interface-Small"] retain];
David@0
   131
David@0
   132
		[serviceIconNames[AIServiceIconLarge] release];
David@0
   133
		serviceIconNames[AIServiceIconLarge] = [[serviceIconDict objectForKey:@"Interface-Large"] retain];
David@0
   134
David@0
   135
		[serviceIconNames[AIServiceIconList] release];
David@0
   136
		serviceIconNames[AIServiceIconList] = [[serviceIconDict objectForKey:@"List"] retain];
David@0
   137
David@0
   138
		//Clear out the service icon cache
David@0
   139
		int i, j;
David@0
   140
David@0
   141
		for (i = 0; i < NUMBER_OF_SERVICE_ICON_TYPES; i++) {
David@0
   142
			for (j = 0; j < NUMBER_OF_ICON_DIRECTIONS; j++) {
David@0
   143
				[serviceIcons[i][j] removeAllObjects];
David@0
   144
			}
David@0
   145
		}
David@0
   146
David@1109
   147
		[[NSNotificationCenter defaultCenter] postNotificationName:AIServiceIconSetDidChangeNotification
David@0
   148
																		   object:nil];
David@0
   149
David@0
   150
		return YES;
David@0
   151
	}
David@0
   152
David@0
   153
	return NO;
David@0
   154
}
David@0
   155
David@0
   156
#define	PREVIEW_MENU_IMAGE_SIZE		13
David@0
   157
#define	PREVIEW_MENU_IMAGE_MARGIN	2
David@0
   158
David@0
   159
+ (NSImage *)previewMenuImageForIconPackAtPath:(NSString *)inPath
David@0
   160
{
David@0
   161
	NSImage			*image;
David@0
   162
	NSDictionary	*iconDict;
David@0
   163
David@0
   164
	image = [[NSImage alloc] initWithSize:NSMakeSize((PREVIEW_MENU_IMAGE_SIZE + PREVIEW_MENU_IMAGE_MARGIN) * 4,
David@0
   165
													 PREVIEW_MENU_IMAGE_SIZE)];
David@0
   166
David@0
   167
	iconDict = [NSDictionary dictionaryWithContentsOfFile:[inPath stringByAppendingPathComponent:@"Icons.plist"]];
David@0
   168
David@0
   169
	if (iconDict && [[iconDict objectForKey:@"AdiumSetVersion"] intValue] == 1) {
David@0
   170
		NSDictionary	*previewIconNames = [iconDict objectForKey:@"List"];
David@0
   171
		NSEnumerator	*enumerator = [[NSArray arrayWithObjects:@"AIM",@"Jabber",@"MSN",@"Yahoo!",nil] objectEnumerator];
David@0
   172
		NSString		*iconID;
David@0
   173
		int				xOrigin = 0;
David@0
   174
David@0
   175
		[image lockFocus];
David@0
   176
		while ((iconID = [enumerator nextObject])) {
David@0
   177
			NSString	*anIconPath = [inPath stringByAppendingPathComponent:[previewIconNames objectForKey:iconID]];
David@0
   178
			NSImage		*anIcon;
David@0
   179
David@0
   180
			if ((anIcon = [[[NSImage alloc] initWithContentsOfFile:anIconPath] autorelease])) {
David@0
   181
				NSSize	anIconSize = [anIcon size];
David@0
   182
				NSRect	targetRect = NSMakeRect(xOrigin, 0, PREVIEW_MENU_IMAGE_SIZE, PREVIEW_MENU_IMAGE_SIZE);
David@0
   183
David@0
   184
				if (anIconSize.width < targetRect.size.width) {
David@0
   185
					float difference = (targetRect.size.width - anIconSize.width)/2;
David@0
   186
David@0
   187
					targetRect.size.width -= difference;
David@0
   188
					targetRect.origin.x += difference;
David@0
   189
				}
David@0
   190
David@0
   191
				if (anIconSize.height < targetRect.size.height) {
David@0
   192
					float difference = (targetRect.size.height - anIconSize.height)/2;
David@0
   193
David@0
   194
					targetRect.size.height -= difference;
David@0
   195
					targetRect.origin.y += difference;
David@0
   196
				}
David@0
   197
David@0
   198
				[anIcon drawInRect:targetRect
David@0
   199
							fromRect:NSMakeRect(0,0,anIconSize.width,anIconSize.height)
David@0
   200
						   operation:NSCompositeCopy
David@0
   201
							fraction:1.0];
David@0
   202
David@0
   203
				//Shift right in preparation for next image
David@0
   204
				xOrigin += PREVIEW_MENU_IMAGE_SIZE + PREVIEW_MENU_IMAGE_MARGIN;
David@0
   205
			}
David@0
   206
		}
David@0
   207
		[image unlockFocus];
David@0
   208
	}
David@0
   209
David@0
   210
	return [image autorelease];
David@0
   211
}
David@0
   212
David@0
   213
#pragma mark Default loading
David@0
   214
David@0
   215
#define PREF_GROUP_APPEARANCE		@"Appearance"
David@0
   216
#define	KEY_SERVICE_ICON_PACK		@"Service Icon Pack"
David@0
   217
David@0
   218
+ (NSImage *)defaultServiceIconForType:(AIServiceIconType)type serviceID:(NSString *)serviceID
David@0
   219
{
David@0
   220
	NSString			*defaultName, *defaultPath;
David@0
   221
	NSDictionary		*serviceIconDict;
David@0
   222
	NSImage				*defaultServiceIcon = nil;
David@0
   223
	
David@95
   224
	defaultName = [adium.preferenceController defaultPreferenceForKey:KEY_SERVICE_ICON_PACK
David@0
   225
																   group:PREF_GROUP_APPEARANCE
David@0
   226
																  object:nil];
David@0
   227
	defaultPath = [adium pathOfPackWithName:defaultName
David@0
   228
								  extension:@"AdiumServiceIcons"
David@0
   229
						 resourceFolderName:@"Service Icons"];
David@0
   230
	
David@0
   231
	serviceIconDict = [NSDictionary dictionaryWithContentsOfFile:[defaultPath stringByAppendingPathComponent:@"Icons.plist"]];
David@0
   232
	if (serviceIconDict && [[serviceIconDict objectForKey:@"AdiumSetVersion"] intValue] == 1) {
David@0
   233
		NSString	*nameKey = nil;
David@0
   234
David@0
   235
		switch (type) {
David@0
   236
			case AIServiceIconSmall:
David@0
   237
				nameKey = @"Interface-Small";
David@0
   238
				break;
David@0
   239
			case AIServiceIconLarge:
David@0
   240
				nameKey = @"Interface-Large";
David@0
   241
				break;
David@0
   242
			case AIServiceIconList:
David@0
   243
				nameKey = @"List";
David@0
   244
				break;
David@0
   245
		}
David@0
   246
		
David@0
   247
		if (nameKey) {
David@0
   248
			NSDictionary	*defaultServiceIconNames;
David@0
   249
			NSString		*thisServiceIconImageName;
David@0
   250
	
David@0
   251
			defaultServiceIconNames = [serviceIconDict objectForKey:nameKey];
David@0
   252
			if ((thisServiceIconImageName = [defaultServiceIconNames objectForKey:serviceID])) {
David@0
   253
				NSString		*iconPath = [defaultPath stringByAppendingPathComponent:thisServiceIconImageName];
David@0
   254
				
David@1657
   255
				defaultServiceIcon = [[[NSImage alloc] initWithContentsOfFile:iconPath] autorelease];
David@0
   256
			}
David@0
   257
		}
David@0
   258
	}
David@0
   259
	
David@0
   260
	return defaultServiceIcon;
David@0
   261
}
David@0
   262
David@0
   263
@end