[gnac/file-chooser] Improved file filters
- From: Benoît Dupasquier <bdupasqu src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnac/file-chooser] Improved file filters
- Date: Tue, 8 Jun 2010 20:30:44 +0000 (UTC)
commit aa0cf78c43d4a01470953bb6aa3a78d33a635643
Author: Benoît Dupasquier <bdupasqu src gnome org>
Date: Tue Jun 8 21:23:10 2010 +0100
Improved file filters
data/ui/gnac.xml | 105 +++++++++++++
src/gnac-main.c | 318 ++-------------------------------------
src/gnac-main.h | 5 -
src/gnac-playlist.c | 98 +++++++++----
src/gnac-playlist.h | 7 +
src/gnac-ui.c | 411 ++++++++++++++++++++++++++++++++++++++++++++++++++-
src/gnac-ui.h | 30 ++++
7 files changed, 635 insertions(+), 339 deletions(-)
---
diff --git a/data/ui/gnac.xml b/data/ui/gnac.xml
index 1141a46..39a5a35 100644
--- a/data/ui/gnac.xml
+++ b/data/ui/gnac.xml
@@ -387,4 +387,109 @@ Alexandre Roux <alexroux src gnome org></property>
</object>
</child>
</object>
+ <object class="GtkFileChooserDialog" id="gnac_file_chooser">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Open a File...</property>
+ <property name="modal">True</property>
+ <property name="window_position">center-on-parent</property>
+ <property name="type_hint">dialog</property>
+ <property name="has_separator">False</property>
+ <property name="select_multiple">True</property>
+ <property name="use_preview_label">False</property>
+ <property name="preview_widget_active">False</property>
+ <signal name="delete-event" handler="gtk_widget_hide_on_delete"/>
+ <signal name="key-press-event" handler="gnac_ui_file_chooser_key_press_event_cb"/>
+ <signal name="file-activated" handler="gnac_ui_file_chooser_file_activated_cb"/>
+ <signal name="response" handler="gnac_ui_file_chooser_response_cb"/>
+ <signal name="destroy" handler="gnac_ui_file_chooser_response_cb"/>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox2">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="bottom_padding">12</property>
+ <property name="left_padding">5</property>
+ <property name="right_padding">5</property>
+ <child>
+ <object class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkCheckButton" id="close_on_add_button">
+ <property name="label" translatable="yes">Close dialog on add</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="filters_combo">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area2">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="add_button">
+ <property name="label" translatable="yes">gtk-add</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="close_button">
+ <property name="label" translatable="yes">gtk-close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-1">add_button</action-widget>
+ <action-widget response="-7">close_button</action-widget>
+ </action-widgets>
+ </object>
</interface>
diff --git a/src/gnac-main.c b/src/gnac-main.c
index 074265f..3c481ea 100644
--- a/src/gnac-main.c
+++ b/src/gnac-main.c
@@ -27,7 +27,6 @@
#include "config.h"
#endif /* HAVE_CONFIG_H */
-#include <gdk/gdkkeysyms.h>
#include <gio/gio.h>
#include <glib/gi18n.h>
#include <gst/gst.h>
@@ -54,10 +53,6 @@
#include "profiles/gnac-profiles-utils.h"
-static GtkFileFilter *current_file_filter;
-static GtkFileFilter *default_file_filter;
-static GSList *filters;
-static gchar *current_directory;
static LibgnacConverter *converter;
static gboolean conversion_errors;
static guint64 prev_time_left;
@@ -72,9 +67,9 @@ static gboolean remember_overwrite = FALSE;
gint nb_files_total;
guint nb_files_added;
-GnacState state;
-GnacState prev_state;
-LibgnacMetadata *metadata;
+GnacState state;
+GnacState prev_state;
+LibgnacMetadata *metadata;
static const gchar *states[] = {
"GNAC_AUDIO_EMPTY_STATE",
@@ -336,179 +331,6 @@ gnac_add_files(GSList *files)
}
-static void
-gnac_file_chooser_foreach(gpointer data,
- gpointer user_data)
-{
- GFile *file;
- GSList **list;
-
- list = (GSList**) user_data;
- file = g_file_new_for_uri((gchar*)data);
- *list = g_slist_append(*list, file);
- g_free(data);
-}
-
-
-static void
-gnac_init_filters(void)
-{
- filters = (GSList*) NULL;
-
- /* To translators: translation of filters' name can be
- * found in /usr/share/mime */
- const gchar *lossy_mime[][2] = {
- { "audio/mpeg" , _("MP3 audio (*.mp3)") },
- { "audio/mp4" , _("MPEG-4 audio (*.aac, *.m4a, *.mp4)") },
- { "audio/x-musepack" , _("Musepack audio (*.mpc)") },
- { "audio/ogg" , _("Ogg Audio (*.oga)") },
- { "audio/vnd.rn-realaudio", _("RealAudio document (*.ra)") },
- { "audio/x-speex" , _("Speex audio (*.spx)") },
- { "audio/x-ms-wma" , _("Windows Media audio (*.wma)") },
- { NULL, NULL }
- };
-
- const gchar *lossless_mime[][2] = {
- /* XXX the Monkey's Audio plug-in has not yet been ported
- * to gstreamer-0.10 */
- /*{ "audio/x-ape" , _("Monkey's audio (*.ape)") },*/
- { "audio/x-flac" , _("Flac audio (*.flac)") },
- { "audio/x-wav" , _("WAV audio (*.wav)") },
- { "audio/x-wavpack", _("WavPack audio (*.wv)") },
- { NULL, NULL }
- };
-
- const gchar *supported_mime_playlists[][2] = {
- { "audio/x-mpegurl" , _("MP3 audio (streamed) (*.m3u)") },
- { "audio/x-scpls" , _("MP3 ShoutCast playlist (*.pls)") },
- { "application/xspf+xml", _("XSPF playlist (*.xspf)") },
- { NULL, NULL }
- };
-
- GtkFileFilter *file_filter_all = gtk_file_filter_new();
- gtk_file_filter_add_pattern(file_filter_all, "*");
- gtk_file_filter_set_name(file_filter_all, _("All files (*.*)"));
-
- GtkFileFilter* file_filter_supported = gtk_file_filter_new();
- gtk_file_filter_set_name(file_filter_supported, _("Supported files"));
-
- /* all supported types */
-
- guint i = 0;
- while (lossless_mime[i][0] != NULL) {
- gtk_file_filter_add_mime_type(file_filter_supported, lossless_mime[i][0]);
- i++;
- }
-
- i = 0;
- while (lossy_mime[i][0] != NULL) {
- gtk_file_filter_add_mime_type(file_filter_supported, lossy_mime[i][0]);
- i++;
- }
-
- i = 0;
- GtkFileFilter *file_filter_playlists = gtk_file_filter_new();
- gtk_file_filter_set_name(file_filter_playlists, _("Playlists files"));
- while (supported_mime_playlists[i][0] != NULL) {
- gtk_file_filter_add_mime_type(file_filter_supported, supported_mime_playlists[i][0]);
- gtk_file_filter_add_mime_type(file_filter_playlists, supported_mime_playlists[i][0]);
- i++;
- }
-
- filters = g_slist_append(filters, (gpointer) file_filter_all);
- filters = g_slist_append(filters, (gpointer) file_filter_supported);
- filters = g_slist_append(filters, (gpointer) file_filter_playlists);
-
- /* Lossless types */
-
- i = 0;
- GtkFileFilter *file_filter_lossless = gtk_file_filter_new();
- gtk_file_filter_set_name(file_filter_lossless, _("Lossless codecs"));
- while (lossless_mime[i][0] != NULL) {
- gtk_file_filter_add_mime_type(file_filter_lossless, lossless_mime[i][0]);
- i++;
- }
- filters = g_slist_append(filters, (gpointer) file_filter_lossless);
-
- /* Lossy types */
-
- i = 0;
- GtkFileFilter *file_filter_lossy = gtk_file_filter_new();
- gtk_file_filter_set_name(file_filter_lossy, _("Lossy codecs"));
- while (lossy_mime[i][0] != NULL) {
- gtk_file_filter_add_mime_type(file_filter_lossy, lossy_mime[i][0]);
- i++;
- }
- filters = g_slist_append(filters, (gpointer) file_filter_lossy);
-
- /* Create filters for each kind of audio files */
-
- i = 0;
- GtkFileFilter *file_filter_tmp;
- while (lossless_mime[i][0] != NULL) {
- file_filter_tmp = gtk_file_filter_new();
- gtk_file_filter_add_mime_type(file_filter_tmp, lossless_mime[i][0]);
- gtk_file_filter_set_name(file_filter_tmp, lossless_mime[i][1]);
- filters = g_slist_append(filters, (gpointer) file_filter_tmp);
- i++;
- }
-
- i = 0;
- while (lossy_mime[i][0] != NULL) {
- file_filter_tmp = gtk_file_filter_new();
- gtk_file_filter_add_mime_type(file_filter_tmp, lossy_mime[i][0]);
- gtk_file_filter_set_name(file_filter_tmp, lossy_mime[i][1]);
- filters = g_slist_append(filters, (gpointer) file_filter_tmp);
- i++;
- }
-
- /* Create filters for playlists */
-
- i = 0;
- while (supported_mime_playlists[i][0] != NULL) {
- file_filter_tmp = gtk_file_filter_new();
- gtk_file_filter_add_mime_type(file_filter_tmp, supported_mime_playlists[i][0]);
- gtk_file_filter_set_name(file_filter_tmp, supported_mime_playlists[i][1]);
- filters = g_slist_append(filters, (gpointer) file_filter_tmp);
- i++;
- }
-
- GSList *next;
- for (next = filters; next; next = next->next) {
- g_object_ref(G_OBJECT(next->data));
- }
- current_file_filter = file_filter_supported;
- default_file_filter = file_filter_supported;
-}
-
-
-static void
-gnac_add_filters(GtkFileChooser *file_chooser)
-{
- GSList *next;
-
- for (next = filters; next; next = next->next) {
- gtk_file_chooser_add_filter (file_chooser, GTK_FILE_FILTER(next->data));
- }
-
- /* we want to keep track of the chosen file filter
- * (Supported files at the beginning) */
- gtk_file_chooser_set_filter(file_chooser, current_file_filter);
-}
-
-
-static void
-gnac_unref_filters(void)
-{
- GSList *next;
- for (next = filters; next; next = next->next) {
- g_object_ref_sink(G_OBJECT(next->data));
- g_object_unref(next->data);
- }
- g_slist_free(filters);
-}
-
-
void
gnac_add_file(GFile *file)
{
@@ -530,18 +352,13 @@ gnac_add_file(GFile *file)
filter_info.mime_type = g_file_info_get_content_type(info);
if (filter_info.mime_type != NULL) {
- /* Playlists */
- if (g_ascii_strcasecmp(filter_info.mime_type, "audio/x-mpegurl") == 0) {
- gnac_playlist_parse_m3u(file);
- } else if (g_ascii_strcasecmp(filter_info.mime_type, "audio/x-scpls") == 0) {
- gnac_playlist_parse_pls(file);
- } else if (g_ascii_strcasecmp(filter_info.mime_type, "application/xspf+xml") == 0) {
- gnac_playlist_parse_xspf(file);
-
- /* Filter the files */
- } else if (gtk_file_filter_filter(current_file_filter, &filter_info)) {
-
- /* No duplicate files */
+ /* Check whether we have a playlist */
+ if (gnac_playlist_is_mime_playlist(filter_info.mime_type)) {
+ gnac_playlist_parse(file, filter_info.mime_type);
+ /* Check whether the file format is supported */
+ } else if (gtk_file_filter_filter(gnac_ui_get_current_filter(),
+ &filter_info))
+ {
libgnac_info("Add file %s", g_file_get_uri(file));
libgnac_converter_add(converter, file, &error);
}
@@ -601,13 +418,9 @@ gnac_on_ui_destroy_cb(GtkWidget *widget,
if (thread != NULL) g_thread_join(thread);
}
- g_free(current_directory);
-
g_object_unref(converter);
g_object_unref(metadata);
- gnac_unref_filters();
-
gnac_properties_destroy();
gnac_prefs_destroy();
gnac_profiles_destroy();
@@ -619,74 +432,6 @@ gnac_on_ui_destroy_cb(GtkWidget *widget,
}
-static void
-gnac_file_chooser_file_activated_cb(GtkFileChooser *chooser,
- gpointer user_data)
-{
- gnac_file_chooser_response_cb(GTK_DIALOG(chooser), GTK_RESPONSE_NONE, NULL);
-}
-
-
-static gboolean
-gnac_file_chooser_key_press_event_cb(GtkWidget *widget,
- GdkEventKey *event,
- gpointer user_data)
-{
- if (event->type == GDK_KEY_PRESS && event->keyval == GDK_Return)
- {
- gnac_file_chooser_response_cb(GTK_DIALOG(widget), GTK_RESPONSE_NONE, NULL);
- return TRUE;
- }
- return FALSE;
-}
-
-
-void
-gnac_file_chooser_response_cb(GtkDialog *dialog,
- gint response,
- gpointer user_data)
-{
- GSList *list_path;
- GSList *list_files = NULL;
-
- GtkWidget *close_on_add_button;
-
- switch (response) {
- /* Add button */
- case GTK_RESPONSE_NONE:
-
- /* Set the current file filter */
- current_file_filter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(dialog));
- list_path = gtk_file_chooser_get_uris(GTK_FILE_CHOOSER(dialog));
-
- /* Add the differents files */
- g_slist_foreach(list_path,(GFunc) gnac_file_chooser_foreach, (gpointer) &list_files);
-
- /* free the list */
- g_slist_free(list_path);
-
- /* add files */
- gnac_add_files(list_files);
-
- /* Do we have to close de file chooser? */
- close_on_add_button = gtk_file_chooser_get_extra_widget(GTK_FILE_CHOOSER(dialog));
-
- /* Get the current uri */
- g_free(current_directory);
- current_directory = gtk_file_chooser_get_current_folder_uri(GTK_FILE_CHOOSER(dialog));
-
- if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(close_on_add_button))) return;
-
- break;
-
- case GTK_RESPONSE_CLOSE:
- default:
- break;
- }
- gtk_widget_destroy(GTK_WIDGET(dialog));
-}
-
-
static gboolean
gnac_on_converter_overwrite_cb(LibgnacConverter *converter,
gpointer file,
@@ -1057,37 +802,7 @@ void
gnac_on_ui_add_cb(GtkAction *action,
gpointer data)
{
- GtkWidget *close_on_add_button;
- GtkWidget *file_chooser;
-
- file_chooser = gtk_file_chooser_dialog_new(_("Open a File..."),
- GTK_WINDOW(data),
- GTK_FILE_CHOOSER_ACTION_OPEN,
- GTK_STOCK_ADD, GTK_RESPONSE_NONE,
- GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
- NULL);
-
- gtk_window_set_type_hint(GTK_WINDOW(file_chooser), GDK_WINDOW_TYPE_HINT_DIALOG);
-
- gtk_file_chooser_set_current_folder_uri(GTK_FILE_CHOOSER(file_chooser),
- current_directory);
- gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(file_chooser), TRUE);
-
- close_on_add_button = gtk_check_button_new_with_label(_("Close dialog on add"));
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(close_on_add_button),TRUE);
- gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(file_chooser),
- close_on_add_button);
-
- gnac_add_filters(GTK_FILE_CHOOSER(file_chooser));
-
- g_signal_connect(file_chooser, "response",
- G_CALLBACK(gnac_file_chooser_response_cb), data);
- g_signal_connect(file_chooser, "key-press-event",
- G_CALLBACK(gnac_file_chooser_key_press_event_cb), data);
- g_signal_connect(file_chooser, "file-activated",
- G_CALLBACK(gnac_file_chooser_file_activated_cb), data);
-
- gtk_dialog_run(GTK_DIALOG(file_chooser));
+ gtk_widget_show_all(gnac_ui_get_file_chooser());
}
@@ -1161,7 +876,7 @@ gnac_on_ui_drag_data_received_cb(GtkWidget *widget,
gint index = 0;
/* Disable any filtering for DnD. */
- current_file_filter = default_file_filter;
+ gnac_ui_reset_file_filter();
uris = gtk_selection_data_get_uris(selection_data);
@@ -1223,12 +938,12 @@ main(gint argc,
textdomain(GETTEXT_PACKAGE);
#endif /* ENABLE_NLS */
- /* Parse command line arguments */
- gnac_options_init(argc, argv);
-
/* Set a name for the application */
g_set_application_name(PACKAGE_NAME);
+ /* Parse command line arguments */
+ gnac_options_init(argc, argv);
+
/* Initialisation of libraries */
gdk_threads_init();
@@ -1240,12 +955,9 @@ main(gint argc,
/* Init gstreamer plugins helper*/
gst_pb_utils_init();
- gnac_init_filters();
gnac_gconf_init();
gnac_profiles_init();
- current_directory = g_strdup(g_get_home_dir());
-
/* Initialise converter and connect signals */
metadata = LIBGNAC_METADATA(libgnac_metadata_new());
converter = LIBGNAC_CONVERTER(libgnac_converter_new(metadata));
diff --git a/src/gnac-main.h b/src/gnac-main.h
index bea7156..b4e913f 100644
--- a/src/gnac-main.h
+++ b/src/gnac-main.h
@@ -104,11 +104,6 @@ gnac_on_file_monitor_changed_cb(GFileMonitor *monitor,
GFileMonitorEvent event_type,
gpointer user_data);
-void
-gnac_file_chooser_response_cb(GtkDialog *dialog,
- gint response,
- gpointer user_data);
-
G_END_DECLS
#endif /* GNAC_MAIN_H */
diff --git a/src/gnac-playlist.c b/src/gnac-playlist.c
index 165f370..42333e4 100755
--- a/src/gnac-playlist.c
+++ b/src/gnac-playlist.c
@@ -34,8 +34,41 @@
#include "gnac-main.h"
#include "gnac-playlist.h"
-// TODO convert content to utf8!
-// work with utf8, needed for all gnome programs
+
+typedef struct {
+ const gchar *mime;
+ void (*handler)(GFile *file);
+} GnacPlaylistMimeHandler;
+
+
+static GnacPlaylistMimeHandler mime_playlist[] = {
+ { "audio/x-mpegurl" , &gnac_playlist_parse_m3u },
+ { "audio/x-scpls" , &gnac_playlist_parse_pls },
+ { "application/xspf+xml", &gnac_playlist_parse_xspf },
+ { NULL, NULL }
+};
+
+
+static void
+gnac_playlist_resolve_uri_and_add(GFile *parent,
+ const gchar *filename)
+{
+ GFile *file;
+
+ if (!g_utf8_validate(filename, -1, NULL)) {
+ g_printerr("%s: %s\n", _("Invalid UTF-8 filename"), filename);
+ return;
+ }
+
+ if (g_str_has_prefix(filename, "file://")) {
+ file = g_file_new_for_uri(filename);
+ } else {
+ file = g_file_get_child(parent, filename);
+ }
+
+ gnac_add_file(file);
+}
+
static gchar *
gnac_playlist_read_file(GFile *file) {
@@ -55,11 +88,36 @@ gnac_playlist_read_file(GFile *file) {
}
+gboolean
+gnac_playlist_is_mime_playlist(const gchar *mime)
+{
+ guint i;
+ for (i = 0; mime_playlist[i].mime; i++) {
+ if (g_ascii_strcasecmp(mime, mime_playlist[i].mime) == 0) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+void
+gnac_playlist_parse(GFile *file,
+ const gchar *mime)
+{
+ guint i;
+ for (i = 0; mime_playlist[i].mime; i++) {
+ if (g_ascii_strcasecmp(mime, mime_playlist[i].mime) == 0) {
+ mime_playlist[i].handler(file);
+ }
+ }
+}
+
+
void
gnac_playlist_parse_m3u(GFile *file)
{
GFile *parent;
- GFile *child;
gchar *contents;
parent = g_file_get_parent(file);
@@ -70,18 +128,12 @@ gnac_playlist_parse_m3u(GFile *file)
gchar **lines;
lines = g_strsplit(contents, "\n", -1);
- gint i, len;
+ gint i;
for (i = 0; lines[i]; i++) {
/* skip comments and empty lines */
if (!*lines[i] || *lines[i] == '#') continue;
g_strchomp(lines[i]);
- len = g_utf8_strlen(lines[i], -1);
- if (!g_utf8_validate(lines[i], -1, NULL)) {
- g_printerr("%s: %s\n", _("Invalid UTF-8 filename"), lines[i]);
- } else {
- child = g_file_get_child(parent, lines[i]);
- gnac_add_file(child);
- }
+ gnac_playlist_resolve_uri_and_add(parent, lines[i]);
}
g_strfreev(lines);
@@ -94,8 +146,7 @@ void
gnac_playlist_parse_pls(GFile *file)
{
GFile *parent;
- GFile *child;
- gchar *contents;
+ gchar *contents;
parent = g_file_get_parent(file);
contents = gnac_playlist_read_file(file);
@@ -105,7 +156,7 @@ gnac_playlist_parse_pls(GFile *file)
gchar **lines;
lines = g_strsplit(contents, "\n", -1);
- gint i, len;
+ gint i;
for (i = 0; lines[i]; i++) {
/* skip empty lines */
if (!*lines[i]) continue;
@@ -115,13 +166,7 @@ gnac_playlist_parse_pls(GFile *file)
key = g_utf8_strdown(pair[0], -1);
if (pair[1] && g_str_has_prefix(key, "file")) {
g_strchomp(pair[1]);
- len = g_utf8_strlen(lines[i], -1);
- if (!g_utf8_validate(pair[1], -1, NULL)) {
- g_printerr("%s: %s\n", _("Invalid UTF-8 filename"), pair[1]);
- } else {
- child = g_file_get_child(parent, pair[1]);
- gnac_add_file(child);
- }
+ gnac_playlist_resolve_uri_and_add(parent, pair[1]);
}
g_free(key);
@@ -138,8 +183,7 @@ void
gnac_playlist_parse_xspf(GFile *file)
{
GFile *parent;
- GFile *child;
- gchar *contents;
+ gchar *contents;
parent = g_file_get_parent(file);
contents = gnac_playlist_read_file(file);
@@ -157,12 +201,8 @@ gnac_playlist_parse_xspf(GFile *file)
if (g_str_has_prefix(line, "<location>")) {
line = g_strsplit(line, ">", 2)[1];
line = g_strsplit(line, "<", 2)[0];
- if (!g_utf8_validate(line, -1, NULL)) {
- g_printerr("%s: %s\n", _("Invalid UTF-8 filename"), line);
- } else {
- child = g_file_get_child(parent, line);
- gnac_add_file(child);
- }
+ g_strchomp(line);
+ gnac_playlist_resolve_uri_and_add(parent, line);
}
}
diff --git a/src/gnac-playlist.h b/src/gnac-playlist.h
index bf8801a..fc8ac5c 100755
--- a/src/gnac-playlist.h
+++ b/src/gnac-playlist.h
@@ -30,6 +30,13 @@
G_BEGIN_DECLS
+gboolean
+gnac_playlist_is_mime_playlist(const gchar *mime);
+
+void
+gnac_playlist_parse(GFile *file,
+ const gchar *mime);
+
void
gnac_playlist_parse_m3u(GFile *file);
diff --git a/src/gnac-ui.c b/src/gnac-ui.c
index 7e17ee2..07204ae 100644
--- a/src/gnac-ui.c
+++ b/src/gnac-ui.c
@@ -27,6 +27,7 @@
#include "config.h"
#endif /* HAVE_CONFIG_H */
+#include <gdk/gdkkeysyms.h>
#include <glib/gi18n.h>
#include <glib/gprintf.h>
@@ -39,10 +40,15 @@
#include "gnac-gconf.h"
#include "profiles/gnac-profiles.h"
+extern GnacState state;
extern LibgnacMetadata *metadata;
+static GSList *filters;
static GtkBuilder *gnac_main_builder = NULL;
+static GtkFileFilter *default_file_filter;
static GtkStatusIcon *trayicon = NULL;
+static GtkWidget *gnac_file_chooser;
+static gchar *current_directory;
static gchar *status_msg = NULL;
static gchar *tooltip_path = NULL;
static gchar *progress_msg = NULL;
@@ -60,8 +66,6 @@ static GtkTargetEntry target_list[] = {
static guint n_targets = G_N_ELEMENTS(target_list);
-extern GnacState state;
-
static void
gnac_about_url_hook(GtkAboutDialog *dialog,
@@ -90,6 +94,401 @@ gnac_about_email_hook(GtkAboutDialog *dialog,
}
+static void
+gnac_ui_file_chooser_unref_filters(void)
+{
+ GSList *f;
+ for (f = filters; f; f = f->next) {
+ g_object_unref(f->data);
+ }
+ g_slist_free(f);
+}
+
+
+static void
+gnac_ui_file_chooser_dispose(void)
+{
+ gnac_ui_file_chooser_unref_filters();
+ gtk_widget_destroy(gnac_file_chooser);
+}
+
+
+static void
+gnac_ui_file_chooser_cell_data_func(GtkCellLayout *layout,
+ GtkCellRenderer *cell,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ GtkFileFilter *filter;
+ gtk_tree_model_get(model, iter, 0, &filter, -1);
+ g_object_set(cell, "text", gtk_file_filter_get_name(filter), NULL);
+}
+
+
+static GtkTreeModel *
+gnac_ui_file_chooser_get_filters_model(void)
+{
+ guint i;
+ GSList *f;
+ GtkFileFilter *filter;
+ GtkTreeIter iter1, iter2, iter3;
+ GtkTreeStore *store;
+
+ /* To translators: translation of filters' name can be
+ * found in /usr/share/mime */
+ const gchar *lossy_mime[][2] = {
+ { "audio/mpeg" , _("MP3 audio") },
+ { "audio/mp4" , _("MPEG-4 audio") },
+ { "audio/x-musepack" , _("Musepack audio") },
+ { "audio/ogg" , _("Ogg Audio") },
+ { "audio/vnd.rn-realaudio", _("RealAudio document") },
+ { "audio/x-speex" , _("Speex audio") },
+ { "audio/x-ms-wma" , _("Windows Media audio") },
+ { NULL, NULL }
+ };
+
+ const gchar *lossless_mime[][2] = {
+ /* XXX the Monkey's Audio plug-in has not yet been ported
+ * to gstreamer-0.10 */
+ /*{ "audio/x-ape" , _("Monkey's audio") },*/
+ { "audio/x-flac" , _("Flac audio") },
+ { "audio/x-wav" , _("WAV audio") },
+ { "audio/x-wavpack", _("WavPack audio") },
+ { NULL, NULL }
+ };
+
+ const gchar *playlists_mime[][2] = {
+ { "audio/x-mpegurl" , _("MP3 audio (streamed)") },
+ { "audio/x-scpls" , _("MP3 ShoutCast playlist") },
+ { "application/xspf+xml", _("XSPF playlist") },
+ { NULL, NULL }
+ };
+
+ filters = NULL;
+ store = gtk_tree_store_new(1, G_TYPE_POINTER);
+
+ /* All files */
+ filter = gtk_file_filter_new();
+ gtk_file_filter_add_pattern(filter, "*");
+ gtk_file_filter_set_name(filter, _("All files"));
+ gtk_tree_store_append(store, &iter1, NULL);
+ gtk_tree_store_set(store, &iter1, 0, filter, -1);
+ filters = g_slist_append(filters, (gpointer)filter);
+
+ /* Supported files */
+ filter = gtk_file_filter_new();
+ gtk_file_filter_set_name(filter, _("Supported files"));
+ i = 0;
+ while (lossless_mime[i][0]) {
+ gtk_file_filter_add_mime_type(filter, lossless_mime[i][0]);
+ i++;
+ }
+ i = 0;
+ while (lossy_mime[i][0]) {
+ gtk_file_filter_add_mime_type(filter, lossy_mime[i][0]);
+ i++;
+ }
+ i = 0;
+ while (playlists_mime[i][0]) {
+ gtk_file_filter_add_mime_type(filter, playlists_mime[i][0]);
+ i++;
+ }
+ gtk_tree_store_append(store, &iter1, NULL);
+ gtk_tree_store_set(store, &iter1, 0, filter, -1);
+ filters = g_slist_append(filters, (gpointer)filter);
+ default_file_filter = filter;
+
+ /* Audio files */
+ filter = gtk_file_filter_new();
+ gtk_file_filter_set_name(filter, _("Audio files"));
+ i = 0;
+ while (lossless_mime[i][0]) {
+ gtk_file_filter_add_mime_type(filter, lossless_mime[i][0]);
+ i++;
+ }
+ i = 0;
+ while (lossy_mime[i][0]) {
+ gtk_file_filter_add_mime_type(filter, lossy_mime[i][0]);
+ i++;
+ }
+ i = 0;
+ while (playlists_mime[i][0]) {
+ gtk_file_filter_add_mime_type(filter, playlists_mime[i][0]);
+ i++;
+ }
+ gtk_tree_store_append(store, &iter1, NULL);
+ gtk_tree_store_set(store, &iter1, 0, filter, -1);
+ filters = g_slist_append(filters, (gpointer)filter);
+
+ /* Lossy files */
+ filter = gtk_file_filter_new();
+ gtk_file_filter_set_name(filter, _("Lossy files"));
+ i = 0;
+ while (lossy_mime[i][0]) {
+ gtk_file_filter_add_mime_type(filter, lossy_mime[i][0]);
+ i++;
+ }
+ gtk_tree_store_append(store, &iter2, &iter1);
+ gtk_tree_store_set(store, &iter2, 0, filter, -1);
+ filters = g_slist_append(filters, (gpointer)filter);
+
+ /* Individual lossy files */
+ i = 0;
+ while (lossy_mime[i][0]) {
+ filter = gtk_file_filter_new();
+ gtk_file_filter_add_mime_type(filter, lossy_mime[i][0]);
+ gtk_file_filter_set_name(filter, lossy_mime[i][1]);
+ gtk_tree_store_append(store, &iter3, &iter2);
+ gtk_tree_store_set(store, &iter3, 0, filter, -1);
+ filters = g_slist_append(filters, (gpointer)filter);
+ i++;
+ }
+
+ /* Lossless files */
+ filter = gtk_file_filter_new();
+ gtk_file_filter_set_name(filter, _("Lossless files"));
+ i = 0;
+ while (lossless_mime[i][0]) {
+ gtk_file_filter_add_mime_type(filter, lossless_mime[i][0]);
+ i++;
+ }
+ gtk_tree_store_append(store, &iter2, &iter1);
+ gtk_tree_store_set(store, &iter2, 0, filter, -1);
+ filters = g_slist_append(filters, (gpointer)filter);
+
+ /* Individual lossless files */
+ i = 0;
+ while (lossless_mime[i][0]) {
+ filter = gtk_file_filter_new();
+ gtk_file_filter_add_mime_type(filter, lossless_mime[i][0]);
+ gtk_file_filter_set_name(filter, lossless_mime[i][1]);
+ gtk_tree_store_append(store, &iter3, &iter2);
+ gtk_tree_store_set(store, &iter3, 0, filter, -1);
+ filters = g_slist_append(filters, (gpointer)filter);
+ i++;
+ }
+
+ /* Playlists */
+ filter = gtk_file_filter_new();
+ gtk_file_filter_set_name(filter, _("Playlists"));
+ i = 0;
+ while (playlists_mime[i][0]) {
+ gtk_file_filter_add_mime_type(filter, playlists_mime[i][0]);
+ i++;
+ }
+ gtk_tree_store_append(store, &iter1, NULL);
+ gtk_tree_store_set(store, &iter1, 0, filter, -1);
+ filters = g_slist_append(filters, (gpointer)filter);
+
+ /* Individual playlists */
+ i = 0;
+ while (playlists_mime[i][0]) {
+ filter = gtk_file_filter_new();
+ gtk_file_filter_add_mime_type(filter, playlists_mime[i][0]);
+ gtk_file_filter_set_name(filter, playlists_mime[i][1]);
+ gtk_tree_store_append(store, &iter2, &iter1);
+ gtk_tree_store_set(store, &iter2, 0, filter, -1);
+ filters = g_slist_append(filters, (gpointer)filter);
+ i++;
+ }
+
+ for (f = filters; f; f = f->next) {
+ g_object_ref(G_OBJECT(f->data));
+ }
+
+ return GTK_TREE_MODEL(store);
+}
+
+
+static void
+gnac_ui_file_chooser_foreach(gpointer data,
+ gpointer user_data)
+{
+ GFile *file;
+ GSList **list;
+
+ list = (GSList**) user_data;
+ file = g_file_new_for_uri((gchar*)data);
+ *list = g_slist_append(*list, file);
+ g_free(data);
+}
+
+
+static GtkWidget *
+gnac_ui_file_chooser_new(void)
+{
+ GtkCellRenderer *renderer;
+ GtkTreeModel *model;
+ GtkWidget *combo;
+
+ gnac_file_chooser = gnac_ui_get_widget("gnac_file_chooser");
+ model = gnac_ui_file_chooser_get_filters_model();
+ combo = gnac_ui_get_widget("filters_combo");
+ gtk_combo_box_set_model(GTK_COMBO_BOX(combo), model);
+
+ renderer = gtk_cell_renderer_text_new();
+ gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), renderer, TRUE);
+ gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(combo), renderer,
+ (GtkCellLayoutDataFunc)gnac_ui_file_chooser_cell_data_func,
+ NULL, NULL);
+
+ g_signal_connect(G_OBJECT(combo), "changed",
+ G_CALLBACK(gnac_ui_on_filter_changed), gnac_file_chooser);
+
+ /* Use the 'Supported files' filter by default */
+ gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 1);
+ gnac_ui_on_filter_changed(GTK_COMBO_BOX(combo), gnac_file_chooser);
+
+ return gnac_file_chooser;
+}
+
+
+void
+gnac_ui_reset_file_filter(void)
+{
+ GtkComboBox *combo;
+ combo = GTK_COMBO_BOX(gnac_ui_get_widget("filters_combo"));
+ gtk_combo_box_set_active(combo, 1);
+ gnac_ui_on_filter_changed(combo, gnac_file_chooser);
+}
+
+
+GtkWidget *
+gnac_ui_get_file_chooser(void)
+{
+ if (G_UNLIKELY(!gnac_file_chooser)) {
+ gnac_file_chooser = gnac_ui_file_chooser_new();
+ }
+ return gnac_file_chooser;
+}
+
+
+GtkFileFilter *
+gnac_ui_get_current_filter(void)
+{
+ gpointer filter;
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ GtkComboBox *combo;
+
+ /* make sure the filters have been created */
+ gnac_ui_get_file_chooser();
+
+ combo = GTK_COMBO_BOX(gnac_ui_get_widget("filters_combo"));
+
+ if (!gtk_combo_box_get_active_iter(combo, &iter)) {
+ return default_file_filter;
+ }
+
+ model = gtk_combo_box_get_model(combo);
+ g_return_val_if_fail(model, default_file_filter);
+
+ gtk_tree_model_get(model, &iter, 0, &filter, -1);
+ if (GTK_IS_FILE_FILTER(filter)) {
+ return GTK_FILE_FILTER(filter);
+ }
+
+ return default_file_filter;
+}
+
+
+GtkFileFilter *
+gnac_ui_get_default_filter(void)
+{
+ return default_file_filter;
+}
+
+
+void
+gnac_ui_on_filter_changed(GtkComboBox *combo,
+ gpointer user_data)
+{
+ gpointer filter;
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+
+ if (!gtk_combo_box_get_active_iter(combo, &iter)) return;
+
+ model = gtk_combo_box_get_model(combo);
+ g_return_if_fail(model);
+ gtk_tree_model_get(model, &iter, 0, &filter, -1);
+ if (GTK_IS_FILE_FILTER(filter)) {
+ gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(user_data),
+ GTK_FILE_FILTER(filter));
+ }
+}
+
+
+void
+gnac_ui_file_chooser_response_cb(GtkDialog *dialog,
+ gint response,
+ gpointer user_data)
+{
+ GSList *list_path;
+ GSList *list_files = NULL;
+
+ GtkWidget *close_on_add_button;
+
+ switch (response) {
+ /* Add button */
+ case GTK_RESPONSE_NONE:
+ list_path = gtk_file_chooser_get_uris(GTK_FILE_CHOOSER(dialog));
+
+ /* Add the differents files */
+ g_slist_foreach(list_path,(GFunc) gnac_ui_file_chooser_foreach,
+ (gpointer)&list_files);
+
+ /* free the list */
+ g_slist_free(list_path);
+
+ /* add files */
+ gnac_add_files(list_files);
+
+ /* Do we have to close de file chooser? */
+ close_on_add_button = gnac_ui_get_widget("close_on_add_button");
+
+ /* Get the current uri */
+ g_free(current_directory);
+ current_directory = gtk_file_chooser_get_current_folder_uri(
+ GTK_FILE_CHOOSER(dialog));
+
+ if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(close_on_add_button)))
+ return;
+
+ break;
+
+ case GTK_RESPONSE_CLOSE:
+ default:
+ break;
+ }
+ gtk_widget_hide(GTK_WIDGET(dialog));
+}
+
+
+void
+gnac_ui_file_chooser_file_activated_cb(GtkFileChooser *chooser,
+ gpointer user_data)
+{
+ gnac_ui_file_chooser_response_cb(GTK_DIALOG(chooser),
+ GTK_RESPONSE_NONE, NULL);
+}
+
+
+gboolean
+gnac_ui_file_chooser_key_press_event_cb(GtkWidget *widget,
+ GdkEventKey *event,
+ gpointer user_data)
+{
+ if (event->type == GDK_KEY_PRESS && event->keyval == GDK_Return) {
+ gnac_ui_file_chooser_response_cb(GTK_DIALOG(widget),
+ GTK_RESPONSE_NONE, NULL);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
void
gnac_ui_new(void)
{
@@ -117,6 +516,8 @@ gnac_ui_new(void)
gtk_about_dialog_set_url_hook(gnac_about_url_hook, NULL, NULL);
gtk_about_dialog_set_email_hook(gnac_about_email_hook, NULL, NULL);
+ current_directory = g_strdup(g_get_home_dir());
+
file_list = gnac_file_list_new();
audio_profile_hbox = GTK_WIDGET(gtk_builder_get_object(gnac_main_builder, "audio_profile_hbox"));
@@ -356,6 +757,11 @@ gnac_ui_destroy(void)
}
}
+ if (current_directory) {
+ g_free(current_directory);
+ current_directory = NULL;
+ }
+
gnac_file_list_destroy();
if (gnac_main_builder) {
@@ -363,6 +769,7 @@ gnac_ui_destroy(void)
if (main_window) gtk_widget_destroy(main_window);
about_dialog = gnac_ui_get_widget("aboutdialog");
if (about_dialog) gtk_widget_destroy(about_dialog);
+ if (gnac_file_chooser) gnac_ui_file_chooser_dispose();
g_object_unref(gnac_main_builder);
gnac_main_builder = NULL;
}
diff --git a/src/gnac-ui.h b/src/gnac-ui.h
index fa0831a..4a05701 100644
--- a/src/gnac-ui.h
+++ b/src/gnac-ui.h
@@ -67,6 +67,36 @@ void
gnac_ui_show_about_dialog(void);
void
+gnac_ui_reset_file_filter(void);
+
+GtkWidget *
+gnac_ui_get_file_chooser(void);
+
+GtkFileFilter *
+gnac_ui_get_current_filter(void);
+
+GtkFileFilter *
+gnac_ui_get_default_filter(void);
+
+void
+gnac_ui_on_filter_changed(GtkComboBox *combo,
+ gpointer user_data);
+
+void
+gnac_ui_file_chooser_response_cb(GtkDialog *dialog,
+ gint response,
+ gpointer user_data);
+
+void
+gnac_ui_file_chooser_file_activated_cb(GtkFileChooser *chooser,
+ gpointer user_data);
+
+gboolean
+gnac_ui_file_chooser_key_press_event_cb(GtkWidget *widget,
+ GdkEventKey *event,
+ gpointer user_data);
+
+void
gnac_ui_new(void);
GtkWidget *
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]