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