Ignore:
Timestamp:
06/11/07 01:21:55 (13 years ago)
Author:
Nicholas Riley
Message:

VERSION: Starting with 1.5d1.

ICeCoffEEKeyEquivalents.m: Support "collision font" for displaying key
equivalent conflicts.

ICeCoffEE.m: Increase debug ICCF_MAX_URL_LEN to 120 for testing. Set
icons in ICCF_ConsolidateServicesMenu (needs better caching).

ICeCoffEEServicePrefController.m: Display icons, proper key
equivalents (instead of #, what was I thinking?!) and conflicts. Fix
a dumb bug in ICCF_PropagateServiceStateChange. Ellipsize long menu
items rather than chopping them off. Fix key equivalent column
getting moved when expanding disclosure triangles.

ICeCoffEELabeledIconCell.[hm]: An IconRef?-displaying text cell.

Info-APE Module.plist: Update version to 1.5d1.

ICeCoffEE.xcodeproj: Added files, no significant changes.

English.lproj/InfoPlist.strings: Update version to 1.5d1.

English.lproj/APEInfo.rtfd/TXT.rtf: Some overdue documentation
updates.

ICeCoffEEShared.[hm]: Enable debugging; we're now using
kICServiceShortcut (though not yet for customizable shortcuts) so
define its data type.

ICeCoffEETerminal.m: Remove some useless code to "extend to beginning
of string" which seems to have been stolen from the NSTextView
implementation and not well understood. Handle common uses of
parentheses in URLs; still need to do this for NSTextView.

ICeCoffEESetServicesMenu.[hm]: Needs renaming; now with icon
extraction functionality and semi-working code to create a service
info dictionary.

Info-APEManagerPrefPane.plist: Update version to 1.5d1.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/ICeCoffEE/ICeCoffEE/ICeCoffEESetServicesMenu.m

    r182 r319  
    88
    99#import "ICeCoffEESetServicesMenu.h"
     10#import "ICeCoffEEShared.h"
     11
     12// XXX rename me to something like "ICeCoffEEServicesMenu.m"
     13
     14// an approximate clone of HIToolbox's CreateServicesLocalizedDictKey
     15static CFStringRef preferredLocalization(CFDictionaryRef localizations) {
     16    if (localizations == NULL)
     17        return NULL;
     18   
     19    CFIndex localizationCount = CFDictionaryGetCount(localizations);
     20    if (localizationCount == 0)
     21        return NULL;
     22   
     23    const void **locales = malloc(localizationCount * sizeof(void *));
     24    if (locales == NULL)
     25        return NULL;
     26   
     27    CFDictionaryGetKeysAndValues(localizations, locales, NULL);
     28    CFArrayRef availableLocales = CFArrayCreate(NULL, locales, localizationCount, NULL);
     29    if (availableLocales == NULL)
     30        return NULL;
     31   
     32    // XXX does this actually work in a localized app?
     33    CFArrayRef preferredLocales = CFBundleCopyPreferredLocalizationsFromArray(availableLocales);
     34    // NSLog(@"%@ => %@", availableLocales, preferredLocales);
     35    CFRelease(availableLocales);
     36    CFStringRef preferredLocalization;
     37    if (preferredLocales != NULL) {
     38        if (CFArrayGetCount(preferredLocales) > 0) {
     39            CFStringRef preferredLocale = CFArrayGetValueAtIndex(preferredLocales, 0);
     40            preferredLocalization = (CFStringRef)CFDictionaryGetValue(localizations, preferredLocale);
     41        }
     42        CFRelease(preferredLocales);
     43    }
     44    if (preferredLocalization == NULL) {
     45        preferredLocalization = (CFStringRef)CFDictionaryGetValue(localizations, CFSTR("default"));
     46        if (preferredLocalization == NULL)
     47            preferredLocalization = (CFStringRef)CFDictionaryGetValue(localizations, (CFStringRef)locales[0]);
     48    }
     49   
     50    free(locales);
     51    // NSLog(@"%@", preferredLocalization);
     52    return preferredLocalization;
     53}
     54
     55NSArray *CFServiceControllerCopyServicesEntries(void);
     56
     57NSDictionary *ICCF_GetServicesInfo(void) {
     58    NSArray *services = CFServiceControllerCopyServicesEntries();
     59    // NSLog(@"%@", services);
     60   
     61    NSEnumerator *e = [services objectEnumerator];
     62    NSDictionary *serviceEntry;
     63    NSMutableDictionary *serviceDict = [[NSMutableDictionary alloc] init];
     64    while ( (serviceEntry = (NSDictionary *)[e nextObject]) != nil) {
     65        // XXX once tested, redo all this with CF, and no autoreleasing
     66        // XXX items named the same as submenus (figure out how Cocoa itself does it, too)
     67        // XXX use kICServiceSubmenu (recursion?)
     68        NSString *itemPath = (NSString *)preferredLocalization((CFDictionaryRef)[serviceEntry objectForKey: @"NSMenuItem"]);
     69        if (itemPath == nil) continue;
     70       
     71        NSString *bundlePath = [serviceEntry objectForKey: @"NSBundlePath"];
     72        BOOL bubbledUp = (bundlePath == nil);
     73        NSArray *itemComponents = [itemPath componentsSeparatedByString: @"/"];
     74        NSEnumerator *ce = [itemComponents objectEnumerator];
     75        NSString *itemComponent;
     76        NSMutableDictionary *levelDict = serviceDict;
     77        NSMutableDictionary *itemDict = nil;
     78        while ( (itemComponent = (NSString *)[ce nextObject]) != nil) {
     79            // itemDict is nil if just created
     80            if (itemDict != nil && !bubbledUp) {
     81                NSString *oldBundlePath = [levelDict objectForKey: (NSString *)kICServiceBundlePath];
     82                if ([oldBundlePath isEqualToString: bundlePath])
     83                    bubbledUp = YES;
     84                else if (oldBundlePath != nil) {
     85                    [oldBundlePath retain];
     86                    [levelDict removeObjectForKey: (NSString *)kICServiceBundlePath];
     87                    NSEnumerator *be = [levelDict objectEnumerator];
     88                    while ( (itemDict = (NSMutableDictionary *)[be nextObject]) != nil)
     89                        [itemDict setObject: oldBundlePath forKey: (NSString *)kICServiceBundlePath];
     90                    [oldBundlePath release];
     91                }
     92            }
     93            itemDict = [levelDict objectForKey: itemComponent];
     94            if (itemDict == nil) {
     95                itemDict = [[NSMutableDictionary alloc] init];
     96                if (!bubbledUp) {
     97                    [itemDict setObject: bundlePath forKey: (NSString *)kICServiceBundlePath];
     98                    bubbledUp = YES;
     99                }
     100                [levelDict setObject: itemDict forKey: itemComponent];
     101                levelDict = itemDict;
     102                [itemDict release];
     103                itemDict = nil;
     104            } else {
     105                levelDict = itemDict;
     106            }
     107        }
     108       
     109        if (!bubbledUp)
     110            [levelDict setObject: bundlePath forKey: (NSString *)kICServiceBundlePath];
     111
     112        NSString *keyEquivalent = (NSString *)preferredLocalization((CFDictionaryRef)[serviceEntry objectForKey: @"NSKeyEquivalent"]);
     113        if (keyEquivalent == nil) continue;
     114
     115        [levelDict setObject: keyEquivalent forKey: (NSString *)kICServiceShortcut];
     116    }
     117    [services release];
     118   
     119    return [serviceDict autorelease];
     120}
    10121
    11122
     
    31142    }
    32143}
     144
     145IconRef ICCF_CopyIconRefForPath(NSString *path) {
     146    IconRef icon;
     147    FSRef fsr;
     148    SInt16 label;
     149    OSStatus err = noErr;
     150   
     151    err = FSPathMakeRef((const UInt8 *)[path fileSystemRepresentation], &fsr, NULL);
     152    if (err != noErr) return NULL;
     153   
     154    err = GetIconRefFromFileInfo(&fsr, 0, NULL, kFSCatInfoNone, NULL, kIconServicesNormalUsageFlag, &icon, &label);
     155    if (err != noErr) return NULL;
     156   
     157    return icon;
     158}
Note: See TracChangeset for help on using the changeset viewer.