diff --git a/Quicksilver/Code-App/QSCatalogPrefPane.m b/Quicksilver/Code-App/QSCatalogPrefPane.m index bb7525df9..5590930f4 100644 --- a/Quicksilver/Code-App/QSCatalogPrefPane.m +++ b/Quicksilver/Code-App/QSCatalogPrefPane.m @@ -31,6 +31,7 @@ #include #import "QSOutlineView.h" #import "QSTableView.h" +#import "QSCatalogEntry_Private.h" @interface QSObject (NSTreeNodePrivate) //- (NSIndexPath *)indexPath; @@ -168,8 +169,8 @@ - (void)awakeFromNib { [[[itemContentsTable tableColumnWithIdentifier:kItemPath] dataCell] setFont:[NSFont labelFontOfSize:9]]; [[[itemContentsTable tableColumnWithIdentifier:kItemPath] dataCell] setWraps:NO]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(catalogChanged:) name:QSCatalogEntryChanged object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(catalogIndexed:) name:QSCatalogEntryIndexed object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(catalogChanged:) name:QSCatalogEntryChangedNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(catalogIndexed:) name:QSCatalogEntryIndexedNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateEntrySelection) name:NSOutlineViewSelectionDidChangeNotification object:nil]; [itemTable reloadData]; @@ -283,7 +284,7 @@ - (IBAction)addSource:(id)sender { [self showOptionsDrawer]; [[NSNotificationCenter defaultCenter] postNotificationName:QSCatalogStructureChanged object:nil]; - [[NSNotificationCenter defaultCenter] postNotificationName:QSCatalogEntryChanged object:childEntry]; + [[NSNotificationCenter defaultCenter] postNotificationName:QSCatalogEntryChangedNotification object:childEntry]; } - (IBAction)saveItem:(id)sender { @@ -539,8 +540,7 @@ - (void)populateCatalogEntryFields { - (IBAction)setValueForSenderForCatalogEntry:(id)sender { if (sender == itemIconField) { - NSData *imageData = [[sender image] TIFFRepresentationUsingCompression:NSTIFFCompressionLZW factor:0]; - [[currentItem info] setObject:imageData forKey:kItemIcon]; + currentItem.icon = [sender image]; [itemTable reloadData]; } } @@ -574,7 +574,7 @@ - (BOOL)windowShouldClose:(id)sender { } - (IBAction)applySettings:(id)sender { - [[NSNotificationCenter defaultCenter] postNotificationName:QSCatalogEntryChanged object:nil]; + [[NSNotificationCenter defaultCenter] postNotificationName:QSCatalogEntryChangedNotification object:nil]; [(QSController *)[NSApp delegate] rescanItems:sender]; } diff --git a/Quicksilver/Code-App/QSSetupAssistant.m b/Quicksilver/Code-App/QSSetupAssistant.m index b181729a7..6098f3cd1 100644 --- a/Quicksilver/Code-App/QSSetupAssistant.m +++ b/Quicksilver/Code-App/QSSetupAssistant.m @@ -78,7 +78,7 @@ - (void)windowDidLoad { // [setupTabView removeTabViewItem:[setupTabView tabViewItemAtIndex:[setupTabView indexOfTabViewItemWithIdentifier:@"network"]]]; //[setupTabView removeTabViewItem:[setupTabView tabViewItemAtIndex:[setupTabView indexOfTabViewItemWithIdentifier:@"features"]]]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(installStatusChanged:) name:@"QSPlugInUpdatesFinished" object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(catalogIndexed:) name:QSCatalogEntryIsIndexing object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(catalogIndexed:) name:QSCatalogEntryIsIndexingNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(catalogIndexingFinished:) name:QSCatalogIndexingCompleted object:nil]; [[self window] setLevel:NSNormalWindowLevel]; @@ -145,7 +145,7 @@ - (void)catalogIndexingFinished:(id)notif { } } - (void)catalogIndexed:(NSNotification *)notif { - if ([[notif name] isEqualToString:QSCatalogEntryIsIndexing]) + if ([[notif name] isEqualToString:QSCatalogEntryIsIndexingNotification]) [scanStatusField setStringValue:[NSString stringWithFormat:@"Scanning %@", [(QSCatalogEntry *)[notif object] name]]]; } diff --git a/Quicksilver/Code-QuickStepCore/QSCatalogEntry.h b/Quicksilver/Code-QuickStepCore/QSCatalogEntry.h index fd9f2495d..2562fdc6e 100644 --- a/Quicksilver/Code-QuickStepCore/QSCatalogEntry.h +++ b/Quicksilver/Code-QuickStepCore/QSCatalogEntry.h @@ -8,79 +8,254 @@ #import -@interface QSCatalogEntry : NSObject { - __block NSDate *indexDate; - BOOL isPreset; +@class QSObjectSource; - NSString *name; - id parent; - NSMutableArray *children; - dispatch_queue_t scanQueue; - NSMutableDictionary *info; - NSArray *contents; - NSBundle *bundle; - BOOL isScanning; -} +extern NSString *const QSCatalogEntryChangedNotification; +extern NSString *const QSCatalogEntryIsIndexingNotification; +extern NSString *const QSCatalogEntryIndexedNotification; +extern NSString *const QSCatalogEntryInvalidatedNotification; -@property (assign, atomic) BOOL isScanning; +/** + * QSCatalogEntry represent an entry in Quicksilver's catalog. + * + * It is built as tree of QSCatalogEntry, each having both `children` (more + * entries) and `contents` (as a list of `QSObject`s. + * It is also responsible for scanning its contents regularly, using one of the + * QSObjectSources provided by QS or a plugin. + */ +@interface QSCatalogEntry : NSObject +//////////////////////////////////////////////////////////////////////////////// +/// @name Properties +//////////////////////////////////////////////////////////////////////////////// -@property (strong, atomic, getter=_contents) NSArray *contents; +/** Is the receiver scanning ? */ +@property (readonly, getter=isScanning) BOOL scanning; -+ (QSCatalogEntry *)entryWithDictionary:(NSDictionary *)dict; +/** Is the receiver suppressed ? */ +@property (readonly, getter=isSuppressed) BOOL suppressed; + +/** Is the receiver a default preset ? */ +@property (readonly, getter=isPreset) BOOL preset; + +/** Is the receiver a separator ? */ +@property (readonly, getter=isSeparator) BOOL separator; + +/** Is the receiver a group of more entries ? */ +@property (readonly, getter=isGroup) BOOL group; + +/** Is the receiver modifiable ? */ +@property (readonly, getter=isEditable) BOOL editable; + +/** Can the receiver be indexed ? */ +@property (readonly, getter=canBeIndexed) BOOL indexable; + +/** Is the receiver enabled ? */ +@property (getter=isEnabled) BOOL enabled; + +/** The receiver's displayable name. */ +@property (copy) NSString *name; + +/** The receiver's icon. */ +@property (retain) NSImage *icon; + +/** The receiver's identifier. */ +@property (readonly, copy) NSString *identifier; + +/** The receiver's source. */ +@property (readonly, retain) QSObjectSource *source; + +/** The receiver's last index date. */ +@property (retain) NSDate *indexDate; + +/** The contents of the receiver. */ +@property (readonly, retain) NSArray *contents; + +/** The subentries of the receiver. */ +@property (readonly, retain) NSMutableArray *children; + +/** The settings for the receiver's object source. */ +@property (readonly, retain) NSMutableDictionary *sourceSettings; + +//////////////////////////////////////////////////////////////////////////////// +/// @name Lifetime +//////////////////////////////////////////////////////////////////////////////// + +/** + * Create a new instance of the receiver from a dictionary. + * + * @param dict A serialized entry as a dictionary. + * + * @see -[QSCatalogEntry initWithDictionary:]. + */ ++ (instancetype)entryWithDictionary:(NSDictionary *)dict; + +/** + * Initialize the receiver from a dictionary. + * + * @param dict A dictionary containing + * + * @return A newly instantiated entry, or nil. + */ +- (instancetype)initWithDictionary:(NSDictionary *)dict; + +/** + * Serialize the receiver to a dictionary. + * + * @warning This is an implementation detail. You should either use the + * receiver's properties, or the private info dictionary. + */ - (NSDictionary *)dictionaryRepresentation; -- (QSCatalogEntry *)initWithDictionary:(NSDictionary *)dict; -- (void)dealloc; -- (QSCatalogEntry *)childWithID:(NSString *)theID; -- (QSCatalogEntry *)childWithPath:(NSString *)path; -- (BOOL)isSuppressed; -- (BOOL)isPreset; -- (BOOL)isSeparator; -- (BOOL)isGroup; -- (BOOL)isEditable; -- (NSInteger) state; -- (NSInteger) hasEnabledChildren; -- (BOOL)isEnabled; -- (void)setEnabled:(BOOL)enabled; +//////////////////////////////////////////////////////////////////////////////// +/// @name Basic methods +//////////////////////////////////////////////////////////////////////////////// + +/** + * Get the receiver's children with the given identifier. + * + * @param theID The identifier to lookup. + * + * @return An instance of QSCatalogEntry, or nil if there was no children with + * the given identifier. + */ +- (instancetype)childWithID:(NSString *)theID; + +/** + * Get one of the receiver's children given an "identifier path". + * + * @param path A slash-separated string of entry identifiers. + * + * @return An instance of QSCatalogEntry, or nil if one of the identifiers in + * the path wasn't valid. + */ +- (instancetype)childWithPath:(NSString *)path; + +/** Make a new unique copy of the receiver */ +- (instancetype)uniqueCopy; + +/* + * The state the receiver is in. + * + * Depending on whether the receiver is a group or not, returns either its + * enabled state, or a negative number whose value represents the number of + * enabled leaf entries. + */ +- (NSInteger)state; + +/** Is any of receiver's children enabled ? */ +- (BOOL)hasEnabledChildren; + +/** + * Enable or disable the receiver and all its children + * + * @param enabled Whether to enable or disable the children. + */ - (void)setDeepEnabled:(BOOL)enabled; + +/** + * Prune all invalid children. + * + * If the receiver's a preset entry, this will recursively remove all children + * which have no contents. + */ - (void)pruneInvalidChildren; + +/** + * Get the receiver's identifiers for its leaves. + * + * @return An array of all the enabled leaves's identifiers for the receiver. + */ - (NSArray *)leafIDs; + +/** + * Get the receiver's enabled leaves. + * + * @return An array of all the enabled leaves for the receiver. + */ - (NSArray *)leafEntries; + +/** + * Get the receiver's children. + * + * @param groups If YES, the resulting array will contain groups. + * @param leaves If YES, the resulting array will contain leaves. + * @param disabled If YES, the resulting array will contain disabled entries. + * + * @return An array of all the receiver's children matching the given options. + */ - (NSArray *)deepChildrenWithGroups:(BOOL)groups leaves:(BOOL)leaves disabled:(BOOL)disabled; -- (NSString *)identifier; + +/** + * Get the ancestors for the receiver. + * + * @return An array of the receiver's ancestor chain, starting with the root. + */ - (NSArray *)ancestors; -- (NSString *)name; -- (NSImage *)icon; -- (NSUInteger) deepObjectCount; + +/** Get the number of objects contained by the receiver and all its children. */ +- (NSUInteger)deepObjectCount; + +/** Same as deepObjectCount */ +- (NSUInteger)count; + +/** Returns whether the receiver is the root catalog entry. */ +- (BOOL)isCatalog; + +- (NSIndexPath *)catalogIndexPath; + +- (NSIndexPath *)catalogSetIndexPath; + +/** + * Get only the non-ommited objects from that entry and its children + */ +- (NSArray *)enabledContents; + +//////////////////////////////////////////////////////////////////////////////// +/// @name Indexing +//////////////////////////////////////////////////////////////////////////////// + +/** Load the receiver's index. */ - (BOOL)loadIndex; + +/** Save the receiver's index. */ - (void)saveIndex; + +/** Returns whether the index of the receiver is valid. */ - (BOOL)indexIsValid; -- (BOOL)isCatalog; -- (id)source; -- (BOOL)canBeIndexed; + +//////////////////////////////////////////////////////////////////////////////// +/// @name Scanning +//////////////////////////////////////////////////////////////////////////////// + +/** + * Get the objects scanned by the receiver's object source. + * + * @warning This bypasses the index and the receiver's object cache. You should + * rarely need to call that method. + * + * @return An array of all object that the receiver's object source generated. + */ - (NSArray *)scannedObjects; + +/** + * Scan the receiver and refresh its cache. + * + * This queries the receiver's source for objects and refresh the index. + * + * @warning If the receiver's already being scanned, this *will* return nil. + * + * @return An array of all the objects generated by the object source. + */ - (NSArray *)scanAndCache; + +/** + * Scan the receiver. + * + * @param force If YES, the current index will be ignored. + */ - (void)scanForced:(BOOL)force; -- (NSMutableArray *)children; -- (NSMutableArray *)getChildren; -- (NSArray *)contents; + - (NSArray *)contentsScanIfNeeded:(BOOL)canScan; -- (void)setContents:(NSArray *)newContents; -- (NSArray *)enabledContents; -- (NSIndexPath *)catalogIndexPath; -- (NSMutableDictionary *)info; -- (QSCatalogEntry *)uniqueCopy; -- (NSString *)indexLocation; -- (void)setName:(NSString *)newName; - -- (NSDate *)indexDate; -- (void)setIndexDate:(NSDate *)anIndexDate; -- (BOOL)isScanning; -- (void)setIsScanning:(BOOL)flag; -//- (NSString *)countString; - -- (NSUInteger) count; -- (NSIndexPath *)catalogSetIndexPath; @end diff --git a/Quicksilver/Code-QuickStepCore/QSCatalogEntry.m b/Quicksilver/Code-QuickStepCore/QSCatalogEntry.m index 94a7e6028..be8e69f5a 100644 --- a/Quicksilver/Code-QuickStepCore/QSCatalogEntry.m +++ b/Quicksilver/Code-QuickStepCore/QSCatalogEntry.m @@ -6,7 +6,9 @@ // Copyright 2005 Blacktree. All rights reserved. // +#import #import "QSCatalogEntry.h" +#import "QSCatalogEntry_Private.h" #import "QSRegistry.h" #import "QSLibrarian.h" #import "QSResourceManager.h" @@ -16,21 +18,34 @@ #import "QSTaskController.h" #import "QSObject_PropertyList.h" #import "QSTask.h" -#import - -@interface NSObject (QSCatalogSourceInformal) -- (void)enableEntry:(QSCatalogEntry *)entry; -- (void)disableEntry:(QSCatalogEntry *)entry; -@end #define kUseNSArchiveForIndexes NO; -/*NSDictionary *entriesByID; -NSDictionary *enabledPresetDictionary;*/ +NSString *const QSCatalogEntryChangedNotification = @"QSCatalogEntryChanged"; +NSString *const QSCatalogEntryIsIndexingNotification = @"QSCatalogEntryIsIndexing"; +NSString *const QSCatalogEntryIndexedNotification = @"QSCatalogEntryIndexed"; +NSString *const QSCatalogEntryInvalidatedNotification = @"QSCatalogEntryInvalidated"; -@implementation QSCatalogEntry +@interface QSCatalogEntry () { + NSString *_name; + NSArray *_contents; + NSImage *_icon; + QSObjectSource *_source; -@synthesize isScanning, contents = contents; + NSMutableArray *_children; + dispatch_queue_t scanQueue; + NSBundle *bundle; +} + +@property (getter=isScanning) BOOL scanning; +@property (retain) NSArray *contents; +@property (retain) NSMutableArray *children; + +- (NSString *)indexLocation; + +@end + +@implementation QSCatalogEntry + (BOOL)accessInstanceVariablesDirectly {return YES;} @@ -39,7 +54,7 @@ + (QSCatalogEntry *)entriesWithArray:(NSArray *)array { return nil; } // KVO + (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key { NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key]; - + if ([key isEqualToString:@"deepObjectCount"]) { NSSet *affectingKeys = [NSSet setWithObjects:@"contents", @"enabled",nil]; keyPaths = [keyPaths setByAddingObjectsFromSet:affectingKeys]; @@ -56,294 +71,340 @@ + (QSCatalogEntry *)entryWithDictionary:(NSDictionary *)dict { } - (NSString *)description { - return [NSString stringWithFormat:@"[%@] ", [self name]]; + return [NSString stringWithFormat:@"[%@] ", self.name]; +} + +- (instancetype)init { + self = [super init]; + if (!self) { + return nil; + } + + _name = nil; + _indexDate = nil; + _children = [NSMutableArray array]; + _contents = nil; + _info = [NSMutableDictionary dictionary]; + + return self; } - (QSCatalogEntry *)initWithDictionary:(NSDictionary *)dict { - if (self = [super init]) { - info = [dict mutableCopy]; - children = nil; contents = nil; indexDate = nil; - - NSArray *childDicts = [dict objectForKey:kItemChildren]; - if (childDicts) { - NSMutableArray *newChildren = [NSMutableArray array]; - for(NSDictionary * child in childDicts) { - [newChildren addObject:[QSCatalogEntry entryWithDictionary:child]]; - } - children = newChildren; - } - // create a serial dispatch queue to make scan processes serial for each catalog entry - scanQueue = dispatch_queue_create([[NSString stringWithFormat:@"QSCatalogEntry scanQueue: %@",[dict objectForKey:kItemID]] UTF8String], NULL); - dispatch_queue_set_specific(scanQueue, kQueueCatalogEntry, (__bridge void *)self, NULL); - } + self = [self init]; + if (!self) { + return nil; + } + + _info = [dict mutableCopy]; + NSDictionary *settings = _info[kItemSettings]; + if (settings) + _info[kItemSettings] = settings.mutableCopy; + + NSArray *childDicts = dict[kItemChildren]; + if (childDicts) { + NSMutableArray *newChildren = [NSMutableArray arrayWithCapacity:childDicts.count]; + for (NSDictionary *child in childDicts) { + [newChildren addObject:[QSCatalogEntry entryWithDictionary:child]]; + } + self.children = newChildren; + } + + // create a serial dispatch queue to make scan processes serial for each catalog entry + scanQueue = dispatch_queue_create([[NSString stringWithFormat:@"QSCatalogEntry scanQueue: %@",[dict objectForKey:kItemID]] UTF8String], NULL); + dispatch_queue_set_specific(scanQueue, kQueueCatalogEntry, (__bridge void *)self, NULL); + return self; } +#warning doesn't look used, and doesn't *actually* update enabled... - (void)enable { - id theSource = [self source]; - if ([theSource respondsToSelector:@selector(enableEntry:)]) - [theSource enableEntry:self]; + if ([self.source respondsToSelector:@selector(enableEntry:)]) { + [self.source enableEntry:self]; + } } - (void)dealloc { - id theSource = [self source]; - if ([theSource respondsToSelector:@selector(disableEntry:)]) - [theSource disableEntry:self]; + if ([self.source respondsToSelector:@selector(disableEntry:)]) { + [self.source disableEntry:self]; + } + dispatch_release(scanQueue); scanQueue = NULL; } - (NSDictionary *)dictionaryRepresentation { - if (children) - [info setObject:[children valueForKey:@"dictionaryRepresentation"] forKey:kItemChildren]; - return info; + NSMutableDictionary *dict = self.info.mutableCopy; + if (self.children) { + dict[kItemChildren] = [self.children valueForKey:@"dictionaryRepresentation"]; + } + return dict; } - (QSCatalogEntry *)childWithID:(NSString *)theID { - QSCatalogEntry *child; - for(child in children) { - if ([[child identifier] isEqualToString:theID]) + for (QSCatalogEntry *child in self.children) { + if ([child.identifier isEqualToString:theID]) { return child; + } } return nil; } - (QSCatalogEntry *)childWithPath:(NSString *)path { - if (![path length]) + if (path.length == 0) { return self; + } + QSCatalogEntry *object = self; - for(NSString *s in [path pathComponents]) { + for (NSString *s in path.pathComponents) { object = [object childWithID:s]; } return object; } - (BOOL)isSuppressed { -#ifdef DEBUG - return NO; -#endif - NSString *path = [info objectForKey:@"requiresPath"]; - if (path && ![[NSFileManager defaultManager] fileExistsAtPath:[path stringByResolvingWildcardsInPath]]) + NSString *path = self.info[@"requiresPath"]; + if (path && ![NSFileManager.defaultManager fileExistsAtPath:path.stringByResolvingWildcardsInPath]) { return YES; - if ([[info objectForKey:@"requiresSettingsPath"] boolValue]) { - path = [[info objectForKey:@"settings"] objectForKey:kItemPath]; - if (path && ![[NSFileManager defaultManager] fileExistsAtPath:[path stringByResolvingWildcardsInPath]]) + } + if ([self.info[@"requiresSettingsPath"] boolValue]) { + path = self.info[kItemSettings][kItemPath]; + if (path && ![NSFileManager.defaultManager fileExistsAtPath:path.stringByResolvingWildcardsInPath]) { return YES; + } } - NSString *requiredBundle = [info objectForKey:@"requiresBundle"]; - if (requiredBundle && ![[NSWorkspace sharedWorkspace] absolutePathForAppBundleWithIdentifier:requiredBundle]) + NSString *requiredBundle = self.info[@"requiresBundle"]; + if (requiredBundle && ![NSWorkspace.sharedWorkspace absolutePathForAppBundleWithIdentifier:requiredBundle]) { return YES; + } return NO; } - (NSDate *)lastScanDate { - if ([[self type] isEqualToString:@"Group"]) { - // It's a group entry. Loop through the child catalog entries to find the one with the latest scan date - NSDate *latestScan = nil; - for (QSCatalogEntry *child in [self children]) { - NSDate *childScanDate = [child lastScanDate]; - if (childScanDate && (childScanDate > latestScan || latestScan == nil)) { - latestScan = childScanDate; - } - } - return latestScan; - } - return [[[NSFileManager defaultManager] attributesOfItemAtPath:[self indexLocation] error:nil] objectForKey:NSFileModificationDate]; + /* tiennou: The one with the latest scan date ? Really ? */ + if ([[self type] isEqualToString:@"Group"]) { + // It's a group entry. Loop through the child catalog entries to find the one with the latest scan date + NSDate *latestScan = nil; + for (QSCatalogEntry *child in [self children]) { + NSDate *childScanDate = [child lastScanDate]; + if (childScanDate && (childScanDate > latestScan || latestScan == nil)) { + latestScan = childScanDate; + } + } + return latestScan; + } + return [[NSFileManager.defaultManager attributesOfItemAtPath:self.indexLocation error:NULL] objectForKey:NSFileModificationDate]; } -- (BOOL)deletable { - if ([self isPreset]) - return NO; - return ![[info objectForKey:@"permanent"] boolValue]; +- (BOOL)canBeDeleted { + if (self.isPreset) { + return NO; + } + + return ![self.info[@"permanent"] boolValue]; } - (BOOL)isEditable { - id source = [self source]; - return ([source respondsToSelector:@selector(usesGlobalSettings)] && [source performSelector:@selector(usesGlobalSettings)]) ? YES : ![self isPreset]; + if ([self.source respondsToSelector:@selector(usesGlobalSettings)] + && [self.source performSelector:@selector(usesGlobalSettings)]) { + return YES; + } + + return !self.isPreset; } - (NSString *)type { - id source = [self source]; - NSString *theID = NSStringFromClass([source class]); - NSString *title = [[NSBundle bundleForClass:[source class]] safeLocalizedStringForKey:theID value:theID table:@"QSObjectSource.name"]; - if ([title isEqualToString:theID]) + NSString *theID = NSStringFromClass([self.source class]); + NSString *title = [[NSBundle bundleForClass:[self.source class]] safeLocalizedStringForKey:theID value:theID table:@"QSObjectSource.name"]; + if ([title isEqualToString:theID]) { return [[NSBundle mainBundle] safeLocalizedStringForKey:theID value:theID table:@"QSObjectSource.name"]; - else + } else { return title; + } } - (BOOL)isCatalog { return self == [[QSLibrarian sharedInstance] catalog]; } -- (BOOL)isPreset { return [[self identifier] hasPrefix:@"QSPreset"]; } -- (BOOL)isSeparator { return [[self identifier] hasPrefix:@"QSSeparator"]; } -- (BOOL)isGroup { return [[info objectForKey:kItemSource] isEqualToString:@"QSGroupObjectSource"]; } -- (BOOL)isLeaf { return ![self isGroup]; } +- (BOOL)isPreset { return [self.identifier hasPrefix:@"QSPreset"]; } +- (BOOL)isSeparator { return [self.identifier hasPrefix:@"QSSeparator"]; } +- (BOOL)isGroup { return [self.info[kItemSource] isEqualToString:@"QSGroupObjectSource"]; } +- (BOOL)isLeaf { return !self.isGroup; } + - (NSInteger)state { - BOOL enabled = [self isEnabled]; + BOOL enabled = self.isEnabled; if (!enabled) return 0; - if ([[info objectForKey:kItemSource] isEqualToString:@"QSGroupObjectSource"]) { - for(QSCatalogEntry * child in [self deepChildrenWithGroups:NO leaves:YES disabled:YES]) { - if (![child isEnabled]) return -1*enabled; + if (self.isGroup) { + for (QSCatalogEntry *child in [self deepChildrenWithGroups:NO leaves:YES disabled:YES]) { + if (!child.isEnabled) { + return -1*enabled; + } } } return enabled; } -- (NSInteger)hasEnabledChildren { - if ([[info objectForKey:kItemSource] isEqualToString:@"QSGroupObjectSource"]) { +- (BOOL)hasEnabledChildren { + if (self.isGroup) { BOOL hasEnabledChildren = NO; - for (id loopItem in children) - hasEnabledChildren |= [loopItem isEnabled]; + for (QSCatalogEntry *child in self.children) + hasEnabledChildren |= child.isEnabled; return hasEnabledChildren; - } else - return YES; + } + + return YES; } - (BOOL)shouldIndex { - return [self isEnabled]; + return self.isEnabled; } - (BOOL)isEnabled { - if ([self isPreset]) { - NSNumber *value; - if (value = [[QSLibrarian sharedInstance] presetIsEnabled:self]) - return [value boolValue]; - else if (value = [info objectForKey:kItemEnabled]) - return [value boolValue]; - // ***warning * this is just a little silly... - return YES; - } else { - return [[info objectForKey:kItemEnabled] boolValue]; - } + @synchronized (self) { + /* Check our enabled state, defaulting to YES if not defined yet. */ + if (self.isPreset) { + NSNumber *value = [[QSLibrarian sharedInstance] presetIsEnabled:self]; + return (value != nil ? value.boolValue : YES); + } + + NSNumber *value = self.info[kItemEnabled]; + return (value != nil ? value.boolValue : YES); + } } - (void)setEnabled:(BOOL)enabled { - NSString *theID = [info objectForKey:kItemID]; - if ([theID hasPrefix:@"QSPreset"]) - [[QSLibrarian sharedInstance] setPreset:self isEnabled:enabled]; - else - [info setObject:[NSNumber numberWithBool:enabled] forKey:kItemEnabled]; - if (enabled && ![[self contents] count]) { - [self scanForced:YES]; + @synchronized (self) { + if (self.isPreset) { + [[QSLibrarian sharedInstance] setPreset:self isEnabled:enabled]; + return; + } + + self.info[kItemEnabled] = @(enabled); + if (enabled && self.contents.count == 0) { + [self scanForced:YES]; + } + + [QSLib writeCatalog:self]; } - [QSLib writeCatalog:self]; } - (void)setDeepEnabled:(BOOL)enabled { - [self setEnabled:enabled]; - if ([[info objectForKey:kItemSource] isEqualToString:@"QSGroupObjectSource"]) { + self.enabled = enabled; + if (self.isGroup) { NSArray *deepChildren = [self deepChildrenWithGroups:YES leaves:YES disabled:YES]; - for(QSCatalogEntry * child in deepChildren) - [child setEnabled:enabled]; + for (QSCatalogEntry *child in deepChildren) { + child.enabled = enabled; + } } } - (void)pruneInvalidChildren { - NSMutableArray *children2 = [children copy]; - for(QSCatalogEntry * child in children2) { - if ([child isSeparator]) break; //Stop when at end of presets - if (![[NSUserDefaults standardUserDefaults] boolForKey:@"Show All Catalog Entries"] && [child isSuppressed]) { - + /* Do a "manual" reverse enumeration because we'd be mutating-while-enumerating + * and we don't want our index to move around. */ + NSIndexSet *prunedChildren = [self.children indexesOfObjectsPassingTest:^BOOL(QSCatalogEntry *child, NSUInteger idx, BOOL *stop) { + if (!child.isPreset) { + /* Prune presets only */ + return NO; + } + + if (child.isSuppressed && ![NSUserDefaults.standardUserDefaults boolForKey:@"Show All Catalog Entries"]) { #ifdef DEBUG - if (DEBUG_CATALOG) NSLog(@"Suppressing Preset:%@", [child identifier]); + if (DEBUG_CATALOG) NSLog(@"Suppressing Preset:%@", child.identifier); #endif - - [children removeObject:child]; - } else if ([child isGroup]) { - [child pruneInvalidChildren]; - if (![(NSArray *)[child children] count]) // Remove empty groups - [children removeObject:child]; - } - } + return TRUE; + } else if (child.isGroup) { + [child pruneInvalidChildren]; + return child.children.count == 0; + } + return NO; + }]; + [self.children removeObjectsAtIndexes:prunedChildren]; } - (NSArray *)leafIDs { - if (![self isEnabled]) { - return nil; - } else if ([[info objectForKey:kItemSource] isEqualToString:@"QSGroupObjectSource"]) { + if (!self.isEnabled) { + return @[]; + } + + if (self.isGroup) { NSMutableArray *childObjects = [NSMutableArray arrayWithCapacity:1]; - for(QSCatalogEntry * child in children) { + for (QSCatalogEntry *child in self.children) { [childObjects addObjectsFromArray:[child leafIDs]]; } return childObjects; - } else { - return [NSArray arrayWithObject:[self identifier]]; - } + } + + return @[self.identifier]; } - (NSArray *)leafEntries { return [self deepChildrenWithGroups:NO leaves:YES disabled:NO]; } -- (NSMutableDictionary *)info { - return info; -} - - (NSArray *)deepChildrenWithGroups:(BOOL)groups leaves:(BOOL)leaves disabled:(BOOL)disabled { - if (!(disabled || [self isEnabled])) - return nil; - if ([[info objectForKey:kItemSource] isEqualToString:@"QSGroupObjectSource"]) { + if (!self.isEnabled && !disabled) { + return @[]; + } + + if (self.isGroup) { NSMutableArray *childObjects = [NSMutableArray arrayWithCapacity:1]; if (groups) [childObjects addObject:self]; - for(QSCatalogEntry * child in children) { + + for (QSCatalogEntry *child in self.children) { [childObjects addObjectsFromArray:[child deepChildrenWithGroups:groups leaves:leaves disabled:disabled]]; } return childObjects; - } else if (leaves) { - return [NSArray arrayWithObject:self]; } - return nil; + + if (!leaves) { + return @[]; + } + + return @[self]; } - (NSString *)identifier { - NSString *ID = [info objectForKey:kItemID]; - if (!ID && [info isKindOfClass:[NSMutableDictionary class]]) { - [(NSMutableDictionary *)info setObject:[NSString uniqueString] forKey:kItemID]; - return [info objectForKey:kItemID]; - } else - return ID; + @synchronized (self) { + NSString *ID = self.info[kItemID]; + if (!ID) { + ID = [NSString uniqueString]; + self.info[kItemID] = ID; + } + return ID; + } } - (NSIndexPath *)catalogIndexPath { - NSArray *anc = [self ancestors]; + NSArray *anc = self.ancestors; NSUInteger i; NSUInteger index; NSIndexPath *p = nil; - for (i = 0; i < ([anc count] - 1); i++) { - index = [[[anc objectAtIndex:i] children] indexOfObject:[anc objectAtIndex:i+1]]; + for (i = 0; i < (anc.count - 1); i++) { + index = [[anc[i] children] indexOfObject:anc[i + 1]]; p = (p) ? [p indexPathByAddingIndex:index] : [NSIndexPath indexPathWithIndex:index]; } return p; } - (NSIndexPath *)catalogSetIndexPath { - NSArray *anc = [self ancestors]; - NSUInteger i; - NSUInteger index; - NSIndexPath *p = nil; - for (i = 1; i < ([anc count] - 1); i++) { - index = [[[anc objectAtIndex:i] children] indexOfObject:[anc objectAtIndex:i+1]]; - p = (p) ? [p indexPathByAddingIndex:index] : [NSIndexPath indexPathWithIndex:index]; - } - return p; + return self.catalogIndexPath; } - (NSArray *)ancestors { - id catalog = [[QSLibrarian sharedInstance] catalog]; + QSCatalogEntry *catalog = [QSLibrarian.sharedInstance catalog]; NSArray *groups = [catalog deepChildrenWithGroups:YES leaves:NO disabled:YES]; NSMutableArray *entryChain = [NSMutableArray arrayWithCapacity:0]; - id thisItem = self; + QSCatalogEntry *thisItem = self; + QSCatalogEntry *theGroup = nil; NSUInteger i; + [entryChain addObject:self]; - id theGroup = nil; - while(thisItem != catalog) { - for (i = 0; i < [groups count]; i++) { - theGroup = [groups objectAtIndex:i]; - if ([[theGroup children] containsObject:thisItem]) { + while (thisItem != catalog) { + for (i = 0; i < groups.count; i++) { + theGroup = groups[i]; + if ([theGroup.children containsObject:thisItem]) { [entryChain insertObject:theGroup atIndex:0]; thisItem = theGroup; break; - } else if (i == [groups count] - 1) { + } else if (i == groups.count - 1) { NSLog(@"couldn't find parent of %@", thisItem); return nil; } @@ -353,47 +414,75 @@ - (NSArray *)ancestors { } - (NSComparisonResult) compare:(QSCatalogEntry *)other { - if ([other name] != nil) { - return [[self name] compare:[other name]]; + if (other.name != nil) { + return [self.name compare:other.name]; } - // othername is nil, so make the receiver higher in the list + // other.name is nil, so make the receiver higher in the list return NSOrderedAscending; } - (NSString *)name { - NSString *ID = [self identifier]; - if ([ID isEqualToString:@"QSSeparator"]) - return @""; - if (!name) - name = [info objectForKey:kItemName]; - if (!name) { - name = [bundle?bundle:[NSBundle mainBundle] safeLocalizedStringForKey:ID value:ID table:@"QSCatalogPreset.name"]; - if (name) [self setValue:name forKey:@"name"]; - } - return name; + @synchronized (self) { + if (self.isSeparator) { + return @""; + } +#warning this is tampering with localization + if (!_name) { + _name = self.info[kItemName]; + } + if (!_name) { + NSString *ID = self.identifier; + _name = [bundle ? bundle : [NSBundle mainBundle] safeLocalizedStringForKey:ID value:ID table:@"QSCatalogPreset.name"]; + } + return [_name copy]; + } } - (void)setName:(NSString *)newName { - [info setObject:newName forKey:kItemName]; - name = newName; + @synchronized (self) { + _name = [newName copy]; + self.info[kItemName] = _name; + } } - (id)imageAndText { return self; } -- (void)setImageAndText:(id)object { [self setName:object]; } +- (void)setImageAndText:(id)object { self.name = object; } -- (NSImage *)image { return [self icon]; } +- (NSImage *)image { return self.icon; } -- (NSString *)text { return [self name]; } +- (NSString *)text { return self.name; } - (NSImage *)icon { - NSImage *image; - if(!(image = [QSResourceManager imageNamed:[info objectForKey:kItemIcon]])){ - if(!(image = [[QSReg sourceNamed:[info objectForKey:kItemSource]] iconForEntry:info])){ - image = [QSResourceManager imageNamed:@"Catalog"]; - } - } - return image; + @synchronized (self) { + _icon = [QSResourceManager imageNamed:self.info[kItemIcon]]; + if (!_icon) + _icon = [self.source iconForEntry:self.info]; + + if (!_icon) + _icon = [QSResourceManager imageNamed:@"Catalog"]; + +#warning tiennou: must check that this actually works + NSData *iconData = self.info[@"iconData"]; + if (!_icon && iconData) { + _icon = [[NSImage alloc] initWithData:iconData]; + } + + return _icon; + } +} + +- (void)setIcon:(NSImage *)icon { + @synchronized (self) { + if (icon) { + if (_icon.name) { + self.info[kItemIcon] = icon.name; + } else { + self.info[@"iconData"] = [icon TIFFRepresentationUsingCompression:NSTIFFCompressionLZW factor:0]; + } + } + _icon = icon; + } } - (NSString *)getCount { @@ -405,38 +494,42 @@ - (NSString *)getCount { } - (NSUInteger)count { - return [self deepObjectCount]; + return self.deepObjectCount; } - (NSUInteger)deepObjectCount { NSArray *leaves = [self deepChildrenWithGroups:NO leaves:YES disabled:NO]; NSUInteger i, count = 0; - for (i = 0; i < [leaves count]; i++) - count += [(NSArray *)[[leaves objectAtIndex:i] enabledContents] count]; + + for (i = 0; i < leaves.count; i++) { + QSCatalogEntry *leaf = leaves[i]; + count += leaf.enabledContents.count; + } + return count; } - (NSString *)indexLocation { - return [[[pIndexLocation stringByStandardizingPath] stringByAppendingPathComponent:[self identifier]] stringByAppendingPathExtension:@"qsindex"]; + return [[[pIndexLocation stringByStandardizingPath] stringByAppendingPathComponent:self.identifier] stringByAppendingPathExtension:@"qsindex"]; } - (BOOL)loadIndex { - if ([self isEnabled]) { - NSString *path = [self indexLocation]; + if (self.isEnabled) { NSMutableArray *dictionaryArray = nil; @try { - dictionaryArray = [QSObject objectsWithDictionaryArray:[NSArray arrayWithContentsOfFile:path]]; + dictionaryArray = [QSObject objectsWithDictionaryArray:[NSMutableArray arrayWithContentsOfFile:self.indexLocation]]; } @catch (NSException *e) { - NSLog(@"Error loading index of %@: %@", [self name] , e); + NSLog(@"Error loading index of %@: %@", self.name , e); } - - if (!dictionaryArray) + + if (!dictionaryArray) { return NO; + } [self setContents:dictionaryArray]; - [[NSNotificationCenter defaultCenter] postNotificationName:QSCatalogEntryIndexed object:self]; - [[QSLibrarian sharedInstance] recalculateTypeArraysForItem:self]; + [NSNotificationCenter.defaultCenter postNotificationName:QSCatalogEntryIndexedNotification object:self]; + [QSLibrarian.sharedInstance recalculateTypeArraysForItem:self]; } return YES; } @@ -446,17 +539,15 @@ - (void)saveIndex { #ifdef DEBUG if (DEBUG_CATALOG) NSLog(@"saving index for %@", self); #endif - - [self setIndexDate:[NSDate date]]; - NSString *key = [self identifier]; - NSString *path = [pIndexLocation stringByStandardizingPath]; + + self.indexDate = [NSDate date]; @try { - NSArray *writeArray = [contents arrayByPerformingSelector:@selector(dictionaryRepresentation)]; - [writeArray writeToFile:[[path stringByAppendingPathComponent:key] stringByAppendingPathExtension:@"qsindex"] atomically:YES]; + NSArray *writeArray = [self.contents arrayByPerformingSelector:@selector(dictionaryRepresentation)]; + [writeArray writeToFile:self.indexLocation atomically:YES]; } @catch (NSException *exception) { - NSLog(@"Exception whilst saving catalog entry %@\ncontents: %@\nException: %@",[self name],contents,exception); + NSLog(@"Exception whilst saving catalog entry %@\ncontents: %@\nException: %@", self.name, self.contents, exception); } }); } @@ -472,48 +563,53 @@ - (void)invalidateIndex:(NSNotification *)notif { - (BOOL)indexIsValid { __block BOOL isValid = YES; - QSGCDQueueSync(scanQueue,^{ - NSFileManager *manager = [NSFileManager defaultManager]; - NSString *indexPath = [[[pIndexLocation stringByStandardizingPath] stringByAppendingPathComponent:[self identifier]]stringByAppendingPathExtension:@"qsindex"]; - if (![manager fileExistsAtPath:indexPath isDirectory:nil]) { + QSGCDQueueSync(scanQueue, ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:QSCatalogEntryIsIndexingNotification object:self]; + NSFileManager *manager = NSFileManager.defaultManager; + NSString *indexLocation = self.indexLocation; + if (![manager fileExistsAtPath:indexLocation isDirectory:nil]) { isValid = NO; } if (isValid) { - if (!indexDate) - [self setIndexDate:[[manager attributesOfItemAtPath:indexPath error:NULL] fileModificationDate]]; - NSNumber *modInterval = [info objectForKey:kItemModificationDate]; + if (!self.indexDate) + self.indexDate = [[manager attributesOfItemAtPath:indexLocation error:NULL] fileModificationDate]; + NSNumber *modInterval = self.info[kItemModificationDate]; if (modInterval) { NSDate *specDate = [NSDate dateWithTimeIntervalSinceReferenceDate:[modInterval doubleValue]]; - if ([specDate compare:indexDate] == NSOrderedDescending) { + if ([specDate compare:self.indexDate] == NSOrderedDescending) { isValid = NO; //Catalog Specification is more recent than index } } } if (isValid) { - isValid = [[self source] indexIsValidFromDate:indexDate forEntry:info]; + isValid = [self.source indexIsValidFromDate:self.indexDate forEntry:self.info]; } }); return isValid; } -- (id)source { - id source = [QSReg sourceNamed:[info objectForKey:kItemSource]]; +- (QSObjectSource *)source { + @synchronized (self) { + if (!_source) { + _source = [QSReg sourceNamed:self.info[kItemSource]]; #ifdef DEBUG - if (!source && VERBOSE) - NSLog(@"Source not found: %@ for Entry: %@", [info objectForKey:kItemSource] , [self identifier]); + if (!_source && VERBOSE) + NSLog(@"Source not found: %@ for Entry: %@", self.info[kItemSource], self.identifier); #endif - return source; + } + return _source; + + } } - (NSArray *)scannedObjects { NSArray *itemContents = nil; @autoreleasepool { @try { - QSObjectSource *source = [self source]; - itemContents = [source objectsForEntry:info]; + itemContents = [self.source objectsForEntry:self.info]; } @catch (NSException *exception) { - NSLog(@"An error ocurred while scanning \"%@\": %@", [self name], exception); + NSLog(@"An error ocurred while scanning \"%@\": %@", self.name, exception); [exception printStackTrace]; } } @@ -521,106 +617,101 @@ - (NSArray *)scannedObjects { } - (BOOL)canBeIndexed { - QSObjectSource *source = [self source]; - return ![source respondsToSelector:@selector(entryCanBeIndexed:)] || [source entryCanBeIndexed:[self info]]; + if (![self.source respondsToSelector:@selector(entryCanBeIndexed:)]) + return YES; + + return [self.source entryCanBeIndexed:self.info]; } - (NSArray *)scanAndCache { - if (isScanning) { + if (self.isScanning) { #ifdef DEBUG - if (VERBOSE) NSLog(@"%@ is already being scanned", [self name]); + if (VERBOSE) NSLog(@"%@ is already being scanned", self.name); #endif return nil; } else { __block NSArray *itemContents = nil; // Use a serial queue to do the grunt of the scan work. Ensures that no more than one thread can scan at any one time. QSGCDQueueSync(scanQueue, ^{ - [self setIsScanning:YES]; + self.scanning = YES; [self willChangeValueForKey:@"self"]; - NSString *ID = [self identifier]; - NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; - [nc postNotificationName:QSCatalogEntryIsIndexing object:self]; + NSString *ID = self.identifier; itemContents = [self scannedObjects]; if (itemContents && ID) { - [self setContents:itemContents]; - QSObjectSource *source = [self source]; - if (![source respondsToSelector:@selector(entryCanBeIndexed:)] || [source entryCanBeIndexed:[self info]]) { + self.contents = itemContents; + if (self.canBeIndexed) { [self saveIndex]; } } else if (ID) { - [self setContents:nil]; + self.contents = nil; } [self didChangeValueForKey:@"self"]; - [nc postNotificationName:QSCatalogEntryIndexed object:self]; - [self setIsScanning:NO]; + self.scanning = NO; + [[NSNotificationCenter defaultCenter] postNotificationName:QSCatalogEntryIndexedNotification object:self]; }); return itemContents; } } - (void)scanForced:(BOOL)force { - if ([self isSeparator] || ![self isEnabled]) { + if (self.isSeparator || !self.isEnabled) { return; } - if ([[info objectForKey:kItemSource] isEqualToString:@"QSGroupObjectSource"]) { + + if (self.isGroup) { @autoreleasepool { - for(QSCatalogEntry * child in children) { + for(QSCatalogEntry *child in self.children) { [child scanForced:force]; } } return; } - [[[QSLibrarian sharedInstance] scanTask] setStatus:[NSString stringWithFormat:NSLocalizedString(@"Checking: %@", @"Catalog task checking (%@ => source name)"), [self name]]]; BOOL valid = [self indexIsValid]; if (valid && !force) { #ifdef DEBUG - if (DEBUG_CATALOG) NSLog(@"\tIndex is valid for source: %@", name); + if (DEBUG_CATALOG) NSLog(@"\tIndex is valid for source: %@", self.name); #endif return; } - + #ifdef DEBUG if (DEBUG_CATALOG) - NSLog(@"Scanning source: %@%@", [self name] , (force?@" (forced) ":@"")); + NSLog(@"Scanning source: %@%@", self.name , (force?@" (forced) ":@"")); #endif - - [[[QSLibrarian sharedInstance] scanTask] setStatus:[NSString stringWithFormat:NSLocalizedString(@"Scanning: %@", @"Catalog task scanning (%@ => source name)"), [self name]]]; + [self scanAndCache]; - return; } -- (NSMutableArray *)children { return children; } -- (NSMutableArray *)getChildren { - if (!children) - children = [[NSMutableArray alloc] init]; - return children; -} -- (void)setChildren:(NSArray *)newChildren { - if(newChildren != children){ - children = [newChildren mutableCopy]; - } +- (NSArray *)contents { + @synchronized (self) { + return [self contentsScanIfNeeded:NO]; + } } -- (NSArray *)contents { return [self contentsScanIfNeeded:NO]; } +- (void)setContents:(NSArray *)newContents { + @synchronized (self) { + _contents = [newContents copy]; + } +} - (NSArray *)contentsScanIfNeeded:(BOOL)canScan { - if (![self isEnabled]) { - return nil; - } - if ([[info objectForKey:kItemSource] isEqualToString:@"QSGroupObjectSource"]) { - NSMutableSet *childObjects = [NSMutableSet setWithCapacity:1]; + @synchronized (self) { + if (!self.isEnabled) return nil; - for(QSCatalogEntry * child in children) { - [childObjects addObjectsFromArray:[child contentsScanIfNeeded:(BOOL)canScan]]; - } - return [childObjects allObjects]; + if (self.isGroup) { + NSMutableSet *childObjects = [NSMutableSet setWithCapacity:1]; - } else { + for (QSCatalogEntry *child in self.children) { + [childObjects addObjectsFromArray:[child contentsScanIfNeeded:canScan]]; + } + return [childObjects allObjects]; + } - if (!contents && canScan) - return [self scanAndCache]; - return contents; - } + if (!_contents && canScan) + return [self scanAndCache]; + + return _contents; + } } - (NSArray *)enabledContents @@ -632,24 +723,27 @@ - (NSArray *)enabledContents } - (QSCatalogEntry *)uniqueCopy { - NSMutableDictionary *newDictionary = [info mutableCopy]; - if ([self isPreset]) { - [newDictionary setObject:[NSNumber numberWithBool:[self isEnabled]] forKey:kItemEnabled]; - [newDictionary setObject:[self name] forKey:kItemName]; + NSMutableDictionary *newDictionary = [self.info mutableCopy]; + if (self.isPreset) { + newDictionary[kItemEnabled] = @(self.isEnabled); +#warning this is tampering with localization + newDictionary[kItemName] = self.name; } - [newDictionary setObject:[NSString uniqueString] forKey:kItemID]; + newDictionary[kItemID] = [NSString uniqueString]; QSCatalogEntry *newEntry = [[QSCatalogEntry alloc] initWithDictionary:newDictionary]; - if ([self children]) - [newEntry setChildren:[[self children] valueForKey:@"uniqueCopy"]]; + if (self.children) + newEntry.children = [self.children valueForKey:@"uniqueCopy"]; return newEntry; } -- (NSDate *)indexDate { return indexDate; } -- (void)setIndexDate:(NSDate *)anIndexDate { - // NSLog(@"date %@ ->%@", indexDate, anIndexDate); - indexDate = anIndexDate; +- (NSMutableDictionary *)sourceSettings { + return self.info[kItemSettings]; } + +// Backward-compatibility +- (BOOL)deletable QS_DEPRECATED { return self.canBeDeleted; } + @end diff --git a/Quicksilver/Code-QuickStepCore/QSCatalogEntry_Private.h b/Quicksilver/Code-QuickStepCore/QSCatalogEntry_Private.h new file mode 100644 index 000000000..fcc4e38a3 --- /dev/null +++ b/Quicksilver/Code-QuickStepCore/QSCatalogEntry_Private.h @@ -0,0 +1,35 @@ +// +// QSCatalogEntry_Private.h +// Quicksilver +// +// Created by Etienne on 15/09/13. +// +// + +#import + +@interface QSCatalogEntry () +/** + * The receiver's private info dictionary + * + * This is considered private API (some other parts of QS access it directly). + * + * It contains the following keys: + * + * - kItemChildren - an array of QSCatalogEntry in dictionary format. + * - @"requiresPath" - a path to a required "file-system object" + * - @"requiresSettingsPath" - a BOOL indicating if the kItemPath in kItemSettings is required + * - @"requiresBundle" - a required bundle identifier + * - @"permanent" - a BOOL indicating if the receiver can be deleted + * - kItemSource - the QSObjectSource identifier of the receiver + * - kItemEnabled - a BOOL representing the enabled state of the receiver + * - kItemID - the identifier for the receiver (will be assigned an UUID if missing) + * - kItemName - the name of the receiver (deprecated because it prevents localization) + * - kItemIcon - the name of the icon to use + * - @"iconData" - data for the icon to use + * - kItemModificationDate - The last modification date of the receiver, as a time interval + * - kItemSettings - a dictionary containing source-specific keys + * - kItemPath - a path to a required "file-system object" + */ +@property (readonly, retain) NSMutableDictionary *info; +@end diff --git a/Quicksilver/Code-QuickStepCore/QSCore.h b/Quicksilver/Code-QuickStepCore/QSCore.h index 0972ff21a..b02292ced 100644 --- a/Quicksilver/Code-QuickStepCore/QSCore.h +++ b/Quicksilver/Code-QuickStepCore/QSCore.h @@ -30,7 +30,6 @@ #import "QSKeys.h" #import "QSLibrarian.h" #import "QSLocalization.h" -#import "QSMacros.h" #import "QSMiscFunctions.h" #import "QSMnemonics.h" #import "QSNotifications.h" diff --git a/Quicksilver/Code-QuickStepCore/QSHistoryController.m b/Quicksilver/Code-QuickStepCore/QSHistoryController.m index a5af36045..f363ee4d8 100644 --- a/Quicksilver/Code-QuickStepCore/QSHistoryController.m +++ b/Quicksilver/Code-QuickStepCore/QSHistoryController.m @@ -61,7 +61,7 @@ - (void)addCommand:(QSCommand *)command { [commandHistory removeLastObject]; } } - [[NSNotificationCenter defaultCenter] postNotificationName:QSCatalogEntryInvalidated object:@"QSPresetCommandHistory"]; + [[NSNotificationCenter defaultCenter] postNotificationName:QSCatalogEntryInvalidatedNotification object:@"QSPresetCommandHistory"]; } - (void)addObject:(id)object { @@ -72,7 +72,7 @@ - (void)addObject:(id)object { [objectHistory insertObject:object atIndex:0]; while ([objectHistory count] > MAXHIST) [objectHistory removeLastObject]; - [[NSNotificationCenter defaultCenter] postNotificationName:QSCatalogEntryInvalidated object:@"QSPresetObjectHistory"]; + [[NSNotificationCenter defaultCenter] postNotificationName:QSCatalogEntryInvalidatedNotification object:@"QSPresetObjectHistory"]; } @end diff --git a/Quicksilver/Code-QuickStepCore/QSLibrarian.m b/Quicksilver/Code-QuickStepCore/QSLibrarian.m index 982659b09..724fffd7d 100644 --- a/Quicksilver/Code-QuickStepCore/QSLibrarian.m +++ b/Quicksilver/Code-QuickStepCore/QSLibrarian.m @@ -11,6 +11,9 @@ #import "QSTask.h" #import "QSTaskController.h" +#import "QSCatalogEntry.h" +#import "QSCatalogEntry_Private.h" + //#define compGT(a, b) (a < b) CGFloat QSMinScore = 0.333333; @@ -95,12 +98,15 @@ - (id)init { #endif // Register for Notifications - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(writeCatalog:) name:QSCatalogEntryChanged object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(writeCatalog:) name:QSCatalogEntryChangedNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(writeCatalog:) name:QSCatalogStructureChanged object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadIDDictionary:) name:QSCatalogStructureChanged object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadSets:) name:QSCatalogEntryIndexed object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadSets:) name:QSCatalogEntryIndexedNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadSource:) name:QSCatalogSourceInvalidated object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadEntry:) name:QSCatalogEntryInvalidated object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadEntry:) name:QSCatalogEntryInvalidatedNotification object:nil]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateScanTask:) name:QSCatalogEntryIsIndexingNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateScanTask:) name:QSCatalogEntryIndexedNotification object:nil]; #if 0 //Create proxy Images [(NSImage *)[[NSImage alloc] initWithSize:NSZeroSize] setName:@"QSDirectProxyImage"]; @@ -112,6 +118,7 @@ - (id)init { return self; } + - (void)enableEntries { [[catalog leafEntries] makeObjectsPerformSelector:@selector(enable)]; } @@ -138,22 +145,17 @@ - (NSNumber *)presetIsEnabled:(QSCatalogEntry *)preset { - (void)registerPresets:(NSArray *)newPresets inBundle:(NSBundle *)bundle scan:(BOOL)scan { - - //NSLog(@"prestes %@", newPresets); - NSMutableDictionary *dict; - QSCatalogEntry *entry, *parent; - NSString *path; - NSMutableArray *children; - for(dict in newPresets) { - parent = nil; - entry = [QSCatalogEntry entryWithDictionary:dict]; - path = [dict objectForKey:@"catalogPath"]; - [dict setObject:bundle forKey:@"bundle"]; + for (NSMutableDictionary *dict in newPresets) { + // Set `bundle` before the entry gets created + dict[@"bundle"] = bundle; + QSCatalogEntry *entry = [QSCatalogEntry entryWithDictionary:dict]; + NSString *path = [dict objectForKey:@"catalogPath"]; NSArray *grandchildren = [entry deepChildrenWithGroups:YES leaves:YES disabled:YES]; [grandchildren setValue:bundle forKey:@"bundle"]; + QSCatalogEntry *parent = nil; if ([path isEqualToString:@"/"]) parent = catalog; else if (path) @@ -164,9 +166,10 @@ - (void)registerPresets:(NSArray *)newPresets inBundle:(NSBundle *)bundle scan:( parent = [catalog childWithPath:@"QSPresetModules"]; // NSLog(@"register failed %@ %@ %@", parent, path, [entry identifier]); } - children = [parent getChildren]; - [children addObject:entry]; - [children sortUsingFunction:presetSort context:(__bridge void *)(self)]; +// children = [parent getChildren]; + [parent.children addObject:entry]; +#warning oh yeah, while we're at it, sort on each loop ! + [parent.children sortUsingFunction:presetSort context:(__bridge void *)(self)]; if (scan) [entry scanForced:YES]; } //[catalogChildren replaceObjectsInRange:NSMakeRange(0, 0) withObjectsFromArray:newPresets]; @@ -175,7 +178,6 @@ - (void)registerPresets:(NSArray *)newPresets inBundle:(NSBundle *)bundle scan:( - (void)initCatalog {} - (void)loadCatalogInfo { - NSMutableArray *catalogChildren = [catalog getChildren]; // NSLog(@"load Catalog %p %@", catalog, [catalog getChildren]); //[catalogChildren addObject:[QSCatalogEntry entryWithDictionary:[NSDictionary dictionaryWithObjectsAndKeys:@"QSSeparator", kItemID, nil]]]; @@ -188,7 +190,7 @@ - (void)loadCatalogInfo { [NSNumber numberWithBool:YES] , @"permanent", [NSNumber numberWithBool:YES] , kItemEnabled, nil]]; - [catalogChildren addObject:customEntry]; + [catalog.children addObject:customEntry]; NSMutableDictionary *catalogStorage = [NSMutableDictionary dictionaryWithContentsOfFile:[pCatalogSettings stringByStandardizingPath]]; @@ -279,7 +281,7 @@ - (void)reloadEntrySources:(NSNotification *)notif { [entriesBySource removeAllObjects]; for (QSCatalogEntry *thisEntry in entries) { - NSString *source = [[thisEntry info] objectForKey:kItemSource]; + NSString *source = [thisEntry.info objectForKey:kItemSource]; NSMutableArray *sourceArray = [entriesBySource objectForKey:source]; if (!sourceArray) { @@ -295,7 +297,7 @@ - (void)reloadEntry:(NSNotification *)notif { QSCatalogEntry *entry = [self entryForID:[notif object]]; if (entry) { - [entry scanForced:NO]; + [entry scanForced:YES]; } } @@ -327,6 +329,18 @@ - (void)reloadSets:(NSNotification *)notif { } } +- (void)updateScanTask:(NSNotification *)notif { + QSCatalogEntry *entry = [notif object]; + if (!entry) { + return; + } + if ([notif.name isEqualToString:QSCatalogEntryIsIndexingNotification]) { + [[self scanTask] setStatus:[NSString stringWithFormat:NSLocalizedString(@"Checking: %@", @"Catalog task checking (%@ => source name)"), entry.name]]; + } else if ([notif.name isEqualToString:QSCatalogEntryIndexedNotification]) { + [[self scanTask] setStatus:[NSString stringWithFormat:NSLocalizedString(@"Scanning: %@", @"Catalog task scanning (%@ => source name)"), entry.name]]; + } +} + - (QSCatalogEntry *)entryForID:(NSString *)theID { QSCatalogEntry *entry = [entriesByID objectForKey:theID]; //if (!entry) @@ -336,7 +350,7 @@ - (QSCatalogEntry *)entryForID:(NSString *)theID { - (QSCatalogEntry *)firstEntryContainingObject:(QSObject *)object { NSArray *entries = [catalog deepChildrenWithGroups:NO leaves:YES disabled:NO]; NSIndexSet *matchedIndexes = [entries indexesOfObjectsWithOptions:NSEnumerationConcurrent passingTest:^BOOL(QSCatalogEntry *entry, NSUInteger idx, BOOL *stop) { - return [[entry _contents] containsObject:object]; + return [entry.contents containsObject:object]; }]; if ([matchedIndexes count]) { NSArray *matchedCatalogEntries = [entries objectsAtIndexes:matchedIndexes]; @@ -402,8 +416,9 @@ - (BOOL)loadCatalogArrays { NSLog(@"Indexes loaded (%fms) ", (-[date timeIntervalSinceNow] *1000)); #endif - [[NSNotificationCenter defaultCenter] postNotificationName:QSCatalogEntryIndexed object:nil]; - if (invalidIndexes) [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(scanInvalidIndexes) name:NSApplicationDidFinishLaunchingNotification object:nil]; + [[NSNotificationCenter defaultCenter] postNotificationName:QSCatalogEntryIndexedNotification object:catalog]; + if (invalidIndexes) + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(scanInvalidIndexes) name:NSApplicationDidFinishLaunchingNotification object:nil]; return indexesValid; } @@ -412,8 +427,7 @@ - (void)scanCatalogWithDelay:(id)sender { } - (BOOL)scanInvalidIndexes { - for(QSCatalogEntry * entry in invalidIndexes) { - + for(QSCatalogEntry *entry in invalidIndexes) { NSLog(@"Forcing %@ to scan", entry); [entry scanForced:NO]; } @@ -507,10 +521,8 @@ - (NSDictionary *)typeArraysFromArray:(NSArray *)array { - (void)loadMissingIndexes { NSArray *entries = [catalog leafEntries]; - id entry; - for (entry in entries) { - if (![entry canBeIndexed] || ![entry _contents]) { - //NSLog(@"Missing: %@", [entry name]); + for (QSCatalogEntry *entry in entries) { + if (!entry.canBeIndexed || !entry.contents) { [entry scanAndCache]; } else { // NSLog(@"monster %d", [[catalogArrays objectForKey:[entry objectForKey:kItemID]]count]); diff --git a/Quicksilver/Code-QuickStepCore/QSNotifications.h b/Quicksilver/Code-QuickStepCore/QSNotifications.h index 7936ef42f..dfd840ecb 100644 --- a/Quicksilver/Code-QuickStepCore/QSNotifications.h +++ b/Quicksilver/Code-QuickStepCore/QSNotifications.h @@ -7,10 +7,6 @@ #define QSReleaseCaches @"QSReleaseCaches" #define QSCatalogStructureChanged @"QSCatalogStructureChanged" #define QSCatalogIndexingCompleted @"QSCatalogIndexingCompleted" -#define QSCatalogEntryChanged @"QSCatalogEntryChanged" -#define QSCatalogEntryIsIndexing @"QSCatalogEntryIsIndexing" -#define QSCatalogEntryIndexed @"QSCatalogEntryIndexed" -#define QSCatalogEntryInvalidated @"QSCatalogEntryInvalidated" #define QSCatalogSourceInvalidated @"QSCatalogSourceInvalidated" #define QSDebugLogRequest @"QSDebugLogRequest" diff --git a/Quicksilver/Code-QuickStepCore/QSObjectSource.h b/Quicksilver/Code-QuickStepCore/QSObjectSource.h index 5a31aa3f2..2673cdd31 100644 --- a/Quicksilver/Code-QuickStepCore/QSObjectSource.h +++ b/Quicksilver/Code-QuickStepCore/QSObjectSource.h @@ -13,6 +13,10 @@ - (void)setSettingsView:(NSView *)newSettingsView; - (BOOL)isVisibleSource; - (BOOL)entryCanBeIndexed:(NSDictionary *)theEntry; + +- (void)enableEntry:(QSCatalogEntry *)entry; +- (void)disableEntry:(QSCatalogEntry *)entry; + - (BOOL)usesGlobalSettings; @end diff --git a/Quicksilver/Code-QuickStepCore/QSObjectSource.m b/Quicksilver/Code-QuickStepCore/QSObjectSource.m index 853065f6e..73b473d07 100644 --- a/Quicksilver/Code-QuickStepCore/QSObjectSource.m +++ b/Quicksilver/Code-QuickStepCore/QSObjectSource.m @@ -7,6 +7,7 @@ #import "QSResourceManager.h" #import "QSNotifications.h" #import "QSCatalogEntry.h" +#import "QSCatalogEntry_Private.h" @implementation QSObjectSource diff --git a/Quicksilver/Code-QuickStepCore/QSTask.m b/Quicksilver/Code-QuickStepCore/QSTask.m index dbcb43193..e9ae70971 100644 --- a/Quicksilver/Code-QuickStepCore/QSTask.m +++ b/Quicksilver/Code-QuickStepCore/QSTask.m @@ -75,9 +75,10 @@ - (id)init { } - (id)initWithIdentifier:(NSString *)newIdentifier { self = [super initWithNibName:@"QSTaskEntry" bundle:[NSBundle mainBundle]]; - if (self != nil) { - [self setIdentifier:newIdentifier]; - } + if (self == nil) return nil; + + [self setIdentifier:newIdentifier]; + return self; } diff --git a/Quicksilver/Code-QuickStepCore/QSTriggerCenter.m b/Quicksilver/Code-QuickStepCore/QSTriggerCenter.m index 90bceff40..d1b0cccde 100644 --- a/Quicksilver/Code-QuickStepCore/QSTriggerCenter.m +++ b/Quicksilver/Code-QuickStepCore/QSTriggerCenter.m @@ -254,24 +254,31 @@ - (NSDictionary *)triggerManagers { @implementation QSTriggerCenter (QSPlugInInfo) - (BOOL)handleInfo:(id)info ofType:(NSString *)type fromBundle:(NSBundle *)bundle { - id matchEntry = nil; - for(__strong NSDictionary * value in info) { - NSString *iden = [value objectForKey:kItemID]; - //NSLog(@"info %@ %@", iden, value); - if (matchEntry = [triggersDict objectForKey:iden]) { - [[matchEntry info] addEntriesFromDictionary:value]; + for (NSDictionary *triggerDict in info) { + NSString *iden = triggerDict[kItemID]; + QSTrigger *matchEntry = self.triggersDict[iden]; + if (matchEntry) { + /* We found that trigger. + * Update the trigger's info dictionary with the new values + * and remove its defaults. + */ + [[matchEntry info] addEntriesFromDictionary:triggerDict]; [[matchEntry info] removeObjectForKey:@"defaults"]; } else if (iden) { - NSMutableDictionary *defaults = [[value objectForKey:@"defaults"] mutableCopy]; + /* No trigger known with that ID. + * Make ourselves a copy, take the values under @"default" specified + * in triggerDict, remove those values from the final dict, and add + * them back at the root of the new trigger dict. + */ +#warning should the @"defaults" key be removed like the above did ? + NSMutableDictionary *newTriggerDict = [triggerDict mutableCopy]; + NSMutableDictionary *defaults = newTriggerDict[@"defaults"]; if (defaults) { - [defaults removeObjectsForKeys:[value allKeys]]; - value = [value mutableCopy]; - [(NSMutableDictionary *)value addEntriesFromDictionary:defaults]; + [defaults removeObjectsForKeys:[newTriggerDict allKeys]]; + [newTriggerDict addEntriesFromDictionary:defaults]; } - //NSLog(@"create %@, %@", value, [QSTrigger triggerWithInfo:value]); - [triggersDict setObject:[QSTrigger triggerWithDictionary:value] forKey:iden]; + [triggersDict setObject:[QSTrigger triggerWithDictionary:newTriggerDict] forKey:iden]; } - //NSLog(@"info %@ %@ %@", info, matchEntry, triggersDict); } return YES; } diff --git a/Quicksilver/Code-QuickStepFoundation/QSFoundation.h b/Quicksilver/Code-QuickStepFoundation/QSFoundation.h index 2293bb062..78bdff6c3 100644 --- a/Quicksilver/Code-QuickStepFoundation/QSFoundation.h +++ b/Quicksilver/Code-QuickStepFoundation/QSFoundation.h @@ -23,6 +23,7 @@ #import "NTViewLocalizer.h" #import "NSString+NDCarbonUtilities.h" +#import "QSMacros.h" #import "QSGCD.h" #import "QSThreadSafeMutableDictionary.h" #import "QSUTI.h" diff --git a/Quicksilver/Code-QuickStepCore/QSMacros.h b/Quicksilver/Code-QuickStepFoundation/QSMacros.h similarity index 69% rename from Quicksilver/Code-QuickStepCore/QSMacros.h rename to Quicksilver/Code-QuickStepFoundation/QSMacros.h index 236114be6..47dd75228 100644 --- a/Quicksilver/Code-QuickStepCore/QSMacros.h +++ b/Quicksilver/Code-QuickStepFoundation/QSMacros.h @@ -1,11 +1,3 @@ -#import - -//#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 -// #define foreach(x, y) id x; NSEnumerator *rwEnum = [y objectEnumerator]; while(x = [rwEnum nextObject]) -//#else -// // use fast enumeration on Mac OS X 10.5+ -// #define foreach(x, y) for (id (x) in (y)) -//#endif #define foreachkey(k, x, y) id x = nil; NSString *k = nil; NSEnumerator *kEnum = [y keyEnumerator]; while((k = [kEnum nextObject]) && (x = [y objectForKey:k]) ) #define defaultBool(x) [[NSUserDefaults standardUserDefaults] boolForKey:x] #define mOptionKeyIsDown (GetCurrentKeyModifiers() &optionKey) @@ -24,3 +16,6 @@ _Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"") \ Code; \ _Pragma("clang diagnostic pop") \ } while (0) + +#define QS_DEPRECATED __attribute__((deprecated)) + diff --git a/Quicksilver/PlugIns-Main/QSCorePlugIn/Code/QSCatalogEntrySource.m b/Quicksilver/PlugIns-Main/QSCorePlugIn/Code/QSCatalogEntrySource.m index a2632a843..8b04a6676 100644 --- a/Quicksilver/PlugIns-Main/QSCorePlugIn/Code/QSCatalogEntrySource.m +++ b/Quicksilver/PlugIns-Main/QSCorePlugIn/Code/QSCatalogEntrySource.m @@ -156,25 +156,26 @@ - (QSObject *)addCatalogEntry:(QSObject *)dObject { NSString *file = [[dObject objectForType:QSFilePathType] stringByStandardizingPath]; NSString *uniqueString = [NSString uniqueString]; - - NSMutableDictionary *childDict = [NSMutableDictionary dictionary]; - [childDict setObject:uniqueString forKey:kItemID]; - [childDict setObject:[NSNumber numberWithBool:YES] forKey:kItemEnabled]; - [childDict setObject:[file lastPathComponent] forKey:kItemName]; - [childDict setObject:@"QSFileSystemObjectSource" forKey:kItemSource]; + NSDictionary *childDict = @{ + kItemID: uniqueString, + kItemEnabled: @(YES), + kItemName: [file lastPathComponent], + kItemSource: @"QSFileSystemObjectSource", + kItemPath: [dObject arrayForType:QSFilePathType], + kItemModificationDate: @([NSDate timeIntervalSinceReferenceDate]), + kItemSettings: @{ + kItemPath: file, + } + }; - [childDict setObject:[dObject arrayForType:QSFilePathType] forKey:kItemPath]; - [childDict setObject:[NSNumber numberWithFloat:[NSDate timeIntervalSinceReferenceDate]] forKey:kItemModificationDate]; - QSCatalogEntry *childEntry = [QSCatalogEntry entryWithDictionary:childDict]; - + [[parentEntry children] addObject:childEntry]; - [[childEntry info] setObject:[NSMutableDictionary dictionaryWithObject:file forKey:kItemPath] forKey:kItemSettings]; - [[childEntry info] setObject:[NSNumber numberWithDouble:[NSDate timeIntervalSinceReferenceDate]] forKey:kItemModificationDate]; + [childEntry scanForced:YES]; [[NSNotificationCenter defaultCenter] postNotificationName:QSCatalogStructureChanged object:nil]; - [[NSNotificationCenter defaultCenter] postNotificationName:QSCatalogEntryChanged object:childEntry]; + [[NSNotificationCenter defaultCenter] postNotificationName:QSCatalogEntryChangedNotification object:childEntry]; [dObject setObject:uniqueString forType:QSCatalogEntryPboardType]; [self show:dObject]; diff --git a/Quicksilver/PlugIns-Main/QSCorePlugIn/Code/QSDefaultsObjectSource.m b/Quicksilver/PlugIns-Main/QSCorePlugIn/Code/QSDefaultsObjectSource.m index 9a5e35248..e06e56b4e 100644 --- a/Quicksilver/PlugIns-Main/QSCorePlugIn/Code/QSDefaultsObjectSource.m +++ b/Quicksilver/PlugIns-Main/QSCorePlugIn/Code/QSDefaultsObjectSource.m @@ -24,8 +24,8 @@ - (BOOL)isVisibleSource { return YES; } - (BOOL)usesGlobalSettings { return NO; } - (void)enableEntry:(QSCatalogEntry *)entry { - NSMutableDictionary *settings = [[entry info] objectForKey:kItemSettings]; - if ([[settings objectForKey:@"watchTarget"] boolValue]) { + NSDictionary *settings = entry.sourceSettings; + if ([settings[@"watchTarget"] boolValue]) { NSString *path = [self prefFileForBundle:[settings objectForKey:kDefaultsObjectSourceBundleID]]; // See VDKQueue.h for more information on queues [[QSVoyeur sharedInstance] addPath:path notifyingAbout:NOTE_DELETE | NOTE_WRITE]; diff --git a/Quicksilver/PlugIns-Main/QSCorePlugIn/Code/QSFileSystemObjectSource.m b/Quicksilver/PlugIns-Main/QSCorePlugIn/Code/QSFileSystemObjectSource.m index dc5a85d73..25fe62113 100644 --- a/Quicksilver/PlugIns-Main/QSCorePlugIn/Code/QSFileSystemObjectSource.m +++ b/Quicksilver/PlugIns-Main/QSCorePlugIn/Code/QSFileSystemObjectSource.m @@ -271,7 +271,7 @@ - (IBAction)setValueForSender:(id)sender { [[self selection] scanAndCache]; [self populateFields]; - [[NSNotificationCenter defaultCenter] postNotificationName:QSCatalogEntryChanged object:[self currentEntry]]; + [[NSNotificationCenter defaultCenter] postNotificationName:QSCatalogEntryChangedNotification object:[self currentEntry]]; } - (BOOL)textShouldEndEditing:(NSText *)aTextObject { return YES; } @@ -297,17 +297,17 @@ - (IBAction)endContainingSheet:(id)sender { } - (void)enableEntry:(QSCatalogEntry *)entry { - NSMutableDictionary *settings = [[entry info] objectForKey:kItemSettings]; + NSMutableDictionary *settings = entry.sourceSettings; NSString *path = [self fullPathForSettings:settings]; NSNotificationCenter *wsNotif = [[NSWorkspace sharedWorkspace] notificationCenter]; - if ([[settings objectForKey:@"watchTarget"] boolValue]) { + if ([settings[@"watchTarget"] boolValue]) { [[QSVoyeur sharedInstance] addPath:path notifyingAbout:NOTE_DELETE | NOTE_WRITE]; #ifdef DEBUG if (VERBOSE) NSLog(@"Watching Path %@", path); #endif [wsNotif addObserver:entry selector:@selector(invalidateIndex:) name:nil object:path]; } - NSArray *paths = [settings objectForKey:@"watchPaths"]; + NSArray *paths = settings[@"watchPaths"]; for (NSString * p in paths) { [[QSVoyeur sharedInstance] addPath:p]; #ifdef DEBIG @@ -318,9 +318,9 @@ - (void)enableEntry:(QSCatalogEntry *)entry { } - (void)disableEntry:(QSCatalogEntry *)entry { - NSMutableDictionary *settings = [[entry info] objectForKey:kItemSettings]; + NSMutableDictionary *settings = entry.sourceSettings; NSString *path = [self fullPathForSettings:settings]; - if ([[settings objectForKey:@"watchTarget"] boolValue]) { + if ([settings[@"watchTarget"] boolValue]) { [[QSVoyeur sharedInstance] removePath:path]; [[NSNotificationCenter defaultCenter] removeObserver:entry]; } @@ -375,7 +375,7 @@ - (BOOL)chooseFile { [self setValueForSender:itemLocationField]; [[self selection] setName:[[openPanel URL] lastPathComponent]]; [currentEntry setObject:[NSNumber numberWithDouble:[NSDate timeIntervalSinceReferenceDate]] forKey:kItemModificationDate]; - [[NSNotificationCenter defaultCenter] postNotificationName:QSCatalogEntryChanged object:[self currentEntry]]; + [[NSNotificationCenter defaultCenter] postNotificationName:QSCatalogEntryChangedNotification object:[self currentEntry]]; return YES; } diff --git a/Quicksilver/PlugIns-Main/QSCorePlugIn/Code/QSUserDefinedProxySource.m b/Quicksilver/PlugIns-Main/QSCorePlugIn/Code/QSUserDefinedProxySource.m index 88ab26dd6..7f25ae385 100644 --- a/Quicksilver/PlugIns-Main/QSCorePlugIn/Code/QSUserDefinedProxySource.m +++ b/Quicksilver/PlugIns-Main/QSCorePlugIn/Code/QSUserDefinedProxySource.m @@ -210,6 +210,6 @@ - (void)save [currentEntry setObject:[NSNumber numberWithFloat:[NSDate timeIntervalSinceReferenceDate]] forKey:kItemModificationDate]; [[self selection] scanAndCache]; [self populateFields]; - [[NSNotificationCenter defaultCenter] postNotificationName:QSCatalogEntryChanged object:[self currentEntry]]; + [[NSNotificationCenter defaultCenter] postNotificationName:QSCatalogEntryChangedNotification object:[self currentEntry]]; } @end diff --git a/Quicksilver/PlugIns-Main/QSCorePlugIn/Code/QSWebSource.m b/Quicksilver/PlugIns-Main/QSCorePlugIn/Code/QSWebSource.m index 01aef3f99..0da1499d5 100644 --- a/Quicksilver/PlugIns-Main/QSCorePlugIn/Code/QSWebSource.m +++ b/Quicksilver/PlugIns-Main/QSCorePlugIn/Code/QSWebSource.m @@ -26,7 +26,7 @@ - (NSArray *)objectsForEntry:(NSDictionary *)theEntry { NSArray *contents = [(QSHTMLLinkParser *)[QSReg getClassInstance:@"QSHTMLLinkParser"] objectsFromURL:[NSURL URLWithString:location] withSettings:settings]; if (!contents) { // return the original contents of the catalog entry if there was a problem getting data from the internet - return [[QSLib entryForID:[theEntry objectForKey:kItemID]] _contents]; + return [QSLib entryForID:[theEntry objectForKey:kItemID]].contents; } else { return contents; } diff --git a/Quicksilver/Quicksilver.xcodeproj/project.pbxproj b/Quicksilver/Quicksilver.xcodeproj/project.pbxproj index d4531adb6..25cf62e60 100644 --- a/Quicksilver/Quicksilver.xcodeproj/project.pbxproj +++ b/Quicksilver/Quicksilver.xcodeproj/project.pbxproj @@ -127,6 +127,8 @@ 4D66BC5D1487027E00351C42 /* NSURL+NDCarbonUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D66BBF11486FFF000351C42 /* NSURL+NDCarbonUtilities.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4D66BC5E1487027E00351C42 /* NSURL+NDCarbonUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D66BBF21486FFF000351C42 /* NSURL+NDCarbonUtilities.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4D6A663410AB2A2F00898CA4 /* QSTreeController.h in Headers */ = {isa = PBXBuildFile; fileRef = 92D9C9680D134BDD00D91825 /* QSTreeController.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4D6D369F17E61F93007017A6 /* QSCatalogEntry_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D6D369E17E61F93007017A6 /* QSCatalogEntry_Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 4D7B9FA117F2040300A91F64 /* QSMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DD89F1F0EBDDBA9005A15AE /* QSMacros.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4D7DF45416ADC7CA004BA4BE /* DefaultsMap.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4D7DF45316ADC7CA004BA4BE /* DefaultsMap.plist */; }; 4D7DF45716ADCDEF004BA4BE /* QSAdvancedPrefPane.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4D7DF45516ADCDEF004BA4BE /* QSAdvancedPrefPane.strings */; }; 4D89177514758620009C1C14 /* QSMainMenuPrefPane.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4D89177714758620009C1C14 /* QSMainMenuPrefPane.strings */; }; @@ -151,7 +153,6 @@ 4DD89F240EBDDBA9005A15AE /* QSDebug.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DD89F1B0EBDDBA9005A15AE /* QSDebug.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4DD89F250EBDDBA9005A15AE /* QSDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DD89F1C0EBDDBA9005A15AE /* QSDefines.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4DD89F270EBDDBA9005A15AE /* QSKeys.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DD89F1E0EBDDBA9005A15AE /* QSKeys.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4DD89F280EBDDBA9005A15AE /* QSMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DD89F1F0EBDDBA9005A15AE /* QSMacros.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4DD89F290EBDDBA9005A15AE /* QSNotifications.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DD89F200EBDDBA9005A15AE /* QSNotifications.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4DD89F2A0EBDDBA9005A15AE /* QSPreferenceKeys.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DD89F210EBDDBA9005A15AE /* QSPreferenceKeys.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4DD89F2B0EBDDBA9005A15AE /* QSTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DD89F220EBDDBA9005A15AE /* QSTypes.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1132,6 +1133,7 @@ 4D66BC3A1487024500351C42 /* NDScriptData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NDScriptData.m; sourceTree = ""; }; 4D66BC3B1487024500351C42 /* NSString+NDUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+NDUtilities.h"; sourceTree = ""; }; 4D66BC3C1487024500351C42 /* NSString+NDUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+NDUtilities.m"; sourceTree = ""; }; + 4D6D369E17E61F93007017A6 /* QSCatalogEntry_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QSCatalogEntry_Private.h; sourceTree = ""; }; 4D7DF45316ADC7CA004BA4BE /* DefaultsMap.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = DefaultsMap.plist; sourceTree = ""; }; 4D7DF45616ADCDEF004BA4BE /* en */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/QSAdvancedPrefPane.strings; sourceTree = ""; }; 4D7DF45816ADD014004BA4BE /* fr */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/QSAdvancedPrefPane.strings; sourceTree = ""; }; @@ -3154,6 +3156,21 @@ CD4FA6E1157A13DE00E549BD /* QSHotKeyEvent.m */, CDCC200E10A4C14B009C4EED /* QSMDPredicate.h */, CDCC200F10A4C14B009C4EED /* QSMDPredicate.m */, + 92D9C9680D134BDD00D91825 /* QSTreeController.h */, + 92D9C9690D134BDD00D91825 /* QSTreeController.m */, + 7F0843CC098ACB2F00F136CC /* QSLog.h */, + 7F0843CD098ACB2F00F136CC /* QSLog.m */, + 7F93148B07E8B626009B3C06 /* NSIndexSet+Extensions.h */, + 7F943F6308033961007EDC31 /* QSUTI.h */, + 7F943F6408033961007EDC31 /* QSUTI.m */, + 4DD89F1F0EBDDBA9005A15AE /* QSMacros.h */, + 7FDF342307F7D60A00594789 /* NSSortDescriptor+BLTRExtensions.h */, + 7FDF342407F7D60A00594789 /* NSSortDescriptor+BLTRExtensions.m */, + 7F93148C07E8B627009B3C06 /* NSIndexSet+Extensions.m */, + 7FDF341607F7D59E00594789 /* NSDictionary+BLTRExtensions.h */, + 7FDF341707F7D59E00594789 /* NSDictionary+BLTRExtensions.m */, + 7FF8BB3607B816A20088CEEF /* NSTask+BLTRExtensions.h */, + 7FF8BB3707B816A20088CEEF /* NSTask+BLTRExtensions.m */, E1E5FA6E07B204BE0044D6EF /* NDAlias+QSMods.h */, E1E5FA6F07B204BE0044D6EF /* NDAlias+QSMods.m */, E1E5FA7007B204BE0044D6EF /* NDProcess+QSMods.h */, @@ -3253,6 +3270,7 @@ 4DD2CF350E7B345500BA1128 /* QSBasicObject.m */, 7FB8D6FA07B98B1300062022 /* QSCatalogEntry.h */, 7FB8D6FB07B98B1300062022 /* QSCatalogEntry.m */, + 4D6D369E17E61F93007017A6 /* QSCatalogEntry_Private.h */, 42ADF4FD1317237900C68070 /* QSClangAnalyzer.h */, E1E5FB6F07B20DD10044D6EF /* QSCollection.h */, E1E5FB7007B20DD10044D6EF /* QSCollection.m */, @@ -3286,7 +3304,6 @@ E1E5FB8607B20DD10044D6EF /* QSLibrarian.m */, E1E5FB8707B20DD10044D6EF /* QSLocalization.h */, E1E5FB8807B20DD10044D6EF /* QSLocalization.m */, - 4DD89F1F0EBDDBA9005A15AE /* QSMacros.h */, 929052F80D0FEAD600579DAE /* QSMiscFunctions.h */, 929052F90D0FEAD600579DAE /* QSMiscFunctions.m */, E1E5FB8D07B20DD20044D6EF /* QSMnemonics.h */, @@ -3569,7 +3586,6 @@ 4DD89F270EBDDBA9005A15AE /* QSKeys.h in Headers */, E1E5FBF207B20DD20044D6EF /* QSLibrarian.h in Headers */, E1E5FBF407B20DD20044D6EF /* QSLocalization.h in Headers */, - 4DD89F280EBDDBA9005A15AE /* QSMacros.h in Headers */, 929052FA0D0FEAD600579DAE /* QSMiscFunctions.h in Headers */, E1E5FBFA07B20DD20044D6EF /* QSMnemonics.h in Headers */, 4DD89F290EBDDBA9005A15AE /* QSNotifications.h in Headers */, @@ -3615,6 +3631,7 @@ D413172F15DEE5D90021479B /* LaunchAtLoginController.h in Headers */, CD39DE6016B43FC40087B09E /* (null) in Headers */, CD65B12916FA1BD000932A9C /* QSPluginUpdaterWindowController.h in Headers */, + 4D6D369F17E61F93007017A6 /* QSCatalogEntry_Private.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3706,6 +3723,7 @@ CD14B79018D06604000FE86A /* QSThreadSafeMutableDictionary.h in Headers */, 2E34EDAA134C9F25005E66A1 /* QSLog.h in Headers */, 7FF447EA080479E200316DB6 /* QSLSTools.h in Headers */, + 4D7B9FA117F2040300A91F64 /* QSMacros.h in Headers */, CDCC201010A4C14B009C4EED /* QSMDPredicate.h in Headers */, 7F943F6508033961007EDC31 /* QSUTI.h in Headers */, 4D6A663410AB2A2F00898CA4 /* QSTreeController.h in Headers */,