aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Resources/Plists/PreferenceDefaults.plist4
-rw-r--r--Source/SPAppController.m267
-rw-r--r--Source/SPBundleEditorController.m32
-rw-r--r--Source/SPConstants.h2
-rw-r--r--Source/SPConstants.m2
5 files changed, 222 insertions, 85 deletions
diff --git a/Resources/Plists/PreferenceDefaults.plist b/Resources/Plists/PreferenceDefaults.plist
index 093174a2..591bb967 100644
--- a/Resources/Plists/PreferenceDefaults.plist
+++ b/Resources/Plists/PreferenceDefaults.plist
@@ -175,5 +175,9 @@
<string>LIKE '%@%'</string>
<key>WebKitDeveloperExtras</key>
<true/>
+ <key>deletedDefaultBundles</key>
+ <array/>
+ <key>updatedDefaultBundles</key>
+ <array/>
</dict>
</plist>
diff --git a/Source/SPAppController.m b/Source/SPAppController.m
index 046628b3..ec315f78 100644
--- a/Source/SPAppController.m
+++ b/Source/SPAppController.m
@@ -1318,117 +1318,214 @@
// Clean menu
[menu compatibleRemoveAllItems];
- NSString *bundlePath = [[NSFileManager defaultManager] applicationSupportDirectoryForSubDirectory:SPBundleSupportFolder createIfNotExists:NO error:nil];
+ NSArray *bundlePaths = [NSArray arrayWithObjects:
+ ([[NSFileManager defaultManager] applicationSupportDirectoryForSubDirectory:SPBundleSupportFolder createIfNotExists:NO error:nil])?:@"",
+ [NSString stringWithFormat:@"%@/Contents/Resources/Default Bundles", [[NSBundle mainBundle] bundlePath]],
+ nil];
- if(bundlePath) {
- NSError *error = nil;
- NSArray *foundBundles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:bundlePath error:&error];
- if (foundBundles && [foundBundles count] && error == nil) {
- for(NSString* bundle in foundBundles) {
- if(![[[bundle pathExtension] lowercaseString] isEqualToString:[SPUserBundleFileExtension lowercaseString]]) continue;
+ BOOL processDefaultBundles = NO;
+ NSFileManager *fm = [NSFileManager defaultManager];
+
+ NSArray *deletedDefaultBundles;
+ NSMutableArray *updatedDefaultBundles = [NSMutableArray array];
+ if([[NSUserDefaults standardUserDefaults] objectForKey:@"deletedDefaultBundles"]) {
+ deletedDefaultBundles = [[[NSUserDefaults standardUserDefaults] objectForKey:@"deletedDefaultBundles"] retain];
+ } else {
+ deletedDefaultBundles = [[NSArray array] retain];
+ }
+ if([[NSUserDefaults standardUserDefaults] objectForKey:@"updatedDefaultBundles"]) {
+ [updatedDefaultBundles setArray:[[NSUserDefaults standardUserDefaults] objectForKey:@"updatedDefaultBundles"]];
+ }
- foundInstalledBundles = YES;
+ for(NSString* bundlePath in bundlePaths) {
+ if([bundlePath length]) {
- NSError *readError = nil;
- NSString *convError = nil;
- NSPropertyListFormat format;
- NSDictionary *cmdData = nil;
- NSString *infoPath = [NSString stringWithFormat:@"%@/%@/%@", bundlePath, bundle, SPBundleFileName];
- NSData *pData = [NSData dataWithContentsOfFile:infoPath options:NSUncachedRead error:&readError];
+ NSError *error = nil;
+ NSArray *foundBundles = [fm contentsOfDirectoryAtPath:bundlePath error:&error];
+ if (foundBundles && [foundBundles count] && error == nil) {
- cmdData = [[NSPropertyListSerialization propertyListFromData:pData
- mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain];
+ for(NSString* bundle in foundBundles) {
+ if(![[[bundle pathExtension] lowercaseString] isEqualToString:[SPUserBundleFileExtension lowercaseString]]) continue;
- if(!cmdData || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) {
- NSLog(@"“%@/%@” file couldn't be read.", bundle, SPBundleFileName);
- NSBeep();
- if (cmdData) [cmdData release];
- } else {
- if((![cmdData objectForKey:SPBundleFileDisabledKey] || ![[cmdData objectForKey:SPBundleFileDisabledKey] intValue]) && [cmdData objectForKey:SPBundleFileNameKey] && [[cmdData objectForKey:SPBundleFileNameKey] length] && [cmdData objectForKey:SPBundleFileScopeKey])
- {
+ foundInstalledBundles = YES;
+
+ NSError *readError = nil;
+ NSString *convError = nil;
+ NSPropertyListFormat format;
+ NSDictionary *cmdData = nil;
+ NSString *infoPath = [NSString stringWithFormat:@"%@/%@/%@", bundlePath, bundle, SPBundleFileName];
+ NSData *pData = [NSData dataWithContentsOfFile:infoPath options:NSUncachedRead error:&readError];
+
+ cmdData = [[NSPropertyListSerialization propertyListFromData:pData
+ mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain];
- NSArray *scopes = [[cmdData objectForKey:SPBundleFileScopeKey] componentsSeparatedByString:@" "];
- for(NSString *scope in scopes) {
- if(![bundleUsedScopes containsObject:scope]) {
- [bundleUsedScopes addObject:scope];
- [bundleItems setObject:[NSMutableArray array] forKey:scope];
- [bundleCategories setObject:[NSMutableArray array] forKey:scope];
- [bundleKeyEquivalents setObject:[NSMutableDictionary dictionary] forKey:scope];
+ if(!cmdData || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) {
+
+ NSLog(@"“%@” file couldn't be read.", infoPath);
+ NSBeep();
+
+ } else {
+ if((![cmdData objectForKey:SPBundleFileDisabledKey] || ![[cmdData objectForKey:SPBundleFileDisabledKey] intValue])
+ && [cmdData objectForKey:SPBundleFileNameKey]
+ && [[cmdData objectForKey:SPBundleFileNameKey] length]
+ && [cmdData objectForKey:SPBundleFileScopeKey])
+ {
+
+ if([cmdData objectForKey:SPBundleFileUUIDKey] && [[cmdData objectForKey:SPBundleFileUUIDKey] length]) {
+
+ if(processDefaultBundles) {
+
+ // Skip deleted default Bundles
+ if([deletedDefaultBundles containsObject:[cmdData objectForKey:SPBundleFileUUIDKey]])
+ continue;
+
+ // If default Bundle is already install check for possible update,
+ // if so duplicate the 'old one' by renaming it and change the UUID
+ if([installedBundleUUIDs objectForKey:[cmdData objectForKey:SPBundleFileUUIDKey]]) {
+ if([updatedDefaultBundles containsObject:[cmdData objectForKey:SPBundleFileUUIDKey]]) {
+ NSString *oldPath = [NSString stringWithFormat:@"%@/%@/%@", [bundlePaths objectAtIndex:0], bundle, SPBundleFileName];
+ NSError *readError = nil;
+ NSString *convError = nil;
+ NSPropertyListFormat format;
+ NSDictionary *cmdData = nil;
+ NSData *pData = [NSData dataWithContentsOfFile:oldPath options:NSUncachedRead error:&readError];
+ cmdData = [[NSPropertyListSerialization propertyListFromData:pData
+ mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain];
+ if(!cmdData || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) {
+ NSLog(@"“%@” file couldn't be read.", oldPath);
+ NSBeep();
+ continue;
+ } else {
+ // Check for modifications
+ if([cmdData objectForKey:SPBundleFileDefaultBundleWasModifiedKey]) {
+
+ } else {
+ [fm removeItemAtPath:[NSString stringWithFormat:@"%@/%@", [bundlePaths objectAtIndex:0], bundle]];
+ [updatedDefaultBundles removeObject:[cmdData objectForKey:SPBundleFileUUIDKey]];
+ }
+ }
+ } else {
+ continue;
+ }
+ }
+
+ BOOL isDir;
+ NSString *newInfoPath = [NSString stringWithFormat:@"%@/%@/%@", [bundlePaths objectAtIndex:0], bundle, SPBundleFileName];
+ if([fm fileExistsAtPath:newInfoPath isDirectory:&isDir] && isDir)
+ newInfoPath = [NSString stringWithFormat:@"%@_%ld", newInfoPath, (NSUInteger)(random() % 35000)];
+ NSError *error = nil;
+ [fm moveItemAtPath:infoPath toPath:newInfoPath error:&error];
+ if(error != nil) {
+ NSBeep();
+ NSLog(@"Default Bundle “%@” couldn't be moved to '%@'", bundle, newInfoPath);
+ continue;
+ }
+ infoPath = [NSString stringWithString:newInfoPath];
+
+ }
+
+ [installedBundleUUIDs setObject:[NSDictionary dictionaryWithObjectsAndKeys:
+ [NSString stringWithFormat:@"%@ (%@)", bundle, [cmdData objectForKey:SPBundleFileNameKey]], @"name",
+ infoPath, @"path", nil] forKey:[cmdData objectForKey:SPBundleFileUUIDKey]];
+
+ } else {
+ NSLog(@"No UUID for %@", bundle);
+ NSBeep();
+ continue;
}
- if([cmdData objectForKey:SPBundleFileCategoryKey] && [[cmdData objectForKey:SPBundleFileCategoryKey] length] && ![[bundleCategories objectForKey:scope] containsObject:[cmdData objectForKey:SPBundleFileCategoryKey]])
- [[bundleCategories objectForKey:scope] addObject:[cmdData objectForKey:SPBundleFileCategoryKey]];
- }
+ NSArray *scopes = [[cmdData objectForKey:SPBundleFileScopeKey] componentsSeparatedByString:@" "];
+ for(NSString *scope in scopes) {
- NSMutableDictionary *aDict = [NSMutableDictionary dictionary];
- [aDict setObject:[cmdData objectForKey:SPBundleFileNameKey] forKey:SPBundleInternLabelKey];
- [aDict setObject:infoPath forKey:SPBundleInternPathToFileKey];
+ if(![bundleUsedScopes containsObject:scope]) {
+ [bundleUsedScopes addObject:scope];
+ [bundleItems setObject:[NSMutableArray array] forKey:scope];
+ [bundleCategories setObject:[NSMutableArray array] forKey:scope];
+ [bundleKeyEquivalents setObject:[NSMutableDictionary dictionary] forKey:scope];
+ }
- // Register trigger
- if([cmdData objectForKey:SPBundleFileTriggerKey]) {
- if(![bundleTriggers objectForKey:[cmdData objectForKey:SPBundleFileTriggerKey]])
- [bundleTriggers setObject:[NSMutableArray array] forKey:[cmdData objectForKey:SPBundleFileTriggerKey]];
- [[bundleTriggers objectForKey:[cmdData objectForKey:SPBundleFileTriggerKey]] addObject:[NSString stringWithFormat:@"%@|%@|%@", infoPath, [cmdData objectForKey:SPBundleFileScopeKey], ([[cmdData objectForKey:SPBundleFileOutputActionKey] isEqualToString:SPBundleOutputActionShowAsHTML])?[cmdData objectForKey:SPBundleFileUUIDKey]:@""]];
- }
+ if([cmdData objectForKey:SPBundleFileCategoryKey] && [[cmdData objectForKey:SPBundleFileCategoryKey] length] && ![[bundleCategories objectForKey:scope] containsObject:[cmdData objectForKey:SPBundleFileCategoryKey]])
+ [[bundleCategories objectForKey:scope] addObject:[cmdData objectForKey:SPBundleFileCategoryKey]];
+ }
+
+ NSMutableDictionary *aDict = [NSMutableDictionary dictionary];
+ [aDict setObject:[cmdData objectForKey:SPBundleFileNameKey] forKey:SPBundleInternLabelKey];
+ [aDict setObject:infoPath forKey:SPBundleInternPathToFileKey];
+
+ // Register trigger
+ if([cmdData objectForKey:SPBundleFileTriggerKey]) {
+ if(![bundleTriggers objectForKey:[cmdData objectForKey:SPBundleFileTriggerKey]])
+ [bundleTriggers setObject:[NSMutableArray array] forKey:[cmdData objectForKey:SPBundleFileTriggerKey]];
+ [[bundleTriggers objectForKey:[cmdData objectForKey:SPBundleFileTriggerKey]] addObject:
+ [NSString stringWithFormat:@"%@|%@|%@",
+ infoPath,
+ [cmdData objectForKey:SPBundleFileScopeKey],
+ ([[cmdData objectForKey:SPBundleFileOutputActionKey] isEqualToString:SPBundleOutputActionShowAsHTML])?[cmdData objectForKey:SPBundleFileUUIDKey]:@""]];
+ }
+
+ if([cmdData objectForKey:SPBundleFileKeyEquivalentKey] && [[cmdData objectForKey:SPBundleFileKeyEquivalentKey] length]) {
+
+ NSString *theKey = [cmdData objectForKey:SPBundleFileKeyEquivalentKey];
+ NSString *theChar = [theKey substringFromIndex:[theKey length]-1];
+ NSString *theMods = [theKey substringToIndex:[theKey length]-1];
+ NSUInteger mask = 0;
+ if([theMods rangeOfString:@"^"].length)
+ mask = mask | NSControlKeyMask;
+ if([theMods rangeOfString:@"@"].length)
+ mask = mask | NSCommandKeyMask;
+ if([theMods rangeOfString:@"~"].length)
+ mask = mask | NSAlternateKeyMask;
+ if([theMods rangeOfString:@"$"].length)
+ mask = mask | NSShiftKeyMask;
+ for(NSString* scope in scopes) {
+ if(![[bundleKeyEquivalents objectForKey:scope] objectForKey:[cmdData objectForKey:SPBundleFileKeyEquivalentKey]])
+ [[bundleKeyEquivalents objectForKey:scope] setObject:[NSMutableArray array] forKey:[cmdData objectForKey:SPBundleFileKeyEquivalentKey]];
+
+ [[[bundleKeyEquivalents objectForKey:scope] objectForKey:[cmdData objectForKey:SPBundleFileKeyEquivalentKey]] addObject:
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ infoPath, @"path",
+ [cmdData objectForKey:SPBundleFileNameKey], @"title",
+ ([cmdData objectForKey:SPBundleFileTooltipKey]) ?: @"", @"tooltip",
+ nil]];
- if([cmdData objectForKey:SPBundleFileKeyEquivalentKey] && [[cmdData objectForKey:SPBundleFileKeyEquivalentKey] length]) {
- NSString *theKey = [cmdData objectForKey:SPBundleFileKeyEquivalentKey];
- NSString *theChar = [theKey substringFromIndex:[theKey length]-1];
- NSString *theMods = [theKey substringToIndex:[theKey length]-1];
- NSUInteger mask = 0;
- if([theMods rangeOfString:@"^"].length)
- mask = mask | NSControlKeyMask;
- if([theMods rangeOfString:@"@"].length)
- mask = mask | NSCommandKeyMask;
- if([theMods rangeOfString:@"~"].length)
- mask = mask | NSAlternateKeyMask;
- if([theMods rangeOfString:@"$"].length)
- mask = mask | NSShiftKeyMask;
- for(NSString* scope in scopes) {
- if(![[bundleKeyEquivalents objectForKey:scope] objectForKey:[cmdData objectForKey:SPBundleFileKeyEquivalentKey]])
- [[bundleKeyEquivalents objectForKey:scope] setObject:[NSMutableArray array] forKey:[cmdData objectForKey:SPBundleFileKeyEquivalentKey]];
-
- [[[bundleKeyEquivalents objectForKey:scope] objectForKey:[cmdData objectForKey:SPBundleFileKeyEquivalentKey]] addObject:
- [NSDictionary dictionaryWithObjectsAndKeys:
- infoPath, @"path",
- [cmdData objectForKey:SPBundleFileNameKey], @"title",
- ([cmdData objectForKey:SPBundleFileTooltipKey]) ?: @"", @"tooltip",
- nil]];
+ }
+ [aDict setObject:[NSArray arrayWithObjects:theChar, [NSNumber numberWithInteger:mask], nil] forKey:SPBundleInternKeyEquivalentKey];
}
- [aDict setObject:[NSArray arrayWithObjects:theChar, [NSNumber numberWithInteger:mask], nil] forKey:SPBundleInternKeyEquivalentKey];
- }
+ if([cmdData objectForKey:SPBundleFileTooltipKey] && [[cmdData objectForKey:SPBundleFileTooltipKey] length])
+ [aDict setObject:[cmdData objectForKey:SPBundleFileTooltipKey] forKey:SPBundleFileTooltipKey];
- if([cmdData objectForKey:SPBundleFileUUIDKey] && [[cmdData objectForKey:SPBundleFileUUIDKey] length])
- [installedBundleUUIDs setObject:[NSDictionary dictionaryWithObjectsAndKeys:
- [NSString stringWithFormat:@"%@ (%@)", bundle, [cmdData objectForKey:SPBundleFileNameKey]], @"name",
- infoPath, @"path", nil] forKey:[cmdData objectForKey:SPBundleFileUUIDKey]];
+ if([cmdData objectForKey:SPBundleFileCategoryKey] && [[cmdData objectForKey:SPBundleFileCategoryKey] length])
+ [aDict setObject:[cmdData objectForKey:SPBundleFileCategoryKey] forKey:SPBundleFileCategoryKey];
- if([cmdData objectForKey:SPBundleFileTooltipKey] && [[cmdData objectForKey:SPBundleFileTooltipKey] length])
- [aDict setObject:[cmdData objectForKey:SPBundleFileTooltipKey] forKey:SPBundleFileTooltipKey];
+ if([cmdData objectForKey:SPBundleFileKeyEquivalentKey] && [[cmdData objectForKey:SPBundleFileKeyEquivalentKey] length])
+ [aDict setObject:[cmdData objectForKey:SPBundleFileKeyEquivalentKey] forKey:@"key"];
- if([cmdData objectForKey:SPBundleFileCategoryKey] && [[cmdData objectForKey:SPBundleFileCategoryKey] length])
- [aDict setObject:[cmdData objectForKey:SPBundleFileCategoryKey] forKey:SPBundleFileCategoryKey];
+ for(NSString* scope in scopes)
+ [[bundleItems objectForKey:scope] addObject:aDict];
- if([cmdData objectForKey:SPBundleFileKeyEquivalentKey] && [[cmdData objectForKey:SPBundleFileKeyEquivalentKey] length])
- [aDict setObject:[cmdData objectForKey:SPBundleFileKeyEquivalentKey] forKey:@"key"];
+ }
+
+ if (cmdData) [cmdData release];
- for(NSString* scope in scopes)
- [[bundleItems objectForKey:scope] addObject:aDict];
}
- if (cmdData) [cmdData release];
}
- }
- NSSortDescriptor *sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:SPBundleInternLabelKey ascending:YES] autorelease];
- for(NSString* scope in [bundleItems allKeys]) {
- [[bundleItems objectForKey:scope] sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
- [[bundleCategories objectForKey:scope] sortUsingSelector:@selector(compare:)];
+ NSSortDescriptor *sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:SPBundleInternLabelKey ascending:YES] autorelease];
+ for(NSString* scope in [bundleItems allKeys]) {
+ [[bundleItems objectForKey:scope] sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
+ [[bundleCategories objectForKey:scope] sortUsingSelector:@selector(compare:)];
+ }
}
}
+ processDefaultBundles = YES;
}
+ [deletedDefaultBundles release];
+
+ [[NSUserDefaults standardUserDefaults] setObject:updatedDefaultBundles forKey:@"updatedDefaultBundles"];
+
// Rebuild Bundles main menu item
// Add default menu items
diff --git a/Source/SPBundleEditorController.m b/Source/SPBundleEditorController.m
index 32f5b581..82c93047 100644
--- a/Source/SPBundleEditorController.m
+++ b/Source/SPBundleEditorController.m
@@ -871,6 +871,7 @@
NSFileManager *fm = [NSFileManager defaultManager];
BOOL isDir = NO;
+ BOOL isNewBundle = NO;
// If passed aPath is nil construct the path from bundle's bundleName.
// aPath is mainly used for dragging a bundle from table view.
@@ -888,6 +889,7 @@
if(![fm createDirectoryAtPath:aPath withIntermediateDirectories:YES attributes:nil error:nil])
return NO;
isDir = YES;
+ isNewBundle = YES;
}
// If aPath exists but it's not a folder bail out
@@ -908,6 +910,28 @@
kBundleNameKey,
nil]];
+
+ if(!isNewBundle) {
+ NSError *readError = nil;
+ NSString *convError = nil;
+ NSPropertyListFormat format;
+ NSDictionary *cmdData = nil;
+ NSData *pData = [NSData dataWithContentsOfFile:cmdFilePath options:NSUncachedRead error:&readError];
+ cmdData = [[NSPropertyListSerialization propertyListFromData:pData
+ mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain];
+ if(!cmdData || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) {
+ NSLog(@"“%@” file couldn't be read.", cmdFilePath);
+ NSBeep();
+ return NO;
+ } else {
+ // Check for changes and return if no changes are found
+ if([[saveDict description] isEqualToString:[cmdData description]])
+ return YES;
+ if([cmdData objectForKey:SPBundleFileIsDefaultBundleKey])
+ [saveDict setObject:[NSNumber numberWithBool:YES] forKey:SPBundleFileDefaultBundleWasModifiedKey];
+ }
+ }
+
// Remove a given old command.plist file
[fm removeItemAtPath:cmdFilePath error:nil];
[saveDict writeToFile:cmdFilePath atomically:YES];
@@ -960,6 +984,14 @@
deletionSuccessfully = NO;
break;
}
+ if([obj objectForKey:SPBundleFileIsDefaultBundleKey]) {
+ NSMutableArray *deletedBundles = [NSMutableArray array];
+ [deletedBundles setArray:[[NSUserDefaults standardUserDefaults] objectForKey:@"deletedDefaultBundles"]];
+ if(![deletedBundles containsObject:[obj objectForKey:SPBundleFileUUIDKey]]) {
+ [deletedBundles addObject:[obj objectForKey:SPBundleFileUUIDKey]];
+ [[NSUserDefaults standardUserDefaults] setObject:deletedBundles forKey:@"deletedDefaultBundles"];
+ }
+ }
[commandsOutlineView reloadData];
}
}
diff --git a/Source/SPConstants.h b/Source/SPConstants.h
index 7d85d2b7..37687ba1 100644
--- a/Source/SPConstants.h
+++ b/Source/SPConstants.h
@@ -482,6 +482,8 @@ extern NSString *SPBundleFileUUIDKey;
extern NSString *SPBundleFileDescriptionKey;
extern NSString *SPBundleFileTriggerKey;
extern NSString *SPBundleFileWithBlobKey;
+extern NSString *SPBundleFileIsDefaultBundleKey;
+extern NSString *SPBundleFileDefaultBundleWasModifiedKey;
extern NSString *SPBundleInternLabelKey;
extern NSString *SPBundleInternPathToFileKey;
extern NSString *SPBundleInternKeyEquivalentKey;
diff --git a/Source/SPConstants.m b/Source/SPConstants.m
index d118b6b6..d2edebfa 100644
--- a/Source/SPConstants.m
+++ b/Source/SPConstants.m
@@ -294,6 +294,8 @@ NSString *SPBundleFileUUIDKey = @"uuid";
NSString *SPBundleFileDescriptionKey = @"description";
NSString *SPBundleFileTriggerKey = @"trigger";
NSString *SPBundleFileWithBlobKey = @"withblob";
+NSString *SPBundleFileIsDefaultBundleKey = @"isDefaultBundle";
+NSString *SPBundleFileDefaultBundleWasModifiedKey = @"defaultBundleWasModified";
NSString *SPBundleInternLabelKey = @"label";
NSString *SPBundleInternPathToFileKey = @"path";
NSString *SPBundleInternKeyEquivalentKey = @"keyEquivalent";