Frameworks/Adium Framework/Source/AIServiceIcons.m
author Zachary West <zacw@adium.im>
Sat Oct 17 17:35:57 2009 -0400 (2009-10-17)
changeset 2632 4e544bf1b994
parent 2631 b8941b8c037c
permissions -rw-r--r--
Add -[AIService pathForDefaultServiceIconOfType:], and use it for replacing %serviceIconImg% in headers. Fixes #12697.
     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 		AIService *service = [adium.accountController firstServiceWithServiceID:serviceID];
    78 		if (service) {
    79 			return [service pathForDefaultServiceIconOfType:iconType];
    80 		} else {
    81 			return nil;
    82 		}
    83 	}
    84 }
    85 
    86 //Retrieve the correct service icon for a service by ID
    87 + (NSImage *)serviceIconForServiceID:(NSString *)serviceID type:(AIServiceIconType)iconType direction:(AIIconDirection)iconDirection
    88 {
    89 	NSImage				*serviceIcon;
    90 
    91 	//Retrieve the service icon from our cache
    92 	serviceIcon = [serviceIcons[iconType][iconDirection] objectForKey:serviceID];
    93 
    94 	//Load the service icon if necessary
    95 	if (!serviceIcon) {
    96 		NSString	*path = [self pathForServiceIconForServiceID:serviceID type:iconType];
    97 
    98 		if (path) {
    99 			serviceIcon = [[NSImage alloc] initWithContentsOfFile:path];
   100 		} else {
   101 			AIService *service = [adium.accountController firstServiceWithServiceID:serviceID];
   102 			if (service) {
   103 				serviceIcon = [[service defaultServiceIconOfType:iconType] retain];
   104 			}
   105 		}
   106 
   107 		if (serviceIcon) {
   108 			if (iconDirection == AIIconFlipped) [serviceIcon setFlipped:YES];
   109 			[serviceIcons[iconType][iconDirection] setObject:serviceIcon forKey:serviceID];
   110 			[serviceIcon release];
   111 		} else {
   112 			//Attempt to load the default service icon
   113 			serviceIcon = [self defaultServiceIconForType:iconType serviceID:serviceID];
   114 			if (serviceIcon) {
   115 				//Cache the default service icon (until the pack is changed) so we have it immediately next time
   116 				if (iconDirection == AIIconFlipped) [serviceIcon setFlipped:YES];
   117 				[serviceIcons[iconType][iconDirection] setObject:serviceIcon forKey:serviceID];
   118 			}
   119 		}
   120 	}
   121 
   122 	return serviceIcon;
   123 }
   124 
   125 //Set the active service icon pack
   126 + (BOOL)setActiveServiceIconsFromPath:(NSString *)inPath
   127 {
   128 	NSDictionary	*serviceIconDict = [NSDictionary dictionaryWithContentsOfFile:[inPath stringByAppendingPathComponent:@"Icons.plist"]];
   129 
   130 	if (serviceIconDict && [[serviceIconDict objectForKey:@"AdiumSetVersion"] intValue] == 1) {
   131 		[serviceIconBasePath release];
   132 		serviceIconBasePath = [inPath retain];
   133 
   134 		[serviceIconNames[AIServiceIconSmall] release];
   135 		serviceIconNames[AIServiceIconSmall] = [[serviceIconDict objectForKey:@"Interface-Small"] retain];
   136 
   137 		[serviceIconNames[AIServiceIconLarge] release];
   138 		serviceIconNames[AIServiceIconLarge] = [[serviceIconDict objectForKey:@"Interface-Large"] retain];
   139 
   140 		[serviceIconNames[AIServiceIconList] release];
   141 		serviceIconNames[AIServiceIconList] = [[serviceIconDict objectForKey:@"List"] retain];
   142 
   143 		//Clear out the service icon cache
   144 		int i, j;
   145 
   146 		for (i = 0; i < NUMBER_OF_SERVICE_ICON_TYPES; i++) {
   147 			for (j = 0; j < NUMBER_OF_ICON_DIRECTIONS; j++) {
   148 				[serviceIcons[i][j] removeAllObjects];
   149 			}
   150 		}
   151 
   152 		[[NSNotificationCenter defaultCenter] postNotificationName:AIServiceIconSetDidChangeNotification
   153 																		   object:nil];
   154 
   155 		return YES;
   156 	}
   157 
   158 	return NO;
   159 }
   160 
   161 #define	PREVIEW_MENU_IMAGE_SIZE		13
   162 #define	PREVIEW_MENU_IMAGE_MARGIN	2
   163 
   164 + (NSImage *)previewMenuImageForIconPackAtPath:(NSString *)inPath
   165 {
   166 	NSImage			*image;
   167 	NSDictionary	*iconDict;
   168 
   169 	image = [[NSImage alloc] initWithSize:NSMakeSize((PREVIEW_MENU_IMAGE_SIZE + PREVIEW_MENU_IMAGE_MARGIN) * 4,
   170 													 PREVIEW_MENU_IMAGE_SIZE)];
   171 
   172 	iconDict = [NSDictionary dictionaryWithContentsOfFile:[inPath stringByAppendingPathComponent:@"Icons.plist"]];
   173 
   174 	if (iconDict && [[iconDict objectForKey:@"AdiumSetVersion"] intValue] == 1) {
   175 		NSDictionary	*previewIconNames = [iconDict objectForKey:@"List"];
   176 		NSEnumerator	*enumerator = [[NSArray arrayWithObjects:@"AIM",@"Jabber",@"MSN",@"Yahoo!",nil] objectEnumerator];
   177 		NSString		*iconID;
   178 		int				xOrigin = 0;
   179 
   180 		[image lockFocus];
   181 		while ((iconID = [enumerator nextObject])) {
   182 			NSString	*anIconPath = [inPath stringByAppendingPathComponent:[previewIconNames objectForKey:iconID]];
   183 			NSImage		*anIcon;
   184 
   185 			if ((anIcon = [[[NSImage alloc] initWithContentsOfFile:anIconPath] autorelease])) {
   186 				NSSize	anIconSize = [anIcon size];
   187 				NSRect	targetRect = NSMakeRect(xOrigin, 0, PREVIEW_MENU_IMAGE_SIZE, PREVIEW_MENU_IMAGE_SIZE);
   188 
   189 				if (anIconSize.width < targetRect.size.width) {
   190 					float difference = (targetRect.size.width - anIconSize.width)/2;
   191 
   192 					targetRect.size.width -= difference;
   193 					targetRect.origin.x += difference;
   194 				}
   195 
   196 				if (anIconSize.height < targetRect.size.height) {
   197 					float difference = (targetRect.size.height - anIconSize.height)/2;
   198 
   199 					targetRect.size.height -= difference;
   200 					targetRect.origin.y += difference;
   201 				}
   202 
   203 				[anIcon drawInRect:targetRect
   204 							fromRect:NSMakeRect(0,0,anIconSize.width,anIconSize.height)
   205 						   operation:NSCompositeCopy
   206 							fraction:1.0];
   207 
   208 				//Shift right in preparation for next image
   209 				xOrigin += PREVIEW_MENU_IMAGE_SIZE + PREVIEW_MENU_IMAGE_MARGIN;
   210 			}
   211 		}
   212 		[image unlockFocus];
   213 	}
   214 
   215 	return [image autorelease];
   216 }
   217 
   218 #pragma mark Default loading
   219 
   220 #define PREF_GROUP_APPEARANCE		@"Appearance"
   221 #define	KEY_SERVICE_ICON_PACK		@"Service Icon Pack"
   222 
   223 + (NSImage *)defaultServiceIconForType:(AIServiceIconType)type serviceID:(NSString *)serviceID
   224 {
   225 	NSString			*defaultName, *defaultPath;
   226 	NSDictionary		*serviceIconDict;
   227 	NSImage				*defaultServiceIcon = nil;
   228 	
   229 	defaultName = [adium.preferenceController defaultPreferenceForKey:KEY_SERVICE_ICON_PACK
   230 																   group:PREF_GROUP_APPEARANCE
   231 																  object:nil];
   232 	defaultPath = [adium pathOfPackWithName:defaultName
   233 								  extension:@"AdiumServiceIcons"
   234 						 resourceFolderName:@"Service Icons"];
   235 	
   236 	serviceIconDict = [NSDictionary dictionaryWithContentsOfFile:[defaultPath stringByAppendingPathComponent:@"Icons.plist"]];
   237 	if (serviceIconDict && [[serviceIconDict objectForKey:@"AdiumSetVersion"] intValue] == 1) {
   238 		NSString	*nameKey = nil;
   239 
   240 		switch (type) {
   241 			case AIServiceIconSmall:
   242 				nameKey = @"Interface-Small";
   243 				break;
   244 			case AIServiceIconLarge:
   245 				nameKey = @"Interface-Large";
   246 				break;
   247 			case AIServiceIconList:
   248 				nameKey = @"List";
   249 				break;
   250 		}
   251 		
   252 		if (nameKey) {
   253 			NSDictionary	*defaultServiceIconNames;
   254 			NSString		*thisServiceIconImageName;
   255 	
   256 			defaultServiceIconNames = [serviceIconDict objectForKey:nameKey];
   257 			if ((thisServiceIconImageName = [defaultServiceIconNames objectForKey:serviceID])) {
   258 				NSString		*iconPath = [defaultPath stringByAppendingPathComponent:thisServiceIconImageName];
   259 				
   260 				defaultServiceIcon = [[[NSImage alloc] initWithContentsOfFile:iconPath] autorelease];
   261 			}
   262 		}
   263 	}
   264 	
   265 	return defaultServiceIcon;
   266 }
   267 
   268 @end