Index: rb-playlist-manager.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/shell/rb-playlist-manager.c,v
retrieving revision 1.94
diff -u -r1.94 rb-playlist-manager.c
--- rb-playlist-manager.c	3 Mar 2006 00:33:37 -0000	1.94
+++ rb-playlist-manager.c	17 Apr 2006 10:37:03 -0000
@@ -1279,6 +1279,46 @@
 				 G_CALLBACK (load_playlist_response_cb), mgr, 0);
 }
 
+static RBPlaylistExportFilter *
+filter_guess_export_filter (GList *export_filters, 
+					const gchar *filename)
+{
+	GList *tmp;
+	gchar *ext;
+
+	ext = strrchr (filename, '.');
+	if (ext)
+		ext++;
+	else
+		ext = "";
+
+	for (tmp = export_filters; tmp != NULL; tmp = tmp->next) {
+		RBPlaylistExportFilter *ef = tmp->data;
+		gint i;
+
+		for (i = 0; ef->extensions[i] != NULL; i++)
+			if (!g_strcasecmp (ef->extensions[i], ext))
+				return ef;
+	}
+
+	return NULL;
+}
+
+static RBPlaylistExportFilter *
+efilter_by_index (GList *export_filters, 
+					int index, 
+					const char* filename)
+{
+	RBPlaylistExportFilter *efilter = NULL;
+
+	if (index >= 0)
+		efilter = g_list_nth_data (export_filters, index);
+	else if (filename) 
+		efilter = filter_guess_export_filter(export_filters, filename); 
+
+	return efilter;
+}
+
 static void
 save_playlist_response_cb (GtkDialog *dialog,
 			   int response_id,
@@ -1293,30 +1333,269 @@
 
 	file = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
 
-	gtk_widget_destroy (GTK_WIDGET (dialog));
-
 	if (file == NULL)
 		return;
 
-	rb_playlist_source_save_playlist (RB_PLAYLIST_SOURCE (mgr->priv->selected_source), 
-					  file, FALSE);
+	GtkWidget *menu = g_object_get_data (G_OBJECT(dialog), "export-menu");
+	GList *filters = g_object_get_data (G_OBJECT(dialog), "export-filters"); 
+	gint index = gtk_combo_box_get_active (GTK_COMBO_BOX(menu)) - 1;
+
+	/* by extension selected */
+	if (index == -1) {
+	
+		gchar *basename = NULL;
+		GString *g_basename;
+		gchar *text = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+		gchar *last_dot = text ? strrchr (text, '.') : NULL;
+
+		if (last_dot == text || text[0] == '\0')
+			return;
+
+		basename = g_path_get_basename (text);
+		last_dot = strrchr (basename, '.');
+		g_basename = g_string_new (basename);
+ 
+		/* check if entered filename actually has a dot seperating the extension */
+		if (!last_dot) {
+		
+			GError *error = NULL;
+
+			g_set_error (&error,
+				     RB_PLAYLIST_MANAGER_ERROR,
+				     RB_PLAYLIST_MANAGER_ERROR_PARSE,
+				     "%s",
+				     _("No file extension was given."));
+			
+			rb_error_dialog (NULL, _("Couldn't save playlist"), error->message);
+			g_error_free (error);
+		
+			g_string_free(g_basename, TRUE);
+			g_free(basename);
+
+			return;
+		}
+			
+		g_string_erase (g_basename, 0, last_dot-basename + 1);
+
+		/* FIXME: Modify rb_playlist_source_save_playlist to handle enums */
+		if (g_ascii_strcasecmp (g_basename->str, "m3u") == 0) {
+			rb_playlist_source_save_playlist (RB_PLAYLIST_SOURCE (mgr->priv->selected_source), 
+						file, TRUE);
+		} else if (g_ascii_strcasecmp (g_basename->str, "pls") == 0) {
+			rb_playlist_source_save_playlist (RB_PLAYLIST_SOURCE (mgr->priv->selected_source), 
+						file, FALSE);
+		} else {
+
+			GError *unsupported_error = NULL;
+
+			g_set_error (&unsupported_error,
+					     RB_PLAYLIST_MANAGER_ERROR,
+					     RB_PLAYLIST_MANAGER_ERROR_PARSE,
+					     "%s",
+				    	 _("Unsupported file extension given."));
+			
+			rb_error_dialog (NULL, _("Couldn't save playlist"), unsupported_error->message);
+			g_error_free (unsupported_error);
+
+
+			return;
+		}
+		
+		g_string_free(g_basename, TRUE);
+		g_free(basename);
+
+	} else {
+		
+		RBPlaylistExportFilter *efilter = efilter_by_index (filters, index, NULL);
+
+		rb_playlist_source_save_playlist (RB_PLAYLIST_SOURCE (mgr->priv->selected_source), 
+							file, (RBPlaylistExportType *) efilter->type == RB_PLAYLIST_EXPORT_TYPE_M3U ? TRUE : FALSE);
+
+		g_free(efilter);
+	
+	}
+		
+	gtk_widget_destroy (GTK_WIDGET (dialog)); 
+	
 	g_free (file);
 }
 
+static gint
+export_filter_compare (gconstpointer a, 
+					gconstpointer b)
+{
+	const RBPlaylistExportFilter *fa = a, *fb = b;
+	return g_strcasecmp (_(fa->description), _(fb->description));
+}
+
+/**
+ * FIXME: Do we really want to hardcode playlist formats this way? (i18n?!) 
+ */
+static GList*
+register_export_filters()
+{
+	GList *export_filters;
+	RBPlaylistExportFilter *pls, *m3u;
+    
+	export_filters = NULL;
+	pls = (RBPlaylistExportFilter *) g_malloc(sizeof(RBPlaylistExportFilter));
+	m3u = (RBPlaylistExportFilter *) g_malloc(sizeof(RBPlaylistExportFilter));
+
+	static const gchar *m3u_extensions[] = { "m3u", NULL };
+	m3u->description = "MPEG Version 3.0 URL";
+	m3u->extensions = m3u_extensions;
+	m3u->type = (RBPlaylistExportType *) RB_PLAYLIST_EXPORT_TYPE_M3U;
+
+	static const gchar *pls_extensions[] = { "pls", NULL };
+	pls->description = "Shoutcast playlist";
+	pls->extensions = pls_extensions;
+	pls->type = (RBPlaylistExportType *) RB_PLAYLIST_EXPORT_TYPE_PLS;
+   
+	export_filters = g_list_insert_sorted(export_filters, pls,
+					export_filter_compare);
+	export_filters = g_list_insert_sorted(export_filters, m3u,
+					export_filter_compare);
+
+	return export_filters;
+}
+
+typedef struct 
+{
+  GtkWidget *export_dialog;
+  GList *export_filters;
+}ExtensionElements;
+
+static void
+export_set_extension_cb (GtkWidget* widget, 
+					ExtensionElements* elements)
+{
+	GString *g_basename;
+	gint index = gtk_combo_box_get_active (GTK_COMBO_BOX (widget)) - 1;
+	gchar *text = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (elements->export_dialog));
+	gchar *last_dot = text ? strrchr (text, '.') : NULL;
+  
+	RBPlaylistExportFilter *efilter = efilter_by_index (elements->export_filters, index, NULL);
+	gchar *basename = NULL;
+
+	if (!efilter || last_dot == text || text[0] == '\0' ||
+		efilter->extensions[0] == NULL)
+		return;
+
+	basename = g_path_get_basename (text);
+	last_dot = strrchr (basename, '.');
+	g_basename = g_string_new (basename);
+  
+	if (last_dot)
+		g_string_truncate (g_basename, last_dot-basename);
+  
+	g_string_append (g_basename, ".");
+	g_string_append (g_basename, efilter->extensions[0]); 
+	gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (elements->export_dialog), g_basename->str);
+
+	g_string_free (g_basename, TRUE);
+	g_free (basename);
+}
+
+static gchar *
+filter_get_export_filter_label (RBPlaylistExportFilter *efilter)
+{
+	GString *str = g_string_new (_ (efilter->description));
+	gint ext = 0;
+	gchar *ret;
+
+	for (ext = 0; efilter->extensions[ext] != NULL; ext++) {
+		if (ext == 0)
+			g_string_append (str, " (*.");
+		else
+			g_string_append (str, ", *.");
+		g_string_append (str, efilter->extensions[ext]);
+	}
+    
+	if (ext > 0)
+		g_string_append (str, ")");
+    
+	ret = str->str;
+	g_string_free (str, FALSE);
+
+	return ret;
+}
+
+static GtkWidget *
+create_export_menu (GtkWidget* widget, 
+				GList* export_filters)
+{
+	GtkWidget *menu;
+	GList *tmp;
+	ExtensionElements *elements;
+
+	menu = gtk_combo_box_new_text ();
+	gtk_combo_box_append_text (GTK_COMBO_BOX (menu), _("By extension"));
+
+	for (tmp = export_filters; tmp != NULL; tmp = tmp->next) {
+		RBPlaylistExportFilter *ef = tmp->data;
+		gchar *filter_label;
+		
+		if (!ef)
+			continue;
+    
+		filter_label = filter_get_export_filter_label (ef);
+		gtk_combo_box_append_text (GTK_COMBO_BOX (menu), filter_label);
+		g_free (filter_label);
+	}
+    
+	elements = g_new (ExtensionElements, 1);
+	elements->export_dialog = widget; 
+	elements->export_filters = export_filters; 
+
+	g_signal_connect (GTK_OBJECT (menu), "changed",
+		G_CALLBACK (export_set_extension_cb), (gpointer) elements);
+
+	g_free(tmp);
+    
+	return menu;
+}
+
 static void
 rb_playlist_manager_cmd_save_playlist (GtkAction *action,
 				       RBPlaylistManager *mgr)
 {
-	GtkWidget *dialog;
+	GtkWidget *dialog, *box, *label, *menu, *options;
+    GList *export_filters;
     
 	dialog = rb_file_chooser_new (_("Save Playlist"),
-				      GTK_WINDOW (mgr->priv->window),
-				      GTK_FILE_CHOOSER_ACTION_SAVE,
-				      FALSE);
+					GTK_WINDOW (mgr->priv->window),
+					GTK_FILE_CHOOSER_ACTION_SAVE,
+					FALSE);
+
+	options = gtk_frame_new (_("Playlist Format"));
+	gtk_frame_set_shadow_type (GTK_FRAME (options), GTK_SHADOW_ETCHED_IN);
+
+	box = gtk_hbox_new (FALSE, 1);
+	gtk_container_set_border_width (GTK_CONTAINER (box), 5);
+	gtk_container_add (GTK_CONTAINER (options), box);
+	gtk_widget_show (box);
+
+	label = gtk_label_new (_("Determine playlist type: "));
+	gtk_box_pack_start (GTK_BOX (box), label, FALSE, TRUE, 0);
+	gtk_widget_show (label);
+
+	export_filters = register_export_filters ();
+	menu = create_export_menu (dialog, export_filters);
+    
+	g_object_set_data (G_OBJECT (dialog), "export-filters", export_filters);
+	g_object_set_data (G_OBJECT (dialog), "export-menu", menu);
+	gtk_box_pack_start (GTK_BOX (box), menu, TRUE, TRUE, 0);
+	
+	gtk_widget_show (menu);
+	gtk_widget_show (options);
+	
+	gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), options);
 
+	/* FIXME: always has "by extension" as default (it should probably remember the last selection) */
+	gtk_combo_box_set_active (GTK_COMBO_BOX (menu), 0);
 	g_signal_connect_object (G_OBJECT (dialog), "response",
-				 G_CALLBACK (save_playlist_response_cb),
-				 mgr, 0);
+					G_CALLBACK (save_playlist_response_cb),
+					mgr, 0);
 }
 
 static void
Index: rb-playlist-manager.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/shell/rb-playlist-manager.h,v
retrieving revision 1.22
diff -u -r1.22 rb-playlist-manager.h
--- rb-playlist-manager.h	9 Apr 2006 07:37:29 -0000	1.22
+++ rb-playlist-manager.h	17 Apr 2006 10:37:03 -0000
@@ -68,6 +68,20 @@
 	void	(*load_finish) (RBPlaylistManager *manager);
 } RBPlaylistManagerClass;
 
+typedef enum
+{
+    RB_PLAYLIST_EXPORT_TYPE_M3U,
+    RB_PLAYLIST_EXPORT_TYPE_PLS
+} RBPlaylistExportType;
+
+typedef struct {
+  const gchar *description;
+  /* NULL terminated array of extensions for this file format.  The first
+   * one is the prefered extension for files of this type. */
+  const gchar **extensions;
+  const RBPlaylistExportType *type;
+} RBPlaylistExportFilter;
+
 GType			rb_playlist_manager_get_type	(void);
 
 RBPlaylistManager *	rb_playlist_manager_new		(RBShell *shell,
