commit 8429fa4b49ea6ce1a232dbb81f46d05ac5b3b4fd
Author: phantomjinx <p.g.richard...@phantomjinx.co.uk>
Date:   Mon Oct 3 20:57:57 2011 +0100

    Allow the multiple selection of playlists in the playlist view
    
    * Only the first selection is passed to libgtkpod and notified to
      other plugins.
    
    * On selection of extra playlists, a reduced context menu can be
      displayed, allowing for actions to be performed on the set of
      playlists, notably deletion.
    
    Fixes:3413192 - Not obvious how to delete a playlist without selecting from

 libgtkpod/context_menus.c                          |   24 ---
 libgtkpod/context_menus.h                          |    1 -
 plugins/playlist_display/display_playlists.c       |  211 ++++++++++----------
 plugins/playlist_display/display_playlists.h       |   12 +-
 .../playlist_display/playlist_display_actions.c    |   68 ++++---
 .../playlist_display/playlist_display_actions.h    |   14 +-
 .../playlist_display_context_menu.c                |  134 ++++++++++---
 plugins/playlist_display/plugin.c                  |   12 +-
 8 files changed, 276 insertions(+), 200 deletions(-)
---
diff --git a/libgtkpod/context_menus.c b/libgtkpod/context_menus.c
index c781d44..1a56c90 100644
--- a/libgtkpod/context_menus.c
+++ b/libgtkpod/context_menus.c
@@ -110,11 +110,6 @@ GtkWidget *add_separator(GtkWidget *menu) {
     return sep;
 }
 
-void context_menu_delete_track_head(GtkMenuItem *mi, gpointer data) {
-    DeleteAction deleteaction = GPOINTER_TO_INT (data);
-    delete_track_head(deleteaction);
-}
-
 GtkWidget *add_exec_commands(GtkWidget *menu) {
     GList *trkcmds = gtkpod_get_registered_track_commands();
     GList *cmds = trkcmds;
@@ -156,25 +151,6 @@ GtkWidget *add_update_tracks_from_file(GtkWidget *menu) {
     return hookup_menu_item(menu, _("Update Tracks from File"), 
GTK_STOCK_REFRESH, G_CALLBACK (update_tracks_from_file), NULL);
 }
 
-/*
- * sync_dirs_ entries - sync the directories of the selected playlist
- *
- * @mi - the menu item selected
- * @data - Ignored, should be NULL
- */
-static void sync_dirs(GtkMenuItem *mi, gpointer data) {
-    if (gtkpod_get_current_playlist()) {
-        sync_playlist(gtkpod_get_current_playlist(), NULL, 
KEY_SYNC_CONFIRM_DIRS, 0, KEY_SYNC_DELETE_TRACKS, 0, KEY_SYNC_CONFIRM_DELETE, 
0, KEY_SYNC_SHOW_SUMMARY, 0);
-    }
-    else {
-        g_return_if_reached ();
-    }
-}
-
-GtkWidget *add_sync_playlist_with_dirs(GtkWidget *menu) {
-    return hookup_menu_item(menu, _("Sync Playlist with Dir(s)"), 
GTK_STOCK_REFRESH, G_CALLBACK (sync_dirs), NULL);
-}
-
 static void copy_selected_tracks_to_target_itdb(GtkMenuItem *mi, gpointer 
*userdata) {
     iTunesDB *t_itdb = *userdata;
     g_return_if_fail (t_itdb);
diff --git a/libgtkpod/context_menus.h b/libgtkpod/context_menus.h
index 8024010..05a2de6 100644
--- a/libgtkpod/context_menus.h
+++ b/libgtkpod/context_menus.h
@@ -54,7 +54,6 @@ void context_menu_delete_track_head(GtkMenuItem *mi, gpointer 
data);
 GtkWidget *add_copy_track_to_filesystem (GtkWidget *menu);
 GtkWidget *add_create_playlist_file (GtkWidget *menu);
 GtkWidget *add_update_tracks_from_file (GtkWidget *menu);
-GtkWidget *add_sync_playlist_with_dirs (GtkWidget *menu);
 GtkWidget *add_create_new_playlist (GtkWidget *menu);
 GtkWidget *add_edit_track_details (GtkWidget *menu);
 
diff --git a/plugins/playlist_display/display_playlists.c 
b/plugins/playlist_display/display_playlists.c
index 951b9da..208ad91 100644
--- a/plugins/playlist_display/display_playlists.c
+++ b/plugins/playlist_display/display_playlists.c
@@ -231,7 +231,7 @@ static gboolean pm_drag_motion(GtkWidget *widget, 
GdkDragContext *dc, gint x, gi
             return TRUE;
         case DND_GTKPOD_TRACKLIST:
             /* do not allow drop into currently selected playlist */
-            if (pl_d == pm_get_selected_playlist()) {
+            if (pl_d == pm_get_first_selected_playlist()) {
                 if ((pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE) || (pos == 
GTK_TREE_VIEW_DROP_INTO_OR_AFTER)) {
                     gtk_tree_path_free(path);
                     gdk_drag_status(dc, 0, time);
@@ -1015,55 +1015,20 @@ void pm_add_child(Itdb_iTunesDB *itdb, PM_column_type 
type, gpointer item, gint
     gtk_tree_store_set(GTK_TREE_STORE (model), &iter, PM_COLUMN_ITDB, itdb, 
PM_COLUMN_TYPE, type, type, item, -1);
 }
 
-/* Remove "playlist" from the display model.
- "select": TRUE: a new playlist is selected
- FALSE: no selection is taking place
- (useful when quitting program) */
-void pm_remove_playlist(Playlist *playlist, gboolean select) {
+/* Remove "playlist" from the display model */
+void pm_remove_playlist(Playlist *playlist) {
     GtkTreeModel *model;
-    gboolean have_iter = FALSE;
-    GtkTreeIter select_iter, delete_iter;
-    GtkTreeSelection *ts = NULL;
+    GtkTreeIter iter;
 
     g_return_if_fail (playlist);
     model = gtk_tree_view_get_model(playlist_treeview);
     g_return_if_fail (model);
 
-    ts = gtk_tree_view_get_selection(playlist_treeview);
-
-    if (itdb_playlist_is_mpl(playlist) && (playlist->itdb == 
gtkpod_get_current_itdb())) {
-        /* We are about to remove the entire itdb (playlist is MPL) and
-         * a playlist of this itdb is selected --> clear display
-         * (pm_unselect_playlist probably works as well, but the
-         * unselect won't be done until later (callback)) */
-        gtkpod_set_current_playlist(NULL);
-    }
-
-    if (select && (gtkpod_get_current_playlist() == playlist)) {
-        /* We are about to delete the currently selected
-         * playlist. Try to select the next. */
-        if (gtk_tree_selection_get_selected(ts, NULL, &select_iter)) {
-            GtkTreePath *path = gtk_tree_model_get_path(model, &select_iter);
-            if (gtk_tree_model_iter_next(model, &select_iter)) {
-                have_iter = TRUE;
-            }
-            else { /* no next iter -- try previous iter */
-                if (gtk_tree_path_prev(path)) { /* OK -- make iter from it */
-                    gtk_tree_model_get_iter(model, &select_iter, path);
-                    have_iter = TRUE;
-                }
-            }
-            gtk_tree_path_free(path);
-        }
-    }
+    gtkpod_set_current_playlist(NULL);
 
-    if (pm_get_iter_for_playlist(playlist, &delete_iter)) {
-        gtk_tree_store_remove(GTK_TREE_STORE (model), &delete_iter);
+    if (pm_get_iter_for_playlist(playlist, &iter)) {
+        gtk_tree_store_remove(GTK_TREE_STORE (model), &iter);
     }
-
-    /* select our new iter !!! */
-    if (have_iter && select)
-        gtk_tree_selection_select_iter(ts, &select_iter);
 }
 
 /* Remove all playlists from the display model */
@@ -1091,6 +1056,35 @@ void pm_remove_all_playlists(gboolean clear_sort) {
 }
 
 /* Select specified playlist */
+void pm_select_playlists(GList *playlists) {
+    GtkTreeIter iter;
+    GtkTreeSelection *ts;
+
+    g_return_if_fail (playlist_treeview);
+
+    if (!playlists) {
+        ts = gtk_tree_view_get_selection(playlist_treeview);
+        gtk_tree_selection_unselect_all(ts);
+        return;
+    }
+
+    ts = gtk_tree_view_get_selection(playlist_treeview);
+
+    for (gint i = 0; i < g_list_length(playlists); ++i) {
+        Playlist *pl = g_list_nth_data(playlists, i);
+
+        if (pm_get_iter_for_playlist(pl, &iter)) {
+            gtk_tree_selection_select_iter(ts, &iter);
+        }
+
+        /* Only properly select the first in the list */
+        if (i == 0 && gtkpod_get_current_playlist() != pl) {
+            gtkpod_set_current_playlist(pl);
+        }
+    }
+}
+
+/* Select specified playlist */
 void pm_select_playlist(Playlist *playlist) {
     GtkTreeIter iter;
     GtkTreeSelection *ts;
@@ -1128,10 +1122,13 @@ void pm_unselect_playlist(Playlist *playlist) {
 }
 
 static gboolean pm_selection_changed_cb(gpointer data) {
-    GtkTreeModel *model;
     GtkTreeIter iter;
     GtkTreeView *tree_view = GTK_TREE_VIEW (data);
-    GtkTreeSelection *selection = gtk_tree_view_get_selection(tree_view);
+
+    g_return_val_if_fail(tree_view, FALSE);
+
+    GtkTreeModel *model = gtk_tree_view_get_model(tree_view);
+    g_return_val_if_fail(model, FALSE);
 
 #if DEBUG_TIMING
     GTimeVal time;
@@ -1140,16 +1137,20 @@ static gboolean pm_selection_changed_cb(gpointer data) {
             time.tv_sec % 3600, time.tv_usec);
 #endif
 
-    if (gtk_tree_selection_get_selected(selection, &model, &iter) == FALSE) { 
/* no selection -> reset sort tabs */
-        //             gphoto_change_to_photo_window (FALSE);
+    if (! pm_is_playlist_selected()) {
+        /* no selection */
         gtkpod_set_current_playlist(NULL);
     }
     else {
-        Playlist *new_playlist = NULL;
+        Playlist *new_playlist = pm_get_first_selected_playlist();
+        g_return_val_if_fail(new_playlist, FALSE);
+
         Itdb_iTunesDB *itdb = NULL;
         Itdb_PhotoDB *photodb = NULL;
         PM_column_type type = 0;
+
         /* handle new selection */
+        pm_get_iter_for_playlist(new_playlist, &iter);
         gtk_tree_model_get(model, &iter, PM_COLUMN_TYPE, &type, 
PM_COLUMN_ITDB, &itdb, PM_COLUMN_PLAYLIST, &new_playlist, PM_COLUMN_PHOTOS, 
&photodb, -1);
 
         gtkpod_set_current_playlist(new_playlist);
@@ -1159,8 +1160,6 @@ static gboolean pm_selection_changed_cb(gpointer data) {
             g_return_val_if_fail (new_playlist, FALSE);
             g_return_val_if_fail (itdb, FALSE);
 
-            //         gphoto_change_to_photo_window (FALSE);
-
             if (new_playlist->is_spl && new_playlist->splpref.liveupdate)
                 itdb_spl_update(new_playlist);
 
@@ -1169,7 +1168,6 @@ static gboolean pm_selection_changed_cb(gpointer data) {
         case PM_COLUMN_PHOTOS:
             g_return_val_if_fail (photodb, FALSE);
             g_return_val_if_fail (itdb, FALSE);
-            //         gphoto_display_photo_window (itdb);
             break;
         case PM_COLUMN_ITDB:
         case PM_COLUMN_TYPE:
@@ -1361,16 +1359,16 @@ static gint pm_get_position_for_playlist(Playlist 
*playlist) {
 /* "unsort" the playlist view without causing the sort tabs to be
  touched. */
 static void pm_unsort() {
-    Playlist *cur_pl;
+    GList *cur_pls;
 
     pm_selection_blocked = TRUE;
 
     /* remember */
-    cur_pl = pm_get_selected_playlist();
+    cur_pls = pm_get_selected_playlists();
 
     pm_remove_all_playlists(TRUE);
 
-    pm_set_selected_playlist(cur_pl);
+    pm_select_playlists(cur_pls);
 
     pm_selection_blocked = FALSE;
     /* reset sort counter */
@@ -1904,11 +1902,12 @@ static void pm_create_treeview(void) {
     model = gtk_tree_store_new(PM_NUM_COLUMNS, G_TYPE_POINTER, G_TYPE_INT, 
G_TYPE_POINTER, G_TYPE_POINTER);
     /* set tree model */
     gtk_tree_view_set_model(playlist_treeview, GTK_TREE_MODEL (model));
-    /* gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (playlist_treeview), TRUE); 
*/
-    
gtk_tree_selection_set_mode(gtk_tree_view_get_selection(playlist_treeview), 
GTK_SELECTION_SINGLE);
+
+    /* set selection mode */
     selection = gtk_tree_view_get_selection(playlist_treeview);
-    g_signal_connect (G_OBJECT (selection), "changed",
-            G_CALLBACK (pm_selection_changed), NULL);
+    gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
+    g_signal_connect (G_OBJECT (selection), "changed", G_CALLBACK 
(pm_selection_changed), NULL);
+
     pm_add_columns();
     pm_add_all_itdbs();
 
@@ -2005,51 +2004,63 @@ GtkWidget *pm_create_playlist_view(GtkActionGroup 
*action_group) {
     return GTK_WIDGET(vbox);
 }
 
-Playlist* pm_get_selected_playlist(void) {
-    GtkTreeSelection *ts;
-    GtkTreeIter iter;
-    GtkTreeModel *model;
-    Playlist *result = NULL;
+void pm_selected_playlists_foreach(PlaylistSelectionForeachFunc func, gpointer 
data) {
+    GList *playlists = pm_get_selected_playlists();
+    while(playlists) {
+        Playlist *pl = playlists->data;
+        (* func) (pl ,data);
+        playlists = playlists->next;
+    }
+}
 
-    g_return_val_if_fail (playlist_treeview, NULL);
-    ts = gtk_tree_view_get_selection(playlist_treeview);
-    g_return_val_if_fail (ts, NULL);
+GList *pm_get_selected_playlists() {
+    g_return_val_if_fail(playlist_treeview, NULL);
 
-    if (gtk_tree_selection_get_selected(ts, &model, &iter)) {
-        gtk_tree_model_get(model, &iter, PM_COLUMN_PLAYLIST, &result, -1);
+    GtkTreeSelection *selection = 
gtk_tree_view_get_selection(playlist_treeview);
+    g_return_val_if_fail(selection, NULL);
+
+    GtkTreeModel *model = gtk_tree_view_get_model(playlist_treeview);
+    GList *paths = gtk_tree_selection_get_selected_rows(selection, &model);
+    GList *playlists = NULL;
+
+    while (paths) {
+        GtkTreePath *path = paths->data;
+        GtkTreeIter iter;
+
+        if (gtk_tree_model_get_iter(model, &iter, path)) {
+            Playlist *pl;
+            gtk_tree_model_get(model, &iter, PM_COLUMN_PLAYLIST, &pl, -1);
+            if (pl) {
+                playlists = g_list_append(playlists, pl);
+            }
+        }
+
+        paths = paths->next;
     }
 
-    /* playlist was just changed -- wait until current_playlist is
-     updated. */
-    if (result != gtkpod_get_current_playlist())
-        result = NULL;
-    return result;
+    g_list_free(paths);
+
+    return playlists;
 }
 
-Itdb_iTunesDB* pm_get_selected_itdb(void) {
-    GtkTreeSelection *ts;
-    GtkTreeIter iter;
-    GtkTreeModel *model;
-    Itdb_iTunesDB *result = NULL;
+Playlist *pm_get_first_selected_playlist(void) {
 
-    g_return_val_if_fail (playlist_treeview, NULL);
-    ts = gtk_tree_view_get_selection(playlist_treeview);
-    g_return_val_if_fail (ts, NULL);
+    GList *playlists = pm_get_selected_playlists();
 
-    if (gtk_tree_selection_get_selected(ts, &model, &iter)) {
-        gtk_tree_model_get(model, &iter, PM_COLUMN_ITDB, &result, -1);
+    if (!playlists) {
+        return NULL;
     }
 
-    /* playlist was just changed -- wait until current_playlist is
-     updated. */
-    if (result != gtkpod_get_current_itdb())
-        result = NULL;
-    return result;
+    return playlists->data;
+}
+
+gint pm_get_selected_playlist_count() {
+    GtkTreeSelection *selection = 
gtk_tree_view_get_selection(playlist_treeview);
+    return gtk_tree_selection_count_selected_rows(selection);
 }
 
-/* use with care!! */
-void pm_set_selected_playlist(Playlist *pl) {
-    gtkpod_set_current_playlist(pl);
+gboolean pm_is_playlist_selected() {
+    return pm_get_selected_playlist_count() > 0;
 }
 
 void pm_show_all_playlists() {
@@ -2082,7 +2093,7 @@ void playlist_display_update_itdb_cb(GtkPodApp *app, 
gpointer olditdb, gpointer
     /* remove @old_itdb (all playlists are removed if the MPL is
      removed and add @new_itdb at its place */
 
-    pm_remove_playlist(itdb_playlist_mpl(old_itdb), FALSE);
+    pm_remove_playlist(itdb_playlist_mpl(old_itdb));
 
     /* display replacement */
     pm_add_itdb(new_itdb, pos);
@@ -2103,21 +2114,7 @@ void playlist_display_itdb_removed_cb(GtkPodApp *app, 
gpointer itdb, gpointer da
         return;
     }
 
-    pm_remove_playlist(itdb_playlist_mpl(old_itdb), FALSE);
-}
-
-void playlist_display_select_playlist_cb(GtkPodApp *app, gpointer pl, gpointer 
data) {
-    Playlist *new_playlist = pl;
-    Playlist *old_playlist = pm_get_selected_playlist();
-
-    if (old_playlist == new_playlist) {
-        return;
-    }
-
-    if (old_playlist)
-        pm_unselect_playlist(old_playlist);
-
-    pm_select_playlist(new_playlist);
+    pm_remove_playlist(itdb_playlist_mpl(old_itdb));
 }
 
 void playlist_display_playlist_added_cb(GtkPodApp *app, gpointer pl, gint32 
pos, gpointer data) {
@@ -2129,7 +2126,7 @@ void playlist_display_playlist_added_cb(GtkPodApp *app, 
gpointer pl, gint32 pos,
 void playlist_display_playlist_removed_cb(GtkPodApp *app, gpointer pl, 
gpointer data) {
     Playlist *old_playlist = pl;
 
-    pm_remove_playlist(old_playlist, TRUE);
+    pm_remove_playlist(old_playlist);
 }
 
 void playlist_display_preference_changed_cb(GtkPodApp *app, gpointer pfname, 
gpointer value, gpointer data) {
diff --git a/plugins/playlist_display/display_playlists.h 
b/plugins/playlist_display/display_playlists.h
index e78f68f..8957a4b 100644
--- a/plugins/playlist_display/display_playlists.h
+++ b/plugins/playlist_display/display_playlists.h
@@ -49,16 +49,22 @@ typedef enum  {
 GtkWidget *pm_create_playlist_view(GtkActionGroup *action_group);
 void pm_destroy_playlist_view(void);
 void pm_select_playlist(Playlist *playlist);
-void pm_set_selected_playlist(Playlist *pl);
+
+GList *pm_get_selected_playlists(void);
+Playlist *pm_get_first_selected_playlist(void);
+gint pm_get_selected_playlist_count(void);
+gboolean pm_is_playlist_selected(void);
+
+typedef gboolean (* PlaylistSelectionForeachFunc) (Playlist *playlist, 
gpointer data);
+void pm_selected_playlists_foreach(PlaylistSelectionForeachFunc func, gpointer 
data);
+
 void pm_remove_all_playlists (gboolean clear_sort);
 void pm_add_all_itdbs (void);
-Playlist* pm_get_selected_playlist(void);
 void pm_stop_editing(gboolean cancel);
 
 void playlist_display_itdb_added_cb(GtkPodApp *app, gpointer itdb, gint32 pos, 
gpointer data);
 void playlist_display_itdb_removed_cb(GtkPodApp *app, gpointer itdb, gpointer 
data);
 void playlist_display_update_itdb_cb (GtkPodApp *app, gpointer olditdb, 
gpointer newitdb, gpointer data);
-void playlist_display_select_playlist_cb (GtkPodApp *app, gpointer pl, 
gpointer data);
 void playlist_display_playlist_added_cb(GtkPodApp *app, gpointer pl, gint32 
pos, gpointer data);
 void playlist_display_playlist_removed_cb(GtkPodApp *app, gpointer pl, 
gpointer data);
 void playlist_display_track_removed_cb(GtkPodApp *app, gpointer tk, gpointer 
data);
diff --git a/plugins/playlist_display/playlist_display_actions.c 
b/plugins/playlist_display/playlist_display_actions.c
index cd612d7..f8954b9 100644
--- a/plugins/playlist_display/playlist_display_actions.c
+++ b/plugins/playlist_display/playlist_display_actions.c
@@ -624,59 +624,77 @@ void on_pl_for_each_rating_activate(GtkAction *action, 
PlaylistDisplayPlugin* pl
     }
 }
 
-static void delete_selected_playlist(DeleteAction deleteaction) {
-    Playlist *pl = pm_get_selected_playlist();
+static void delete_selected_playlists(DeleteAction deleteaction) {
+    GList *playlists = pm_get_selected_playlists();
+
+    while (playlists) {
+        Playlist *pl = playlists->data;
+        if (pl) {
+            gtkpod_set_current_playlist(pl);
+            delete_playlist_head(deleteaction);
+        }
+        else {
+            message_sb_no_playlist_selected();
+        }
 
-    if (pl) {
-        delete_playlist_head(deleteaction);
-    }
-    else {
-        message_sb_no_playlist_selected();
+        playlists = playlists->next;
     }
 }
 
-void on_delete_selected_playlist (GtkAction *action, PlaylistDisplayPlugin* 
plugin)
+void on_delete_selected_playlists (GtkAction *action, PlaylistDisplayPlugin* 
plugin)
 {
-    delete_selected_playlist (DELETE_ACTION_PLAYLIST);
+    delete_selected_playlists (DELETE_ACTION_PLAYLIST);
 }
 
-void on_delete_selected_playlist_including_tracks_from_harddisk (GtkAction 
*action, PlaylistDisplayPlugin* plugin)
+void on_delete_selected_playlists_including_tracks_from_harddisk (GtkAction 
*action, PlaylistDisplayPlugin* plugin)
 {
-    delete_selected_playlist (DELETE_ACTION_LOCAL);
+    delete_selected_playlists (DELETE_ACTION_LOCAL);
 }
 
-void on_delete_selected_playlist_including_tracks_from_ipod (GtkAction 
*action, PlaylistDisplayPlugin* plugin)
+void on_delete_selected_playlists_including_tracks_from_ipod (GtkAction 
*action, PlaylistDisplayPlugin* plugin)
 {
-    delete_selected_playlist (DELETE_ACTION_IPOD);
+    delete_selected_playlists (DELETE_ACTION_IPOD);
 }
 
-void on_delete_selected_playlist_including_tracks_from_database (GtkAction 
*action, PlaylistDisplayPlugin* plugin)
+void on_delete_selected_playlists_including_tracks_from_database (GtkAction 
*action, PlaylistDisplayPlugin* plugin)
 {
-    delete_selected_playlist (DELETE_ACTION_DATABASE);
+    delete_selected_playlists (DELETE_ACTION_DATABASE);
 }
 
-void on_delete_selected_playlist_including_tracks_from_device(GtkAction 
*action, PlaylistDisplayPlugin* plugin)
+void on_delete_selected_playlists_including_tracks_from_device(GtkAction 
*action, PlaylistDisplayPlugin* plugin)
 {
     iTunesDB *itdb = gtkpod_get_current_itdb();
     if (!itdb)
         return;
 
     if (itdb->usertype & GP_ITDB_TYPE_IPOD) {
-        on_delete_selected_playlist_including_tracks_from_ipod(action, plugin);
+        on_delete_selected_playlists_including_tracks_from_ipod(action, 
plugin);
     } else if (itdb->usertype & GP_ITDB_TYPE_LOCAL) {
-        on_delete_selected_playlist_including_tracks_from_harddisk(action, 
plugin);
+        on_delete_selected_playlists_including_tracks_from_harddisk(action, 
plugin);
     }
 }
 
-void on_update_selected_playlist (GtkAction *action, PlaylistDisplayPlugin* 
plugin) {
-    Playlist *pl = pm_get_selected_playlist();
-    if (pl) {
-        update_tracks(pm_get_selected_playlist()->members);
+void on_update_selected_playlists (GtkAction *action, PlaylistDisplayPlugin* 
plugin) {
+
+    GList *playlists = pm_get_selected_playlists();
+
+    while (playlists) {
+        Playlist *pl = playlists->data;
+        if (pl) {
+            update_tracks(pl->members);
+        }
+        playlists = playlists->next;
     }
 }
 
-void on_sync_playlist_with_dirs(GtkAction *action, PlaylistDisplayPlugin* 
plugin) {
-    if (gtkpod_get_current_playlist()) {
-        sync_playlist(gtkpod_get_current_playlist(), NULL, 
KEY_SYNC_CONFIRM_DIRS, 0, KEY_SYNC_DELETE_TRACKS, 0, KEY_SYNC_CONFIRM_DELETE, 
0, KEY_SYNC_SHOW_SUMMARY, 0);
+void on_sync_playlists_with_dirs(GtkAction *action, PlaylistDisplayPlugin* 
plugin) {
+    GList *playlists = pm_get_selected_playlists();
+
+    while (playlists) {
+        Playlist *pl = playlists->data;
+        if (pl) {
+            sync_playlist(pl, NULL, KEY_SYNC_CONFIRM_DIRS, 0, 
KEY_SYNC_DELETE_TRACKS, 0, KEY_SYNC_CONFIRM_DELETE, 0, KEY_SYNC_SHOW_SUMMARY, 
0);
+        }
+        playlists = playlists->next;
     }
 }
diff --git a/plugins/playlist_display/playlist_display_actions.h 
b/plugins/playlist_display/playlist_display_actions.h
index 20ced8c..5d7b6d2 100644
--- a/plugins/playlist_display/playlist_display_actions.h
+++ b/plugins/playlist_display/playlist_display_actions.h
@@ -61,13 +61,13 @@ void on_pl_for_each_composer_activate(GtkAction *action, 
PlaylistDisplayPlugin*
 void on_pl_for_each_year_activate(GtkAction *action, PlaylistDisplayPlugin* 
plugin);
 void on_pl_for_each_rating_activate(GtkAction *action, PlaylistDisplayPlugin* 
plugin);
 
-void on_delete_selected_playlist (GtkAction *action, PlaylistDisplayPlugin* 
plugin);
-void on_delete_selected_playlist_including_tracks_from_harddisk (GtkAction 
*action, PlaylistDisplayPlugin* plugin);
-void on_delete_selected_playlist_including_tracks_from_ipod (GtkAction 
*action, PlaylistDisplayPlugin* plugin);
-void on_delete_selected_playlist_including_tracks_from_database (GtkAction 
*action, PlaylistDisplayPlugin* plugin);
-void on_delete_selected_playlist_including_tracks_from_device(GtkAction 
*action, PlaylistDisplayPlugin* plugin);
+void on_delete_selected_playlists (GtkAction *action, PlaylistDisplayPlugin* 
plugin);
+void on_delete_selected_playlists_including_tracks_from_harddisk (GtkAction 
*action, PlaylistDisplayPlugin* plugin);
+void on_delete_selected_playlists_including_tracks_from_ipod (GtkAction 
*action, PlaylistDisplayPlugin* plugin);
+void on_delete_selected_playlists_including_tracks_from_database (GtkAction 
*action, PlaylistDisplayPlugin* plugin);
+void on_delete_selected_playlists_including_tracks_from_device(GtkAction 
*action, PlaylistDisplayPlugin* plugin);
 
-void on_update_selected_playlist (GtkAction *action, PlaylistDisplayPlugin* 
plugin);
-void on_sync_playlist_with_dirs(GtkAction *action, PlaylistDisplayPlugin* 
plugin);
+void on_update_selected_playlists (GtkAction *action, PlaylistDisplayPlugin* 
plugin);
+void on_sync_playlists_with_dirs(GtkAction *action, PlaylistDisplayPlugin* 
plugin);
 
 #endif
diff --git a/plugins/playlist_display/playlist_display_context_menu.c 
b/plugins/playlist_display/playlist_display_context_menu.c
index b3246c6..2e8adda 100644
--- a/plugins/playlist_display/playlist_display_context_menu.c
+++ b/plugins/playlist_display/playlist_display_context_menu.c
@@ -40,13 +40,21 @@
 #include "libgtkpod/gp_itdb.h"
 #include "libgtkpod/context_menus.h"
 #include "libgtkpod/misc_playlist.h"
+#include "libgtkpod/misc_track.h"
 #include "libgtkpod/misc.h"
+#include "libgtkpod/prefs.h"
+#include "libgtkpod/syncdir.h"
 
 static void context_menu_delete_playlist_head(GtkMenuItem *mi, gpointer data) {
     DeleteAction deleteaction = GPOINTER_TO_INT (data);
     delete_playlist_head(deleteaction);
 }
 
+void context_menu_delete_track_head(GtkMenuItem *mi, gpointer data) {
+    DeleteAction deleteaction = GPOINTER_TO_INT (data);
+    delete_track_head(deleteaction);
+}
+
 static GtkWidget *add_delete_all_tracks_from_ipod(GtkWidget *menu) {
     GtkWidget *mi;
     GtkWidget *sub;
@@ -99,21 +107,33 @@ static GtkWidget 
*add_delete_playlist_but_keep_tracks(GtkWidget *menu) {
     return hookup_menu_item(menu, _("Delete But Keep Tracks"), 
GTK_STOCK_DELETE, G_CALLBACK (context_menu_delete_playlist_head), 
GINT_TO_POINTER (DELETE_ACTION_PLAYLIST));
 }
 
-static void copy_selected_playlist_to_target_itdb(GtkMenuItem *mi, gpointer 
*userdata) {
+static void copy_selected_playlists_to_target_itdb(GtkMenuItem *mi, gpointer 
*userdata) {
     iTunesDB *t_itdb = *userdata;
     g_return_if_fail (t_itdb);
-    if (gtkpod_get_current_playlist())
-        copy_playlist_to_target_itdb(gtkpod_get_current_playlist(), t_itdb);
+
+    GList *playlists = pm_get_selected_playlists();
+    while(playlists) {
+        Playlist *pl = playlists->data;
+        copy_playlist_to_target_itdb(pl, t_itdb);
+        playlists = playlists->next;
+    }
 }
 
-static void copy_selected_playlist_to_target_playlist(GtkMenuItem *mi, 
gpointer *userdata) {
+
+
+static void copy_selected_playlists_to_target_playlist(GtkMenuItem *mi, 
gpointer *userdata) {
     Playlist *t_pl = *userdata;
     g_return_if_fail (t_pl);
-    if (gtkpod_get_current_playlist())
-        copy_playlist_to_target_playlist(gtkpod_get_current_playlist(), t_pl);
+
+    GList *playlists = pm_get_selected_playlists();
+    while(playlists) {
+        Playlist *pl = playlists->data;
+        copy_playlist_to_target_playlist(pl, t_pl);
+        playlists = playlists->next;
+    }
 }
 
-static GtkWidget *add_copy_selected_playlist_to_target_itdb(GtkWidget *menu, 
const gchar *title) {
+static GtkWidget *add_copy_selected_playlists_to_target_itdb(GtkWidget *menu, 
const gchar *title) {
     GtkWidget *mi;
     GtkWidget *sub;
     GtkWidget *pl_mi;
@@ -150,7 +170,7 @@ static GtkWidget 
*add_copy_selected_playlist_to_target_itdb(GtkWidget *menu, con
         pl_sub = gtk_menu_new();
         gtk_widget_show(pl_sub);
         gtk_menu_item_set_submenu(GTK_MENU_ITEM (pl_mi), pl_sub);
-        hookup_menu_item(pl_sub, _(itdb_playlist_mpl(itdb)->name), stock_id, 
G_CALLBACK(copy_selected_playlist_to_target_itdb), &itdbs->data);
+        hookup_menu_item(pl_sub, _(itdb_playlist_mpl(itdb)->name), stock_id, 
G_CALLBACK(copy_selected_playlists_to_target_itdb), &itdbs->data);
         add_separator(pl_sub);
         for (db = itdb->playlists; db; db = db->next) {
             pl = db->data;
@@ -159,7 +179,7 @@ static GtkWidget 
*add_copy_selected_playlist_to_target_itdb(GtkWidget *menu, con
                     stock_id = GTK_STOCK_PROPERTIES;
                 else
                     stock_id = GTK_STOCK_JUSTIFY_LEFT;
-                hookup_menu_item(pl_sub, _(pl->name), stock_id, 
G_CALLBACK(copy_selected_playlist_to_target_playlist), &db->data);
+                hookup_menu_item(pl_sub, _(pl->name), stock_id, 
G_CALLBACK(copy_selected_playlists_to_target_playlist), &db->data);
             }
         }
     }
@@ -195,7 +215,13 @@ static void open_photo_editor(GtkMenuItem *mi, gpointer 
data) {
 /* Save Changes */
 static void save_changes(GtkMenuItem *mi, gpointer data) {
     g_return_if_fail (gtkpod_get_current_playlist());
-    gp_save_itdb(gtkpod_get_current_playlist()->itdb);
+
+    GList *playlists = pm_get_selected_playlists();
+    while (playlists) {
+        Playlist *pl = playlists->data;
+        gp_save_itdb(pl->itdb);
+        playlists = playlists->next;
+    }
 }
 
 /* Load an itdb */
@@ -268,21 +294,42 @@ static GtkWidget *add_eject_ipod(GtkWidget *menu) {
     return hookup_menu_item(menu, _("Eject iPod"), GTK_STOCK_DISCONNECT, 
G_CALLBACK (eject_ipod), NULL);
 }
 
-void pm_context_menu_init(void) {
-    GtkWidget *menu = NULL;
-    Playlist *pl;
+/*
+ * sync_dirs_ entries - sync the directories of the selected playlist
+ *
+ * @mi - the menu item selected
+ * @data - Ignored, should be NULL
+ */
+static void sync_dirs(GtkMenuItem *mi, gpointer data) {
+    GList *playlists = pm_get_selected_playlists();
+    while (playlists) {
+        Playlist *pl = playlists->data;
+        sync_playlist(pl, NULL, KEY_SYNC_CONFIRM_DIRS, 0, 
KEY_SYNC_DELETE_TRACKS, 0, KEY_SYNC_CONFIRM_DELETE, 0, KEY_SYNC_SHOW_SUMMARY, 
0);
+        playlists = playlists->next;
+    }
+}
 
-    if (widgets_blocked)
-        return;
+static GtkWidget *add_sync_playlist_with_dirs(GtkWidget *menu) {
+    return hookup_menu_item(menu, _("Sync Playlist with Dir(s)"), 
GTK_STOCK_REFRESH, G_CALLBACK (sync_dirs), NULL);
+}
 
-    pm_stop_editing(TRUE);
+static void update_multi_tracks_from_file(GtkMenuItem *mi, gpointer data) {
+    GList *playlists = pm_get_selected_playlists();
+    while (playlists) {
+        Playlist *pl = playlists->data;
+        update_tracks(pl->members);
+        playlists = playlists->next;
+    }
+}
 
-    if (!pm_get_selected_playlist())
-        return;
+GtkWidget *add_multi_update_tracks_from_file(GtkWidget *menu) {
+    return hookup_menu_item(menu, _("Update Tracks from File"), 
GTK_STOCK_REFRESH, G_CALLBACK (update_multi_tracks_from_file), NULL);
+}
 
-    pl = pm_get_selected_playlist();
-    if (!pl)
-        return;
+static void _populate_single_playlist_menu(GtkWidget *menu) {
+
+    Playlist *pl = pm_get_first_selected_playlist();
+    g_return_if_fail(pl);
 
     // Ensure that all the tracks in the playlist are the current selected 
tracks
     gtkpod_set_selected_tracks(pl->members);
@@ -293,8 +340,6 @@ void pm_context_menu_init(void) {
     eitdb = itdb->userdata;
     g_return_if_fail (eitdb);
 
-    menu = gtk_menu_new();
-
     if (itdb->usertype & GP_ITDB_TYPE_IPOD) {
         if (eitdb->itdb_imported) {
             add_exec_commands(menu);
@@ -312,7 +357,7 @@ void pm_context_menu_init(void) {
                 add_delete_playlist_but_keep_tracks(delete_menu);
             }
             add_separator(menu);
-            add_copy_selected_playlist_to_target_itdb(menu, _("Copy selected 
playlist to..."));
+            add_copy_selected_playlists_to_target_itdb(menu, _("Copy selected 
playlist to..."));
 
             add_separator(menu);
             add_update_tracks_from_file(menu);
@@ -340,7 +385,7 @@ void pm_context_menu_init(void) {
             add_load_ipod(menu);
         }
     }
-    if (itdb->usertype & GP_ITDB_TYPE_LOCAL) {
+    else if (itdb->usertype & GP_ITDB_TYPE_LOCAL) {
         add_exec_commands(menu);
         add_separator(menu);
 
@@ -353,7 +398,7 @@ void pm_context_menu_init(void) {
             add_delete_playlist_including_tracks_harddisk(delete_menu);
             add_delete_playlist_but_keep_tracks(delete_menu);
         }
-        add_copy_selected_playlist_to_target_itdb(menu, _("Copy selected 
playlist to..."));
+        add_copy_selected_playlists_to_target_itdb(menu, _("Copy selected 
playlist to..."));
         add_separator(menu);
         add_update_tracks_from_file(menu);
         if (!pl->is_spl) {
@@ -376,6 +421,43 @@ void pm_context_menu_init(void) {
     if (eitdb->data_changed) {
         add_save_changes(menu);
     }
+}
+
+static void _populate_multi_playlist_menu(GtkWidget *menu) {
+
+    GtkWidget *delete_menu = add_sub_menu(menu, "Delete", GTK_STOCK_DELETE);
+    add_delete_playlist_including_tracks_ipod(delete_menu);
+    add_delete_playlist_but_keep_tracks(delete_menu);
+
+    add_separator(menu);
+    add_copy_selected_playlists_to_target_itdb(menu, _("Copy selected playlist 
to..."));
+
+    add_separator(menu);
+    add_multi_update_tracks_from_file(menu);
+
+    add_sync_playlist_with_dirs(menu);
+
+    add_save_changes(menu);
+}
+
+void pm_context_menu_init(void) {
+    GtkWidget *menu = NULL;
+
+    if (widgets_blocked)
+        return;
+
+    pm_stop_editing(TRUE);
+
+    if (!pm_is_playlist_selected())
+        return;
+
+    menu = gtk_menu_new();
+
+    if (pm_get_selected_playlist_count() == 1) {
+        _populate_single_playlist_menu(menu);
+    } else {
+        _populate_multi_playlist_menu(menu);
+    }
 
     /*
      * button should be button 0 as per the docs because we're calling
diff --git a/plugins/playlist_display/plugin.c 
b/plugins/playlist_display/plugin.c
index 2368e2c..407c55c 100644
--- a/plugins/playlist_display/plugin.c
+++ b/plugins/playlist_display/plugin.c
@@ -116,7 +116,7 @@ static GtkActionEntry playlist_actions[] =
             N_("Sync Playlist with Dir(s)"),
             NULL,
             NULL,
-            G_CALLBACK (on_sync_playlist_with_dirs)
+            G_CALLBACK (on_sync_playlists_with_dirs)
         },
         {
             ACTION_NEW_PLAYLIST_MENU,
@@ -268,7 +268,7 @@ static GtkActionEntry playlist_actions[] =
             N_("Selected Playlist"),
             NULL,
             NULL,
-            G_CALLBACK (on_delete_selected_playlist)
+            G_CALLBACK (on_delete_selected_playlists)
         },
         {
             "ActionDeleteSelectedPlaylistIncDb",
@@ -276,7 +276,7 @@ static GtkActionEntry playlist_actions[] =
             N_("Selected Playlist including Tracks from Database"),
             NULL,
             NULL,
-            G_CALLBACK 
(on_delete_selected_playlist_including_tracks_from_database)
+            G_CALLBACK 
(on_delete_selected_playlists_including_tracks_from_database)
         },
         {
             "ActionDeleteSelectedPlaylistIncDev",
@@ -284,7 +284,7 @@ static GtkActionEntry playlist_actions[] =
             N_("Selected Playlist including Tracks from Device"),
             NULL,
             NULL,
-            G_CALLBACK 
(on_delete_selected_playlist_including_tracks_from_device)
+            G_CALLBACK 
(on_delete_selected_playlists_including_tracks_from_device)
         },
         {
             "ActionUpdatePlaylist",
@@ -292,7 +292,7 @@ static GtkActionEntry playlist_actions[] =
             N_("Selected Playlist"),
             NULL,
             NULL,
-            G_CALLBACK (on_update_selected_playlist)
+            G_CALLBACK (on_update_selected_playlists)
         }
     };
 
@@ -349,7 +349,6 @@ static gboolean activate_plugin(AnjutaPlugin *plugin) {
 
     playlist_display_plugin->playlist_view = 
pm_create_playlist_view(action_group);
 
-    g_signal_connect (gtkpod_app, SIGNAL_PLAYLIST_SELECTED, G_CALLBACK 
(playlist_display_select_playlist_cb), NULL);
     g_signal_connect (gtkpod_app, SIGNAL_PLAYLIST_ADDED, G_CALLBACK 
(playlist_display_playlist_added_cb), NULL);
     g_signal_connect (gtkpod_app, SIGNAL_PLAYLIST_REMOVED, G_CALLBACK 
(playlist_display_playlist_removed_cb), NULL);
     g_signal_connect (gtkpod_app, SIGNAL_ITDB_ADDED, G_CALLBACK 
(playlist_display_itdb_added_cb), NULL);
@@ -373,7 +372,6 @@ static gboolean deactivate_plugin(AnjutaPlugin *plugin) {
     playlist_display_plugin = (PlaylistDisplayPlugin*) plugin;
     ui = anjuta_shell_get_ui(plugin->shell, NULL);
 
-    g_signal_handlers_disconnect_by_func (plugin->shell, G_CALLBACK 
(playlist_display_select_playlist_cb), plugin);
     g_signal_handlers_disconnect_by_func (plugin->shell, G_CALLBACK 
(playlist_display_playlist_added_cb), plugin);
     g_signal_handlers_disconnect_by_func (plugin->shell, G_CALLBACK 
(playlist_display_playlist_removed_cb), plugin);
     g_signal_handlers_disconnect_by_func (plugin->shell, G_CALLBACK 
(playlist_display_itdb_added_cb), plugin);

------------------------------------------------------------------------------
All the data continuously generated in your IT infrastructure contains a
definitive record of customers, application performance, security
threats, fraudulent activity and more. Splunk takes this data and makes
sense of it. Business sense. IT sense. Common sense.
http://p.sf.net/sfu/splunk-d2dcopy1
_______________________________________________
gtkpod-cvs2 mailing list
gtkpod-cvs2@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/gtkpod-cvs2

Reply via email to