[easytag/wip/application-window: 4/79] Move playlist window to EtPlaylistDialog object



commit fc61c8469dfb31da5393388e0343c29ae4375e84
Author: David King <amigadave amigadave com>
Date:   Fri Dec 27 19:56:40 2013 +0000

    Move playlist window to EtPlaylistDialog object

 Makefile.am              |    2 +
 po/POTFILES.in           |    1 +
 src/application_window.c |   50 +++-
 src/application_window.h |    2 +
 src/bar.c                |    3 +-
 src/misc.c               |  807 -------------------------------------------
 src/misc.h               |   16 -
 src/playlist_dialog.c    |  855 ++++++++++++++++++++++++++++++++++++++++++++++
 src/playlist_dialog.h    |   67 ++++
 src/setting.c            |   11 +-
 src/setting.h            |    3 -
 11 files changed, 980 insertions(+), 837 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 36bc22f..4ae3e81 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -69,6 +69,7 @@ easytag_SOURCES = \
        src/opus_header.c \
        src/opus_tag.c \
        src/picture.c \
+       src/playlist_dialog.c \
        src/prefs.c \
        src/scan.c \
        src/scan_dialog.c \
@@ -113,6 +114,7 @@ easytag_headers = \
        src/opus_header.h \
        src/opus_tag.h \
        src/picture.h \
+       src/playlist_dialog.h \
        src/prefs.h \
        src/scan.h \
        src/scan_dialog.h \
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 331c927..000d7cb 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -27,6 +27,7 @@ src/ogg_tag.c
 src/opus_header.c
 src/picture.c
 src/prefs.c
+src/playlist_dialog.c
 src/scan_dialog.c
 src/setting.c
 src/vcedit.c
diff --git a/src/application_window.c b/src/application_window.c
index def9f38..6e3c910 100644
--- a/src/application_window.c
+++ b/src/application_window.c
@@ -30,6 +30,7 @@
 #include "log.h"
 #include "misc.h"
 #include "picture.h"
+#include "playlist_dialog.h"
 #include "scan.h"
 #include "scan_dialog.h"
 #include "setting.h"
@@ -44,6 +45,7 @@ struct _EtApplicationWindowPrivate
     GtkWidget *file_area;
     GtkWidget *log_area;
     GtkWidget *tag_area;
+    GtkWidget *playlist_dialog;
 
     /* Tag area labels. */
     GtkWidget *title_label;
@@ -1631,9 +1633,17 @@ create_tag_area (EtApplicationWindow *self)
 
 
 static void
-et_application_window_finalize (GObject *object)
+et_application_window_dispose (GObject *object)
 {
-    G_OBJECT_CLASS (et_application_window_parent_class)->finalize (object);
+    EtApplicationWindow *self;
+    EtApplicationWindowPrivate *priv;
+
+    self = ET_APPLICATION_WINDOW (object);
+    priv = et_application_window_get_instance_private (self);
+
+    g_clear_pointer (&priv->playlist_dialog, gtk_widget_destroy);
+
+    G_OBJECT_CLASS (et_application_window_parent_class)->dispose (object);
 }
 
 static void
@@ -1649,6 +1659,8 @@ et_application_window_init (EtApplicationWindow *self)
                                                      ET_TYPE_APPLICATION_WINDOW,
                                                      EtApplicationWindowPrivate);
 
+    priv->playlist_dialog = NULL;
+
     window = GTK_WINDOW (self);
 
     gtk_window_set_icon_name (window, PACKAGE_TARNAME);
@@ -1720,7 +1732,7 @@ et_application_window_init (EtApplicationWindow *self)
 static void
 et_application_window_class_init (EtApplicationWindowClass *klass)
 {
-    G_OBJECT_CLASS (klass)->finalize = et_application_window_finalize;
+    G_OBJECT_CLASS (klass)->dispose = et_application_window_dispose;
 
     g_type_class_add_private (klass, sizeof (EtApplicationWindowPrivate));
 }
@@ -1777,6 +1789,38 @@ et_application_window_get_log_area (EtApplicationWindow *self)
     return priv->log_area;
 }
 
+GtkWidget *
+et_application_window_get_playlist_dialog (EtApplicationWindow *self)
+{
+    EtApplicationWindowPrivate *priv;
+
+    g_return_val_if_fail (self != NULL, NULL);
+
+    priv = et_application_window_get_instance_private (self);
+
+    return priv->playlist_dialog;
+}
+
+void
+et_application_window_show_playlist_dialog (G_GNUC_UNUSED GtkAction *action,
+                                            gpointer user_data)
+{
+    EtApplicationWindowPrivate *priv;
+    EtApplicationWindow *self = ET_APPLICATION_WINDOW (user_data);
+
+    priv = et_application_window_get_instance_private (self);
+
+    if (priv->playlist_dialog)
+    {
+        gtk_widget_show (priv->playlist_dialog);
+    }
+    else
+    {
+        priv->playlist_dialog = GTK_WIDGET (et_playlist_dialog_new ());
+        gtk_widget_show_all (priv->playlist_dialog);
+    }
+}
+
 /*
  * Disable (FALSE) / Enable (TRUE) all user widgets in the tag area
  */
diff --git a/src/application_window.h b/src/application_window.h
index a08346e..9cc2636 100644
--- a/src/application_window.h
+++ b/src/application_window.h
@@ -51,6 +51,8 @@ void et_application_window_tag_area_set_sensitive (EtApplicationWindow *self, gb
 void et_application_window_file_area_set_sensitive (EtApplicationWindow *self, gboolean sensitive);
 void et_application_window_tag_area_display_controls (EtApplicationWindow *self, ET_File *ETFile);
 GtkWidget * et_application_window_get_log_area (EtApplicationWindow *self);
+GtkWidget * et_application_window_get_playlist_dialog (EtApplicationWindow *self);
+void et_application_window_show_playlist_dialog (GtkAction *action, gpointer user_data);
 void et_application_window_hide_log_area (EtApplicationWindow *self);
 void et_application_window_show_log_area (EtApplicationWindow *self);
 
diff --git a/src/bar.c b/src/bar.c
index c9595d6..7722971 100644
--- a/src/bar.c
+++ b/src/bar.c
@@ -23,6 +23,7 @@
 #include <gtk/gtk.h>
 #include <glib/gi18n.h>
 
+#include "application_window.h"
 #include "bar.h"
 #include "easytag.h"
 #include "about.h"
@@ -294,7 +295,7 @@ Create_UI (GtkWindow *window, GtkWidget **ppmenubar, GtkWidget **pptoolbar)
           G_CALLBACK (Open_Load_Filename_Window) },
         { AM_WRITE_PLAYLIST, GTK_STOCK_SAVE_AS, _("Generate Playlist…"),
           "<Primary>W", _("Generate a playlist"),
-          G_CALLBACK (Open_Write_Playlist_Window) },
+          G_CALLBACK (et_application_window_show_playlist_dialog) },
         { AM_RUN_AUDIO_PLAYER, GTK_STOCK_MEDIA_PLAY, _("Run Audio Player"),
           "<Primary>M", _("Run audio player"),
           G_CALLBACK (Run_Audio_Player_Using_Selection) },
diff --git a/src/misc.c b/src/misc.c
index aa0b9de..f29a36e 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -49,13 +49,6 @@
 /***************
  * Declaration *
  ***************/
-/* Playlist window. */
-static GtkWidget *WritePlaylistWindow;
-static GtkWidget *PlayListNameMaskCombo;
-static GtkWidget *PlayListContentMaskCombo;
-static GtkListStore *PlayListNameMaskModel;
-static GtkListStore *PlayListContentMaskModel;
-
 static const guint BOX_SPACING = 6;
 
 static GdkCursor *MouseCursor;
@@ -155,13 +148,6 @@ enum
 /**************
  * Prototypes *
  **************/
-void     Open_Write_Playlist_Window      (void);
-static void Destroy_Write_Playlist_Window (void);
-static void Playlist_Write_Button_Pressed (void);
-static gboolean write_playlist (GFile *file, GError **error);
-static void entry_check_content_mask (GtkEntry *entry, gpointer user_data);
-static void Playlist_Convert_Forwardslash_Into_Backslash (const gchar *string);
-
 void Open_Search_File_Window          (void);
 static void Destroy_Search_File_Window (void);
 static void Search_File (GtkWidget *search_button);
@@ -200,8 +186,6 @@ void        File_Selection_Window_For_Directory (GtkWidget *entry);
 
 static void et_load_text_file_on_response (GtkDialog *dialog, gint response_id,
                                            gpointer user_data);
-static void et_playlist_on_response (GtkDialog *dialog, gint response_id,
-                                     gpointer user_data);
 
 /*************
  * Functions *
@@ -1115,771 +1099,6 @@ et_get_file_size (const gchar *filename)
     return size;
 }
 
-
-
-/*******************************
- * Writting playlist functions *
- *******************************/
-/*
- * The window to write playlists.
- */
-void Open_Write_Playlist_Window (void)
-{
-    GtkWidget *Frame;
-    GtkWidget *VBox;
-    GtkWidget *vbox, *hbox;
-
-    if (WritePlaylistWindow != NULL)
-    {
-        gtk_window_present(GTK_WINDOW(WritePlaylistWindow));
-        return;
-    }
-
-    WritePlaylistWindow = gtk_dialog_new_with_buttons (_("Generate Playlist"),
-                                                       GTK_WINDOW (MainWindow),
-                                                       GTK_DIALOG_DESTROY_WITH_PARENT,
-                                                       GTK_STOCK_CANCEL,
-                                                       GTK_RESPONSE_CANCEL,
-                                                       GTK_STOCK_SAVE,
-                                                       GTK_RESPONSE_OK, NULL);
-
-    gtk_dialog_set_default_response (GTK_DIALOG (WritePlaylistWindow),
-                                     GTK_RESPONSE_OK);
-    g_signal_connect (WritePlaylistWindow, "response",
-                      G_CALLBACK (et_playlist_on_response), NULL);
-
-    VBox = gtk_dialog_get_content_area (GTK_DIALOG (WritePlaylistWindow));
-    gtk_box_set_spacing (GTK_BOX (VBox), BOX_SPACING);
-    gtk_container_set_border_width (GTK_CONTAINER (VBox), BOX_SPACING);
-
-
-    /* Playlist name */
-    if (!PlayListNameMaskModel)
-        PlayListNameMaskModel = gtk_list_store_new(MISC_COMBO_COUNT, G_TYPE_STRING);
-    else
-        gtk_list_store_clear(PlayListNameMaskModel);
-
-    Frame = gtk_frame_new(_("M3U Playlist Name"));
-    gtk_box_pack_start(GTK_BOX(VBox),Frame,TRUE,TRUE,0);
-    vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, BOX_SPACING);
-    gtk_container_add(GTK_CONTAINER(Frame),vbox);
-    gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
-
-    playlist_use_mask_name = gtk_radio_button_new_with_label(NULL, _("Use mask:"));
-    hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, BOX_SPACING);
-    gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,0);
-    gtk_box_pack_start(GTK_BOX(hbox),playlist_use_mask_name,FALSE,FALSE,0);
-    PlayListNameMaskCombo = gtk_combo_box_new_with_model_and_entry(GTK_TREE_MODEL(PlayListNameMaskModel));
-    gtk_combo_box_set_entry_text_column(GTK_COMBO_BOX(PlayListNameMaskCombo),MISC_COMBO_TEXT);
-    gtk_box_pack_start (GTK_BOX (hbox), PlayListNameMaskCombo, FALSE, FALSE,
-                        0);
-    playlist_use_dir_name = gtk_radio_button_new_with_label_from_widget(
-        GTK_RADIO_BUTTON(playlist_use_mask_name),_("Use directory name"));
-    gtk_box_pack_start(GTK_BOX(vbox),playlist_use_dir_name,FALSE,FALSE,0);
-    // History list
-    Load_Play_List_Name_List(PlayListNameMaskModel, MISC_COMBO_TEXT);
-    Add_String_To_Combo_List(PlayListNameMaskModel, PLAYLIST_NAME);
-    gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(PlayListNameMaskCombo))), PLAYLIST_NAME);
-
-    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_use_mask_name),PLAYLIST_USE_MASK_NAME);
-    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_use_dir_name),PLAYLIST_USE_DIR_NAME);
-
-    // Mask status icon
-    // Signal connection to check if mask is correct into the mask entry
-    g_signal_connect (gtk_bin_get_child (GTK_BIN (PlayListNameMaskCombo)),
-                      "changed", G_CALLBACK (entry_check_content_mask),
-                      NULL);
-
-    /* Playlist options */
-    Frame = gtk_frame_new(_("Playlist Options"));
-    gtk_box_pack_start(GTK_BOX(VBox),Frame,TRUE,TRUE,0);
-    vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, BOX_SPACING);
-    gtk_container_add(GTK_CONTAINER(Frame),vbox);
-    gtk_container_set_border_width (GTK_CONTAINER (vbox), BOX_SPACING);
-
-    playlist_only_selected_files = gtk_check_button_new_with_label(_("Include only the selected files"));
-    gtk_box_pack_start(GTK_BOX(vbox),playlist_only_selected_files,FALSE,FALSE,0);
-    
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_only_selected_files),PLAYLIST_ONLY_SELECTED_FILES);
-    gtk_widget_set_tooltip_text(playlist_only_selected_files,_("If activated, only the selected files will 
be "
-        "written in the playlist file. Else, all the files will be written."));
-
-    playlist_full_path = gtk_radio_button_new_with_label(NULL,_("Use full path for files in playlist"));
-    gtk_box_pack_start(GTK_BOX(vbox),playlist_full_path,FALSE,FALSE,0);
-    playlist_relative_path = 
gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(playlist_full_path),
-        _("Use relative path for files in playlist"));
-    gtk_box_pack_start(GTK_BOX(vbox),playlist_relative_path,FALSE,FALSE,0);
-    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_full_path),PLAYLIST_FULL_PATH);
-    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_relative_path),PLAYLIST_RELATIVE_PATH);
-
-    // Create playlist in parent directory
-    playlist_create_in_parent_dir = gtk_check_button_new_with_label(_("Create playlist in the parent 
directory"));
-    gtk_box_pack_start(GTK_BOX(vbox),playlist_create_in_parent_dir,FALSE,FALSE,0);
-    
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_create_in_parent_dir),PLAYLIST_CREATE_IN_PARENT_DIR);
-    gtk_widget_set_tooltip_text(playlist_create_in_parent_dir,_("If activated, the playlist will be created "
-        "in the parent directory."));
-
-    // DOS Separator
-    playlist_use_dos_separator = gtk_check_button_new_with_label(_("Use DOS directory separator"));
-#ifndef G_OS_WIN32
-    /* This makes no sense under Win32, so we do not display it. */
-    gtk_box_pack_start(GTK_BOX(vbox),playlist_use_dos_separator,FALSE,FALSE,0);
-#endif /* !G_OS_WIN32 */
-    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_use_dos_separator),PLAYLIST_USE_DOS_SEPARATOR);
-    gtk_widget_set_tooltip_text(playlist_use_dos_separator,_("This option replaces the UNIX directory "
-        "separator '/' into DOS separator '\\'."));
-
-    /* Playlist content */
-    if (!PlayListContentMaskModel)
-        PlayListContentMaskModel = gtk_list_store_new(MISC_COMBO_COUNT, G_TYPE_STRING);
-    else
-        gtk_list_store_clear(PlayListContentMaskModel);
-
-    Frame = gtk_frame_new(_("Playlist Content"));
-    gtk_box_pack_start(GTK_BOX(VBox),Frame,TRUE,TRUE,0);
-    vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, BOX_SPACING);
-    gtk_container_add(GTK_CONTAINER(Frame),vbox);
-    gtk_container_set_border_width (GTK_CONTAINER (vbox), BOX_SPACING);
-
-    playlist_content_none = gtk_radio_button_new_with_label(NULL,_("Write only list of files"));
-    gtk_box_pack_start(GTK_BOX(vbox),playlist_content_none,FALSE,FALSE,0);
-
-    playlist_content_filename = gtk_radio_button_new_with_label_from_widget(
-        GTK_RADIO_BUTTON(playlist_content_none),_("Write info using filename"));
-    gtk_box_pack_start(GTK_BOX(vbox),playlist_content_filename,FALSE,FALSE,0);
-
-    playlist_content_mask = 
gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(playlist_content_none), _("Write info using:"));
-    hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, BOX_SPACING);
-    gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,0);
-    gtk_box_pack_start(GTK_BOX(hbox),playlist_content_mask,FALSE,FALSE,0);
-    // Set a label, a combobox and un editor button in the 3rd radio button
-    PlayListContentMaskCombo = 
gtk_combo_box_new_with_model_and_entry(GTK_TREE_MODEL(PlayListContentMaskModel));
-    gtk_combo_box_set_entry_text_column(GTK_COMBO_BOX(PlayListContentMaskCombo),MISC_COMBO_TEXT);
-    gtk_box_pack_start(GTK_BOX(hbox),PlayListContentMaskCombo,FALSE,FALSE,0);
-    // History list
-    Load_Playlist_Content_Mask_List(PlayListContentMaskModel, MISC_COMBO_TEXT);
-    Add_String_To_Combo_List(PlayListContentMaskModel, PLAYLIST_CONTENT_MASK_VALUE);
-    gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(PlayListContentMaskCombo))), 
PLAYLIST_CONTENT_MASK_VALUE);
-
-    // Mask status icon
-    // Signal connection to check if mask is correct into the mask entry
-    g_signal_connect (gtk_bin_get_child (GTK_BIN (PlayListContentMaskCombo)),
-                      "changed", G_CALLBACK (entry_check_content_mask),
-                      NULL);
-
-    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_content_none),    PLAYLIST_CONTENT_NONE);
-    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_content_filename),PLAYLIST_CONTENT_FILENAME);
-    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_content_mask),    PLAYLIST_CONTENT_MASK);
-
-
-    gtk_widget_show_all(WritePlaylistWindow);
-    if (PLAYLIST_WINDOW_X > 0 && PLAYLIST_WINDOW_Y > 0)
-        gtk_window_move(GTK_WINDOW(WritePlaylistWindow),PLAYLIST_WINDOW_X,PLAYLIST_WINDOW_Y);
-
-    /* To initialize the mask status icon and visibility */
-    g_signal_emit_by_name(G_OBJECT(gtk_bin_get_child(GTK_BIN(PlayListNameMaskCombo))),"changed");
-    g_signal_emit_by_name(G_OBJECT(gtk_bin_get_child(GTK_BIN(PlayListContentMaskCombo))),"changed");
-}
-
-static void
-Destroy_Write_Playlist_Window (void)
-{
-    if (WritePlaylistWindow)
-    {
-        Write_Playlist_Window_Apply_Changes();
-
-        gtk_widget_destroy(WritePlaylistWindow);
-        WritePlaylistWindow = NULL;
-    }
-}
-
-/*
- * For the configuration file...
- */
-void Write_Playlist_Window_Apply_Changes (void)
-{
-    if (WritePlaylistWindow)
-    {
-        gint x, y;
-        GdkWindow *window;
-
-        window = gtk_widget_get_window (WritePlaylistWindow);
-
-        if ( window && gdk_window_is_visible(window) && 
gdk_window_get_state(window)!=GDK_WINDOW_STATE_MAXIMIZED )
-        {
-            /* Origin of the window. */
-            gdk_window_get_root_origin(window,&x,&y);
-            PLAYLIST_WINDOW_X = x;
-            PLAYLIST_WINDOW_Y = y;
-        }
-
-        /* List of variables also set in the function 'Playlist_Write_Button_Pressed' */
-        if (PLAYLIST_NAME) g_free(PLAYLIST_NAME);
-        PLAYLIST_NAME                 = 
g_strdup(gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(PlayListNameMaskCombo)))));
-        PLAYLIST_USE_MASK_NAME        = 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_use_mask_name));
-        PLAYLIST_USE_DIR_NAME         = 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_use_dir_name));
-
-        PLAYLIST_ONLY_SELECTED_FILES  = 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_only_selected_files));
-        PLAYLIST_FULL_PATH            = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_full_path));
-        PLAYLIST_RELATIVE_PATH        = 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_relative_path));
-        PLAYLIST_CREATE_IN_PARENT_DIR = 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_create_in_parent_dir));
-        PLAYLIST_USE_DOS_SEPARATOR    = 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_use_dos_separator));
-
-        PLAYLIST_CONTENT_NONE         = 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_content_none));
-        PLAYLIST_CONTENT_FILENAME     = 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_content_filename));
-        PLAYLIST_CONTENT_MASK         = 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_content_mask));
-        
-        if (PLAYLIST_CONTENT_MASK_VALUE) g_free(PLAYLIST_CONTENT_MASK_VALUE);
-        PLAYLIST_CONTENT_MASK_VALUE   = 
g_strdup(gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(PlayListContentMaskCombo)))));
-
-        /* Save combobox history lists before exit */
-        Save_Play_List_Name_List(PlayListNameMaskModel, MISC_COMBO_TEXT);
-        Save_Playlist_Content_Mask_List(PlayListContentMaskModel, MISC_COMBO_TEXT);
-    }
-}
-
-static void
-Playlist_Write_Button_Pressed (void)
-{
-    gchar *playlist_name = NULL;
-    gchar *playlist_path_utf8;      // Path
-    gchar *playlist_basename_utf8;  // Filename
-    gchar *playlist_name_utf8;      // Path + filename
-    gchar *temp;
-    GtkWidget *msgdialog;
-
-    // Check if playlist name was filled
-    if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_use_mask_name))
-    &&   g_utf8_strlen(gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(PlayListNameMaskCombo)))), 
-1)<=0 )
-        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_use_dir_name),TRUE);
-
-    /* List of variables also set in the function 'Write_Playlist_Window_Apply_Changes' */
-    /***if (PLAYLIST_NAME) g_free(PLAYLIST_NAME);
-    PLAYLIST_NAME                 = 
g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_BIN(PlayListNameMaskCombo)->child)));
-    PLAYLIST_USE_MASK_NAME        = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_use_mask_name));
-    PLAYLIST_USE_DIR_NAME         = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_use_dir_name));
-
-    PLAYLIST_ONLY_SELECTED_FILES  = 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_only_selected_files));
-    PLAYLIST_FULL_PATH            = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_full_path));
-    PLAYLIST_RELATIVE_PATH        = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_relative_path));
-    PLAYLIST_CREATE_IN_PARENT_DIR = 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_create_in_parent_dir));
-    PLAYLIST_USE_DOS_SEPARATOR    = 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_use_dos_separator));
-
-    PLAYLIST_CONTENT_NONE         = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_content_none));
-    PLAYLIST_CONTENT_FILENAME     = 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_content_filename));
-    PLAYLIST_CONTENT_MASK         = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_content_mask));
-    if (PLAYLIST_CONTENT_MASK_VALUE) g_free(PLAYLIST_CONTENT_MASK_VALUE);
-    PLAYLIST_CONTENT_MASK_VALUE   = 
g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_BIN(PlayListContentMaskCombo)->child)));***/
-    Write_Playlist_Window_Apply_Changes();
-
-    // Path of the playlist file (may be truncated later if PLAYLIST_CREATE_IN_PARENT_DIR is TRUE)
-    playlist_path_utf8 = filename_to_display(Browser_Get_Current_Path());
-
-    /* Build the playlist filename. */
-    if (PLAYLIST_USE_MASK_NAME)
-    {
-
-        if (!ETCore->ETFileList)
-            return;
-
-        Add_String_To_Combo_List(PlayListNameMaskModel, PLAYLIST_NAME);
-
-        // Generate filename from tag of the current selected file (hummm FIX ME)
-        temp = filename_from_display(PLAYLIST_NAME);
-        playlist_basename_utf8 = Scan_Generate_New_Filename_From_Mask(ETCore->ETFileDisplayed,temp,FALSE);
-        g_free(temp);
-
-        // Replace Characters (with scanner)
-        if (RFS_CONVERT_UNDERSCORE_AND_P20_INTO_SPACE)
-        {
-            Scan_Convert_Underscore_Into_Space(playlist_basename_utf8);
-            Scan_Convert_P20_Into_Space(playlist_basename_utf8);
-        }
-        if (RFS_CONVERT_SPACE_INTO_UNDERSCORE)
-        {
-            Scan_Convert_Space_Into_Underscore (playlist_basename_utf8);
-        }
-        if (RFS_REMOVE_SPACES)
-                                {
-                                   Scan_Remove_Spaces(playlist_basename_utf8);
-                                }
-
-    }else // PLAYLIST_USE_DIR_NAME
-    {
-
-        if ( strcmp(playlist_path_utf8,G_DIR_SEPARATOR_S)==0 )
-        {
-            playlist_basename_utf8 = g_strdup("playlist");
-        }else
-        {
-            gchar *tmp_string = g_strdup(playlist_path_utf8);
-            // Remove last '/'
-            if (tmp_string[strlen(tmp_string)-1]==G_DIR_SEPARATOR)
-                tmp_string[strlen(tmp_string)-1] = '\0';
-            // Get directory name
-            temp = g_path_get_basename(tmp_string);
-            playlist_basename_utf8 = g_strdup(temp);
-            g_free(tmp_string);
-            g_free(temp);
-        }
-
-    }
-
-    // Must be placed after "Build the playlist filename", as we can truncate the path!
-    if (PLAYLIST_CREATE_IN_PARENT_DIR)
-    {
-        if ( (strcmp(playlist_path_utf8,G_DIR_SEPARATOR_S) != 0) )
-        {
-            gchar *tmp;
-            // Remove last '/'
-            if (playlist_path_utf8[strlen(playlist_path_utf8)-1]==G_DIR_SEPARATOR)
-                playlist_path_utf8[strlen(playlist_path_utf8)-1] = '\0';
-            // Get parent directory
-            if ( (tmp=strrchr(playlist_path_utf8,G_DIR_SEPARATOR)) != NULL )
-                *(tmp + 1) = '\0';
-        }
-    }
-
-    // Generate path + filename of playlist
-    if (playlist_path_utf8[strlen(playlist_path_utf8)-1]==G_DIR_SEPARATOR)
-        playlist_name_utf8 = g_strconcat(playlist_path_utf8,playlist_basename_utf8,".m3u",NULL);
-    else
-        playlist_name_utf8 = 
g_strconcat(playlist_path_utf8,G_DIR_SEPARATOR_S,playlist_basename_utf8,".m3u",NULL);
-
-    g_free(playlist_path_utf8);
-    g_free(playlist_basename_utf8);
-
-    playlist_name = filename_from_display(playlist_name_utf8);
-
-    {
-        GFile *file = g_file_new_for_path (playlist_name);
-        GError *error = NULL;
-
-        if (!write_playlist (file, &error))
-        {
-            // Writing fails...
-            msgdialog = gtk_message_dialog_new(GTK_WINDOW(WritePlaylistWindow),
-                                               GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
-                                               GTK_MESSAGE_ERROR,
-                                               GTK_BUTTONS_CLOSE,
-                                               _("Cannot write playlist file '%s'"),
-                                               playlist_name_utf8);
-            gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (msgdialog),
-                                                      "%s", error->message);
-            gtk_window_set_title(GTK_WINDOW(msgdialog),_("Playlist File Error"));
-
-            gtk_dialog_run(GTK_DIALOG(msgdialog));
-            gtk_widget_destroy(msgdialog);
-            g_error_free (error);
-        }else
-        {
-            gchar *msg;
-            msg = g_strdup_printf(_("Written playlist file '%s'"),playlist_name_utf8);
-            /*msgbox = msg_box_new(_("Information"),
-                                   GTK_WINDOW(WritePlaylistWindow),
-                                   NULL,
-                                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
-                                                                  msg,
-                                                                  GTK_STOCK_DIALOG_INFO,
-                                   GTK_STOCK_OK, GTK_RESPONSE_OK,
-                                   NULL);
-            gtk_dialog_run(GTK_DIALOG(msgbox));
-            gtk_widget_destroy(msgbox);*/
-            Statusbar_Message(msg,TRUE);
-            g_free(msg);
-        }
-        g_object_unref (file);
-    }
-    g_free(playlist_name_utf8);
-    g_free(playlist_name);
-}
-
-/*
- * entry_check_content_mask:
- * @entry: the entry for which to check the mask
- * @user_data: user data set when the signal was connected
- *
- * Display an icon in the entry if the current text contains an invalid mask.
- */
-static void
-entry_check_content_mask (GtkEntry *entry, gpointer user_data)
-{
-    gchar *tmp  = NULL;
-    gchar *mask = NULL;
-
-    g_return_if_fail (entry != NULL);
-
-    mask = g_strdup (gtk_entry_get_text (entry));
-    if (!mask || strlen(mask)<1)
-        goto Bad_Mask;
-
-    while (mask)
-    {
-        if ( (tmp=strrchr(mask,'%'))==NULL )
-        {
-            /* There is no more code. */
-            /* No code in mask is accepted. */
-            goto Good_Mask;
-        }
-        if (strlen(tmp)>1 && (tmp[1]=='t' || tmp[1]=='a' || tmp[1]=='b' || tmp[1]=='y' ||
-                              tmp[1]=='g' || tmp[1]=='n' || tmp[1]=='l' || tmp[1]=='c' || tmp[1]=='i'))
-        {
-            /* The code is valid. */
-            /* No separator is accepted. */
-            *(mask+strlen(mask)-strlen(tmp)) = '\0';
-        }else
-        {
-            goto Bad_Mask;
-        }
-    }
-
-    Bad_Mask:
-        g_free(mask);
-        gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY,
-                                           "emblem-unreadable");
-        gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_SECONDARY,
-                                         _("Invalid scanner mask"));
-        return;
-
-    Good_Mask:
-        g_free(mask);
-        gtk_entry_set_icon_from_stock (entry, GTK_ENTRY_ICON_SECONDARY, NULL);
-        return;
-}
-
-/*
- * Function to replace UNIX ForwardSlash with a DOS BackSlash
- */
-static void
-Playlist_Convert_Forwardslash_Into_Backslash (const gchar *string)
-{
-    gchar *tmp;
-
-    while ((tmp=strchr(string,'/'))!=NULL)
-        *tmp = '\\';
-}
-
-
-/*
- * Write a playlist
- *  - 'playlist_name' in file system encoding (not UTF-8)
- */
-static gboolean
-write_playlist (GFile *file, GError **error)
-{
-    GFile *parent;
-    GFileOutputStream *ostream;
-    GString *to_write;
-    ET_File *etfile;
-    GList *l;
-    GList *etfilelist = NULL;
-    gchar *filename;
-    gchar *basedir;
-    gchar *temp;
-    gint   duration;
-
-    g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
-    ostream = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, error);
-
-    if (!ostream)
-    {
-        g_assert (error == NULL || *error != NULL);
-        return FALSE;
-    }
-
-    /* 'base directory' where is located the playlist. Used also to write file with a
-     * relative path for file located in this directory and sub-directories
-     */
-    parent = g_file_get_parent (file);
-    basedir = g_file_get_path (parent);
-    g_object_unref (parent);
-
-    // 1) First line of the file (if playlist content is not set to "write only list of files")
-    if (!PLAYLIST_CONTENT_NONE)
-    {
-        gsize bytes_written;
-
-        to_write = g_string_new ("#EXTM3U\r\n");
-
-        if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
-                                        to_write->str, to_write->len,
-                                        &bytes_written, NULL, error))
-        {
-            g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %" G_GSIZE_FORMAT
-                     "bytes of data were written", bytes_written,
-                     to_write->len);
-            g_assert (error == NULL || *error != NULL);
-            g_string_free (to_write, TRUE);
-            g_object_unref (ostream);
-            return FALSE;
-        }
-        g_string_free (to_write, TRUE);
-    }
-
-    if (PLAYLIST_ONLY_SELECTED_FILES)
-    {
-        GList *selfilelist = NULL;
-        GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(BrowserList));
-
-        selfilelist = gtk_tree_selection_get_selected_rows(selection, NULL);
-
-        for (l = selfilelist; l != NULL; l = g_list_next (l))
-        {
-            etfile = Browser_List_Get_ETFile_From_Path (l->data);
-            etfilelist = g_list_prepend (etfilelist, etfile);
-        }
-
-        etfilelist = g_list_reverse (etfilelist);
-
-        g_list_free_full (selfilelist, (GDestroyNotify)gtk_tree_path_free);
-    }else
-    {
-        etfilelist = g_list_first(ETCore->ETFileList);
-    }
-
-    for (l = etfilelist; l != NULL; l = g_list_next (l))
-    {
-        etfile = (ET_File *)l->data;
-        filename = ((File_Name *)etfile->FileNameCur->data)->value;
-        duration = ((ET_File_Info *)etfile->ETFileInfo)->duration;
-
-        if (PLAYLIST_RELATIVE_PATH)
-        {
-            // Keep only files in this directory and sub-dirs
-            if ( strncmp(filename,basedir,strlen(basedir))==0 )
-            {
-                gsize bytes_written;
-
-                // 2) Write the header
-                if (PLAYLIST_CONTENT_NONE)
-                {
-                    // No header written
-                }else if (PLAYLIST_CONTENT_FILENAME)
-                {
-
-                    // Header uses only filename
-                    temp = g_path_get_basename(filename);
-                    to_write = g_string_new ("#EXTINF:");
-                    /* Must be written in system encoding (not UTF-8)*/
-                    g_string_append_printf (to_write, "%d,%s\r\n", duration,
-                                            temp);
-
-                    if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
-                                                    to_write->str,
-                                                    to_write->len,
-                                                    &bytes_written, NULL,
-                                                    error))
-                    {
-                        g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %"
-                                 G_GSIZE_FORMAT "bytes of data were written",
-                                 bytes_written, to_write->len);
-                        g_assert (error == NULL || *error != NULL);
-                        g_string_free (to_write, TRUE);
-                        g_object_unref (ostream);
-                        return FALSE;
-                    }
-                    g_string_free (to_write, TRUE);
-                    g_free(temp);
-                }else if (PLAYLIST_CONTENT_MASK)
-                {
-                    // Header uses generated filename from a mask
-                    gchar *mask = 
filename_from_display(gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(PlayListContentMaskCombo)))));
-                    // Special case : we don't replace illegal characters and don't check if there is a 
directory separator in the mask.
-                    gchar *filename_generated_utf8 = Scan_Generate_New_Filename_From_Mask(etfile,mask,TRUE);
-                    gchar *filename_generated = filename_from_display(filename_generated_utf8);
-
-                    to_write = g_string_new ("#EXTINF:");
-                    /* Must be written in system encoding (not UTF-8)*/
-                    g_string_append_printf (to_write, "%d,%s\r\n", duration,
-                                            filename_generated);
-
-                    if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
-                                                    to_write->str,
-                                                    to_write->len,
-                                                    &bytes_written, NULL,
-                                                    error))
-                    {
-                        g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %"
-                                 G_GSIZE_FORMAT "bytes of data were written",
-                                 bytes_written, to_write->len);
-                        g_assert (error == NULL || *error != NULL);
-                        g_string_free (to_write, TRUE);
-                        g_object_unref (ostream);
-                        return FALSE;
-                    }
-                    g_string_free (to_write, TRUE);
-                    g_free(mask);
-                    g_free(filename_generated_utf8);
-                }
-
-                // 3) Write the file path
-                if (PLAYLIST_USE_DOS_SEPARATOR)
-                {
-                    gchar *filename_conv = g_strdup(filename+strlen(basedir)+1);
-                    Playlist_Convert_Forwardslash_Into_Backslash(filename_conv);
-
-                    to_write = g_string_new (filename_conv);
-                    /* Must be written in system encoding (not UTF-8)*/
-                    to_write = g_string_append (to_write, "\r\n");
-
-                    if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
-                                                    to_write->str,
-                                                    to_write->len,
-                                                    &bytes_written, NULL,
-                                                    error))
-                    {
-                        g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %"
-                                 G_GSIZE_FORMAT "bytes of data were written",
-                                 bytes_written, to_write->len);
-                        g_assert (error == NULL || *error != NULL);
-                        g_string_free (to_write, TRUE);
-                        g_object_unref (ostream);
-                        return FALSE;
-                    }
-                    g_string_free (to_write, TRUE);
-                    g_free(filename_conv);
-                }else
-                {
-                    to_write = g_string_new (filename+strlen(basedir)+1);
-                    /* Must be written in system encoding (not UTF-8)*/
-                    to_write = g_string_append (to_write, "\r\n");
-
-                    if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
-                                                    to_write->str,
-                                                    to_write->len,
-                                                    &bytes_written, NULL,
-                                                    error))
-                    {
-                        g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %"
-                                 G_GSIZE_FORMAT "bytes of data were written",
-                                 bytes_written, to_write->len);
-                        g_assert (error == NULL || *error != NULL);
-                        g_string_free (to_write, TRUE);
-                        g_object_unref (ostream);
-                        return FALSE;
-                    }
-                    g_string_free (to_write, TRUE);
-                }
-            }
-        }else // PLAYLIST_FULL_PATH
-        {
-            gsize bytes_written;
-
-            // 2) Write the header
-            if (PLAYLIST_CONTENT_NONE)
-            {
-                // No header written
-            }else if (PLAYLIST_CONTENT_FILENAME)
-            {
-                // Header uses only filename
-                temp = g_path_get_basename(filename);
-                to_write = g_string_new ("#EXTINF:");
-                /* Must be written in system encoding (not UTF-8)*/
-                g_string_append_printf (to_write, "%d,%s\r\n", duration,
-                                        temp);
-
-                if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
-                                                to_write->str, to_write->len,
-                                                &bytes_written, NULL, error))
-                {
-                    g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %"
-                             G_GSIZE_FORMAT" bytes of data were written",
-                             bytes_written, to_write->len);
-                    g_assert (error == NULL || *error != NULL);
-                    g_string_free (to_write, TRUE);
-                    g_object_unref (ostream);
-                    return FALSE;
-                }
-                g_string_free (to_write, TRUE);
-                g_free(temp);
-            }else if (PLAYLIST_CONTENT_MASK)
-            {
-                // Header uses generated filename from a mask
-                gchar *mask = 
filename_from_display(gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(PlayListContentMaskCombo)))));
-                gchar *filename_generated_utf8 = Scan_Generate_New_Filename_From_Mask(etfile,mask,TRUE);
-                gchar *filename_generated = filename_from_display(filename_generated_utf8);
-
-                to_write = g_string_new ("#EXTINF:");
-                /* Must be written in system encoding (not UTF-8)*/
-                g_string_append_printf (to_write, "%d,%s\r\n", duration,
-                                        filename_generated);
-
-                if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
-                                                to_write->str, to_write->len,
-                                                &bytes_written, NULL, error))
-                {
-                    g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %"
-                             G_GSIZE_FORMAT" bytes of data were written",
-                             bytes_written, to_write->len);
-                    g_assert (error == NULL || *error != NULL);
-                    g_string_free (to_write, TRUE);
-                    g_object_unref (ostream);
-                    return FALSE;
-                }
-                g_string_free (to_write, TRUE);
-                g_free(mask);
-                g_free(filename_generated_utf8);
-            }
-
-            // 3) Write the file path
-            if (PLAYLIST_USE_DOS_SEPARATOR)
-            {
-                gchar *filename_conv = g_strdup(filename);
-                Playlist_Convert_Forwardslash_Into_Backslash(filename_conv);
-
-                to_write = g_string_new (filename_conv);
-                /* Must be written in system encoding (not UTF-8)*/
-                to_write = g_string_append (to_write, "\r\n");
-
-                if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
-                                                to_write->str, to_write->len,
-                                                &bytes_written, NULL, error))
-                {
-                    g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %"
-                             G_GSIZE_FORMAT" bytes of data were written",
-                             bytes_written, to_write->len);
-                    g_assert (error == NULL || *error != NULL);
-                    g_string_free (to_write, TRUE);
-                    g_object_unref (ostream);
-                    return FALSE;
-                }
-                g_string_free (to_write, TRUE);
-                g_free(filename_conv);
-            }else
-            {
-                to_write = g_string_new (filename);
-                /* Must be written in system encoding (not UTF-8)*/
-                to_write = g_string_append (to_write, "\r\n");
-
-                if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
-                                                to_write->str, to_write->len,
-                                                &bytes_written, NULL, error))
-                {
-                    g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %"
-                             G_GSIZE_FORMAT" bytes of data were written",
-                             bytes_written, to_write->len);
-                    g_assert (error == NULL || *error != NULL);
-                    g_string_free (to_write, TRUE);
-                    g_object_unref (ostream);
-                    return FALSE;
-                }
-                g_string_free (to_write, TRUE);
-            }
-        }
-    }
-
-    if (PLAYLIST_ONLY_SELECTED_FILES)
-        g_list_free(etfilelist);
-
-    g_assert (error == NULL || *error == NULL);
-    g_object_unref (ostream);
-    g_free(basedir);
-    return TRUE;
-}
-
-
-
-
 /*****************************
  * Searching files functions *
  *****************************/
@@ -3699,32 +2918,6 @@ et_load_text_file_on_response (GtkDialog *dialog, gint response_id,
     }
 }
 
-/*
- * et_playlist_on_response:
- * @dialog: the dialog which emitted the response signal
- * @response_id: the response ID
- * @user_data: user data set when the signal was connected
- *
- * Signal handler for the write playlist dialog.
- */
-static void
-et_playlist_on_response (GtkDialog *dialog, gint response_id,
-                         gpointer user_data)
-{
-    switch (response_id)
-    {
-        case GTK_RESPONSE_OK:
-            Playlist_Write_Button_Pressed ();
-            break;
-        case GTK_RESPONSE_CANCEL:
-        case GTK_RESPONSE_DELETE_EVENT:
-            Destroy_Write_Playlist_Window ();
-            break;
-        default:
-            g_assert_not_reached ();
-    }
-}
-
 gchar *
 et_disc_number_to_string (const guint disc_number)
 {
diff --git a/src/misc.h b/src/misc.h
index 2ca216d..fe0c414 100644
--- a/src/misc.h
+++ b/src/misc.h
@@ -26,18 +26,6 @@
 
 G_BEGIN_DECLS
 
-GtkWidget *playlist_use_mask_name;
-GtkWidget *playlist_use_dir_name;
-GtkWidget *playlist_only_selected_files;
-GtkWidget *playlist_full_path;
-GtkWidget *playlist_relative_path;
-GtkWidget *playlist_create_in_parent_dir;
-GtkWidget *playlist_use_dos_separator;
-GtkWidget *playlist_content_none;
-GtkWidget *playlist_content_filename;
-GtkWidget *playlist_content_mask;
-
-
 /**************
  * Prototypes *
  **************/
@@ -91,10 +79,6 @@ gboolean et_run_program (const gchar *program_name, GList *args_list);
 void File_Selection_Window_For_File      (GtkWidget *entry);
 void File_Selection_Window_For_Directory (GtkWidget *entry);
 
-// Playlist window
-void Open_Write_Playlist_Window          (void);
-void Write_Playlist_Window_Apply_Changes (void);
-
 // Search file window
 void Open_Search_File_Window (void);
 void Search_File_Window_Apply_Changes (void);
diff --git a/src/playlist_dialog.c b/src/playlist_dialog.c
new file mode 100644
index 0000000..7949b0e
--- /dev/null
+++ b/src/playlist_dialog.c
@@ -0,0 +1,855 @@
+/* EasyTAG - tag editor for audio files
+ * Copyright (C) 2013  David King <amigadave amigadave com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include "playlist_dialog.h"
+
+#include <glib/gi18n.h>
+
+#include "bar.h"
+#include "browser.h"
+#include "charset.h"
+#include "easytag.h"
+#include "gtk2_compat.h"
+#include "log.h"
+#include "misc.h"
+#include "picture.h"
+#include "scan.h"
+#include "scan_dialog.h"
+#include "setting.h"
+
+/* TODO: Use G_DEFINE_TYPE_WITH_PRIVATE. */
+G_DEFINE_TYPE (EtPlaylistDialog, et_playlist_dialog, GTK_TYPE_DIALOG)
+
+#define et_playlist_dialog_get_instance_private(dialog) (dialog->priv)
+
+static const guint BOX_SPACING = 6;
+
+struct _EtPlaylistDialogPrivate
+{
+    GtkWidget *name_mask_combo;
+    GtkWidget *content_mask_combo;
+    GtkListStore *name_mask_model;
+    GtkListStore *content_mask_model;
+};
+
+/*
+ * Function to replace UNIX ForwardSlash with a DOS BackSlash
+ */
+static void
+convert_forwardslash_to_backslash (const gchar *string)
+{
+    gchar *tmp;
+
+    while ((tmp = strchr (string,'/')) != NULL)
+    {
+        *tmp = '\\';
+    }
+}
+
+/*
+ * Write a playlist
+ *  - 'playlist_name' in file system encoding (not UTF-8)
+ */
+static gboolean
+write_playlist (EtPlaylistDialog *self, GFile *file, GError **error)
+{
+    EtPlaylistDialogPrivate *priv;
+    GFile *parent;
+    GFileOutputStream *ostream;
+    GString *to_write;
+    ET_File *etfile;
+    GList *l;
+    GList *etfilelist = NULL;
+    gchar *filename;
+    gchar *basedir;
+    gchar *temp;
+    gint   duration;
+
+    g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+    priv = et_playlist_dialog_get_instance_private (self);
+
+    ostream = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, error);
+
+    if (!ostream)
+    {
+        g_assert (error == NULL || *error != NULL);
+        return FALSE;
+    }
+
+    /* 'base directory' where is located the playlist. Used also to write file with a
+     * relative path for file located in this directory and sub-directories
+     */
+    parent = g_file_get_parent (file);
+    basedir = g_file_get_path (parent);
+    g_object_unref (parent);
+
+    // 1) First line of the file (if playlist content is not set to "write only list of files")
+    if (!PLAYLIST_CONTENT_NONE)
+    {
+        gsize bytes_written;
+
+        to_write = g_string_new ("#EXTM3U\r\n");
+
+        if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
+                                        to_write->str, to_write->len,
+                                        &bytes_written, NULL, error))
+        {
+            g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %" G_GSIZE_FORMAT
+                     "bytes of data were written", bytes_written,
+                     to_write->len);
+            g_assert (error == NULL || *error != NULL);
+            g_string_free (to_write, TRUE);
+            g_object_unref (ostream);
+            return FALSE;
+        }
+        g_string_free (to_write, TRUE);
+    }
+
+    if (PLAYLIST_ONLY_SELECTED_FILES)
+    {
+        GList *selfilelist = NULL;
+        GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(BrowserList));
+
+        selfilelist = gtk_tree_selection_get_selected_rows(selection, NULL);
+
+        for (l = selfilelist; l != NULL; l = g_list_next (l))
+        {
+            etfile = Browser_List_Get_ETFile_From_Path (l->data);
+            etfilelist = g_list_prepend (etfilelist, etfile);
+        }
+
+        etfilelist = g_list_reverse (etfilelist);
+
+        g_list_free_full (selfilelist, (GDestroyNotify)gtk_tree_path_free);
+    }else
+    {
+        etfilelist = g_list_first(ETCore->ETFileList);
+    }
+
+    for (l = etfilelist; l != NULL; l = g_list_next (l))
+    {
+        etfile = (ET_File *)l->data;
+        filename = ((File_Name *)etfile->FileNameCur->data)->value;
+        duration = ((ET_File_Info *)etfile->ETFileInfo)->duration;
+
+        if (PLAYLIST_RELATIVE_PATH)
+        {
+            // Keep only files in this directory and sub-dirs
+            if ( strncmp(filename,basedir,strlen(basedir))==0 )
+            {
+                gsize bytes_written;
+
+                // 2) Write the header
+                if (PLAYLIST_CONTENT_NONE)
+                {
+                    // No header written
+                }else if (PLAYLIST_CONTENT_FILENAME)
+                {
+
+                    // Header uses only filename
+                    temp = g_path_get_basename(filename);
+                    to_write = g_string_new ("#EXTINF:");
+                    /* Must be written in system encoding (not UTF-8)*/
+                    g_string_append_printf (to_write, "%d,%s\r\n", duration,
+                                            temp);
+
+                    if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
+                                                    to_write->str,
+                                                    to_write->len,
+                                                    &bytes_written, NULL,
+                                                    error))
+                    {
+                        g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %"
+                                 G_GSIZE_FORMAT "bytes of data were written",
+                                 bytes_written, to_write->len);
+                        g_assert (error == NULL || *error != NULL);
+                        g_string_free (to_write, TRUE);
+                        g_object_unref (ostream);
+                        return FALSE;
+                    }
+                    g_string_free (to_write, TRUE);
+                    g_free(temp);
+                }else if (PLAYLIST_CONTENT_MASK)
+                {
+                    // Header uses generated filename from a mask
+                    gchar *mask = 
filename_from_display(gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(priv->content_mask_combo)))));
+                    // Special case : we don't replace illegal characters and don't check if there is a 
directory separator in the mask.
+                    gchar *filename_generated_utf8 = Scan_Generate_New_Filename_From_Mask(etfile,mask,TRUE);
+                    gchar *filename_generated = filename_from_display(filename_generated_utf8);
+
+                    to_write = g_string_new ("#EXTINF:");
+                    /* Must be written in system encoding (not UTF-8)*/
+                    g_string_append_printf (to_write, "%d,%s\r\n", duration,
+                                            filename_generated);
+
+                    if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
+                                                    to_write->str,
+                                                    to_write->len,
+                                                    &bytes_written, NULL,
+                                                    error))
+                    {
+                        g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %"
+                                 G_GSIZE_FORMAT "bytes of data were written",
+                                 bytes_written, to_write->len);
+                        g_assert (error == NULL || *error != NULL);
+                        g_string_free (to_write, TRUE);
+                        g_object_unref (ostream);
+                        return FALSE;
+                    }
+                    g_string_free (to_write, TRUE);
+                    g_free(mask);
+                    g_free(filename_generated_utf8);
+                }
+
+                // 3) Write the file path
+                if (PLAYLIST_USE_DOS_SEPARATOR)
+                {
+                    gchar *filename_conv = g_strdup(filename+strlen(basedir)+1);
+                    convert_forwardslash_to_backslash (filename_conv);
+
+                    to_write = g_string_new (filename_conv);
+                    /* Must be written in system encoding (not UTF-8)*/
+                    to_write = g_string_append (to_write, "\r\n");
+
+                    if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
+                                                    to_write->str,
+                                                    to_write->len,
+                                                    &bytes_written, NULL,
+                                                    error))
+                    {
+                        g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %"
+                                 G_GSIZE_FORMAT "bytes of data were written",
+                                 bytes_written, to_write->len);
+                        g_assert (error == NULL || *error != NULL);
+                        g_string_free (to_write, TRUE);
+                        g_object_unref (ostream);
+                        return FALSE;
+                    }
+                    g_string_free (to_write, TRUE);
+                    g_free(filename_conv);
+                }else
+                {
+                    to_write = g_string_new (filename+strlen(basedir)+1);
+                    /* Must be written in system encoding (not UTF-8)*/
+                    to_write = g_string_append (to_write, "\r\n");
+
+                    if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
+                                                    to_write->str,
+                                                    to_write->len,
+                                                    &bytes_written, NULL,
+                                                    error))
+                    {
+                        g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %"
+                                 G_GSIZE_FORMAT "bytes of data were written",
+                                 bytes_written, to_write->len);
+                        g_assert (error == NULL || *error != NULL);
+                        g_string_free (to_write, TRUE);
+                        g_object_unref (ostream);
+                        return FALSE;
+                    }
+                    g_string_free (to_write, TRUE);
+                }
+            }
+        }else // PLAYLIST_FULL_PATH
+        {
+            gsize bytes_written;
+
+            // 2) Write the header
+            if (PLAYLIST_CONTENT_NONE)
+            {
+                // No header written
+            }else if (PLAYLIST_CONTENT_FILENAME)
+            {
+                // Header uses only filename
+                temp = g_path_get_basename(filename);
+                to_write = g_string_new ("#EXTINF:");
+                /* Must be written in system encoding (not UTF-8)*/
+                g_string_append_printf (to_write, "%d,%s\r\n", duration,
+                                        temp);
+
+                if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
+                                                to_write->str, to_write->len,
+                                                &bytes_written, NULL, error))
+                {
+                    g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %"
+                             G_GSIZE_FORMAT" bytes of data were written",
+                             bytes_written, to_write->len);
+                    g_assert (error == NULL || *error != NULL);
+                    g_string_free (to_write, TRUE);
+                    g_object_unref (ostream);
+                    return FALSE;
+                }
+                g_string_free (to_write, TRUE);
+                g_free(temp);
+            }else if (PLAYLIST_CONTENT_MASK)
+            {
+                // Header uses generated filename from a mask
+                gchar *mask = 
filename_from_display(gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(priv->content_mask_combo)))));
+                gchar *filename_generated_utf8 = Scan_Generate_New_Filename_From_Mask(etfile,mask,TRUE);
+                gchar *filename_generated = filename_from_display(filename_generated_utf8);
+
+                to_write = g_string_new ("#EXTINF:");
+                /* Must be written in system encoding (not UTF-8)*/
+                g_string_append_printf (to_write, "%d,%s\r\n", duration,
+                                        filename_generated);
+
+                if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
+                                                to_write->str, to_write->len,
+                                                &bytes_written, NULL, error))
+                {
+                    g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %"
+                             G_GSIZE_FORMAT" bytes of data were written",
+                             bytes_written, to_write->len);
+                    g_assert (error == NULL || *error != NULL);
+                    g_string_free (to_write, TRUE);
+                    g_object_unref (ostream);
+                    return FALSE;
+                }
+                g_string_free (to_write, TRUE);
+                g_free(mask);
+                g_free(filename_generated_utf8);
+            }
+
+            // 3) Write the file path
+            if (PLAYLIST_USE_DOS_SEPARATOR)
+            {
+                gchar *filename_conv = g_strdup(filename);
+                convert_forwardslash_to_backslash(filename_conv);
+
+                to_write = g_string_new (filename_conv);
+                /* Must be written in system encoding (not UTF-8)*/
+                to_write = g_string_append (to_write, "\r\n");
+
+                if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
+                                                to_write->str, to_write->len,
+                                                &bytes_written, NULL, error))
+                {
+                    g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %"
+                             G_GSIZE_FORMAT" bytes of data were written",
+                             bytes_written, to_write->len);
+                    g_assert (error == NULL || *error != NULL);
+                    g_string_free (to_write, TRUE);
+                    g_object_unref (ostream);
+                    return FALSE;
+                }
+                g_string_free (to_write, TRUE);
+                g_free(filename_conv);
+            }else
+            {
+                to_write = g_string_new (filename);
+                /* Must be written in system encoding (not UTF-8)*/
+                to_write = g_string_append (to_write, "\r\n");
+
+                if (!g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
+                                                to_write->str, to_write->len,
+                                                &bytes_written, NULL, error))
+                {
+                    g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %"
+                             G_GSIZE_FORMAT" bytes of data were written",
+                             bytes_written, to_write->len);
+                    g_assert (error == NULL || *error != NULL);
+                    g_string_free (to_write, TRUE);
+                    g_object_unref (ostream);
+                    return FALSE;
+                }
+                g_string_free (to_write, TRUE);
+            }
+        }
+    }
+
+    if (PLAYLIST_ONLY_SELECTED_FILES)
+        g_list_free(etfilelist);
+
+    g_assert (error == NULL || *error == NULL);
+    g_object_unref (ostream);
+    g_free(basedir);
+    return TRUE;
+}
+
+static void
+write_button_clicked (EtPlaylistDialog *self)
+{
+    EtPlaylistDialogPrivate *priv;
+    gchar *playlist_name = NULL;
+    gchar *playlist_path_utf8;      // Path
+    gchar *playlist_basename_utf8;  // Filename
+    gchar *playlist_name_utf8;      // Path + filename
+    gchar *temp;
+    GtkWidget *msgdialog;
+
+    priv = et_playlist_dialog_get_instance_private (self);
+
+    // Check if playlist name was filled
+    if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_use_mask_name))
+    &&   g_utf8_strlen(gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(priv->name_mask_combo)))), 
-1)<=0 )
+        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_use_dir_name),TRUE);
+
+    /* List of variables also set in the function 'Write_Playlist_Window_Apply_Changes' */
+    /***if (PLAYLIST_NAME) g_free(PLAYLIST_NAME);
+    PLAYLIST_NAME                 = g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_BIN(name_mask_combo)->child)));
+    PLAYLIST_USE_MASK_NAME        = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_use_mask_name));
+    PLAYLIST_USE_DIR_NAME         = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_use_dir_name));
+
+    PLAYLIST_ONLY_SELECTED_FILES  = 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_only_selected_files));
+    PLAYLIST_FULL_PATH            = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_full_path));
+    PLAYLIST_RELATIVE_PATH        = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_relative_path));
+    PLAYLIST_CREATE_IN_PARENT_DIR = 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_create_in_parent_dir));
+    PLAYLIST_USE_DOS_SEPARATOR    = 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_use_dos_separator));
+
+    PLAYLIST_CONTENT_NONE         = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_content_none));
+    PLAYLIST_CONTENT_FILENAME     = 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_content_filename));
+    PLAYLIST_CONTENT_MASK         = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_content_mask));
+    if (PLAYLIST_CONTENT_MASK_VALUE) g_free(PLAYLIST_CONTENT_MASK_VALUE);
+    PLAYLIST_CONTENT_MASK_VALUE   = 
g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_BIN(content_mask_combo)->child)));***/
+    et_playlist_dialog_apply_changes (self);
+
+    // Path of the playlist file (may be truncated later if PLAYLIST_CREATE_IN_PARENT_DIR is TRUE)
+    playlist_path_utf8 = filename_to_display (Browser_Get_Current_Path ());
+
+    /* Build the playlist filename. */
+    if (PLAYLIST_USE_MASK_NAME)
+    {
+
+        if (!ETCore->ETFileList)
+            return;
+
+        Add_String_To_Combo_List (priv->name_mask_model, PLAYLIST_NAME);
+
+        // Generate filename from tag of the current selected file (hummm FIX ME)
+        temp = filename_from_display(PLAYLIST_NAME);
+        playlist_basename_utf8 = Scan_Generate_New_Filename_From_Mask(ETCore->ETFileDisplayed,temp,FALSE);
+        g_free(temp);
+
+        // Replace Characters (with scanner)
+        if (RFS_CONVERT_UNDERSCORE_AND_P20_INTO_SPACE)
+        {
+            Scan_Convert_Underscore_Into_Space(playlist_basename_utf8);
+            Scan_Convert_P20_Into_Space(playlist_basename_utf8);
+        }
+        if (RFS_CONVERT_SPACE_INTO_UNDERSCORE)
+        {
+            Scan_Convert_Space_Into_Underscore(playlist_basename_utf8);
+        }
+        if (RFS_REMOVE_SPACES)
+                                {
+                                   Scan_Remove_Spaces(playlist_basename_utf8);
+                                }
+
+    }else // PLAYLIST_USE_DIR_NAME
+    {
+
+        if ( strcmp(playlist_path_utf8,G_DIR_SEPARATOR_S)==0 )
+        {
+            playlist_basename_utf8 = g_strdup("playlist");
+        }else
+        {
+            gchar *tmp_string = g_strdup(playlist_path_utf8);
+            // Remove last '/'
+            if (tmp_string[strlen(tmp_string)-1]==G_DIR_SEPARATOR)
+                tmp_string[strlen(tmp_string)-1] = '\0';
+            // Get directory name
+            temp = g_path_get_basename(tmp_string);
+            playlist_basename_utf8 = g_strdup(temp);
+            g_free(tmp_string);
+            g_free(temp);
+        }
+
+    }
+
+    // Must be placed after "Build the playlist filename", as we can truncate the path!
+    if (PLAYLIST_CREATE_IN_PARENT_DIR)
+    {
+        if ( (strcmp(playlist_path_utf8,G_DIR_SEPARATOR_S) != 0) )
+        {
+            gchar *tmp;
+            // Remove last '/'
+            if (playlist_path_utf8[strlen(playlist_path_utf8)-1]==G_DIR_SEPARATOR)
+                playlist_path_utf8[strlen(playlist_path_utf8)-1] = '\0';
+            // Get parent directory
+            if ( (tmp=strrchr(playlist_path_utf8,G_DIR_SEPARATOR)) != NULL )
+                *(tmp + 1) = '\0';
+        }
+    }
+
+    // Generate path + filename of playlist
+    if (playlist_path_utf8[strlen(playlist_path_utf8)-1]==G_DIR_SEPARATOR)
+        playlist_name_utf8 = g_strconcat(playlist_path_utf8,playlist_basename_utf8,".m3u",NULL);
+    else
+        playlist_name_utf8 = 
g_strconcat(playlist_path_utf8,G_DIR_SEPARATOR_S,playlist_basename_utf8,".m3u",NULL);
+
+    g_free(playlist_path_utf8);
+    g_free(playlist_basename_utf8);
+
+    playlist_name = filename_from_display(playlist_name_utf8);
+
+    {
+        GFile *file = g_file_new_for_path (playlist_name);
+        GError *error = NULL;
+
+        if (!write_playlist (self, file, &error))
+        {
+            // Writing fails...
+            msgdialog = gtk_message_dialog_new (GTK_WINDOW (self),
+                                               GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+                                               GTK_MESSAGE_ERROR,
+                                               GTK_BUTTONS_CLOSE,
+                                               _("Cannot write playlist file '%s'"),
+                                               playlist_name_utf8);
+            gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (msgdialog),
+                                                      "%s", error->message);
+            gtk_window_set_title(GTK_WINDOW(msgdialog),_("Playlist File Error"));
+
+            gtk_dialog_run(GTK_DIALOG(msgdialog));
+            gtk_widget_destroy(msgdialog);
+            g_error_free (error);
+        }else
+        {
+            gchar *msg;
+            msg = g_strdup_printf(_("Written playlist file '%s'"),playlist_name_utf8);
+            /*msgbox = msg_box_new(_("Information"),
+                                   GTK_WINDOW(WritePlaylistWindow),
+                                   NULL,
+                                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+                                                                  msg,
+                                                                  GTK_STOCK_DIALOG_INFO,
+                                   GTK_STOCK_OK, GTK_RESPONSE_OK,
+                                   NULL);
+            gtk_dialog_run(GTK_DIALOG(msgbox));
+            gtk_widget_destroy(msgbox);*/
+            Statusbar_Message(msg,TRUE);
+            g_free(msg);
+        }
+        g_object_unref (file);
+    }
+    g_free(playlist_name_utf8);
+    g_free(playlist_name);
+}
+
+/*
+ * on_response:
+ * @dialog: the dialog which emitted the response signal
+ * @response_id: the response ID
+ * @user_data: user data set when the signal was connected
+ *
+ * Signal handler for the write playlist dialog.
+ */
+static void
+on_response (GtkDialog *dialog, gint response_id, gpointer user_data)
+{
+    switch (response_id)
+    {
+        case GTK_RESPONSE_OK:
+            write_button_clicked (ET_PLAYLIST_DIALOG (dialog));
+            break;
+        case GTK_RESPONSE_CANCEL:
+            et_playlist_dialog_apply_changes (ET_PLAYLIST_DIALOG (dialog));
+            gtk_widget_hide (GTK_WIDGET (dialog));
+            break;
+        case GTK_RESPONSE_DELETE_EVENT:
+            et_playlist_dialog_apply_changes (ET_PLAYLIST_DIALOG (dialog));
+            break;
+        default:
+            g_assert_not_reached ();
+    }
+}
+
+/*
+ * entry_check_content_mask:
+ * @entry: the entry for which to check the mask
+ * @user_data: user data set when the signal was connected
+ *
+ * Display an icon in the entry if the current text contains an invalid mask.
+ */
+static void
+entry_check_content_mask (GtkEntry *entry, gpointer user_data)
+{
+    gchar *tmp  = NULL;
+    gchar *mask = NULL;
+
+    g_return_if_fail (entry != NULL);
+
+    mask = g_strdup (gtk_entry_get_text (entry));
+    if (!mask || strlen(mask)<1)
+        goto Bad_Mask;
+
+    while (mask)
+    {
+        if ( (tmp=strrchr(mask,'%'))==NULL )
+        {
+            /* There is no more code. */
+            /* No code in mask is accepted. */
+            goto Good_Mask;
+        }
+        if (strlen(tmp)>1 && (tmp[1]=='t' || tmp[1]=='a' || tmp[1]=='b' || tmp[1]=='y' ||
+                              tmp[1]=='g' || tmp[1]=='n' || tmp[1]=='l' || tmp[1]=='c' || tmp[1]=='i'))
+        {
+            /* The code is valid. */
+            /* No separator is accepted. */
+            *(mask+strlen(mask)-strlen(tmp)) = '\0';
+        }else
+        {
+            goto Bad_Mask;
+        }
+    }
+
+    Bad_Mask:
+        g_free(mask);
+        gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY,
+                                           "emblem-unreadable");
+        gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_SECONDARY,
+                                         _("Invalid scanner mask"));
+        return;
+
+    Good_Mask:
+        g_free(mask);
+        gtk_entry_set_icon_from_stock (entry, GTK_ENTRY_ICON_SECONDARY, NULL);
+        return;
+}
+
+static void
+create_playlist_dialog (EtPlaylistDialog *self)
+{
+    EtPlaylistDialogPrivate *priv;
+    GtkDialog *dialog;
+    GtkWidget *frame;
+    GtkWidget *content_area;
+    GtkWidget *hbox;
+    GtkWidget *vbox;
+
+    priv = et_playlist_dialog_get_instance_private (self);
+    dialog = GTK_DIALOG (self);
+
+    gtk_window_set_title (GTK_WINDOW (self), _("Generate Playlist"));
+    gtk_window_set_transient_for (GTK_WINDOW (self), GTK_WINDOW (MainWindow));
+    gtk_window_set_destroy_with_parent (GTK_WINDOW (self), TRUE);
+    gtk_dialog_add_buttons (dialog, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                            GTK_STOCK_SAVE, GTK_RESPONSE_OK, NULL);
+    gtk_dialog_set_default_response (dialog, GTK_RESPONSE_OK);
+    g_signal_connect (dialog, "response", G_CALLBACK (on_response), NULL);
+    g_signal_connect (dialog, "delete-event",
+                      G_CALLBACK (gtk_widget_hide_on_delete), NULL);
+
+    content_area = gtk_dialog_get_content_area (dialog);
+    gtk_box_set_spacing (GTK_BOX (content_area), BOX_SPACING);
+    gtk_container_set_border_width (GTK_CONTAINER (content_area), BOX_SPACING);
+
+
+    /* Playlist name */
+    priv->name_mask_model = gtk_list_store_new (MISC_COMBO_COUNT,
+                                                G_TYPE_STRING);
+
+    frame = gtk_frame_new (_("M3U Playlist Name"));
+    gtk_box_pack_start (GTK_BOX (content_area), frame, TRUE, TRUE, 0);
+    vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, BOX_SPACING);
+    gtk_container_add (GTK_CONTAINER(frame), vbox);
+    gtk_container_set_border_width(GTK_CONTAINER (vbox), 4);
+
+    playlist_use_mask_name = gtk_radio_button_new_with_label(NULL, _("Use mask:"));
+    hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, BOX_SPACING);
+    gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,0);
+    gtk_box_pack_start(GTK_BOX(hbox),playlist_use_mask_name,FALSE,FALSE,0);
+    priv->name_mask_combo = gtk_combo_box_new_with_model_and_entry (GTK_TREE_MODEL (priv->name_mask_model));
+    g_object_unref (priv->name_mask_model);
+    gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (priv->name_mask_combo),
+                                         MISC_COMBO_TEXT);
+    gtk_box_pack_start (GTK_BOX (hbox), priv->name_mask_combo, FALSE, FALSE,
+                        0);
+    playlist_use_dir_name = gtk_radio_button_new_with_label_from_widget(
+        GTK_RADIO_BUTTON(playlist_use_mask_name),_("Use directory name"));
+    gtk_box_pack_start(GTK_BOX(vbox),playlist_use_dir_name,FALSE,FALSE,0);
+    // History list
+    Load_Play_List_Name_List (priv->name_mask_model, MISC_COMBO_TEXT);
+    Add_String_To_Combo_List (priv->name_mask_model, PLAYLIST_NAME);
+    gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->name_mask_combo))),
+                        PLAYLIST_NAME);
+
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_use_mask_name),PLAYLIST_USE_MASK_NAME);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_use_dir_name),PLAYLIST_USE_DIR_NAME);
+
+    // Mask status icon
+    // Signal connection to check if mask is correct into the mask entry
+    g_signal_connect (gtk_bin_get_child (GTK_BIN (priv->name_mask_combo)),
+                      "changed", G_CALLBACK (entry_check_content_mask),
+                      NULL);
+
+    /* Playlist options */
+    frame = gtk_frame_new (_("Playlist Options"));
+    gtk_box_pack_start (GTK_BOX (content_area), frame, TRUE, TRUE, 0);
+    vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, BOX_SPACING);
+    gtk_container_add (GTK_CONTAINER (frame), vbox);
+    gtk_container_set_border_width (GTK_CONTAINER (vbox), BOX_SPACING);
+
+    playlist_only_selected_files = gtk_check_button_new_with_label(_("Include only the selected files"));
+    gtk_box_pack_start(GTK_BOX(vbox),playlist_only_selected_files,FALSE,FALSE,0);
+    
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_only_selected_files),PLAYLIST_ONLY_SELECTED_FILES);
+    gtk_widget_set_tooltip_text(playlist_only_selected_files,_("If activated, only the selected files will 
be "
+        "written in the playlist file. Else, all the files will be written."));
+
+    playlist_full_path = gtk_radio_button_new_with_label(NULL,_("Use full path for files in playlist"));
+    gtk_box_pack_start(GTK_BOX(vbox),playlist_full_path,FALSE,FALSE,0);
+    playlist_relative_path = 
gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(playlist_full_path),
+        _("Use relative path for files in playlist"));
+    gtk_box_pack_start(GTK_BOX(vbox),playlist_relative_path,FALSE,FALSE,0);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_full_path),PLAYLIST_FULL_PATH);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_relative_path),PLAYLIST_RELATIVE_PATH);
+
+    // Create playlist in parent directory
+    playlist_create_in_parent_dir = gtk_check_button_new_with_label(_("Create playlist in the parent 
directory"));
+    gtk_box_pack_start(GTK_BOX(vbox),playlist_create_in_parent_dir,FALSE,FALSE,0);
+    
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_create_in_parent_dir),PLAYLIST_CREATE_IN_PARENT_DIR);
+    gtk_widget_set_tooltip_text(playlist_create_in_parent_dir,_("If activated, the playlist will be created "
+        "in the parent directory."));
+
+    // DOS Separator
+    playlist_use_dos_separator = gtk_check_button_new_with_label(_("Use DOS directory separator"));
+#ifndef G_OS_WIN32
+    /* This makes no sense under Win32, so we do not display it. */
+    gtk_box_pack_start(GTK_BOX(vbox),playlist_use_dos_separator,FALSE,FALSE,0);
+#endif /* !G_OS_WIN32 */
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_use_dos_separator),PLAYLIST_USE_DOS_SEPARATOR);
+    gtk_widget_set_tooltip_text(playlist_use_dos_separator,_("This option replaces the UNIX directory "
+        "separator '/' into DOS separator '\\'."));
+
+    /* Playlist content */
+    priv->content_mask_model = gtk_list_store_new (MISC_COMBO_COUNT,
+                                                   G_TYPE_STRING);
+
+    frame = gtk_frame_new (_("Playlist Content"));
+    gtk_box_pack_start (GTK_BOX (content_area), frame, TRUE, TRUE, 0);
+    vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, BOX_SPACING);
+    gtk_container_add (GTK_CONTAINER (frame), vbox);
+    gtk_container_set_border_width (GTK_CONTAINER (vbox), BOX_SPACING);
+
+    playlist_content_none = gtk_radio_button_new_with_label(NULL,_("Write only list of files"));
+    gtk_box_pack_start(GTK_BOX(vbox),playlist_content_none,FALSE,FALSE,0);
+
+    playlist_content_filename = gtk_radio_button_new_with_label_from_widget(
+        GTK_RADIO_BUTTON(playlist_content_none),_("Write info using filename"));
+    gtk_box_pack_start(GTK_BOX(vbox),playlist_content_filename,FALSE,FALSE,0);
+
+    playlist_content_mask = 
gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(playlist_content_none), _("Write info using:"));
+    hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, BOX_SPACING);
+    gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,0);
+    gtk_box_pack_start(GTK_BOX(hbox),playlist_content_mask,FALSE,FALSE,0);
+    // Set a label, a combobox and un editor button in the 3rd radio button
+    priv->content_mask_combo = gtk_combo_box_new_with_model_and_entry (GTK_TREE_MODEL 
(priv->content_mask_model));
+    g_object_unref (priv->content_mask_model);
+    gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (priv->content_mask_combo),
+                                         MISC_COMBO_TEXT);
+    gtk_box_pack_start (GTK_BOX (hbox), priv->content_mask_combo, FALSE, FALSE, 0);
+    // History list
+    Load_Playlist_Content_Mask_List (priv->content_mask_model,
+                                     MISC_COMBO_TEXT);
+    Add_String_To_Combo_List (priv->content_mask_model,
+                              PLAYLIST_CONTENT_MASK_VALUE);
+    gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->content_mask_combo))),
+                        PLAYLIST_CONTENT_MASK_VALUE);
+
+    // Mask status icon
+    // Signal connection to check if mask is correct into the mask entry
+    g_signal_connect (gtk_bin_get_child (GTK_BIN (priv->content_mask_combo)),
+                      "changed", G_CALLBACK (entry_check_content_mask),
+                      NULL);
+
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_content_none),    PLAYLIST_CONTENT_NONE);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_content_filename),PLAYLIST_CONTENT_FILENAME);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_content_mask),    PLAYLIST_CONTENT_MASK);
+
+
+    /* To initialize the mask status icon and visibility */
+    g_signal_emit_by_name (gtk_bin_get_child (GTK_BIN (priv->name_mask_combo)),
+                           "changed");
+    g_signal_emit_by_name (gtk_bin_get_child (GTK_BIN (priv->content_mask_combo)),
+                           "changed");
+}
+
+/*
+ * For the configuration file...
+ */
+void
+et_playlist_dialog_apply_changes (EtPlaylistDialog *self)
+{
+    EtPlaylistDialogPrivate *priv;
+
+    g_return_if_fail (ET_PLAYLIST_DIALOG (self));
+
+    priv = et_playlist_dialog_get_instance_private (self);
+
+    /* List of variables also set in the function 'Playlist_Write_Button_Pressed' */
+    if (PLAYLIST_NAME) g_free(PLAYLIST_NAME);
+    PLAYLIST_NAME = g_strdup (gtk_entry_get_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN 
(priv->name_mask_combo)))));
+    PLAYLIST_USE_MASK_NAME = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (playlist_use_mask_name));
+    PLAYLIST_USE_DIR_NAME = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (playlist_use_dir_name));
+
+    PLAYLIST_ONLY_SELECTED_FILES  = 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_only_selected_files));
+    PLAYLIST_FULL_PATH            = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_full_path));
+    PLAYLIST_RELATIVE_PATH        = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_relative_path));
+    PLAYLIST_CREATE_IN_PARENT_DIR = 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_create_in_parent_dir));
+    PLAYLIST_USE_DOS_SEPARATOR    = 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_use_dos_separator));
+
+    PLAYLIST_CONTENT_NONE         = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_content_none));
+    PLAYLIST_CONTENT_FILENAME     = 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_content_filename));
+    PLAYLIST_CONTENT_MASK         = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_content_mask));
+    
+    if (PLAYLIST_CONTENT_MASK_VALUE) g_free(PLAYLIST_CONTENT_MASK_VALUE);
+    PLAYLIST_CONTENT_MASK_VALUE = g_strdup (gtk_entry_get_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN 
(priv->content_mask_combo)))));
+
+    /* Save combobox history lists before exit */
+    Save_Play_List_Name_List (priv->name_mask_model, MISC_COMBO_TEXT);
+    Save_Playlist_Content_Mask_List (priv->content_mask_model,
+                                     MISC_COMBO_TEXT);
+}
+
+static void
+et_playlist_dialog_finalize (GObject *object)
+{
+    G_OBJECT_CLASS (et_playlist_dialog_parent_class)->finalize (object);
+}
+
+static void
+et_playlist_dialog_init (EtPlaylistDialog *self)
+{
+    self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, ET_TYPE_PLAYLIST_DIALOG,
+                                              EtPlaylistDialogPrivate);
+
+    create_playlist_dialog (self);
+}
+
+static void
+et_playlist_dialog_class_init (EtPlaylistDialogClass *klass)
+{
+    G_OBJECT_CLASS (klass)->finalize = et_playlist_dialog_finalize;
+
+    g_type_class_add_private (klass, sizeof (EtPlaylistDialogPrivate));
+}
+
+/*
+ * et_playlist_dialog_new:
+ *
+ * Create a new EtPlaylistDialog instance.
+ *
+ * Returns: a new #EtPlaylistDialog
+ */
+EtPlaylistDialog *
+et_playlist_dialog_new (void)
+{
+    return g_object_new (ET_TYPE_PLAYLIST_DIALOG, NULL);
+}
diff --git a/src/playlist_dialog.h b/src/playlist_dialog.h
new file mode 100644
index 0000000..af80777
--- /dev/null
+++ b/src/playlist_dialog.h
@@ -0,0 +1,67 @@
+/* EasyTAG - tag editor for audio files
+ * Copyright (C) 2013  David King <amigadave amigadave com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef ET_PLAYLIST_DIALOG_H_
+#define ET_PLAYLIST_DIALOG_H_
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#include "et_core.h"
+
+#define ET_TYPE_PLAYLIST_DIALOG (et_playlist_dialog_get_type ())
+#define ET_PLAYLIST_DIALOG(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), ET_TYPE_PLAYLIST_DIALOG, 
EtPlaylistDialog))
+
+typedef struct _EtPlaylistDialog EtPlaylistDialog;
+typedef struct _EtPlaylistDialogClass EtPlaylistDialogClass;
+typedef struct _EtPlaylistDialogPrivate EtPlaylistDialogPrivate;
+
+/* FIXME: Used by setting.c, remove when porting to GSettings. */
+GtkWidget *playlist_use_mask_name;
+GtkWidget *playlist_use_dir_name;
+GtkWidget *playlist_only_selected_files;
+GtkWidget *playlist_full_path;
+GtkWidget *playlist_relative_path;
+GtkWidget *playlist_create_in_parent_dir;
+GtkWidget *playlist_use_dos_separator;
+GtkWidget *playlist_content_none;
+GtkWidget *playlist_content_filename;
+GtkWidget *playlist_content_mask;
+
+
+struct _EtPlaylistDialog
+{
+    /*< private >*/
+    GtkDialog parent_instance;
+    EtPlaylistDialogPrivate *priv;
+};
+
+struct _EtPlaylistDialogClass
+{
+    /*< private >*/
+    GtkDialogClass parent_class;
+};
+
+GType et_playlist_dialog_get_type (void);
+EtPlaylistDialog *et_playlist_dialog_new (void);
+void et_playlist_dialog_apply_changes (EtPlaylistDialog *self);
+
+G_END_DECLS
+
+#endif /* !ET_PLAYLIST_DIALOG_H_ */
diff --git a/src/setting.c b/src/setting.c
index cfa1bce..9bcbf80 100644
--- a/src/setting.c
+++ b/src/setting.c
@@ -34,6 +34,7 @@
 
 #include "setting.h"
 #include "application_window.h"
+#include "playlist_dialog.h"
 #include "prefs.h"
 #include "bar.h"
 #include "easytag.h"
@@ -240,8 +241,6 @@ static const tConfigVariable Config_Variables[] =
     {"playlist_content_filename",               CV_TYPE_BOOL,    &PLAYLIST_CONTENT_FILENAME              },
     {"playlist_content_mask",                   CV_TYPE_BOOL,    &PLAYLIST_CONTENT_MASK                  },
     {"playlist_content_mask_value",             CV_TYPE_STRING,  &PLAYLIST_CONTENT_MASK_VALUE            },
-    {"playlist_window_x",                       CV_TYPE_INT,     &PLAYLIST_WINDOW_X                      },
-    {"playlist_window_y",                       CV_TYPE_INT,     &PLAYLIST_WINDOW_Y                      },
 
     {"load_file_run_scanner",                   CV_TYPE_BOOL,    &LOAD_FILE_RUN_SCANNER                  },
     {"load_file_window_x",                      CV_TYPE_INT,     &LOAD_FILE_WINDOW_X                     },
@@ -510,9 +509,6 @@ void Init_Config_Variables (void)
     PLAYLIST_CONTENT_MASK           = 0;
     PLAYLIST_CONTENT_MASK_VALUE     = g_strdup("%n/%l - %a - %b - %t");
 
-    PLAYLIST_WINDOW_X               = -1;
-    PLAYLIST_WINDOW_Y               = -1;
-
     /*
      * Load File window
      */
@@ -865,8 +861,9 @@ Apply_Changes_Of_UI (void)
     // Configuration of the cddb window (see cddb.c) - Function also called when destroying the window
     Cddb_Window_Apply_Changes();
 
-    // Configuration of the playlist window (see misc.c) - Function also called when destroying the window
-    Write_Playlist_Window_Apply_Changes();
+    /* Configuration of the playlist window (see playlist_dialog.c).
+     * Function also called when destroying the window. */
+    et_playlist_dialog_apply_changes (ET_PLAYLIST_DIALOG (et_application_window_get_playlist_dialog 
(ET_APPLICATION_WINDOW (MainWindow))));
 
     // Configuration of the search_file window (see misc.c) - Function also called when destroying the window
     Search_File_Window_Apply_Changes();
diff --git a/src/setting.h b/src/setting.h
index eaa1dcf..2a6500f 100644
--- a/src/setting.h
+++ b/src/setting.h
@@ -192,9 +192,6 @@ gint    PLAYLIST_CONTENT_FILENAME;
 gint    PLAYLIST_CONTENT_MASK;
 gchar  *PLAYLIST_CONTENT_MASK_VALUE;
 
-gint    PLAYLIST_WINDOW_X;
-gint    PLAYLIST_WINDOW_Y;
-
 /* "Load filenames from txt" window */
 gint    LOAD_FILE_RUN_SCANNER;
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]