totem r5841 - in trunk: . src



Author: hadess
Date: Wed Dec 10 17:23:36 2008
New Revision: 5841
URL: http://svn.gnome.org/viewvc/totem?rev=5841&view=rev

Log:
2008-12-10  Bastien Nocera  <hadess hadess net>

	* src/Makefile.am:
	* src/eggfileformatchooser.[ch]: Add the EggFileFormatChooser
	from bug 440431
	* src/totem-playlist.c (totem_playlist_save_playlist),
	(suffix_match_replace), (format_selection_changed),
	(totem_playlist_save_add_format_chooser),
	(totem_playlist_save_files): Use a better file format chooser,
	- if the extension isn't known, use "PLS"
	- when changing the file type, change the prefix of the saved file
	(Closes: #379608)



Added:
   trunk/src/eggfileformatchooser.c
   trunk/src/eggfileformatchooser.h
Modified:
   trunk/ChangeLog
   trunk/src/Makefile.am
   trunk/src/totem-playlist.c

Modified: trunk/src/Makefile.am
==============================================================================
--- trunk/src/Makefile.am	(original)
+++ trunk/src/Makefile.am	Wed Dec 10 17:23:36 2008
@@ -101,8 +101,9 @@
 	totem-private.h					\
 	totem-preferences.c totem-preferences.h		\
 	totem-dnd-menu.c totem-dnd-menu.h 		\
-	totem-options.c totem-options.h	\
-	totem-playlist.c totem-playlist.h \
+	totem-options.c totem-options.h			\
+	totem-playlist.c totem-playlist.h		\
+	eggfileformatchooser.c eggfileformatchooser.h	\
 	totem-screenshot.c		\
 	totem-screenshot.h		\
 	totem-session.c totem-session.h	\

Added: trunk/src/eggfileformatchooser.c
==============================================================================
--- (empty file)
+++ trunk/src/eggfileformatchooser.c	Wed Dec 10 17:23:36 2008
@@ -0,0 +1,664 @@
+#include "eggfileformatchooser.h"
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <string.h>
+#include <ctype.h>
+
+typedef struct _EggFileFormatSearch EggFileFormatSearch;
+
+enum 
+{
+  MODEL_COLUMN_ID,
+  MODEL_COLUMN_NAME,
+  MODEL_COLUMN_ICON,
+  MODEL_COLUMN_EXTENSIONS,
+  MODEL_COLUMN_DATA,
+  MODEL_COLUMN_DESTROY
+};
+
+enum 
+{
+  SIGNAL_SELECTION_CHANGED,
+  SIGNAL_LAST
+};
+
+struct _EggFileFormatChooserPrivate
+{
+  GtkTreeStore *model;
+  GtkTreeSelection *selection;
+  guint idle_hack;
+  guint last_id;
+};
+
+struct _EggFileFormatSearch
+{
+  gboolean success;
+  GtkTreeIter iter;
+
+  guint format;
+  const gchar *extension;
+};
+
+static guint signals[SIGNAL_LAST];
+
+G_DEFINE_TYPE (EggFileFormatChooser, 
+	       egg_file_format_chooser,
+               GTK_TYPE_EXPANDER);
+
+static void
+selection_changed (GtkTreeSelection     *selection,
+                   EggFileFormatChooser *self)
+{
+  gchar *label;
+  gchar *name;
+
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+
+  if (gtk_tree_selection_get_selected (selection, &model, &iter)) 
+    {
+      gtk_tree_model_get (model, &iter, MODEL_COLUMN_NAME, &name, -1);
+
+      label = g_strdup_printf (_("File Format: %s"), name);
+      gtk_expander_set_label (GTK_EXPANDER (self), label);
+
+      g_free (name);
+      g_free (label);
+
+      g_signal_emit (self, signals[SIGNAL_SELECTION_CHANGED], 0);
+    }
+}
+
+/* XXX This hack is needed, as gtk_expander_set_label seems 
+ * not to work from egg_file_format_chooser_init */
+static gboolean
+select_default_file_format (gpointer data)
+{
+  EggFileFormatChooser *self = EGG_FILE_FORMAT_CHOOSER (data);
+  egg_file_format_chooser_set_format (self, 0);
+  self->priv->idle_hack = 0;
+  return FALSE;
+}
+
+static gboolean
+find_by_format (GtkTreeModel *model,
+                GtkTreePath  *path G_GNUC_UNUSED,
+                GtkTreeIter  *iter,
+                gpointer      data)
+{
+  EggFileFormatSearch *search = data;
+  guint id;
+
+  gtk_tree_model_get (model, iter, MODEL_COLUMN_ID, &id, -1);
+
+  if (id == search->format)
+    {
+      search->success = TRUE;
+      search->iter = *iter;
+    }
+
+  return search->success;
+}
+
+static gboolean
+find_in_list (gchar       *list,
+              const gchar *needle)
+{
+  gchar *saveptr;
+  gchar *token;
+
+  for(token = strtok_r (list, ",", &saveptr); NULL != token;
+      token = strtok_r (NULL, ",", &saveptr))
+    {
+      token = g_strstrip (token);
+
+      if (g_str_equal (needle, token))
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+find_by_extension (GtkTreeModel *model,
+                   GtkTreePath  *path G_GNUC_UNUSED,
+                   GtkTreeIter  *iter,
+                   gpointer      data)
+{
+  EggFileFormatSearch *search = data;
+
+  gchar *extensions = NULL;
+  guint format = 0;
+
+  gtk_tree_model_get (model, iter,
+                      MODEL_COLUMN_EXTENSIONS, &extensions,
+                      MODEL_COLUMN_ID, &format,
+                      -1);
+
+  if (extensions && find_in_list (extensions, search->extension))
+    {
+      search->format = format;
+      search->success = TRUE;
+      search->iter = *iter;
+    }
+
+  g_free (extensions);
+  return search->success;
+}
+
+static void
+egg_file_format_chooser_init (EggFileFormatChooser *self)
+{
+  GtkWidget *scroller;
+  GtkWidget *view;
+
+  GtkTreeViewColumn *column;
+  GtkCellRenderer *cell;
+  GtkTreeIter iter;
+
+  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EGG_TYPE_FILE_FORMAT_CHOOSER, 
+                                            EggFileFormatChooserPrivate);
+
+/* tree model */
+
+  self->priv->model = gtk_tree_store_new (6, G_TYPE_UINT, G_TYPE_STRING,
+                                             G_TYPE_STRING, G_TYPE_STRING,
+                                             G_TYPE_POINTER, G_TYPE_POINTER);
+
+  gtk_tree_store_append (self->priv->model, &iter, NULL);
+  gtk_tree_store_set (self->priv->model, &iter,
+                      MODEL_COLUMN_NAME, _("By Extension"),
+                      MODEL_COLUMN_ID, 0,
+                      -1);
+
+/* tree view */
+
+  view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (self->priv->model));
+  self->priv->selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
+  gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (view), TRUE);
+
+/* file format column */
+
+  column = gtk_tree_view_column_new ();
+  gtk_tree_view_column_set_expand (column, TRUE);
+  gtk_tree_view_column_set_title (column, _("File Format"));
+  gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
+
+  cell = gtk_cell_renderer_pixbuf_new ();
+  gtk_tree_view_column_pack_start (column, cell, FALSE);
+  gtk_tree_view_column_set_attributes (column, cell,
+                                       "icon-name", MODEL_COLUMN_ICON,
+                                       NULL);
+
+  cell = gtk_cell_renderer_text_new ();
+  gtk_tree_view_column_pack_start (column, cell, TRUE);
+  gtk_tree_view_column_set_attributes (column, cell,
+                                       "text", MODEL_COLUMN_NAME,
+                                       NULL);
+
+/* extensions column */
+
+  column = gtk_tree_view_column_new_with_attributes (
+    _("Extension(s)"), gtk_cell_renderer_text_new (),
+    "text", MODEL_COLUMN_EXTENSIONS, NULL);
+  gtk_tree_view_column_set_expand (column, FALSE);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
+
+/* selection */
+
+  gtk_tree_selection_set_mode (self->priv->selection, GTK_SELECTION_BROWSE);
+  g_signal_connect (self->priv->selection, "changed", G_CALLBACK (selection_changed), self);
+  self->priv->idle_hack = g_idle_add (select_default_file_format, self);
+
+/* scroller */
+
+  scroller = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroller),
+                                  GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroller),
+                                       GTK_SHADOW_IN);
+  gtk_widget_set_size_request (scroller, -1, 150);
+  gtk_container_add (GTK_CONTAINER (scroller), view);
+  gtk_widget_show_all (scroller);
+
+  gtk_container_add (GTK_CONTAINER (self), scroller);
+}
+
+static void
+reset_model (EggFileFormatChooser *self)
+{
+  GtkTreeModel *model = GTK_TREE_MODEL (self->priv->model);
+  GtkTreeIter iter;
+
+  if (gtk_tree_model_get_iter_first (model, &iter))
+    {
+      do
+        {
+          GDestroyNotify destroy = NULL;
+          gpointer data = NULL;
+
+          gtk_tree_model_get (model, &iter,
+                              MODEL_COLUMN_DESTROY, &destroy,
+                              MODEL_COLUMN_DATA, &data,
+                              -1);
+
+          if (destroy)
+            destroy (data);
+        }
+      while (gtk_tree_model_iter_next (model, &iter));
+    }
+
+  gtk_tree_store_clear (self->priv->model);
+}
+
+static void
+egg_file_format_chooser_dispose (GObject *obj)
+{
+  EggFileFormatChooser *self = EGG_FILE_FORMAT_CHOOSER (obj);
+
+  if (NULL != self)
+    {
+      if (self->priv->idle_hack)
+        {
+          g_source_remove (self->priv->idle_hack);
+          self->priv->idle_hack = 0;
+        }
+    }
+
+  G_OBJECT_CLASS (egg_file_format_chooser_parent_class)->dispose (obj);
+}
+
+static void
+egg_file_format_chooser_finalize (GObject *obj)
+{
+  EggFileFormatChooser *self = EGG_FILE_FORMAT_CHOOSER (obj);
+
+  if (NULL != self)
+    {
+      if (self->priv->model)
+        {
+          reset_model (self);
+          g_object_unref (self->priv->model);
+          self->priv->model = NULL;
+        }
+    }
+
+  G_OBJECT_CLASS (egg_file_format_chooser_parent_class)->finalize (obj);
+}
+
+static void
+egg_file_format_chooser_class_init (EggFileFormatChooserClass *cls)
+{
+  g_type_class_add_private (cls, sizeof (EggFileFormatChooserPrivate));
+
+  G_OBJECT_CLASS (cls)->dispose = egg_file_format_chooser_dispose;
+  G_OBJECT_CLASS (cls)->finalize = egg_file_format_chooser_finalize;
+
+  signals[SIGNAL_SELECTION_CHANGED] = g_signal_new (
+    "selection-changed", EGG_TYPE_FILE_FORMAT_CHOOSER, G_SIGNAL_RUN_FIRST,
+    G_STRUCT_OFFSET (EggFileFormatChooserClass, selection_changed),
+    NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+}
+
+GtkWidget*
+egg_file_format_chooser_new (void)
+{
+  return g_object_new (EGG_TYPE_FILE_FORMAT_CHOOSER, NULL);
+}
+
+static guint
+egg_file_format_chooser_add_format_impl (EggFileFormatChooser *self,
+                                         guint                 parent,
+                                         const gchar          *name,
+                                         const gchar          *icon,
+                                         const gchar          *extensions)
+{
+  EggFileFormatSearch search;
+  GtkTreeIter iter;
+
+  search.success = FALSE;
+  search.format = parent;
+
+  if (parent > 0)
+    gtk_tree_model_foreach (GTK_TREE_MODEL (self->priv->model),
+                            find_by_format, &search);
+
+  gtk_tree_store_append (self->priv->model, &iter, 
+                         search.success ? &search.iter : NULL);
+
+  gtk_tree_store_set (self->priv->model, &iter,
+                      MODEL_COLUMN_ID, ++self->priv->last_id,
+                      MODEL_COLUMN_EXTENSIONS, extensions,
+                      MODEL_COLUMN_NAME, name,
+                      MODEL_COLUMN_ICON, icon,
+                      -1);
+
+  return self->priv->last_id;
+}
+
+guint
+egg_file_format_chooser_add_format (EggFileFormatChooser *self,
+                                    guint                 parent,
+                                    const gchar          *name,
+                                    const gchar          *icon,
+                                    ...)
+{
+  GString *buffer = NULL;
+  const gchar* extptr;
+  va_list extensions;
+  guint id;
+
+  g_return_val_if_fail (EGG_IS_FILE_FORMAT_CHOOSER (self), 0);
+  g_return_val_if_fail (NULL != name, 0);
+
+  va_start (extensions, icon);
+
+  while (NULL != (extptr = va_arg (extensions, const gchar*)))
+    {
+      if (NULL == buffer)
+        buffer = g_string_new (NULL);
+      else
+        g_string_append (buffer, ", ");
+
+      g_string_append (buffer, extptr);
+    }
+
+  va_end (extensions);
+
+  id = egg_file_format_chooser_add_format_impl (self, parent, name, icon,
+                                                buffer ? buffer->str : NULL);
+
+  if (buffer)
+    g_string_free (buffer, TRUE);
+
+  return id;
+}
+
+static gchar*
+get_icon_name (const gchar *mime_type)
+{
+  gchar *name = NULL;
+  gchar *s;
+
+  if (mime_type)
+    {
+      name = g_strconcat ("gnome-mime-", mime_type, NULL);
+
+      for(s = name; *s; ++s)
+        {
+          if (!isalpha (*s) || !isascii (*s))
+            *s = '-';
+        }
+    }
+
+  if (!name ||
+      !gtk_icon_theme_has_icon (gtk_icon_theme_get_default (), name))
+    {
+      g_free (name);
+      name = g_strdup ("gnome-mime-image");
+    }
+
+  return name;
+}
+
+void           
+egg_file_format_chooser_add_pixbuf_formats (EggFileFormatChooser *self,
+                                            guint                 parent G_GNUC_UNUSED,
+                                            guint               **formats)
+{
+  GSList *pixbuf_formats = NULL;
+  GSList *iter;
+  gint i;
+
+  g_return_if_fail (EGG_IS_FILE_FORMAT_CHOOSER (self));
+
+  pixbuf_formats = gdk_pixbuf_get_formats ();
+
+  if (formats)
+    *formats = g_new0 (guint, g_slist_length (pixbuf_formats) + 1);
+
+  for(iter = pixbuf_formats, i = 0; iter; iter = iter->next, ++i)
+    {
+      GdkPixbufFormat *format = iter->data;
+
+      gchar *description, *name, *extensions, *icon;
+      gchar **mime_types, **extension_list;
+      guint id;
+
+      if (gdk_pixbuf_format_is_disabled (format) ||
+         !gdk_pixbuf_format_is_writable (format))
+        continue;
+
+      mime_types = gdk_pixbuf_format_get_mime_types (format);
+      icon = get_icon_name (mime_types[0]);
+      g_strfreev (mime_types);
+
+      extension_list = gdk_pixbuf_format_get_extensions (format);
+      extensions = g_strjoinv (", ", extension_list);
+      g_strfreev (extension_list);
+
+      description = gdk_pixbuf_format_get_description (format);
+      name = gdk_pixbuf_format_get_name (format);
+
+      id = egg_file_format_chooser_add_format_impl (self, parent, description, 
+                                                    icon, extensions);
+
+      g_free (description);
+      g_free (extensions);
+      g_free (icon);
+
+      egg_file_format_chooser_set_format_data (self, id, name, g_free);
+
+      if (formats)
+        *formats[i] = id;
+    }
+
+  g_slist_free (pixbuf_formats);
+}
+
+void
+egg_file_format_chooser_remove_format (EggFileFormatChooser *self,
+                                       guint                 format)
+{
+  GDestroyNotify destroy = NULL;
+  gpointer data = NULL;
+
+  EggFileFormatSearch search;
+  GtkTreeModel *model;
+
+  g_return_if_fail (EGG_IS_FILE_FORMAT_CHOOSER (self));
+
+  search.success = FALSE;
+  search.format = format;
+
+  model = GTK_TREE_MODEL (self->priv->model);
+  gtk_tree_model_foreach (model, find_by_format, &search);
+
+  g_return_if_fail (search.success);
+
+  gtk_tree_model_get (model, &search.iter,
+                      MODEL_COLUMN_DESTROY, &destroy,
+                      MODEL_COLUMN_DATA, &data,
+                      -1);
+
+  if (destroy)
+    destroy (data);
+
+  gtk_tree_store_remove (self->priv->model, &search.iter);
+}
+
+void            
+egg_file_format_chooser_set_format (EggFileFormatChooser *self,
+                                    guint                 format)
+{
+  EggFileFormatSearch search;
+
+  GtkTreeModel *model;
+  GtkTreePath *path;
+  GtkTreeView *view;
+
+  g_return_if_fail (EGG_IS_FILE_FORMAT_CHOOSER (self));
+
+  search.success = FALSE;
+  search.format = format;
+
+  model = GTK_TREE_MODEL (self->priv->model);
+  gtk_tree_model_foreach (model, find_by_format, &search);
+
+  g_return_if_fail (search.success);
+
+  path = gtk_tree_model_get_path (model, &search.iter);
+  view = gtk_tree_selection_get_tree_view (self->priv->selection);
+
+  gtk_tree_view_expand_to_path (view, path);
+  gtk_tree_selection_unselect_all (self->priv->selection);
+  gtk_tree_selection_select_path (self->priv->selection, path);
+
+  gtk_tree_path_free (path);
+
+  if (self->priv->idle_hack > 0)
+    {
+      g_source_remove (self->priv->idle_hack);
+      self->priv->idle_hack = 0;
+    }
+}
+
+guint
+egg_file_format_chooser_get_format (EggFileFormatChooser *self,
+                                    const gchar          *filename)
+{
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+  guint format = 0;
+
+  g_return_val_if_fail (EGG_IS_FILE_FORMAT_CHOOSER (self), -1);
+
+  if (gtk_tree_selection_get_selected (self->priv->selection, &model, &iter))
+    gtk_tree_model_get (model, &iter, MODEL_COLUMN_ID, &format, -1);
+
+  if (0 == format && NULL != filename)
+    {
+      EggFileFormatSearch search;
+
+      search.extension = strrchr(filename, '.');
+      search.success = FALSE;
+
+      if (search.extension++)
+        gtk_tree_model_foreach (model, find_by_extension, &search);
+      if (search.success)
+        format = search.format;
+    }
+
+  return format;
+}
+
+void            
+egg_file_format_chooser_set_format_data (EggFileFormatChooser *self,
+                                         guint                 format,
+                                         gpointer              data,
+                                         GDestroyNotify        destroy)
+{
+  EggFileFormatSearch search;
+
+  g_return_if_fail (EGG_IS_FILE_FORMAT_CHOOSER (self));
+
+  search.success = FALSE;
+  search.format = format;
+
+  gtk_tree_model_foreach (GTK_TREE_MODEL (self->priv->model),
+                          find_by_format, &search);
+
+  g_return_if_fail (search.success);
+
+  gtk_tree_store_set (self->priv->model, &search.iter,
+                      MODEL_COLUMN_DESTROY, destroy,
+                      MODEL_COLUMN_DATA, data,
+                      -1);
+}
+
+gpointer
+egg_file_format_chooser_get_format_data (EggFileFormatChooser *self,
+                                         guint                 format)
+{
+  EggFileFormatSearch search;
+  gpointer data = NULL;
+  GtkTreeModel *model;
+
+  g_return_val_if_fail (EGG_IS_FILE_FORMAT_CHOOSER (self), NULL);
+
+  search.success = FALSE;
+  search.format = format;
+
+  model = GTK_TREE_MODEL (self->priv->model);
+  gtk_tree_model_foreach (model, find_by_format, &search);
+
+  g_return_val_if_fail (search.success, NULL);
+
+  gtk_tree_model_get (model, &search.iter,
+                      MODEL_COLUMN_DATA, &data,
+                      -1);
+  return data;
+}
+
+gchar*
+egg_file_format_chooser_append_extension (EggFileFormatChooser *self,
+                                          const gchar          *filename,
+                                          guint                 format)
+{
+  EggFileFormatSearch search;
+  GtkTreeModel *model;
+  GtkTreeIter child;
+
+  gchar *extensions;
+  gchar *tmpstr;
+
+  g_return_val_if_fail (EGG_IS_FILE_FORMAT_CHOOSER (self), NULL);
+  g_return_val_if_fail (NULL != filename, NULL);
+
+  if (0 == format)
+    format = egg_file_format_chooser_get_format (self, filename);
+
+  if (0 == format)
+    {
+      g_warning ("%s: No file format selected. Cannot append extension.", __FUNCTION__);
+      return NULL;
+    }
+
+  search.success = FALSE;
+  search.format = format;
+
+  model = GTK_TREE_MODEL (self->priv->model);
+  gtk_tree_model_foreach (model, find_by_format, &search);
+
+  g_return_val_if_fail (search.success, NULL);
+
+  gtk_tree_model_get (model, &search.iter, 
+                      MODEL_COLUMN_EXTENSIONS, &extensions,
+                      -1);
+
+  if (NULL == extensions && 
+      gtk_tree_model_iter_nth_child (model, &child, &search.iter, 0))
+    {
+      gtk_tree_model_get (model, &child, 
+                          MODEL_COLUMN_EXTENSIONS, &extensions,
+                          -1);
+    }
+
+  if (NULL == extensions)
+    {
+      g_warning ("%s: File format %d doesn't provide file extensions. "
+                 "Cannot append extension.", __FUNCTION__, format);
+      return NULL;
+    }
+
+  if (NULL != (tmpstr = strchr(extensions, ',')))
+    *tmpstr = '\0';
+
+  tmpstr = g_strconcat (filename, ".", extensions, NULL);
+  g_free (extensions);
+
+  return tmpstr;
+}
+
+/* vim: set sw=2 sta et: */

Added: trunk/src/eggfileformatchooser.h
==============================================================================
--- (empty file)
+++ trunk/src/eggfileformatchooser.h	Wed Dec 10 17:23:36 2008
@@ -0,0 +1,66 @@
+#ifndef __EGG_FILE_FORMAT_CHOOSER_H__
+#define __EGG_FILE_FORMAT_CHOOSER_H__
+
+#include <gtk/gtkexpander.h>
+
+G_BEGIN_DECLS
+
+#define EGG_TYPE_FILE_FORMAT_CHOOSER           (egg_file_format_chooser_get_type())
+#define EGG_FILE_FORMAT_CHOOSER(obj)           (G_TYPE_CHECK_INSTANCE_CAST(obj, EGG_TYPE_FILE_FORMAT_CHOOSER, EggFileFormatChooser))
+#define EGG_FILE_FORMAT_CHOOSER_CLASS(klass)   (G_TYPE_CHECK_CLASS_CAST(klass, EGG_TYPE_FILE_FORMAT_CHOOSER, EggFileFormatChooserClass))
+#define EGG_IS_FILE_FORMAT_CHOOSER(obj)        (G_TYPE_CHECK_INSTANCE_TYPE(obj, EGG_TYPE_FILE_FORMAT_CHOOSER))
+#define EGG_IS_FILE_FORMAT_CHOOSER_CLASS(obj)  (G_TYPE_CHECK_CLASS_TYPE(obj, EGG_TYPE_FILE_FORMAT_CHOOSER))
+#define EGG_FILE_FORMAT_CHOOSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EGG_TYPE_FILE_FORMAT_CHOOSER, EggFileFormatChooserClass))
+
+typedef struct _EggFileFormatChooser        EggFileFormatChooser;
+typedef struct _EggFileFormatChooserClass   EggFileFormatChooserClass;
+typedef struct _EggFileFormatChooserPrivate EggFileFormatChooserPrivate;
+
+struct _EggFileFormatChooser
+{
+  GtkExpander parent;
+  EggFileFormatChooserPrivate *priv;
+};
+
+struct _EggFileFormatChooserClass
+{
+  GtkExpanderClass parent;
+
+  void (*selection_changed)(EggFileFormatChooser *self);
+};
+
+GType           egg_file_format_chooser_get_type           (void) G_GNUC_CONST;
+GtkWidget*      egg_file_format_chooser_new                (void);
+
+guint           egg_file_format_chooser_add_format         (EggFileFormatChooser *self,
+                                                            guint                 parent,
+                                                            const gchar          *name,
+                                                            const gchar          *icon,
+                                                            ...) G_GNUC_NULL_TERMINATED;
+void            egg_file_format_chooser_add_pixbuf_formats (EggFileFormatChooser *self,
+                                                            guint                 parent,
+                                                            guint               **formats);
+void            egg_file_format_chooser_remove_format      (EggFileFormatChooser *self,
+                                                            guint                 format);
+
+void            egg_file_format_chooser_set_format         (EggFileFormatChooser *self,
+                                                            guint                 format);
+guint           egg_file_format_chooser_get_format         (EggFileFormatChooser *self,
+                                                            const gchar          *filename);
+
+void            egg_file_format_chooser_set_format_data    (EggFileFormatChooser *self,
+                                                            guint                 format,
+                                                            gpointer              data,
+                                                            GDestroyNotify        destroy);
+gpointer        egg_file_format_chooser_get_format_data    (EggFileFormatChooser *self,
+                                                            guint                 format);
+
+gchar*          egg_file_format_chooser_append_extension   (EggFileFormatChooser *self,
+                                                            const gchar          *filename,
+                                                            guint                 format);
+
+G_END_DECLS
+
+#endif /* __EGG_FILE_FORMAT_CHOOSER_H__ */
+
+/* vim: set sw=2 sta et: */

Modified: trunk/src/totem-playlist.c
==============================================================================
--- trunk/src/totem-playlist.c	(original)
+++ trunk/src/totem-playlist.c	Wed Dec 10 17:23:36 2008
@@ -32,6 +32,7 @@
 #include <gio/gio.h>
 #include <string.h>
 
+#include "eggfileformatchooser.h"
 #include "totem-dnd-menu.h"
 #include "totem-uri.h"
 #include "totem-interface.h"
@@ -43,8 +44,6 @@
 static void ensure_shuffled (TotemPlaylist *playlist, gboolean shuffle);
 static gboolean totem_playlist_add_one_mrl (TotemPlaylist *playlist, const char *mrl, const char *display_name);
 
-typedef gboolean (*PlaylistCallback) (TotemPlaylist *playlist, const char *mrl,
-		gpointer data);
 typedef gboolean (*ClearComparisonFunc) (TotemPlaylist *playlist, GtkTreeIter *iter, gconstpointer data);
 
 static void totem_playlist_clear_with_compare (TotemPlaylist *playlist,
@@ -68,17 +67,6 @@
 	gpointer user_data;
 } PlaylistForeachContext;
 
-typedef struct {
-	char *mimetype;
-	PlaylistCallback func;
-} PlaylistTypes;
-
-typedef struct {
-	const char *name;
-	const char *suffix;
-	TotemPlParserType type;
-} PlaylistSaveType;
-
 struct TotemPlaylistPrivate
 {
 	GtkBuilder *xml;
@@ -95,6 +83,8 @@
 	/* These is the current paths for the file selectors */
 	char *path;
 	char *save_path;
+	guint save_format;
+	GtkWidget *file_chooser;
 
 	/* Shuffle mode */
 	int *shuffled;
@@ -149,11 +139,18 @@
 	NUM_COLS
 };
 
+typedef struct {
+	const char *name;
+	const char *suffix;
+	TotemPlParserType type;
+} PlaylistSaveType;
+
 static PlaylistSaveType save_types [] = {
-	{".PLS", ".pls", TOTEM_PL_PARSER_PLS},
-	{".M3U", ".m3u", TOTEM_PL_PARSER_M3U},
-	{".M3U (DOS)", ".m3u", TOTEM_PL_PARSER_M3U_DOS},
-	{".XSPF", ".xspf", TOTEM_PL_PARSER_XSPF}
+	{ NULL, NULL, -1 }, /* By extension entry */
+	{ N_("MP3 ShoutCast playlist"), "pls", TOTEM_PL_PARSER_PLS },
+	{ N_("MP3 audio (streamed)"), "m3u", TOTEM_PL_PARSER_M3U },
+	{ N_("MP3 audio (streamed, DOS format)"), "m3u", TOTEM_PL_PARSER_M3U_DOS },
+	{ N_("XML Shareable Playlist"), "xspf", TOTEM_PL_PARSER_XSPF }
 };
 
 static int totem_playlist_table_signals[LAST_SIGNAL];
@@ -972,103 +969,144 @@
 static void
 totem_playlist_save_playlist (TotemPlaylist *playlist, char *filename, gint active_format)
 {
-	PlaylistSaveType *cur = NULL;
-	guint i;
+	if (active_format == 0)
+		active_format = 1;
 
-	if (active_format > 0)
-		totem_playlist_save_current_playlist_ext (playlist, filename,
-							save_types[active_format - 1].type);
-	else {
-		for (i = 0; i < G_N_ELEMENTS(save_types); i++) {
-			if (g_str_has_suffix (filename, save_types[i].suffix)) {
-				cur = &save_types[i];
-				break;
+	totem_playlist_save_current_playlist_ext (playlist, filename,
+						  save_types[active_format].type);
+}
+
+static char *
+suffix_match_replace (const char *fname, guint old_format, guint new_format)
+{
+	char *ext;
+
+	ext = g_strdup_printf (".%s", save_types[old_format].suffix);
+	if (g_str_has_suffix (fname, ext) != FALSE) {
+		char *no_suffix, *new_fname;
+
+		no_suffix = g_strndup (fname, strlen (fname) - strlen (ext));
+		new_fname = g_strconcat (no_suffix, ".", save_types[new_format].suffix, NULL);
+		g_free (no_suffix);
+		g_free (ext);
+
+		return new_fname;
+	}
+	g_free (ext);
+
+	return NULL;
+}
+
+static void
+format_selection_changed (EggFileFormatChooser *chooser, TotemPlaylist *playlist)
+{
+	guint format;
+
+	format = egg_file_format_chooser_get_format (chooser, NULL);
+
+	if (format != playlist->priv->save_format) {
+		char *fname, *new_fname;
+
+		new_fname = NULL;
+		fname = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (playlist->priv->file_chooser));
+
+		if (format == 0) {
+			/* The new format is "By extension" don't touch anything */
+		} else if (playlist->priv->save_format == 0) {
+			guint i;
+
+			for (i = 1; i < G_N_ELEMENTS (save_types); i++) {
+				new_fname = suffix_match_replace (fname, i, format);
+				if (new_fname != NULL)
+					break;
 			}
+		} else {
+			new_fname = suffix_match_replace (fname, playlist->priv->save_format, format);
 		}
-		if (cur == NULL)
-			totem_playlist_error (_("Could not save the playlist"), _("Unknown file extension."), playlist);
-		else
-			totem_playlist_save_current_playlist_ext (playlist, filename, cur->type);
+		if (new_fname != NULL) {
+			char *basename;
+
+			basename = g_path_get_basename (new_fname);
+			g_free (new_fname);
+			gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (playlist->priv->file_chooser), basename);
+			g_free (basename);
+		}
+		playlist->priv->save_format = format;
 	}
 }
 
 static GtkWidget *
-totem_playlist_save_add_format_combo_box (GtkFileChooser *fc)
+totem_playlist_save_add_format_chooser (GtkFileChooser *fc, TotemPlaylist *playlist)
 {
-	GtkWidget *hbox, *label, *combo_box;
+	GtkWidget *format_chooser;
 	guint i;
 
-	hbox = gtk_hbox_new (FALSE, 4);
-	label = gtk_label_new (_("Select playlist format:"));
-	gtk_widget_show (label);
-
-	combo_box = gtk_combo_box_new_text ();
-	gtk_combo_box_append_text (GTK_COMBO_BOX (combo_box),
-			_("By extension"));
-	gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), 0);
-	for (i = 0; i < G_N_ELEMENTS(save_types); i++) {
-		gtk_combo_box_append_text (GTK_COMBO_BOX (combo_box),
-				save_types[i].name);
-	}
-	gtk_widget_show (combo_box);
-
-	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
-	gtk_box_pack_start (GTK_BOX (hbox), combo_box, TRUE, TRUE, 0);
-	gtk_widget_show (hbox);
-	gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (fc), hbox);
-
-	atk_object_add_relationship (gtk_widget_get_accessible (label),
-			ATK_RELATION_LABEL_FOR,
-			gtk_widget_get_accessible (combo_box));
-	atk_object_add_relationship (gtk_widget_get_accessible (combo_box),
-			ATK_RELATION_LABELLED_BY,
-			gtk_widget_get_accessible (label));
+	format_chooser = egg_file_format_chooser_new ();
+
+	playlist->priv->save_format = 0;
+
+	for (i = 1; i < G_N_ELEMENTS (save_types) ; i++) {
+		egg_file_format_chooser_add_format (
+		    EGG_FILE_FORMAT_CHOOSER (format_chooser), 0, _(save_types[i].name),
+		    "gnome-mime-audio", save_types[i].suffix, NULL);
+	}
+
+	g_signal_connect (format_chooser, "selection-changed",
+			  G_CALLBACK (format_selection_changed), playlist);
+
+	gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (fc),
+					   format_chooser);
 
-	return combo_box;
+	return format_chooser;
 }
 
 void
 totem_playlist_save_files (GtkWidget *widget, TotemPlaylist *playlist)
 {
-	GtkWidget *fs, *combo_box;
+	GtkWidget *fs, *format_chooser;
 	char *filename;
 	int response;
 
+	g_assert (playlist->priv->file_chooser == NULL);
+
 	fs = gtk_file_chooser_dialog_new (_("Save Playlist"),
-			totem_playlist_get_toplevel (playlist),
-			GTK_FILE_CHOOSER_ACTION_SAVE,
-			GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-			GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
-			NULL);
+					  totem_playlist_get_toplevel (playlist),
+					  GTK_FILE_CHOOSER_ACTION_SAVE,
+					  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+					  GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+					  NULL);
 	gtk_dialog_set_default_response (GTK_DIALOG (fs), GTK_RESPONSE_ACCEPT);
 	gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (fs), FALSE);
 	gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (fs), TRUE);
+
 	/* translators: Playlist is the default saved playlist filename,
 	 * without the suffix */
-	filename = g_strconcat (_("Playlist"), save_types[0].suffix, NULL);
+	filename = g_strconcat (_("Playlist"), ".", save_types[1].suffix, NULL);
 	gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (fs), filename);
 	g_free (filename);
-	combo_box = totem_playlist_save_add_format_combo_box (GTK_FILE_CHOOSER (fs));
+	format_chooser = totem_playlist_save_add_format_chooser (GTK_FILE_CHOOSER (fs), playlist);
 
-	if (playlist->priv->save_path != NULL)
-	{
+	if (playlist->priv->save_path != NULL) {
 		gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (fs),
 				playlist->priv->save_path);
 	}
 
+	playlist->priv->file_chooser = fs;
+
 	response = gtk_dialog_run (GTK_DIALOG (fs));
 	gtk_widget_hide (fs);
 	while (gtk_events_pending())
 		gtk_main_iteration();
 
-	if (response == GTK_RESPONSE_ACCEPT)
-	{
+	if (response == GTK_RESPONSE_ACCEPT) {
 		char *fname;
-		gint active_format;
+		guint active_format;
 
 		fname = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (fs));
-		active_format = gtk_combo_box_get_active (GTK_COMBO_BOX (combo_box));
+		active_format = egg_file_format_chooser_get_format (EGG_FILE_FORMAT_CHOOSER (format_chooser),
+								    fname);
 
+		playlist->priv->file_chooser = NULL;
 		gtk_widget_destroy (fs);
 
 		if (fname == NULL)
@@ -1080,6 +1118,7 @@
 		totem_playlist_save_playlist (playlist, fname, active_format);
 		g_free (fname);
 	} else {
+		playlist->priv->file_chooser = NULL;
 		gtk_widget_destroy (fs);
 	}
 }



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