📄 playlist.m
字号:
/***************************************************************************** * playlist.m: MacOS X interface module ****************************************************************************** Copyright (C) 2002-2005 VideoLAN * $Id: playlist.m 11514 2005-06-24 20:14:28Z hartman $ * * Authors: Jon Lech Johansen <jon-vl@nanocrew.net> * Derk-Jan Hartman <hartman at videolan dot org> * Benjamin Pracht <bigben at videolab dot org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. *****************************************************************************//* TODO * add 'icons' for different types of nodes? (http://www.cocoadev.com/index.pl?IconAndTextInTableCell) * create a new search field build with pictures from the 'regular' search field, so it can be emulated on 10.2 * create toggle buttons for the shuffle, repeat one, repeat all functions. * implement drag and drop and item reordering. * reimplement enable/disable item * create a new 'tool' button (see the gear button in the Finder window) for 'actions' (adding service discovery, other views, new node/playlist, save node/playlist) stuff like that *//***************************************************************************** * Preamble *****************************************************************************/#include <stdlib.h> /* malloc(), free() */#include <sys/param.h> /* for MAXPATHLEN */#include <string.h>#include <math.h>#include <sys/mount.h>#include <vlc_keys.h>#include "intf.h"#include "playlist.h"#include "controls.h"#include "osd.h"#include "misc.h"/***************************************************************************** * VLCPlaylistView implementation *****************************************************************************/@implementation VLCPlaylistView- (NSMenu *)menuForEvent:(NSEvent *)o_event{ return( [[self delegate] menuForEvent: o_event] );}- (void)keyDown:(NSEvent *)o_event{ unichar key = 0; if( [[o_event characters] length] ) { key = [[o_event characters] characterAtIndex: 0]; } switch( key ) { case NSDeleteCharacter: case NSDeleteFunctionKey: case NSDeleteCharFunctionKey: case NSBackspaceCharacter: [[self delegate] deleteItem:self]; break; case NSEnterCharacter: case NSCarriageReturnCharacter: [(VLCPlaylist *)[[VLCMain sharedInstance] getPlaylist] playItem:self]; break; default: [super keyDown: o_event]; break; }}@end/***************************************************************************** * VLCPlaylist implementation *****************************************************************************/@implementation VLCPlaylist- (id)init{ self = [super init]; if ( self != nil ) { o_outline_dict = [[NSMutableDictionary alloc] init]; //i_moveRow = -1; } return self;}- (void)awakeFromNib{ playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); vlc_list_t *p_list = vlc_list_find( p_playlist, VLC_OBJECT_MODULE, FIND_ANYWHERE ); int i_index; i_current_view = VIEW_CATEGORY; playlist_ViewUpdate( p_playlist, i_current_view ); [o_outline_view setTarget: self]; [o_outline_view setDelegate: self]; [o_outline_view setDataSource: self]; [o_outline_view setDoubleAction: @selector(playItem:)]; [o_outline_view registerForDraggedTypes: [NSArray arrayWithObjects: NSFilenamesPboardType, nil]]; [o_outline_view setIntercellSpacing: NSMakeSize (0.0, 1.0)];/* We need to check whether _defaultTableHeaderSortImage exists, since it belongs to an Apple hidden private API, and then can "disapear" at any time*/ if( [[NSOutlineView class] respondsToSelector:@selector(_defaultTableHeaderSortImage)] ) { o_ascendingSortingImage = [[NSOutlineView class] _defaultTableHeaderSortImage]; } else { o_ascendingSortingImage = nil; } if( [[NSOutlineView class] respondsToSelector:@selector(_defaultTableHeaderReverseSortImage)] ) { o_descendingSortingImage = [[NSOutlineView class] _defaultTableHeaderReverseSortImage]; } else { o_descendingSortingImage = nil; } o_tc_sortColumn = nil; for( i_index = 0; i_index < p_list->i_count; i_index++ ) { NSMenuItem * o_lmi; module_t * p_parser = (module_t *)p_list->p_values[i_index].p_object ; if( !strcmp( p_parser->psz_capability, "services_discovery" ) ) { /* create the menu entries used in the playlist menu */ o_lmi = [[o_mi_services submenu] addItemWithTitle: [NSString stringWithUTF8String: p_parser->psz_longname ? p_parser->psz_longname : ( p_parser->psz_shortname ? p_parser->psz_shortname: p_parser->psz_object_name)] action: @selector(servicesChange:) keyEquivalent: @""]; [o_lmi setTarget: self]; [o_lmi setRepresentedObject: [NSString stringWithCString: p_parser->psz_object_name]]; if( playlist_IsServicesDiscoveryLoaded( p_playlist, p_parser->psz_object_name ) ) [o_lmi setState: NSOnState]; /* create the menu entries for the main menu */ o_lmi = [[o_mm_mi_services submenu] addItemWithTitle: [NSString stringWithUTF8String: p_parser->psz_longname ? p_parser->psz_longname : ( p_parser->psz_shortname ? p_parser->psz_shortname: p_parser->psz_object_name)] action: @selector(servicesChange:) keyEquivalent: @""]; [o_lmi setTarget: self]; [o_lmi setRepresentedObject: [NSString stringWithCString: p_parser->psz_object_name]]; if( playlist_IsServicesDiscoveryLoaded( p_playlist, p_parser->psz_object_name ) ) [o_lmi setState: NSOnState]; } } vlc_list_release( p_list ); vlc_object_release( p_playlist ); /* Change the simple textfield into a searchField if we can... */#if 0 if( MACOS_VERSION >= 10.3 ) { NSView *o_parentview = [o_status_field superview]; NSSearchField *o_better_search_field = [[NSSearchField alloc]initWithFrame:[o_search_field frame]]; [o_better_search_field setRecentsAutosaveName:@"VLC media player search"]; [o_better_search_field setDelegate:self]; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(searchfieldChanged:) name: NSControlTextDidChangeNotification object: o_better_search_field]; [o_better_search_field setTarget:self]; [o_better_search_field setAction:@selector(searchItem:)]; [o_better_search_field setAutoresizingMask:NSViewMinXMargin]; [o_parentview addSubview:o_better_search_field]; [o_search_field setHidden:YES]; }#endif [self initStrings]; //[self playlistUpdated];}- (void)searchfieldChanged:(NSNotification *)o_notification{ [o_search_field setStringValue:[[o_notification object] stringValue]];}- (void)initStrings{ [o_mi_save_playlist setTitle: _NS("Save Playlist...")]; [o_mi_play setTitle: _NS("Play")]; [o_mi_delete setTitle: _NS("Delete")]; [o_mi_selectall setTitle: _NS("Select All")]; [o_mi_info setTitle: _NS("Properties")]; [o_mi_sort_name setTitle: _NS("Sort Node by Name")]; [o_mi_sort_author setTitle: _NS("Sort Node by Author")]; [o_mi_services setTitle: _NS("Services discovery")]; [[o_tc_name headerCell] setStringValue:_NS("Name")]; [[o_tc_author headerCell] setStringValue:_NS("Author")]; [[o_tc_duration headerCell] setStringValue:_NS("Duration")]; [o_status_field setStringValue: [NSString stringWithFormat: _NS("no items in playlist")]]; [o_random_ckb setTitle: _NS("Random")];#if 0 [o_search_button setTitle: _NS("Search")];#endif [o_search_field setToolTip: _NS("Search in Playlist")]; [[o_loop_popup itemAtIndex:0] setTitle: _NS("Standard Play")]; [[o_loop_popup itemAtIndex:1] setTitle: _NS("Repeat One")]; [[o_loop_popup itemAtIndex:2] setTitle: _NS("Repeat All")];}- (NSOutlineView *)outlineView{ return o_outline_view;}- (void)playlistUpdated{ unsigned int i; /* Clear indications of any existing column sorting*/ for( i = 0 ; i < [[o_outline_view tableColumns] count] ; i++ ) { [o_outline_view setIndicatorImage:nil inTableColumn: [[o_outline_view tableColumns] objectAtIndex:i]]; } [o_outline_view setHighlightedTableColumn:nil]; o_tc_sortColumn = nil; // TODO Find a way to keep the dict size to a minimum //[o_outline_dict removeAllObjects]; [o_outline_view reloadData];}- (void)playModeUpdated{ playlist_t *p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); vlc_value_t val, val2; if( p_playlist == NULL ) { return; } var_Get( p_playlist, "loop", &val2 ); var_Get( p_playlist, "repeat", &val ); if( val.b_bool == VLC_TRUE ) { [o_loop_popup selectItemAtIndex: 1]; } else if( val2.b_bool == VLC_TRUE ) { [o_loop_popup selectItemAtIndex: 2]; } else { [o_loop_popup selectItemAtIndex: 0]; } var_Get( p_playlist, "random", &val ); [o_random_ckb setState: val.b_bool]; vlc_object_release( p_playlist );}- (void)updateRowSelection{ int i,i_row; unsigned int j; playlist_t *p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); playlist_item_t *p_item, *p_temp_item; NSMutableArray *o_array = [NSMutableArray array]; if( p_playlist == NULL ) return; p_item = p_playlist->status.p_item; if( p_item == NULL ) return; p_temp_item = p_item; while( p_temp_item->i_parents > 0 ) { [o_array insertObject: [NSValue valueWithPointer: p_temp_item] atIndex: 0]; for (i = 0 ; i < p_temp_item->i_parents ; i++) { if( p_temp_item->pp_parents[i]->i_view == i_current_view ) { p_temp_item = p_temp_item->pp_parents[i]->p_parent; break; } } } for (j = 0 ; j < [o_array count] - 1 ; j++) { id o_item; if( ( o_item = [o_outline_dict objectForKey: [NSString stringWithFormat: @"%p", [[o_array objectAtIndex:j] pointerValue]]] ) != nil ) [o_outline_view expandItem: o_item]; } i_row = [o_outline_view rowForItem:[o_outline_dict objectForKey:[NSString stringWithFormat: @"%p", p_item]]]; [o_outline_view selectRow: i_row byExtendingSelection: NO]; [o_outline_view scrollRowToVisible: i_row]; vlc_object_release(p_playlist);}- (BOOL)isValueItem: (id)o_item inNode: (id)o_node{ int i; int i_total = [[o_outline_view dataSource] outlineView:o_outline_view numberOfChildrenOfItem: o_node]; for( i = 0 ; i < i_total ; i++ ) { id o_temp_item = [[o_outline_view dataSource] outlineView: o_outline_view child:i ofItem: o_node]; if( [[o_outline_view dataSource] outlineView:o_outline_view numberOfChildrenOfItem: o_temp_item] > 0 ) { if( [self isValueItem: o_item inNode: o_temp_item] == YES ) return YES; } else if( [o_temp_item isEqual: o_item] ) { return YES; } } return NO;}- (IBAction)savePlaylist:(id)sender{ intf_thread_t * p_intf = VLCIntf; playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); NSSavePanel *o_save_panel = [NSSavePanel savePanel]; NSString * o_name = [NSString stringWithFormat: @"%@.m3u", _NS("Untitled")]; [o_save_panel setTitle: _NS("Save Playlist")]; [o_save_panel setPrompt: _NS("Save")]; if( [o_save_panel runModalForDirectory: nil file: o_name] == NSOKButton ) { playlist_Export( p_playlist, [[o_save_panel filename] fileSystemRepresentation], "export-m3u" ); }}/* When called retrieves the selected outlineview row and plays that node or item */- (IBAction)playItem:(id)sender{ intf_thread_t * p_intf = VLCIntf; playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); if( p_playlist != NULL ) { playlist_item_t *p_item; playlist_item_t *p_node = NULL; int i; p_item = [[o_outline_view itemAtRow:[o_outline_view selectedRow]] pointerValue]; if( p_item ) { if( p_item->i_children == -1 ) { for( i = 0 ; i < p_item->i_parents ; i++ ) { if( p_item->pp_parents[i]->i_view == i_current_view ) { p_node = p_item->pp_parents[i]->p_parent; } } } else { p_node = p_item; if( p_node->i_children > 0 && p_node->pp_children[0]->i_children == -1 ) { p_item = p_node->pp_children[0]; } else { p_item = NULL; } } playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, i_current_view, p_node, p_item ); } vlc_object_release( p_playlist ); }}- (IBAction)servicesChange:(id)sender{ NSMenuItem *o_mi = (NSMenuItem *)sender; NSString *o_string = [o_mi representedObject]; playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); if( !playlist_IsServicesDiscoveryLoaded( p_playlist, [o_string cString] ) ) playlist_ServicesDiscoveryAdd( p_playlist, [o_string cString] ); else playlist_ServicesDiscoveryRemove( p_playlist, [o_string cString] );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -