Commit c39aaf28 authored by David Fuhrmann's avatar David Fuhrmann

macosx: Add new playlist model

The current playlist model directly operates on the core playlist
datastructures without proper locking for a complete playlist table
reload/update. This resulted in various ugly hacks and workarounds.

The new playlist model encapsulates the data in own objects like
in the qt interface. This allows a much easier integration with
the table view and proper updates from the core playlist.

This way, the previous playlist objects, stored in an ugly map with
pointer strings as keys, pointing to the same pointer inside a
NSValue, is obsolete finally. :-)
parent da0b9bbc
......@@ -84,7 +84,8 @@ static VLCCoreInteraction *_o_sharedInstance = nil;
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];
......
......@@ -769,7 +769,8 @@ static VLCMainWindow *_o_sharedInstance = 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];
......@@ -947,15 +948,16 @@ static VLCMainWindow *_o_sharedInstance = nil;
#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
......@@ -964,9 +966,9 @@ static VLCMainWindow *_o_sharedInstance = nil;
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 @"";
......@@ -1132,19 +1134,29 @@ static VLCMainWindow *_o_sharedInstance = nil;
[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
......@@ -1154,7 +1166,8 @@ static VLCMainWindow *_o_sharedInstance = nil;
[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];
......
......@@ -95,4 +95,8 @@ SOURCES_macosx = \
BWQuincyUI.m \
iTunes.h \
Spotify.h \
PLItem.h \
PLItem.m \
PLModel.h \
PLModel.m \
$(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
/*****************************************************************************
* 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
/*****************************************************************************
* 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
This diff is collapsed.
......@@ -89,6 +89,7 @@ static int PLItemUpdated(vlc_object_t *, const char *,
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 *,
......@@ -413,6 +414,31 @@ static int PLItemUpdated(vlc_object_t *p_this, const char *psz_var,
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)
{
......@@ -682,8 +708,8 @@ static VLCMain *_o_sharedMainInstance = nil;
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);
......@@ -856,8 +882,8 @@ static bool f_appExit = false;
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);
......@@ -1289,6 +1315,23 @@ static bool f_appExit = false;
#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
{
......@@ -1848,7 +1891,7 @@ static const int kCurrentPreferencesVersion = 3;
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;
......
......@@ -53,6 +53,8 @@
@end
#import "PLModel.h"
/*****************************************************************************
* VLCPlaylist interface
*****************************************************************************/
......@@ -90,9 +92,12 @@
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;
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment