Changeset 39 for trunk/Cocoa/Pester/Source/NJRQTMediaPopUpButton.m
- Timestamp:
- 11/04/02 20:23:02 (22 years ago)
- File:
-
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
trunk/Cocoa/Pester/Source/NJRQTMediaPopUpButton.m
r34 r39 12 12 #import "NSImage-NJRExtensions.h" 13 13 14 static const int NJRQTMediaPopUpButtonMaxRecentItems = 10; 15 14 16 @interface NJRQTMediaPopUpButton (Private) 15 - (BOOL)_previewSound; 17 - (void)_setPath:(NSString *)path; 18 - (BOOL)_validatePreview; 16 19 @end 17 20 … … 19 22 20 23 // 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 } 24 91 25 92 - (void)awakeFromNib; … … 29 96 SoundFileManager *sfm = [SoundFileManager sharedSoundFileManager]; 30 97 int soundCount = [sfm count]; 31 98 32 99 [self removeAllItems]; 33 100 menu = [self menu]; … … 53 120 item = [menu addItemWithTitle: @"OtherÉ" action: @selector(select:) keyEquivalent: @""]; 54 121 [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"); 55 282 } 56 283 … … 71 298 } 72 299 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 92 300 - (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo; 93 301 { … … 97 305 NSArray *files = [sheet filenames]; 98 306 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 } 152 311 } 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; 173 328 return YES; 174 329 } 175 330 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 176 366 @end
Note:
See TracChangeset
for help on using the changeset viewer.