playlist.m
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:32k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * playlist.m: MacOS X interface module
  3.  *****************************************************************************
  4.  * Copyright (C) 2002-2004 VideoLAN
  5.  * $Id: playlist.m 8388 2004-08-05 21:32:32Z hartman $
  6.  *
  7.  * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
  8.  *          Derk-Jan Hartman <hartman at videolan dot org>
  9.  *          Benjamin Pracht <bigben at videolab dot org>
  10.  *
  11.  * This program is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  * 
  16.  * This program is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  24.  *****************************************************************************/
  25. /*****************************************************************************
  26.  * Preamble
  27.  *****************************************************************************/
  28. #include <stdlib.h>                                      /* malloc(), free() */
  29. #include <sys/param.h>                                    /* for MAXPATHLEN */
  30. #include <string.h>
  31. #include <math.h>
  32. #include <sys/mount.h>
  33. #include <vlc_keys.h>
  34. #include "intf.h"
  35. #include "playlist.h"
  36. #include "controls.h"
  37. #include <OSD.h>
  38. /*****************************************************************************
  39.  * VLCPlaylistView implementation 
  40.  *****************************************************************************/
  41. @implementation VLCPlaylistView
  42. - (NSMenu *)menuForEvent:(NSEvent *)o_event
  43. {
  44.     return( [[self delegate] menuForEvent: o_event] );
  45. }
  46. - (void)keyDown:(NSEvent *)o_event
  47. {
  48.     unichar key = 0;
  49.     int i, c, i_row;
  50.     NSMutableArray *o_to_delete;
  51.     NSNumber *o_number;
  52.     playlist_t * p_playlist;
  53.     intf_thread_t * p_intf = VLCIntf;
  54.     if( [[o_event characters] length] )
  55.     {
  56.         key = [[o_event characters] characterAtIndex: 0];
  57.     }
  58.     p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  59.                                           FIND_ANYWHERE );
  60.     if ( p_playlist == NULL )
  61.     {
  62.         return;
  63.     }
  64.     switch( key )
  65.     {
  66.         case NSDeleteCharacter:
  67.         case NSDeleteFunctionKey:
  68.         case NSDeleteCharFunctionKey:
  69.         case NSBackspaceCharacter:
  70.             o_to_delete = [NSMutableArray arrayWithArray:[[self selectedRowEnumerator] allObjects]];
  71.             c = [o_to_delete count];
  72.             for( i = 0; i < c; i++ ) {
  73.                 o_number = [o_to_delete lastObject];
  74.                 i_row = [o_number intValue];
  75.                 if( p_playlist->i_index == i_row && p_playlist->i_status )
  76.                 {
  77.                     playlist_Stop( p_playlist );
  78.                 }
  79.                 [o_to_delete removeObject: o_number];
  80.                 [self deselectRow: i_row];
  81.                 playlist_Delete( p_playlist, i_row );
  82.             }
  83.             [self reloadData];
  84.             break;
  85.         default:
  86.             [super keyDown: o_event];
  87.             break;
  88.     }
  89.     if( p_playlist != NULL )
  90.     {
  91.         vlc_object_release( p_playlist );
  92.     }
  93. }
  94. @end
  95. /*****************************************************************************
  96.  * VLCPlaylist implementation 
  97.  *****************************************************************************/
  98. @implementation VLCPlaylist
  99. - (id)init
  100. {
  101.     self = [super init];
  102.     if ( self !=nil )
  103.     {
  104.         i_moveRow = -1;
  105.     }
  106.     return self;
  107. }
  108. - (void)awakeFromNib
  109. {
  110.     [o_table_view setTarget: self];
  111.     [o_table_view setDelegate: self];
  112.     [o_table_view setDataSource: self];
  113.     [o_table_view setDoubleAction: @selector(playItem:)];
  114.     [o_table_view registerForDraggedTypes: 
  115.         [NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
  116.     [o_table_view setIntercellSpacing: NSMakeSize (0.0, 1.0)];
  117.     [o_window setExcludedFromWindowsMenu: TRUE];
  118. //    [o_tbv_info setDataSource: [VLCInfoDataSource init]];
  119. /* We need to check whether _defaultTableHeaderSortImage exists, since it 
  120. belongs to an Apple hidden private API, and then can "disapear" at any time*/
  121.     if( [[NSTableView class] respondsToSelector:@selector(_defaultTableHeaderSortImage)] )
  122.     {
  123.         o_ascendingSortingImage = [[NSTableView class] _defaultTableHeaderSortImage];
  124.     }
  125.     else
  126.     {
  127.         o_ascendingSortingImage = nil;
  128.     }
  129.     if( [[NSTableView class] respondsToSelector:@selector(_defaultTableHeaderReverseSortImage)] )
  130.     {
  131.         o_descendingSortingImage = [[NSTableView class] _defaultTableHeaderReverseSortImage];
  132.     }
  133.     else
  134.     {
  135.         o_descendingSortingImage = nil;
  136.     }
  137.     [self initStrings];
  138.     [self playlistUpdated];
  139. }
  140. - (void)initStrings
  141. {
  142.     [o_window setTitle: _NS("Playlist")];
  143.     [o_mi_save_playlist setTitle: _NS("Save Playlist...")];
  144.     [o_mi_play setTitle: _NS("Play")];
  145.     [o_mi_delete setTitle: _NS("Delete")];
  146.     [o_mi_selectall setTitle: _NS("Select All")];
  147.     [o_mi_toggleItemsEnabled setTitle: _NS("Item Enabled")];
  148.     [o_mi_enableGroup setTitle: _NS("Enable all group items")];
  149.     [o_mi_disableGroup setTitle: _NS("Disable all group items")];
  150.     [o_mi_info setTitle: _NS("Properties")];
  151.     [[o_tc_name headerCell] setStringValue:_NS("Name")];
  152.     [[o_tc_author headerCell] setStringValue:_NS("Author")];
  153.     [[o_tc_duration headerCell] setStringValue:_NS("Duration")];
  154.     [o_random_ckb setTitle: _NS("Random")];
  155.     [o_search_button setTitle: _NS("Search")];
  156.     [o_btn_playlist setToolTip: _NS("Playlist")];
  157.     [[o_loop_popup itemAtIndex:0] setTitle: _NS("Standard Play")];
  158.     [[o_loop_popup itemAtIndex:1] setTitle: _NS("Repeat One")];
  159.     [[o_loop_popup itemAtIndex:2] setTitle: _NS("Repeat All")];
  160. }
  161. - (void) tableView:(NSTableView*)o_tv
  162.                   didClickTableColumn:(NSTableColumn *)o_tc
  163. {
  164.     intf_thread_t * p_intf = VLCIntf;
  165.     playlist_t *p_playlist =
  166.         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  167.                                        FIND_ANYWHERE );
  168.     int max = [[o_table_view tableColumns] count];
  169.     int i;
  170.     if( p_playlist == NULL )
  171.     {
  172.         return;
  173.     }
  174.     if( o_tc_sortColumn == o_tc )
  175.     {
  176.         b_isSortDescending = !b_isSortDescending;
  177.     }
  178.     else if( o_tc == o_tc_name || o_tc == o_tc_author || 
  179.         o_tc == o_tc_id )
  180.     {
  181.         b_isSortDescending = VLC_FALSE;
  182.         [o_table_view setHighlightedTableColumn:o_tc];
  183.         o_tc_sortColumn = o_tc;
  184.         for( i=0 ; i<max ; i++ )
  185.         {
  186.             [o_table_view setIndicatorImage:nil inTableColumn:[[o_table_view tableColumns] objectAtIndex:i]];
  187.         }
  188.     }
  189.     if( o_tc_id == o_tc && !b_isSortDescending )
  190.     {
  191.         playlist_SortID( p_playlist , ORDER_NORMAL );
  192.         [o_table_view setIndicatorImage:o_ascendingSortingImage inTableColumn:o_tc];
  193.     }
  194.     else if( o_tc_name == o_tc && !b_isSortDescending )
  195.     {
  196.         playlist_SortTitle( p_playlist , ORDER_NORMAL );
  197.         [o_table_view setIndicatorImage:o_ascendingSortingImage inTableColumn:o_tc];
  198.     }
  199.     else if( o_tc_author == o_tc && !b_isSortDescending )
  200.     {
  201.         playlist_SortAuthor( p_playlist , ORDER_NORMAL );
  202.         [o_table_view setIndicatorImage:o_ascendingSortingImage inTableColumn:o_tc];
  203.     }
  204.     else if( o_tc_id == o_tc && b_isSortDescending )
  205.     {
  206.         playlist_SortID( p_playlist , ORDER_REVERSE );
  207.         [o_table_view setIndicatorImage:o_ascendingSortingImage inTableColumn:o_tc];
  208.     }
  209.     else if( o_tc_name == o_tc && b_isSortDescending )
  210.     {
  211.         playlist_SortTitle( p_playlist , ORDER_REVERSE );
  212.         [o_table_view setIndicatorImage:o_descendingSortingImage inTableColumn:o_tc];
  213.     }
  214.     else if( o_tc_author == o_tc && b_isSortDescending )
  215.     {
  216.         playlist_SortAuthor( p_playlist , ORDER_REVERSE );
  217.         [o_table_view setIndicatorImage:o_descendingSortingImage inTableColumn:o_tc];
  218.     }
  219.     vlc_object_release( p_playlist );
  220.     [self playlistUpdated];
  221. }
  222. - (BOOL)tableView:(NSTableView *)o_tv
  223.                   shouldEditTableColumn:(NSTableColumn *)o_tc
  224.                   row:(int)i_row
  225. {
  226.     return( NO );
  227. }
  228. - (NSMenu *)menuForEvent:(NSEvent *)o_event
  229. {
  230.     intf_thread_t * p_intf = VLCIntf;
  231.     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  232.                                             FIND_ANYWHERE );
  233.     bool b_itemstate = FALSE;
  234.     NSPoint pt;
  235.     vlc_bool_t b_rows;
  236.     vlc_bool_t b_item_sel;
  237.     pt = [o_table_view convertPoint: [o_event locationInWindow]
  238.                                                  fromView: nil];
  239.     b_item_sel = ( [o_table_view rowAtPoint: pt] != -1 &&
  240.                    [o_table_view selectedRow] != -1 );
  241.     b_rows = [o_table_view numberOfRows] != 0;
  242.     [o_mi_play setEnabled: b_item_sel];
  243.     [o_mi_delete setEnabled: b_item_sel];
  244.     [o_mi_selectall setEnabled: b_rows];
  245.     [o_mi_info setEnabled: b_item_sel];
  246.     [o_mi_toggleItemsEnabled setEnabled: b_item_sel];
  247.     [o_mi_enableGroup setEnabled: b_item_sel];
  248.     [o_mi_disableGroup setEnabled: b_item_sel];
  249.     if (p_playlist)
  250.     {
  251.         b_itemstate = ([o_table_view selectedRow] > -1) ?
  252.             p_playlist->pp_items[[o_table_view selectedRow]]->b_enabled : FALSE;
  253.         vlc_object_release(p_playlist);
  254.     }
  255.     [o_mi_toggleItemsEnabled setState: b_itemstate];
  256.     return( o_ctx_menu );
  257. }
  258. - (IBAction)toggleWindow:(id)sender
  259. {
  260.     if( [o_window isVisible] )
  261.     {
  262.         [o_window orderOut:sender];
  263.         [o_btn_playlist setState:NSOffState];
  264.     }
  265.     else
  266.     {
  267.         [o_window makeKeyAndOrderFront:sender];
  268.         [o_btn_playlist setState:NSOnState];
  269.     }
  270. }
  271. - (IBAction)savePlaylist:(id)sender
  272. {
  273.     intf_thread_t * p_intf = VLCIntf;
  274.     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  275.                                                        FIND_ANYWHERE );
  276.     NSSavePanel *o_save_panel = [NSSavePanel savePanel];
  277.     NSString * o_name = [NSString stringWithFormat: @"%@.m3u", _NS("Untitled")];
  278.     [o_save_panel setTitle: _NS("Save Playlist")];
  279.     [o_save_panel setPrompt: _NS("Save")];
  280.     if( [o_save_panel runModalForDirectory: nil
  281.             file: o_name] == NSOKButton )
  282.     {
  283.         playlist_Export( p_playlist, [[o_save_panel filename] fileSystemRepresentation], "export-m3u" );
  284.     }
  285. }
  286. - (IBAction)playItem:(id)sender
  287. {
  288.     intf_thread_t * p_intf = VLCIntf;
  289.     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  290.                                                        FIND_ANYWHERE );
  291.     if( p_playlist != NULL )
  292.     {
  293.         playlist_Goto( p_playlist, [o_table_view selectedRow] );
  294.         vlc_object_release( p_playlist );
  295.     }
  296. }
  297. - (IBAction)deleteItems:(id)sender
  298. {
  299.     int i, c, i_row;
  300.     NSMutableArray *o_to_delete;
  301.     NSNumber *o_number;
  302.     intf_thread_t * p_intf = VLCIntf;
  303.     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  304.                                                        FIND_ANYWHERE );
  305.     if( p_playlist == NULL )
  306.     {
  307.         return;
  308.     }
  309.     o_to_delete = [NSMutableArray arrayWithArray:[[o_table_view selectedRowEnumerator] allObjects]];
  310.     c = (int)[o_to_delete count];
  311.     for( i = 0; i < c; i++ ) {
  312.         o_number = [o_to_delete lastObject];
  313.         i_row = [o_number intValue];
  314.         if( p_playlist->i_index == i_row && p_playlist->i_status )
  315.         {
  316.             playlist_Stop( p_playlist );
  317.         }
  318.         [o_to_delete removeObject: o_number];
  319.         [o_table_view deselectRow: i_row];
  320.         playlist_Delete( p_playlist, i_row );
  321.     }
  322.     vlc_object_release( p_playlist );
  323.     /* this is actually duplicity, because the intf.m manage also updates the view
  324.      * when the playlist changes. we do this on purpose, because else there is a
  325.      * delay of .5 sec or so when we delete an item */
  326.     [self playlistUpdated];
  327.     [self updateRowSelection];
  328. }
  329. - (IBAction)toggleItemsEnabled:(id)sender
  330. {
  331.     int i, c, i_row;
  332.     NSMutableArray *o_selected;
  333.     NSNumber *o_number;
  334.     intf_thread_t * p_intf = VLCIntf;
  335.     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  336.                                                        FIND_ANYWHERE );
  337.     if( p_playlist == NULL )
  338.     {
  339.         return;
  340.     }
  341.     o_selected = [NSMutableArray arrayWithArray:[[o_table_view selectedRowEnumerator] allObjects]];
  342.     c = (int)[o_selected count];
  343.     if (p_playlist->pp_items[[o_table_view selectedRow]]->b_enabled)
  344.     {
  345.         for( i = 0; i < c; i++ )
  346.         {
  347.             o_number = [o_selected lastObject];
  348.             i_row = [o_number intValue];
  349.             if( p_playlist->i_index == i_row && p_playlist->i_status )
  350.             {
  351.                 playlist_Stop( p_playlist );
  352.             }
  353.             [o_selected removeObject: o_number];
  354.             playlist_Disable( p_playlist, i_row );
  355.         }
  356.     }
  357.     else
  358.     {
  359.         for( i = 0; i < c; i++ )
  360.         {
  361.             o_number = [o_selected lastObject];
  362.             i_row = [o_number intValue];
  363.             [o_selected removeObject: o_number];
  364.             playlist_Enable( p_playlist, i_row );
  365.         }
  366.     }
  367.     vlc_object_release( p_playlist );
  368.     [self playlistUpdated];
  369. }
  370. - (IBAction)enableGroup:(id)sender
  371. {
  372.     intf_thread_t * p_intf = VLCIntf;
  373.     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  374.                                                        FIND_ANYWHERE );
  375.     if (p_playlist)
  376.     {
  377.         playlist_EnableGroup(p_playlist,
  378.                 p_playlist->pp_items[[o_table_view selectedRow]]->i_group);
  379.         vlc_object_release(p_playlist);
  380.     }
  381. }
  382. - (IBAction)disableGroup:(id)sender
  383. {
  384.     intf_thread_t * p_intf = VLCIntf;
  385.     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  386.                                                        FIND_ANYWHERE );
  387.     if (p_playlist)
  388.     {
  389.         playlist_DisableGroup(p_playlist,
  390.                 p_playlist->pp_items[[o_table_view selectedRow]]->i_group);
  391.         vlc_object_release(p_playlist);
  392.     }
  393. }
  394. - (IBAction)selectAll:(id)sender
  395. {
  396.     [o_table_view selectAll: nil];
  397. }
  398. - (IBAction)searchItem:(id)sender
  399. {
  400.     int i_current = -1;
  401.     NSString *o_current_name;
  402.     NSString *o_current_author;
  403.     intf_thread_t * p_intf = VLCIntf;
  404.     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  405.                                                FIND_ANYWHERE );
  406.     if( p_playlist == NULL )
  407.     {
  408.         return;
  409.     }
  410.     if( [o_table_view numberOfRows] < 1 )
  411.     {
  412.         return;
  413.     }
  414.     if( [o_table_view selectedRow] == [o_table_view numberOfRows]-1 )
  415.     {
  416.         i_current = -1;
  417.     }
  418.     else
  419.     {
  420.         i_current = [o_table_view selectedRow];
  421.     }
  422.     do
  423.     {
  424.         char *psz_temp;
  425.         i_current++;
  426.         vlc_mutex_lock( &p_playlist->object_lock );
  427.         o_current_name = [NSString stringWithUTF8String:
  428.             p_playlist->pp_items[i_current]->input.psz_name];
  429.         psz_temp = playlist_GetInfo(p_playlist, i_current ,_("General"),_("Author") );
  430.         o_current_author = [NSString stringWithUTF8String: psz_temp];
  431.         free( psz_temp);
  432.         vlc_mutex_unlock( &p_playlist->object_lock );
  433.         if( [o_current_name rangeOfString:[o_search_keyword stringValue] options:NSCaseInsensitiveSearch ].length ||
  434.              [o_current_author rangeOfString:[o_search_keyword stringValue] options:NSCaseInsensitiveSearch ].length )
  435.         {
  436.              [o_table_view selectRow: i_current byExtendingSelection: NO];
  437.              [o_table_view scrollRowToVisible: i_current];
  438.              break;
  439.         }
  440.         if( i_current == [o_table_view numberOfRows] - 1 )
  441.         {
  442.              i_current = -1;
  443.         }
  444.     }
  445.     while (i_current != [o_table_view selectedRow]);
  446.     vlc_object_release( p_playlist );
  447. }
  448. - (IBAction)handlePopUp:(id)sender
  449. {
  450.              intf_thread_t * p_intf = VLCIntf;
  451.              vlc_value_t val1,val2;
  452.              playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  453.                                                         FIND_ANYWHERE );
  454.              if( p_playlist == NULL )
  455.              {
  456.                  return;
  457.              }
  458.     switch ([o_loop_popup indexOfSelectedItem])
  459.     {
  460.         case 1:
  461.              val1.b_bool = 0;
  462.              var_Set( p_playlist, "loop", val1 );
  463.              val1.b_bool = 1;
  464.              var_Set( p_playlist, "repeat", val1 );
  465.              vout_OSDMessage( p_intf, DEFAULT_CHAN, _( "Repeat One" ) );
  466.         break;
  467.         case 2:
  468.              val1.b_bool = 0;
  469.              var_Set( p_playlist, "repeat", val1 );
  470.              val1.b_bool = 1;
  471.              var_Set( p_playlist, "loop", val1 );
  472.              vout_OSDMessage( p_intf, DEFAULT_CHAN, _( "Repeat All" ) );
  473.         break;
  474.         default:
  475.              var_Get( p_playlist, "repeat", &val1 );
  476.              var_Get( p_playlist, "loop", &val2 );
  477.              if (val1.b_bool || val2.b_bool)
  478.              {
  479.                   val1.b_bool = 0;
  480.                   var_Set( p_playlist, "repeat", val1 );
  481.                   var_Set( p_playlist, "loop", val1 );
  482.                   vout_OSDMessage( p_intf, DEFAULT_CHAN, _( "Repeat Off" ) );
  483.              }
  484.          break;
  485.      }
  486.      vlc_object_release( p_playlist );
  487.      [self playlistUpdated];
  488. }
  489. - (void)appendArray:(NSArray*)o_array atPos:(int)i_position enqueue:(BOOL)b_enqueue
  490. {
  491.     int i_item;
  492.     intf_thread_t * p_intf = VLCIntf;
  493.     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  494.                                                        FIND_ANYWHERE );
  495.     if( p_playlist == NULL )
  496.     {
  497.         return;
  498.     }
  499.     for ( i_item = 0; i_item < (int)[o_array count]; i_item++ )
  500.     {
  501.         /* One item */
  502.         NSDictionary *o_one_item;
  503.         int j, i_total_options = 0, i_new_id = -1;
  504.         int i_mode = PLAYLIST_INSERT;
  505.         BOOL b_rem = FALSE, b_dir = FALSE;
  506.         NSString *o_uri, *o_name;
  507.         NSArray *o_options;
  508.         NSURL *o_true_file;
  509.         char **ppsz_options = NULL;
  510.         /* Get the item */
  511.         o_one_item = [o_array objectAtIndex: i_item];
  512.         o_uri = (NSString *)[o_one_item objectForKey: @"ITEM_URL"];
  513.         o_name = (NSString *)[o_one_item objectForKey: @"ITEM_NAME"];
  514.         o_options = (NSArray *)[o_one_item objectForKey: @"ITEM_OPTIONS"];
  515.         /* If no name, then make a guess */
  516.         if( !o_name) o_name = [[NSFileManager defaultManager] displayNameAtPath: o_uri];
  517.         if( [[NSFileManager defaultManager] fileExistsAtPath:o_uri isDirectory:&b_dir] && b_dir &&
  518.             [[NSWorkspace sharedWorkspace] getFileSystemInfoForPath: o_uri isRemovable: &b_rem
  519.                     isWritable:NULL isUnmountable:NULL description:NULL type:NULL] && b_rem   )
  520.         {
  521.             /* All of this is to make sure CD's play when you D&D them on VLC */
  522.             /* Converts mountpoint to a /dev file */
  523.             struct statfs *buf;
  524.             char *psz_dev;
  525.             buf = (struct statfs *) malloc (sizeof(struct statfs));
  526.             statfs( [o_uri fileSystemRepresentation], buf );
  527.             psz_dev = strdup(buf->f_mntfromname);
  528.             o_uri = [NSString stringWithCString: psz_dev ];
  529.         }
  530.         if( o_options && [o_options count] > 0 )
  531.         {
  532.             /* Count the input options */
  533.             i_total_options = [o_options count];
  534.             /* Allocate ppsz_options */
  535.             for( j = 0; j < i_total_options; j++ )
  536.             {
  537.                 if( !ppsz_options )
  538.                     ppsz_options = (char **)malloc( sizeof(char *) * i_total_options );
  539.                 ppsz_options[j] = strdup([[o_options objectAtIndex:j] UTF8String]);
  540.             }
  541.         }
  542.         /* Add the item */
  543.         i_new_id = playlist_AddExt( p_playlist, [o_uri fileSystemRepresentation],
  544.                       [o_name UTF8String], i_mode,
  545.                       i_position == -1 ? PLAYLIST_END : i_position + i_item,
  546.                       0, (ppsz_options != NULL ) ? (const char **)ppsz_options : 0, i_total_options );
  547.         /* clean up
  548.         for( j = 0; j < i_total_options; j++ )
  549.             free( ppsz_options[j] );
  550.         if( ppsz_options ) free( ppsz_options ); */
  551.         /* Recent documents menu */
  552.         o_true_file = [NSURL fileURLWithPath: o_uri];
  553.         if( o_true_file != nil )
  554.         {
  555.             [[NSDocumentController sharedDocumentController]
  556.                 noteNewRecentDocumentURL: o_true_file];
  557.         }
  558.         if( i_item == 0 && !b_enqueue )
  559.         {
  560.             playlist_Goto( p_playlist, playlist_GetPositionById( p_playlist, i_new_id ) );
  561.             playlist_Play( p_playlist );
  562.         }
  563.     }
  564.     vlc_object_release( p_playlist );
  565. }
  566. - (void)playlistUpdated
  567. {
  568.     vlc_value_t val1, val2;
  569.     intf_thread_t * p_intf = VLCIntf;
  570.     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  571.                                                        FIND_ANYWHERE );
  572.     if( p_playlist != NULL )
  573.     {
  574.         var_Get( p_playlist, "random", &val1 );
  575.         [o_random_ckb setState: val1.b_bool];
  576.         var_Get( p_playlist, "repeat", &val1 );
  577.         var_Get( p_playlist, "loop", &val2 );
  578.         if(val1.b_bool)
  579.         {
  580.             [o_loop_popup selectItemAtIndex:1];
  581.         }
  582.         else if(val2.b_bool)
  583.         {
  584.             [o_loop_popup selectItemAtIndex:2];
  585.         }
  586.         else
  587.         {
  588.             [o_loop_popup selectItemAtIndex:0];
  589.         }
  590.         vlc_object_release( p_playlist );
  591.     }
  592.     [o_table_view reloadData];
  593. }
  594. - (void)updateRowSelection
  595. {
  596.     int i_row;
  597.     intf_thread_t * p_intf = VLCIntf;
  598.     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  599.                                                        FIND_ANYWHERE );
  600.     if( p_playlist == NULL )
  601.     {
  602.         return;
  603.     }
  604.     i_row = p_playlist->i_index;
  605.     vlc_object_release( p_playlist );
  606.     [o_table_view selectRow: i_row byExtendingSelection: NO];
  607.     [o_table_view scrollRowToVisible: i_row];
  608. }
  609. - (int)selectedPlaylistItem
  610. {
  611.     return [o_table_view selectedRow];
  612. }
  613. - (NSMutableArray *)selectedPlaylistItemsList
  614. {
  615.     return [NSMutableArray arrayWithArray:[[o_table_view
  616.                         selectedRowEnumerator] allObjects]];
  617. }
  618. - (void)deleteGroup:(int)i_id
  619. {
  620.     intf_thread_t * p_intf = VLCIntf;
  621.     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  622.                                                        FIND_ANYWHERE );
  623.     int i;
  624.     int i_newgroup = 0;
  625.     if (p_playlist)
  626.     {
  627.     /*first, change the group of all the items that belong to the group to
  628.     delete. Change it to the group with the smallest id.*/
  629.     /*search for the group with the smallest id*/
  630.         if(p_playlist->i_groups == 1)
  631.         {
  632.             msg_Warn(p_playlist,"Trying to delete last group, cancelling");
  633.             vlc_object_release(p_playlist);
  634.             return;
  635.         }
  636.         for (i = 0 ; i<p_playlist->i_groups ; i++)
  637.         {
  638.             if((i_newgroup == 0 || i_newgroup > p_playlist->pp_groups[i]->i_id)
  639.                             && p_playlist->pp_groups[i]->i_id != i_id)
  640.             {
  641.                 i_newgroup = p_playlist->pp_groups[i]->i_id;
  642.             }
  643.         }
  644.         vlc_mutex_lock( &p_playlist->object_lock );
  645.         for (i = 0; i < p_playlist->i_size;i++)
  646.         {
  647.             if (p_playlist->pp_items[i]->i_group == i_id)
  648.             {
  649.                 vlc_mutex_lock(&p_playlist->pp_items[i]->input.lock);
  650.                 p_playlist->pp_items[i]->i_group = i_newgroup;
  651.                 vlc_mutex_unlock(&p_playlist->pp_items[i]->input.lock);
  652.             }
  653.         }
  654.         vlc_mutex_unlock( &p_playlist->object_lock );
  655.         playlist_DeleteGroup( p_playlist, i_id );
  656.         vlc_object_release(p_playlist);
  657.         [self playlistUpdated];
  658.     }
  659. }
  660. - (NSColor *)getColor:(int)i_group
  661. {
  662.     NSColor * o_color = nil;
  663.     switch ( i_group % 8 )
  664.     {
  665.         case 1:
  666.             /*white*/
  667.             o_color = [NSColor colorWithDeviceRed:1.0 green:1.0 blue:1.0 alpha:1.0];
  668.         break;
  669.         case 2:
  670.             /*red*/
  671.            o_color = [NSColor colorWithDeviceRed:1.0 green:0.76471 blue:0.76471 alpha:1.0];
  672.         break;
  673.         case 3:
  674.               /*dark blue*/
  675.            o_color = [NSColor colorWithDeviceRed:0.76471 green:0.76471 blue:1.0 alpha:1.0];
  676.         break;
  677.         case 4:
  678.                /*orange*/
  679.            o_color = [NSColor colorWithDeviceRed:1.0 green:0.89804 blue:0.76471 alpha:1.0];
  680.         break;
  681.         case 5:
  682.                /*purple*/
  683.            o_color = [NSColor colorWithDeviceRed:1.0 green:0.76471 blue:1.0 alpha:1.0];
  684.         break;
  685.         case 6:
  686.               /*green*/
  687.            o_color = [NSColor colorWithDeviceRed:0.76471 green:1.0 blue:0.76471 alpha:1.0];
  688.         break;
  689.         case 7:
  690.               /*light blue*/
  691.            o_color = [NSColor colorWithDeviceRed:0.76471 green:1.0 blue:1.0 alpha:1.0];
  692.         break;
  693.         case 0:
  694.               /*yellow*/
  695.            o_color = [NSColor colorWithDeviceRed:1.0 green:1.0 blue:0.76471 alpha:1.0];
  696.         break;
  697.     }
  698.     return o_color;
  699. }
  700. @end
  701. @implementation VLCPlaylist (NSTableDataSource)
  702. - (int)numberOfRowsInTableView:(NSTableView *)o_tv
  703. {
  704.     int i_count = 0;
  705.     intf_thread_t * p_intf = VLCIntf;
  706.     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  707.                                                        FIND_ANYWHERE );
  708.     if( p_playlist != NULL )
  709.     {
  710.         vlc_mutex_lock( &p_playlist->object_lock );
  711.         i_count = p_playlist->i_size;
  712.         vlc_mutex_unlock( &p_playlist->object_lock );
  713.         vlc_object_release( p_playlist );
  714.     }
  715.     [o_status_field setStringValue: [NSString stringWithFormat:_NS("%i items in playlist"), i_count]];
  716.     return( i_count );
  717. }
  718. - (id)tableView:(NSTableView *)o_tv
  719.                 objectValueForTableColumn:(NSTableColumn *)o_tc
  720.                 row:(int)i_row
  721. {
  722.     id o_value = nil;
  723.     intf_thread_t * p_intf = VLCIntf;
  724.     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  725.                                                FIND_ANYWHERE );
  726.     if( p_playlist == NULL )
  727.     {
  728.         return( nil );
  729.     }
  730.     if( [[o_tc identifier] isEqualToString:@"0"] )
  731.     {
  732.         o_value = [NSString stringWithFormat:@"%i", i_row + 1];
  733.     }
  734.     else if( [[o_tc identifier] isEqualToString:@"1"] )
  735.     {
  736.         vlc_mutex_lock( &p_playlist->object_lock );
  737.         o_value = [NSString stringWithUTF8String:
  738.             p_playlist->pp_items[i_row]->input.psz_name];
  739.         if( o_value == NULL )
  740.             o_value = [NSString stringWithCString:
  741.                 p_playlist->pp_items[i_row]->input.psz_name];
  742.         vlc_mutex_unlock( &p_playlist->object_lock );
  743.     }
  744.     else if( [[o_tc identifier] isEqualToString:@"2"] )
  745.     {
  746.         char *psz_temp;
  747.         vlc_mutex_lock( &p_playlist->object_lock );
  748.         psz_temp = playlist_GetInfo( p_playlist, i_row ,_("Meta-information"),_("Artist") );
  749.         vlc_mutex_unlock( &p_playlist->object_lock );
  750.         if( psz_temp == NULL )
  751.         {
  752.             o_value = @"";
  753.         }
  754.         else
  755.         {
  756.             o_value = [NSString stringWithUTF8String: psz_temp];
  757.             if( o_value == NULL )
  758.             {
  759.                 o_value = [NSString stringWithCString: psz_temp];
  760.             }
  761.             free( psz_temp );
  762.         }
  763.     }
  764.     else if( [[o_tc identifier] isEqualToString:@"3"] )
  765.     {
  766.         char psz_duration[MSTRTIME_MAX_SIZE];
  767.         mtime_t dur = p_playlist->pp_items[i_row]->input.i_duration;
  768.         if( dur != -1 )
  769.         {
  770.             secstotimestr( psz_duration, dur/1000000 );
  771.             o_value = [NSString stringWithUTF8String: psz_duration];
  772.         }
  773.         else
  774.         {
  775.             o_value = @"-:--:--";
  776.         }
  777.     }
  778.     vlc_object_release( p_playlist );
  779.     return( o_value );
  780. }
  781. - (void)tableView:(NSTableView *)o_tv
  782.                 willDisplayCell:(id)o_cell
  783.                 forTableColumn:(NSTableColumn *)o_tc
  784.                 row:(int)i_rows
  785. {
  786.     intf_thread_t * p_intf = VLCIntf;
  787.     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  788.                                                FIND_ANYWHERE );
  789.     if (p_playlist)
  790.     {
  791.         if ((p_playlist->i_groups) > 1 )
  792.         {
  793.             [o_cell setDrawsBackground: VLC_TRUE];
  794.             [o_cell setBackgroundColor:
  795.                 [self getColor:p_playlist->pp_items[i_rows]->i_group]];
  796.         }
  797.         else
  798.         {
  799.             [o_cell setDrawsBackground: VLC_FALSE];
  800.         }
  801.         if (!p_playlist->pp_items[i_rows]->b_enabled)
  802.         {
  803.             [o_cell setTextColor: [NSColor colorWithDeviceRed:0.3686 green:0.3686 blue:0.3686 alpha:1.0]];
  804.         }
  805.         else
  806.         {
  807.             [o_cell setTextColor:[NSColor colorWithDeviceRed:0.0 green:0.0 blue:0.0 alpha:1.0]];
  808.         }
  809.     vlc_object_release( p_playlist );
  810.     }
  811. }
  812. - (BOOL)tableView:(NSTableView *)o_tv
  813.                     writeRows:(NSArray*)o_rows
  814.                     toPasteboard:(NSPasteboard*)o_pasteboard
  815. {
  816.     int i_rows = [o_rows count];
  817.     NSArray *o_filenames = [NSArray array];
  818.     [o_pasteboard declareTypes:[NSArray arrayWithObject:NSFilenamesPboardType] owner:self];
  819.     [o_pasteboard setPropertyList:o_filenames forType:NSFilenamesPboardType];
  820.     if ( i_rows == 1 )
  821.     {
  822.         i_moveRow = [[o_rows objectAtIndex:0]intValue];
  823.         return YES;
  824.     }
  825.     return NO;
  826. }
  827. - (NSDragOperation)tableView:(NSTableView*)o_tv
  828.                     validateDrop:(id <NSDraggingInfo>)o_info
  829.                     proposedRow:(int)i_row
  830.                     proposedDropOperation:(NSTableViewDropOperation)o_operation
  831. {
  832.     if ( o_operation == NSTableViewDropAbove )
  833.     {
  834.         if ( i_moveRow >= 0 )
  835.         {
  836.             if ( i_row != i_moveRow )
  837.             {
  838.                 return NSDragOperationMove;
  839.             }
  840.             /* what if in the previous run, the row wasn't actually moved?
  841.                then we can't drop new files on this location */
  842.             return NSDragOperationNone;
  843.         }
  844.         return NSDragOperationGeneric;
  845.     }
  846.     return NSDragOperationNone;
  847. }
  848. - (BOOL)tableView:(NSTableView*)o_tv
  849.                     acceptDrop:(id <NSDraggingInfo>)o_info
  850.                     row:(int)i_proposed_row
  851.                     dropOperation:(NSTableViewDropOperation)o_operation
  852. {
  853.     if (  i_moveRow >= 0 )
  854.     {
  855.         if (i_moveRow != -1 && i_proposed_row != -1)
  856.         {
  857.             intf_thread_t * p_intf = VLCIntf;
  858.             playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  859.                                                             FIND_ANYWHERE );
  860.             if( p_playlist == NULL )
  861.             {
  862.                 i_moveRow = -1;
  863.                 return NO;
  864.             }
  865.             playlist_Move( p_playlist, i_moveRow, i_proposed_row );
  866.             vlc_object_release( p_playlist );
  867.         }
  868.         [self playlistUpdated];
  869.         i_moveRow = -1;
  870.         return YES;
  871.     }
  872.     else
  873.     {
  874.         NSPasteboard * o_pasteboard;
  875.         o_pasteboard = [o_info draggingPasteboard];
  876.         if( [[o_pasteboard types] containsObject: NSFilenamesPboardType] )
  877.         {
  878.             int i;
  879.             NSArray *o_array = [NSArray array];
  880.             NSArray *o_values = [[o_pasteboard propertyListForType: NSFilenamesPboardType]
  881.                         sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
  882.             for( i = 0; i < (int)[o_values count]; i++)
  883.             {
  884.                 NSDictionary *o_dic;
  885.                 o_dic = [NSDictionary dictionaryWithObject:[o_values objectAtIndex:i] forKey:@"ITEM_URL"];
  886.                 o_array = [o_array arrayByAddingObject: o_dic];
  887.             }
  888.             [self appendArray: o_array atPos: i_proposed_row enqueue:YES];
  889.             return YES;
  890.         }
  891.         return NO;
  892.     }
  893.     [self updateRowSelection];
  894. }
  895. /* Delegate method of NSWindow */
  896. - (void)windowWillClose:(NSNotification *)aNotification
  897. {
  898.     [o_btn_playlist setState: NSOffState];
  899. }
  900. @end