empty = playlist_IsEmpty(p_playlist);
PL_UNLOCK;
- if ([[[VLCMain sharedInstance] playlist] isSelectionEmpty] && ([[[VLCMain sharedInstance] playlist] currentPlaylistRoot] == p_playlist->p_local_category || [[[VLCMain sharedInstance] playlist] currentPlaylistRoot] == p_playlist->p_ml_category))
+ PLRootType root = [[[[VLCMain sharedInstance] playlist] model] currentRootType];
+ if ([[[VLCMain sharedInstance] playlist] isSelectionEmpty] && (root == ROOT_TYPE_PLAYLIST || root == ROOT_TYPE_MEDIALIBRARY))
[[[VLCMain sharedInstance] open] openFileGeneric];
else
[[[VLCMain sharedInstance] playlist] playItem:nil];
[o_fspanel setSeekable: b_seekable];
PL_LOCK;
- if ([[[VLCMain sharedInstance] playlist] currentPlaylistRoot] != p_playlist->p_local_category || p_playlist->p_local_category->i_children > 0)
+ if ([[[[VLCMain sharedInstance] playlist] model] currentRootType] != ROOT_TYPE_PLAYLIST ||
+ [[[[VLCMain sharedInstance] playlist] model] hasChildren])
[self hideDropZone];
else
[self showDropZone];
#pragma mark private playlist magic
- (void)_updatePlaylistTitle
{
- playlist_t * p_playlist = pl_Get(VLCIntf);
- PL_LOCK;
- playlist_item_t *currentPlaylistRoot = [[[VLCMain sharedInstance] playlist] currentPlaylistRoot];
- PL_UNLOCK;
+ PLRootType root = [[[[VLCMain sharedInstance] playlist] model] currentRootType];
+ playlist_t *p_playlist = pl_Get(VLCIntf);
- if (currentPlaylistRoot == p_playlist->p_local_category)
+ PL_LOCK;
+ if (root == ROOT_TYPE_PLAYLIST)
[o_chosen_category_lbl setStringValue: [_NS("Playlist") stringByAppendingString:[self _playbackDurationOfNode:p_playlist->p_local_category]]];
- else if (currentPlaylistRoot == p_playlist->p_ml_category)
+ else if (root == ROOT_TYPE_MEDIALIBRARY)
[o_chosen_category_lbl setStringValue: [_NS("Media Library") stringByAppendingString:[self _playbackDurationOfNode:p_playlist->p_ml_category]]];
+
+ PL_UNLOCK;
}
- (NSString *)_playbackDurationOfNode:(playlist_item_t*)node
return @"";
playlist_t * p_playlist = pl_Get(VLCIntf);
- PL_LOCK;
+ PL_ASSERT_LOCKED;
+
mtime_t mt_duration = playlist_GetNodeDuration( node );
- PL_UNLOCK;
if (mt_duration < 1)
return @"";
[o_chosen_category_lbl setStringValue:[item title]];
if ([[item identifier] isEqualToString:@"playlist"]) {
- [[[VLCMain sharedInstance] playlist] setPlaylistRoot:p_playlist->p_local_category];
- [o_chosen_category_lbl setStringValue: [[o_chosen_category_lbl stringValue] stringByAppendingString:[self _playbackDurationOfNode:p_playlist->p_local_category]]];
+ PL_LOCK;
+
+ [[[[VLCMain sharedInstance] playlist] model] changeRootItem:p_playlist->p_playing];
+ PL_UNLOCK;
+
+ [self _updatePlaylistTitle];
+
} else if ([[item identifier] isEqualToString:@"medialibrary"]) {
if (p_playlist->p_ml_category) {
- [[[VLCMain sharedInstance] playlist] setPlaylistRoot:p_playlist->p_ml_category];
- [o_chosen_category_lbl setStringValue: [[o_chosen_category_lbl stringValue] stringByAppendingString:[self _playbackDurationOfNode:p_playlist->p_ml_category]]];
+
+ PL_LOCK;
+ [[[[VLCMain sharedInstance] playlist] model] changeRootItem:p_playlist->p_media_library];
+
+ PL_UNLOCK;
+
+ [self _updatePlaylistTitle];
}
} else {
- playlist_item_t * pl_item;
PL_LOCK;
- pl_item = playlist_ChildSearchName(p_playlist->p_root, [[item untranslatedTitle] UTF8String]);
+ playlist_item_t *pl_item = playlist_ChildSearchName(p_playlist->p_root, [[item untranslatedTitle] UTF8String]);
+ [[[[VLCMain sharedInstance] playlist] model] changeRootItem:pl_item];
+
PL_UNLOCK;
- [[[VLCMain sharedInstance] playlist] setPlaylistRoot: pl_item];
}
// Note the order: first hide the podcast controls, then show the drop zone
[self hidePodcastControls];
PL_LOCK;
- if ([[[VLCMain sharedInstance] playlist] currentPlaylistRoot] != p_playlist->p_local_category || p_playlist->p_local_category->i_children > 0)
+ if ([[[[VLCMain sharedInstance] playlist] model] currentRootType] != ROOT_TYPE_PLAYLIST ||
+ [[[[VLCMain sharedInstance] playlist] model] hasChildren])
[self hideDropZone];
else
[self showDropZone];
BWQuincyUI.m \
iTunes.h \
Spotify.h \
+ PLItem.h \
+ PLItem.m \
+ PLModel.h \
+ PLModel.m \
$(NULL)
--- /dev/null
+/*****************************************************************************
+ * PLItem.h: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2014 VLC authors and VideoLAN
+ * $Id$
+ *
+ * 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.
+ *****************************************************************************/
+
+#import <Cocoa/Cocoa.h>
+
+#include <vlc_common.h>
+
+@interface PLItem : NSObject
+{
+ input_item_t *p_input;
+
+ int _playlistId;
+ NSMutableArray *_children;
+
+ PLItem *_parent;
+}
+
+@property(readonly, copy) NSMutableArray *children;
+@property(readonly) int plItemId;
+@property(readonly) input_item_t *input;
+@property(readonly) PLItem *parent;
+
+- (id)initWithPlaylistItem:(playlist_item_t *)p_item parent:(PLItem *)parent;
+
+- (BOOL)isLeaf;
+
+- (void)clear;
+- (void)addChild:(PLItem *)item atPos:(int)pos;
+- (void)deleteChild:(PLItem *)child;
+
+@end
+
--- /dev/null
+/*****************************************************************************
+ * PLItem.m: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2014 VLC authors and VideoLAN
+ * $Id$
+ *
+ * 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.
+ *****************************************************************************/
+
+#import "PLItem.h"
+
+#include <vlc_playlist.h>
+#include <vlc_input_item.h>
+
+#pragma mark -
+;
+@implementation PLItem
+
+@synthesize children=_children;
+@synthesize plItemId=_playlistId;
+@synthesize input=p_input;
+@synthesize parent=_parent;
+
+- (id)initWithPlaylistItem:(playlist_item_t *)p_item parent:(PLItem *)parent;
+{
+ self = [super init];
+ if(self) {
+ _playlistId = p_item->i_id;
+
+ p_input = p_item->p_input;
+ input_item_Hold(p_input);
+ _children = [[NSMutableArray alloc] init];
+ [parent retain];
+ _parent = parent;
+ }
+
+ return self;
+}
+
+- (void)dealloc
+{
+ input_item_Release(p_input);
+ [_children release];
+ [_parent release];
+
+ [super dealloc];
+}
+
+
+- (BOOL)isLeaf
+{
+ return [_children count] == 0;
+}
+
+- (void)clear
+{
+ [_children removeAllObjects];
+}
+
+- (void)addChild:(PLItem *)item atPos:(int)pos
+{
+// if ([o_children count] > pos) {
+// NSLog(@"invalid position %d", pos);
+// }
+ [_children insertObject:item atIndex:pos];
+
+}
+
+- (void)deleteChild:(PLItem *)child
+{
+ [_children removeObject:child];
+}
+
+@end
--- /dev/null
+/*****************************************************************************
+ * PLItem.h: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2014 VLC authors and VideoLAN
+ * $Id$
+ *
+ * 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.
+ *****************************************************************************/
+
+#import <Cocoa/Cocoa.h>
+
+#import "PLItem.h"
+
+#include <vlc_common.h>
+
+@interface PLModel : NSObject<NSOutlineViewDataSource>
+{
+ PLItem *_rootItem;
+
+ playlist_t *p_playlist;
+ NSOutlineView *_outlineView;
+}
+
+@property(readonly) PLItem *rootItem;
+
+- (id)initWithOutlineView:(NSOutlineView *)outlineView playlist:(playlist_t *)pl rootItem:(playlist_item_t *)root;
+
+- (void)changeRootItem:(playlist_item_t *)p_root;
+
+- (BOOL)hasChildren;
+
+typedef enum {
+ ROOT_TYPE_PLAYLIST,
+ ROOT_TYPE_MEDIALIBRARY,
+ ROOT_TYPE_OTHER
+} PLRootType;
+
+- (PLRootType)currentRootType;
+
+- (BOOL)editAllowed;
+
+- (void)addItem:(int)i_item withParentNode:(int)i_node;
+- (void)removeItem:(int)i_item;
+
+- (void)sortForColumn:(NSString *)o_column withMode:(int)i_mode;
+
+
+
+
+
+@end
+
--- /dev/null
+/*****************************************************************************
+ * PLItem.m: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2014 VLC authors and VideoLAN
+ * $Id$
+ *
+ * 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.
+ *****************************************************************************/
+
+#import "PLModel.h"
+
+#import "misc.h"
+
+#include <vlc_playlist.h>
+#include <vlc_input_item.h>
+#include <vlc_url.h>
+
+#define TRACKNUM_COLUMN @"tracknumber"
+#define TITLE_COLUMN @"name"
+#define ARTIST_COLUMN @"artist"
+#define DURATION_COLUMN @"duration"
+#define GENRE_COLUMN @"genre"
+#define ALBUM_COLUMN @"album"
+#define DESCRIPTION_COLUMN @"description"
+#define DATE_COLUMN @"date"
+#define LANGUAGE_COLUMN @"language"
+#define URI_COLUMN @"uri"
+#define FILESIZE_COLUMN @"file-size"
+
+#pragma mark -
+
+@implementation PLModel
+
+@synthesize rootItem=_rootItem;
+
+- (id)initWithOutlineView:(NSOutlineView *)outlineView playlist:(playlist_t *)pl rootItem:(playlist_item_t *)root;
+{
+ self = [super init];
+ if(self) {
+ p_playlist = pl;
+ _outlineView = [outlineView retain];
+
+ PL_LOCK;
+ _rootItem = [[PLItem alloc] initWithPlaylistItem:root parent:nil];
+ [self rebuildPLItem:_rootItem];
+ PL_UNLOCK;
+
+ }
+
+ return self;
+}
+
+- (void)changeRootItem:(playlist_item_t *)p_root;
+{
+ NSLog(@"change root item to %p", p_root);
+ PL_ASSERT_LOCKED;
+ [_rootItem release];
+ _rootItem = [[PLItem alloc] initWithPlaylistItem:p_root parent:nil];
+ [self rebuildPLItem:_rootItem];
+ [_outlineView reloadData];
+}
+
+- (BOOL)hasChildren
+{
+ return [[_rootItem children] count] > 0;
+}
+
+- (PLRootType)currentRootType
+{
+ int i_root_id = [_rootItem plItemId];
+ if (i_root_id == p_playlist->p_playing->i_id)
+ return ROOT_TYPE_PLAYLIST;
+ if (p_playlist->p_media_library && i_root_id == p_playlist->p_media_library->i_id)
+ return ROOT_TYPE_MEDIALIBRARY;
+
+ return ROOT_TYPE_OTHER;
+}
+
+- (BOOL)editAllowed
+{
+ return [self currentRootType] == ROOT_TYPE_MEDIALIBRARY ||
+ [self currentRootType] == ROOT_TYPE_PLAYLIST;
+}
+
+
+
+- (void)rebuildPLItem:(PLItem *)o_item
+{
+ [o_item clear];
+ playlist_item_t *p_item = playlist_ItemGetById(p_playlist, [o_item plItemId]);
+ if (p_item) {
+ for(int i = 0; i < p_item->i_children; ++i) {
+ PLItem *o_child = [[[PLItem alloc] initWithPlaylistItem:p_item->pp_children[i] parent:o_item] autorelease];
+ [o_item addChild:o_child atPos:i];
+
+ if (p_item->pp_children[i]->i_children >= 0) {
+ [self rebuildPLItem:o_child];
+ }
+
+ }
+ }
+
+}
+
+- (PLItem *)findItemByPlaylistId:(int)i_pl_id
+{
+ return [self findItemInnerByPlaylistId:i_pl_id node:_rootItem];
+}
+
+- (PLItem *)findItemInnerByPlaylistId:(int)i_pl_id node:(PLItem *)node
+{
+ if ([node plItemId] == i_pl_id) {
+ return node;
+ }
+
+ for (NSUInteger i = 0; i < [[node children] count]; ++i) {
+ PLItem *o_sub_item = [[node children] objectAtIndex:i];
+ if ([o_sub_item plItemId] == i_pl_id) {
+ return o_sub_item;
+ }
+
+ if (![o_sub_item isLeaf]) {
+ PLItem *o_returned = [self findItemInnerByPlaylistId:i_pl_id node:o_sub_item];
+ if (o_returned)
+ return o_returned;
+ }
+ }
+
+ return nil;
+}
+
+
+- (void)addItem:(int)i_item withParentNode:(int)i_node
+{
+ NSLog(@"add item with index %d, parent: %d", i_item, i_node);
+
+ PLItem *o_parent = [self findItemByPlaylistId:i_node];
+ if (!o_parent) {
+ return;
+ }
+
+ PL_LOCK;
+ playlist_item_t *p_item = playlist_ItemGetById(p_playlist, i_item);
+ if (!p_item || p_item->i_flags & PLAYLIST_DBL_FLAG)
+ {
+ PL_UNLOCK; return;
+ }
+
+ int pos;
+ for(pos = p_item->p_parent->i_children - 1; pos >= 0; pos--)
+ if(p_item->p_parent->pp_children[pos] == p_item)
+ break;
+
+ PLItem *o_new_item = [[[PLItem alloc] initWithPlaylistItem:p_item parent:o_parent] autorelease];
+ PL_UNLOCK;
+ if (pos < 0)
+ return;
+
+ [o_parent addChild:o_new_item atPos:pos];
+
+ if ([o_parent plItemId] == [_rootItem plItemId])
+ [_outlineView reloadData];
+ else // only reload leafs this way, doing it with nil collapses width of title column
+ [_outlineView reloadItem:o_parent reloadChildren:YES];
+}
+
+- (void)removeItem:(int)i_item
+{
+ NSLog(@"remove item with index %d", i_item);
+
+ PLItem *o_item = [self findItemByPlaylistId:i_item];
+ if (!o_item) {
+ return;
+ }
+
+ PLItem *o_parent = [o_item parent];
+ [o_parent deleteChild:o_item];
+
+ if ([o_parent plItemId] == [_rootItem plItemId])
+ [_outlineView reloadData];
+ else
+ [_outlineView reloadItem:o_parent reloadChildren:YES];
+}
+
+- (void)sortForColumn:(NSString *)o_column withMode:(int)i_mode
+{
+ int i_column = 0;
+ if ([o_column isEqualToString:TRACKNUM_COLUMN])
+ i_column = SORT_TRACK_NUMBER;
+ else if ([o_column isEqualToString:TITLE_COLUMN])
+ i_column = SORT_TITLE;
+ else if ([o_column isEqualToString:ARTIST_COLUMN])
+ i_column = SORT_ARTIST;
+ else if ([o_column isEqualToString:GENRE_COLUMN])
+ i_column = SORT_GENRE;
+ else if ([o_column isEqualToString:DURATION_COLUMN])
+ i_column = SORT_DURATION;
+ else if ([o_column isEqualToString:ALBUM_COLUMN])
+ i_column = SORT_ALBUM;
+ else if ([o_column isEqualToString:DESCRIPTION_COLUMN])
+ i_column = SORT_DESCRIPTION;
+ else if ([o_column isEqualToString:URI_COLUMN])
+ i_column = SORT_URI;
+ else
+ return;
+
+ PL_LOCK;
+ playlist_item_t *p_root = playlist_ItemGetById(p_playlist, [_rootItem plItemId]);
+ if (!p_root) {
+ PL_UNLOCK;
+ return;
+ }
+
+ playlist_RecursiveNodeSort(p_playlist, p_root, i_column, i_mode);
+
+ [self rebuildPLItem:_rootItem];
+ [_outlineView reloadData];
+ PL_UNLOCK;
+}
+
+@end
+
+#pragma mark -
+#pragma mark Outline view data source
+
+@implementation PLModel(NSOutlineViewDataSource)
+
+- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
+{
+ return !item ? [[_rootItem children] count] : [[item children] count];
+}
+
+- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
+{
+ return !item ? YES : [[item children] count] > 0;
+}
+
+- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item
+{
+ id obj = !item ? _rootItem : item;
+ return [[obj children] objectAtIndex:index];
+}
+
+- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
+{
+ id o_value = nil;
+ char * psz_value;
+ playlist_item_t *p_item;
+
+ input_item_t *p_input = [item input];
+
+ NSString * o_identifier = [tableColumn identifier];
+
+ if ([o_identifier isEqualToString:TRACKNUM_COLUMN]) {
+ psz_value = input_item_GetTrackNumber(p_input);
+ if (psz_value) {
+ o_value = [NSString stringWithUTF8String:psz_value];
+ free(psz_value);
+ }
+ } else if ([o_identifier isEqualToString:TITLE_COLUMN]) {
+ /* sanity check to prevent the NSString class from crashing */
+ char *psz_title = input_item_GetTitleFbName(p_input);
+ if (psz_title) {
+ o_value = [NSString stringWithUTF8String:psz_title];
+ free(psz_title);
+ }
+ } else if ([o_identifier isEqualToString:ARTIST_COLUMN]) {
+ psz_value = input_item_GetArtist(p_input);
+ if (psz_value) {
+ o_value = [NSString stringWithUTF8String:psz_value];
+ free(psz_value);
+ }
+ } else if ([o_identifier isEqualToString:@"duration"]) {
+ char psz_duration[MSTRTIME_MAX_SIZE];
+ mtime_t dur = input_item_GetDuration(p_input);
+ if (dur != -1) {
+ secstotimestr(psz_duration, dur/1000000);
+ o_value = [NSString stringWithUTF8String:psz_duration];
+ }
+ else
+ o_value = @"--:--";
+ } else if ([o_identifier isEqualToString:GENRE_COLUMN]) {
+ psz_value = input_item_GetGenre(p_input);
+ if (psz_value) {
+ o_value = [NSString stringWithUTF8String:psz_value];
+ free(psz_value);
+ }
+ } else if ([o_identifier isEqualToString:ALBUM_COLUMN]) {
+ psz_value = input_item_GetAlbum(p_input);
+ if (psz_value) {
+ o_value = [NSString stringWithUTF8String:psz_value];
+ free(psz_value);
+ }
+ } else if ([o_identifier isEqualToString:DESCRIPTION_COLUMN]) {
+ psz_value = input_item_GetDescription(p_input);
+ if (psz_value) {
+ o_value = [NSString stringWithUTF8String:psz_value];
+ free(psz_value);
+ }
+ } else if ([o_identifier isEqualToString:DATE_COLUMN]) {
+ psz_value = input_item_GetDate(p_input);
+ if (psz_value) {
+ o_value = [NSString stringWithUTF8String:psz_value];
+ free(psz_value);
+ }
+ } else if ([o_identifier isEqualToString:LANGUAGE_COLUMN]) {
+ psz_value = input_item_GetLanguage(p_input);
+ if (psz_value) {
+ o_value = [NSString stringWithUTF8String:psz_value];
+ free(psz_value);
+ }
+ }
+ else if ([o_identifier isEqualToString:URI_COLUMN]) {
+ psz_value = decode_URI(input_item_GetURI(p_input));
+ if (psz_value) {
+ o_value = [NSString stringWithUTF8String:psz_value];
+ free(psz_value);
+ }
+ }
+ else if ([o_identifier isEqualToString:FILESIZE_COLUMN]) {
+ psz_value = input_item_GetURI(p_item->p_input);
+ o_value = @"";
+ if (psz_value) {
+ NSURL *url = [NSURL URLWithString:[NSString stringWithUTF8String:psz_value]];
+ if ([url isFileURL]) {
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ if ([fileManager fileExistsAtPath:[url path]]) {
+ NSError *error;
+ NSDictionary *attributes = [fileManager attributesOfItemAtPath:[url path] error:&error];
+ o_value = [VLCByteCountFormatter stringFromByteCount:[attributes fileSize] countStyle:NSByteCountFormatterCountStyleDecimal];
+ }
+ }
+ free(psz_value);
+ }
+
+ }
+ else if ([o_identifier isEqualToString:@"status"]) {
+ if (input_item_HasErrorWhenReading(p_input)) {
+ o_value = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kAlertCautionIcon)];
+ [o_value setSize: NSMakeSize(16,16)];
+ }
+ }
+
+ return o_value;
+}
+
+@end
vlc_value_t, vlc_value_t, void *);
static int PlaylistUpdated(vlc_object_t *, const char *,
vlc_value_t, vlc_value_t, void *);
+
static int PlaybackModeUpdated(vlc_object_t *, const char *,
vlc_value_t, vlc_value_t, void *);
static int VolumeUpdated(vlc_object_t *, const char *,
return VLC_SUCCESS;
}
+static int PLItemAppended(vlc_object_t *p_this, const char *psz_var,
+ vlc_value_t oldval, vlc_value_t new_val, void *param)
+{
+ NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
+
+ playlist_add_t *p_add = new_val.p_address;
+ NSArray *o_val = [NSArray arrayWithObjects:[NSNumber numberWithInt:p_add->i_node], [NSNumber numberWithInt:p_add->i_item], nil];
+ [[VLCMain sharedInstance] performSelectorOnMainThread:@selector(plItemAppended:) withObject:o_val waitUntilDone:NO];
+
+ [o_pool release];
+ return VLC_SUCCESS;
+}
+
+static int PLItemRemoved(vlc_object_t *p_this, const char *psz_var,
+ vlc_value_t oldval, vlc_value_t new_val, void *param)
+{
+ NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
+
+ NSNumber *o_val = [NSNumber numberWithInt:new_val.i_int];
+ [[VLCMain sharedInstance] performSelectorOnMainThread:@selector(plItemRemoved:) withObject:o_val waitUntilDone:NO];
+
+ [o_pool release];
+ return VLC_SUCCESS;
+}
+
static int PlaylistUpdated(vlc_object_t *p_this, const char *psz_var,
vlc_value_t oldval, vlc_value_t new_val, void *param)
{
var_AddCallback(p_playlist, "item-change", PLItemUpdated, self);
var_AddCallback(p_playlist, "activity", PLItemChanged, self);
var_AddCallback(p_playlist, "leaf-to-parent", PlaylistUpdated, self);
- var_AddCallback(p_playlist, "playlist-item-append", PlaylistUpdated, self);
- var_AddCallback(p_playlist, "playlist-item-deleted", PlaylistUpdated, self);
+ var_AddCallback(p_playlist, "playlist-item-append", PLItemAppended, self);
+ var_AddCallback(p_playlist, "playlist-item-deleted", PLItemRemoved, self);
var_AddCallback(p_playlist, "random", PlaybackModeUpdated, self);
var_AddCallback(p_playlist, "repeat", PlaybackModeUpdated, self);
var_AddCallback(p_playlist, "loop", PlaybackModeUpdated, self);
var_DelCallback(p_playlist, "item-change", PLItemUpdated, self);
var_DelCallback(p_playlist, "activity", PLItemChanged, self);
var_DelCallback(p_playlist, "leaf-to-parent", PlaylistUpdated, self);
- var_DelCallback(p_playlist, "playlist-item-append", PlaylistUpdated, self);
- var_DelCallback(p_playlist, "playlist-item-deleted", PlaylistUpdated, self);
+ var_DelCallback(p_playlist, "playlist-item-append", PLItemAppended, self);
+ var_DelCallback(p_playlist, "playlist-item-deleted", PLItemRemoved, self);
var_DelCallback(p_playlist, "random", PlaybackModeUpdated, self);
var_DelCallback(p_playlist, "repeat", PlaybackModeUpdated, self);
var_DelCallback(p_playlist, "loop", PlaybackModeUpdated, self);
#pragma mark -
#pragma mark Interface updaters
+
+- (void)plItemAppended:(NSArray *)o_val
+{
+ int i_node = [[o_val objectAtIndex:0] intValue];
+ int i_item = [[o_val objectAtIndex:1] intValue];
+
+ [[[self playlist] model] addItem:i_item withParentNode:i_node];
+}
+
+- (void)plItemRemoved:(NSNumber *)o_val
+{
+ int i_item = [o_val intValue];
+
+ [[[self playlist] model] removeItem:i_item];
+}
+
+
// This must be called on main thread
- (void)PlaylistItemChanged
{
if (b_mediaKeySupport && !o_mediaKeyController)
o_mediaKeyController = [[SPMediaKeyTap alloc] initWithDelegate:self];
- if (b_mediaKeySupport && ([[[VLCMain sharedInstance] playlist] currentPlaylistRoot]->i_children > 0 ||
+ if (b_mediaKeySupport && ([[[[VLCMain sharedInstance] playlist] model] hasChildren] ||
p_current_input)) {
if (!b_mediaKeyTrapEnabled) {
b_mediaKeyTrapEnabled = YES;
@end
+#import "PLModel.h"
+
/*****************************************************************************
* VLCPlaylist interface
*****************************************************************************/
IBOutlet id o_playlist_header;
int currentResumeTimeout;
+
+ PLModel *o_model;
}
-- (void)setPlaylistRoot: (playlist_item_t *)root_item;
+- (PLModel *)model;
+
- (playlist_item_t *)currentPlaylistRoot;
- (void)reloadStyles;
@end
-
/*****************************************************************************
* VLCPlaylistWizard implementation
*****************************************************************************/
[o_columnArray release];
}
-- (void)setPlaylistRoot: (playlist_item_t *)root_item
+- (playlist_item_t *)currentPlaylistRoot
{
- p_current_root_item = root_item;
- [o_outline_view reloadData];
+ // TODO remove
+ playlist_t *p_playlist = pl_Get(VLCIntf);
+ return p_playlist->p_playing;
}
-- (playlist_item_t *)currentPlaylistRoot
+- (PLModel *)model
{
- return p_current_root_item;
+ return o_model;
}
- (void)reloadStyles
playlist_t * p_playlist = pl_Get(VLCIntf);
[o_outline_view setTarget: self];
[o_outline_view setDelegate: self];
- [o_outline_view setDataSource: self];
[o_outline_view setAllowsEmptySelection: NO];
[o_outline_view expandItem: [o_outline_view itemAtRow:0]];
[self reloadStyles];
[self initStrings];
+ o_model = [[PLModel alloc] initWithOutlineView:o_outline_view playlist:p_playlist rootItem:p_current_root_item];
+ [o_outline_view setDataSource:o_model];
+ [o_outline_view reloadData];
+
[o_outline_view setDoubleAction: @selector(playItem:)];
[o_outline_view registerForDraggedTypes: [NSArray arrayWithObjects:NSFilenamesPboardType, @"VLCPlaylistItemPboardType", nil]];
- (void)searchfieldChanged:(NSNotification *)o_notification
{
+ assert(0);
[o_search_field setStringValue:[[o_notification object] stringValue]];
}
- (void)outlineViewSelectionDidChange:(NSNotification *)notification
{
- // FIXME: unsafe
- playlist_item_t * p_item = [[o_outline_view itemAtRow:[o_outline_view selectedRow]] pointerValue];
-
- if (p_item) {
- /* update the state of our Reveal-in-Finder menu items */
- NSMutableString *o_mrl;
- char *psz_uri = input_item_GetURI(p_item->p_input);
-
- [o_mi_revealInFinder setEnabled: NO];
- [o_mm_mi_revealInFinder setEnabled: NO];
- if (psz_uri) {
- o_mrl = [NSMutableString stringWithUTF8String: psz_uri];
-
- /* perform some checks whether it is a file and if it is local at all... */
- NSRange prefix_range = [o_mrl rangeOfString: @"file:"];
- if (prefix_range.location != NSNotFound)
- [o_mrl deleteCharactersInRange: prefix_range];
-
- if ([o_mrl characterAtIndex:0] == '/') {
- [o_mi_revealInFinder setEnabled: YES];
- [o_mm_mi_revealInFinder setEnabled: YES];
- }
- free(psz_uri);
- }
-
- /* update our info-panel to reflect the new item */
- [[[VLCMain sharedInstance] info] updatePanelWithItem:p_item->p_input];
- }
+// // FIXME: unsafe
+// playlist_item_t * p_item = [[o_outline_view itemAtRow:[o_outline_view selectedRow]] pointerValue];
+//
+// if (p_item) {
+// /* update the state of our Reveal-in-Finder menu items */
+// NSMutableString *o_mrl;
+// char *psz_uri = input_item_GetURI(p_item->p_input);
+//
+// [o_mi_revealInFinder setEnabled: NO];
+// [o_mm_mi_revealInFinder setEnabled: NO];
+// if (psz_uri) {
+// o_mrl = [NSMutableString stringWithUTF8String: psz_uri];
+//
+// /* perform some checks whether it is a file and if it is local at all... */
+// NSRange prefix_range = [o_mrl rangeOfString: @"file:"];
+// if (prefix_range.location != NSNotFound)
+// [o_mrl deleteCharactersInRange: prefix_range];
+//
+// if ([o_mrl characterAtIndex:0] == '/') {
+// [o_mi_revealInFinder setEnabled: YES];
+// [o_mm_mi_revealInFinder setEnabled: YES];
+// }
+// free(psz_uri);
+// }
+//
+// /* update our info-panel to reflect the new item */
+// [[[VLCMain sharedInstance] info] updatePanelWithItem:p_item->p_input];
+// }
}
- (BOOL)isSelectionEmpty
deleted. We don't do it when not required since this verification takes
quite a long time on big playlists (yes, pretty hacky). */
-- (BOOL)isItem: (playlist_item_t *)p_item inNode: (playlist_item_t *)p_node checkItemExistence:(BOOL)b_check locked:(BOOL)b_locked
+// todo remove useless parameters
+- (BOOL)isItem: (PLItem *)p_item inNode: (PLItem *)p_node checkItemExistence:(BOOL)b_check locked:(BOOL)b_locked
{
- playlist_t * p_playlist = pl_Get(VLCIntf);
- playlist_item_t *p_temp_item = p_item;
-
- if (!p_node)
- return NO;
+ PLItem *p_temp_item = p_item;
- if (p_node == p_item)
+ if ([p_node plItemId] == [p_item plItemId])
return YES;
- if (p_node->i_children < 1)
- return NO;
-
- if (p_temp_item) {
- int i;
- if (!b_locked) PL_LOCK;
-
- if (b_check) {
- /* Since outlineView: willDisplayCell:... may call this function with
- p_items that don't exist anymore, first check if the item is still
- in the playlist. Any cleaner solution welcomed. */
- for (i = 0; i < p_playlist->all_items.i_size; i++) {
- if (ARRAY_VAL(p_playlist->all_items, i) == p_item)
- break;
- else if (i == p_playlist->all_items.i_size - 1)
- {
- if (!b_locked) PL_UNLOCK;
- return NO;
- }
- }
- }
-
- while(p_temp_item) {
- p_temp_item = p_temp_item->p_parent;
- if (p_temp_item == p_node) {
- if (!b_locked) PL_UNLOCK;
- return YES;
- }
+ while(p_temp_item) {
+ p_temp_item = [p_temp_item parent];
+ if ([p_temp_item plItemId] == [p_node plItemId]) {
+ return YES;
}
- if (!b_locked) PL_UNLOCK;
}
+
return NO;
}
if (o_items == o_nodes) {
if (j == i) continue;
}
- if ([self isItem: [[o_items objectAtIndex:i] pointerValue]
- inNode: [[o_nodes objectAtIndex:j] pointerValue]
+ if ([self isItem: [o_items objectAtIndex:i]
+ inNode: [o_nodes objectAtIndex:j]
checkItemExistence: NO locked:NO]) {
[o_items removeObjectAtIndex:i];
/* We need to execute the next iteration with the same index
if (sender != nil && [o_outline_view clickedRow] == -1 && sender != o_mi_play)
return;
- p_item = [[o_outline_view itemAtRow:[o_outline_view selectedRow]] pointerValue];
-
PL_LOCK;
+ PLItem *o_item = [o_outline_view itemAtRow:[o_outline_view selectedRow]];
+ p_item = playlist_ItemGetById(p_playlist, [o_item plItemId]);
+
if (p_item) {
if (p_item->i_children == -1) {
p_node = p_item->p_parent;
[selectedRows getIndexes:indexes maxCount:count inIndexRange:nil];
NSMutableString * o_mrl;
- playlist_item_t *p_item;
for (NSUInteger i = 0; i < count; i++) {
- p_item = [[o_outline_view itemAtRow:indexes[i]] pointerValue];
+ PLItem *o_item = [o_outline_view itemAtRow:indexes[i]];
- if (! p_item || !p_item->p_input)
- continue;
-
- char * psz_url = decode_URI(input_item_GetURI(p_item->p_input));
+ char * psz_url = decode_URI(input_item_GetURI([o_item input]));
o_mrl = [[NSMutableString alloc] initWithString: [NSString stringWithUTF8String:psz_url ? psz_url : ""]];
if (psz_url != NULL)
free( psz_url );
NSUInteger indexes[i_count];
[o_selected_indexes getIndexes:indexes maxCount:i_count inIndexRange:nil];
for (int i = 0; i < i_count; i++) {
- p_item = [[o_outline_view itemAtRow:indexes[i]] pointerValue];
+ PLItem *o_item = [o_outline_view itemAtRow:indexes[i]];
[o_outline_view deselectRow: indexes[i]];
- if (p_item) {
- if (p_item->i_children == -1)
- libvlc_MetaRequest(p_intf->p_libvlc, p_item->p_input, META_REQUEST_OPTION_NONE);
- else
- msg_Dbg(p_intf, "preparsing nodes not implemented");
+ if (![o_item isLeaf]) {
+ msg_Dbg(p_intf, "preparsing nodes not implemented");
+ continue;
}
+
+ libvlc_MetaRequest(p_intf->p_libvlc, [o_item input], META_REQUEST_OPTION_NONE);
+
}
[self playlistUpdated];
}
NSUInteger indexes[i_count];
[o_selected_indexes getIndexes:indexes maxCount:i_count inIndexRange:nil];
for (int i = 0; i < i_count; i++) {
- p_item = [[o_outline_view itemAtRow: indexes[i]] pointerValue];
+ PLItem *o_item = [o_outline_view itemAtRow: indexes[i]];
- if (p_item && p_item->i_children == -1)
- libvlc_ArtRequest(p_intf->p_libvlc, p_item->p_input, META_REQUEST_OPTION_NONE);
+ if (![o_item isLeaf])
+ continue;
+
+ libvlc_ArtRequest(p_intf->p_libvlc, [o_item input], META_REQUEST_OPTION_NONE);
}
[self playlistUpdated];
}
playlist_t * p_playlist = pl_Get(p_intf);
// check if deletion is allowed
- if ([self currentPlaylistRoot] != p_playlist->p_local_category && [self currentPlaylistRoot] != p_playlist->p_ml_category)
+ if (![[self model] editAllowed])
return;
o_selected_indexes = [o_outline_view selectedRowIndexes];
NSUInteger indexes[i_count];
- if (i_count == [o_outline_view numberOfRows]) {
- PL_LOCK;
- playlist_NodeDelete(p_playlist, [self currentPlaylistRoot], true, false);
- PL_UNLOCK;
- [self playlistUpdated];
- return;
- }
+// if (i_count == [o_outline_view numberOfRows]) {
+// PL_LOCK;
+// playlist_NodeDelete(p_playlist, [self currentPlaylistRoot], true, false);
+// PL_UNLOCK;
+// [self playlistUpdated];
+// return;
+// }
[o_selected_indexes getIndexes:indexes maxCount:i_count inIndexRange:nil];
for (int i = 0; i < i_count; i++) {
- id o_item = [o_outline_view itemAtRow: indexes[i]];
+ PLItem *o_item = [o_outline_view itemAtRow: indexes[i]];
[o_outline_view deselectRow: indexes[i]];
- PL_LOCK;
- playlist_item_t *p_item = [o_item pointerValue];
- if (!p_item || !p_item->p_input) {
- PL_UNLOCK;
- continue;
- }
-
- if (p_item->i_children != -1) {
- //is a node and not an item
- if (playlist_Status(p_playlist) != PLAYLIST_STOPPED &&
- [self isItem: playlist_CurrentPlayingItem(p_playlist) inNode: ((playlist_item_t *)[o_item pointerValue])
- checkItemExistence: NO locked:YES] == YES)
- // if current item is in selected node and is playing then stop playlist
- playlist_Control(p_playlist, PLAYLIST_STOP, pl_Locked);
-
- playlist_NodeDelete(p_playlist, p_item, true, false);
- } else
- playlist_DeleteFromInput(p_playlist, p_item->p_input, pl_Locked);
-
- PL_UNLOCK;
- [o_outline_dict removeObjectForKey:[NSString stringWithFormat:@"%p", [o_item pointerValue]]];
- [o_item release];
+ /// TODO
+// if (p_item->i_children != -1) {
+// //is a node and not an item
+// if (playlist_Status(p_playlist) != PLAYLIST_STOPPED &&
+// [self isItem: playlist_CurrentPlayingItem(p_playlist) inNode: ((playlist_item_t *)[o_item pointerValue])
+// checkItemExistence: NO locked:YES] == YES)
+// // if current item is in selected node and is playing then stop playlist
+// playlist_Control(p_playlist, PLAYLIST_STOP, pl_Locked);
+//
+// playlist_NodeDelete(p_playlist, p_item, true, false);
+// } else
+
+ playlist_DeleteFromInput(p_playlist, [o_item input], pl_Unlocked);
+// [[o_item parent] deleteChild:o_item];
+//
+// [o_outline_view reloadData];
}
- [self playlistUpdated];
+// [self playlistUpdated];
}
- (IBAction)sortNodeByName:(id)sender
playlist_t * p_playlist = pl_Get(VLCIntf);
playlist_item_t * p_item;
- if ([o_outline_view selectedRow] > -1) {
- p_item = [[o_outline_view itemAtRow: [o_outline_view selectedRow]] pointerValue];
- if (!p_item)
- return;
- } else
- p_item = [self currentPlaylistRoot]; // If no item is selected, sort the whole playlist
-
- PL_LOCK;
- if (p_item->i_children > -1) // the item is a node
- playlist_RecursiveNodeSort(p_playlist, p_item, i_mode, ORDER_NORMAL);
- else
- playlist_RecursiveNodeSort(p_playlist, p_item->p_parent, i_mode, ORDER_NORMAL);
-
- PL_UNLOCK;
- [self playlistUpdated];
+ // TODO why do we need this kind of sort? It looks crap and confusing...
+
+// if ([o_outline_view selectedRow] > -1) {
+// p_item = [[o_outline_view itemAtRow: [o_outline_view selectedRow]] pointerValue];
+// if (!p_item)
+// return;
+// } else
+// p_item = [self currentPlaylistRoot]; // If no item is selected, sort the whole playlist
+//
+// PL_LOCK;
+// if (p_item->i_children > -1) // the item is a node
+// playlist_RecursiveNodeSort(p_playlist, p_item, i_mode, ORDER_NORMAL);
+// else
+// playlist_RecursiveNodeSort(p_playlist, p_item->p_parent, i_mode, ORDER_NORMAL);
+//
+// PL_UNLOCK;
+// [self playlistUpdated];
}
- (input_item_t *)createItem:(NSDictionary *)o_one_item
{
playlist_t * p_playlist = pl_Get(VLCIntf);
NSUInteger count = [o_array count];
- BOOL b_usingPlaylist;
- if ([self currentPlaylistRoot] == p_playlist->p_ml_category)
- b_usingPlaylist = NO;
- else
- b_usingPlaylist = YES;
+ BOOL b_usingPlaylist = [[self model] currentRootType] == ROOT_TYPE_PLAYLIST;
PL_LOCK;
for (NSUInteger i_item = 0; i_item < count; i_item++) {
PL_UNLOCK;
vlc_gc_decref(p_input);
}
- [self playlistUpdated];
+// [self playlistUpdated];
}
- (NSMutableArray *)subSearchItem:(playlist_item_t *)p_item
b_rows = [o_outline_view numberOfRows] != 0;
playlist_t *p_playlist = pl_Get(VLCIntf);
- bool b_del_allowed = [self currentPlaylistRoot] == p_playlist->p_local_category || [self currentPlaylistRoot] == p_playlist->p_ml_category;
+ bool b_del_allowed = [[self model] editAllowed];
[o_mi_play setEnabled: b_item_sel];
[o_mi_delete setEnabled: b_item_sel && b_del_allowed];
playlist_t *p_playlist = pl_Get(p_intf);
- if ([o_identifier isEqualToString:TRACKNUM_COLUMN])
- i_mode = SORT_TRACK_NUMBER;
- else if ([o_identifier isEqualToString:TITLE_COLUMN])
- i_mode = SORT_TITLE;
- else if ([o_identifier isEqualToString:ARTIST_COLUMN])
- i_mode = SORT_ARTIST;
- else if ([o_identifier isEqualToString:GENRE_COLUMN])
- i_mode = SORT_GENRE;
- else if ([o_identifier isEqualToString:DURATION_COLUMN])
- i_mode = SORT_DURATION;
- else if ([o_identifier isEqualToString:ALBUM_COLUMN])
- i_mode = SORT_ALBUM;
- else if ([o_identifier isEqualToString:DESCRIPTION_COLUMN])
- i_mode = SORT_DESCRIPTION;
- else if ([o_identifier isEqualToString:URI_COLUMN])
- i_mode = SORT_URI;
- else
- return;
-
if (o_tc_sortColumn == o_tc)
b_isSortDescending = !b_isSortDescending;
else
else
i_type = ORDER_NORMAL;
- PL_LOCK;
- playlist_RecursiveNodeSort(p_playlist, [self currentPlaylistRoot], i_mode, i_type);
- PL_UNLOCK;
+ [[self model] sortForColumn:o_identifier withMode:i_type];
+
+ // TODO rework, why do we need a full call here?
+// [self playlistUpdated];
+
+ /* Clear indications of any existing column sorting */
+ NSUInteger count = [[o_outline_view tableColumns] count];
+ for (NSUInteger i = 0 ; i < count ; i++)
+ [o_outline_view setIndicatorImage:nil inTableColumn: [[o_outline_view tableColumns] objectAtIndex:i]];
+
+ [o_outline_view setHighlightedTableColumn:nil];
+ o_tc_sortColumn = nil;
- [self playlistUpdated];
o_tc_sortColumn = o_tc;
[o_outline_view setHighlightedTableColumn:o_tc];
- (void)outlineView:(NSOutlineView *)outlineView
- willDisplayCell:(id)cell
- forTableColumn:(NSTableColumn *)tableColumn
- item:(id)item
+ willDisplayCell:(id)cell
+ forTableColumn:(NSTableColumn *)tableColumn
+ item:(id)item
{
/* this method can be called when VLC is already dead, hence the extra checks */
intf_thread_t * p_intf = VLCIntf;
if (!p_intf)
return;
playlist_t *p_playlist = pl_Get(p_intf);
- if (!p_playlist)
- return;
id o_playing_item;
else
fontToUse = [NSFont systemFontOfSize:11.];
- if ([self isItem: [o_playing_item pointerValue] inNode: [item pointerValue] checkItemExistence:YES locked:NO]
- || [o_playing_item isEqual: item])
+ BOOL b_is_playing = NO;
+ PL_LOCK;
+ playlist_item_t *p_current_item = playlist_CurrentPlayingItem(p_playlist);
+ if (p_current_item) {
+ b_is_playing = p_current_item->i_id == [item plItemId];
+ }
+ PL_UNLOCK;
+
+ /*
+ TODO: repaint all items bold:
+ [self isItem: [o_playing_item pointerValue] inNode: [item pointerValue] checkItemExistence:YES locked:NO]
+ || [o_playing_item isEqual: item]
+ */
+
+ if (b_is_playing)
[cell setFont: [[NSFontManager sharedFontManager] convertFont:fontToUse toHaveTrait:NSBoldFontMask]];
else
[cell setFont: [[NSFontManager sharedFontManager] convertFont:fontToUse toNotHaveTrait:NSBoldFontMask]];
id o_item = [items objectAtIndex:i];
/* Fill the items and nodes to move in 2 different arrays */
- if (((playlist_item_t *)[o_item pointerValue])->i_children > 0)
+ if (![o_item isLeaf])
[o_nodes_array addObject: o_item];
else
[o_items_array addObject: o_item];
/* 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_local_category checkItemExistence: NO locked: NO] ||
- (var_CreateGetBool(p_playlist, "media-library") && [self isItem: [item pointerValue] inNode: p_playlist->p_ml_category checkItemExistence: NO locked: NO])) || item == nil)) {
- return NSDragOperationNone;
- }
+ /// todo
+ // if (!(([self isItem: [item pointerValue] inNode: p_playlist->p_local_category checkItemExistence: NO locked: NO] ||
+// (var_CreateGetBool(p_playlist, "media-library") && [self isItem: [item pointerValue] inNode: p_playlist->p_ml_category checkItemExistence: NO locked: NO])) || item == nil)) {
+// return NSDragOperationNone;
+// }
/* Drop from the Playlist */
if ([[o_pasteboard types] containsObject: @"VLCPlaylistItemPboardType"]) {
NSUInteger count = [o_nodes_array count];
for (NSUInteger i = 0 ; i < 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 locked:NO]) {
+ if ([self isItem: item inNode: [o_nodes_array objectAtIndex:i] checkItemExistence: NO locked:NO]) {
return NSDragOperationNone;
}
}
child of the respective general node, if is either the pl or the ml
Else, choose the proposed parent as parent. */
if (item == nil) {
- if ([self currentPlaylistRoot] == p_playlist->p_local_category || [self currentPlaylistRoot] == p_playlist->p_ml_category)
- p_new_parent = [self currentPlaylistRoot];
+ // TODO edit allowed / no drop in other types
+ if ([[self model] currentRootType] == ROOT_TYPE_PLAYLIST ||
+ [[self model] currentRootType] == ROOT_TYPE_MEDIALIBRARY)
+ item = [[self model] rootItem];
else
return NO;
}
- else
- p_new_parent = [item pointerValue];
/* Make sure the proposed parent is a node.
(This should never be true) */
return NO;
PL_LOCK;
+ p_new_parent = playlist_ItemGetById(p_playlist, [item plItemId]);
+ if (!p_new_parent) {
+ PL_UNLOCK;
+ return NO;
+ }
+
NSUInteger j = 0;
for (NSUInteger i = 0; i < count; i++) {
- p_item = [[o_all_items objectAtIndex:i] pointerValue];
+ p_item = playlist_ItemGetById(p_playlist, [[o_all_items objectAtIndex:i] plItemId]);
if (p_item)
pp_items[j++] = p_item;
}
free(pp_items);
[self playlistUpdated];
- i_row = [o_outline_view rowForItem:[o_outline_dict objectForKey:[NSString stringWithFormat: @"%p", [[o_all_items objectAtIndex:0] pointerValue]]]];
+ i_row = [o_outline_view rowForItem:[o_all_items objectAtIndex:0]];
if (i_row == -1)
- i_row = [o_outline_view rowForItem:[o_outline_dict objectForKey:[NSString stringWithFormat: @"%p", p_new_parent]]];
+ i_row = [o_outline_view rowForItem:item];
[o_outline_view deselectAll: self];
[o_outline_view selectRowIndexes:[NSIndexSet indexSetWithIndex:i_row] byExtendingSelection:NO];
}
else if ([[o_pasteboard types] containsObject: NSFilenamesPboardType]) {
- if ([self currentPlaylistRoot] != p_playlist->p_local_category && [self currentPlaylistRoot] != p_playlist->p_ml_category)
+ // TODO: can this already checked in drop validation?
+ if (![[self model] editAllowed])
return NO;
playlist_item_t *p_node = [item pointerValue];