1 /* EasyTAG - tag editor for audio files
2 * Copyright (C) 2013-2015 David King <amigadave@amigadave.com>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the Free
6 * Software Foundation; either version 2 of the License, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 51
16 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include "config.h"
20
21 #include "playlist_dialog.h"
22
23 #include <glib/gi18n.h>
24
25 #include "application_window.h"
26 #include "browser.h"
27 #include "charset.h"
28 #include "easytag.h"
29 #include "misc.h"
30 #include "picture.h"
31 #include "scan.h"
32 #include "scan_dialog.h"
33 #include "setting.h"
34
35 typedef struct
36 {
37 GtkWidget *name_mask_radio;
38 GtkWidget *name_mask_entry;
39 GtkWidget *selected_files_check;
40 GtkWidget *path_relative_radio;
41 GtkWidget *playlist_parent_check;
42 GtkWidget *playlist_dos_check;
43 GtkWidget *content_filenames_radio;
44 GtkWidget *content_extended_radio;
45 GtkWidget *content_extended_mask_radio;
46 GtkWidget *content_mask_entry;
47 } EtPlaylistDialogPrivate;
48
G_DEFINE_TYPE_WITH_PRIVATE(EtPlaylistDialog,et_playlist_dialog,GTK_TYPE_DIALOG)49 G_DEFINE_TYPE_WITH_PRIVATE (EtPlaylistDialog, et_playlist_dialog, GTK_TYPE_DIALOG)
50
51 /*
52 * Function to replace UNIX ForwardSlash with a DOS BackSlash
53 */
54 static void
55 convert_forwardslash_to_backslash (const gchar *string)
56 {
57 gchar *tmp;
58
59 while ((tmp = strchr (string,'/')) != NULL)
60 {
61 *tmp = '\\';
62 }
63 }
64
65 /*
66 * Write a playlist
67 * - 'playlist_name' in file system encoding (not UTF-8)
68 */
69 static gboolean
write_playlist(EtPlaylistDialog * self,GFile * file,GError ** error)70 write_playlist (EtPlaylistDialog *self, GFile *file, GError **error)
71 {
72 EtPlaylistDialogPrivate *priv;
73 GFile *parent;
74 GFileOutputStream *ostream;
75 GString *to_write;
76 GList *l;
77 GList *etfilelist = NULL;
78 gchar *basedir;
79 gchar *temp;
80 EtPlaylistContent playlist_content;
81
82 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
83
84 priv = et_playlist_dialog_get_instance_private (self);
85
86 ostream = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, error);
87
88 if (!ostream)
89 {
90 g_assert (error == NULL || *error != NULL);
91 return FALSE;
92 }
93
94 /* 'base directory' where is located the playlist. Used also to write file with a
95 * relative path for file located in this directory and sub-directories
96 */
97 parent = g_file_get_parent (file);
98 basedir = g_file_get_path (parent);
99 g_object_unref (parent);
100
101 playlist_content = g_settings_get_enum (MainSettings, "playlist-content");
102
103 /* 1) First line of the file (if playlist content is not set to "write only
104 * list of files") */
105 if (playlist_content != ET_PLAYLIST_CONTENT_FILENAMES)
106 {
107 gsize bytes_written;
108
109 to_write = g_string_new ("#EXTM3U\r\n");
110
111 if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
112 to_write->str, to_write->len,
113 &bytes_written, NULL, error))
114 {
115 g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %" G_GSIZE_FORMAT
116 "bytes of data were written", bytes_written,
117 to_write->len);
118 g_assert (error == NULL || *error != NULL);
119 g_string_free (to_write, TRUE);
120 g_object_unref (ostream);
121 return FALSE;
122 }
123 g_string_free (to_write, TRUE);
124 }
125
126 if (g_settings_get_boolean (MainSettings, "playlist-selected-only"))
127 {
128 GList *selfilelist = NULL;
129 GtkTreeSelection *selection = et_application_window_browser_get_selection (ET_APPLICATION_WINDOW (MainWindow));
130
131 selfilelist = gtk_tree_selection_get_selected_rows(selection, NULL);
132
133 for (l = selfilelist; l != NULL; l = g_list_next (l))
134 {
135 ET_File *etfile;
136
137 etfile = et_application_window_browser_get_et_file_from_path (ET_APPLICATION_WINDOW (MainWindow),
138 l->data);
139 etfilelist = g_list_prepend (etfilelist, etfile);
140 }
141
142 etfilelist = g_list_reverse (etfilelist);
143
144 g_list_free_full (selfilelist, (GDestroyNotify)gtk_tree_path_free);
145 }else
146 {
147 etfilelist = ETCore->ETFileList;
148 }
149
150 for (l = etfilelist; l != NULL; l = g_list_next (l))
151 {
152 const ET_File *etfile;
153 const gchar *filename;
154 gint duration;
155
156 etfile = (ET_File *)l->data;
157 filename = ((File_Name *)etfile->FileNameCur->data)->value;
158 duration = ((ET_File_Info *)etfile->ETFileInfo)->duration;
159
160 if (g_settings_get_boolean (MainSettings, "playlist-relative"))
161 {
162 // Keep only files in this directory and sub-dirs
163 if ( strncmp(filename,basedir,strlen(basedir))==0 )
164 {
165 gsize bytes_written;
166
167 /* 2) Write the header. */
168 switch (playlist_content)
169 {
170 case ET_PLAYLIST_CONTENT_FILENAMES:
171 /* No header written. */
172 break;
173 case ET_PLAYLIST_CONTENT_EXTENDED:
174 /* Header has extended information. */
175 temp = g_path_get_basename (filename);
176 to_write = g_string_new ("#EXTINF:");
177 /* Must be written in system encoding (not UTF-8). */
178 g_string_append_printf (to_write, "%d,%s\r\n", duration,
179 temp);
180
181 if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
182 to_write->str,
183 to_write->len,
184 &bytes_written, NULL,
185 error))
186 {
187 g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %"
188 G_GSIZE_FORMAT "bytes of data were written",
189 bytes_written, to_write->len);
190 g_assert (error == NULL || *error != NULL);
191 g_string_free (to_write, TRUE);
192 g_object_unref (ostream);
193 return FALSE;
194 }
195 g_string_free (to_write, TRUE);
196 g_free (temp);
197 break;
198 case ET_PLAYLIST_CONTENT_EXTENDED_MASK:
199 {
200 /* Header uses information generated from a mask. */
201 gchar *mask = filename_from_display (gtk_entry_get_text (GTK_ENTRY (priv->content_mask_entry)));
202 /* Special case: do not replace illegal characters and
203 * do not check if there is a directory separator in
204 * the mask. */
205 gchar *filename_generated_utf8 = et_scan_generate_new_filename_from_mask (etfile, mask, TRUE);
206 gchar *filename_generated = filename_from_display (filename_generated_utf8);
207
208 to_write = g_string_new ("#EXTINF:");
209 /* Must be written in system encoding (not UTF-8). */
210 g_string_append_printf (to_write, "%d,%s\r\n", duration,
211 filename_generated);
212
213 if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
214 to_write->str,
215 to_write->len,
216 &bytes_written, NULL,
217 error))
218 {
219 g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %"
220 G_GSIZE_FORMAT "bytes of data were written",
221 bytes_written, to_write->len);
222 g_assert (error == NULL || *error != NULL);
223 g_string_free (to_write, TRUE);
224 g_object_unref (ostream);
225 return FALSE;
226 }
227 g_string_free (to_write, TRUE);
228 g_free (mask);
229 g_free (filename_generated_utf8);
230
231 break;
232 }
233 default:
234 g_assert_not_reached ();
235 break;
236 }
237
238 /* 3) Write the file path. */
239 if (g_settings_get_boolean (MainSettings,
240 "playlist-dos-separator"))
241 {
242 gchar *filename_conv = g_strdup(filename+strlen(basedir)+1);
243 convert_forwardslash_to_backslash (filename_conv);
244
245 to_write = g_string_new (filename_conv);
246 /* Must be written in system encoding (not UTF-8)*/
247 to_write = g_string_append (to_write, "\r\n");
248
249 if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
250 to_write->str,
251 to_write->len,
252 &bytes_written, NULL,
253 error))
254 {
255 g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %"
256 G_GSIZE_FORMAT "bytes of data were written",
257 bytes_written, to_write->len);
258 g_assert (error == NULL || *error != NULL);
259 g_string_free (to_write, TRUE);
260 g_object_unref (ostream);
261 return FALSE;
262 }
263 g_string_free (to_write, TRUE);
264 g_free(filename_conv);
265 }else
266 {
267 to_write = g_string_new (filename+strlen(basedir)+1);
268 /* Must be written in system encoding (not UTF-8)*/
269 to_write = g_string_append (to_write, "\r\n");
270
271 if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
272 to_write->str,
273 to_write->len,
274 &bytes_written, NULL,
275 error))
276 {
277 g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %"
278 G_GSIZE_FORMAT "bytes of data were written",
279 bytes_written, to_write->len);
280 g_assert (error == NULL || *error != NULL);
281 g_string_free (to_write, TRUE);
282 g_object_unref (ostream);
283 return FALSE;
284 }
285 g_string_free (to_write, TRUE);
286 }
287 }
288 }
289 else /* !ETSettings:playlist-relative */
290 {
291 gsize bytes_written;
292
293 /* 2) Write the header. */
294 switch (playlist_content)
295 {
296 case ET_PLAYLIST_CONTENT_FILENAMES:
297 /* No header written. */
298 break;
299 case ET_PLAYLIST_CONTENT_EXTENDED:
300 /* Header has extended information. */
301 temp = g_path_get_basename (filename);
302 to_write = g_string_new ("#EXTINF:");
303 /* Must be written in system encoding (not UTF-8). */
304 g_string_append_printf (to_write, "%d,%s\r\n", duration,
305 temp);
306 g_free (temp);
307
308 if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
309 to_write->str, to_write->len,
310 &bytes_written, NULL, error))
311 {
312 g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %"
313 G_GSIZE_FORMAT" bytes of data were written",
314 bytes_written, to_write->len);
315 g_assert (error == NULL || *error != NULL);
316 g_string_free (to_write, TRUE);
317 g_object_unref (ostream);
318 return FALSE;
319 }
320 g_string_free (to_write, TRUE);
321 break;
322 case ET_PLAYLIST_CONTENT_EXTENDED_MASK:
323 {
324 /* Header uses information generated from a mask. */
325 gchar *mask = filename_from_display (gtk_entry_get_text (GTK_ENTRY (priv->content_mask_entry)));
326 /* Special case: do not replace illegal characters and
327 * do not check if there is a directory separator in
328 * the mask. */
329 gchar *filename_generated_utf8 = et_scan_generate_new_filename_from_mask (etfile, mask, TRUE);
330 gchar *filename_generated = filename_from_display (filename_generated_utf8);
331
332 to_write = g_string_new ("#EXTINF:");
333 /* Must be written in system encoding (not UTF-8). */
334 g_string_append_printf (to_write, "%d,%s\r\n", duration,
335 filename_generated);
336 g_free (filename_generated);
337
338 if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
339 to_write->str, to_write->len,
340 &bytes_written, NULL, error))
341 {
342 g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %"
343 G_GSIZE_FORMAT" bytes of data were written",
344 bytes_written, to_write->len);
345 g_assert (error == NULL || *error != NULL);
346 g_string_free (to_write, TRUE);
347 g_object_unref (ostream);
348 return FALSE;
349 }
350 g_string_free (to_write, TRUE);
351 g_free (mask);
352 g_free (filename_generated_utf8);
353 }
354 break;
355 default:
356 g_assert_not_reached ();
357 break;
358 }
359
360 /* 3) Write the file path. */
361 if (g_settings_get_boolean (MainSettings,
362 "playlist-dos-separator"))
363 {
364 gchar *filename_conv = g_strdup(filename);
365 convert_forwardslash_to_backslash(filename_conv);
366
367 to_write = g_string_new (filename_conv);
368 /* Must be written in system encoding (not UTF-8)*/
369 to_write = g_string_append (to_write, "\r\n");
370
371 if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
372 to_write->str, to_write->len,
373 &bytes_written, NULL, error))
374 {
375 g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %"
376 G_GSIZE_FORMAT" bytes of data were written",
377 bytes_written, to_write->len);
378 g_assert (error == NULL || *error != NULL);
379 g_string_free (to_write, TRUE);
380 g_object_unref (ostream);
381 return FALSE;
382 }
383 g_string_free (to_write, TRUE);
384 g_free(filename_conv);
385 }else
386 {
387 to_write = g_string_new (filename);
388 /* Must be written in system encoding (not UTF-8)*/
389 to_write = g_string_append (to_write, "\r\n");
390
391 if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
392 to_write->str, to_write->len,
393 &bytes_written, NULL, error))
394 {
395 g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %"
396 G_GSIZE_FORMAT" bytes of data were written",
397 bytes_written, to_write->len);
398 g_assert (error == NULL || *error != NULL);
399 g_string_free (to_write, TRUE);
400 g_object_unref (ostream);
401 return FALSE;
402 }
403 g_string_free (to_write, TRUE);
404 }
405 }
406 }
407
408 if (g_settings_get_boolean (MainSettings, "playlist-selected-only"))
409 {
410 g_list_free (etfilelist);
411 }
412
413 g_assert (error == NULL || *error == NULL);
414 g_object_unref (ostream);
415 g_free(basedir);
416 return TRUE;
417 }
418
419 static void
write_button_clicked(EtPlaylistDialog * self)420 write_button_clicked (EtPlaylistDialog *self)
421 {
422 EtPlaylistDialogPrivate *priv;
423 gchar *playlist_name = NULL;
424 gchar *playlist_path_utf8; // Path
425 gchar *playlist_basename_utf8; // Filename
426 gchar *playlist_name_utf8; // Path + filename
427 gchar *temp;
428 GtkWidget *msgdialog;
429
430 priv = et_playlist_dialog_get_instance_private (self);
431
432 /* Check if playlist name was filled. */
433 if (g_settings_get_boolean (MainSettings, "playlist-use-mask")
434 && *(gtk_entry_get_text (GTK_ENTRY (priv->name_mask_entry))) == '\0')
435 {
436 /* TODO: Can this happen? */
437 g_settings_set_boolean (MainSettings, "playlist-use-mask", FALSE);
438 }
439
440 // Path of the playlist file (may be truncated later if PLAYLIST_CREATE_IN_PARENT_DIR is TRUE)
441 temp = g_file_get_path (et_application_window_get_current_path (ET_APPLICATION_WINDOW (MainWindow)));
442 playlist_path_utf8 = g_filename_display_name (temp);
443 g_free (temp);
444
445 /* Build the playlist filename. */
446 if (g_settings_get_boolean (MainSettings, "playlist-use-mask"))
447 {
448 EtConvertSpaces convert_mode;
449
450 if (!ETCore->ETFileList)
451 return;
452
453 playlist_name = g_settings_get_string (MainSettings,
454 "playlist-filename-mask");
455
456 /* Generate filename from tag of the current selected file (FIXME). */
457 temp = filename_from_display (playlist_name);
458 g_free (playlist_name);
459 playlist_basename_utf8 = et_scan_generate_new_filename_from_mask (ETCore->ETFileDisplayed,
460 temp,
461 FALSE);
462 g_free (temp);
463
464 /* Replace Characters (with scanner). */
465 convert_mode = g_settings_get_enum (MainSettings,
466 "rename-convert-spaces");
467
468 switch (convert_mode)
469 {
470 case ET_CONVERT_SPACES_SPACES:
471 Scan_Convert_Underscore_Into_Space (playlist_basename_utf8);
472 Scan_Convert_P20_Into_Space (playlist_basename_utf8);
473 break;
474 case ET_CONVERT_SPACES_UNDERSCORES:
475 Scan_Convert_Space_Into_Underscore (playlist_basename_utf8);
476 break;
477 case ET_CONVERT_SPACES_REMOVE:
478 Scan_Remove_Spaces (playlist_basename_utf8);
479 break;
480 /* FIXME: Check that this is intended. */
481 case ET_CONVERT_SPACES_NO_CHANGE:
482 default:
483 g_assert_not_reached ();
484 break;
485 }
486 }else // PLAYLIST_USE_DIR_NAME
487 {
488
489 if ( strcmp(playlist_path_utf8,G_DIR_SEPARATOR_S)==0 )
490 {
491 playlist_basename_utf8 = g_strdup("playlist");
492 }else
493 {
494 gchar *tmp_string = g_strdup(playlist_path_utf8);
495 // Remove last '/'
496 if (tmp_string[strlen(tmp_string)-1]==G_DIR_SEPARATOR)
497 tmp_string[strlen(tmp_string)-1] = '\0';
498 // Get directory name
499 temp = g_path_get_basename(tmp_string);
500 playlist_basename_utf8 = g_strdup(temp);
501 g_free(tmp_string);
502 g_free(temp);
503 }
504
505 }
506
507 /* Must be placed after "Build the playlist filename", as we can truncate
508 * the path! */
509 if (g_settings_get_boolean (MainSettings, "playlist-parent-directory"))
510 {
511 if ( (strcmp(playlist_path_utf8,G_DIR_SEPARATOR_S) != 0) )
512 {
513 gchar *tmp;
514 // Remove last '/'
515 if (playlist_path_utf8[strlen(playlist_path_utf8)-1]==G_DIR_SEPARATOR)
516 playlist_path_utf8[strlen(playlist_path_utf8)-1] = '\0';
517 // Get parent directory
518 if ( (tmp=strrchr(playlist_path_utf8,G_DIR_SEPARATOR)) != NULL )
519 *(tmp + 1) = '\0';
520 }
521 }
522
523 // Generate path + filename of playlist
524 if (playlist_path_utf8[strlen(playlist_path_utf8)-1]==G_DIR_SEPARATOR)
525 playlist_name_utf8 = g_strconcat(playlist_path_utf8,playlist_basename_utf8,".m3u",NULL);
526 else
527 playlist_name_utf8 = g_strconcat(playlist_path_utf8,G_DIR_SEPARATOR_S,playlist_basename_utf8,".m3u",NULL);
528
529 g_free(playlist_path_utf8);
530 g_free(playlist_basename_utf8);
531
532 playlist_name = filename_from_display(playlist_name_utf8);
533
534 {
535 GFile *file = g_file_new_for_path (playlist_name);
536 GError *error = NULL;
537
538 if (!write_playlist (self, file, &error))
539 {
540 // Writing fails...
541 msgdialog = gtk_message_dialog_new (GTK_WINDOW (self),
542 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
543 GTK_MESSAGE_ERROR,
544 GTK_BUTTONS_CLOSE,
545 _("Cannot write playlist file ‘%s’"),
546 playlist_name_utf8);
547 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (msgdialog),
548 "%s", error->message);
549 gtk_window_set_title(GTK_WINDOW(msgdialog),_("Playlist File Error"));
550
551 gtk_dialog_run(GTK_DIALOG(msgdialog));
552 gtk_widget_destroy(msgdialog);
553 g_error_free (error);
554 }else
555 {
556 gchar *msg;
557 msg = g_strdup_printf (_("Wrote playlist file ‘%s’"),
558 playlist_name_utf8);
559 et_application_window_status_bar_message (ET_APPLICATION_WINDOW (MainWindow),
560 msg, TRUE);
561 g_free (msg);
562 }
563 g_object_unref (file);
564 }
565 g_free(playlist_name_utf8);
566 g_free(playlist_name);
567 }
568
569 /*
570 * on_response:
571 * @dialog: the dialog which emitted the response signal
572 * @response_id: the response ID
573 * @user_data: user data set when the signal was connected
574 *
575 * Signal handler for the write playlist dialog.
576 */
577 static void
on_response(GtkDialog * dialog,gint response_id,gpointer user_data)578 on_response (GtkDialog *dialog, gint response_id, gpointer user_data)
579 {
580 switch (response_id)
581 {
582 case GTK_RESPONSE_OK:
583 write_button_clicked (ET_PLAYLIST_DIALOG (dialog));
584 break;
585 case GTK_RESPONSE_CANCEL:
586 gtk_widget_hide (GTK_WIDGET (dialog));
587 break;
588 case GTK_RESPONSE_DELETE_EVENT:
589 break;
590 default:
591 g_assert_not_reached ();
592 }
593 }
594
595 /*
596 * entry_check_content_mask:
597 * @entry: the entry for which to check the mask
598 * @user_data: user data set when the signal was connected
599 *
600 * Display an icon in the entry if the current text contains an invalid mask.
601 */
602 static void
entry_check_content_mask(GtkEntry * entry,gpointer user_data)603 entry_check_content_mask (GtkEntry *entry, gpointer user_data)
604 {
605 gchar *tmp = NULL;
606 gchar *mask = NULL;
607
608 g_return_if_fail (entry != NULL);
609
610 mask = g_strdup (gtk_entry_get_text (entry));
611
612 if (et_str_empty (mask))
613 goto Bad_Mask;
614
615 while (mask)
616 {
617 if ( (tmp=strrchr(mask,'%'))==NULL )
618 {
619 /* There is no more code. */
620 /* No code in mask is accepted. */
621 goto Good_Mask;
622 }
623 if (strlen(tmp)>1 && (tmp[1]=='t' || tmp[1]=='a' || tmp[1]=='b' || tmp[1]=='y' ||
624 tmp[1]=='g' || tmp[1]=='n' || tmp[1]=='l' || tmp[1]=='c' || tmp[1]=='i'))
625 {
626 /* The code is valid. */
627 /* No separator is accepted. */
628 *(mask+strlen(mask)-strlen(tmp)) = '\0';
629 }else
630 {
631 goto Bad_Mask;
632 }
633 }
634
635 Bad_Mask:
636 g_free(mask);
637 gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY,
638 "emblem-unreadable");
639 gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_SECONDARY,
640 _("Invalid scanner mask"));
641 return;
642
643 Good_Mask:
644 g_free(mask);
645 gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY,
646 NULL);
647 return;
648 }
649
650 static void
create_playlist_dialog(EtPlaylistDialog * self)651 create_playlist_dialog (EtPlaylistDialog *self)
652 {
653 EtPlaylistDialogPrivate *priv;
654 GtkDialog *dialog;
655
656 priv = et_playlist_dialog_get_instance_private (self);
657 dialog = GTK_DIALOG (self);
658
659 gtk_dialog_add_buttons (dialog, _("_Cancel"), GTK_RESPONSE_CANCEL,
660 _("_Save"), GTK_RESPONSE_OK, NULL);
661 gtk_dialog_set_default_response (dialog, GTK_RESPONSE_OK);
662
663 /* Playlist name */
664 g_settings_bind (MainSettings, "playlist-filename-mask",
665 priv->name_mask_entry, "text", G_SETTINGS_BIND_DEFAULT);
666 g_settings_bind (MainSettings, "playlist-use-mask", priv->name_mask_radio,
667 "active", G_SETTINGS_BIND_DEFAULT);
668
669 /* Playlist options */
670 g_settings_bind (MainSettings, "playlist-selected-only",
671 priv->selected_files_check, "active",
672 G_SETTINGS_BIND_DEFAULT);
673
674 g_settings_bind (MainSettings, "playlist-relative",
675 priv->path_relative_radio, "active",
676 G_SETTINGS_BIND_DEFAULT);
677
678 /* Create playlist in parent directory. */
679 g_settings_bind (MainSettings, "playlist-parent-directory",
680 priv->playlist_parent_check, "active",
681 G_SETTINGS_BIND_DEFAULT);
682
683 /* DOS Separator. */
684 g_settings_bind (MainSettings, "playlist-dos-separator",
685 priv->playlist_dos_check, "active",
686 G_SETTINGS_BIND_DEFAULT);
687
688 /* Playlist content */
689 g_settings_bind (MainSettings, "playlist-default-mask",
690 priv->content_mask_entry, "text",
691 G_SETTINGS_BIND_DEFAULT);
692
693 /* Mask status icon. Signal connection to check if mask is correct in the
694 * mask entry. */
695 g_signal_connect (priv->content_mask_entry, "changed",
696 G_CALLBACK (entry_check_content_mask), NULL);
697
698 g_settings_bind_with_mapping (MainSettings, "playlist-content",
699 priv->content_filenames_radio, "active",
700 G_SETTINGS_BIND_DEFAULT,
701 et_settings_enum_radio_get,
702 et_settings_enum_radio_set,
703 priv->content_filenames_radio, NULL);
704 g_settings_bind_with_mapping (MainSettings, "playlist-content",
705 priv->content_extended_radio, "active",
706 G_SETTINGS_BIND_DEFAULT,
707 et_settings_enum_radio_get,
708 et_settings_enum_radio_set,
709 priv->content_extended_radio, NULL);
710 g_settings_bind_with_mapping (MainSettings, "playlist-content",
711 priv->content_extended_mask_radio, "active",
712 G_SETTINGS_BIND_DEFAULT,
713 et_settings_enum_radio_get,
714 et_settings_enum_radio_set,
715 priv->content_extended_mask_radio, NULL);
716
717 /* To initialize the mask status icon and visibility. */
718 g_signal_emit_by_name (priv->name_mask_entry, "changed");
719 g_signal_emit_by_name (priv->content_mask_entry, "changed");
720 }
721
722 static void
et_playlist_dialog_init(EtPlaylistDialog * self)723 et_playlist_dialog_init (EtPlaylistDialog *self)
724 {
725 gtk_widget_init_template (GTK_WIDGET (self));
726 create_playlist_dialog (self);
727 }
728
729 static void
et_playlist_dialog_class_init(EtPlaylistDialogClass * klass)730 et_playlist_dialog_class_init (EtPlaylistDialogClass *klass)
731 {
732 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
733
734 gtk_widget_class_set_template_from_resource (widget_class,
735 "/org/gnome/EasyTAG/playlist_dialog.ui");
736 gtk_widget_class_bind_template_child_private (widget_class,
737 EtPlaylistDialog,
738 name_mask_radio);
739 gtk_widget_class_bind_template_child_private (widget_class,
740 EtPlaylistDialog,
741 name_mask_entry);
742 gtk_widget_class_bind_template_child_private (widget_class,
743 EtPlaylistDialog,
744 selected_files_check);
745 gtk_widget_class_bind_template_child_private (widget_class,
746 EtPlaylistDialog,
747 path_relative_radio);
748 gtk_widget_class_bind_template_child_private (widget_class,
749 EtPlaylistDialog,
750 playlist_parent_check);
751 gtk_widget_class_bind_template_child_private (widget_class,
752 EtPlaylistDialog,
753 playlist_dos_check);
754 gtk_widget_class_bind_template_child_private (widget_class,
755 EtPlaylistDialog,
756 content_filenames_radio);
757 gtk_widget_class_bind_template_child_private (widget_class,
758 EtPlaylistDialog,
759 content_extended_radio);
760 gtk_widget_class_bind_template_child_private (widget_class,
761 EtPlaylistDialog,
762 content_extended_mask_radio);
763 gtk_widget_class_bind_template_child_private (widget_class,
764 EtPlaylistDialog,
765 content_mask_entry);
766 gtk_widget_class_bind_template_callback (widget_class,
767 entry_check_content_mask);
768 gtk_widget_class_bind_template_callback (widget_class, on_response);
769 }
770
771 /*
772 * et_playlist_dialog_new:
773 *
774 * Create a new EtPlaylistDialog instance.
775 *
776 * Returns: a new #EtPlaylistDialog
777 */
778 EtPlaylistDialog *
et_playlist_dialog_new(GtkWindow * parent)779 et_playlist_dialog_new (GtkWindow *parent)
780 {
781 g_return_val_if_fail (GTK_WINDOW (parent), NULL);
782
783 return g_object_new (ET_TYPE_PLAYLIST_DIALOG, "transient-for", parent,
784 NULL);
785 }
786