Changeset 6365
- Timestamp:
- 11/29/08 16:33:13 (1 month ago)
- Files:
-
- trunk/Spiral/AppleTV.tiff (added)
- trunk/Spiral/English.lproj/Export.nib (added)
- trunk/Spiral/English.lproj/Export.nib/designable.nib (added)
- trunk/Spiral/English.lproj/Export.nib/keyedobjects.nib (added)
- trunk/Spiral/English.lproj/Playlist.nib/classes.nib (modified) (2 diffs)
- trunk/Spiral/English.lproj/Playlist.nib/info.nib (modified) (1 diff)
- trunk/Spiral/English.lproj/Playlist.nib/keyedobjects.nib (modified) (previous)
- trunk/Spiral/PlaylistExportGroup.icns (added)
- trunk/Spiral/SPApplicationController.m (modified) (4 diffs)
- trunk/Spiral/SPExportCell.h (added)
- trunk/Spiral/SPExportCell.m (added)
- trunk/Spiral/SPExportController.h (added)
- trunk/Spiral/SPExportController.m (added)
- trunk/Spiral/SPExportJob.h (added)
- trunk/Spiral/SPExportJob.m (added)
- trunk/Spiral/SPPlaylistController.h (modified) (6 diffs)
- trunk/Spiral/SPPlaylistController.m (modified) (37 diffs)
- trunk/Spiral/SPPlaylistItem.h (modified) (6 diffs)
- trunk/Spiral/SPPlaylistItem.m (modified) (15 diffs)
- trunk/Spiral/SPSettings.h (modified) (1 diff)
- trunk/Spiral/SPSettings.m (modified) (2 diffs)
- trunk/Spiral/Spiral.xcodeproj/project.pbxproj (modified) (25 diffs)
- trunk/Spiral/StopExport.tiff (added)
- trunk/Spiral/StopExportPressed.tiff (added)
- trunk/Spiral/iPhone.tiff (added)
- trunk/Spiral/iPod.tiff (added)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/Spiral/English.lproj/Playlist.nib/classes.nib
r5121 r6365 62 62 <key>browseInFullscreen</key> 63 63 <string>id</string> 64 <key>destination</key> 65 <string>id</string> 66 <key>format</key> 67 <string>id</string> 64 68 <key>fullscreen</key> 69 <string>id</string> 70 <key>newExportGroup</key> 65 71 <string>id</string> 66 72 <key>newGroup</key> … … 93 99 <key>_drillMovieView</key> 94 100 <string>QTMovieView</string> 101 <key>_exportGroupDestinationPopUpButton</key> 102 <string>NSPopUpButton</string> 103 <key>_exportGroupDirectoryMenuItem</key> 104 <string>NSMenuItem</string> 105 <key>_exportGroupFormatPopUpButton</key> 106 <string>NSPopUpButton</string> 107 <key>_exportGroupNameTextField</key> 108 <string>NSTextField</string> 109 <key>_exportGroupPanel</key> 110 <string>NSPanel</string> 111 <key>_exportGroupSameAsOriginalMenuItem</key> 112 <string>NSMenuItem</string> 113 <key>_exportGroupiTunesMenuItem</key> 114 <string>NSMenuItem</string> 95 115 <key>_filesTableColumn</key> 96 116 <string>NSTableColumn</string> trunk/Spiral/English.lproj/Playlist.nib/info.nib
r6308 r6365 12 12 <array> 13 13 <integer>6</integer> 14 <integer>252</integer> 15 <integer>97</integer> 14 16 </array> 15 17 <key>IBSystem Version</key> trunk/Spiral/SPApplicationController.m
r6359 r6365 30 30 #import "SPApplicationController.h" 31 31 #import "SPDrillController.h" 32 #import "SPExportController.h" 32 33 #import "SPInspectorController.h" 33 34 #import "SPMobileRemote.h" … … 376 377 - (void)applicationWillResignActive:(NSNotification *)notification { 377 378 [[SPAppleRemote sharedRemote] stopListening]; 379 } 380 381 382 383 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { 384 if([[SPExportController exportController] numberOfExports] > 0 || 385 [[SPPlaylistController playlistController] numberOfExports] > 0) { 386 return [(WIApplication *) NSApp runTerminationDelayPanelWithTimeInterval:30.0 message:NSLS(@"There are unfinished exports. Quitting now will terminate them.", @"Quit warning")]; 387 } 388 389 return NSTerminateNow; 378 390 } 379 391 … … 489 501 delegate = [[NSApp keyWindow] delegate]; 490 502 491 if([delegate isKindOfClass:[SPPlayerController class]]) 492 return YES; 493 else if([delegate isKindOfClass:[SPPlaylistController class]]) 494 return ([[delegate selectedFiles] count] == 1); 503 return [delegate isKindOfClass:[SPPlayerController class]]; 495 504 } 496 505 … … 787 796 788 797 - (IBAction)export:(id)sender { 789 NSArray *files; 790 QTMovie *movie; 791 id delegate; 798 SPMovieController *controller; 799 id delegate; 792 800 793 801 delegate = [[NSApp keyWindow] delegate]; 794 802 795 803 if([delegate isKindOfClass:[SPPlayerController class]]) { 796 movie = [[(SPPlayerController *) delegate movieController] movie]; 797 798 NSLog(@"export %@", movie); 799 } 800 else if([delegate isKindOfClass:[SPPlaylistController class]]) { 801 files = [delegate selectedFiles]; 802 803 if([files count] == 1) 804 NSLog(@"export %@", [files objectAtIndex:0]); 804 controller = [(SPPlayerController *) delegate movieController]; 805 806 [[SPExportController exportController] beginSavePanelForWindow:[delegate window] 807 movie:[controller movie] 808 playlistFile:[controller playlistFile]]; 805 809 } 806 810 } trunk/Spiral/SPPlaylistController.h
r6359 r6365 27 27 */ 28 28 29 #import "SPExportJob.h" 29 30 #import "SPPlaylistLoader.h" 30 31 … … 39 40 @class SPFullscreenWindow, SPPlaylistGroup, SPPlaylistFile, SPPlaylistLoader; 40 41 41 @interface SPPlaylistController : WIWindowController <SPPlaylistLoaderDelegate > {42 @interface SPPlaylistController : WIWindowController <SPPlaylistLoaderDelegate, SPExportJobDelegate> { 42 43 IBOutlet WIOutlineView *_outlineView; 43 44 IBOutlet NSTableColumn *_filesTableColumn; … … 60 61 IBOutlet NSPredicateEditor *_predicateEditor; 61 62 63 IBOutlet NSPanel *_exportGroupPanel; 64 IBOutlet NSTextField *_exportGroupNameTextField; 65 IBOutlet NSPopUpButton *_exportGroupFormatPopUpButton; 66 IBOutlet NSPopUpButton *_exportGroupDestinationPopUpButton; 67 IBOutlet NSMenuItem *_exportGroupSameAsOriginalMenuItem; 68 IBOutlet NSMenuItem *_exportGroupiTunesMenuItem; 69 IBOutlet NSMenuItem *_exportGroupDirectoryMenuItem; 70 62 71 SPPlaylistGroup *_playlist; 63 72 SPPlaylistGroup *_recentPlaylist; 64 73 65 74 SPPlaylistLoader *_loader; 75 76 NSUInteger _exports; 77 NSMutableArray *_exportQueue; 66 78 67 79 SPPlaylistRepeatMode _repeatMode; … … 80 92 - (void)setShuffle:(BOOL)shuffle; 81 93 - (BOOL)shuffle; 94 - (NSUInteger)numberOfExports; 82 95 83 96 - (void)openSelection; … … 90 103 - (IBAction)newGroup:(id)sender; 91 104 - (IBAction)newSmartGroup:(id)sender; 105 - (IBAction)newExportGroup:(id)sender; 106 - (IBAction)format:(id)sender; 107 - (IBAction)destination:(id)sender; 92 108 - (IBAction)remove:(id)sender; 93 109 - (IBAction)revealInFinder:(id)sender; … … 98 114 - (IBAction)browseInFullscreen:(id)sender; 99 115 100 - (NSArray *)selectedFiles;101 116 - (SPPlaylistFile *)previousFileForFile:(SPPlaylistFile *)file; 102 117 - (SPPlaylistFile *)nextFileForFile:(SPPlaylistFile *)file; trunk/Spiral/SPPlaylistController.m
r6359 r6365 58 58 - (void)_setShuffle:(BOOL)shuffle; 59 59 60 - (void)_setExportGroupDirectory:(NSString *)path; 61 - (void)_startNextExportJob; 62 60 63 - (void)_validate; 61 64 … … 66 69 67 70 + (SPPlaylistGroup *)_defaultPlaylist { 68 SPPlaylistGroup *playlist, *group; 71 SPPlaylistGroup *playlist, *group; 72 SPPlaylistExportGroup *exportGroup; 69 73 70 74 playlist = [[SPPlaylistGroup alloc] initWithName:@"<SPPlaylist>"]; … … 75 79 76 80 [playlist addItem:group]; 81 82 exportGroup = [SPPlaylistExportGroup exportGroupWithName:NSLS(@"Export for iPhone", @"Playlist export group name")]; 83 [exportGroup setFormat:SPExportiPhone]; 84 85 [playlist addItem:exportGroup]; 77 86 78 87 return [playlist autorelease]; … … 132 141 133 142 - (void)_reloadItem:(id)item { 143 NSString *name, *path, *destinationPath; 144 SPExportJob *job; 145 id exportItem; 146 NSUInteger counter; 147 134 148 if([item isKindOfClass:[SPPlaylistFolder class]]) { 135 149 if(![item isLoading]) { … … 146 160 } 147 161 } 162 else if([item isKindOfClass:[SPPlaylistExportGroup class]]) { 163 for(exportItem in [item items]) { 164 if([exportItem isKindOfClass:[SPPlaylistExportItem class]]) { 165 if(![exportItem job]) { 166 name = [[[exportItem path] lastPathComponent] stringByDeletingPathExtension]; 167 168 if([item destination] == SPPlaylistExportToiTunes) { 169 destinationPath = [NSFileManager temporaryPathWithPrefix:name]; 170 171 [[NSFileManager defaultManager] createDirectoryAtPath:destinationPath]; 172 173 path = [destinationPath stringByAppendingPathComponent:[name stringByAppendingPathExtension:@"mp4"]]; 174 } else { 175 if([item destination] == SPPlaylistExportToOriginalPath) 176 destinationPath = [[exportItem path] stringByDeletingLastPathComponent]; 177 else 178 destinationPath = [item destinationPath]; 179 180 path = [destinationPath stringByAppendingPathComponent:[name stringByAppendingPathExtension:@"mp4"]]; 181 counter = 2; 182 183 while([[NSFileManager defaultManager] fileExistsAtPath:path]) { 184 path = [destinationPath stringByAppendingPathComponent: 185 [[NSSWF:@"%@ %u", name, counter++] stringByAppendingPathExtension:@"mp4"]]; 186 } 187 } 188 189 job = [SPExportJob exportJobWithPath:[exportItem path] 190 file:path 191 format:[(SPPlaylistExportGroup *) item format]]; 192 [job setDelegate:self]; 193 [job setPlaylistItem:exportItem]; 194 195 [exportItem setDestinationPath:path]; 196 [exportItem setJob:job]; 197 198 if(_exports >= [[NSProcessInfo processInfo] processorCount]) { 199 [_exportQueue addObject:job]; 200 } else { 201 _exports++; 202 [job start]; 203 } 204 } 205 } 206 } 207 208 if(![item isLoading]) { 209 _spinners++; 210 [_progressIndicator startAnimation:self]; 211 [_loader loadMetadataOfItemsInContainer:item synchronously:NO]; 212 } 213 } 148 214 else if([item isKindOfClass:[SPPlaylistGroup class]]) { 149 215 if(![item isLoading]) { … … 162 228 for(item in items) { 163 229 if([item isExpanded]) { 164 [self _reloadItem:item];165 166 230 [_outlineView expandItem:item]; 167 231 … … 231 295 #pragma mark - 232 296 297 - (void)_setExportGroupDirectory:(NSString *)path { 298 NSImage *image; 299 300 image = [[NSWorkspace sharedWorkspace] iconForFile:path]; 301 [image setSize:NSMakeSize(16.0, 16.0)]; 302 303 [_exportGroupDirectoryMenuItem setTitle:[[NSFileManager defaultManager] displayNameAtPath:path]]; 304 [_exportGroupDirectoryMenuItem setImage:image]; 305 [_exportGroupDirectoryMenuItem setRepresentedObject:path]; 306 } 307 308 309 310 - (void)_startNextExportJob { 311 SPExportJob *job; 312 313 if([_exportQueue count] > 0) { 314 job = [[[_exportQueue objectAtIndex:0] retain] autorelease]; 315 [_exportQueue removeObjectAtIndex:0]; 316 _exports++; 317 [job start]; 318 } 319 } 320 321 322 323 - (BOOL)_launchiTunesAndImportFile:(NSString *)path error:(NSError **)error { 324 NSDictionary *application; 325 FSRef fsRef; 326 AliasHandle alias; 327 AppleEvent request, reply; 328 AEBuildError buildError; 329 OSType iTunesSignature = 'hook'; 330 OSStatus status; 331 BOOL running = NO; 332 const char *event = 333 "'insh':'obj '{form: indx, want: type(cLiP), seld: long(1), from:'null'()}, '----':alis (@@)"; 334 335 for(application in [[NSWorkspace sharedWorkspace] launchedApplications]) { 336 if([[application objectForKey:@"NSApplicationName"] isEqualToString:@"iTunes"]) { 337 running = YES; 338 339 break; 340 } 341 } 342 343 [[NSWorkspace sharedWorkspace] launchApplication:@"iTunes"]; 344 345 if(!running) 346 [NSThread sleepForTimeInterval:10.0]; 347 348 status = FSPathMakeRef((UInt8 *) [path fileSystemRepresentation], &fsRef, NULL); 349 350 if(status != noErr) { 351 *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:status]; 352 353 return NO; 354 } 355 356 status = FSNewAlias(NULL, &fsRef, &alias); 357 358 if(status != noErr) { 359 *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:status]; 360 361 return NO; 362 } 363 364 status = AEBuildAppleEvent('hook', 365 'Add ', 366 typeApplSignature, 367 &iTunesSignature, 368 sizeof(iTunesSignature), 369 kAutoGenerateReturnID, 370 kAnyTransactionID, 371 &request, 372 &buildError, 373 event, 374 alias); 375 376 if(status == noErr) { 377 status = AESendMessage(&request, &reply, kAEWaitReply, kAEDefaultTimeout); 378 379 if(status == noErr) 380 AEDisposeDesc(&reply); 381 else 382 *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:status]; 383 } else { 384 *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:status]; 385 } 386 387 AEDisposeDesc(&request); 388 DisposeHandle((Handle) alias); 389 390 return (status == noErr); 391 } 392 393 394 395 #pragma mark - 396 233 397 - (void)_validate { 234 [_removeButton setEnabled:([self _selectedItem] && ![[self _selectedItem] isRepresented])];398 [_removeButton setEnabled:([self _selectedItem] != NULL)]; 235 399 } 236 400 … … 259 423 _loader = [[SPPlaylistLoader alloc] init]; 260 424 [_loader setDelegate:self]; 425 426 _exportQueue = [[NSMutableArray alloc] init]; 261 427 262 428 _simplifyFilenames = [SPSettings boolForKey:SPSimplifyFilenames]; … … 267 433 name:NSApplicationWillTerminateNotification]; 268 434 269 [[[ NSWorkspace sharedWorkspace] notificationCenter]435 [[[WIEventQueue sharedQueue] notificationCenter] 270 436 addObserver:self 271 437 selector:@selector(eventFileWrite:) … … 297 463 [_eventQueueItems release]; 298 464 465 [_exportQueue release]; 466 299 467 [_loader release]; 300 468 … … 307 475 308 476 - (void)windowDidLoad { 477 NSImage *icon; 309 478 NSData *data; 310 479 SPPlaylistCell *cell; … … 347 516 [self _restoreExpansionStateForItems:[_playlist items]]; 348 517 349 [[_actionPopUpButton cell] setArrowPosition:NSPopUpNoArrow];350 [ [[_actionPopUpButton menu] itemAtIndex:[_actionPopUpButton indexOfSelectedItem]] setState:NSOffState];351 [_ actionPopUpButton setImagePosition:NSNoImage];518 icon = [[NSWorkspace sharedWorkspace] iconForFile:[[NSWorkspace sharedWorkspace] fullPathForApplication:@"iTunes"]]; 519 [icon setSize:NSMakeSize(16.0, 16.0)]; 520 [_exportGroupiTunesMenuItem setImage:icon]; 352 521 353 522 [self _setRepeatMode:[SPSettings intForKey:SPPlaylistRepeat]]; … … 441 610 442 611 612 - (void)exportJobProgressed:(SPExportJob *)job { 613 [_outlineView display]; 614 } 615 616 617 618 - (void)exportJobCompleted:(SPExportJob *)job { 619 NSString *path; 620 NSError *error; 621 SPPlaylistExportGroup *group; 622 SPPlaylistExportItem *item; 623 SPPlaylistFile *newItem; 624 NSUInteger index; 625 626 item = [job playlistItem]; 627 group = [item parentItem]; 628 path = [item destinationPath]; 629 index = [[group items] indexOfObject:item]; 630 631 [group removeItem:item]; 632 633 if([group destination] == SPPlaylistExportToiTunes) { 634 if(![self _launchiTunesAndImportFile:path error:&error]) 635 [[error alert] beginSheetModalForWindow:[self window] modalDelegate:NULL didEndSelector:NULL contextInfo:NULL]; 636 637 [[NSFileManager defaultManager] removeItemAtPath:[path stringByDeletingLastPathComponent] error:NULL]; 638 } else { 639 newItem = [SPPlaylistFile fileWithPath:path]; 640 641 if(index >= 0 && (NSUInteger) index < [group numberOfItems]) 642 [group insertItem:newItem atIndex:index]; 643 else 644 [group addItem:newItem]; 645 } 646 647 [_outlineView reloadData]; 648 649 [self _reloadItem:group]; 650 651 _exports--; 652 653 [self _startNextExportJob]; 654 } 655 656 657 658 - (void)exportJobStopped:(SPExportJob *)job { 659 _exports--; 660 661 [self _startNextExportJob]; 662 } 663 664 665 666 - (void)exportJob:(SPExportJob *)job failedWithError:(NSError *)error { 667 SPPlaylistExportGroup *group; 668 SPPlaylistExportItem *item; 669 670 [[error alert] beginSheetModalForWindow:[self window] modalDelegate:NULL didEndSelector:NULL contextInfo:NULL]; 671 672 item = [job playlistItem]; 673 group = [item parentItem]; 674 675 [group removeItem:item]; 676 677 [_outlineView reloadData]; 678 679 _exports--; 680 681 [self _startNextExportJob]; 682 } 683 684 685 443 686 - (void)preferencesDidChange:(NSNotification *)notification { 444 687 _simplifyFilenames = [SPSettings boolForKey:SPSimplifyFilenames]; … … 454 697 455 698 - (void)movieControllerViewCountChanged:(NSNotification *)notification { 456 [_outlineView setNeedsDisplay ];699 [_outlineView setNeedsDisplay:YES]; 457 700 } 458 701 … … 471 714 return (item != NULL && [item isInFileSystem]); 472 715 else if(selector == @selector(remove:)) 473 return (item != NULL && ![item isRepresented]);716 return (item != NULL); 474 717 475 718 return YES; … … 540 783 541 784 785 - (NSUInteger)numberOfExports { 786 return _exports + [_exportQueue count]; 787 } 788 789 790 542 791 #pragma mark - 543 792 … … 638 887 contextInfo:[item retain]]; 639 888 } 889 else if([item isKindOfClass:[SPPlaylistExportGroup class]]) { 890 [_exportGroupNameTextField setStringValue:[item name]]; 891 [_exportGroupFormatPopUpButton selectItemWithTag:[(SPPlaylistExportGroup *) item format]]; 892 [_exportGroupDestinationPopUpButton selectItemWithTag:[item destination]]; 893 894 if([item destinationPath]) 895 [self _setExportGroupDirectory:[item destinationPath]]; 896 else 897 [self _setExportGroupDirectory:[@"~/Desktop" stringByExpandingTildeInPath]]; 898 899 [NSApp beginSheet:_exportGroupPanel 900 modalForWindow:[self window] 901 modalDelegate:self 902 didEndSelector:@selector(editExportGroupSheetDidEnd:returnCode:contextInfo:) 903 contextInfo:[item retain]]; 904 } 640 905 } 641 906 … … 651 916 if([_outlineView isItemExpanded:smartGroup]) 652 917 [self _reloadItem:smartGroup]; 918 919 [self _savePlaylist]; 653 920 } 654 921 655 922 [smartGroup release]; 656 923 [_smartGroupPanel close]; 924 } 925 926 927 928 - (void)editExportGroupSheetDidEnd:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo { 929 SPPlaylistExportGroup *exportGroup = contextInfo; 930 931 if(returnCode == NSAlertDefaultReturn) { 932 [exportGroup setName:[_exportGroupNameTextField stringValue]]; 933 [exportGroup setFormat:[_exportGroupFormatPopUpButton tagOfSelectedItem]]; 934 [exportGroup setDestination:[_exportGroupDestinationPopUpButton tagOfSelectedItem]]; 935 [exportGroup setDestinationPath:[_exportGroupDestinationPopUpButton representedObjectOfSelectedItem]]; 936 937 [self _savePlaylist]; 938 } 939 940 [exportGroup release]; 941 [_exportGroupPanel close]; 657 942 } 658 943 … … 683 968 NSString *path; 684 969 id item, newItem; 970 BOOL exportGroup; 685 971 686 972 if(returnCode == NSOKButton) { … … 692 978 if(!item) 693 979 item = _playlist; 980 981 exportGroup = [item isKindOfClass:[SPPlaylistExportGroup class]]; 694 982 695 983 items = [NSMutableArray array]; … … 698 986 if([[NSFileManager defaultManager] directoryExistsAtPath:path]) 699 987 newItem = [SPPlaylistFolder folderWithPath:path]; 988 else if(exportGroup) 989 newItem = [SPPlaylistExportItem exportItemWithPath:path]; 700 990 else 701 991 newItem = [SPPlaylistFile fileWithPath:path]; … … 803 1093 804 1094 1095 - (IBAction)newExportGroup:(id)sender { 1096 [_exportGroupNameTextField setStringValue:NSLS(@"Export for iPhone", @"Playlist export group name")]; 1097 1098 [self _setExportGroupDirectory:[@"~/Desktop" stringByExpandingTildeInPath]]; 1099 1100 [_exportGroupDestinationPopUpButton selectItem:_exportGroupSameAsOriginalMenuItem]; 1101 1102 [NSApp beginSheet:_exportGroupPanel 1103 modalForWindow:[self window] 1104 modalDelegate:self 1105 didEndSelector:@selector(newExportGroupSheetDidEnd:returnCode:contextInfo:) 1106 contextInfo:NULL]; 1107 } 1108 1109 1110 1111 - (void)newExportGroupSheetDidEnd:(NSWindow *)window returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo { 1112 SPPlaylistExportGroup *exportGroup; 1113 id item; 1114 NSInteger row; 1115 1116 if(returnCode == NSAlertDefaultReturn) { 1117 exportGroup = [SPPlaylistExportGroup exportGroupWithName:[_exportGroupNameTextField stringValue]]; 1118 [exportGroup setFormat:[_exportGroupFormatPopUpButton tagOfSelectedItem]]; 1119 [exportGroup setDestination:[_exportGroupDestinationPopUpButton tagOfSelectedItem]]; 1120 [exportGroup setDestinationPath:[_exportGroupDestinationPopUpButton representedObjectOfSelectedItem]]; 1121 1122 item = [self _selectedItem]; 1123 1124 while(item && ![item isKindOfClass:[SPPlaylistGroup class]]) 1125 item = [item parentItem]; 1126 1127 if(!item) 1128 item = _playlist; 1129 1130 [(SPPlaylistGroup *) item addItem:exportGroup]; 1131 1132 [_outlineView expandItem:item]; 1133 [_outlineView reloadData]; 1134 1135 row = [_outlineView rowForItem:exportGroup]; 1136 1137 if(row >= 0) 1138 [_outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO]; 1139 1140 [self _savePlaylist]; 1141 } 1142 1143 [_exportGroupPanel close]; 1144 } 1145 1146 1147 1148 - (IBAction)format:(id)sender { 1149 NSMutableString *string; 1150 NSMenuItem *item; 1151 1152 string = [[_exportGroupNameTextField stringValue] mutableCopy]; 1153 1154 for(item in [_exportGroupFormatPopUpButton itemArray]) 1155 [string replaceOccurrencesOfString:[item title] withString:[_exportGroupFormatPopUpButton titleOfSelectedItem]]; 1156 1157 [_exportGroupNameTextField setStringValue:string]; 1158 [string release]; 1159 } 1160 1161 1162 1163 - (IBAction)destination:(id)sender { 1164 NSOpenPanel *openPanel; 1165 1166 openPanel = [NSOpenPanel openPanel]; 1167 [openPanel setCanChooseFiles:NO]; 1168 [openPanel setCanChooseDirectories:YES]; 1169 [openPanel setPrompt:NSLS(@"Select", @"Export destination open panel button")]; 1170 1171 if([openPanel runModalForDirectory:NULL file:NULL types:NULL] == NSOKButton) { 1172 [self _setExportGroupDirectory:[openPanel filename]]; 1173 1174 [_exportGroupDestinationPopUpButton selectItem:_exportGroupDirectoryMenuItem]; 1175 } 1176 } 1177 1178 1179 805 1180 - (IBAction)remove:(id)sender { 806 NSString *path; 807 id item; 1181 NSMutableDictionary *paths; 1182 NSMutableArray *files, *names; 1183 NSAlert *alert; 1184 NSString *path, *title; 1185 id item, exportItem; 1186 1187 files = [NSMutableArray array]; 808 1188 809 1189 for(item in [[self _selectedItems] reversedArray]) { 810 if(![item isRepresented]) { 1190 if([item isRepresented]) { 1191 [files addObject:item]; 1192 } else { 811 1193 if([item isKindOfClass:[SPPlaylistFolder class]]) { 812 1194 path = [item resolvedPath]; … … 816 1198 [_eventQueueItems removeObjectForKey:path]; 817 1199 } 1200 else if([item isKindOfClass:[SPPlaylistExportGroup class]]) { 1201 for(exportItem in [item items]) { 1202 if([exportItem isKindOfClass:[SPPlaylistExportItem class]]) 1203 [[exportItem job] stop]; 1204 } 1205 } 1206 else if([item isKindOfClass:[SPPlaylistExportItem class]]) { 1207 [[item job] stop]; 1208 } 818 1209 819 1210 [(SPPlaylistGroup *) [item parentItem] removeItem:item]; 1211 } 1212 } 1213 1214 if([files count] > 0) { 1215 if([files count] == 1) { 1216 title = [NSSWF:NSLS(@"Are you sure you want to move \"%@\" to Trash?", @"Remove file dialog title (filename)"), 1217 [[files objectAtIndex:0] name]]; 1218 } else { 1219 title = [NSSWF:NSLS(@"Are you sure you want to move %lu items to Trash?", @"Remove file dialog title (count)"), 1220 [files count]]; 1221 } 1222 1223 alert = [NSAlert alertWithMessageText:title 1224 defaultButton:NSLS(@"OK", @"Remove file dialog button") 1225 alternateButton:NSLS(@"Cancel", @"Remove file dialog button") 1226 otherButton:NULL informativeTextWithFormat:@""]; 1227 1228 if([alert runModal] == NSAlertDefaultReturn) { 1229 paths = [NSMutableDictionary dictionary]; 1230 1231 for(item in files) { 1232 path = [[item resolvedPath] stringByDeletingLastPathComponent]; 1233 names = [paths objectForKey:path]; 1234 1235 if(!names) { 1236 names = [NSMutableArray array]; 1237 [paths setObject:names forKey:path]; 1238 } 1239 1240 [names addObject:[item name]]; 1241 } 1242 1243 for(path in paths) { 1244 names = [paths objectForKey:path]; 1245 1246 [[NSWorkspace sharedWorkspace] 1247 performFileOperation:NSWorkspaceRecycleOperation 1248  
