Ignore:
Timestamp:
11/04/02 20:23:02 (20 years ago)
Author:
Nicholas Riley
Message:

Lots of wonderful changes for which I composed a detailed svn commit
message, which it proceeded to mangle yet AGAIN on failed commit.

File:
1 moved

Legend:

Unmodified
Added
Removed
  • trunk/Cocoa/Pester/Source/NJRQTMediaPopUpButton.m

    r34 r39  
    1212#import "NSImage-NJRExtensions.h"
    1313
     14static const int NJRQTMediaPopUpButtonMaxRecentItems = 10;
     15
    1416@interface NJRQTMediaPopUpButton (Private)
    15 - (BOOL)_previewSound;
     17- (void)_setPath:(NSString *)path;
     18- (BOOL)_validatePreview;
    1619@end
    1720
     
    1922
    2023// XXX handle refreshing sound list on resume
    21 // XXX don't add icons on Puma
    22 // XXX add saving of recently selected media
    23 // XXX launch preview on a separate thread (if movies take too long to load, they inhibit the interface)
     24// XXX don't add icons on Puma, they look like ass
     25// XXX launch preview on a separate thread (if movies take too long to load, they inhibit the interface responsiveness)
     26
     27- (NSString *)_defaultKey;
     28{
     29    NSAssert([self tag] != 0, @"CanÕt track recently selected media for popup with tag 0: please set a tag");
     30    return [NSString stringWithFormat: @"NJRQTMediaPopUpButtonMaxRecentItems tag %d", [self tag]];
     31}
     32
     33- (void)_writeRecentMedia;
     34{
     35    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
     36    [defaults setObject: recentMediaAliasData forKey: [self _defaultKey]];
     37    [defaults synchronize];
     38}
     39
     40- (NSMenuItem *)_addRecentMediaAtPath:(NSString *)path withAlias:(BDAlias *)alias;
     41{
     42    NSString *title = [[NSFileManager defaultManager] displayNameAtPath: path];
     43    NSMenu *menu = [self menu];
     44    NSMenuItem *item = [menu insertItemWithTitle: title action: @selector(_aliasSelected:) keyEquivalent: @"" atIndex: [menu indexOfItem: otherItem] + 1];
     45    [item setTarget: self];
     46    [item setRepresentedObject: alias];
     47    [item setImage: [[[NSWorkspace sharedWorkspace] iconForFile: path] bestFitImageForSize: NSMakeSize(16, 16)]];
     48    [recentMediaAliasData addObject: [alias aliasData]];
     49    if ([recentMediaAliasData count] > NJRQTMediaPopUpButtonMaxRecentItems) {
     50        [menu removeItemAtIndex: [menu numberOfItems] - 1];
     51        [recentMediaAliasData removeObjectAtIndex: 0];
     52    }
     53    return item;
     54}
     55
     56- (void)_addRecentMediaFromAliasesData:(NSArray *)aliasesData;
     57{
     58    NSEnumerator *e = [aliasesData objectEnumerator];
     59    NSData *aliasData;
     60    BDAlias *alias;
     61    while ( (aliasData = [e nextObject]) != nil) {
     62        if ( (alias = [[BDAlias alloc] initWithData: aliasData]) != nil) {
     63            [self _addRecentMediaAtPath: [alias fullPath] withAlias: alias];
     64            [alias release];
     65        }
     66    }
     67}
     68
     69- (void)_validateRecentMedia;
     70{
     71    NSEnumerator *e = [recentMediaAliasData objectEnumerator];
     72    NSData *aliasData;
     73    NSMenuItem *item;
     74    BDAlias *itemAlias;
     75    int otherIndex = [self indexOfItem: otherItem];
     76    int aliasDataCount = [recentMediaAliasData count];
     77    int lastItemIndex = [self numberOfItems] - 1;
     78    int recentItemCount = lastItemIndex - otherIndex;
     79    int recentItemIndex = otherIndex;
     80    NSAssert2(recentItemCount == aliasDataCount, @"Counted %d recent menu items, %d of alias data", recentItemCount, aliasDataCount);
     81    while ( (aliasData = [e nextObject]) != nil) {
     82        recentItemIndex++;
     83        item = [self itemAtIndex: recentItemIndex];
     84        itemAlias = [item representedObject];
     85        if (![itemAlias aliasDataIsEqual: aliasData])
     86            NSLog(@"item %d %@: %@", recentItemIndex, [item title], [itemAlias fullPath]);
     87        else
     88            NSLog(@"ITEM %d %@: %@ != aliasData %@", recentItemIndex, [item title], [itemAlias fullPath], [[BDAlias aliasWithData: aliasData] fullPath]);
     89    }
     90}
    2491
    2592- (void)awakeFromNib;
     
    2996    SoundFileManager *sfm = [SoundFileManager sharedSoundFileManager];
    3097    int soundCount = [sfm count];
    31    
     98
    3299    [self removeAllItems];
    33100    menu = [self menu];
     
    53120    item = [menu addItemWithTitle: @"OtherÉ" action: @selector(select:) keyEquivalent: @""];
    54121    [item setTarget: self];
     122    otherItem = [item retain];
     123
     124    recentMediaAliasData = [[NSMutableArray alloc] initWithCapacity: NJRQTMediaPopUpButtonMaxRecentItems + 1];
     125    [self _addRecentMediaFromAliasesData: [[NSUserDefaults standardUserDefaults] arrayForKey: [self _defaultKey]]];
     126
     127    [self registerForDraggedTypes:
     128        [NSArray arrayWithObjects: NSFilenamesPboardType, NSURLPboardType, nil]];
     129}
     130
     131- (void)dealloc;
     132{
     133    [recentMediaAliasData release]; recentMediaAliasData = nil;
     134    [otherItem release];
     135    [selectedAlias release]; [previousAlias release];
     136    [super dealloc];
     137}
     138
     139- (BDAlias *)selectedAlias;
     140{
     141    return selectedAlias;
     142}
     143
     144- (void)_setAlias:(BDAlias *)alias;
     145{
     146   
     147    BDAlias *oldAlias = [selectedAlias retain];
     148    [previousAlias release];
     149    previousAlias = oldAlias;
     150    if (selectedAlias != alias) {
     151        [selectedAlias release];
     152        selectedAlias = [alias retain];
     153    }
     154}
     155
     156- (void)_setPath:(NSString *)path;
     157{
     158    [self _setAlias: [BDAlias aliasWithPath: path]];
     159}
     160
     161- (NSMenuItem *)_itemForAlias:(BDAlias *)alias;
     162{
     163    NSString *path;
     164    SoundFile *sf;
     165    if (alias == nil) {
     166        return [self itemAtIndex: 0];
     167    }
     168
     169    // [self _validateRecentMedia];
     170    path = [alias fullPath];
     171    sf = [[SoundFileManager sharedSoundFileManager] soundFileFromPath: path];
     172    NSLog(@"_itemForAlias: %@", path);
     173
     174    // selected a system sound?
     175    if (sf != nil) {
     176        NSLog(@"_itemForAlias: selected system sound");
     177        return [self itemAtIndex: [self indexOfItemWithRepresentedObject: sf]];
     178    } else {
     179        NSEnumerator *e = [recentMediaAliasData objectEnumerator];
     180        NSData *aliasData;
     181        NSMenuItem *item;
     182        int recentIndex = 0;
     183
     184        while ( (aliasData = [e nextObject]) != nil) {
     185            // selected a recently selected, non-system sound?
     186            if ([alias aliasDataIsEqual: aliasData]) {
     187                int otherIndex = [self indexOfItem: otherItem];
     188                int menuIndex = [recentMediaAliasData count] - recentIndex + otherIndex + 1;
     189                if (menuIndex == otherIndex + 1) return [self itemAtIndex: menuIndex]; // already at top
     190                // remove item, add (at top) later
     191                NSLog(@"_itemForAlias removing item: count %d - idx %d + otherItemIndex %d + 1 = %d [%@]", [recentMediaAliasData count], recentIndex, otherIndex, menuIndex, [self itemAtIndex: menuIndex]);
     192                [self removeItemAtIndex: menuIndex];
     193                [recentMediaAliasData removeObjectAtIndex: recentIndex];
     194                break;
     195            }
     196            recentIndex++;
     197        }
     198
     199        // create the item
     200        item = [self _addRecentMediaAtPath: path withAlias: alias];
     201        [self _writeRecentMedia];
     202        return item;
     203    }
     204}
     205
     206- (void)_invalidateSelection;
     207{
     208    [self _setAlias: previousAlias];
     209    [self selectItem: [self _itemForAlias: [self selectedAlias]]];
     210}
     211
     212- (BOOL)_validatePreview;
     213{
     214    [preview stop: self];
     215    if (selectedAlias == nil) {
     216        [preview setMovie: nil];
     217        NSBeep();
     218    } else {
     219        NSMovie *movie = [[NSMovie alloc] initWithURL: [NSURL fileURLWithPath: [selectedAlias fullPath]] byReference: YES];
     220        if ([movie hasAudio])
     221            [preview setMovie: movie];
     222        else {
     223            [preview setMovie: nil];
     224            if (movie == nil) {
     225                NSBeginAlertSheet(@"Format not recognized", @"OK", nil, nil, [self window], nil, nil, nil, nil, @"The item you selected isnÕt a sound or movie recognized by QuickTime.  Please select a different item.");
     226                [self _invalidateSelection];
     227                return NO;
     228            }
     229            if (![movie hasAudio] && ![movie hasVideo]) {
     230                NSBeginAlertSheet(@"No video or audio", @"OK", nil, nil, [self window], nil, nil, nil, nil, @"Ò%@Ó contains neither audio nor video content playable by QuickTime.  Please select a different item.", [[NSFileManager defaultManager] displayNameAtPath: [selectedAlias fullPath]]);
     231                [self _invalidateSelection];
     232                [movie release];
     233                return NO;
     234            }
     235        }
     236        [movie release];
     237        [preview start: self];
     238    }
     239    return YES;
     240}
     241
     242- (IBAction)stopSoundPreview:(id)sender;
     243{
     244    [preview stop: self];
     245}
     246
     247- (void)_beepSelected:(NSMenuItem *)sender;
     248{
     249    [self _setAlias: nil];
     250    [self _validatePreview];
     251}
     252
     253- (void)_soundFileSelected:(NSMenuItem *)sender;
     254{
     255    [self _setPath: [(SoundFile *)[sender representedObject] path]];
     256    if (![self _validatePreview]) {
     257        [[self menu] removeItem: sender];
     258    }
     259}
     260
     261- (void)_aliasSelected:(NSMenuItem *)sender;
     262{
     263    BDAlias *alias = [sender representedObject];
     264    int index = [self indexOfItem: sender], otherIndex = [self indexOfItem: otherItem];
     265    [self _setAlias: alias];
     266    if (![self _validatePreview]) {
     267        [[self menu] removeItem: sender];
     268    } else if (index > otherIndex + 1) { // move "other" item to top of list
     269        int recentIndex = [recentMediaAliasData count] - index + otherIndex + 1;
     270        NSMenuItem *item = [[self itemAtIndex: index] retain];
     271        NSData *data = [[recentMediaAliasData objectAtIndex: recentIndex] retain];
     272        [self removeItemAtIndex: index];
     273        [[self menu] insertItem: item atIndex: otherIndex + 1];
     274        [self selectItem: item];
     275        [item release];
     276        NSAssert(recentIndex >= 0, @"Recent media index invalid");
     277        NSLog(@"_aliasSelected removing item %d - %d + %d + 1 = %d of recentMediaAliasData", [recentMediaAliasData count], index, otherIndex, recentIndex);
     278        [recentMediaAliasData removeObjectAtIndex: recentIndex];
     279        [recentMediaAliasData addObject: data];
     280        [data release];
     281    } else NSLog(@"_aliasSelected ...already at top");
    55282}
    56283
     
    71298}
    72299
    73 - (void)setAlias:(BDAlias *)alias;
    74 {
    75     if (selectedAlias != alias) {
    76         [selectedAlias release];
    77         selectedAlias = [alias retain];
    78     }
    79 }
    80 
    81 - (void)setPath:(NSString *)path;
    82 {
    83     [self setAlias: [BDAlias aliasWithPath: path]];
    84 }
    85 
    86 - (BDAlias *)selectedAlias;
    87 {
    88     return selectedAlias;
    89 }
    90 
    91 
    92300- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
    93301{
     
    97305        NSArray *files = [sheet filenames];
    98306        NSAssert1([files count] == 1, @"%d items returned, only one expected", [files count]);
    99         [self setPath: [files objectAtIndex: 0]];
    100         if ([self _previewSound]) {
    101             NSString *path = [selectedAlias fullPath];
    102             SoundFile *sf = [[SoundFileManager sharedSoundFileManager] soundFileFromPath: path];
    103             if (sf != nil) {
    104                 [self selectItemAtIndex: [self indexOfItemWithRepresentedObject: sf]];
    105             } else {
    106                 NSString *title = [[NSFileManager defaultManager] displayNameAtPath: path];
    107                 NSMenuItem *item = [[self menu] addItemWithTitle: title action: @selector(_aliasSelected:) keyEquivalent: @""];
    108                 [item setTarget: self];
    109                 [item setRepresentedObject: selectedAlias];
    110                 [item setImage: [[[NSWorkspace sharedWorkspace] iconForFile: path] bestFitImageForSize: NSMakeSize(16, 16)]];
    111                 [self selectItem: item];
    112             }
    113         }
    114     }
    115 }
    116 
    117 - (void)_beepSelected:(NSMenuItem *)sender;
    118 {
    119     [self setAlias: nil];
    120     [self _previewSound];
    121 }
    122 
    123 - (void)_soundFileSelected:(NSMenuItem *)sender;
    124 {
    125     [self setPath: [(SoundFile *)[sender representedObject] path]];
    126     [self _previewSound];
    127 }
    128 
    129 - (void)_aliasSelected:(NSMenuItem *)sender;
    130 {
    131     [self setAlias: [sender representedObject]];
    132     [self _previewSound];
    133 }
    134 
    135 - (void)_invalidateSoundSelection;
    136 {
    137     [self setAlias: nil];
    138     [self selectItemAtIndex: 0];
    139 }
    140 
    141 - (IBAction)stopSoundPreview:(id)sender;
    142 {
    143     [preview stop: self];
    144 }
    145 
    146 - (BOOL)_previewSound;
    147 {
    148     [preview stop: self];
    149     if (selectedAlias == nil) {
    150         [preview setMovie: nil];
    151         NSBeep();
     307        [self _setPath: [files objectAtIndex: 0]];
     308        if ([self _validatePreview]) {
     309            [self selectItem: [self _itemForAlias: selectedAlias]];
     310        }
    152311    } else {
    153         NSMovie *movie = [[NSMovie alloc] initWithURL: [NSURL fileURLWithPath: [selectedAlias fullPath]] byReference: YES];
    154         if ([movie hasAudio])
    155             [preview setMovie: movie];
    156         else {
    157             [preview setMovie: nil];
    158             if (movie == nil) {
    159                 NSBeginAlertSheet(@"Format not recognized", @"OK", nil, nil, [self window], nil, nil, nil, nil, @"The item you selected isnÕt a sound or movie recognized by QuickTime.  Please select a different item.");
    160                 [self _invalidateSoundSelection];
    161                 return NO;
    162             }
    163             if (![movie hasAudio] && ![movie hasVideo]) {
    164                 NSBeginAlertSheet(@"No video or audio", @"OK", nil, nil, [self window], nil, nil, nil, nil, @"Ò%@Ó contains neither audio nor video content playable by QuickTime.  Please select a different item.", [[NSFileManager defaultManager] displayNameAtPath: [selectedAlias fullPath]]);
    165                 [self _invalidateSoundSelection];
    166                 [movie release];
    167                 return NO;
    168             }
    169         }
    170         [movie release];
    171         [preview start: self];
    172     }
     312        // "Other..." item is still selected, revert to previously selected item
     313        // XXX issue with cancelling, top item in recent menu is sometimes duplicated!?
     314        [self selectItem: [self _itemForAlias: selectedAlias]];
     315    }
     316    // [self _validateRecentMedia];
     317}
     318
     319@end
     320
     321@implementation NJRQTMediaPopUpButton (NSDraggingDestination)
     322
     323- (BOOL)acceptsDragFrom:(id <NSDraggingInfo>)sender;
     324{
     325    NSURL *url = [NSURL URLFromPasteboard: [sender draggingPasteboard]];
     326
     327    if (url == nil || ![url isFileURL]) return NO;
    173328    return YES;
    174329}
    175330
     331- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender;
     332{
     333    if ([self acceptsDragFrom: sender] && [sender draggingSourceOperationMask] &
     334        NSDragOperationCopy) {
     335        dragAccepted = YES;
     336        [self setNeedsDisplay: YES];
     337        return NSDragOperationGeneric;
     338    }
     339    return NSDragOperationNone;
     340}
     341
     342- (void)draggingExited:(id <NSDraggingInfo>)sender;
     343{
     344    dragAccepted = NO;
     345    [self setNeedsDisplay: YES];
     346}
     347
     348- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender;
     349{
     350    dragAccepted = NO;
     351    [self setNeedsDisplay: YES];
     352    return [self acceptsDragFrom: sender];
     353}
     354
     355- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender;
     356{
     357    if ([sender draggingSource] != self) {
     358        NSURL *url = [NSURL URLFromPasteboard: [sender draggingPasteboard]];
     359        if (url == nil) return NO;
     360        [self _setPath: [url path]];
     361        [self _validatePreview];
     362    }
     363    return YES;
     364}
     365
    176366@end
Note: See TracChangeset for help on using the changeset viewer.