1 /*
2  *
3  *   File: playlist.c
4  *
5  *   Copyright (C) 2009-2014 Darran Kartaschew
6  *
7  *   This file is part of the gMTP package.
8  *
9  *   gMTP is free software; you can redistribute it and/or modify
10  *   it under the terms of the BSD License as included within the
11  *   file 'COPYING' located in the root directory
12  *
13  */
14 #include "playlist.h"
15 #include "main.h"
16 #include "mtp.h"
17 #include "interface.h"
18 #include "callbacks.h"
19 
20 GtkWidget *windowPlaylistDialog;
21 // Playlist
22 
23 GtkWidget *comboboxentry_playlist;
24 gint playlist_number = 0;
25 gint comboboxentry_playlist_entries = 0;
26 gint playlist_track_count = 0;
27 gboolean runPlaylistHandler = TRUE;
28 
29 GtkWidget *treeview_Avail_Files;
30 GtkWidget *treeview_Playlist_Files;
31 
32 GtkListStore *playlist_TrackList;
33 GtkTreeSelection *playlist_TrackSelection;
34 GList *playlist_Selection_TrackRowReferences = NULL;
35 
36 GtkListStore *playlist_PL_List;
37 GtkTreeSelection *playlist_PL_Selection;
38 GList *playlist_Selection_PL_RowReferences = NULL;
39 
40 // Buttons for playlist
41 GtkWidget *button_Del_Playlist;
42 GtkWidget *button_Export_Playlist;
43 GtkWidget *button_File_Move_Up;
44 GtkWidget *button_File_Move_Down;
45 GtkWidget *button_Del_File;
46 GtkWidget *button_Add_Files;
47 
48 // ************************************************************************************************
49 
50 // Playlist support
51 
create_windowPlaylist(void)52 GtkWidget* create_windowPlaylist(void) {
53     GtkWidget *window_playlist;
54     GtkWidget *vbox1;
55     GtkWidget *hbox1;
56     GtkWidget *label_Playlist;
57 
58     GtkWidget *button_Add_Playlist;
59     GtkWidget *button_Import_Playlist;
60     //GtkWidget *alignment2;
61     GtkWidget *hbox3;
62     GtkWidget *image2;
63     GtkWidget *label3;
64 
65     //GtkWidget *alignment1;
66     GtkWidget *hbox2;
67     GtkWidget *image1;
68     GtkWidget *label2;
69     GtkWidget *hbox4;
70     GtkWidget *scrolledwindow2;
71 
72     GtkWidget *vbuttonbox1;
73 
74     // GtkWidget *alignment6;
75     GtkWidget *hbox8;
76     GtkWidget *image6;
77     GtkWidget *label10;
78 
79     //GtkWidget *alignment7;
80     GtkWidget *hbox9;
81     GtkWidget *image7;
82     GtkWidget *label11;
83     GtkWidget *scrolledwindow3;
84 
85     GtkWidget *vbuttonbox2;
86 
87     GtkWidget *hbuttonbox1;
88     GtkWidget *button_Close;
89 
90 
91 #if HAVE_GTK3 == 0
92     GtkTooltips *tooltips;
93     tooltips = gtk_tooltips_new();
94 #endif
95 
96     window_playlist = gtk_window_new(GTK_WINDOW_TOPLEVEL);
97     gchar * winTitle;
98     winTitle = g_strconcat(PACKAGE_NAME, _(" Playlists"), NULL);
99     gtk_window_set_title(GTK_WINDOW(window_playlist), winTitle);
100     gtk_window_set_modal(GTK_WINDOW(window_playlist), TRUE);
101     gtk_window_set_resizable(GTK_WINDOW(window_playlist), TRUE);
102     gtk_window_set_default_size(GTK_WINDOW(window_playlist), 760, 400);
103     gtk_window_set_transient_for(GTK_WINDOW(window_playlist), GTK_WINDOW(windowMain));
104     gtk_window_set_position(GTK_WINDOW(window_playlist), GTK_WIN_POS_CENTER_ON_PARENT);
105     gtk_window_set_skip_taskbar_hint(GTK_WINDOW(window_playlist), TRUE);
106     gtk_window_set_type_hint(GTK_WINDOW(window_playlist), GDK_WINDOW_TYPE_HINT_DIALOG);
107     gtk_container_set_border_width(GTK_CONTAINER(window_playlist), 5);
108     g_free(winTitle);
109 #if HAVE_GTK3 == 0
110     vbox1 = gtk_vbox_new(FALSE, 0);
111 #else
112     vbox1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
113 #endif
114     gtk_widget_show(vbox1);
115     gtk_container_add(GTK_CONTAINER(window_playlist), vbox1);
116 #if HAVE_GTK3 == 0
117     hbox1 = gtk_hbox_new(FALSE, 5);
118 #else
119     hbox1 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
120 #endif
121     gtk_widget_show(hbox1);
122     gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, TRUE, 5);
123 
124     label_Playlist = gtk_label_new(_("Current Playlist: "));
125     gtk_widget_show(label_Playlist);
126     gtk_box_pack_start(GTK_BOX(hbox1), label_Playlist, FALSE, FALSE, 5);
127 #if HAVE_GTK3 == 0
128     gtk_misc_set_padding(GTK_MISC(label_Playlist), 5, 0);
129 #else
130 #if GTK_CHECK_VERSION(3,12,0)
131     gtk_widget_set_margin_start(label_Playlist, 5);
132     gtk_widget_set_margin_end(label_Playlist, 5);
133 #else
134     gtk_widget_set_margin_left(label_Playlist, 5);
135     gtk_widget_set_margin_right(label_Playlist, 5);
136 #endif
137 #endif
138 
139 #if HAVE_GTK3 == 0
140     comboboxentry_playlist = gtk_combo_box_new_text();
141 #else
142     comboboxentry_playlist = gtk_combo_box_text_new();
143 #endif
144     gtk_widget_show(comboboxentry_playlist);
145     gtk_box_pack_start(GTK_BOX(hbox1), comboboxentry_playlist, TRUE, TRUE, 0);
146     gtk_container_set_border_width(GTK_CONTAINER(comboboxentry_playlist), 5);
147 
148     button_Add_Playlist = gtk_button_new();
149     gtk_widget_show(button_Add_Playlist);
150     gtk_box_pack_start(GTK_BOX(hbox1), button_Add_Playlist, FALSE, FALSE, 0);
151     gtk_container_set_border_width(GTK_CONTAINER(button_Add_Playlist), 5);
152 #if HAVE_GTK3 == 0
153     gtk_tooltips_set_tip(tooltips, button_Add_Playlist, _("Add New Playlist"), NULL);
154 #else
155     gtk_widget_set_tooltip_text(button_Add_Playlist, _("Add New Playlist"));
156 #endif
157 
158     //    alignment2 = gtk_alignment_new(0.5, 0.5, 0, 0);
159     //    gtk_widget_show(alignment2);
160     //    gtk_container_add(GTK_CONTAINER(button_Add_Playlist), alignment2);
161 #if HAVE_GTK3 == 0
162     hbox3 = gtk_hbox_new(FALSE, 2);
163 #else
164     hbox3 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2);
165 #endif
166     gtk_widget_show(hbox3);
167     gtk_container_add(GTK_CONTAINER(button_Add_Playlist), hbox3);
168 #if HAVE_GTK3 == 0
169     image2 = gtk_image_new_from_stock(GTK_STOCK_ADD, GTK_ICON_SIZE_BUTTON);
170 #else
171     image2 = gtk_image_new_from_icon_name("list-add", GTK_ICON_SIZE_BUTTON);
172 #endif
173     gtk_widget_show(image2);
174     gtk_box_pack_start(GTK_BOX(hbox3), image2, FALSE, FALSE, 0);
175 
176     label3 = gtk_label_new_with_mnemonic(_("Add"));
177     gtk_widget_show(label3);
178     gtk_box_pack_start(GTK_BOX(hbox3), label3, FALSE, FALSE, 0);
179 
180     button_Del_Playlist = gtk_button_new();
181     gtk_widget_show(button_Del_Playlist);
182     gtk_box_pack_start(GTK_BOX(hbox1), button_Del_Playlist, FALSE, FALSE, 0);
183     gtk_container_set_border_width(GTK_CONTAINER(button_Del_Playlist), 5);
184 #if HAVE_GTK3 == 0
185     gtk_tooltips_set_tip(tooltips, button_Del_Playlist, _("Remove Current Selected Playlist"), NULL);
186 #else
187     gtk_widget_set_tooltip_text(button_Del_Playlist, _("Remove Current Selected Playlist"));
188 #endif
189 
190     //    alignment1 = gtk_alignment_new(0.5, 0.5, 0, 0);
191     //    gtk_widget_show(alignment1);
192     //    gtk_container_add(GTK_CONTAINER(button_Del_Playlist), alignment1);
193 #if HAVE_GTK3 == 0
194     hbox2 = gtk_hbox_new(FALSE, 2);
195 #else
196     hbox2 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2);
197 #endif
198 
199     gtk_widget_show(hbox2);
200     gtk_container_add(GTK_CONTAINER(button_Del_Playlist), hbox2);
201 #if HAVE_GTK3 == 0
202     image1 = gtk_image_new_from_stock(GTK_STOCK_DELETE, GTK_ICON_SIZE_BUTTON);
203 #else
204     image1 = gtk_image_new_from_icon_name("edit-delete", GTK_ICON_SIZE_BUTTON);
205 #endif
206     gtk_widget_show(image1);
207     gtk_box_pack_start(GTK_BOX(hbox2), image1, FALSE, FALSE, 0);
208 
209     label2 = gtk_label_new_with_mnemonic(_("Del"));
210     gtk_widget_show(label2);
211     gtk_box_pack_start(GTK_BOX(hbox2), label2, FALSE, FALSE, 0);
212 
213     // Import Button
214 #if HAVE_GTK3 == 0
215     button_Import_Playlist = gtk_button_new_from_stock(GTK_STOCK_OPEN);
216 #else
217     button_Import_Playlist = gtk_button_new_with_label(_("Open"));
218 #endif
219     gtk_widget_show(button_Import_Playlist);
220     gtk_box_pack_start(GTK_BOX(hbox1), button_Import_Playlist, FALSE, FALSE, 0);
221     gtk_container_set_border_width(GTK_CONTAINER(button_Import_Playlist), 5);
222 #if HAVE_GTK3 == 0
223     gtk_tooltips_set_tip(tooltips, button_Import_Playlist, _("Import Playlist"), NULL);
224 #else
225     gtk_widget_set_tooltip_text(button_Import_Playlist, _("Import Playlist"));
226 #endif
227 
228     // Export Button
229 #if HAVE_GTK3 == 0
230     button_Export_Playlist = gtk_button_new_from_stock(GTK_STOCK_SAVE_AS);
231 #else
232     button_Export_Playlist = gtk_button_new_with_label(_("Save"));
233 #endif
234     gtk_widget_show(button_Export_Playlist);
235     gtk_box_pack_start(GTK_BOX(hbox1), button_Export_Playlist, FALSE, FALSE, 0);
236     gtk_container_set_border_width(GTK_CONTAINER(button_Export_Playlist), 5);
237 #if HAVE_GTK3 == 0
238     gtk_tooltips_set_tip(tooltips, button_Export_Playlist, _("Export Playlist"), NULL);
239 #else
240     gtk_widget_set_tooltip_text(button_Export_Playlist, _("Export Playlist"));
241 #endif
242 
243     // Scrolled Window.
244 #if HAVE_GTK3 == 0
245     hbox4 = gtk_hbox_new(FALSE, 5);
246 #else
247     hbox4 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
248 #endif
249     gtk_widget_show(hbox4);
250     gtk_box_pack_start(GTK_BOX(vbox1), hbox4, TRUE, TRUE, 0);
251 
252     scrolledwindow2 = gtk_scrolled_window_new(NULL, NULL);
253     gtk_widget_show(scrolledwindow2);
254     gtk_box_pack_start(GTK_BOX(hbox4), scrolledwindow2, TRUE, TRUE, 0);
255     gtk_container_set_border_width(GTK_CONTAINER(scrolledwindow2), 5);
256 
257     treeview_Avail_Files = gtk_tree_view_new();
258     gtk_widget_show(treeview_Avail_Files);
259     gtk_container_add(GTK_CONTAINER(scrolledwindow2), treeview_Avail_Files);
260     gtk_container_set_border_width(GTK_CONTAINER(treeview_Avail_Files), 5);
261 #if HAVE_GTK3 == 0
262     gtk_tooltips_set_tip(tooltips, treeview_Avail_Files, _("Device Audio Tracks"), NULL);
263 #else
264     gtk_widget_set_tooltip_text(treeview_Avail_Files, _("Device Audio Tracks"));
265 #endif
266 
267     playlist_TrackSelection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview_Avail_Files));
268     gtk_tree_selection_set_mode(playlist_TrackSelection, GTK_SELECTION_MULTIPLE);
269 
270     playlist_TrackList = gtk_list_store_new(NUM_TCOLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING);
271     setupTrackList(GTK_TREE_VIEW(treeview_Avail_Files));
272     gtk_tree_view_set_model(GTK_TREE_VIEW(treeview_Avail_Files), GTK_TREE_MODEL(playlist_TrackList));
273     g_object_unref(playlist_TrackList);
274 #if HAVE_GTK3 == 0
275     vbuttonbox1 = gtk_vbutton_box_new();
276 #else
277     vbuttonbox1 = gtk_button_box_new(GTK_ORIENTATION_VERTICAL);
278 #endif
279     gtk_widget_show(vbuttonbox1);
280     gtk_box_pack_start(GTK_BOX(hbox4), vbuttonbox1, FALSE, FALSE, 0);
281     gtk_button_box_set_layout(GTK_BUTTON_BOX(vbuttonbox1), GTK_BUTTONBOX_SPREAD);
282 
283     button_Add_Files = gtk_button_new();
284     gtk_widget_show(button_Add_Files);
285     gtk_container_add(GTK_CONTAINER(vbuttonbox1), button_Add_Files);
286 #if HAVE_GTK3 == 0
287     gtk_tooltips_set_tip(tooltips, button_Add_Files, _("Add file to playlist"), NULL);
288 #else
289     gtk_widget_set_tooltip_text(button_Add_Files, _("Add file to playlist"));
290 #endif
291 
292     //    alignment6 = gtk_alignment_new(0.5, 0.5, 0, 0);
293     //    gtk_widget_show(alignment6);
294     //    gtk_container_add(GTK_CONTAINER(button_Add_Files), alignment6);
295 #if HAVE_GTK3 == 0
296     hbox8 = gtk_hbox_new(FALSE, 2);
297 #else
298     hbox8 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2);
299 #endif
300     gtk_widget_show(hbox8);
301     gtk_container_add(GTK_CONTAINER(button_Add_Files), hbox8);
302 #if HAVE_GTK3 == 0
303     image6 = gtk_image_new_from_stock(GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_BUTTON);
304 #else
305     image6 = gtk_image_new_from_icon_name("go-next", GTK_ICON_SIZE_BUTTON);
306 #endif
307     gtk_widget_show(image6);
308     gtk_box_pack_start(GTK_BOX(hbox8), image6, FALSE, FALSE, 0);
309 
310     label10 = gtk_label_new_with_mnemonic(_("Add File"));
311     gtk_widget_show(label10);
312     gtk_box_pack_start(GTK_BOX(hbox8), label10, FALSE, FALSE, 0);
313 
314     button_Del_File = gtk_button_new();
315     gtk_widget_show(button_Del_File);
316     gtk_container_add(GTK_CONTAINER(vbuttonbox1), button_Del_File);
317 #if HAVE_GTK3 == 0
318     gtk_tooltips_set_tip(tooltips, button_Del_File, _("Remove file from playlist"), NULL);
319 #else
320     gtk_widget_set_tooltip_text(button_Del_File, _("Remove file from playlist"));
321 #endif
322 
323     //    alignment7 = gtk_alignment_new(0.5, 0.5, 0, 0);
324     //    gtk_widget_show(alignment7);
325     //    gtk_container_add(GTK_CONTAINER(button_Del_File), alignment7);
326 #if HAVE_GTK3 == 0
327     hbox9 = gtk_hbox_new(FALSE, 2);
328 #else
329     hbox9 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2);
330 #endif
331     gtk_widget_show(hbox9);
332     gtk_container_add(GTK_CONTAINER(button_Del_File), hbox9);
333 #if HAVE_GTK3 == 0
334     image7 = gtk_image_new_from_stock(GTK_STOCK_GO_BACK, GTK_ICON_SIZE_BUTTON);
335 #else
336     image7 = gtk_image_new_from_icon_name("go-previous", GTK_ICON_SIZE_BUTTON);
337 #endif
338     gtk_widget_show(image7);
339     gtk_box_pack_start(GTK_BOX(hbox9), image7, FALSE, FALSE, 0);
340 
341     label11 = gtk_label_new_with_mnemonic(_("Del File"));
342     gtk_widget_show(label11);
343     gtk_box_pack_start(GTK_BOX(hbox9), label11, FALSE, FALSE, 0);
344 
345     scrolledwindow3 = gtk_scrolled_window_new(NULL, NULL);
346     gtk_widget_show(scrolledwindow3);
347     gtk_box_pack_start(GTK_BOX(hbox4), scrolledwindow3, TRUE, TRUE, 0);
348     gtk_container_set_border_width(GTK_CONTAINER(scrolledwindow3), 5);
349 
350     treeview_Playlist_Files = gtk_tree_view_new();
351     gtk_widget_show(treeview_Playlist_Files);
352     gtk_container_add(GTK_CONTAINER(scrolledwindow3), treeview_Playlist_Files);
353     gtk_container_set_border_width(GTK_CONTAINER(treeview_Playlist_Files), 5);
354 #if HAVE_GTK3 == 0
355     gtk_tooltips_set_tip(tooltips, treeview_Playlist_Files, _("Playlist Audio Tracks"), NULL);
356 #else
357     gtk_widget_set_tooltip_text(treeview_Playlist_Files, _("Playlist Audio Tracks"));
358 #endif
359 
360     playlist_PL_Selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview_Playlist_Files));
361     gtk_tree_selection_set_mode(playlist_PL_Selection, GTK_SELECTION_MULTIPLE);
362 
363     playlist_PL_List = gtk_list_store_new(NUM_PL_COLUMNS, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING);
364     setup_PL_List(GTK_TREE_VIEW(treeview_Playlist_Files));
365     gtk_tree_view_set_model(GTK_TREE_VIEW(treeview_Playlist_Files), GTK_TREE_MODEL(playlist_PL_List));
366     g_object_unref(playlist_PL_List);
367 #if HAVE_GTK3 == 0
368     vbuttonbox2 = gtk_vbutton_box_new();
369 #else
370     vbuttonbox2 = gtk_button_box_new(GTK_ORIENTATION_VERTICAL);
371 #endif
372     gtk_widget_show(vbuttonbox2);
373     gtk_box_pack_start(GTK_BOX(hbox4), vbuttonbox2, FALSE, FALSE, 5);
374     gtk_button_box_set_layout(GTK_BUTTON_BOX(vbuttonbox2), GTK_BUTTONBOX_SPREAD);
375 #if HAVE_GTK3 == 0
376     button_File_Move_Up = gtk_button_new_from_stock(GTK_STOCK_GO_UP);
377 #else
378 #if GTK_CHECK_VERSION(3,10,0)
379     button_File_Move_Up = gtk_button_new_from_icon_name("go-up", GTK_ICON_SIZE_BUTTON);
380 #else
381     button_File_Move_Up = gtk_button_new_from_stock(GTK_STOCK_GO_UP);
382 #endif
383 #endif
384     gtk_widget_show(button_File_Move_Up);
385     gtk_container_add(GTK_CONTAINER(vbuttonbox2), button_File_Move_Up);
386 #if HAVE_GTK3 == 0
387     gtk_tooltips_set_tip(tooltips, button_File_Move_Up, _("Move selected file up in the playlist"), NULL);
388 #else
389     gtk_widget_set_tooltip_text(button_File_Move_Up, _("Move selected file up in the playlist"));
390 #endif
391 
392 #if HAVE_GTK3 == 0
393     button_File_Move_Down = gtk_button_new_from_stock(GTK_STOCK_GO_DOWN);
394 #else
395 #if GTK_CHECK_VERSION(3,10,0)
396     button_File_Move_Down = gtk_button_new_from_icon_name("go-down", GTK_ICON_SIZE_BUTTON);
397 #else
398     button_File_Move_Down = gtk_button_new_from_stock(GTK_STOCK_GO_DOWN);
399 #endif
400 #endif
401     gtk_widget_show(button_File_Move_Down);
402     gtk_container_add(GTK_CONTAINER(vbuttonbox2), button_File_Move_Down);
403 #if HAVE_GTK3 == 0
404     gtk_tooltips_set_tip(tooltips, button_File_Move_Down, _("Move selected file down in the playlist"), NULL);
405 #else
406     gtk_widget_set_tooltip_text(button_File_Move_Down, _("Move selected file down in the playlist"));
407 #endif
408 #if HAVE_GTK3 == 0
409     hbuttonbox1 = gtk_hbutton_box_new();
410 #else
411     hbuttonbox1 = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
412 #endif
413     gtk_widget_show(hbuttonbox1);
414     gtk_box_pack_start(GTK_BOX(vbox1), hbuttonbox1, FALSE, FALSE, 5);
415     gtk_button_box_set_layout(GTK_BUTTON_BOX(hbuttonbox1), GTK_BUTTONBOX_END);
416 #if HAVE_GTK3 == 0
417     button_Close = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
418 #else
419     button_Close = gtk_button_new_with_label(_("Close"));
420 #endif
421     gtk_widget_show(button_Close);
422     gtk_container_add(GTK_CONTAINER(hbuttonbox1), button_Close);
423     gtk_container_set_border_width(GTK_CONTAINER(button_Close), 5);
424 
425     g_signal_connect((gpointer) window_playlist, "destroy",
426             G_CALLBACK(on_quitPlaylist_activate),
427             NULL);
428 
429     g_signal_connect((gpointer) button_Close, "clicked",
430             G_CALLBACK(on_quitPlaylist_activate),
431             NULL);
432 
433     g_signal_connect((gpointer) button_Add_Playlist, "clicked",
434             G_CALLBACK(on_Playlist_NewPlaylistButton_activate),
435             NULL);
436 
437     g_signal_connect((gpointer) button_Import_Playlist, "clicked",
438             G_CALLBACK(on_Playlist_ImportPlaylistButton_activate),
439             NULL);
440 
441     g_signal_connect((gpointer) button_Export_Playlist, "clicked",
442             G_CALLBACK(on_Playlist_ExportPlaylistButton_activate),
443             NULL);
444 
445     g_signal_connect((gpointer) button_Del_Playlist, "clicked",
446             G_CALLBACK(on_Playlist_DelPlaylistButton_activate),
447             NULL);
448 
449     g_signal_connect((gpointer) button_Del_File, "clicked",
450             G_CALLBACK(on_Playlist_DelFileButton_activate),
451             NULL);
452 
453     g_signal_connect((gpointer) button_Add_Files, "clicked",
454             G_CALLBACK(on_Playlist_AddFileButton_activate),
455             NULL);
456 
457     g_signal_connect((gpointer) button_File_Move_Up, "clicked",
458             G_CALLBACK(on_Playlist_FileUpButton_activate),
459             NULL);
460 
461     g_signal_connect((gpointer) button_File_Move_Down, "clicked",
462             G_CALLBACK(on_Playlist_FileDownButton_activate),
463             NULL);
464 
465     g_signal_connect((gpointer) comboboxentry_playlist, "changed",
466             G_CALLBACK(on_Playlist_Combobox_activate),
467             NULL);
468 
469     return window_playlist;
470 }
471 
472 // ************************************************************************************************
473 
on_editPlaylist_activate(GtkWidget * item,gpointer user_data)474 void on_editPlaylist_activate(GtkWidget *item, gpointer user_data) {
475     UNUSED(item);
476     UNUSED(user_data);
477     displayPlaylistDialog();
478 } // end on_editPlaylist_activate()
479 
480 // ************************************************************************************************
481 
on_fileAddToPlaylist_activate(GtkWidget * item,gpointer user_data)482 void on_fileAddToPlaylist_activate(GtkWidget *item, gpointer user_data) {
483     UNUSED(item);
484     UNUSED(user_data);
485     // Let's check to see if we have anything selected in our treeview?
486     if (fileListGetSelection() == NULL) {
487         displayInformation(_("No files/folders selected?"));
488         return;
489     }
490     // Display the select playlist dialog;
491     int32_t addTrackPlaylistID = displayAddTrackPlaylistDialog(TRUE);
492 
493     // Now add the actual files from the MTP device.
494     if (addTrackPlaylistID != GMTP_NO_PLAYLIST) {
495         fileListAddToPlaylist(fileListGetSelection(), addTrackPlaylistID);
496     }
497 }
498 
499 // ************************************************************************************************
500 
on_fileRemoveFromPlaylist_activate(GtkWidget * item,gpointer user_data)501 void on_fileRemoveFromPlaylist_activate(GtkWidget *item, gpointer user_data) {
502     UNUSED(item);
503     UNUSED(user_data);
504     // Let's check to see if we have anything selected in our treeview?
505     if (fileListGetSelection() == NULL) {
506         displayInformation(_("No files/folders selected?"));
507         return;
508     }
509     // Display the select playlist dialog;
510     int32_t addTrackPlaylistID = displayAddTrackPlaylistDialog(FALSE);
511 
512     // Now remove the actual files from the MTP device.
513     if (addTrackPlaylistID != GMTP_NO_PLAYLIST) {
514         fileListRemoveFromPlaylist(fileListGetSelection(), addTrackPlaylistID);
515     }
516 }
517 
518 // ************************************************************************************************
519 
fileListRemoveFromPlaylist(GList * List,uint32_t PlaylistID)520 gboolean fileListRemoveFromPlaylist(GList *List, uint32_t PlaylistID) {
521     LIBMTP_playlist_t *playlist = NULL;
522     LIBMTP_playlist_t *node = NULL;
523 
524     node = devicePlayLists;
525     while (node != NULL) {
526         if (node->playlist_id == PlaylistID) {
527             playlist = node;
528             node = NULL;
529         } else {
530             node = node->next;
531         }
532     }
533     if (playlist != NULL) {
534         g_list_foreach(List, (GFunc) __fileRemoveFromPlaylist, (gpointer) & playlist);
535     }
536     return TRUE;
537 }
538 
539 // ************************************************************************************************
540 
__fileAddToPlaylist(GtkTreeRowReference * Row,LIBMTP_playlist_t ** playlist)541 void __fileAddToPlaylist(GtkTreeRowReference *Row, LIBMTP_playlist_t **playlist) {
542     GtkTreePath *path;
543     GtkTreeIter iter;
544     uint32_t objectID;
545     gboolean isFolder;
546     LIBMTP_track_t *tracks = deviceTracks;
547     // convert the referenece to a path and retrieve the iterator;
548     path = gtk_tree_row_reference_get_path(Row);
549     gtk_tree_model_get_iter(GTK_TREE_MODEL(fileList), &iter, path);
550     // We have our Iter now.
551     gtk_tree_model_get(GTK_TREE_MODEL(fileList), &iter, COL_ISFOLDER, &isFolder, COL_FILEID, &objectID, -1);
552     if (isFolder == FALSE) {
553         // Now add the file to the playlist.
554          LIBMTP_track_t *node = NULL;
555         // We need the playlist pointer, and the **track** pointer;
556         while (tracks != NULL) {
557             if (tracks->item_id == objectID) {
558                 node = tracks;
559                 tracks = NULL;
560             } else {
561                 tracks = tracks->next;
562             }
563         }
564         if (node != NULL) {
565             playlistAddTrack(*(playlist), node);
566         }
567     }
568     gtk_tree_path_free(path);
569 }
570 
571 // ************************************************************************************************
572 
__fileRemoveFromPlaylist(GtkTreeRowReference * Row,LIBMTP_playlist_t ** playlist)573 void __fileRemoveFromPlaylist(GtkTreeRowReference *Row, LIBMTP_playlist_t **playlist) {
574     GtkTreePath *path;
575     GtkTreeIter iter;
576     uint32_t objectID;
577     gboolean isFolder;
578     LIBMTP_track_t *tracks = deviceTracks;
579 
580     // convert the referenece to a path and retrieve the iterator;
581     path = gtk_tree_row_reference_get_path(Row);
582     gtk_tree_model_get_iter(GTK_TREE_MODEL(fileList), &iter, path);
583     // We have our Iter now.
584     gtk_tree_model_get(GTK_TREE_MODEL(fileList), &iter, COL_ISFOLDER, &isFolder, COL_FILEID, &objectID, -1);
585     if (isFolder == FALSE) {
586         // Now add the file to the playlist.
587         LIBMTP_track_t *node = NULL;
588         // We need the playlist pointer, and the **track** pointer;
589         while (tracks != NULL) {
590             if (tracks->item_id == objectID) {
591                 node = tracks;
592                 tracks = NULL;
593             } else {
594                 tracks = tracks->next;
595             }
596         }
597         if (node != NULL) {
598             playlistRemoveTrack(*(playlist), node, MTP_PLAYLIST_FIRST_INSTANCE);
599         }
600     }
601     gtk_tree_path_free(path);
602 }
603 
604 // ************************************************************************************************
605 
displayPlaylistDialog(void)606 void displayPlaylistDialog(void) {
607     //LIBMTP_playlist_t* tmpplaylist;
608     LIBMTP_track_t* tmptrack;
609     GtkTreeIter rowIter;
610     //gchar * tmp_string;
611 
612     if (windowPlaylistDialog != NULL) {
613         gtk_widget_hide(windowPlaylistDialog);
614         gtk_widget_destroy(windowPlaylistDialog);
615     }
616     windowPlaylistDialog = create_windowPlaylist();
617     playlist_number = 0;
618     // Clear the track and playlist lists;
619     gtk_list_store_clear(GTK_LIST_STORE(playlist_PL_List));
620     gtk_list_store_clear(GTK_LIST_STORE(playlist_TrackList));
621     // Populate the playlist changebox.
622     devicePlayLists = getPlaylists();
623     deviceTracks = getTracks();
624     setPlayListComboBox();
625 
626     // Populate the available track list.
627     if (deviceTracks != NULL) {
628         // Populate the track list;
629         tmptrack = deviceTracks;
630         while (tmptrack != NULL) {
631             if ((tmptrack->storage_id == DeviceMgr.devicestorage->id) && (LIBMTP_FILETYPE_IS_AUDIO(tmptrack->filetype))) {
632                 gtk_list_store_append(GTK_LIST_STORE(playlist_TrackList), &rowIter);
633                 gchar * tmp_string = g_strdup_printf("%d:%.2d", (int) ((tmptrack->duration / 1000) / 60), (int) ((tmptrack->duration / 1000) % 60));
634                 gtk_list_store_set(GTK_LIST_STORE(playlist_TrackList), &rowIter, COL_ARTIST, tmptrack->artist, COL_ALBUM, tmptrack->album,
635                         COL_TRACKID, tmptrack->item_id, COL_TRACKNAME, tmptrack->title, COL_TRACKDURATION, tmp_string, -1);
636                 g_free(tmp_string);
637                 tmp_string = NULL;
638             }
639             tmptrack = tmptrack->next;
640         }
641     }
642     gtk_widget_show(GTK_WIDGET(windowPlaylistDialog));
643     // Save the current selected playlist if needed.
644 }
645 
646 // ************************************************************************************************
647 
setupTrackList(GtkTreeView * treeviewFiles)648 void setupTrackList(GtkTreeView *treeviewFiles) {
649     GtkCellRenderer *renderer;
650     GtkTreeViewColumn *column;
651 
652     // Artist
653     renderer = gtk_cell_renderer_text_new();
654     column = gtk_tree_view_column_new_with_attributes(_("Artist"), renderer,
655             "text", COL_ARTIST,
656             NULL);
657     gtk_tree_view_append_column(GTK_TREE_VIEW(treeviewFiles), column);
658     gtk_tree_view_column_set_sort_column_id(column, COL_ARTIST);
659     gtk_tree_view_column_set_resizable(column, TRUE);
660     gtk_tree_view_column_set_spacing(column, 5);
661 
662     // Album column
663     renderer = gtk_cell_renderer_text_new();
664     column = gtk_tree_view_column_new_with_attributes(_("Album"), renderer,
665             "text", COL_ALBUM,
666             NULL);
667     gtk_tree_view_append_column(GTK_TREE_VIEW(treeviewFiles), column);
668     gtk_tree_view_column_set_sort_column_id(column, COL_ALBUM);
669     gtk_tree_view_column_set_resizable(column, TRUE);
670     gtk_tree_view_column_set_spacing(column, 5);
671 
672     // Folder/FileID column
673     renderer = gtk_cell_renderer_text_new();
674     column = gtk_tree_view_column_new_with_attributes("Object ID", renderer,
675             "text", COL_TRACKID,
676             NULL);
677     gtk_tree_view_append_column(GTK_TREE_VIEW(treeviewFiles), column);
678     gtk_tree_view_column_set_visible(column, FALSE);
679 
680     // Track column
681     renderer = gtk_cell_renderer_text_new();
682     column = gtk_tree_view_column_new_with_attributes(_("Track"), renderer,
683             "text", COL_TRACKNAME,
684             NULL);
685     gtk_tree_view_append_column(GTK_TREE_VIEW(treeviewFiles), column);
686     gtk_tree_view_column_set_sort_column_id(column, COL_TRACKNAME);
687     gtk_tree_view_column_set_resizable(column, TRUE);
688     gtk_tree_view_column_set_visible(column, TRUE);
689 
690     // Track Duration
691     renderer = gtk_cell_renderer_text_new();
692     column = gtk_tree_view_column_new_with_attributes(_("Duration"), renderer,
693             "text", COL_TRACKDURATION,
694             NULL);
695     gtk_tree_view_append_column(GTK_TREE_VIEW(treeviewFiles), column);
696     gtk_tree_view_column_set_resizable(column, TRUE);
697     gtk_tree_view_column_set_visible(column, TRUE);
698 }
699 
700 // ************************************************************************************************
701 
setup_PL_List(GtkTreeView * treeviewFiles)702 void setup_PL_List(GtkTreeView *treeviewFiles) {
703     GtkCellRenderer *renderer;
704     GtkTreeViewColumn *column;
705 
706     // Order Num
707     renderer = gtk_cell_renderer_text_new();
708     column = gtk_tree_view_column_new_with_attributes(_("Num"), renderer,
709             "text", COL_PL_ORDER_NUM,
710             NULL);
711     gtk_tree_view_append_column(GTK_TREE_VIEW(treeviewFiles), column);
712     //gtk_tree_view_column_set_sort_column_id(column, COL_PL_ORDER_NUM);
713     gtk_tree_view_column_set_resizable(column, TRUE);
714     gtk_tree_view_column_set_spacing(column, 5);
715 
716     // Artist
717     renderer = gtk_cell_renderer_text_new();
718     column = gtk_tree_view_column_new_with_attributes(_("Artist"), renderer,
719             "text", COL_PL_ARTIST,
720             NULL);
721     gtk_tree_view_append_column(GTK_TREE_VIEW(treeviewFiles), column);
722     //gtk_tree_view_column_set_sort_column_id(column, COL_PL_ARTIST);
723     gtk_tree_view_column_set_resizable(column, TRUE);
724     gtk_tree_view_column_set_spacing(column, 5);
725 
726     // Album column
727     renderer = gtk_cell_renderer_text_new();
728     column = gtk_tree_view_column_new_with_attributes(_("Album"), renderer,
729             "text", COL_PL_ALBUM,
730             NULL);
731     gtk_tree_view_append_column(GTK_TREE_VIEW(treeviewFiles), column);
732     //gtk_tree_view_column_set_sort_column_id(column, COL_PL_ALBUM);
733     gtk_tree_view_column_set_resizable(column, TRUE);
734     gtk_tree_view_column_set_spacing(column, 5);
735 
736     // Folder/FileID column
737     renderer = gtk_cell_renderer_text_new();
738     column = gtk_tree_view_column_new_with_attributes("Object ID", renderer,
739             "text", COL_PL_TRACKID,
740             NULL);
741     gtk_tree_view_append_column(GTK_TREE_VIEW(treeviewFiles), column);
742     gtk_tree_view_column_set_visible(column, FALSE);
743 
744     // Track column
745     renderer = gtk_cell_renderer_text_new();
746     column = gtk_tree_view_column_new_with_attributes(_("Track"), renderer,
747             "text", COL_PL_TRACKNAME,
748             NULL);
749     gtk_tree_view_append_column(GTK_TREE_VIEW(treeviewFiles), column);
750     //gtk_tree_view_column_set_sort_column_id(column, COL_TRACKNAME);
751     gtk_tree_view_column_set_resizable(column, TRUE);
752     gtk_tree_view_column_set_visible(column, TRUE);
753 
754     // Track Duration
755     renderer = gtk_cell_renderer_text_new();
756     column = gtk_tree_view_column_new_with_attributes(_("Duration"), renderer,
757             "text", COL_PL_TRACKDURATION,
758             NULL);
759     gtk_tree_view_append_column(GTK_TREE_VIEW(treeviewFiles), column);
760     gtk_tree_view_column_set_resizable(column, TRUE);
761     gtk_tree_view_column_set_visible(column, TRUE);
762 }
763 
764 // ************************************************************************************************
765 
SetPlaylistButtonState(gboolean state)766 void SetPlaylistButtonState(gboolean state) {
767     gtk_widget_set_sensitive(GTK_WIDGET(button_Del_Playlist), state);
768     gtk_widget_set_sensitive(GTK_WIDGET(button_Export_Playlist), state);
769     gtk_widget_set_sensitive(GTK_WIDGET(button_File_Move_Up), state);
770     gtk_widget_set_sensitive(GTK_WIDGET(button_File_Move_Down), state);
771     gtk_widget_set_sensitive(GTK_WIDGET(button_Del_File), state);
772     gtk_widget_set_sensitive(GTK_WIDGET(button_Add_Files), state);
773     gtk_widget_set_sensitive(GTK_WIDGET(treeview_Avail_Files), state);
774     gtk_widget_set_sensitive(GTK_WIDGET(treeview_Playlist_Files), state);
775 }
776 
777 // ************************************************************************************************
778 
setPlayListComboBox(void)779 void setPlayListComboBox(void) {
780     LIBMTP_playlist_t* tmpplaylist = NULL;
781 
782     // We need to remove all entries in the combo box before starting.
783     // This is a little bit of a hack - but does work.
784     runPlaylistHandler = FALSE; // disable the handler from running on the control.
785     // For some reason the "changed" event is triggered on a remove_all operation.
786 #if HAVE_GTK3 == 0
787     //gtk_list_store_clear(GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(comboboxentry_playlist))));
788     while (comboboxentry_playlist_entries-- > 0) {
789         gtk_combo_box_remove_text(GTK_COMBO_BOX(comboboxentry_playlist), 0);
790     }
791 #else
792     gtk_combo_box_text_remove_all(GTK_COMBO_BOX_TEXT(comboboxentry_playlist));
793 #endif
794     comboboxentry_playlist_entries = 0;
795 
796     if (devicePlayLists != NULL) {
797         // Populate the playlist dropdown box;
798         //comboboxentry_playlist;
799         tmpplaylist = devicePlayLists;
800         while (tmpplaylist != NULL) {
801             if (tmpplaylist->storage_id == DeviceMgr.devicestorage->id) {
802 #if HAVE_GTK3 == 0
803                 gtk_combo_box_append_text(GTK_COMBO_BOX(comboboxentry_playlist), (tmpplaylist->name));
804 #else
805                 //gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(comboboxentry_playlist), g_strdup(tmpplaylist->name));
806                 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(comboboxentry_playlist), (tmpplaylist->name));
807 #endif
808                 comboboxentry_playlist_entries++;
809             }
810             tmpplaylist = tmpplaylist->next;
811         }
812     }
813     if (devicePlayLists != NULL) {
814         // Set our playlist to the first one.
815         gtk_combo_box_set_active(GTK_COMBO_BOX(comboboxentry_playlist), 0);
816         playlist_number = 0;
817         // Now populate the playlist screen with it's details.
818         setPlaylistField(0);
819     } else {
820         playlist_number = -1;
821     }
822     // If no playlists set parts of dialog to disabled.
823     if (devicePlayLists == NULL) {
824         SetPlaylistButtonState(FALSE);
825     } else {
826         SetPlaylistButtonState(TRUE);
827     }
828     runPlaylistHandler = TRUE;
829 }
830 
831 // ************************************************************************************************
832 
setPlaylistField(gint PlayListID)833 void setPlaylistField(gint PlayListID) {
834     // This function will populate the playlist_PL_List widget with the
835     // details of the selected playlist.
836     LIBMTP_playlist_t* tmpplaylist = devicePlayLists;
837     gint tmpplaylistID = PlayListID;
838     guint trackID = 0;
839     GtkTreeIter rowIter;
840     gchar * tmp_string = NULL;
841 
842     playlist_track_count = 0;
843 
844     gtk_list_store_clear(GTK_LIST_STORE(playlist_PL_List));
845 
846     if (PlayListID > 0) {
847         while (tmpplaylistID--)
848             if (tmpplaylist->next != NULL)
849                 tmpplaylist = tmpplaylist->next;
850     }
851     // tmpplaylist points to our playlist;
852     for (trackID = 0; trackID < tmpplaylist->no_tracks; trackID++) {
853         LIBMTP_track_t *trackinfo;
854         trackinfo = LIBMTP_Get_Trackmetadata(DeviceMgr.device, tmpplaylist->tracks[trackID]);
855         if (trackinfo != NULL) {
856             playlist_track_count++;
857             gtk_list_store_append(GTK_LIST_STORE(playlist_PL_List), &rowIter);
858             tmp_string = g_strdup_printf("%d:%.2d", (int) ((trackinfo->duration / 1000) / 60), (int) ((trackinfo->duration / 1000) % 60));
859             gtk_list_store_set(GTK_LIST_STORE(playlist_PL_List), &rowIter, COL_PL_ORDER_NUM, playlist_track_count,
860                     COL_PL_ARTIST, trackinfo->artist,
861                     COL_PL_ALBUM, trackinfo->album, COL_PL_TRACKID, trackinfo->item_id,
862                     COL_PL_TRACKNAME, trackinfo->title, COL_PL_TRACKDURATION, tmp_string, -1);
863             g_free(tmp_string);
864             tmp_string = NULL;
865 
866             LIBMTP_destroy_track_t(trackinfo);
867         } else {
868             LIBMTP_Dump_Errorstack(DeviceMgr.device);
869             LIBMTP_Clear_Errorstack(DeviceMgr.device);
870         }
871     }
872 }
873 
874 // ************************************************************************************************
875 
displayPlaylistNewDialog(void)876 gchar* displayPlaylistNewDialog(void) {
877     GtkWidget *dialog, *hbox, *label, *textbox;
878 
879     dialog = gtk_dialog_new_with_buttons(_("New Playlist"), GTK_WINDOW(windowMain),
880             (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
881             _("_OK"), GTK_RESPONSE_OK,
882             _("_Cancel"), GTK_RESPONSE_CANCEL,
883             NULL);
884 
885     gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
886     gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
887     gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
888 
889 #if HAVE_GTK3 == 0
890     hbox = gtk_hbox_new(FALSE, 5);
891 #else
892     hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
893 #endif
894     gtk_widget_show(hbox);
895 
896 #if HAVE_GTK3 == 0
897     gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
898 #else
899     gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), hbox);
900 #endif
901 
902     label = gtk_label_new(_("Playlist Name:"));
903     gtk_widget_show(label);
904     gtk_container_add(GTK_CONTAINER(hbox), label);
905 
906     textbox = gtk_entry_new();
907     gtk_widget_show(textbox);
908     gtk_entry_set_max_length(GTK_ENTRY(textbox), 64);
909     gtk_entry_set_has_frame(GTK_ENTRY(textbox), TRUE);
910     gtk_entry_set_activates_default(GTK_ENTRY(textbox), TRUE);
911     gtk_container_add(GTK_CONTAINER(hbox), textbox);
912 
913     gint result = gtk_dialog_run(GTK_DIALOG(dialog));
914     if (result == GTK_RESPONSE_OK) {
915         gchar* textfield = g_strdup(gtk_entry_get_text(GTK_ENTRY(textbox)));
916         if (strlen(textfield) == 0) {
917             // We have an emtpy string.
918             gtk_widget_destroy(dialog);
919             return NULL;
920         } else {
921             gtk_widget_destroy(dialog);
922             return textfield;
923         }
924     } else {
925         gtk_widget_destroy(dialog);
926         return NULL;
927     }
928 }
929 
930 // ************************************************************************************************
931 
playlist_PL_ListGetSelection()932 GList* playlist_PL_ListGetSelection() {
933     GList *selectedFiles, *ptr;
934     // Lets clear up the old list.
935     g_list_free(playlist_Selection_PL_RowReferences);
936     playlist_Selection_PL_RowReferences = NULL;
937 
938     if (gtk_tree_selection_count_selected_rows(playlist_PL_Selection) == 0) {
939         // We have no rows.
940         return NULL;
941     }
942     // So now we must convert each selection to a row reference and store it in a new GList variable
943     // which we will return below.
944     GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview_Playlist_Files));
945     selectedFiles = gtk_tree_selection_get_selected_rows(playlist_PL_Selection, &model);
946     ptr = selectedFiles;
947     while (ptr != NULL) {
948         GtkTreeRowReference *ref = gtk_tree_row_reference_new(GTK_TREE_MODEL(playlist_PL_List), (GtkTreePath*) ptr->data);
949         playlist_Selection_PL_RowReferences = g_list_append(playlist_Selection_PL_RowReferences, gtk_tree_row_reference_copy(ref));
950         gtk_tree_row_reference_free(ref);
951         ptr = ptr->next;
952     }
953     g_list_foreach(selectedFiles, (GFunc) gtk_tree_path_free, NULL);
954     g_list_free(selectedFiles);
955     return playlist_Selection_PL_RowReferences;
956 }
957 
958 // ************************************************************************************************
959 
playlist_PL_ListClearSelection()960 gboolean playlist_PL_ListClearSelection() {
961     if (playlist_PL_Selection != NULL)
962         gtk_tree_selection_unselect_all(playlist_PL_Selection);
963     return TRUE;
964 }
965 
966 // ************************************************************************************************
967 
playlist_PL_ListRemove(GList * List)968 gboolean playlist_PL_ListRemove(GList *List) {
969     GtkTreeIter iter;
970     gint tracknumber = 1;
971 
972     playlist_PL_ListClearSelection();
973     g_list_foreach(List, (GFunc) __playlist_PL_Remove, NULL);
974 
975     // Now reorder all tracks in this playlist.
976     if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(playlist_PL_List), &iter)) {
977         gtk_list_store_set(GTK_LIST_STORE(playlist_PL_List), &iter, COL_PL_ORDER_NUM, tracknumber, -1);
978         tracknumber++;
979         while (gtk_tree_model_iter_next(GTK_TREE_MODEL(playlist_PL_List), &iter)) {
980             gtk_list_store_set(GTK_LIST_STORE(playlist_PL_List), &iter, COL_PL_ORDER_NUM, tracknumber, -1);
981             tracknumber++;
982         }
983     }
984     return TRUE;
985 }
986 
987 // ************************************************************************************************
988 
__playlist_PL_Remove(GtkTreeRowReference * Row)989 void __playlist_PL_Remove(GtkTreeRowReference *Row) {
990     GtkTreePath *path;
991     GtkTreeIter iter;
992     // convert the referenece to a path and retrieve the iterator;
993     path = gtk_tree_row_reference_get_path(Row);
994     gtk_tree_model_get_iter(GTK_TREE_MODEL(playlist_PL_List), &iter, path);
995     // We have our Iter now.
996     gtk_list_store_remove(GTK_LIST_STORE(playlist_PL_List), &iter);
997     playlist_track_count--;
998     gtk_tree_path_free(path);
999 }
1000 
1001 // ************************************************************************************************
1002 
playlist_TrackList_GetSelection()1003 GList* playlist_TrackList_GetSelection() {
1004     GList *selectedFiles, *ptr;
1005     // Lets clear up the old list.
1006     g_list_free(playlist_Selection_TrackRowReferences);
1007     playlist_Selection_TrackRowReferences = NULL;
1008 
1009     if (gtk_tree_selection_count_selected_rows(playlist_TrackSelection) == 0) {
1010         // We have no rows.
1011         return NULL;
1012     }
1013     // So now we must convert each selection to a row reference and store it in a new GList variable
1014     // which we will return below.
1015     GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview_Avail_Files));
1016     selectedFiles = gtk_tree_selection_get_selected_rows(playlist_TrackSelection, &model);
1017     ptr = selectedFiles;
1018     while (ptr != NULL) {
1019         GtkTreeRowReference *ref = gtk_tree_row_reference_new(GTK_TREE_MODEL(playlist_TrackList), (GtkTreePath*) ptr->data);
1020         playlist_Selection_TrackRowReferences = g_list_append(playlist_Selection_TrackRowReferences, gtk_tree_row_reference_copy(ref));
1021         gtk_tree_row_reference_free(ref);
1022         ptr = ptr->next;
1023     }
1024     g_list_foreach(selectedFiles, (GFunc) gtk_tree_path_free, NULL);
1025     g_list_free(selectedFiles);
1026     return playlist_Selection_TrackRowReferences;
1027 }
1028 
1029 // ************************************************************************************************
1030 
playlist_TrackList_Add(GList * List)1031 gboolean playlist_TrackList_Add(GList *List) {
1032     g_list_foreach(List, (GFunc) __playlist_TrackList_Add, NULL);
1033     return TRUE;
1034 }
1035 
1036 // ************************************************************************************************
1037 
__playlist_TrackList_Add(GtkTreeRowReference * Row)1038 void __playlist_TrackList_Add(GtkTreeRowReference *Row) {
1039     GtkTreePath *path = NULL;
1040     GtkTreeIter iter;
1041     GtkTreeIter PL_rowIter;
1042     gchar* artist = NULL;
1043     gchar* album = NULL;
1044     gchar* title = NULL;
1045     gint item_id = 0;
1046     gchar * duration = NULL;
1047 
1048     // convert the referenece to a path and retrieve the iterator;
1049     path = gtk_tree_row_reference_get_path(Row);
1050     gtk_tree_model_get_iter(GTK_TREE_MODEL(playlist_TrackList), &iter, path);
1051     // We have our Iter now, so get the required information from the track treeview.
1052     gtk_tree_model_get(GTK_TREE_MODEL(playlist_TrackList), &iter, COL_ARTIST, &artist, COL_ALBUM, &album,
1053             COL_TRACKID, &item_id, COL_TRACKNAME, &title, COL_TRACKDURATION, & duration, -1);
1054     // Now store our information in the playlist treeview.
1055     playlist_track_count++;
1056     gtk_list_store_append(GTK_LIST_STORE(playlist_PL_List), &PL_rowIter);
1057     gtk_list_store_set(GTK_LIST_STORE(playlist_PL_List), &PL_rowIter, COL_PL_ORDER_NUM, playlist_track_count, COL_PL_ARTIST, artist,
1058             COL_PL_ALBUM, album, COL_PL_TRACKID, item_id, COL_PL_TRACKNAME, title, COL_PL_TRACKDURATION, duration, -1);
1059 
1060     //Need to free our string values
1061     g_free(artist);
1062     g_free(album);
1063     g_free(title);
1064     g_free(duration);
1065     gtk_tree_path_free(path);
1066 }
1067 
1068 // ************************************************************************************************
1069 
playlist_move_files(gint direction)1070 gboolean playlist_move_files(gint direction) {
1071     GList * playlist_files = NULL;
1072     GtkTreeIter iter;
1073     gint tracknumber = 1;
1074     // Get our files...
1075     playlist_files = playlist_PL_ListGetSelection();
1076     if (playlist_files == NULL)
1077         return FALSE;
1078 
1079     // If we are moving files down we need to reverse the rows references...
1080     if (direction == 1) {
1081         playlist_files = g_list_reverse(playlist_files);
1082         g_list_foreach(playlist_files, (GFunc) __playlist_move_files_down, NULL);
1083     } else {
1084         g_list_foreach(playlist_files, (GFunc) __playlist_move_files_up, NULL);
1085     }
1086     // Now reorder all tracks in this playlist.
1087     if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(playlist_PL_List), &iter)) {
1088         gtk_list_store_set(GTK_LIST_STORE(playlist_PL_List), &iter, COL_PL_ORDER_NUM, tracknumber, -1);
1089         tracknumber++;
1090         while (gtk_tree_model_iter_next(GTK_TREE_MODEL(playlist_PL_List), &iter)) {
1091             gtk_list_store_set(GTK_LIST_STORE(playlist_PL_List), &iter, COL_PL_ORDER_NUM, tracknumber, -1);
1092             tracknumber++;
1093         }
1094     }
1095     return TRUE;
1096 }
1097 
1098 // ************************************************************************************************
1099 
__playlist_move_files_up(GtkTreeRowReference * Row)1100 void __playlist_move_files_up(GtkTreeRowReference *Row) {
1101     GtkTreePath *path;
1102     GtkTreeIter iter;
1103     GtkTreeIter iter2;
1104     // convert the referenece to a path and retrieve the iterator;
1105     path = gtk_tree_row_reference_get_path(Row);
1106     gtk_tree_model_get_iter(GTK_TREE_MODEL(playlist_PL_List), &iter, path);
1107     // We have our Iter now.
1108     // Now get it's prev path and turn it into a iter
1109     if (gtk_tree_path_prev(path) == TRUE) {
1110         // we have a previous entry...
1111         gtk_tree_model_get_iter(GTK_TREE_MODEL(playlist_PL_List), &iter2, path);
1112         gtk_list_store_swap(GTK_LIST_STORE(playlist_PL_List), &iter, &iter2);
1113     }
1114     gtk_tree_path_free(path);
1115 }
1116 
1117 // ************************************************************************************************
1118 
__playlist_move_files_down(GtkTreeRowReference * Row)1119 void __playlist_move_files_down(GtkTreeRowReference *Row) {
1120     GtkTreePath *path;
1121     GtkTreeIter iter;
1122     GtkTreeIter iter2;
1123     // convert the referenece to a path and retrieve the iterator;
1124     path = gtk_tree_row_reference_get_path(Row);
1125     gtk_tree_model_get_iter(GTK_TREE_MODEL(playlist_PL_List), &iter, path);
1126     // We have our Iter now.
1127     iter2 = iter;
1128     if (gtk_tree_model_iter_next(GTK_TREE_MODEL(playlist_PL_List), &iter2) == TRUE) {
1129         // we have something to swap with...
1130         gtk_list_store_swap(GTK_LIST_STORE(playlist_PL_List), &iter, &iter2);
1131     }
1132     gtk_tree_path_free(path);
1133 }
1134 
1135 // ************************************************************************************************
1136 
playlist_SavePlaylist(gint PlayListID)1137 void playlist_SavePlaylist(gint PlayListID) {
1138     LIBMTP_playlist_t* tmpplaylist = devicePlayLists;
1139     gint tmpplaylistID = PlayListID;
1140     gint item_id = 0;
1141     GtkTreeIter iter;
1142     uint32_t *tmp = NULL;
1143 
1144     if (PlayListID > 0) {
1145         while (tmpplaylistID--)
1146             if (tmpplaylist->next != NULL)
1147                 tmpplaylist = tmpplaylist->next;
1148     }
1149     // tmpplaylist points to our playlist;
1150     // So all we need to do is - update our current structure with the new details
1151 
1152     if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(playlist_PL_List), &iter)) {
1153         gtk_tree_model_get(GTK_TREE_MODEL(playlist_PL_List), &iter, COL_PL_TRACKID, &item_id, -1);
1154         tmpplaylist->no_tracks = 1;
1155 
1156         // item_id = our track num... so append to tmpplaylist->tracks
1157         if ((tmp = g_realloc(tmpplaylist->tracks, sizeof (uint32_t) * (tmpplaylist->no_tracks))) == NULL) {
1158             g_fprintf(stderr, _("realloc in savePlayList failed\n"));
1159             displayError(_("Updating playlist failed? 'realloc in savePlayList'\n"));
1160             return;
1161         }
1162         tmpplaylist->tracks = tmp;
1163         tmpplaylist->tracks[(tmpplaylist->no_tracks - 1)] = item_id;
1164         //tmpplaylist->no_tracks++;
1165         while (gtk_tree_model_iter_next(GTK_TREE_MODEL(playlist_PL_List), &iter)) {
1166             gtk_tree_model_get(GTK_TREE_MODEL(playlist_PL_List), &iter, COL_PL_TRACKID, &item_id, -1);
1167             tmpplaylist->no_tracks++;
1168             // item_id = our track num... so append to tmpplaylist->tracks
1169             if ((tmp = g_realloc(tmpplaylist->tracks, sizeof (uint32_t) * (tmpplaylist->no_tracks))) == NULL) {
1170                 g_fprintf(stderr, _("realloc in savePlayList failed\n"));
1171                 displayError(_("Updating playlist failed? 'realloc in savePlayList'\n"));
1172                 return;
1173             }
1174             tmpplaylist->tracks = tmp;
1175             tmpplaylist->tracks[(tmpplaylist->no_tracks - 1)] = item_id;
1176             //tmpplaylist->no_tracks++;
1177 
1178         }
1179     }
1180     // get libmtp to save it.
1181     playlistUpdate(tmpplaylist);
1182     // Update our own metadata.
1183     devicePlayLists = getPlaylists();
1184 }
1185 
1186 // Playlist Callbacks.
1187 // ************************************************************************************************
1188 
on_quitPlaylist_activate(GtkWidget * item,gpointer user_data)1189 void on_quitPlaylist_activate(GtkWidget *item, gpointer user_data) {
1190     UNUSED(item);
1191     UNUSED(user_data);
1192     // Save our current selected playlist!
1193     if (devicePlayLists != NULL)
1194         playlist_SavePlaylist(playlist_number);
1195     // Kill our window
1196     gtk_widget_hide(windowPlaylistDialog);
1197     gtk_widget_destroy(windowPlaylistDialog);
1198     windowPlaylistDialog = NULL;
1199     // Do a device rescan to show the new playlists in the file window
1200     deviceRescan();
1201 } // end on_quitPlaylist_activate()
1202 
1203 // ************************************************************************************************
1204 
on_Playlist_NewPlaylistButton_activate(GtkWidget * item,gpointer user_data)1205 void on_Playlist_NewPlaylistButton_activate(GtkWidget *item, gpointer user_data) {
1206     UNUSED(item);
1207     UNUSED(user_data);
1208 
1209     // Save our current selected playlist!
1210     if (devicePlayLists != NULL)
1211         playlist_SavePlaylist(playlist_number);
1212 
1213     gchar *playlistname = displayPlaylistNewDialog();
1214     if (playlistname != NULL) {
1215         // Add in playlist to MTP device.
1216         playlistAdd(playlistname);
1217         // Refresh our playlist information.
1218         devicePlayLists = getPlaylists();
1219         gtk_list_store_clear(GTK_LIST_STORE(playlist_PL_List));
1220         // Add it to our combobox
1221 
1222 #if HAVE_GTK3 == 0
1223         gtk_combo_box_append_text(GTK_COMBO_BOX(comboboxentry_playlist), (playlistname));
1224 #else
1225         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(comboboxentry_playlist), (playlistname));
1226 #endif
1227         g_free(playlistname);
1228 
1229         // Set the active combobox item.
1230         comboboxentry_playlist_entries++;
1231         playlist_number = comboboxentry_playlist_entries - 1;
1232         gtk_combo_box_set_active(GTK_COMBO_BOX(comboboxentry_playlist), comboboxentry_playlist_entries - 1);
1233         SetPlaylistButtonState(TRUE);
1234         setPlaylistField(playlist_number);
1235     }
1236 } // end on_Playlist_NewPlaylistButton_activate()
1237 
1238 // ************************************************************************************************
1239 
on_Playlist_ImportPlaylistButton_activate(GtkWidget * item,gpointer user_data)1240 void on_Playlist_ImportPlaylistButton_activate(GtkWidget *item, gpointer user_data) {
1241     UNUSED(item);
1242     UNUSED(user_data);
1243     gchar *playlistfilename = NULL;
1244     GtkWidget *FileDialog;
1245     GtkFileFilter *OpenFormFilter, *OpenFormFilter2;
1246 
1247     // Save our current selected playlist!
1248     if (devicePlayLists != NULL)
1249         playlist_SavePlaylist(playlist_number);
1250 
1251     // Get our filename...
1252 
1253     FileDialog = gtk_file_chooser_dialog_new(_("Select Playlist to Import"),
1254             GTK_WINDOW(windowMain), GTK_FILE_CHOOSER_ACTION_OPEN,
1255             _("_Cancel"), GTK_RESPONSE_CANCEL,
1256             _("_Open"), GTK_RESPONSE_ACCEPT,
1257             NULL);
1258     gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(FileDialog), FALSE);
1259     OpenFormFilter = gtk_file_filter_new();
1260     gtk_file_filter_add_pattern(OpenFormFilter, "*.m3u");
1261     gtk_file_filter_set_name(OpenFormFilter, "m3u Playlists");
1262     gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(FileDialog), OpenFormFilter);
1263     OpenFormFilter2 = gtk_file_filter_new();
1264     gtk_file_filter_add_pattern(OpenFormFilter2, "*");
1265     gtk_file_filter_set_name(OpenFormFilter2, "All Files");
1266     gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(FileDialog), OpenFormFilter2);
1267 
1268     if (gtk_dialog_run(GTK_DIALOG(FileDialog)) == GTK_RESPONSE_ACCEPT) {
1269         playlistfilename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(FileDialog));
1270     }
1271 
1272     gtk_widget_hide(FileDialog);
1273     gtk_widget_destroy(FileDialog);
1274 
1275     if (playlistfilename != NULL) {
1276         // Add in playlist to MTP device.
1277         gchar *playlistname = playlistImport(playlistfilename);
1278 
1279         // If our name is NULL, then the import failed...
1280         if (playlistname != NULL) {
1281             // Refresh our playlist information.
1282             devicePlayLists = getPlaylists();
1283             gtk_list_store_clear(GTK_LIST_STORE(playlist_PL_List));
1284             // Add it to our combobox
1285 
1286 #if HAVE_GTK3 == 0
1287             gtk_combo_box_append_text(GTK_COMBO_BOX(comboboxentry_playlist), (playlistname));
1288 #else
1289             gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(comboboxentry_playlist), (playlistname));
1290 #endif
1291 
1292             // Set the active combobox item.
1293             comboboxentry_playlist_entries++;
1294             playlist_number = comboboxentry_playlist_entries - 1;
1295             gtk_combo_box_set_active(GTK_COMBO_BOX(comboboxentry_playlist), comboboxentry_playlist_entries - 1);
1296             SetPlaylistButtonState(TRUE);
1297             setPlaylistField(playlist_number);
1298 
1299             // Clean up fields.
1300             g_free(playlistname);
1301         } else {
1302             // Let the user know the import failed.
1303             g_fprintf(stderr, _("The playlist failed to import correctly.\n"));
1304             displayError(_("The playlist failed to import correctly.\n"));
1305         }
1306         // Clean up fields.
1307         g_free(playlistfilename);
1308     }
1309 } // end on_Playlist_ImportPlaylistButton_activate()
1310 
1311 // ************************************************************************************************
1312 
on_Playlist_ExportPlaylistButton_activate(GtkWidget * item,gpointer user_data)1313 void on_Playlist_ExportPlaylistButton_activate(GtkWidget *item, gpointer user_data) {
1314     UNUSED(item);
1315     UNUSED(user_data);
1316 
1317     // Save our current selected playlist!
1318     if (devicePlayLists != NULL)
1319         playlist_SavePlaylist(playlist_number);
1320 
1321     gint PlayListID = gtk_combo_box_get_active(GTK_COMBO_BOX(comboboxentry_playlist));
1322 
1323     if (PlayListID != -1) {
1324         // We have something selected so lets do the dance.
1325         LIBMTP_playlist_t* tmpplaylist = devicePlayLists;
1326         if (PlayListID > 0) {
1327             while (PlayListID--)
1328                 if (tmpplaylist->next != NULL)
1329                     tmpplaylist = tmpplaylist->next;
1330         }
1331         // We should be in the correct playlist LIBMTP structure.
1332 
1333         gchar *playlistfilename = g_strdup_printf("%s.%s", tmpplaylist->name, "m3u");
1334 
1335         GtkWidget *FileDialog = gtk_file_chooser_dialog_new(_("Save as..."),
1336                 GTK_WINDOW(windowMain), GTK_FILE_CHOOSER_ACTION_SAVE,
1337                 _("_Cancel"), GTK_RESPONSE_CANCEL,
1338                 _("_Open"), GTK_RESPONSE_ACCEPT,
1339                 NULL);
1340         gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(FileDialog), playlistfilename);
1341 
1342         if (gtk_dialog_run(GTK_DIALOG(FileDialog)) == GTK_RESPONSE_ACCEPT) {
1343             playlistfilename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(FileDialog));
1344         }
1345 
1346         gtk_widget_hide(FileDialog);
1347         gtk_widget_destroy(FileDialog);
1348 
1349         if (playlistfilename != NULL) {
1350             playlistExport(playlistfilename, tmpplaylist);
1351             g_free(playlistfilename);
1352         }
1353     }
1354 } // end on_Playlist_ExportPlaylistButton_activate()
1355 
1356 // ************************************************************************************************
1357 
on_Playlist_DelPlaylistButton_activate(GtkWidget * item,gpointer user_data)1358 void on_Playlist_DelPlaylistButton_activate(GtkWidget *item, gpointer user_data) {
1359     UNUSED(item);
1360     UNUSED(user_data);
1361     gint PlayListID = gtk_combo_box_get_active(GTK_COMBO_BOX(comboboxentry_playlist));
1362     if (PlayListID != -1) {
1363         // We have something selected so lets do the dance.
1364         LIBMTP_playlist_t* tmpplaylist = devicePlayLists;
1365         if (PlayListID > 0) {
1366             while (PlayListID--)
1367                 if (tmpplaylist->next != NULL)
1368                     tmpplaylist = tmpplaylist->next;
1369         }
1370         // We should be in the correct playlist LIBMTP structure.
1371         playlistDelete(tmpplaylist);
1372         // Clear the PL list view box
1373         gtk_list_store_clear(GTK_LIST_STORE(playlist_PL_List));
1374         // Rebuild the playlist structure and combobox.
1375         devicePlayLists = getPlaylists();
1376         setPlayListComboBox();
1377     }
1378 } // end on_Playlist_DelPlaylistButton_activate()
1379 
1380 // ************************************************************************************************
1381 
on_Playlist_DelFileButton_activate(GtkWidget * item,gpointer user_data)1382 void on_Playlist_DelFileButton_activate(GtkWidget *item, gpointer user_data) {
1383     UNUSED(item);
1384     UNUSED(user_data);
1385     if (playlist_PL_ListGetSelection() == NULL)
1386         return;
1387     playlist_PL_ListRemove(playlist_PL_ListGetSelection());
1388 } // end on_Playlist_DelFileButton_activate()
1389 
1390 // ************************************************************************************************
1391 
on_Playlist_AddFileButton_activate(GtkWidget * item,gpointer user_data)1392 void on_Playlist_AddFileButton_activate(GtkWidget *item, gpointer user_data) {
1393     UNUSED(item);
1394     UNUSED(user_data);
1395     //g_printf("Clicked on add file in playlist button\n");
1396     if (playlist_TrackList_GetSelection() == NULL)
1397         return;
1398     playlist_TrackList_Add(playlist_TrackList_GetSelection());
1399 } // end on_Playlist_AddFileButton_activate()
1400 
1401 // ************************************************************************************************
1402 
on_Playlist_FileUpButton_activate(GtkWidget * item,gpointer user_data)1403 void on_Playlist_FileUpButton_activate(GtkWidget *item, gpointer user_data) {
1404     UNUSED(item);
1405     UNUSED(user_data);
1406     playlist_move_files(-1);
1407 } // end on_Playlist_FileUpButton_activate()
1408 
1409 // ************************************************************************************************
1410 
on_Playlist_FileDownButton_activate(GtkWidget * item,gpointer user_data)1411 void on_Playlist_FileDownButton_activate(GtkWidget *item, gpointer user_data) {
1412     UNUSED(item);
1413     UNUSED(user_data);
1414     playlist_move_files(1);
1415 } // end on_Playlist_FileDownButton_activate()
1416 
1417 // ************************************************************************************************
1418 
on_Playlist_Combobox_activate(GtkComboBox * combobox,gpointer user_data)1419 void on_Playlist_Combobox_activate(GtkComboBox *combobox, gpointer user_data) {
1420     UNUSED(combobox);
1421     UNUSED(user_data);
1422     if (runPlaylistHandler == TRUE) {
1423         // Save our current selected playlist
1424         playlist_SavePlaylist(playlist_number);
1425         // Get our new playlist ID, and display the contents of it.
1426         playlist_number = gtk_combo_box_get_active(GTK_COMBO_BOX(comboboxentry_playlist));
1427         setPlaylistField(playlist_number);
1428     }
1429 } // end on_Playlist_Combobox_activate()
1430 
1431