Import from SVN r48.
[sparkle2.git] / Framework / SUProduct.m
blob3321b3fc78d105f79077c1293576f7d56614ff57
1 //
2 //  SUProduct.m
3 //  Sparkle
4 //
5 //  Created by Andy Matuschak on 8/10/07.
6 //  Copyright 2007 __MyCompanyName__. All rights reserved.
7 //
9 #import "SUProduct.h"
10 #import "NDAlias/NDAlias.h"
12 @interface SUProduct (Private)
13 - (NSImage *)genericApplicationIcon;
14 - (NSArray *)codedKeys;
15 @end
17 @implementation SUProduct
19 - (SUProduct *)initWithMainBundle:(NSBundle *)bundle
21         [super init];
22         // Create an alias to the icon URL.
23         NSString *iconPath = [bundle pathForImageResource:@"NSApplicationIcon"];
24         if (iconPath != nil)
25                 [self setIconPath:[bundle pathForImageResource:@"NSApplicationIcon"]];
26         
27         // Find the product name from the bundle.
28         NSString *productName = [bundle objectForInfoDictionaryKey:@"CFBundleName"];
29         if (!productName)
30                 productName = [[[NSFileManager defaultManager] displayNameAtPath:[bundle bundlePath]] stringByDeletingPathExtension]; // Make one up from the path.
31         [self setValue:productName forKey:@"name"];
32         
33         // Find the Sparkle feed URL.
34         NSString *feed = [bundle objectForInfoDictionaryKey:@"SUFeedURL"];
35         if (!feed)
36                 [NSException raise:@"SUNoFeedException" format:@"You must include an SUFeedURL key in Info.plist for Sparkle to know where to look!"];
37         [self setValue:[NSURL URLWithString:feed] forKey:@"feedURL"];
38         
39         // Now we set the bundle as the first path in the list of paths.
40         [self insertObject:[bundle bundlePath] inPathsAtIndex:0];
41         mainBundleAlias = [pathAliases objectAtIndex:0]; // Keep a pointer to the main bundle so we can get the version from it.
42         return self;
45 - (void)encodeWithCoder:(NSCoder *)coder
47         if ([coder allowsKeyedCoding])
48         {
49                 NSEnumerator *keyEnumerator = [[self codedKeys] objectEnumerator];
50                 NSString *key;
51                 while (key = [keyEnumerator nextObject])
52                 {
53                         [coder encodeObject:[self valueForKey:key] forKey:key];
54                 }
55                 [coder encodeConditionalObject:mainBundleAlias forKey:@"mainBundleAlias"]; // Encode this separately, since it's just a reference.
56         }
57         else
58         {
59                 // NSPortCoder doesn't support keyed coding, so we just send over the archived data.
60                 [coder encodeDataObject:[NSKeyedArchiver archivedDataWithRootObject:self]];
61         }
64 - initWithCoder:(NSCoder *)coder
66         // NSPortCoder doesn't support keyed coding, so we just send over the archived data.
67         if ([coder allowsKeyedCoding])
68         {
69                 [super init];
70                 NSEnumerator *keyEnumerator = [[self codedKeys] objectEnumerator];
71                 NSString *key;
72                 while (key = [keyEnumerator nextObject])
73                 {
74                         [self setValue:[coder decodeObjectForKey:key] forKey:key];
75                 }
76                 mainBundleAlias = [coder decodeObjectForKey:@"mainBundleAlias"]; // Decode this separately, since it's just a reference.
77                 return self;
78         }
79         else
80         {
81                 // NSPortCoder doesn't support keyed coding, so we just take archived data and make a new product from that.
82                 return [NSKeyedUnarchiver unarchiveObjectWithData:[coder decodeDataObject]];
83         }
86 - copyWithZone:(NSZone *)zone
88         return [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:self]];
91 // Keys that should be archived for NSCoding.
92 - (NSArray *)codedKeys
94         return [NSArray arrayWithObjects:@"name", @"iconAlias", @"feedURL", @"pathAliases", nil];
97 - (NSImage *)icon
99         if (!icon) // Lazily cache the icon.
100         {
101                 if ([self valueForKey:@"iconAlias"])
102                         icon = [[NSImage alloc] initWithContentsOfFile:[[self valueForKey:@"iconAlias"] path]];
103                 else
104                         return [self genericApplicationIcon]; // In case the app doesn't have an icon.
105         }
106         return icon;
109 // Abstract away the NDAlias for the icon path.
110 - (NSString *)iconPath
112         return [[self valueForKey:@"iconAlias"] path];
115 - (void)setIconPath:(NSString *)path
117         [icon release];
118         icon = nil; // We'll want to reload it next time it's asked for.
119         [self setValue:[NDAlias aliasWithPath:path] forKey:@"iconAlias"];
122 // Put a nice KVC-compliant wrapper around the paths to get around the NDAlias messiness.
123 - (NSArray *)paths
125         return [pathAliases valueForKey:@"path"];
128 - (void)insertObject:(NSString *)path inPathsAtIndex:(int)index
130         if (pathAliases == nil) { pathAliases = [[NSMutableArray array] retain]; }
131         if (![[pathAliases valueForKey:@"path"] containsObject:path])
132                 [pathAliases insertObject:[NDAlias aliasWithPath:path] atIndex:index];
135 - (void)removeObjectFromPathsAtIndex:(int)index
137         [pathAliases removeObjectAtIndex:index];
140 - (void)removeAllObjectsFromPaths
142         [pathAliases removeAllObjects];
145 - (void)dealloc
147         [name release];
148         [icon release];
149         [iconAlias release];
150         [feedURL release];
151         [pathAliases release];
152         [super dealloc];
155 - (NSImage *)genericApplicationIcon
157         return [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kGenericApplicationIcon)];
160 // We implement this to let the coder know that we actually want to send the *contents* over the line when it's passed bycopy.
161 - replacementObjectForPortCoder:(NSPortCoder *)encoder
163     if ([encoder isByref])
164                 return [NSDistantObject proxyWithLocal:self connection:[encoder connection]];
165     else
166                 return self;
169 @end