Ignore:
Timestamp:
02/06/03 20:11:46 (19 years ago)
Author:
Nicholas Riley
Message:

ICeCoffEE 1.3.1d1

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/ICeCoffEE/ICeCoffEE/ICeCoffEEActionMenu.c

    r82 r88  
    1010#include "ICeCoffEEActionMenu.h"
    1111#include "ICeCoffEEConfig.h"
     12#include "ICeCoffEEShared.h"
    1213#include "ICeCoffEEBookmarks.h"
    1314
     
    3233    CFURLRef defaultAppURL; // URL of default app, set to NULL after added to menu
    3334    CFMutableSetRef appPaths;
    34     CFMutableDictionaryRef appNames; // keys: app display names (CFString), values: MenuItemIndex of matching item without path appended, or kICAppMenuItemHasPath if already appended (at least 2 items with this name exist)
     35    CFMutableDictionaryRef appItemTitles; // keys: URLs; values: item titles (CFString)
     36    CFMutableDictionaryRef appURLs; // keys: app display names (CFString), values: URL of item without path appended, or NULL if already appended (at least 2 items with this name exist)
    3537    MenuRef menu;
    3638} icAppMenuContext;
    3739
    38 static OSStatus ICCF_AddAppToMenu(icAppMenuContext *ctx, CFURLRef appURL, MenuCommand menuCommand) {
     40static OSStatus ICCF_AddAppItemTitle(icAppMenuContext *ctx, CFURLRef appURL) {
    3941    CFStringRef appName = NULL, appItemTitle = NULL;
    4042    CFBundleRef appBundle = NULL;
    41     IconRef appIcon = NULL;
    42     FSRef appRef;
    43     SInt16 label;
    44     MenuItemIndex menuItemIndex;
    4543    OSStatus err = noErr;
    4644
     
    4846    // only one entry for each path
    4947    if (CFSetContainsValue(ctx->appPaths, appPath))
    50         return noErr;
     48        return dupFNErr;
    5149    CFSetAddValue(ctx->appPaths, appPath);
    52    
     50
    5351    if ( (err = LSCopyDisplayNameForURL(appURL, &appName)) != noErr)
    5452        return err;
    5553
    56     menuItemIndex = (long)CFDictionaryGetValue(ctx->appNames, appName);
    57     if (menuItemIndex != 0) {
    58         CFURLRef sameAppRef;
    59         if (menuItemIndex != kICAppMenuItemHasPath &&
    60             GetMenuItemRefCon(ctx->menu, menuItemIndex, (void *)&sameAppRef) == noErr) {
    61             CFStringRef sameAppItemTitle = NULL;
    62             if ( (err = CopyMenuItemTextAsCFString(ctx->menu, menuItemIndex, &sameAppItemTitle)) != noErr)
    63                 return err;
    64             CFStringRef appItemTitleWithVersion = ICCF_NameWithLocation(sameAppItemTitle, sameAppRef);
    65             SetMenuItemTextWithCFString(ctx->menu, menuItemIndex, appItemTitleWithVersion);
    66             SAFE_RELEASE(appItemTitleWithVersion);
    67             CFDictionarySetValue(ctx->appNames, appName, (void *)(long)kICAppMenuItemHasPath);
    68         }
     54    // if we encounter multiple applications with the same display name, add locations to the menu item titles to disambiguate them
     55    CFURLRef sameAppURL;
     56    Boolean shouldAppendLocation;
     57    if ( (shouldAppendLocation = CFDictionaryGetValueIfPresent(ctx->appURLs, appName, (const void **)&sameAppURL)) && (CFTypeRef)sameAppURL != kCFNull) {
     58        // this app is the second encountered with the same name; go back and fix the menu item title of the first app
     59        CFStringRef sameAppItemTitle = CFDictionaryGetValue(ctx->appItemTitles, sameAppURL);
     60        CFStringRef appItemTitleWithVersion = ICCF_NameWithLocation(sameAppItemTitle, sameAppURL);
     61        CFDictionarySetValue(ctx->appItemTitles, sameAppURL, appItemTitleWithVersion);
     62        SAFE_RELEASE(appItemTitleWithVersion);
     63        CFDictionarySetValue(ctx->appURLs, appName, kCFNull);
    6964    }
    7065
     
    8479    }
    8580
    86     if (menuItemIndex != 0) {
     81    if (shouldAppendLocation) {
    8782        CFStringRef appItemTitleWithVersion = ICCF_NameWithLocation(appItemTitle, appURL);
    8883        CFRelease(appItemTitle);
    8984        appItemTitle = appItemTitleWithVersion;
     85    } else {
     86        CFDictionarySetValue(ctx->appURLs, appName, appURL);
    9087    }
    9188
     
    9592        CFRelease(appItemTitle);
    9693        appItemTitle = appItemTitleWithDefault;
    97         ctx->defaultAppURL = NULL;
    98     }
    99 
     94        ctx->defaultAppURL = NULL; // mark as added
     95    }
     96
     97    CFDictionarySetValue(ctx->appItemTitles, appURL, appItemTitle);
     98    CFRelease(appItemTitle);
     99
     100    return noErr;
     101}
     102
     103static OSStatus ICCF_AddTitledAppToMenu(icAppMenuContext *ctx, CFURLRef appURL, MenuCommand menuCommand) {
     104    CFStringRef appItemTitle = NULL;
     105    IconRef appIcon = NULL;
     106    FSRef appFSR;
     107    SInt16 label;
     108    MenuItemIndex menuItemIndex;
     109    OSStatus err = noErr;
     110
     111    appItemTitle = CFDictionaryGetValue(ctx->appItemTitles, appURL);
     112    if (appItemTitle == NULL) return fnfErr;
     113   
    100114    err = AppendMenuItemTextWithCFString(ctx->menu, appItemTitle, 0, 0, &menuItemIndex);
    101     CFRelease(appItemTitle);
    102115    if (err != noErr) return err;
    103116
    104     if (!CFDictionaryContainsKey(ctx->appNames, appName)) {
    105         CFDictionarySetValue(ctx->appNames, appName, (void *)(long)menuItemIndex);
    106         CFRelease(appName);
    107     }
    108 
    109     if (!CFURLGetFSRef(appURL, &appRef)) return paramErr;
    110     err = GetIconRefFromFileInfo(&appRef, 0, NULL, kFSCatInfoNone, NULL, kIconServicesNormalUsageFlag, &appIcon, &label);
     117    if (!CFURLGetFSRef(appURL, &appFSR)) return paramErr;
     118    err = GetIconRefFromFileInfo(&appFSR, 0, NULL, kFSCatInfoNone, NULL, kIconServicesNormalUsageFlag, &appIcon, &label);
    111119    if (err != noErr) return err;
    112120
     
    119127}
    120128
     129static OSStatus ICCF_AddAppToMenu(icAppMenuContext *ctx, CFURLRef appURL, MenuCommand menuCommand) {
     130    OSStatus err = ICCF_AddAppItemTitle(ctx, appURL);
     131    switch (err) {
     132        case noErr: break;
     133        case dupFNErr: return noErr;
     134        default: return err;
     135    }
     136    return ICCF_AddTitledAppToMenu(ctx, appURL, menuCommand);
     137}   
     138
     139CFComparisonResult ICCF_CompareURLsByItemTitle(const void *url1, const void *url2, void *appItemTitles) {
     140    CFStringRef appItemTitle1 = CFDictionaryGetValue((CFDictionaryRef)appItemTitles, (CFURLRef)url1);
     141    CFStringRef appItemTitle2 = CFDictionaryGetValue((CFDictionaryRef)appItemTitles, (CFURLRef)url2);
     142    return CFStringCompareWithOptions(appItemTitle1, appItemTitle2,
     143                                      CFRangeMake(0, CFStringGetLength(appItemTitle1)),
     144                                      kCFCompareCaseInsensitive | kCFCompareNumerically);
     145}
     146
    121147enum {
    122148    kICURLActionOpenWith = 'OpnW',
     
    127153    Handle h = NewHandle(0);
    128154    CFURLRef url = NULL;
    129     CFArrayRef appURLs = NULL; // matching app URLs
     155    CFArrayRef appURLsUnsorted = NULL; // matching app URLs
     156    CFMutableArrayRef appURLs = NULL; // matching app URLs sorted by item title
    130157    CFArrayRef urlArray = NULL; // single-URL array
    131158    icAppMenuContext ctx = {NULL, NULL, NULL, NULL};
     
    140167                                     NULL)) == NULL) THROW_ERR(paramErr);
    141168
     169    if ( (err = _LSCopyApplicationURLsForItemURL(url, kLSRolesAll, &appURLsUnsorted)) != noErr)
     170        THROW_ERR(err);
     171
    142172    CFIndex appCount = 0;
    143     if ( (err = _LSCopyApplicationURLsForItemURL(url, kLSRolesAll, &appURLs)) != noErr)
    144         THROW_ERR(err);
    145    
    146     if (appURLs == NULL || (appCount = CFArrayGetCount(appURLs)) == 0)
     173    if (appURLsUnsorted == NULL || (appCount = CFArrayGetCount(appURLsUnsorted)) == 0)
    147174        THROW_ERR(kLSApplicationNotFoundErr);
    148175
     176    if ( (appURLs = CFArrayCreateMutableCopy(NULL, appCount, appURLsUnsorted)) == NULL)
     177        THROW_ERR(memFullErr);
     178
    149179    if ( (ctx.appPaths = CFSetCreateMutable(NULL, appCount, &kCFCopyStringSetCallBacks)) == NULL)
    150180        THROW_ERR(memFullErr);
    151181
    152     // values: index of single item with name; 0/NULL if no name; kICAppMenuItemHasPath if multiple items have name
    153     if ( (ctx.appNames = CFDictionaryCreateMutable(NULL, appCount, &kCFCopyStringDictionaryKeyCallBacks, NULL)) == NULL)
    154         THROW_ERR(memFullErr);
    155 
     182    if ( (ctx.appItemTitles = CFDictionaryCreateMutable(NULL, appCount, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == NULL)
     183        THROW_ERR(memFullErr);
     184
     185    if ( (ctx.appURLs = CFDictionaryCreateMutable(NULL, appCount, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == NULL)
     186        THROW_ERR(memFullErr);
     187
     188    LSGetApplicationForURL(url, kLSRolesAll, NULL, &ctx.defaultAppURL);
     189
     190    CFIndex appIndex;
     191    CFURLRef appURL;
     192    for (appIndex = 0 ; appIndex < appCount ; appIndex++) {
     193        appURL = CFArrayGetValueAtIndex(appURLs, appIndex);
     194        err = ICCF_AddAppItemTitle(&ctx, appURL);
     195        switch (err) {
     196            case noErr: break;
     197            case dupFNErr:
     198                CFArrayRemoveValueAtIndex(appURLs, appIndex);
     199                appIndex--;
     200                appCount--;
     201                break;
     202            default:
     203                THROW_ERR(err);
     204        }
     205    }
     206
     207    CFArraySortValues(appURLs, CFRangeMake(0, appCount), ICCF_CompareURLsByItemTitle, ctx.appItemTitles);
     208   
    156209    if ( (err = CreateNewMenu(0, kMenuAttrExcludesMarkColumn, &ctx.menu)) != noErr)
    157210        THROW_ERR(err);
     
    164217        THROW_ERR(memFullErr);
    165218
    166     LSGetApplicationForURL(url, kLSRolesAll, NULL, &ctx.defaultAppURL);
    167 
    168     CFIndex appIndex;
    169     CFURLRef appURL;
    170 
    171219    for (appIndex = 0 ; appIndex < appCount ; appIndex++) {
    172220        appURL = CFArrayGetValueAtIndex(appURLs, appIndex);
    173221
    174         if ( (err = ICCF_AddAppToMenu(&ctx, appURL, kICURLActionOpenWith)) != noErr)
     222        if ( (err = ICCF_AddTitledAppToMenu(&ctx, appURL, kICURLActionOpenWith)) != noErr)
    175223            THROW_ERR(err);
    176224    }
     
    223271    SAFE_RELEASE(url);
    224272    SAFE_RELEASE(urlArray);
     273    SAFE_RELEASE(appURLsUnsorted);
    225274    SAFE_RELEASE(appURLs);
    226     SAFE_RELEASE(ctx.appNames);
    227275    SAFE_RELEASE(ctx.appPaths);
     276    SAFE_RELEASE(ctx.appItemTitles);
     277    SAFE_RELEASE(ctx.appURLs);
    228278   
    229279    return err;
Note: See TracChangeset for help on using the changeset viewer.