📄 playlist.m
字号:
/***************************************************************************** * playlist.m: MacOS X interface module ****************************************************************************** Copyright (C) 2002-2008 the VideoLAN team * $Id: a03cbd1c60f0ce4fb24aaf72252bb5212443f84d $ * * Authors: Jon Lech Johansen <jon-vl@nanocrew.net> * Derk-Jan Hartman <hartman at videola/n 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************//* TODO * add 'icons' for different types of nodes? (http://www.cocoadev.com/index.pl?IconAndTextInTableCell) * 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>#import "intf.h"#import "wizard.h"#import "bookmarks.h"#import "playlistinfo.h"#import "playlist.h"#import "controls.h"#import "vlc_osd.h"#import "misc.h"#import <vlc_interface.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/***************************************************************************** * VLCPlaylistCommon implementation * * This class the superclass of the VLCPlaylist and VLCPlaylistWizard. * It contains the common methods and elements of these 2 entities. *****************************************************************************/@implementation VLCPlaylistCommon- (id)init{ self = [super init]; if ( self != nil ) { o_outline_dict = [[NSMutableDictionary alloc] init]; } return self;}- (void)awakeFromNib{ playlist_t * p_playlist = pl_Yield( VLCIntf ); [o_outline_view setTarget: self]; [o_outline_view setDelegate: self]; [o_outline_view setDataSource: self]; [o_outline_view setAllowsEmptySelection: NO]; vlc_object_release( p_playlist ); [self initStrings];}- (void)initStrings{ [[o_tc_name headerCell] setStringValue:_NS("Name")]; [[o_tc_author headerCell] setStringValue:_NS("Author")]; [[o_tc_duration headerCell] setStringValue:_NS("Duration")];}- (NSOutlineView *)outlineView{ return o_outline_view;}- (playlist_item_t *)selectedPlaylistItem{ return [[o_outline_view itemAtRow: [o_outline_view selectedRow]] pointerValue];}@end@implementation VLCPlaylistCommon (NSOutlineViewDataSource)/* return the number of children for Obj-C pointer item */ /* DONE */- (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item{ int i_return = 0; playlist_item_t *p_item = NULL; playlist_t * p_playlist = pl_Yield( VLCIntf ); assert( outlineView == o_outline_view ); if( !item ) p_item = p_playlist->p_root_category; else p_item = (playlist_item_t *)[item pointerValue]; if( p_item ) i_return = p_item->i_children; pl_Release( VLCIntf ); return i_return > 0 ? i_return : 0;}/* return the child at index for the Obj-C pointer item */ /* DONE */- (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item{ playlist_item_t *p_return = NULL, *p_item = NULL; NSValue *o_value; playlist_t * p_playlist = pl_Yield( VLCIntf ); if( item == nil ) { /* root object */ p_item = p_playlist->p_root_category; } else { p_item = (playlist_item_t *)[item pointerValue]; } if( p_item && index < p_item->i_children && index >= 0 ) p_return = p_item->pp_children[index]; vlc_object_release( p_playlist ); o_value = [o_outline_dict objectForKey:[NSString stringWithFormat: @"%p", p_return]]; if( o_value == nil ) { /* Why is there a warning if that happens all the time and seems * to be normal? Add an assert and fix it. * msg_Warn( VLCIntf, "playlist item misses pointer value, adding one" ); */ o_value = [[NSValue valueWithPointer: p_return] retain]; } return o_value;}/* is the item expandable */- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item{ int i_return = 0; playlist_t *p_playlist = pl_Yield( VLCIntf ); if( item == nil ) { /* root object */ if( p_playlist->p_root_category ) { i_return = p_playlist->p_root_category->i_children; } } else { playlist_item_t *p_item = (playlist_item_t *)[item pointerValue]; if( p_item ) i_return = p_item->i_children; } pl_Release( VLCIntf ); return (i_return >= 0);}/* retrieve the string values for the cells */- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)o_tc byItem:(id)item{ id o_value = nil; playlist_item_t *p_item; /* For error handling */ static BOOL attempted_reload = NO; if( item == nil || ![item isKindOfClass: [NSValue class]] ) { /* Attempt to fix the error by asking for a data redisplay * This might cause infinite loop, so add a small check */ if( !attempted_reload ) { attempted_reload = YES; [outlineView reloadData]; } return @"error" ; } p_item = (playlist_item_t *)[item pointerValue]; if( !p_item || !p_item->p_input ) { /* Attempt to fix the error by asking for a data redisplay * This might cause infinite loop, so add a small check */ if( !attempted_reload ) { attempted_reload = YES; [outlineView reloadData]; } return @"error"; } attempted_reload = NO; if( [[o_tc identifier] isEqualToString:@"name"] ) { /* sanity check to prevent the NSString class from crashing */ char *psz_title = input_item_GetTitle( p_item->p_input ); if( !EMPTY_STR( psz_title ) ) { o_value = [NSString stringWithUTF8String: psz_title]; } else { char *psz_name = input_item_GetName( p_item->p_input ); if( psz_name ) o_value = [NSString stringWithUTF8String: psz_name]; free( psz_name ); } free( psz_title ); } else if( [[o_tc identifier] isEqualToString:@"artist"] ) { char *psz_artist = input_item_GetArtist( p_item->p_input ); if( psz_artist ) o_value = [NSString stringWithUTF8String: psz_artist]; free( psz_artist ); } else if( [[o_tc identifier] isEqualToString:@"duration"] ) { char psz_duration[MSTRTIME_MAX_SIZE]; mtime_t dur = input_item_GetDuration( p_item->p_input ); if( dur != -1 ) { secstotimestr( psz_duration, dur/1000000 ); o_value = [NSString stringWithUTF8String: psz_duration]; } else o_value = @"--:--"; } else if( [[o_tc identifier] isEqualToString:@"status"] ) { if( input_item_HasErrorWhenReading( p_item->p_input ) ) { o_value = [NSImage imageWithWarningIcon]; } } return o_value;}@end/***************************************************************************** * VLCPlaylistWizard implementation *****************************************************************************/@implementation VLCPlaylistWizard- (IBAction)reloadOutlineView{ /* Only reload the outlineview if the wizard window is open since this can be quite long on big playlists */ if( [[o_outline_view window] isVisible] ) { [o_outline_view reloadData]; }}@end/***************************************************************************** * extension to NSOutlineView's interface to fix compilation warnings * and let us access these 2 functions properly * this uses a private Apple-API, but works fine on all current OSX releases * keep checking for compatiblity with future releases though *****************************************************************************/@interface NSOutlineView (UndocumentedSortImages)+ (NSImage *)_defaultTableHeaderSortImage;+ (NSImage *)_defaultTableHeaderReverseSortImage;@end/***************************************************************************** * VLCPlaylist implementation *****************************************************************************/@implementation VLCPlaylist- (id)init{ self = [super init]; if ( self != nil ) { o_nodes_array = [[NSMutableArray alloc] init]; o_items_array = [[NSMutableArray alloc] init]; } return self;}- (void)dealloc{ [o_nodes_array release]; [o_items_array release]; [super dealloc];}- (void)awakeFromNib{ playlist_t * p_playlist = pl_Yield( VLCIntf ); int i; [super awakeFromNib]; [o_outline_view setDoubleAction: @selector(playItem:)]; [o_outline_view registerForDraggedTypes: [NSArray arrayWithObjects: NSFilenamesPboardType, @"VLCPlaylistItemPboardType", nil]]; [o_outline_view setIntercellSpacing: NSMakeSize (0.0, 1.0)]; /* This uses private Apple API which works fine until 10.5. * We need to keep checking in the future! * These methods are being added artificially to NSOutlineView's interface above */ o_ascendingSortingImage = [[NSOutlineView class] _defaultTableHeaderSortImage]; o_descendingSortingImage = [[NSOutlineView class] _defaultTableHeaderReverseSortImage]; o_tc_sortColumn = nil; char ** ppsz_name; char ** ppsz_services = services_discovery_GetServicesNames( p_playlist, &ppsz_name ); if( !ppsz_services ) { vlc_object_release( p_playlist ); return; } for( i = 0; ppsz_services[i]; i++ ) { bool b_enabled; NSMenuItem *o_lmi; char * name = ppsz_name[i] ? ppsz_name[i] : ppsz_services[i]; /* Check whether to enable these menuitems */ b_enabled = playlist_IsServicesDiscoveryLoaded( p_playlist, ppsz_services[i] ); /* Create the menu entries used in the playlist menu */ o_lmi = [[o_mi_services submenu] addItemWithTitle: [NSString stringWithUTF8String: name] action: @selector(servicesChange:) keyEquivalent: @""]; [o_lmi setTarget: self]; [o_lmi setRepresentedObject: [NSString stringWithUTF8String: ppsz_services[i]]]; if( b_enabled ) [o_lmi setState: NSOnState]; /* Create the menu entries for the main menu */ o_lmi = [[o_mm_mi_services submenu] addItemWithTitle: [NSString stringWithUTF8String: name] action: @selector(servicesChange:) keyEquivalent: @""]; [o_lmi setTarget: self]; [o_lmi setRepresentedObject: [NSString stringWithUTF8String: ppsz_services[i]]]; if( b_enabled ) [o_lmi setState: NSOnState];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -