00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #include <stdlib.h>
00041 #include <sys/param.h>
00042 #include <string.h>
00043 #include <math.h>
00044 #include <sys/mount.h>
00045 #include <vlc_keys.h>
00046
00047 #include "intf.h"
00048 #import "wizard.h"
00049 #import "bookmarks.h"
00050 #include "playlist.h"
00051 #include "controls.h"
00052 #include "vlc_osd.h"
00053 #include "misc.h"
00054
00055
00056
00057
00058 @implementation VLCPlaylistView
00059
00060 - (NSMenu *)menuForEvent:(NSEvent *)o_event
00061 {
00062 return( [[self delegate] menuForEvent: o_event] );
00063 }
00064
00065 - (void)keyDown:(NSEvent *)o_event
00066 {
00067 unichar key = 0;
00068
00069 if( [[o_event characters] length] )
00070 {
00071 key = [[o_event characters] characterAtIndex: 0];
00072 }
00073
00074 switch( key )
00075 {
00076 case NSDeleteCharacter:
00077 case NSDeleteFunctionKey:
00078 case NSDeleteCharFunctionKey:
00079 case NSBackspaceCharacter:
00080 [[self delegate] deleteItem:self];
00081 break;
00082
00083 case NSEnterCharacter:
00084 case NSCarriageReturnCharacter:
00085 [(VLCPlaylist *)[[VLCMain sharedInstance] getPlaylist]
00086 playItem:self];
00087 break;
00088
00089 default:
00090 [super keyDown: o_event];
00091 break;
00092 }
00093 }
00094
00095 @end
00096
00097
00098
00099
00100
00101
00102
00103
00104 @implementation VLCPlaylistCommon
00105
00106 - (id)init
00107 {
00108 self = [super init];
00109 if ( self != nil )
00110 {
00111 o_outline_dict = [[NSMutableDictionary alloc] init];
00112 }
00113 return self;
00114 }
00115 - (void)awakeFromNib
00116 {
00117 playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
00118 FIND_ANYWHERE );
00119 i_current_view = VIEW_CATEGORY;
00120 playlist_ViewUpdate( p_playlist, i_current_view );
00121
00122 [o_outline_view setTarget: self];
00123 [o_outline_view setDelegate: self];
00124 [o_outline_view setDataSource: self];
00125
00126 vlc_object_release( p_playlist );
00127 [self initStrings];
00128 }
00129
00130 - (void)initStrings
00131 {
00132 [[o_tc_name headerCell] setStringValue:_NS("Name")];
00133 [[o_tc_author headerCell] setStringValue:_NS("Author")];
00134 [[o_tc_duration headerCell] setStringValue:_NS("Duration")];
00135 }
00136
00137 - (NSOutlineView *)outlineView
00138 {
00139 return o_outline_view;
00140 }
00141
00142 - (playlist_item_t *)selectedPlaylistItem
00143 {
00144 return [[o_outline_view itemAtRow: [o_outline_view selectedRow]]
00145 pointerValue];
00146 }
00147
00148 @end
00149
00150 @implementation VLCPlaylistCommon (NSOutlineViewDataSource)
00151
00152
00153 - (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
00154 {
00155 int i_return = 0;
00156 playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
00157 FIND_ANYWHERE );
00158 if( p_playlist == NULL )
00159 return 0;
00160 if( outlineView != o_outline_view )
00161 {
00162 vlc_object_release( p_playlist );
00163 return 0;
00164 }
00165
00166 if( item == nil )
00167 {
00168
00169 playlist_view_t *p_view;
00170 p_view = playlist_ViewFind( p_playlist, i_current_view );
00171 if( p_view && p_view->p_root )
00172 {
00173 i_return = p_view->p_root->i_children;
00174
00175 if( i_current_view == VIEW_CATEGORY )
00176 {
00177 i_return--;
00178 i_return += p_playlist->p_general->i_children;
00179 }
00180 }
00181 }
00182 else
00183 {
00184 playlist_item_t *p_item = (playlist_item_t *)[item pointerValue];
00185 if( p_item )
00186 i_return = p_item->i_children;
00187 }
00188 vlc_object_release( p_playlist );
00189
00190 if( i_return <= 0 )
00191 i_return = 0;
00192
00193 return i_return;
00194 }
00195
00196
00197 - (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item
00198 {
00199 playlist_item_t *p_return = NULL;
00200 playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
00201 FIND_ANYWHERE );
00202 NSValue *o_value;
00203
00204 if( p_playlist == NULL )
00205 return nil;
00206
00207 if( item == nil )
00208 {
00209
00210 playlist_view_t *p_view;
00211 p_view = playlist_ViewFind( p_playlist, i_current_view );
00212 if( p_view && p_view->p_root ) p_return = p_view->p_root->pp_children[index];
00213
00214 if( i_current_view == VIEW_CATEGORY )
00215 {
00216 if( p_playlist->p_general->i_children && index >= 0 && index < p_playlist->p_general->i_children )
00217 {
00218 p_return = p_playlist->p_general->pp_children[index];
00219 }
00220 else if( p_view && p_view->p_root && index >= 0 && index - p_playlist->p_general->i_children < p_view->p_root->i_children )
00221 {
00222 p_return = p_view->p_root->pp_children[index - p_playlist->p_general->i_children + 1];
00223 }
00224 }
00225 }
00226 else
00227 {
00228 playlist_item_t *p_item = (playlist_item_t *)[item pointerValue];
00229 if( p_item && index < p_item->i_children && index >= 0 )
00230 p_return = p_item->pp_children[index];
00231 }
00232
00233
00234 vlc_object_release( p_playlist );
00235
00236 o_value = [o_outline_dict objectForKey:[NSString stringWithFormat: @"%p", p_return]];
00237 if( o_value == nil )
00238 {
00239 o_value = [[NSValue valueWithPointer: p_return] retain];
00240 }
00241 return o_value;
00242 }
00243
00244
00245 - (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
00246 {
00247 int i_return = 0;
00248 playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
00249 FIND_ANYWHERE );
00250 if( p_playlist == NULL )
00251 return NO;
00252
00253 if( item == nil )
00254 {
00255
00256 playlist_view_t *p_view;
00257 p_view = playlist_ViewFind( p_playlist, i_current_view );
00258 if( p_view && p_view->p_root ) i_return = p_view->p_root->i_children;
00259
00260 if( i_current_view == VIEW_CATEGORY )
00261 {
00262 i_return--;
00263 i_return += p_playlist->p_general->i_children;
00264 }
00265 }
00266 else
00267 {
00268 playlist_item_t *p_item = (playlist_item_t *)[item pointerValue];
00269 if( p_item )
00270 i_return = p_item->i_children;
00271 }
00272 vlc_object_release( p_playlist );
00273
00274 if( i_return <= 0 )
00275 return NO;
00276 else
00277 return YES;
00278 }
00279
00280
00281 - (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)o_tc byItem:(id)item
00282 {
00283 id o_value = nil;
00284 intf_thread_t *p_intf = VLCIntf;
00285 playlist_t *p_playlist;
00286 playlist_item_t *p_item;
00287
00288 if( item == nil || ![item isKindOfClass: [NSValue class]] ) return( @"error" );
00289
00290 p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
00291 FIND_ANYWHERE );
00292 if( p_playlist == NULL )
00293 {
00294 return( @"error" );
00295 }
00296
00297 p_item = (playlist_item_t *)[item pointerValue];
00298
00299 if( p_item == NULL )
00300 {
00301 vlc_object_release( p_playlist );
00302 return( @"error");
00303 }
00304
00305 if( [[o_tc identifier] isEqualToString:@"1"] )
00306 {
00307 o_value = [NSString stringWithUTF8String:
00308 p_item->input.psz_name];
00309 if( o_value == NULL )
00310 o_value = [NSString stringWithCString:
00311 p_item->input.psz_name];
00312 }
00313 else if( [[o_tc identifier] isEqualToString:@"2"] )
00314 {
00315 char *psz_temp;
00316 psz_temp = vlc_input_item_GetInfo( &p_item->input ,_("Meta-information"),_("Artist") );
00317
00318 if( psz_temp == NULL )
00319 o_value = @"";
00320 else
00321 {
00322 o_value = [NSString stringWithUTF8String: psz_temp];
00323 if( o_value == NULL )
00324 {
00325 o_value = [NSString stringWithCString: psz_temp];
00326 }
00327 free( psz_temp );
00328 }
00329 }
00330 else if( [[o_tc identifier] isEqualToString:@"3"] )
00331 {
00332 char psz_duration[MSTRTIME_MAX_SIZE];
00333 mtime_t dur = p_item->input.i_duration;
00334 if( dur != -1 )
00335 {
00336 secstotimestr( psz_duration, dur/1000000 );
00337 o_value = [NSString stringWithUTF8String: psz_duration];
00338 }
00339 else
00340 {
00341 o_value = @"-:--:--";
00342 }
00343 }
00344 vlc_object_release( p_playlist );
00345
00346 return( o_value );
00347 }
00348
00349 @end
00350
00351
00352
00353
00354 @implementation VLCPlaylistWizard
00355
00356 - (IBAction)reloadOutlineView
00357 {
00358
00359
00360 if( [[o_outline_view window] isVisible] )
00361 {
00362 [o_outline_view reloadData];
00363 }
00364 }
00365
00366 @end
00367
00368
00369
00370
00371 @implementation VLCPlaylist
00372
00373 - (id)init
00374 {
00375 self = [super init];
00376 if ( self != nil )
00377 {
00378 o_nodes_array = [[NSMutableArray alloc] init];
00379 o_items_array = [[NSMutableArray alloc] init];
00380 }
00381 return self;
00382 }
00383
00384 - (void)awakeFromNib
00385 {
00386 playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
00387 FIND_ANYWHERE );
00388 vlc_list_t *p_list = vlc_list_find( p_playlist, VLC_OBJECT_MODULE,
00389 FIND_ANYWHERE );
00390
00391 int i_index;
00392
00393 [super awakeFromNib];
00394
00395 [o_outline_view setDoubleAction: @selector(playItem:)];
00396
00397 [o_outline_view registerForDraggedTypes:
00398 [NSArray arrayWithObjects: NSFilenamesPboardType,
00399 @"VLCPlaylistItemPboardType", nil]];
00400 [o_outline_view setIntercellSpacing: NSMakeSize (0.0, 1.0)];
00401
00402
00403
00404
00405 if( [[NSOutlineView class] respondsToSelector:@selector(_defaultTableHeaderSortImage)] )
00406 {
00407 o_ascendingSortingImage = [[NSOutlineView class] _defaultTableHeaderSortImage];
00408 }
00409 else
00410 {
00411 o_ascendingSortingImage = nil;
00412 }
00413
00414 if( [[NSOutlineView class] respondsToSelector:@selector(_defaultTableHeaderReverseSortImage)] )
00415 {
00416 o_descendingSortingImage = [[NSOutlineView class] _defaultTableHeaderReverseSortImage];
00417 }
00418 else
00419 {
00420 o_descendingSortingImage = nil;
00421 }
00422
00423 o_tc_sortColumn = nil;
00424
00425 for( i_index = 0; i_index < p_list->i_count; i_index++ )
00426 {
00427 NSMenuItem * o_lmi;
00428 module_t * p_parser = (module_t *)p_list->p_values[i_index].p_object ;
00429
00430 if( !strcmp( p_parser->psz_capability, "services_discovery" ) )
00431 {
00432
00433 o_lmi = [[o_mi_services submenu] addItemWithTitle:
00434 [NSString stringWithUTF8String:
00435 p_parser->psz_longname ? p_parser->psz_longname :
00436 ( p_parser->psz_shortname ? p_parser->psz_shortname:
00437 p_parser->psz_object_name)]
00438 action: @selector(servicesChange:)
00439 keyEquivalent: @""];
00440 [o_lmi setTarget: self];
00441 [o_lmi setRepresentedObject:
00442 [NSString stringWithCString: p_parser->psz_object_name]];
00443 if( playlist_IsServicesDiscoveryLoaded( p_playlist,
00444 p_parser->psz_object_name ) )
00445 [o_lmi setState: NSOnState];
00446
00447
00448 o_lmi = [[o_mm_mi_services submenu] addItemWithTitle:
00449 [NSString stringWithUTF8String:
00450 p_parser->psz_longname ? p_parser->psz_longname :
00451 ( p_parser->psz_shortname ? p_parser->psz_shortname:
00452 p_parser->psz_object_name)]
00453 action: @selector(servicesChange:)
00454 keyEquivalent: @""];
00455 [o_lmi setTarget: self];
00456 [o_lmi setRepresentedObject:
00457 [NSString stringWithCString: p_parser->psz_object_name]];
00458 if( playlist_IsServicesDiscoveryLoaded( p_playlist,
00459 p_parser->psz_object_name ) )
00460 [o_lmi setState: NSOnState];
00461 }
00462 }
00463 vlc_list_release( p_list );
00464 vlc_object_release( p_playlist );
00465
00466
00467 #if 0
00468 if( MACOS_VERSION >= 10.3 )
00469 {
00470 NSView *o_parentview = [o_status_field superview];
00471 NSSearchField *o_better_search_field = [[NSSearchField alloc]initWithFrame:[o_search_field frame]];
00472 [o_better_search_field setRecentsAutosaveName:@"VLC media player search"];
00473 [o_better_search_field setDelegate:self];
00474 [[NSNotificationCenter defaultCenter] addObserver: self
00475 selector: @selector(searchfieldChanged:)
00476 name: NSControlTextDidChangeNotification
00477 object: o_better_search_field];
00478
00479 [o_better_search_field setTarget:self];
00480 [o_better_search_field setAction:@selector(searchItem:)];
00481
00482 [o_better_search_field setAutoresizingMask:NSViewMinXMargin];
00483 [o_parentview addSubview:o_better_search_field];
00484 [o_search_field setHidden:YES];
00485 }
00486 #endif
00487
00488 }
00489
00490 - (void)searchfieldChanged:(NSNotification *)o_notification
00491 {
00492 [o_search_field setStringValue:[[o_notification object] stringValue]];
00493 }
00494
00495 - (void)initStrings
00496 {
00497 [super initStrings];
00498
00499 [o_mi_save_playlist setTitle: _NS("Save Playlist...")];
00500 [o_mi_play setTitle: _NS("Play")];
00501 [o_mi_delete setTitle: _NS("Delete")];
00502 [o_mi_recursive_expand setTitle: _NS("Expand Node")];
00503 [o_mi_selectall setTitle: _NS("Select All")];
00504 [o_mi_info setTitle: _NS("Properties")];
00505 [o_mi_preparse setTitle: _NS("Preparse")];
00506 [o_mi_sort_name setTitle: _NS("Sort Node by Name")];
00507 [o_mi_sort_author setTitle: _NS("Sort Node by Author")];
00508 [o_mi_services setTitle: _NS("Services discovery")];
00509 [o_status_field setStringValue: [NSString stringWithFormat:
00510 _NS("No items in the playlist")]];
00511
00512 [o_random_ckb setTitle: _NS("Random")];
00513 #if 0
00514 [o_search_button setTitle: _NS("Search")];
00515 #endif
00516 [o_search_field setToolTip: _NS("Search in Playlist")];
00517 [[o_loop_popup itemAtIndex:0] setTitle: _NS("Standard Play")];
00518 [[o_loop_popup itemAtIndex:1] setTitle: _NS("Repeat One")];
00519 [[o_loop_popup itemAtIndex:2] setTitle: _NS("Repeat All")];
00520 }
00521
00522 - (void)playlistUpdated
00523 {
00524 unsigned int i;
00525
00526
00527 for( i = 0 ; i < [[o_outline_view tableColumns] count] ; i++ )
00528 {
00529 [o_outline_view setIndicatorImage:nil inTableColumn:
00530 [[o_outline_view tableColumns] objectAtIndex:i]];
00531 }
00532
00533 [o_outline_view setHighlightedTableColumn:nil];
00534 o_tc_sortColumn = nil;
00535
00536
00537 [o_outline_view reloadData];
00538 [[[[VLCMain sharedInstance] getWizard] getPlaylistWizard] reloadOutlineView];
00539 [[[[VLCMain sharedInstance] getBookmarks] getDataTable] reloadData];
00540 }
00541
00542 - (void)playModeUpdated
00543 {
00544 playlist_t *p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
00545 FIND_ANYWHERE );
00546 vlc_value_t val, val2;
00547
00548 if( p_playlist == NULL )
00549 {
00550 return;
00551 }
00552
00553 var_Get( p_playlist, "loop", &val2 );
00554 var_Get( p_playlist, "repeat", &val );
00555 if( val.b_bool == VLC_TRUE )
00556 {
00557 [o_loop_popup selectItemAtIndex: 1];
00558 }
00559 else if( val2.b_bool == VLC_TRUE )
00560 {
00561 [o_loop_popup selectItemAtIndex: 2];
00562 }
00563 else
00564 {
00565 [o_loop_popup selectItemAtIndex: 0];
00566 }
00567
00568 var_Get( p_playlist, "random", &val );
00569 [o_random_ckb setState: val.b_bool];
00570
00571 vlc_object_release( p_playlist );
00572 }
00573
00574 - (playlist_item_t *)parentOfItem:(playlist_item_t *)p_item
00575 {
00576 int i;
00577 for( i = 0 ; i < p_item->i_parents; i++ )
00578 {
00579 if( p_item->pp_parents[i]->i_view == i_current_view )
00580 {
00581 return p_item->pp_parents[i]->p_parent;
00582 }
00583 }
00584 return NULL;
00585 }
00586
00587 - (void)updateRowSelection
00588 {
00589 int i_row;
00590 unsigned int j;
00591
00592 playlist_t *p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
00593 FIND_ANYWHERE );
00594 playlist_item_t *p_item, *p_temp_item;
00595 NSMutableArray *o_array = [NSMutableArray array];
00596
00597 if( p_playlist == NULL )
00598 return;
00599
00600 p_item = p_playlist->status.p_item;
00601 if( p_item == NULL )
00602 {
00603 vlc_object_release(p_playlist);
00604 return;
00605 }
00606
00607 p_temp_item = p_item;
00608 while( p_temp_item->i_parents > 0 )
00609 {
00610 [o_array insertObject: [NSValue valueWithPointer: p_temp_item] atIndex: 0];
00611
00612 p_temp_item = [self parentOfItem: p_temp_item];
00613
00614
00615
00616
00617
00618
00619
00620
00621 }
00622
00623 for (j = 0 ; j < [o_array count] - 1 ; j++)
00624 {
00625 id o_item;
00626 if( ( o_item = [o_outline_dict objectForKey:
00627 [NSString stringWithFormat: @"%p",
00628 [[o_array objectAtIndex:j] pointerValue]]] ) != nil )
00629 [o_outline_view expandItem: o_item];
00630
00631 }
00632
00633 i_row = [o_outline_view rowForItem:[o_outline_dict
00634 objectForKey:[NSString stringWithFormat: @"%p", p_item]]];
00635
00636 [o_outline_view selectRow: i_row byExtendingSelection: NO];
00637 [o_outline_view scrollRowToVisible: i_row];
00638
00639 vlc_object_release(p_playlist);
00640 }
00641
00642
00643
00644
00645
00646 - (BOOL)isItem: (playlist_item_t *)p_item
00647 inNode: (playlist_item_t *)p_node
00648 checkItemExistence:(BOOL)b_check
00649
00650 {
00651 playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
00652 FIND_ANYWHERE );
00653 playlist_item_t *p_temp_item = p_item;
00654
00655 if( p_playlist == NULL )
00656 {
00657 return NO;
00658 }
00659
00660 if( p_node == p_item )
00661 {
00662 vlc_object_release(p_playlist);
00663 return YES;
00664 }
00665
00666 if( p_node->i_children < 1)
00667 {
00668 vlc_object_release(p_playlist);
00669 return NO;
00670 }
00671
00672 if ( p_temp_item )
00673 {
00674 int i;
00675 vlc_mutex_lock( &p_playlist->object_lock );
00676
00677 if( b_check )
00678 {
00679
00680
00681
00682 for( i = 0; i < p_playlist->i_all_size; i++ )
00683 {
00684 if( p_playlist->pp_all_items[i] == p_item ) break;
00685 else if ( i == p_playlist->i_all_size - 1 )
00686 {
00687 vlc_object_release( p_playlist );
00688 vlc_mutex_unlock( &p_playlist->object_lock );
00689 return NO;
00690 }
00691 }
00692 }
00693
00694 while( p_temp_item->i_parents > 0 )
00695 {
00696 p_temp_item = [self parentOfItem: p_temp_item];
00697 if( p_temp_item == p_node )
00698 {
00699 vlc_mutex_unlock( &p_playlist->object_lock );
00700 vlc_object_release( p_playlist );
00701 return YES;
00702 }
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721 }
00722 vlc_mutex_unlock( &p_playlist->object_lock );
00723 }
00724
00725 vlc_object_release( p_playlist );
00726 return NO;
00727 }
00728
00729
00730
00731 - (void)removeItemsFrom:(id)o_items ifChildrenOf:(id)o_nodes
00732 {
00733 unsigned int i, j;
00734 for( i = 0 ; i < [o_items count] ; i++ )
00735 {
00736 for ( j = 0 ; j < [o_nodes count] ; j++ )
00737 {
00738 if( o_items == o_nodes)
00739 {
00740 if( j == i ) continue;
00741 }
00742 if( [self isItem: [[o_items objectAtIndex:i] pointerValue]
00743 inNode: [[o_nodes objectAtIndex:j] pointerValue]
00744 checkItemExistence: NO] )
00745 {
00746 [o_items removeObjectAtIndex:i];
00747
00748
00749 i--;
00750 break;
00751 }
00752 }
00753 }
00754
00755 }
00756
00757 - (IBAction)savePlaylist:(id)sender
00758 {
00759 intf_thread_t * p_intf = VLCIntf;
00760 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
00761 FIND_ANYWHERE );
00762
00763 NSSavePanel *o_save_panel = [NSSavePanel savePanel];
00764 NSString * o_name = [NSString stringWithFormat: @"%@.m3u", _NS("Untitled")];
00765 [o_save_panel setTitle: _NS("Save Playlist")];
00766 [o_save_panel setPrompt: _NS("Save")];
00767
00768 if( [o_save_panel runModalForDirectory: nil
00769 file: o_name] == NSOKButton )
00770 {
00771 playlist_Export( p_playlist, [[o_save_panel filename] fileSystemRepresentation], "export-m3u" );
00772 }
00773 vlc_object_release( p_playlist );
00774 }
00775
00776
00777
00778 - (IBAction)playItem:(id)sender
00779 {
00780 intf_thread_t * p_intf = VLCIntf;
00781 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
00782 FIND_ANYWHERE );
00783
00784 if( p_playlist != NULL )
00785 {
00786 playlist_item_t *p_item;
00787 playlist_item_t *p_node = NULL;
00788
00789 p_item = [[o_outline_view itemAtRow:[o_outline_view selectedRow]] pointerValue];
00790
00791 if( p_item )
00792 {
00793 if( p_item->i_children == -1 )
00794 {
00795 p_node = [self parentOfItem: p_item];
00796
00797
00798
00799
00800
00801
00802
00803
00804 }
00805 else
00806 {
00807 p_node = p_item;
00808 if( p_node->i_children > 0 && p_node->pp_children[0]->i_children == -1 )
00809 {
00810 p_item = p_node->pp_children[0];
00811 }
00812 else
00813 {
00814 p_item = NULL;
00815 }
00816 }
00817 playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, i_current_view, p_node, p_item );
00818 }
00819 vlc_object_release( p_playlist );
00820 }
00821 }
00822
00823
00824 - (IBAction)preparseItem:(id)sender
00825 {
00826 int i_count;
00827 NSMutableArray *o_to_preparse;
00828 intf_thread_t * p_intf = VLCIntf;
00829 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
00830 FIND_ANYWHERE );
00831
00832 o_to_preparse = [NSMutableArray arrayWithArray:[[o_outline_view selectedRowEnumerator] allObjects]];
00833 i_count = [o_to_preparse count];
00834
00835 if( p_playlist != NULL )
00836 {
00837 int i, i_row;
00838 NSNumber *o_number;
00839 playlist_item_t *p_item = NULL;
00840
00841 for( i = 0; i < i_count; i++ )
00842 {
00843 o_number = [o_to_preparse lastObject];
00844 i_row = [o_number intValue];
00845 p_item = [[o_outline_view itemAtRow:i_row] pointerValue];
00846 [o_to_preparse removeObject: o_number];
00847 [o_outline_view deselectRow: i_row];
00848
00849 if( p_item )
00850 {
00851 if( p_item->i_children == -1 )
00852 {
00853 playlist_PreparseEnqueue( p_playlist, &p_item->input );
00854 }
00855 else
00856 {
00857 msg_Dbg( p_intf, "preparse of nodes not yet implemented" );
00858 }
00859 }
00860 }
00861 vlc_object_release( p_playlist );
00862 }
00863 [self playlistUpdated];
00864 }
00865
00866 - (IBAction)servicesChange:(id)sender
00867 {
00868 NSMenuItem *o_mi = (NSMenuItem *)sender;
00869 NSString *o_string = [o_mi representedObject];
00870 playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
00871 FIND_ANYWHERE );
00872 if( !playlist_IsServicesDiscoveryLoaded( p_playlist, [o_string cString] ) )
00873 playlist_ServicesDiscoveryAdd( p_playlist, [o_string cString] );
00874 else
00875 playlist_ServicesDiscoveryRemove( p_playlist, [o_string cString] );
00876
00877 [o_mi setState: playlist_IsServicesDiscoveryLoaded( p_playlist,
00878 [o_string cString] ) ? YES : NO];
00879
00880 i_current_view = VIEW_CATEGORY;
00881 playlist_ViewUpdate( p_playlist, i_current_view );
00882 vlc_object_release( p_playlist );
00883 [self playlistUpdated];
00884 return;
00885 }
00886
00887 - (IBAction)selectAll:(id)sender
00888 {
00889 [o_outline_view selectAll: nil];
00890 }
00891
00892 - (IBAction)deleteItem:(id)sender
00893 {
00894 int i, i_count, i_row;
00895 NSMutableArray *o_to_delete;
00896 NSNumber *o_number;
00897
00898 playlist_t * p_playlist;
00899 intf_thread_t * p_intf = VLCIntf;
00900
00901 p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
00902 FIND_ANYWHERE );
00903
00904 if ( p_playlist == NULL )
00905 {
00906 return;
00907 }
00908 o_to_delete = [NSMutableArray arrayWithArray:[[o_outline_view selectedRowEnumerator] allObjects]];
00909 i_count = [o_to_delete count];
00910
00911 for( i = 0; i < i_count; i++ )
00912 {
00913 o_number = [o_to_delete lastObject];
00914 i_row = [o_number intValue];
00915 id o_item = [o_outline_view itemAtRow: i_row];
00916 playlist_item_t *p_item = [o_item pointerValue];
00917 [o_to_delete removeObject: o_number];
00918 [o_outline_view deselectRow: i_row];
00919
00920 if( [[o_outline_view dataSource] outlineView:o_outline_view
00921 numberOfChildrenOfItem: o_item] > 0 )
00922
00923 {
00924 if( p_playlist->status.i_status != PLAYLIST_STOPPED &&
00925 [self isItem: p_playlist->status.p_item inNode:
00926 ((playlist_item_t *)[o_item pointerValue])
00927 checkItemExistence: NO] == YES )
00928 {
00929
00930 playlist_Stop( p_playlist );
00931 }
00932 vlc_mutex_lock( &p_playlist->object_lock );
00933 playlist_NodeDelete( p_playlist, p_item, VLC_TRUE, VLC_FALSE );
00934 vlc_mutex_unlock( &p_playlist->object_lock );
00935 }
00936 else
00937 {
00938 if( p_playlist->status.i_status != PLAYLIST_STOPPED &&
00939 p_playlist->status.p_item == [[o_outline_view itemAtRow: i_row] pointerValue] )
00940 {
00941 playlist_Stop( p_playlist );
00942 }
00943 vlc_mutex_lock( &p_playlist->object_lock );
00944 playlist_Delete( p_playlist, p_item->input.i_id );
00945 vlc_mutex_unlock( &p_playlist->object_lock );
00946 }
00947 }
00948 [self playlistUpdated];
00949 vlc_object_release( p_playlist );
00950 }
00951
00952 - (IBAction)sortNodeByName:(id)sender
00953 {
00954 [self sortNode: SORT_TITLE];
00955 }
00956
00957 - (IBAction)sortNodeByAuthor:(id)sender
00958 {
00959 [self sortNode: SORT_AUTHOR];
00960 }
00961
00962 - (void)sortNode:(int)i_mode
00963 {
00964 playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
00965 FIND_ANYWHERE );
00966 playlist_item_t * p_item;
00967
00968 if (p_playlist == NULL)
00969 {
00970 return;
00971 }
00972
00973 if( [o_outline_view selectedRow] > -1 )
00974 {
00975 p_item = [[o_outline_view itemAtRow: [o_outline_view selectedRow]]
00976 pointerValue];
00977 }
00978 else
00979
00980 {
00981 playlist_view_t * p_view = playlist_ViewFind( p_playlist, i_current_view );
00982 p_item = p_view->p_root;
00983 }
00984
00985 if( p_item->i_children > -1 )
00986 {
00987 vlc_mutex_lock( &p_playlist->object_lock );
00988 playlist_RecursiveNodeSort( p_playlist, p_item, i_mode, ORDER_NORMAL );
00989 vlc_mutex_unlock( &p_playlist->object_lock );
00990 }
00991 else
00992 {
00993 int i;
00994
00995 for( i = 0 ; i < p_item->i_parents ; i++ )
00996 {
00997 if( p_item->pp_parents[i]->i_view == i_current_view )
00998 {
00999 vlc_mutex_lock( &p_playlist->object_lock );
01000 playlist_RecursiveNodeSort( p_playlist,
01001 p_item->pp_parents[i]->p_parent, i_mode, ORDER_NORMAL );
01002 vlc_mutex_unlock( &p_playlist->object_lock );
01003 break;
01004 }
01005 }
01006 }
01007 vlc_object_release( p_playlist );
01008 [self playlistUpdated];
01009 }
01010
01011 - (playlist_item_t *)createItem:(NSDictionary *)o_one_item
01012 {
01013 intf_thread_t * p_intf = VLCIntf;
01014 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
01015 FIND_ANYWHERE );
01016
01017 if( p_playlist == NULL )
01018 {
01019 return NULL;
01020 }
01021 playlist_item_t *p_item;
01022 int i;
01023 BOOL b_rem = FALSE, b_dir = FALSE;
01024 NSString *o_uri, *o_name;
01025 NSArray *o_options;
01026 NSURL *o_true_file;
01027
01028
01029 o_uri = (NSString *)[o_one_item objectForKey: @"ITEM_URL"];
01030 o_name = (NSString *)[o_one_item objectForKey: @"ITEM_NAME"];
01031 o_options = (NSArray *)[o_one_item objectForKey: @"ITEM_OPTIONS"];
01032
01033
01034 if( ( !o_name || [o_name isEqualToString:@""] ) && [o_uri rangeOfString: @"/dev/"].location != NSNotFound )
01035 {
01036 int i_count, i_index;
01037 struct statfs *mounts = NULL;
01038
01039 i_count = getmntinfo (&mounts, MNT_NOWAIT);
01040
01041 for( i_index = 0 ; i_index < i_count; i_index++ )
01042 {
01043 NSMutableString *o_temp, *o_temp2;
01044 o_temp = [NSMutableString stringWithString: o_uri];
01045 o_temp2 = [NSMutableString stringWithCString: mounts[i_index].f_mntfromname];
01046 [o_temp replaceOccurrencesOfString: @"/dev/rdisk" withString: @"/dev/disk" options:nil range:NSMakeRange(0, [o_temp length]) ];
01047 [o_temp2 replaceOccurrencesOfString: @"s0" withString: @"" options:nil range:NSMakeRange(0, [o_temp2 length]) ];
01048 [o_temp2 replaceOccurrencesOfString: @"s1" withString: @"" options:nil range:NSMakeRange(0, [o_temp2 length]) ];
01049
01050 if( strstr( [o_temp fileSystemRepresentation], [o_temp2 fileSystemRepresentation] ) != NULL )
01051 {
01052 o_name = [[NSFileManager defaultManager] displayNameAtPath: [NSString stringWithCString:mounts[i_index].f_mntonname]];
01053 }
01054 }
01055 }
01056
01057 if( !o_name) o_name = [[NSFileManager defaultManager] displayNameAtPath: o_uri];
01058
01059 if( [[NSFileManager defaultManager] fileExistsAtPath:o_uri isDirectory:&b_dir] && b_dir &&
01060 [[NSWorkspace sharedWorkspace] getFileSystemInfoForPath: o_uri isRemovable: &b_rem
01061 isWritable:NULL isUnmountable:NULL description:NULL type:NULL] && b_rem )
01062 {
01063
01064
01065 struct statfs *buf;
01066 char *psz_dev;
01067 NSMutableString *o_temp;
01068
01069 buf = (struct statfs *) malloc (sizeof(struct statfs));
01070 statfs( [o_uri fileSystemRepresentation], buf );
01071 psz_dev = strdup(buf->f_mntfromname);
01072 o_temp = [NSMutableString stringWithCString: psz_dev ];
01073 [o_temp replaceOccurrencesOfString: @"/dev/disk" withString: @"/dev/rdisk" options:nil range:NSMakeRange(0, [o_temp length]) ];
01074 [o_temp replaceOccurrencesOfString: @"s0" withString: @"" options:nil range:NSMakeRange(0, [o_temp length]) ];
01075 [o_temp replaceOccurrencesOfString: @"s1" withString: @"" options:nil range:NSMakeRange(0, [o_temp length]) ];
01076 o_uri = o_temp;
01077 }
01078
01079 p_item = playlist_ItemNew( p_intf, [o_uri fileSystemRepresentation], [o_name UTF8String] );
01080 if( !p_item )
01081 return NULL;
01082
01083 if( o_options )
01084 {
01085 for( i = 0; i < (int)[o_options count]; i++ )
01086 {
01087 playlist_ItemAddOption( p_item, strdup( [[o_options objectAtIndex:i] UTF8String] ) );
01088 }
01089 }
01090
01091
01092 o_true_file = [NSURL fileURLWithPath: o_uri];
01093 if( o_true_file != nil )
01094 {
01095 [[NSDocumentController sharedDocumentController]
01096 noteNewRecentDocumentURL: o_true_file];
01097 }
01098
01099 vlc_object_release( p_playlist );
01100 return p_item;
01101 }
01102
01103 - (void)appendArray:(NSArray*)o_array atPos:(int)i_position enqueue:(BOOL)b_enqueue
01104 {
01105 int i_item;
01106 playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
01107 FIND_ANYWHERE );
01108 if( p_playlist == NULL )
01109 {
01110 return;
01111 }
01112
01113 for( i_item = 0; i_item < (int)[o_array count]; i_item++ )
01114 {
01115 playlist_item_t *p_item;
01116 NSDictionary *o_one_item;
01117
01118
01119 o_one_item = [o_array objectAtIndex: i_item];
01120 p_item = [self createItem: o_one_item];
01121 if( !p_item )
01122 {
01123 continue;
01124 }
01125
01126
01127 playlist_AddItem( p_playlist, p_item, PLAYLIST_INSERT, i_position == -1 ? PLAYLIST_END : i_position + i_item );
01128
01129 if( i_item == 0 && !b_enqueue )
01130 {
01131 playlist_Control( p_playlist, PLAYLIST_ITEMPLAY, p_item );
01132 }
01133 }
01134 vlc_object_release( p_playlist );
01135 }
01136
01137 - (void)appendNodeArray:(NSArray*)o_array inNode:(playlist_item_t *)p_node atPos:(int)i_position inView:(int)i_view enqueue:(BOOL)b_enqueue
01138 {
01139 int i_item;
01140 playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
01141 FIND_ANYWHERE );
01142 if( p_playlist == NULL )
01143 {
01144 return;
01145 }
01146
01147 for( i_item = 0; i_item < (int)[o_array count]; i_item++ )
01148 {
01149 playlist_item_t *p_item;
01150 NSDictionary *o_one_item;
01151
01152
01153 o_one_item = [o_array objectAtIndex: i_item];
01154 p_item = [self createItem: o_one_item];
01155 if( !p_item )
01156 {
01157 continue;
01158 }
01159
01160
01161 playlist_NodeAddItem( p_playlist, p_item, i_view, p_node, PLAYLIST_INSERT, i_position + i_item );
01162
01163 if( i_item == 0 && !b_enqueue )
01164 {
01165 playlist_Control( p_playlist, PLAYLIST_ITEMPLAY, p_item );
01166 }
01167 }
01168 vlc_object_release( p_playlist );
01169
01170 }
01171
01172 - (IBAction)handlePopUp:(id)sender
01173
01174 {
01175 intf_thread_t * p_intf = VLCIntf;
01176 vlc_value_t val1,val2;
01177 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
01178 FIND_ANYWHERE );
01179 if( p_playlist == NULL )
01180 {
01181 return;
01182 }
01183
01184 switch( [o_loop_popup indexOfSelectedItem] )
01185 {
01186 case 1:
01187
01188 val1.b_bool = 0;
01189 var_Set( p_playlist, "loop", val1 );
01190 val1.b_bool = 1;
01191 var_Set( p_playlist, "repeat", val1 );
01192 vout_OSDMessage( p_intf, DEFAULT_CHAN, _( "Repeat One" ) );
01193 break;
01194
01195 case 2:
01196 val1.b_bool = 0;
01197 var_Set( p_playlist, "repeat", val1 );
01198 val1.b_bool = 1;
01199 var_Set( p_playlist, "loop", val1 );
01200 vout_OSDMessage( p_intf, DEFAULT_CHAN, _( "Repeat All" ) );
01201 break;
01202
01203 default:
01204 var_Get( p_playlist, "repeat", &val1 );
01205 var_Get( p_playlist, "loop", &val2 );
01206 if( val1.b_bool || val2.b_bool )
01207 {
01208 val1.b_bool = 0;
01209 var_Set( p_playlist, "repeat", val1 );
01210 var_Set( p_playlist, "loop", val1 );
01211 vout_OSDMessage( p_intf, DEFAULT_CHAN, _( "Repeat Off" ) );
01212 }
01213 break;
01214 }
01215 vlc_object_release( p_playlist );
01216 [self playlistUpdated];
01217 }
01218
01219 - (NSMutableArray *)subSearchItem:(playlist_item_t *)p_item
01220 {
01221 playlist_t *p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
01222 FIND_ANYWHERE );
01223 playlist_item_t *p_selected_item;
01224 int i_current, i_selected_row;
01225
01226 if( !p_playlist )
01227 return NULL;
01228
01229 i_selected_row = [o_outline_view selectedRow];
01230 if (i_selected_row < 0)
01231 i_selected_row = 0;
01232
01233 p_selected_item = (playlist_item_t *)[[o_outline_view itemAtRow:
01234 i_selected_row] pointerValue];
01235
01236 for( i_current = 0; i_current < p_item->i_children ; i_current++ )
01237 {
01238 char *psz_temp;
01239 NSString *o_current_name, *o_current_author;
01240
01241 vlc_mutex_lock( &p_playlist->object_lock );
01242 o_current_name = [NSString stringWithUTF8String:
01243 p_item->pp_children[i_current]->input.psz_name];
01244 psz_temp = vlc_input_item_GetInfo( &p_item->input ,
01245 _("Meta-information"),_("Artist") );
01246 o_current_author = [NSString stringWithUTF8String: psz_temp];
01247 free( psz_temp);
01248 vlc_mutex_unlock( &p_playlist->object_lock );
01249
01250 if( p_selected_item == p_item->pp_children[i_current] &&
01251 b_selected_item_met == NO )
01252 {
01253 b_selected_item_met = YES;
01254 }
01255 else if( p_selected_item == p_item->pp_children[i_current] &&
01256 b_selected_item_met == YES )
01257 {
01258 vlc_object_release( p_playlist );
01259 return NULL;
01260 }
01261 else if( b_selected_item_met == YES &&
01262 ( [o_current_name rangeOfString:[o_search_field
01263 stringValue] options:NSCaseInsensitiveSearch ].length ||
01264 [o_current_author rangeOfString:[o_search_field
01265 stringValue] options:NSCaseInsensitiveSearch ].length ) )
01266 {
01267 vlc_object_release( p_playlist );
01268
01269
01270 return [NSMutableArray arrayWithObject: [NSValue
01271 valueWithPointer: p_item->pp_children[i_current]]];
01272 }
01273 if( p_item->pp_children[i_current]->i_children > 0 )
01274 {
01275 id o_result = [self subSearchItem:
01276 p_item->pp_children[i_current]];
01277 if( o_result != NULL )
01278 {
01279 vlc_object_release( p_playlist );
01280 [o_result insertObject: [NSValue valueWithPointer:
01281 p_item->pp_children[i_current]] atIndex:0];
01282 return o_result;
01283 }
01284 }
01285 }
01286 vlc_object_release( p_playlist );
01287 return NULL;
01288 }
01289
01290 - (IBAction)searchItem:(id)sender
01291 {
01292 playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
01293 FIND_ANYWHERE );
01294 playlist_view_t * p_view;
01295 id o_result;
01296
01297 unsigned int i;
01298 int i_row = -1;
01299
01300 b_selected_item_met = NO;
01301
01302 if( p_playlist == NULL )
01303 return;
01304 p_view = playlist_ViewFind( p_playlist, i_current_view );
01305
01306 if( p_view )
01307 {
01308
01309
01310 o_result = [self subSearchItem:p_view->p_root];
01311 if( o_result == NULL )
01312 {
01313
01314 o_result = [self subSearchItem:p_view->p_root];
01315 }
01316 if( o_result != NULL )
01317 {
01318 int i_start;
01319 if( [[o_result objectAtIndex: 0] pointerValue] ==
01320 p_playlist->p_general )
01321 i_start = 1;
01322 else
01323 i_start = 0;
01324
01325 for( i = i_start ; i < [o_result count] - 1 ; i++ )
01326 {
01327 [o_outline_view expandItem: [o_outline_dict objectForKey:
01328 [NSString stringWithFormat: @"%p",
01329 [[o_result objectAtIndex: i] pointerValue]]]];
01330 }
01331 i_row = [o_outline_view rowForItem: [o_outline_dict objectForKey:
01332 [NSString stringWithFormat: @"%p",
01333 [[o_result objectAtIndex: [o_result count] - 1 ]
01334 pointerValue]]]];
01335 }
01336 if( i_row > -1 )
01337 {
01338 [o_outline_view selectRow:i_row byExtendingSelection: NO];
01339 [o_outline_view scrollRowToVisible: i_row];
01340 }
01341 }
01342 vlc_object_release( p_playlist );
01343 }
01344
01345 - (IBAction)recursiveExpandNode:(id)sender
01346 {
01347 int i;
01348 id o_item = [o_outline_view itemAtRow: [o_outline_view selectedRow]];
01349 playlist_item_t *p_item = (playlist_item_t *)[o_item pointerValue];
01350
01351 if( ![[o_outline_view dataSource] outlineView: o_outline_view
01352 isItemExpandable: o_item] )
01353 {
01354 for( i = 0 ; i < p_item->i_parents ; i++ )
01355 {
01356 if( p_item->pp_parents[i]->i_view == i_current_view )
01357 {
01358 o_item = [o_outline_dict objectForKey: [NSString
01359 stringWithFormat: @"%p", p_item->pp_parents[i]->p_parent]];
01360 break;
01361 }
01362 }
01363 }
01364
01365
01366
01367 [o_outline_view collapseItem: o_item collapseChildren: YES];
01368 [o_outline_view expandItem: o_item expandChildren: YES];
01369 }
01370
01371 - (NSMenu *)menuForEvent:(NSEvent *)o_event
01372 {
01373 NSPoint pt;
01374 vlc_bool_t b_rows;
01375 vlc_bool_t b_item_sel;
01376
01377 pt = [o_outline_view convertPoint: [o_event locationInWindow]
01378 fromView: nil];
01379 b_item_sel = ( [o_outline_view rowAtPoint: pt] != -1 &&
01380 [o_outline_view selectedRow] != -1 );
01381 b_rows = [o_outline_view numberOfRows] != 0;
01382
01383 [o_mi_play setEnabled: b_item_sel];
01384 [o_mi_delete setEnabled: b_item_sel];
01385 [o_mi_selectall setEnabled: b_rows];
01386 [o_mi_info setEnabled: b_item_sel];
01387 [o_mi_preparse setEnabled: b_item_sel];
01388 [o_mi_recursive_expand setEnabled: b_item_sel];
01389 [o_mi_sort_name setEnabled: b_item_sel];
01390 [o_mi_sort_author setEnabled: b_item_sel];
01391
01392 return( o_ctx_menu );
01393 }
01394
01395 - (void)outlineView: (NSTableView*)o_tv
01396 didClickTableColumn:(NSTableColumn *)o_tc
01397 {
01398 int i_mode = 0, i_type;
01399 intf_thread_t *p_intf = VLCIntf;
01400 playlist_view_t *p_view;
01401
01402 playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
01403 FIND_ANYWHERE );
01404 if( p_playlist == NULL )
01405 {
01406 return;
01407 }
01408
01409
01410
01411 if( !( o_tc == o_tc_name || o_tc == o_tc_author ) )
01412 {
01413 vlc_object_release( p_playlist );
01414 return;
01415 }
01416
01417 p_view = playlist_ViewFind( p_playlist, i_current_view );
01418
01419 if( o_tc_sortColumn == o_tc )
01420 {
01421 b_isSortDescending = !b_isSortDescending;
01422 }
01423 else
01424 {
01425 b_isSortDescending = VLC_FALSE;
01426 }
01427
01428 if( o_tc == o_tc_name )
01429 {
01430 i_mode = SORT_TITLE;
01431 }
01432 else if( o_tc == o_tc_author )
01433 {
01434 i_mode = SORT_AUTHOR;
01435 }
01436
01437 if( b_isSortDescending )
01438 {
01439 i_type = ORDER_REVERSE;
01440 }
01441 else
01442 {
01443 i_type = ORDER_NORMAL;
01444 }
01445
01446 vlc_mutex_lock( &p_playlist->object_lock );
01447 playlist_RecursiveNodeSort( p_playlist, p_view->p_root, i_mode, i_type );
01448 vlc_mutex_unlock( &p_playlist->object_lock );
01449
01450 vlc_object_release( p_playlist );
01451 [self playlistUpdated];
01452
01453 o_tc_sortColumn = o_tc;
01454 [o_outline_view setHighlightedTableColumn:o_tc];
01455
01456 if( b_isSortDescending )
01457 {
01458 [o_outline_view setIndicatorImage:o_descendingSortingImage
01459 inTableColumn:o_tc];
01460 }
01461 else
01462 {
01463 [o_outline_view setIndicatorImage:o_ascendingSortingImage
01464 inTableColumn:o_tc];
01465 }
01466 }
01467
01468
01469 - (void)outlineView:(NSOutlineView *)outlineView
01470 willDisplayCell:(id)cell
01471 forTableColumn:(NSTableColumn *)tableColumn
01472 item:(id)item
01473 {
01474 playlist_t *p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
01475 FIND_ANYWHERE );
01476
01477 id o_playing_item;
01478
01479 if( !p_playlist ) return;
01480
01481 o_playing_item = [o_outline_dict objectForKey:
01482 [NSString stringWithFormat:@"%p", p_playlist->status.p_item]];
01483
01484 if( [self isItem: [o_playing_item pointerValue] inNode:
01485 [item pointerValue] checkItemExistence: YES]
01486 || [o_playing_item isEqual: item] )
01487 {
01488 [cell setFont: [NSFont boldSystemFontOfSize: 0]];
01489 }
01490 else
01491 {
01492 [cell setFont: [NSFont systemFontOfSize: 0]];
01493 }
01494 vlc_object_release( p_playlist );
01495 }
01496
01497 @end
01498
01499 @implementation VLCPlaylist (NSOutlineViewDataSource)
01500
01501 - (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item
01502 {
01503 id o_value = [super outlineView: outlineView child: index ofItem: item];
01504 playlist_t *p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
01505 FIND_ANYWHERE );
01506
01507 if( !p_playlist ) return nil;
01508
01509 if( p_playlist->i_size >= 2 )
01510 {
01511 [o_status_field setStringValue: [NSString stringWithFormat:
01512 _NS("%i items in the playlist"), p_playlist->i_size]];
01513 }
01514 else
01515 {
01516 if( p_playlist->i_size == 0 )
01517 {
01518 [o_status_field setStringValue: _NS("No items in the playlist")];
01519 }
01520 else
01521 {
01522 [o_status_field setStringValue: _NS("1 item in the playlist")];
01523 }
01524 }
01525 vlc_object_release( p_playlist );
01526
01527 [o_outline_dict setObject:o_value forKey:[NSString stringWithFormat:@"%p",
01528 [o_value pointerValue]]];
01529
01530 return o_value;
01531
01532 }
01533
01534
01535 - (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pboard
01536 {
01537 unsigned int i;
01538 playlist_t *p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
01539 FIND_ANYWHERE );
01540
01541
01542
01543 [o_items_array removeAllObjects];
01544 [o_nodes_array removeAllObjects];
01545
01546 if( !p_playlist ) return NO;
01547
01548 for( i = 0 ; i < [items count] ; i++ )
01549 {
01550 id o_item = [items objectAtIndex: i];
01551
01552
01553
01554 if( ![self isItem: [o_item pointerValue] inNode:
01555 p_playlist->p_general checkItemExistence: NO])
01556 {
01557 vlc_object_release(p_playlist);
01558 return NO;
01559 }
01560
01561 if( ((playlist_item_t *)[o_item pointerValue])->i_children > 0 )
01562 [o_nodes_array addObject: o_item];
01563 else
01564 [o_items_array addObject: o_item];
01565 }
01566
01567
01568
01569 [self removeItemsFrom: o_nodes_array ifChildrenOf: o_nodes_array];
01570 [self removeItemsFrom: o_items_array ifChildrenOf: o_nodes_array];
01571
01572
01573
01574
01575 [pboard declareTypes: [NSArray arrayWithObjects:
01576 @"VLCPlaylistItemPboardType", nil] owner: self];
01577 [pboard setData:[NSData data] forType:@"VLCPlaylistItemPboardType"];
01578
01579 vlc_object_release(p_playlist);
01580 return YES;
01581 }
01582
01583 - (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(int)index
01584 {
01585 playlist_t *p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
01586 FIND_ANYWHERE );
01587 NSPasteboard *o_pasteboard = [info draggingPasteboard];
01588
01589 if( !p_playlist ) return NSDragOperationNone;
01590
01591
01592 if( item )
01593 {
01594 if( index == NSOutlineViewDropOnItemIndex &&
01595 ((playlist_item_t *)[item pointerValue])->i_children == -1 )
01596 {
01597 vlc_object_release( p_playlist );
01598 return NSDragOperationNone;
01599 }
01600 }
01601
01602
01603
01604
01605 if( !([self isItem: [item pointerValue] inNode: p_playlist->p_general
01606 checkItemExistence: NO] || item == nil) )
01607 {
01608 vlc_object_release( p_playlist );
01609 return NSDragOperationNone;
01610 }
01611
01612
01613 if( [[o_pasteboard types] containsObject: @"VLCPlaylistItemPboardType"] )
01614 {
01615 unsigned int i;
01616 for( i = 0 ; i < [o_nodes_array count] ; i++ )
01617 {
01618
01619 if( [self isItem: [item pointerValue] inNode:
01620 [[o_nodes_array objectAtIndex: i] pointerValue]
01621 checkItemExistence: NO] )
01622 {
01623 vlc_object_release( p_playlist );
01624 return NSDragOperationNone;
01625 }
01626 }
01627 vlc_object_release(p_playlist);
01628 return NSDragOperationMove;
01629 }
01630
01631
01632 else if( [[o_pasteboard types] containsObject: NSFilenamesPboardType] )
01633 {
01634 vlc_object_release(p_playlist);
01635 return NSDragOperationGeneric;
01636 }
01637 vlc_object_release(p_playlist);
01638 return NSDragOperationNone;
01639 }
01640
01641 - (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(int)index
01642 {
01643 playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
01644 FIND_ANYWHERE );
01645 NSPasteboard *o_pasteboard = [info draggingPasteboard];
01646
01647 if( !p_playlist ) return NO;
01648
01649
01650 if( [[o_pasteboard types] containsObject: @"VLCPlaylistItemPboardType"] )
01651 {
01652 int i_row, i_removed_from_node = 0;
01653 unsigned int i;
01654 playlist_item_t *p_new_parent, *p_item = NULL;
01655 NSArray *o_all_items = [o_nodes_array arrayByAddingObjectsFromArray:
01656 o_items_array];
01657
01658
01659
01660 if( item == nil ) p_new_parent = p_playlist->p_general;
01661 else p_new_parent = [item pointerValue];
01662
01663
01664
01665 if( p_new_parent->i_children < 0 )
01666 {
01667 vlc_object_release( p_playlist );
01668 return NO;
01669 }
01670
01671 for( i = 0; i < [o_all_items count]; i++ )
01672 {
01673 playlist_item_t *p_old_parent = NULL;
01674 int i_old_index = 0;
01675
01676 p_item = [[o_all_items objectAtIndex:i] pointerValue];
01677 p_old_parent = [self parentOfItem: p_item];
01678 if( !p_old_parent )
01679 continue;
01680
01681 if( p_new_parent == p_old_parent )
01682 {
01683 int j;
01684 for( j = 0; j < p_old_parent->i_children; j++ )
01685 {
01686 if( p_old_parent->pp_children[j] == p_item )
01687 {
01688 i_old_index = j;
01689 break;
01690 }
01691 }
01692 }
01693
01694 vlc_mutex_lock( &p_playlist->object_lock );
01695
01696 if( playlist_NodeRemoveItem( p_playlist, p_item, p_old_parent ) ==
01697 VLC_SUCCESS &&
01698 playlist_NodeRemoveParent( p_playlist, p_item, p_old_parent ) ==
01699 VLC_SUCCESS )
01700 {
01701 int i_new_index;
01702
01703 if( index == -1 )
01704 i_new_index = -1;
01705
01706
01707 else
01708 {
01709 if ((p_new_parent == p_old_parent &&
01710 i_old_index < index + (int)i) )
01711 {
01712 i_removed_from_node++;
01713 }
01714 i_new_index = index + i - i_removed_from_node;
01715 }
01716
01717 playlist_NodeInsert( p_playlist, i_current_view, p_item,
01718 p_new_parent, i_new_index );
01719 }
01720 vlc_mutex_unlock( &p_playlist->object_lock );
01721 }
01722 [self playlistUpdated];
01723 i_row = [o_outline_view rowForItem:[o_outline_dict
01724 objectForKey:[NSString stringWithFormat: @"%p",
01725 [[o_all_items objectAtIndex: 0] pointerValue]]]];
01726
01727 if( i_row == -1 )
01728 {
01729 i_row = [o_outline_view rowForItem:[o_outline_dict
01730 objectForKey:[NSString stringWithFormat: @"%p", p_new_parent]]];
01731 }
01732
01733 [o_outline_view deselectAll: self];
01734 [o_outline_view selectRow: i_row byExtendingSelection: NO];
01735 [o_outline_view scrollRowToVisible: i_row];
01736
01737 vlc_object_release(p_playlist);
01738 return YES;
01739 }
01740
01741 else if( [[o_pasteboard types] containsObject: NSFilenamesPboardType] )
01742 {
01743 int i;
01744 playlist_item_t *p_node = [item pointerValue];
01745
01746 NSArray *o_array = [NSArray array];
01747 NSArray *o_values = [[o_pasteboard propertyListForType:
01748 NSFilenamesPboardType]
01749 sortedArrayUsingSelector:
01750 @selector(caseInsensitiveCompare:)];
01751
01752 for( i = 0; i < (int)[o_values count]; i++)
01753 {
01754 NSDictionary *o_dic;
01755 o_dic = [NSDictionary dictionaryWithObject:[o_values
01756 objectAtIndex:i] forKey:@"ITEM_URL"];
01757 o_array = [o_array arrayByAddingObject: o_dic];
01758 }
01759
01760 if ( item == nil )
01761 {
01762 [self appendArray: o_array atPos: index enqueue: YES];
01763 }
01764
01765 else if( p_node->i_children == -1 )
01766 {
01767 vlc_object_release( p_playlist );
01768 return NO;
01769 }
01770 else
01771 {
01772 [self appendNodeArray: o_array inNode: p_node
01773 atPos: index inView: i_current_view enqueue: YES];
01774 }
01775 vlc_object_release( p_playlist );
01776 return YES;
01777 }
01778 vlc_object_release( p_playlist );
01779 return NO;
01780 }
01781
01782
01783
01784
01785
01786
01787
01788 @end
01789
01790