#import "misc.h"
#import "open.h"
#import "MainMenu.h"
+#import "CoreInteraction.h"
#include <vlc_keys.h>
#import <vlc_interface.h>
[o_outline_view setAllowsEmptySelection: NO];
[o_outline_view expandItem: [o_outline_view itemAtRow:0]];
- [o_outline_view_other setTarget: self];
- [o_outline_view_other setDelegate: self];
- [o_outline_view_other setDataSource: self];
- [o_outline_view_other setAllowsEmptySelection: NO];
-
- [[o_tc_name_other headerCell] setStringValue:_NS("Name")];
- [[o_tc_author_other headerCell] setStringValue:_NS("Author")];
- [[o_tc_duration_other headerCell] setStringValue:_NS("Duration")];
-
[self reloadStyles];
}
{
p_current_root_item = root_item;
[o_outline_view reloadData];
- [o_outline_view_other reloadData];
}
- (playlist_item_t *)currentPlaylistRoot
NSArray *columns = [o_outline_view tableColumns];
NSUInteger count = columns.count;
for (NSUInteger x = 0; x < count; x++)
- [[columns[x] dataCell] setFont:fontToUse];
+ [[[columns objectAtIndex:x] dataCell] setFont:fontToUse];
[o_outline_view setRowHeight:rowHeight];
-
- columns = [o_outline_view_other tableColumns];
- count = columns.count;
- for (NSUInteger x = 0; x < count; x++)
- [[columns[x] dataCell] setFont:fontToUse];
- [o_outline_view_other setRowHeight:rowHeight];
}
- (void)dealloc {
BOOL b_selected_item_met;
BOOL b_isSortDescending;
id o_tc_sortColumn;
- NSInteger retainedRowSelection;
+ NSUInteger retainedRowSelection;
BOOL b_playlistmenu_nib_loaded;
BOOL b_view_setup;
@implementation VLCPlaylist
-+ (void)initialize{
++ (void)initialize
+{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
- NSMutableArray * o_columnArray = [[NSMutableArray alloc] init];
+ NSMutableArray *o_columnArray = [[NSMutableArray alloc] init];
[o_columnArray addObject: [NSArray arrayWithObjects:TITLE_COLUMN, [NSNumber numberWithFloat:190.], nil]];
[o_columnArray addObject: [NSArray arrayWithObjects:ARTIST_COLUMN, [NSNumber numberWithFloat:95.], nil]];
[o_columnArray addObject: [NSArray arrayWithObjects:DURATION_COLUMN, [NSNumber numberWithFloat:95.], nil]];
- NSDictionary *appDefaults = [NSDictionary dictionaryWithObject:[NSArray arrayWithArray:o_columnArray] forKey: @"PlaylistColumnSelection"];
+
+ NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSArray arrayWithArray:o_columnArray], @"PlaylistColumnSelection",
+ [NSArray array], @"recentlyPlayedMediaList",
+ [NSDictionary dictionary], @"recentlyPlayedMedia", nil];
[defaults registerDefaults:appDefaults];
[o_columnArray release];
[self initStrings];
[o_outline_view setDoubleAction: @selector(playItem:)];
- [o_outline_view_other setDoubleAction: @selector(playItem:)];
[o_outline_view registerForDraggedTypes: [NSArray arrayWithObjects:NSFilenamesPboardType, @"VLCPlaylistItemPboardType", nil]];
[o_outline_view setIntercellSpacing: NSMakeSize (0.0, 1.0)];
- [o_outline_view_other registerForDraggedTypes: [NSArray arrayWithObjects:NSFilenamesPboardType, @"VLCPlaylistItemPboardType", nil]];
- [o_outline_view_other setIntercellSpacing: NSMakeSize (0.0, 1.0)];
-
/* This uses a private API, but works fine on all current OSX releases.
* Radar ID 11739459 request a public API for this. However, it is probably
* easier and faster to recreate similar looking bitmaps ourselves. */
//[o_outline_dict removeAllObjects];
[o_outline_view reloadData];
[[[[VLCMain sharedInstance] wizard] playlistWizard] reloadOutlineView];
- [[[[VLCMain sharedInstance] bookmarks] dataTable] reloadData];
[o_outline_view selectRowIndexes:[NSIndexSet indexSetWithIndex:retainedRowSelection] byExtendingSelection:NO];
p_item = NULL;
}
- /* continue playback where you left off */
- input_item_t *p_input = p_item->p_input;
- if (p_input)
- [self _continuePlaybackWhereYouLeftOff:p_input];
-
playlist_Control(p_playlist, PLAYLIST_VIEWPLAY, pl_Locked, p_node, p_item);
}
PL_UNLOCK;
if (p_item) {
if (p_item->i_children == -1)
- libvlc_MetaRequest(p_intf->p_libvlc, p_item->p_input);
+ libvlc_MetaRequest(p_intf->p_libvlc, p_item->p_input, META_REQUEST_OPTION_NONE);
else
msg_Dbg(p_intf, "preparsing nodes not implemented");
}
p_item = [[o_outline_view itemAtRow: indexes[i]] pointerValue];
if (p_item && p_item->i_children == -1)
- libvlc_ArtRequest(p_intf->p_libvlc, p_item->p_input);
+ libvlc_ArtRequest(p_intf->p_libvlc, p_item->p_input, META_REQUEST_OPTION_NONE);
}
[self playlistUpdated];
}
{
int i_count;
NSIndexSet *o_selected_indexes;
- playlist_t * p_playlist;
intf_thread_t * p_intf = VLCIntf;
+ 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)
+ return;
o_selected_indexes = [o_outline_view selectedRowIndexes];
i_count = [o_selected_indexes count];
retainedRowSelection = [o_selected_indexes firstIndex];
+ if (retainedRowSelection == NSNotFound)
+ retainedRowSelection = 0;
- p_playlist = pl_Get(p_intf);
NSUInteger indexes[i_count];
if (i_count == [o_outline_view numberOfRows]) {
if ([[NSFileManager defaultManager] fileExistsAtPath:o_path isDirectory:&b_dir] && b_dir &&
[[NSWorkspace sharedWorkspace] getFileSystemInfoForPath:o_path isRemovable: &b_rem
isWritable:&b_writable isUnmountable:NULL description:NULL type:NULL] && b_rem && !b_writable && [o_nsurl isFileURL]) {
- id o_vlc_open = [[VLCMain sharedInstance] open];
- NSString *diskType = [o_vlc_open getVolumeTypeFromMountPath: o_path];
+ NSString *diskType = [VLCOpen getVolumeTypeFromMountPath: o_path];
msg_Dbg(p_intf, "detected optical media of type %s in the file input", [diskType UTF8String]);
if ([diskType isEqualToString: kVLCMediaDVD])
- o_uri = [NSString stringWithFormat: @"dvdnav://%@", [o_vlc_open getBSDNodeFromMountPath: o_path]];
+ o_uri = [NSString stringWithFormat: @"dvdnav://%@", [VLCOpen getBSDNodeFromMountPath: o_path]];
else if ([diskType isEqualToString: kVLCMediaVideoTSFolder])
o_uri = [NSString stringWithFormat: @"dvdnav://%@", o_path];
else if ([diskType isEqualToString: kVLCMediaAudioCD])
- o_uri = [NSString stringWithFormat: @"cdda://%@", [o_vlc_open getBSDNodeFromMountPath: o_path]];
+ o_uri = [NSString stringWithFormat: @"cdda://%@", [VLCOpen getBSDNodeFromMountPath: o_path]];
else if ([diskType isEqualToString: kVLCMediaVCD])
- o_uri = [NSString stringWithFormat: @"vcd://%@#0:0", [o_vlc_open getBSDNodeFromMountPath: o_path]];
+ o_uri = [NSString stringWithFormat: @"vcd://%@#0:0", [VLCOpen getBSDNodeFromMountPath: o_path]];
else if ([diskType isEqualToString: kVLCMediaSVCD])
- o_uri = [NSString stringWithFormat: @"vcd://%@@0:0", [o_vlc_open getBSDNodeFromMountPath: o_path]];
+ o_uri = [NSString stringWithFormat: @"vcd://%@@0:0", [VLCOpen getBSDNodeFromMountPath: o_path]];
else if ([diskType isEqualToString: kVLCMediaBD] || [diskType isEqualToString: kVLCMediaBDMVFolder])
o_uri = [NSString stringWithFormat: @"bluray://%@", o_path];
else
input_item_AddOption(p_input, [[o_options objectAtIndex:i] UTF8String], VLC_INPUT_OPTION_TRUSTED);
}
- [self _continuePlaybackWhereYouLeftOff:p_input];
-
/* Recent documents menu */
if (o_nsurl != nil && (BOOL)config_GetInt(p_playlist, "macosx-recentitems") == YES)
[[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL: o_nsurl];
b_item_sel = (row != -1 && [o_outline_view selectedRow] != -1);
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;
+
[o_mi_play setEnabled: b_item_sel];
- [o_mi_delete setEnabled: b_item_sel];
+ [o_mi_delete setEnabled: b_item_sel && b_del_allowed];
[o_mi_selectall setEnabled: b_rows];
[o_mi_info setEnabled: b_item_sel];
[o_mi_preparse setEnabled: b_item_sel];
[o_arrayToSave release];
}
-- (void)_continuePlaybackWhereYouLeftOff:(input_item_t *)p_input
+- (BOOL)isValidResumeItem:(input_item_t *)p_item
+{
+ char *psz_url = input_item_GetURI(p_item);
+ NSString *o_url_string = toNSStr(psz_url);
+ free(psz_url);
+
+ if ([o_url_string isEqualToString:@""])
+ return NO;
+
+ NSURL *o_url = [NSURL URLWithString:o_url_string];
+
+ if (![o_url isFileURL])
+ return NO;
+
+ BOOL isDir = false;
+ if (![[NSFileManager defaultManager] fileExistsAtPath:[o_url path] isDirectory:&isDir])
+ return NO;
+
+ if (isDir)
+ return NO;
+
+ return YES;
+}
+
+- (void)updateAlertWindow:(NSTimer *)timer
+{
+ NSAlert *alert = [timer userInfo];
+
+ --currentResumeTimeout;
+ if (currentResumeTimeout <= 0) {
+ [[alert window] close];
+ [NSApp abortModal];
+ }
+
+ NSString *buttonLabel = _NS("Restart playback");
+ buttonLabel = [buttonLabel stringByAppendingFormat:@" (%d)", currentResumeTimeout];
+
+ [[[alert buttons] objectAtIndex:2] setTitle:buttonLabel];
+}
+
+- (void)continuePlaybackWhereYouLeftOff:(input_thread_t *)p_input_thread
{
NSDictionary *recentlyPlayedFiles = [[NSUserDefaults standardUserDefaults] objectForKey:@"recentlyPlayedMedia"];
- if (recentlyPlayedFiles) {
- char *psz_url = decode_URI(input_item_GetURI(p_input));
- NSString *url = [NSString stringWithUTF8String:psz_url ? psz_url : ""];
- free(psz_url);
+ if (!recentlyPlayedFiles)
+ return;
- NSNumber *lastPosition = [recentlyPlayedFiles objectForKey:url];
- if (lastPosition && lastPosition.intValue > 0) {
- msg_Dbg(VLCIntf, "last playback position for %s was %i", [url UTF8String], lastPosition.intValue);
+ input_item_t *p_item = input_GetItem(p_input_thread);
+ if (!p_item)
+ return;
- int settingValue = config_GetInt(VLCIntf, "macosx-continue-playback");
- NSInteger returnValue = NSAlertErrorReturn;
+ /* allow the user to over-write the start/stop/run-time */
+ if (var_GetFloat(p_input_thread, "run-time") > 0 ||
+ var_GetFloat(p_input_thread, "start-time") > 0 ||
+ var_GetFloat(p_input_thread, "stop-time") > 0) {
+ return;
+ }
- if (settingValue == 0) {
- NSAlert *theAlert = [NSAlert alertWithMessageText:_NS("Continue playback?") defaultButton:_NS("Continue") alternateButton:_NS("Restart playback") otherButton:_NS("Always continue") informativeTextWithFormat:_NS("Playback of \"%@\" will continue at %@"), [NSString stringWithUTF8String:input_item_GetTitleFbName(p_input)], [[VLCStringUtility sharedInstance] stringForTime:lastPosition.intValue]];
+ /* check for file existance before resuming */
+ if (![self isValidResumeItem:p_item])
+ return;
- playlist_t *p_playlist = pl_Get(VLCIntf);
- PL_UNLOCK;
- returnValue = [theAlert runModal];
- PL_LOCK;
- }
+ char *psz_url = decode_URI(input_item_GetURI(p_item));
+ if (!psz_url)
+ return;
+ NSString *url = toNSStr(psz_url);
+ free(psz_url);
+
+ NSNumber *lastPosition = [recentlyPlayedFiles objectForKey:url];
+ if (!lastPosition || lastPosition.intValue <= 0)
+ return;
+
+ int settingValue = config_GetInt(VLCIntf, "macosx-continue-playback");
+ if (settingValue == 2) // never resume
+ return;
+
+ NSInteger returnValue = NSAlertErrorReturn;
+ if (settingValue == 0) { // ask
+ NSAlert *theAlert = [NSAlert alertWithMessageText:_NS("Continue playback?") defaultButton:_NS("Continue") alternateButton:_NS("Restart playback") otherButton:_NS("Always continue") informativeTextWithFormat:_NS("Playback of \"%@\" will continue at %@"), [NSString stringWithUTF8String:input_item_GetTitleFbName(p_item)], [[VLCStringUtility sharedInstance] stringForTime:lastPosition.intValue]];
+
+ currentResumeTimeout = 6;
+ NSTimer *timer = [NSTimer timerWithTimeInterval:1
+ target:self
+ selector:@selector(updateAlertWindow:)
+ userInfo:theAlert
+ repeats:YES];
+
+ [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSModalPanelRunLoopMode];
+
+ [[VLCCoreInteraction sharedInstance] pause];
+ returnValue = [theAlert runModal];
+ [timer invalidate];
+ [[VLCCoreInteraction sharedInstance] playOrPause];
+
+ // restart button was pressed or timeout happened
+ if (returnValue == NSAlertAlternateReturn ||
+ returnValue == NSRunAbortedResponse)
+ return;
+ }
+
+ mtime_t lastPos = (mtime_t)lastPosition.intValue * 1000000;
+ msg_Dbg(VLCIntf, "continuing playback at %lld", lastPos);
+ var_SetTime(p_input_thread, "time", lastPos);
- if (returnValue == NSAlertAlternateReturn || settingValue == 2)
- lastPosition = [NSNumber numberWithInt:0];
- input_item_AddOption(p_input, [[NSString stringWithFormat:@"start-time=%i", lastPosition.intValue] UTF8String], VLC_INPUT_OPTION_TRUSTED | VLC_INPUT_OPTION_REPLACE);
+ if (returnValue == NSAlertOtherReturn)
+ config_PutInt(VLCIntf, "macosx-continue-playback", 1);
+}
+
+- (void)storePlaybackPositionForItem:(input_thread_t *)p_input_thread
+{
+ if (!var_InheritBool(VLCIntf, "macosx-recentitems"))
+ return;
+
+ input_item_t *p_item = input_GetItem(p_input_thread);
+ if (!p_item)
+ return;
+
+ if (![self isValidResumeItem:p_item])
+ return;
+
+ char *psz_url = decode_URI(input_item_GetURI(p_item));
+ if (!psz_url)
+ return;
+ NSString *url = toNSStr(psz_url);
+ free(psz_url);
+
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+ NSMutableDictionary *mutDict = [[NSMutableDictionary alloc] initWithDictionary:[defaults objectForKey:@"recentlyPlayedMedia"]];
+
+ float relativePos = var_GetFloat(p_input_thread, "position");
+ mtime_t pos = var_GetTime(p_input_thread, "time") / 1000000;
+ mtime_t dur = input_item_GetDuration(p_item) / 1000000;
+
+ NSMutableArray *mediaList = [[defaults objectForKey:@"recentlyPlayedMediaList"] mutableCopy];
- if (returnValue == NSAlertOtherReturn)
- config_PutInt(VLCIntf, "macosx-continue-playback", 1);
+ if (relativePos > .05 && relativePos < .95 && dur > 180) {
+ [mutDict setObject:[NSNumber numberWithInt:pos] forKey:url];
+
+ [mediaList removeObject:url];
+ [mediaList addObject:url];
+ NSUInteger mediaListCount = mediaList.count;
+ if (mediaListCount > 30) {
+ for (NSUInteger x = 0; x < mediaListCount - 30; x++) {
+ [mutDict removeObjectForKey:[mediaList objectAtIndex:0]];
+ [mediaList removeObjectAtIndex:0];
+ }
}
+ } else {
+ [mutDict removeObjectForKey:url];
+ [mediaList removeObject:url];
}
+ [defaults setObject:mutDict forKey:@"recentlyPlayedMedia"];
+ [defaults setObject:mediaList forKey:@"recentlyPlayedMediaList"];
+ [defaults synchronize];
+
+ [mutDict release];
+ [mediaList release];
}
@end