📄 playlist.m
字号:
} } } /* We need to collapse the node first, since OSX refuses to recursively expand an already expanded node, even if children nodes are collapsed. */ [o_outline_view collapseItem: o_item collapseChildren: YES]; [o_outline_view expandItem: o_item expandChildren: YES];}- (NSMenu *)menuForEvent:(NSEvent *)o_event{ NSPoint pt; vlc_bool_t b_rows; vlc_bool_t b_item_sel; pt = [o_outline_view convertPoint: [o_event locationInWindow] fromView: nil]; b_item_sel = ( [o_outline_view rowAtPoint: pt] != -1 && [o_outline_view selectedRow] != -1 ); b_rows = [o_outline_view numberOfRows] != 0; [o_mi_play setEnabled: b_item_sel]; [o_mi_delete setEnabled: b_item_sel]; [o_mi_selectall setEnabled: b_rows]; [o_mi_info setEnabled: b_item_sel]; [o_mi_preparse setEnabled: b_item_sel]; [o_mi_recursive_expand setEnabled: b_item_sel]; [o_mi_sort_name setEnabled: b_item_sel]; [o_mi_sort_author setEnabled: b_item_sel]; return( o_ctx_menu );}- (void)outlineView: (NSTableView*)o_tv didClickTableColumn:(NSTableColumn *)o_tc{ int i_mode = 0, i_type; intf_thread_t *p_intf = VLCIntf; playlist_view_t *p_view; playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); if( p_playlist == NULL ) { return; } /* Check whether the selected table column header corresponds to a sortable table column*/ if( !( o_tc == o_tc_name || o_tc == o_tc_author ) ) { vlc_object_release( p_playlist ); return; } p_view = playlist_ViewFind( p_playlist, i_current_view ); if( o_tc_sortColumn == o_tc ) { b_isSortDescending = !b_isSortDescending; } else { b_isSortDescending = VLC_FALSE; } if( o_tc == o_tc_name ) { i_mode = SORT_TITLE; } else if( o_tc == o_tc_author ) { i_mode = SORT_AUTHOR; } if( b_isSortDescending ) { i_type = ORDER_REVERSE; } else { i_type = ORDER_NORMAL; } vlc_mutex_lock( &p_playlist->object_lock ); playlist_RecursiveNodeSort( p_playlist, p_view->p_root, i_mode, i_type ); vlc_mutex_unlock( &p_playlist->object_lock ); vlc_object_release( p_playlist ); [self playlistUpdated]; o_tc_sortColumn = o_tc; [o_outline_view setHighlightedTableColumn:o_tc]; if( b_isSortDescending ) { [o_outline_view setIndicatorImage:o_descendingSortingImage inTableColumn:o_tc]; } else { [o_outline_view setIndicatorImage:o_ascendingSortingImage inTableColumn:o_tc]; }}- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item{ playlist_t *p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); id o_playing_item; if( !p_playlist ) return; o_playing_item = [o_outline_dict objectForKey: [NSString stringWithFormat:@"%p", p_playlist->status.p_item]]; if( [self isItem: [o_playing_item pointerValue] inNode: [item pointerValue] checkItemExistence: YES] || [o_playing_item isEqual: item] ) { [cell setFont: [NSFont boldSystemFontOfSize: 0]]; } else { [cell setFont: [NSFont systemFontOfSize: 0]]; } vlc_object_release( p_playlist );}- (IBAction)addNode:(id)sender{ /* simply adds a new node to the end of the playlist */ playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); if( !p_playlist ) { return; } playlist_item_t * p_item = playlist_NodeCreate( p_playlist, VIEW_CATEGORY, _("Empty Folder"), p_playlist->p_general ); if(! p_item ) msg_Warn( VLCIntf, "node creation failed" ); playlist_ViewUpdate( p_playlist, VIEW_CATEGORY ); vlc_object_release( p_playlist );}@end@implementation VLCPlaylist (NSOutlineViewDataSource)- (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item{ id o_value = [super outlineView: outlineView child: index ofItem: item]; playlist_t *p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); if( !p_playlist ) return nil; if( p_playlist->i_size >= 2 ) { [o_status_field setStringValue: [NSString stringWithFormat: _NS("%i items in the playlist"), p_playlist->i_size]]; } else { if( p_playlist->i_size == 0 ) { [o_status_field setStringValue: _NS("No items in the playlist")]; } else { [o_status_field setStringValue: _NS("1 item in the playlist")]; } } vlc_object_release( p_playlist ); [o_outline_dict setObject:o_value forKey:[NSString stringWithFormat:@"%p", [o_value pointerValue]]]; return o_value;}/* Required for drag & drop and reordering */- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pboard{ unsigned int i; playlist_t *p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); /* First remove the items that were moved during the last drag & drop operation */ [o_items_array removeAllObjects]; [o_nodes_array removeAllObjects]; if( !p_playlist ) return NO; for( i = 0 ; i < [items count] ; i++ ) { id o_item = [items objectAtIndex: i]; /* Refuse to move items that are not in the General Node (Service Discovery) */ if( ![self isItem: [o_item pointerValue] inNode: p_playlist->p_general checkItemExistence: NO]) { vlc_object_release(p_playlist); return NO; } /* Fill the items and nodes to move in 2 different arrays */ if( ((playlist_item_t *)[o_item pointerValue])->i_children > 0 ) [o_nodes_array addObject: o_item]; else [o_items_array addObject: o_item]; } /* Now we need to check if there are selected items that are in already selected nodes. In that case, we only want to move the nodes */ [self removeItemsFrom: o_nodes_array ifChildrenOf: o_nodes_array]; [self removeItemsFrom: o_items_array ifChildrenOf: o_nodes_array]; /* We add the "VLCPlaylistItemPboardType" type to be able to recognize a Drop operation coming from the playlist. */ [pboard declareTypes: [NSArray arrayWithObjects: @"VLCPlaylistItemPboardType", nil] owner: self]; [pboard setData:[NSData data] forType:@"VLCPlaylistItemPboardType"]; vlc_object_release(p_playlist); return YES;}- (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(int)index{ playlist_t *p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); NSPasteboard *o_pasteboard = [info draggingPasteboard]; if( !p_playlist ) return NSDragOperationNone; /* Dropping ON items is not allowed if item is not a node */ if( item ) { if( index == NSOutlineViewDropOnItemIndex && ((playlist_item_t *)[item pointerValue])->i_children == -1 ) { vlc_object_release( p_playlist ); return NSDragOperationNone; } } /* We refuse to drop an item in anything else than a child of the General Node. We still accept items that would be root nodes of the outlineview however, to allow drop in an empty playlist. */ if( !([self isItem: [item pointerValue] inNode: p_playlist->p_general checkItemExistence: NO] || item == nil) ) { vlc_object_release( p_playlist ); return NSDragOperationNone; } /* Drop from the Playlist */ if( [[o_pasteboard types] containsObject: @"VLCPlaylistItemPboardType"] ) { unsigned int i; for( i = 0 ; i < [o_nodes_array count] ; i++ ) { /* We refuse to Drop in a child of an item we are moving */ if( [self isItem: [item pointerValue] inNode: [[o_nodes_array objectAtIndex: i] pointerValue] checkItemExistence: NO] ) { vlc_object_release( p_playlist ); return NSDragOperationNone; } } vlc_object_release(p_playlist); return NSDragOperationMove; } /* Drop from the Finder */ else if( [[o_pasteboard types] containsObject: NSFilenamesPboardType] ) { vlc_object_release(p_playlist); return NSDragOperationGeneric; } vlc_object_release(p_playlist); return NSDragOperationNone;}- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(int)index{ playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); NSPasteboard *o_pasteboard = [info draggingPasteboard]; if( !p_playlist ) return NO; /* Drag & Drop inside the playlist */ if( [[o_pasteboard types] containsObject: @"VLCPlaylistItemPboardType"] ) { int i_row, i_removed_from_node = 0; unsigned int i; playlist_item_t *p_new_parent, *p_item = NULL; NSArray *o_all_items = [o_nodes_array arrayByAddingObjectsFromArray: o_items_array]; /* If the item is to be dropped as root item of the outline, make it a child of the General node. Else, choose the proposed parent as parent. */ if( item == nil ) p_new_parent = p_playlist->p_general; else p_new_parent = [item pointerValue]; /* Make sure the proposed parent is a node. (This should never be true) */ if( p_new_parent->i_children < 0 ) { vlc_object_release( p_playlist ); return NO; } for( i = 0; i < [o_all_items count]; i++ ) { playlist_item_t *p_old_parent = NULL; int i_old_index = 0; p_item = [[o_all_items objectAtIndex:i] pointerValue]; p_old_parent = [self parentOfItem: p_item]; if( !p_old_parent ) continue; /* We may need the old index later */ if( p_new_parent == p_old_parent ) { int j; for( j = 0; j < p_old_parent->i_children; j++ ) { if( p_old_parent->pp_children[j] == p_item ) { i_old_index = j; break; } } } vlc_mutex_lock( &p_playlist->object_lock ); // Acually detach the item from the old position if( playlist_NodeRemoveItem( p_playlist, p_item, p_old_parent ) == VLC_SUCCESS && playlist_NodeRemoveParent( p_playlist, p_item, p_old_parent ) == VLC_SUCCESS ) { int i_new_index; /* Calculate the new index */ if( index == -1 ) i_new_index = -1; /* If we move the item in the same node, we need to take into account that one item will be deleted */ else { if ((p_new_parent == p_old_parent && i_old_index < index + (int)i) ) { i_removed_from_node++; } i_new_index = index + i - i_removed_from_node; } // Reattach the item to the new position playlist_NodeInsert( p_playlist, i_current_view, p_item, p_new_parent, i_new_index ); } vlc_mutex_unlock( &p_playlist->object_lock ); } [self playlistUpdated]; i_row = [o_outline_view rowForItem:[o_outline_dict objectForKey:[NSString stringWithFormat: @"%p", [[o_all_items objectAtIndex: 0] pointerValue]]]]; if( i_row == -1 ) { i_row = [o_outline_view rowForItem:[o_outline_dict objectForKey:[NSString stringWithFormat: @"%p", p_new_parent]]]; } [o_outline_view deselectAll: self]; [o_outline_view selectRow: i_row byExtendingSelection: NO]; [o_outline_view scrollRowToVisible: i_row]; vlc_object_release(p_playlist); return YES; } else if( [[o_pasteboard types] containsObject: NSFilenamesPboardType] ) { int i; playlist_item_t *p_node = [item pointerValue]; NSArray *o_array = [NSArray array]; NSArray *o_values = [[o_pasteboard propertyListForType: NSFilenamesPboardType] sortedArrayUsingSelector: @selector(caseInsensitiveCompare:)]; for( i = 0; i < (int)[o_values count]; i++) { NSDictionary *o_dic; o_dic = [NSDictionary dictionaryWithObject:[o_values objectAtIndex:i] forKey:@"ITEM_URL"]; o_array = [o_array arrayByAddingObject: o_dic]; } if ( item == nil ) { [self appendArray: o_array atPos: index enqueue: YES]; } /* This should never occur */ else if( p_node->i_children == -1 ) { vlc_object_release( p_playlist ); return NO; } else { [self appendNodeArray: o_array inNode: p_node atPos: index inView: i_current_view enqueue: YES]; } vlc_object_release( p_playlist ); return YES; } vlc_object_release( p_playlist ); return NO;}/* Delegate method of NSWindow *//*- (void)windowWillClose:(NSNotification *)aNotification{ [o_btn_playlist setState: NSOffState];}*/@end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -