Ignore:
Timestamp:
06/11/07 01:21:55 (17 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/ICeCoffEEServicePrefController.m

    r182 r319  
    1212#import "ICeCoffEENonHighlightingButtonCell.h"
    1313#import "ICeCoffEENonHighlightingTextFieldCell.h"
     14#import "ICeCoffEELabeledIconCell.h"
    1415#import <objc/objc.h>
    1516#import <ApplicationEnhancer/ApplicationEnhancer.h>
     
    2223}
    2324
    24 static inline NSCellStateValue ICCF_ServiceItemState(id <NSMenuItem> item) {
     25static NSMutableDictionary *keyEquivalents;
     26
     27static void ICCF_RemoveSingleKeyEquivalents() {
     28    NSMutableArray *singleKeys = [[NSMutableArray alloc] init];
     29    NSEnumerator *e = [[keyEquivalents allKeys] objectEnumerator];
     30    NSString *keyEquivalent;
     31    ICLog(@"before ICCF_RemoveSingleKeyEquivalents: %@", keyEquivalents);
     32    while ( (keyEquivalent = [e nextObject]) != nil) {
     33        if ([[keyEquivalents objectForKey: keyEquivalent] count] == 1)
     34            [singleKeys addObject: keyEquivalent];
     35    }
     36    [keyEquivalents removeObjectsForKeys: singleKeys];
     37    [singleKeys release];
     38    ICLog(@"after ICCF_RemoveSingleKeyEquivalents: %@", keyEquivalents);
     39}
     40
     41static inline unsigned ICCF_CountForKeyEquivalent(NSString *keyEquivalent) {
     42    if (keyEquivalent == nil) return 0;
     43    NSMutableSet *setOrNil = (NSMutableSet *)[keyEquivalents objectForKey: keyEquivalent];
     44    return (setOrNil == nil) ? nil : [setOrNil count];
     45}
     46
     47static inline void ICCF_AddKeyEquivalentForItem(NSMenuItem *item) {
     48    NSString *keyEquivalent = [item toolTip];
     49    if (keyEquivalent == nil) return;
     50    NSMutableSet *setOrNil = (NSMutableSet *)[keyEquivalents objectForKey: keyEquivalent];
     51    if (setOrNil == nil) return;
     52    [setOrNil addObject: item];
     53}
     54
     55static inline void ICCF_RemoveKeyEquivalentForItem(NSMenuItem *item) {
     56    NSString *keyEquivalent = [item toolTip];
     57    if (keyEquivalent == nil) return;
     58    NSMutableSet *setOrNil = (NSMutableSet *)[keyEquivalents objectForKey: keyEquivalent];
     59    if (setOrNil == nil) return;
     60    [setOrNil removeObject: item];
     61}
     62
     63static inline void ICCF_UpdateKeyEquivalentForItem(NSMenuItem *item, id state) {
     64    NSNumber *oldState = [item representedObject];
     65    if ((oldState == nil || oldState == ICCF_SERVICE_SHOWN) && state == ICCF_SERVICE_HIDDEN)
     66        ICCF_RemoveKeyEquivalentForItem(item);
     67    else if (oldState == ICCF_SERVICE_HIDDEN && (state == ICCF_SERVICE_SHOWN || state == nil))
     68        ICCF_AddKeyEquivalentForItem(item);
     69}
     70
     71static inline NSCellStateValue ICCF_ServiceItemState(NSMenuItem *item) {
    2572    id state = [item representedObject];
    2673    return (state == nil) ? NSOnState : [state intValue];
     
    3481    while ( (item = [e nextObject]) != nil) {
    3582        submenu = [item submenu];
    36         if (submenu != nil) {
    37             ICCF_PropagateServiceStateChange(submenu, state);
    38             [item setRepresentedObject: (state == nil) ? ICCF_SERVICE_SHOWN : state];
    39         }
    40         [item setRepresentedObject: state];
    41     }
    42 }
    43 
    44 static NSCellStateValue ICCF_PropagateServiceState(id <NSMenuItem> item, NSMenuItem *changedItem) {
     83        if (submenu != nil)
     84            ICCF_PropagateServiceStateChange(submenu, state);
     85        else
     86            ICCF_UpdateKeyEquivalentForItem(item, state);
     87       
     88        [item setRepresentedObject: state];
     89    }
     90}
     91
     92static NSCellStateValue ICCF_PropagateServiceState(NSMenuItem *item, NSMenuItem *changedItem) {
    4593    NSMenu *submenu = [item submenu];
    4694    if (submenu == nil) return ICCF_ServiceItemState(item);
     
    102150    NSString *itemTitle;
    103151    NSDictionary *subDict, *submenuDict;
    104     id <NSMenuItem> item;
     152    NSMenuItem *item;
    105153    NSMenu *submenu;
    106154
    107155    // XXX handle exceptions
    108156    while ( (itemTitle = [e nextObject]) != nil) {
    109         item = [menu itemWithTitle: itemTitle];
     157        item = (NSMenuItem *)[menu itemWithTitle: itemTitle];
    110158        if (item == nil) continue;
    111159        subDict = [dict objectForKey: itemTitle];
    112160        if ([[subDict objectForKey: (NSString *)kICServiceHidden] boolValue]) {
    113161            [item setRepresentedObject: ICCF_SERVICE_HIDDEN];
     162            ICCF_RemoveKeyEquivalentForItem(item);
    114163        }
    115164        if ( (submenu = [item submenu]) != nil) {
     
    123172}
    124173
     174static void ICCF_AddServiceKeyEquivalentsAndIcons(NSMenu *menu, NSDictionary *serviceInfo) {
     175    if (serviceInfo == nil) return;
     176    NSEnumerator *enumerator = [[menu itemArray] objectEnumerator];
     177    NSMenuItem *menuItem;
     178    NSMenu *submenu;
     179    NSDictionary *itemInfo = nil;
     180    while ( (menuItem = [enumerator nextObject]) != nil) {
     181        itemInfo = [serviceInfo objectForKey: [menuItem title]];
     182        if (itemInfo == nil) continue;
     183       
     184        if ( (submenu = [menuItem submenu]) != nil) {
     185            ICCF_AddServiceKeyEquivalentsAndIcons(submenu, itemInfo);
     186        } else {
     187            NSString *keyEquivalent = (NSString *)[itemInfo objectForKey: (NSString *)kICServiceShortcut];
     188            if (keyEquivalent != nil) {
     189                [menuItem setToolTip: keyEquivalent];
     190                NSMutableSet *equivalentItems = (NSMutableSet *)[keyEquivalents objectForKey: keyEquivalent];
     191                if (equivalentItems == nil) {
     192                    equivalentItems = [[NSMutableSet alloc] initWithObjects: menuItem, nil];
     193                    [keyEquivalents setObject: equivalentItems forKey: keyEquivalent];
     194                    [equivalentItems release];
     195                } else {
     196                    [equivalentItems addObject: menuItem];
     197                }
     198            }
     199        }
     200
     201        NSString *bundlePath = (NSString *)[itemInfo objectForKey: (NSString *)kICServiceBundlePath];
     202        if (bundlePath == NULL) continue;
     203        IconRef serviceIcon = ICCF_CopyIconRefForPath(bundlePath);
     204        if (serviceIcon == NULL) continue;
     205        [menuItem _setIconRef: serviceIcon];
     206        ReleaseIconRef(serviceIcon);
     207    }
     208}
     209
    125210@implementation ICeCoffEEServicePrefController
    126211
     
    141226    if ( (self = [self initWithWindowNibName: @"Select services"])) {
    142227        NSWindow *window = [self window]; // connect outlets
     228        [serviceOutline setAutoresizesOutlineColumn: NO];
     229       
    143230        NSButtonCell *checkBoxCell = [[ICeCoffEENonHighlightingButtonCell alloc] init];
    144231        [checkBoxCell setButtonType: NSSwitchButton];
     
    149236
    150237        NSTextFieldCell *textFieldCell = [[serviceOutline tableColumnWithIdentifier: @"service"] dataCell];
    151         ((struct objc_object *)textFieldCell)->isa = [ICeCoffEENonHighlightingTextFieldCell class];
     238        [textFieldCell setWraps: YES];
     239        [[serviceOutline tableColumnWithIdentifier: @"service"] setDataCell:
     240            [ICeCoffEELabeledIconCell copyFromTextFieldCell: textFieldCell]];
    152241
    153242        textFieldCell = [[serviceOutline tableColumnWithIdentifier: @"key"] dataCell];
     
    167256- (void)dealloc;
    168257{
     258    [keyEquivalents release];
    169259    [servicesMenu release];
    170260    [super dealloc];
     
    223313{
    224314    if (servicesMenu == nil) {
     315        keyEquivalents = [[NSMutableDictionary alloc] init];
    225316        servicesMenu = [[NSMenu alloc] initWithTitle: @""];
    226317        ICCF_SetServicesMenu(servicesMenu);
    227         [servicesMenu update]; // XXX necessary on 10.3? or anywhere?
     318        ICCF_AddServiceKeyEquivalentsAndIcons(servicesMenu, ICCF_GetServicesInfo());
     319        ICCF_RemoveSingleKeyEquivalents();
     320       
    228321        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    229322        NSDictionary *icDefaults = [defaults persistentDomainForName: (NSString *)kICBundleIdentifier];
     
    244337}
    245338
    246 NSAttributedString *ICCF_KeyEquivalentAttributedStringWithModifierFlags(NSString *self, unsigned int modifierFlags);
     339NSAttributedString *ICCF_KeyEquivalentAttributedStringWithModifierFlags(NSString *self, unsigned int modifierFlags, unsigned count);
    247340
    248341- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item;
    249342{
    250343    if ([[tableColumn identifier] isEqualToString: @"service"]) {
    251         return [item title];
     344        static NSDictionary *attrDict = nil;
     345        if (attrDict == nil) { // XXX we leak this, but so does the Apple sample code...
     346            NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
     347            [style setLineBreakMode: NSLineBreakByTruncatingMiddle];
     348            attrDict = [[NSDictionary alloc] initWithObjectsAndKeys: style, NSParagraphStyleAttributeName, nil];
     349            [style release];
     350        }
     351        return [[[NSAttributedString alloc] initWithString: [item title] attributes: attrDict] autorelease];
    252352    } else if ([[tableColumn identifier] isEqualToString: @"show"]) {
    253353        id state = [item representedObject];
     
    257357        return (state == nil) ? ICCF_SERVICE_SHOWN : state;
    258358    } else if ([[tableColumn identifier] isEqualToString: @"key"]) {
    259         [item setKeyEquivalent: @"#"];
    260         NSString *equivalent = [item keyEquivalent];
     359        NSString *equivalent = [item toolTip];
    261360        if (equivalent == nil || [equivalent length] != 1) return nil;
    262361        // XXX Inconsistency between Cocoa and Carbon: always command-shift in Carbon, not in Cocoa.  Since we only patch Cocoa for the moment, keep as is.
    263         return ICCF_KeyEquivalentAttributedStringWithModifierFlags(equivalent, [item keyEquivalentModifierMask] | ([[NSCharacterSet uppercaseLetterCharacterSet] characterIsMember: [equivalent characterAtIndex: 0]] ? NSShiftKeyMask : 0));
     362        return ICCF_KeyEquivalentAttributedStringWithModifierFlags(equivalent, [item keyEquivalentModifierMask] | ([[NSCharacterSet uppercaseLetterCharacterSet] characterIsMember: [equivalent characterAtIndex: 0]] ? NSShiftKeyMask : 0), ICCF_CountForKeyEquivalent(equivalent));
    264363    }
    265364    return nil;
     
    269368{
    270369    if ([[tableColumn identifier] isEqualToString: @"show"]) {
    271         [item setRepresentedObject: [object boolValue] ? nil : ICCF_SERVICE_HIDDEN];
     370        NSNumber *newState = [object boolValue] ? nil : ICCF_SERVICE_HIDDEN;
     371        ICCF_UpdateKeyEquivalentForItem(item, newState);
     372        [item setRepresentedObject: newState];
    272373       
    273374        NSMenu *submenu = [item menu];
     
    279380                submenu = supermenu;
    280381            }
    281             ICCF_PropagateServiceState([supermenu itemAtIndex: [supermenu indexOfItemWithSubmenu: submenu]], item);
     382            ICCF_PropagateServiceState((NSMenuItem *)[supermenu itemAtIndex: [supermenu indexOfItemWithSubmenu: submenu]], item);
    282383        }
    283384        [outlineView reloadData];
    284385    }
     386}
     387
     388@end
     389
     390@implementation ICeCoffEEServicePrefController (NSOutlineViewDelegate)
     391
     392- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item;
     393{
     394    if (![[tableColumn identifier] isEqualToString: @"service"])
     395        return;
     396    [(ICeCoffEELabeledIconCell *)cell setIconRef: [item _iconRef]];
    285397}
    286398
Note: See TracChangeset for help on using the changeset viewer.