]> git.sesse.net Git - vlc/blobdiff - modules/gui/macosx/playlist.m
* extras/MacOSX/Resources/English.lproj/MainMenu.nib
[vlc] / modules / gui / macosx / playlist.m
index e36e3f8b269c4ccf132e73686183b2a5b5c015a4..21cd0d943f0ee43e57e7b7e1b968376306d8f52c 100644 (file)
@@ -1,17 +1,11 @@
 /*****************************************************************************
  * playlist.m: MacOS X interface plugin
  *****************************************************************************
- * Copyright (C) 2002-2003 VideoLAN
- * $Id: playlist.m,v 1.15 2003/03/17 17:10:21 hartman Exp $
+ * Copyright (C) 2002-2004 VideoLAN
+ * $Id: playlist.m,v 1.51 2004/01/09 22:11:04 hartman Exp $
  *
  * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
- *          Derk-Jan Hartman <thedj@users.sourceforge.net>
- * Thanks:  Andrew Stone for documenting the row reordering methods on the net
- *              http://www.omnigroup.com/mailman/archive/macosx-dev/
- *              2001-January/008195.html
- *          Apple Computer for documenting the Alternating row colors
- *             http://developer.apple.com/samplecode/Sample_Code/Cocoa/
- *              MP3_Player/MyTableView.m.htm
+ *          Derk-Jan Hartman <hartman at videolan 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
 #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>
 
 #include "intf.h"
 #include "playlist.h"
-
-// RGB values for stripe color (light blue)
-#define STRIPE_RED   (237.0 / 255.0)
-#define STRIPE_GREEN (243.0 / 255.0)
-#define STRIPE_BLUE  (254.0 / 255.0)
-static NSColor *sStripeColor = nil;
+#include "controls.h"
 
 /*****************************************************************************
  * VLCPlaylistView implementation 
@@ -57,7 +49,10 @@ static NSColor *sStripeColor = nil;
 - (void)keyDown:(NSEvent *)o_event
 {
     unichar key = 0;
-    int i_row;
+    int i, c, i_row;
+    NSMutableArray *o_to_delete;
+    NSNumber *o_number;
+    
     playlist_t * p_playlist;
     intf_thread_t * p_intf = [NSApp getIntf];
 
@@ -76,29 +71,24 @@ static NSColor *sStripeColor = nil;
     
     switch( key )
     {
-        case ' ':
-            vlc_mutex_lock( &p_playlist->object_lock );
-            if( p_playlist->p_input != NULL )
-            {
-                input_SetStatus( p_playlist->p_input, INPUT_STATUS_PAUSE );
-            }
-            vlc_mutex_unlock( &p_playlist->object_lock );
-            break;
-
         case NSDeleteCharacter:
         case NSDeleteFunctionKey:
         case NSDeleteCharFunctionKey:
         case NSBackspaceCharacter:
-            while( ( i_row = [self selectedRow] ) != -1 )
-            {
+            o_to_delete = [NSMutableArray arrayWithArray:[[self selectedRowEnumerator] allObjects]];
+            c = [o_to_delete count];
+            
+            for( i = 0; i < c; i++ ) {
+                o_number = [o_to_delete lastObject];
+                i_row = [o_number intValue];
+                
                 if( p_playlist->i_index == i_row && p_playlist->i_status )
                 {
                     playlist_Stop( p_playlist );
                 }
-        
-                playlist_Delete( p_playlist, i_row ); 
-        
+                [o_to_delete removeObject: o_number];
                 [self deselectRow: i_row];
+                playlist_Delete( p_playlist, i_row );
             }
             [self reloadData];
             break;
@@ -114,41 +104,6 @@ static NSColor *sStripeColor = nil;
     }
 }
 
-
-/* This is called after the table background is filled in, but before the cell contents are drawn.
- * We override it so we can do our own light-blue row stripes a la iTunes.
- */
-- (void) highlightSelectionInClipRect:(NSRect)rect {
-    [self drawStripesInRect:rect];
-    [super highlightSelectionInClipRect:rect];
-}
-
-/* This routine does the actual blue stripe drawing, filling in every other row of the table
- * with a blue background so you can follow the rows easier with your eyes.
- */
-- (void) drawStripesInRect:(NSRect)clipRect {
-    NSRect stripeRect;
-    float fullRowHeight = [self rowHeight] + [self intercellSpacing].height;
-    float clipBottom = NSMaxY(clipRect);
-    int firstStripe = clipRect.origin.y / fullRowHeight;
-    if (firstStripe % 2 == 0)
-        firstStripe++;   // we're only interested in drawing the stripes
-                         // set up first rect
-    stripeRect.origin.x = clipRect.origin.x;
-    stripeRect.origin.y = firstStripe * fullRowHeight;
-    stripeRect.size.width = clipRect.size.width;
-    stripeRect.size.height = fullRowHeight;
-    // set the color
-    if (sStripeColor == nil)
-        sStripeColor = [[NSColor colorWithCalibratedRed:STRIPE_RED green:STRIPE_GREEN blue:STRIPE_BLUE alpha:1.0] retain];
-    [sStripeColor set];
-    // and draw the stripes
-    while (stripeRect.origin.y < clipBottom) {
-        NSRectFill(stripeRect);
-        stripeRect.origin.y += fullRowHeight * 2.0;
-    }
-}
-
 @end
 
 /*****************************************************************************
@@ -156,6 +111,16 @@ static NSColor *sStripeColor = nil;
  *****************************************************************************/
 @implementation VLCPlaylist
 
+- (id)init
+{
+    self = [super init];
+    if ( self !=nil )
+    {
+        i_moveRow = -1;
+    }
+    return self;
+}
+
 - (void)awakeFromNib
 {
     [o_table_view setTarget: self];
@@ -167,12 +132,25 @@ static NSColor *sStripeColor = nil;
     [o_table_view registerForDraggedTypes: 
         [NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
 
+    [o_window setExcludedFromWindowsMenu: TRUE];
+    [self initStrings];
+}
+
+- (void)initStrings
+{
+    [o_window setTitle: _NS("Playlist")];
+    [o_mi_save_playlist setTitle: _NS("Save Playlist...")];
     [o_mi_play setTitle: _NS("Play")];
     [o_mi_delete setTitle: _NS("Delete")];
     [o_mi_selectall setTitle: _NS("Select All")];
-    
-    [o_btn_add setToolTip: _NS("Add")];
-    [o_btn_remove setToolTip: _NS("Delete")];
+    [[o_tc_name headerCell] setStringValue:_NS("Name")];
+    [[o_tc_author headerCell] setStringValue:_NS("Author")];
+    [[o_tc_duration headerCell] setStringValue:_NS("Duration")];
+    [o_random_ckb setTitle: _NS("Shuffle")];
+    [o_loop_ckb setTitle: _NS("Repeat Playlist")];
+    [o_repeat_ckb setTitle: _NS("Repeat Item")];
+    [o_search_button setTitle: _NS("Search")];
+    [o_btn_playlist setToolTip: _NS("Playlist")];
 }
 
 - (BOOL)tableView:(NSTableView *)o_tv 
@@ -201,25 +179,57 @@ static NSColor *sStripeColor = nil;
     return( o_ctx_menu );
 }
 
-- (IBAction)playItem:(id)sender
+- (IBAction)toggleWindow:(id)sender
+{
+    if( [o_window isVisible] )
+    {
+        [o_window orderOut:sender];
+        [o_btn_playlist setState:NSOffState];
+    }
+    else
+    {
+        [o_window makeKeyAndOrderFront:sender];
+        [o_btn_playlist setState:NSOnState];
+    }
+}
+
+- (IBAction)savePlaylist:(id)sender
 {
     intf_thread_t * p_intf = [NSApp getIntf];
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                        FIND_ANYWHERE );
+    
+    NSSavePanel *o_save_panel = [NSSavePanel savePanel];
+    NSString * o_name = [NSString stringWithFormat: @"%@.m3u", _NS("Untitled")];
+    [o_save_panel setTitle: _NS("Save Playlist")];
+    [o_save_panel setPrompt: _NS("Save")];
 
-    if( p_playlist == NULL )
+    if( [o_save_panel runModalForDirectory: nil
+            file: o_name] == NSOKButton )
     {
-        return;
+        playlist_SaveFile( p_playlist, [[o_save_panel filename] fileSystemRepresentation] );
     }
 
-    playlist_Goto( p_playlist, [o_table_view selectedRow] );
+}
 
-    vlc_object_release( p_playlist );
+- (IBAction)playItem:(id)sender
+{
+    intf_thread_t * p_intf = [NSApp getIntf];
+    playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
+                                                       FIND_ANYWHERE );
+
+    if( p_playlist != NULL )
+    {
+        playlist_Goto( p_playlist, [o_table_view selectedRow] );
+        vlc_object_release( p_playlist );
+    }
 }
 
 - (IBAction)deleteItems:(id)sender
 {
-    int i_row;
+    int i, c, i_row;
+    NSMutableArray *o_to_delete;
+    NSNumber *o_number;
 
     intf_thread_t * p_intf = [NSApp getIntf];
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
@@ -229,17 +239,21 @@ static NSColor *sStripeColor = nil;
     {
         return;
     }
-
-    while( ( i_row = [o_table_view selectedRow] ) != -1 )
-    {
+    
+    o_to_delete = [NSMutableArray arrayWithArray:[[o_table_view selectedRowEnumerator] allObjects]];
+    c = (int)[o_to_delete count];
+    
+    for( i = 0; i < c; i++ ) {
+        o_number = [o_to_delete lastObject];
+        i_row = [o_number intValue];
+        
         if( p_playlist->i_index == i_row && p_playlist->i_status )
         {
             playlist_Stop( p_playlist );
         }
-
-        playlist_Delete( p_playlist, i_row ); 
-
+        [o_to_delete removeObject: o_number];
         [o_table_view deselectRow: i_row];
+        playlist_Delete( p_playlist, i_row );
     }
 
     vlc_object_release( p_playlist );
@@ -248,6 +262,7 @@ static NSColor *sStripeColor = nil;
      * when the playlist changes. we do this on purpose, because else there is a 
      * delay of .5 sec or so when we delete an item */
     [self playlistUpdated];
+    [self updateRowSelection];
 }
 
 - (IBAction)selectAll:(id)sender
@@ -255,11 +270,66 @@ static NSColor *sStripeColor = nil;
     [o_table_view selectAll: nil];
 }
 
-- (void)appendArray:(NSArray*)o_array atPos:(int)i_pos enqueue:(BOOL)b_enqueue
+
+- (IBAction)searchItem:(id)sender
+{
+    int i_current = -1;
+    NSString *o_current_name;
+    NSString *o_current_author;
+
+    intf_thread_t * p_intf = [NSApp getIntf];
+    playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
+                                               FIND_ANYWHERE );
+    
+    if( p_playlist == NULL )
+    {
+        return;
+    }
+    if( [o_table_view numberOfRows] < 1 )
+    {
+        return;
+    }
+
+    if( [o_table_view selectedRow] == [o_table_view numberOfRows]-1 )
+    {
+        i_current = -1;
+    }
+    else
+    {
+        i_current = [o_table_view selectedRow]; 
+    }
+
+    do
+    {
+        i_current++;
+
+        vlc_mutex_lock( &p_playlist->object_lock );
+        o_current_name = [NSString stringWithUTF8String: 
+            p_playlist->pp_items[i_current]->psz_name];
+        o_current_author = [NSString stringWithUTF8String: 
+            playlist_GetInfo(p_playlist, i_current ,_("General"),_("Author") )];
+        vlc_mutex_unlock( &p_playlist->object_lock );
+
+
+        if( [o_current_name rangeOfString:[o_search_keyword stringValue] options:NSCaseInsensitiveSearch ].length ||
+             [o_current_author rangeOfString:[o_search_keyword stringValue] options:NSCaseInsensitiveSearch ].length )
+        {
+             [o_table_view selectRow: i_current byExtendingSelection: NO];
+             [o_table_view scrollRowToVisible: i_current];
+             break;
+        }
+        if( i_current == [o_table_view numberOfRows] - 1 )
+        {
+             i_current = -1;
+        }
+    }
+    while (i_current != [o_table_view selectedRow]);
+    vlc_object_release( p_playlist );
+}
+
+- (void)appendArray:(NSArray*)o_array atPos:(int)i_position enqueue:(BOOL)b_enqueue
 {
-    int i_items;
-    NSString * o_value;
-    NSEnumerator * o_enum;
+    int i_item;
     intf_thread_t * p_intf = [NSApp getIntf];
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                        FIND_ANYWHERE );
@@ -269,28 +339,68 @@ static NSColor *sStripeColor = nil;
         return;
     }
 
-    i_items = 0;
-    o_enum = [o_array objectEnumerator];
-    while( ( o_value = [o_enum nextObject] ) )
+    for ( i_item = 0; i_item < (int)[o_array count]; i_item++ )
     {
-        NSURL * o_url;
-
+        /* One item */
+        NSDictionary *o_one_item;
+        int j, i_new_position = -1;
         int i_mode = PLAYLIST_INSERT;
+        BOOL b_rem = FALSE, b_dir = FALSE;
+        NSString *o_uri, *o_name;
+        NSArray *o_options;
+        NSURL *o_true_file;
+    
+        /* Get the item */
+        o_one_item = [o_array objectAtIndex: i_item];
+        o_uri = (NSString *)[o_one_item objectForKey: @"ITEM_URL"];
+        o_name = (NSString *)[o_one_item objectForKey: @"ITEM_NAME"];
+        o_options = (NSArray *)[o_one_item objectForKey: @"ITEM_OPTIONS"];
         
-        if (i_items == 0 && !b_enqueue)
+        /* If no name, then make a guess */
+        if( !o_name) o_name = [[NSFileManager defaultManager] displayNameAtPath: o_uri];
+    
+        if( [[NSFileManager defaultManager] fileExistsAtPath:o_uri isDirectory:&b_dir] && b_dir &&
+            [[NSWorkspace sharedWorkspace] getFileSystemInfoForPath: o_uri isRemovable: &b_rem
+                    isWritable:NULL isUnmountable:NULL description:NULL type:NULL] && b_rem   )
+        {
+            /* All of this is to make sure CD's play when you D&D them on VLC */
+            /* Converts mountpoint to a /dev file */
+            struct statfs *buf;
+            char *psz_dev, *temp;
+            buf = (struct statfs *) malloc (sizeof(struct statfs));
+            statfs( [o_uri fileSystemRepresentation], buf );
+            psz_dev = strdup(buf->f_mntfromname);
+            free( buf );
+            temp = strrchr( psz_dev , 's' );
+            psz_dev[temp - psz_dev] = '\0';
+            o_uri = [NSString stringWithCString: psz_dev ];
+        }
+    
+        if (i_item == 0 && !b_enqueue)
             i_mode |= PLAYLIST_GO;
-
-        playlist_Add( p_playlist, [o_value fileSystemRepresentation],
-            i_mode, i_pos == -1 ? PLAYLIST_END : i_pos + i_items );
-
-        o_url = [NSURL fileURLWithPath: o_value];
-        if( o_url != nil )
+        
+        /* Add the item */
+        i_new_position = playlist_Add( p_playlist, [o_uri fileSystemRepresentation], 
+                      [o_name UTF8String], i_mode, 
+                      i_position == -1 ? PLAYLIST_END : i_position + i_item);
+        
+        /* Add the options, when there are any */
+        if( o_options )
+        {
+            for( j = 0; j < [o_options count]; j++ )
+            {
+                playlist_AddOption( p_playlist, i_new_position,
+                 strdup( [[o_options objectAtIndex:j] UTF8String] ) );
+            }
+        }
+    
+        /* Recent documents menu */
+        o_true_file = [NSURL fileURLWithPath: o_uri];
+        if( o_true_file != nil )
         { 
             [[NSDocumentController sharedDocumentController]
-                noteNewRecentDocumentURL: o_url]; 
+                noteNewRecentDocumentURL: o_true_file]; 
         }
-
-        i_items++;
     }
 
     vlc_object_release( p_playlist );
@@ -298,6 +408,23 @@ static NSColor *sStripeColor = nil;
 
 - (void)playlistUpdated
 {
+    vlc_value_t val;
+    intf_thread_t * p_intf = [NSApp getIntf];
+    playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
+                                                       FIND_ANYWHERE );
+    if( p_playlist != NULL )
+    {
+        var_Get( p_playlist, "random", &val );
+        [o_random_ckb setState: val.b_bool];
+
+        var_Get( p_playlist, "loop", &val );
+        [o_loop_ckb setState: val.b_bool];
+
+        var_Get( p_playlist, "repeat", &val );
+        [o_repeat_ckb setState: val.b_bool];
+
+        vlc_object_release( p_playlist );
+    }
     [o_table_view reloadData];
 }
 
@@ -314,14 +441,13 @@ static NSColor *sStripeColor = nil;
         return;
     }
 
-    vlc_mutex_lock( &p_playlist->object_lock );    
     i_row = p_playlist->i_index;
-    vlc_mutex_unlock( &p_playlist->object_lock );
     vlc_object_release( p_playlist );
 
     [o_table_view selectRow: i_row byExtendingSelection: NO];
     [o_table_view scrollRowToVisible: i_row];
 }
+    
 
 @end
 
@@ -341,7 +467,7 @@ static NSColor *sStripeColor = nil;
         vlc_mutex_unlock( &p_playlist->object_lock );
         vlc_object_release( p_playlist );
     }
-
+    [o_status_field setStringValue: [NSString stringWithFormat:_NS("%i items in playlist"), i_count]];
     return( i_count );
 }
 
@@ -359,110 +485,140 @@ static NSColor *sStripeColor = nil;
         return( nil );
     }
 
-    vlc_mutex_lock( &p_playlist->object_lock );
-    o_value = [[NSString stringWithUTF8String: 
-        p_playlist->pp_items[i_row]->psz_name] lastPathComponent]; 
-    vlc_mutex_unlock( &p_playlist->object_lock ); 
+    if( [[o_tc identifier] isEqualToString:@"0"] )
+    {
+        o_value = [NSString stringWithFormat:@"%i", i_row + 1];
+    }
+    else if( [[o_tc identifier] isEqualToString:@"1"] )
+    {
+        vlc_mutex_lock( &p_playlist->object_lock );
+        o_value = [[NSString stringWithUTF8String: 
+            p_playlist->pp_items[i_row]->psz_name] lastPathComponent];
+        vlc_mutex_unlock( &p_playlist->object_lock );
+    }
+    else if( [[o_tc identifier] isEqualToString:@"2"] )
+    {
+        vlc_mutex_lock( &p_playlist->object_lock );
+        o_value = [NSString stringWithUTF8String: 
+            playlist_GetInfo(p_playlist, i_row ,_("General"),_("Author") )];
+        vlc_mutex_unlock( &p_playlist->object_lock );
+    }
+    else if( [[o_tc identifier] isEqualToString:@"3"] )
+    {
+        char psz_duration[MSTRTIME_MAX_SIZE];
+        mtime_t dur = p_playlist->pp_items[i_row]->i_duration;
+        if( dur != -1 )
+        {
+            secstotimestr( psz_duration, dur/1000000 );
+            o_value = [NSString stringWithUTF8String: psz_duration];
+        }
+        else
+        {
+            o_value = @"-:--:--";
+        }
+    }
 
     vlc_object_release( p_playlist );
 
     return( o_value );
 }
 
-// NEW API for Dragging in TableView:
-// typedef enum { NSTableViewDropOn, NSTableViewDropAbove } NSTableViewDropOperation;
-// In drag and drop, used to specify a dropOperation. For example, given a table with N rows (numbered with row 0 at the top visually), a row of N-1 and operation of NSTableViewDropOn would specify a drop on the last row. To specify a drop below the last row, one would use a row of N and NSTableViewDropAbove for the operation.
-
-static int _moveRow = -1;
-
-- (BOOL)tableView:(NSTableView *)tv
-                    writeRows:(NSArray*)rows
-                    toPasteboard:(NSPasteboard*)pboard 
-// This method is called after it has been determined that a drag should begin, but before the drag has been started. To refuse the drag, return NO. To start a drag, return YES and place the drag data onto the pasteboard (data, owner, etc...). The drag image and other drag related information will be set up and provided by the table view once this call returns with YES. The rows array is the list of row numbers that will be participating in the drag.
+- (BOOL)tableView:(NSTableView *)o_tv
+                    writeRows:(NSArray*)o_rows
+                    toPasteboard:(NSPasteboard*)o_pasteboard 
 {
-    int rowCount = [rows count];
+    int i_rows = [o_rows count];
     NSArray *o_filenames = [NSArray array];
     
-    // we should allow group selection and copy between windows: PENDING
-    [pboard declareTypes:[NSArray arrayWithObject:NSFilenamesPboardType] owner:self];
-    [pboard setPropertyList:o_filenames forType:NSFilenamesPboardType];
-    if (rowCount == 1)
+    [o_pasteboard declareTypes:[NSArray arrayWithObject:NSFilenamesPboardType] owner:self];
+    [o_pasteboard setPropertyList:o_filenames forType:NSFilenamesPboardType];
+    if ( i_rows == 1 )
     {
-        _moveRow = [[rows objectAtIndex:0]intValue];
+        i_moveRow = [[o_rows objectAtIndex:0]intValue];
         return YES;
     }
     return NO;
 }
 
-- (NSDragOperation)tableView:(NSTableView*)tv
-                    validateDrop:(id <NSDraggingInfo>)info
-                    proposedRow:(int)row
-                    proposedDropOperation:(NSTableViewDropOperation)op 
-// This method is used by NSTableView to determine a valid drop target. Based on the mouse position, the table view will suggest a proposed drop location. This method must return a value that indicates which dragging operation the data source will perform. The data source may "re-target" a drop if desired by calling setDropRow:dropOperation: and returning something other than NSDragOperationNone. One may choose to re-target for various reasons (eg. for better visual feedback when inserting into a sorted position).
+- (NSDragOperation)tableView:(NSTableView*)o_tv
+                    validateDrop:(id <NSDraggingInfo>)o_info
+                    proposedRow:(int)i_row
+                    proposedDropOperation:(NSTableViewDropOperation)o_operation 
 {
-    if ( op == NSTableViewDropAbove )
+    if ( o_operation == NSTableViewDropAbove )
     {
-        if ( row != _moveRow && _moveRow >= 0 )
+        if ( i_moveRow >= 0 )
         {
-            return NSDragOperationMove;
+            if ( i_row != i_moveRow )
+            {
+                return NSDragOperationMove;
+            }
+            /* what if in the previous run, the row wasn't actually moved? 
+               then we can't drop new files on this location */
+            return NSDragOperationNone;
         }
-        return NSDragOperationLink;
+        return NSDragOperationGeneric;
     }
     return NSDragOperationNone;
 }
 
-- (BOOL)tableView:(NSTableView*)tv
-                    acceptDrop:(id <NSDraggingInfo>)info
-                    row:(int)i_row
-                    dropOperation:(NSTableViewDropOperation)op 
-// This method is called when the mouse is released over an outline view that previously decided to allow a drop via the validateDrop method. The data source should incorporate the data from the dragging pasteboard at this time. 
+- (BOOL)tableView:(NSTableView*)o_tv
+                    acceptDrop:(id <NSDraggingInfo>)o_info
+                    row:(int)i_proposed_row
+                    dropOperation:(NSTableViewDropOperation)o_operation 
 {
-    if (  _moveRow >= 0 )
+    if (  i_moveRow >= 0 )
     {
-        BOOL result = [self tableView:tv didDepositRow:_moveRow at:(int)i_row];
+        if (i_moveRow != -1 && i_proposed_row != -1)
+        {
+            intf_thread_t * p_intf = [NSApp getIntf];
+            playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
+                                                            FIND_ANYWHERE );
+        
+            if( p_playlist == NULL )
+            {
+                i_moveRow = -1;
+                return NO;
+            }
+    
+            playlist_Move( p_playlist, i_moveRow, i_proposed_row ); 
+        
+            vlc_object_release( p_playlist );
+        }
         [self playlistUpdated];
-        _moveRow = -1;
-        return result;
+        i_moveRow = -1;
+        return YES;
     }
     else
     {
-        NSArray * o_values;
         NSPasteboard * o_pasteboard;
-        
-        o_pasteboard = [info draggingPasteboard];
+        o_pasteboard = [o_info draggingPasteboard];
         
         if( [[o_pasteboard types] containsObject: NSFilenamesPboardType] )
         {
-            o_values = [o_pasteboard propertyListForType: NSFilenamesPboardType];
-        
-            [self appendArray: o_values atPos: i_row enqueue:YES];
-        
-            return( YES );
+            int i;
+            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];
+            }
+            [self appendArray: o_array atPos: i_proposed_row enqueue:YES];
+            return YES;
         }
-        
-        return( NO );
+        return NO;
     }
+    [self updateRowSelection];
 }
 
--  (BOOL)tableView:(NSTableView *)tv didDepositRow:(int)i_row at:(int)i_newrow
+/* Delegate method of NSWindow */
+- (void)windowWillClose:(NSNotification *)aNotification
 {
-    if (i_row != -1 && i_newrow != -1)
-    {
-        intf_thread_t * p_intf = [NSApp getIntf];
-        playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
-                                                        FIND_ANYWHERE );
-    
-        if( p_playlist == NULL )
-        {
-            return NO;
-        }
-
-        playlist_Move( p_playlist, i_row, i_newrow ); 
-    
-        vlc_object_release( p_playlist );
-        return YES;
-    }
-    return NO;
+    [o_btn_playlist setState: NSOffState];
 }
 
 @end