sound-juicer r2158 - in trunk: . src



Author: rburton
Date: Thu Apr 17 09:46:39 2008
New Revision: 2158
URL: http://svn.gnome.org/viewvc/sound-juicer?rev=2158&view=rev

Log:
2008-04-17  Luca Cavalli  <lcavalli svn gnome org>

	* src/Makefile.am:
	* src/egg-play-preview.[ch]:
	Add an audio preview widget.
	* src/sj-extracting.c: (confirm_overwrite_existing_file):
	Allow the user to listen to the track before choose to skip or
	overwrite it (#161315).


Added:
   trunk/src/egg-play-preview.c
   trunk/src/egg-play-preview.h
Modified:
   trunk/ChangeLog
   trunk/src/Makefile.am
   trunk/src/sj-extracting.c

Modified: trunk/src/Makefile.am
==============================================================================
--- trunk/src/Makefile.am	(original)
+++ trunk/src/Makefile.am	Thu Apr 17 09:46:39 2008
@@ -21,6 +21,8 @@
 	gedit-message-area.c \
 	gconf-bridge.h \
 	gconf-bridge.c \
+	egg-play-preview.c \
+	egg-play-preview.h \
 	$(BACON_FILES)
 
 sound_juicer_CPPFLAGS = \

Added: trunk/src/egg-play-preview.c
==============================================================================
--- (empty file)
+++ trunk/src/egg-play-preview.c	Thu Apr 17 09:46:39 2008
@@ -0,0 +1,948 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+/*
+ * EggPlayPreview GTK+ Widget - egg-play-preview.c
+ * 
+ * Copyright (C) 2008 Luca Cavalli <luca cavalli gmail 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.
+ *
+ * Authors: Luca Cavalli <luca cavalli gmail com>
+ */
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <gst/gst.h>
+
+#include "egg-play-preview.h"
+
+enum {
+	PROP_NONE,
+
+	PROP_URI,
+	PROP_TITLE,
+	PROP_ARTIST,
+	PROP_ALBUM,
+	PROP_DURATION,
+	PROP_POSITION
+};
+
+enum {
+	PLAY_STARTED_SIGNAL,
+	PAUSED_SIGNAL,
+	STOPPED_SIGNAL,
+
+	LAST_SIGNAL
+};
+
+#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EGG_TYPE_PLAY_PREVIEW, EggPlayPreviewPrivate))
+
+struct _EggPlayPreviewPrivate {
+
+	GtkWidget *title_label;
+	GtkWidget *artist_album_label;
+
+	GtkWidget *play_button;
+	GtkWidget *play_button_image;
+
+	GtkWidget *time_scale;
+	GtkWidget *time_label;
+
+	GstElement *playbin;
+	GstState state;
+
+	gchar *title;
+	gchar *artist;
+	gchar *album;
+
+	gint duration;
+	gint position;
+
+	gint timeout_id;
+
+	gboolean is_seekable;
+
+	gchar *uri;
+};
+
+static void	egg_play_preview_class_init   (EggPlayPreviewClass *klass);
+static void	egg_play_preview_init         (EggPlayPreview      *play_preview);
+static void egg_play_preview_finalize     (GObject             *object);
+static void egg_play_preview_dispose      (GObject             *object);
+static void	egg_play_preview_set_property (GObject             *object,
+										   guint                prop_id,
+										   const GValue        *value,
+										   GParamSpec          *pspec);
+static void	egg_play_preview_get_property (GObject             *object,
+										   guint                prop_id,
+										   GValue              *value,
+										   GParamSpec          *pspec);
+
+static gboolean _timeout_cb                  (EggPlayPreview *play_preview);
+static void _ui_update_duration              (EggPlayPreview *play_preview);
+static void _ui_update_tags                  (EggPlayPreview *play_preview);
+static void _ui_set_sensitive                (EggPlayPreview *play_preview,
+											  gboolean sensitive);
+static gboolean _change_value_cb             (GtkRange *range,
+											  GtkScrollType scroll,
+											  gdouble value,
+											  EggPlayPreview *play_preview);
+static void _clicked_cb                      (GtkButton      *button,
+											  EggPlayPreview *play_preview);
+static void _setup_pipeline                  (EggPlayPreview *play_preview);
+static void _clear_pipeline                  (EggPlayPreview *play_preview);
+static gboolean _process_bus_messages        (GstBus         *bus,
+											  GstMessage     *msg,
+											  EggPlayPreview *play_preview);
+static gboolean _query_seeking               (GstElement *element);
+static gint _query_duration                  (GstElement *element);
+static gint _query_position                  (GstElement *element);
+static void _seek                            (GstElement *element,
+											  gint position);
+static gboolean _is_playing                  (GstState state);
+static void _play                            (EggPlayPreview *play_preview);
+static void _pause                           (EggPlayPreview *play_preview);
+static void _stop                            (EggPlayPreview *play_preview);
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (EggPlayPreview, egg_play_preview, GTK_TYPE_VBOX)
+
+static void
+egg_play_preview_class_init (EggPlayPreviewClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (EggPlayPreviewPrivate));
+
+	gobject_class->finalize = egg_play_preview_finalize;
+	gobject_class->dispose = egg_play_preview_dispose;
+	gobject_class->set_property = egg_play_preview_set_property;
+	gobject_class->get_property = egg_play_preview_get_property;
+
+	signals[PLAY_STARTED_SIGNAL] =
+		g_signal_new ("play-started",
+					  G_TYPE_FROM_CLASS (klass),
+					  G_SIGNAL_RUN_LAST,
+					  G_STRUCT_OFFSET (EggPlayPreviewClass, play),
+					  NULL, NULL,
+					  g_cclosure_marshal_VOID__VOID,
+					  G_TYPE_NONE, 0);
+
+	signals[PAUSED_SIGNAL] =
+		g_signal_new ("paused",
+					  G_TYPE_FROM_CLASS (klass),
+					  G_SIGNAL_RUN_LAST,
+					  G_STRUCT_OFFSET (EggPlayPreviewClass, pause),
+					  NULL, NULL,
+					  g_cclosure_marshal_VOID__VOID,
+					  G_TYPE_NONE, 0);
+
+	signals[STOPPED_SIGNAL] =
+		g_signal_new ("stopped",
+					  G_TYPE_FROM_CLASS (klass),
+					  G_SIGNAL_RUN_LAST,
+					  G_STRUCT_OFFSET (EggPlayPreviewClass, stop),
+					  NULL, NULL,
+					  g_cclosure_marshal_VOID__VOID,
+					  G_TYPE_NONE, 0);
+
+	g_object_class_install_property (gobject_class,
+									 PROP_URI,
+									 g_param_spec_string ("uri",
+														  _("URI"),
+														  _("The URI of the audio file"),
+														  NULL,
+														  G_PARAM_READWRITE |
+														  G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
+														  G_PARAM_STATIC_BLURB));
+
+	g_object_class_install_property (gobject_class,
+									 PROP_TITLE,
+									 g_param_spec_string ("title",
+														  _("Title"),
+														  _("The title of the current stream."),
+														  NULL,
+														  G_PARAM_READABLE |
+														  G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
+														  G_PARAM_STATIC_BLURB));
+
+	g_object_class_install_property (gobject_class,
+									 PROP_TITLE,
+									 g_param_spec_string ("artist",
+														  _("Artist"),
+														  _("The artist of the current stream."),
+														  NULL,
+														  G_PARAM_READABLE |
+														  G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
+														  G_PARAM_STATIC_BLURB));
+
+	g_object_class_install_property (gobject_class,
+									 PROP_ALBUM,
+									 g_param_spec_string ("album",
+														  _("Album"),
+														  _("The album of the current stream."),
+														  NULL,
+														  G_PARAM_READABLE |
+														  G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
+														  G_PARAM_STATIC_BLURB));
+
+	g_object_class_install_property (gobject_class,
+									 PROP_POSITION,
+									 g_param_spec_int ("position",
+													   _("Position"),
+													   _("The position in the current stream in seconds."),
+													   0, G_MAXINT, 0,
+													   G_PARAM_READWRITE |
+													   G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
+													   G_PARAM_STATIC_BLURB));
+
+	g_object_class_install_property (gobject_class,
+									 PROP_DURATION,
+									 g_param_spec_int ("duration",
+													   _("Duration"),
+													   _("The duration of the current stream in seconds."),
+													   0, G_MAXINT, 0,
+													   G_PARAM_READABLE |
+													   G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
+													   G_PARAM_STATIC_BLURB));
+
+	gst_init (NULL, NULL);
+}
+
+static void
+egg_play_preview_init (EggPlayPreview *play_preview)
+{
+	EggPlayPreviewPrivate *priv;
+	PangoAttribute *bold;
+	PangoAttrList *attrs;
+	GtkWidget *vbox;
+	GtkWidget *hbox;
+	GtkWidget *align;
+
+	play_preview->priv = priv = GET_PRIVATE (play_preview);
+
+	_setup_pipeline (play_preview);
+
+	priv->title = NULL;
+	priv->album = NULL;
+
+	priv->duration = 0;
+	priv->position = 0;
+	priv->timeout_id = 0;
+
+	priv->is_seekable = FALSE;
+
+	priv->uri = NULL;
+
+	gtk_box_set_homogeneous (GTK_BOX (play_preview), FALSE);
+	gtk_box_set_spacing (GTK_BOX (play_preview), 6);
+
+	/* track info */
+	vbox = gtk_vbox_new (TRUE, 0);
+
+	priv->title_label = gtk_label_new (NULL);
+	gtk_label_set_justify (GTK_LABEL (priv->title_label), GTK_JUSTIFY_LEFT);
+	gtk_misc_set_alignment (GTK_MISC (priv->title_label), 0.0, 0.5);
+	bold = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
+	attrs = pango_attr_list_new ();
+	bold->start_index = 0;
+	bold->end_index = G_MAXINT;
+	pango_attr_list_insert (attrs, bold);
+	gtk_label_set_attributes (GTK_LABEL (priv->title_label), attrs);
+	pango_attr_list_unref(attrs);
+	gtk_box_pack_start_defaults (GTK_BOX (vbox), priv->title_label);
+
+	priv->artist_album_label = gtk_label_new (NULL);
+	gtk_label_set_justify (GTK_LABEL (priv->artist_album_label), GTK_JUSTIFY_LEFT);
+	gtk_misc_set_alignment (GTK_MISC (priv->artist_album_label), 0.0, 0.5);
+	gtk_box_pack_start_defaults (GTK_BOX (vbox), priv->artist_album_label);
+
+	hbox = gtk_hbox_new (FALSE, 12);
+
+	/* play button */
+	priv->play_button = gtk_button_new ();
+	priv->play_button_image = gtk_image_new_from_stock (GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_BUTTON);
+	gtk_container_add (GTK_CONTAINER (priv->play_button), priv->play_button_image);
+	align = gtk_alignment_new (0.5, 0.5, 1.0, 0.0);
+	gtk_container_add (GTK_CONTAINER (align), priv->play_button);
+
+	/* time scale */
+	priv->time_scale = gtk_hscale_new_with_range (0.0, 100.0, 1.0);
+	gtk_scale_set_draw_value (GTK_SCALE (priv->time_scale), FALSE);
+	gtk_widget_set_size_request (priv->time_scale, EGG_PLAYER_PREVIEW_WIDTH, -1);
+	priv->time_label = gtk_label_new ("0:00");
+	gtk_misc_set_alignment (GTK_MISC (priv->time_label), 0.0, 0.5);
+
+	gtk_box_pack_start (GTK_BOX (hbox), align, FALSE, FALSE, 0);
+	gtk_box_pack_start (GTK_BOX (hbox), priv->time_scale, TRUE, TRUE, 0);
+	gtk_box_pack_start (GTK_BOX (hbox), priv->time_label, FALSE, FALSE, 0);
+
+	g_signal_connect (G_OBJECT (priv->play_button), "clicked",
+					  G_CALLBACK (_clicked_cb), play_preview);
+	g_signal_connect (G_OBJECT (priv->time_scale), "change-value",
+					  G_CALLBACK (_change_value_cb), play_preview);
+
+	gtk_box_pack_start (GTK_BOX (play_preview), vbox, FALSE, FALSE, 0);
+	gtk_box_pack_start (GTK_BOX (play_preview), hbox, FALSE, FALSE, 0);
+
+	_ui_set_sensitive (play_preview, FALSE);
+
+	gtk_widget_show_all (GTK_WIDGET (play_preview));
+}
+
+static void
+egg_play_preview_finalize (GObject *object)
+{
+	gst_deinit ();
+
+	G_OBJECT_CLASS (egg_play_preview_parent_class)->finalize (object);
+}
+
+static void
+egg_play_preview_dispose (GObject *object)
+{
+	EggPlayPreview *play_preview;
+	EggPlayPreviewPrivate *priv;
+
+	play_preview = EGG_PLAY_PREVIEW (object);
+	priv = GET_PRIVATE (play_preview);
+
+	_clear_pipeline (play_preview);
+
+	if (priv->title) {
+		g_free (priv->title);
+		priv->title = NULL;
+	}
+
+	if (priv->album) {
+		g_free (priv->album);
+		priv->album = NULL;
+	}
+
+	if (priv->uri) {
+		g_free (priv->uri);
+		priv->uri = NULL;
+	}
+
+	if (priv->timeout_id != 0) {
+		g_source_remove (priv->timeout_id);
+		priv->timeout_id = 0;
+	}
+}
+
+static void
+egg_play_preview_set_property (GObject       *object,
+							   guint          prop_id,
+							   const GValue  *value,
+							   GParamSpec    *pspec)
+{
+	EggPlayPreview *play_preview;
+
+	play_preview = EGG_PLAY_PREVIEW (object);
+
+	switch (prop_id) {
+    case PROP_URI:
+		egg_play_preview_set_uri (play_preview,
+								  g_value_get_string (value));
+		break;
+
+	case PROP_POSITION:
+		egg_play_preview_set_position (play_preview,
+									   g_value_get_int (value));
+		break;
+
+    default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+    }
+}
+
+static void 
+egg_play_preview_get_property (GObject     *object,
+							   guint        prop_id,
+							   GValue      *value,
+							   GParamSpec  *pspec)
+{
+	EggPlayPreview *play_preview;
+	EggPlayPreviewPrivate *priv;
+
+	play_preview = EGG_PLAY_PREVIEW (object);
+	priv = GET_PRIVATE (play_preview);
+
+	switch (prop_id) {
+    case PROP_URI:
+		g_value_set_string (value,
+							egg_play_preview_get_uri (play_preview));
+		break;
+
+    case PROP_TITLE:
+		g_value_set_string (value,
+							egg_play_preview_get_title (play_preview));
+		break;
+
+    case PROP_ARTIST:
+		g_value_set_string (value,
+							egg_play_preview_get_artist (play_preview));
+		break;
+
+    case PROP_ALBUM:
+		g_value_set_string (value,
+							egg_play_preview_get_album (play_preview));
+		break;
+
+	case PROP_POSITION:
+		g_value_set_int (value,
+                         egg_play_preview_get_position (play_preview));
+		break;
+
+	case PROP_DURATION:
+		g_value_set_int (value,
+                         egg_play_preview_get_duration (play_preview));
+		break;
+
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static gboolean
+_timeout_cb (EggPlayPreview *play_preview)
+{
+	EggPlayPreviewPrivate *priv;
+
+	priv = GET_PRIVATE (play_preview);
+
+	priv->position = _query_position (priv->playbin);
+	g_object_notify (G_OBJECT (play_preview), "position");
+
+	gtk_range_set_value (GTK_RANGE (priv->time_scale), priv->position * (100.0 / priv->duration));
+
+	return TRUE;
+}
+
+static void
+_ui_update_duration (EggPlayPreview *play_preview)
+{
+	EggPlayPreviewPrivate *priv;
+	gchar *str;
+
+	priv = GET_PRIVATE (play_preview);
+
+	str = g_strdup_printf ("%u:%02u",
+						   priv->duration / 60,
+						   priv->duration % 60);
+
+	gtk_label_set_text (GTK_LABEL (priv->time_label), str);
+	g_free (str);
+}
+
+static void
+_ui_update_tags (EggPlayPreview *play_preview)
+{
+	EggPlayPreviewPrivate *priv;
+	gchar *str;
+
+	priv = GET_PRIVATE (play_preview);
+
+	str = g_strdup_printf ("%s", priv->title ? priv->title : _("Unknown Title"));
+	gtk_label_set_text (GTK_LABEL (priv->title_label), str);
+	g_free (str);
+
+	str = g_strdup_printf ("%s - %s",
+						   priv->artist ? priv->artist : _("Unknown Artist"),
+						   priv->album ? priv->album : _("Unknown Album"));
+	gtk_label_set_text (GTK_LABEL (priv->artist_album_label), str);
+	g_free (str);
+}
+
+static void
+_ui_set_sensitive (EggPlayPreview *play_preview, gboolean sensitive)
+{
+	EggPlayPreviewPrivate *priv;
+
+	priv = GET_PRIVATE (play_preview);
+
+	gtk_widget_set_sensitive (priv->play_button, sensitive);
+	gtk_widget_set_sensitive (priv->time_scale, sensitive && priv->is_seekable);
+}
+
+static gboolean
+_change_value_cb (GtkRange *range, GtkScrollType scroll, gdouble value, EggPlayPreview *play_preview)
+{
+	EggPlayPreviewPrivate *priv;
+
+	priv = GET_PRIVATE (play_preview);
+
+	if (priv->is_seekable)
+		_seek (priv->playbin, (gint) ((value / 100.0) * priv->duration));
+
+	return FALSE;
+}
+
+static void
+_clicked_cb (GtkButton *button, EggPlayPreview *play_preview)
+{
+	EggPlayPreviewPrivate *priv;
+
+	priv = GET_PRIVATE (play_preview);
+
+	if (priv->playbin == NULL)
+		return;
+
+	if (_is_playing (GST_STATE (priv->playbin))) {		
+		_pause (play_preview);
+		g_signal_emit (play_preview, signals[PAUSED_SIGNAL], 0);
+	} else {
+		_play (play_preview);
+		g_signal_emit (play_preview, signals[PLAY_STARTED_SIGNAL], 0);
+	}
+}
+
+static void
+_setup_pipeline (EggPlayPreview *play_preview)
+{
+	EggPlayPreviewPrivate *priv;
+	GstElement *audiosink;
+	GstBus *bus = NULL;
+
+	priv = GET_PRIVATE (play_preview);
+
+	priv->state = GST_STATE_NULL;
+
+	priv->playbin = gst_element_factory_make ("playbin", "playbin");
+	if (!priv->playbin)
+		return;
+
+	audiosink = gst_element_factory_make ("gconfaudiosink", "audiosink");
+	if (!audiosink) {
+		audiosink = gst_element_factory_make ("autoaudiosink", "audiosink");
+		if (!audiosink) {
+			audiosink = gst_element_factory_make ("alsasink", "audiosink");
+			if (!audiosink) {
+				return;
+			}
+		}
+	}
+
+	g_object_set (G_OBJECT (priv->playbin),
+				  "audio-sink", audiosink,
+				  "video-sink", NULL,
+				  NULL);
+
+	bus = gst_pipeline_get_bus (GST_PIPELINE (priv->playbin));
+	gst_bus_add_watch (bus, (GstBusFunc) _process_bus_messages, play_preview);
+	gst_object_unref (bus);
+
+	gst_element_set_state (priv->playbin, GST_STATE_NULL);
+}
+
+static void
+_clear_pipeline (EggPlayPreview *play_preview)
+{
+	EggPlayPreviewPrivate *priv;
+	GstBus *bus;
+
+	priv = GET_PRIVATE (play_preview);
+
+	if (priv->playbin) {
+		bus = gst_pipeline_get_bus (GST_PIPELINE (priv->playbin));
+		gst_bus_set_flushing (bus, TRUE);
+		gst_object_unref (bus);
+
+		gst_element_set_state (priv->playbin, GST_STATE_NULL);
+        gst_object_unref (GST_OBJECT (priv->playbin));
+		priv->playbin = NULL;
+	}
+}
+
+static gboolean
+_process_bus_messages (GstBus *bus, GstMessage *msg, EggPlayPreview *play_preview)
+{
+	EggPlayPreviewPrivate *priv;
+	GstFormat format = GST_FORMAT_TIME;
+	GstTagList *tag_list;
+	gint64 duration;
+	GstState state;
+	GstStateChangeReturn result;
+
+	priv = GET_PRIVATE (play_preview);
+
+	switch (GST_MESSAGE_TYPE (msg)) {
+	case GST_MESSAGE_DURATION:
+		gst_message_parse_duration (msg, &format, (gint64*) &duration);
+
+		if (format != GST_FORMAT_TIME)
+			break;
+
+		priv->duration = duration / GST_SECOND;
+
+		g_object_notify (G_OBJECT (play_preview), "duration");
+
+		_ui_update_duration (play_preview);
+		break;
+
+	case GST_MESSAGE_EOS:
+		_stop (play_preview);
+		break;
+
+	case GST_MESSAGE_TAG:
+		gst_message_parse_tag (msg, &tag_list);
+		gst_tag_list_get_string (tag_list, GST_TAG_TITLE, &priv->title);
+		gst_tag_list_get_string (tag_list, GST_TAG_ARTIST, &priv->artist);
+		gst_tag_list_get_string (tag_list, GST_TAG_ALBUM, &priv->album);
+
+		g_object_notify (G_OBJECT (play_preview), "title");
+		g_object_notify (G_OBJECT (play_preview), "artist");
+		g_object_notify (G_OBJECT (play_preview), "album");
+
+		_ui_update_tags (play_preview);
+		break;
+
+	case GST_MESSAGE_STATE_CHANGED:
+		result = gst_element_get_state (GST_ELEMENT (priv->playbin), &state, NULL, 500);
+
+		if (result != GST_STATE_CHANGE_SUCCESS)
+			break;
+
+		if (priv->state == state || state < GST_STATE_PAUSED)
+			break;
+
+		if (state == GST_STATE_PLAYING) {
+			g_signal_emit (G_OBJECT (play_preview), signals[PLAY_STARTED_SIGNAL], 0);
+		} else if (state == GST_STATE_PAUSED) {
+			g_signal_emit (G_OBJECT (play_preview), signals[PAUSED_SIGNAL], 0);
+		} else {
+			g_signal_emit (G_OBJECT (play_preview), signals[STOPPED_SIGNAL], 0);
+		}
+
+		priv->state = state;
+		break;
+
+	default:
+		break;
+	}
+
+	return TRUE;
+}
+
+static gboolean
+_query_seeking (GstElement *element)
+{
+	GstStateChangeReturn result;
+	GstState state;
+	GstState pending;
+	GstQuery *query;
+	gboolean seekable;
+
+	seekable = _query_duration (element) > 0;
+
+	result = gst_element_get_state (element, &state, &pending, GST_CLOCK_TIME_NONE);
+
+	if (result == GST_STATE_CHANGE_FAILURE)
+		return FALSE;
+
+	if (pending)
+		state = pending;
+
+	result = gst_element_set_state (element, GST_STATE_PAUSED);
+
+	if (result == GST_STATE_CHANGE_ASYNC)
+		gst_element_get_state (element, NULL, NULL, GST_CLOCK_TIME_NONE);
+
+	query = gst_query_new_seeking (GST_FORMAT_TIME);
+
+	if (gst_element_query (element, query))
+		gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
+
+	gst_query_unref (query);
+
+	gst_element_set_state (element, state);
+
+	return seekable;
+}
+
+static gint
+_query_duration (GstElement *element)
+{
+	GstStateChangeReturn result;
+	GstState state;
+	GstState pending;
+	gint64 duration;
+	GstFormat format;
+
+	duration = 0;
+	format = GST_FORMAT_TIME;
+
+	result = gst_element_get_state (element, &state, &pending, GST_CLOCK_TIME_NONE);
+
+	if (result == GST_STATE_CHANGE_FAILURE)
+		return 0;
+
+	if (pending)
+		state = pending;
+
+	result = gst_element_set_state (element, GST_STATE_PAUSED);
+
+	if (result == GST_STATE_CHANGE_ASYNC)
+		gst_element_get_state (element, NULL, NULL, GST_CLOCK_TIME_NONE);
+
+	gst_element_query_duration (element, &format, &duration);
+
+	gst_element_set_state (element, state);
+
+	return (gint) (duration / GST_SECOND);
+}
+
+static gint
+_query_position (GstElement *element)
+{
+	gint64 position;
+	GstFormat format;
+
+	position = 0;
+	format = GST_FORMAT_TIME;
+
+	gst_element_query_position (element, &format, &position);
+
+	return (gint) (position / GST_SECOND);
+}
+
+static void
+_seek (GstElement *element, gint position)
+{
+	GstStateChangeReturn result;
+	GstState state;
+
+	result = gst_element_get_state (element, &state, NULL, GST_CLOCK_TIME_NONE);
+
+	if (result == GST_STATE_CHANGE_FAILURE)
+		return;
+
+	result = gst_element_set_state (element, GST_STATE_PAUSED);
+
+	if (result == GST_STATE_CHANGE_ASYNC) {
+		gst_element_get_state (element, NULL, NULL, GST_CLOCK_TIME_NONE);
+	}
+
+	gst_element_seek (element, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
+					  GST_SEEK_TYPE_SET, position * GST_SECOND,
+					  GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
+
+	gst_element_set_state (element, state);
+}
+
+static gboolean
+_is_playing (GstState state)
+{
+	return (state == GST_STATE_PLAYING);
+}
+
+static void
+_play (EggPlayPreview *play_preview)
+{
+	EggPlayPreviewPrivate *priv;
+
+	priv = GET_PRIVATE (play_preview);
+
+	gst_element_set_state (priv->playbin, GST_STATE_PLAYING);
+
+	gtk_image_set_from_stock (GTK_IMAGE (priv->play_button_image),
+							  GTK_STOCK_MEDIA_PAUSE,
+							  GTK_ICON_SIZE_BUTTON);
+}
+
+static void
+_pause (EggPlayPreview *play_preview)
+{
+	EggPlayPreviewPrivate *priv;
+
+	priv = GET_PRIVATE (play_preview);
+
+	gst_element_set_state (priv->playbin, GST_STATE_PAUSED);
+
+	gtk_image_set_from_stock (GTK_IMAGE (priv->play_button_image),
+							  GTK_STOCK_MEDIA_PLAY,
+							  GTK_ICON_SIZE_BUTTON);
+}
+
+static void
+_stop (EggPlayPreview *play_preview)
+{
+	EggPlayPreviewPrivate *priv;
+
+	priv = GET_PRIVATE (play_preview);
+
+	gst_element_set_state (priv->playbin, GST_STATE_READY);
+
+	gtk_image_set_from_stock (GTK_IMAGE (priv->play_button_image),
+							  GTK_STOCK_MEDIA_PLAY,
+							  GTK_ICON_SIZE_BUTTON);
+}
+
+GtkWidget *
+egg_play_preview_new (void)
+{
+	EggPlayPreview *play_preview;
+
+	play_preview = g_object_new (EGG_TYPE_PLAY_PREVIEW, NULL);
+
+	return GTK_WIDGET (play_preview);
+}
+
+GtkWidget *
+egg_play_preview_new_with_uri (const gchar *uri)
+{
+	EggPlayPreview *play_preview;
+
+	play_preview = g_object_new (EGG_TYPE_PLAY_PREVIEW, NULL);
+	egg_play_preview_set_uri (play_preview, uri);
+
+	return GTK_WIDGET (play_preview);
+}
+
+void
+egg_play_preview_set_uri (EggPlayPreview *play_preview, const gchar *uri)
+{
+	EggPlayPreviewPrivate *priv;
+
+	g_return_if_fail (EGG_IS_PLAY_PREVIEW (play_preview));
+
+	priv = GET_PRIVATE (play_preview);
+
+	if (priv->uri) {
+		g_free (priv->uri);
+		priv->uri = NULL;
+		priv->duration = 0;
+	}
+
+	if (priv->timeout_id != 0) {
+		g_source_remove (priv->timeout_id);
+		priv->timeout_id = 0;
+	}
+
+	_stop (play_preview);
+	priv->is_seekable = FALSE;
+
+	if (gst_uri_is_valid (uri)) {
+		priv->uri = g_strdup (uri);
+
+		g_object_set (G_OBJECT (priv->playbin), "uri", uri, NULL);
+
+		priv->duration = _query_duration (priv->playbin);
+		priv->is_seekable = _query_seeking (priv->playbin);
+
+		g_object_notify (G_OBJECT (play_preview), "duration");
+
+		_pause (play_preview);
+
+		_ui_set_sensitive (play_preview, TRUE);
+		_ui_update_duration (play_preview);
+		_ui_update_tags (play_preview);
+		priv->timeout_id = g_timeout_add_seconds (1, (GSourceFunc) _timeout_cb, play_preview);
+	}
+
+	g_object_notify (G_OBJECT (play_preview), "uri");
+}
+
+void
+egg_play_preview_set_position (EggPlayPreview *play_preview, gint position)
+{
+	EggPlayPreviewPrivate *priv;
+
+	g_return_if_fail (EGG_IS_PLAY_PREVIEW (play_preview));
+
+	priv = GET_PRIVATE (play_preview);
+
+	/* FIXME: write function content */
+	if (priv->is_seekable) {
+		_seek (priv->playbin, MIN (position, priv->duration));
+
+		g_object_notify (G_OBJECT (play_preview), "position");
+	}
+}
+
+gchar *
+egg_play_preview_get_uri (EggPlayPreview *play_preview)
+{
+	EggPlayPreviewPrivate *priv;
+
+	g_return_val_if_fail (EGG_IS_PLAY_PREVIEW (play_preview), NULL);
+
+	priv = GET_PRIVATE (play_preview);
+
+	return priv->uri;
+}
+
+gchar *
+egg_play_preview_get_title (EggPlayPreview *play_preview)
+{
+	EggPlayPreviewPrivate *priv;
+
+	g_return_val_if_fail (EGG_IS_PLAY_PREVIEW (play_preview), NULL);
+
+	priv = GET_PRIVATE (play_preview);
+
+	return priv->title;
+}
+
+gchar *
+egg_play_preview_get_artist (EggPlayPreview *play_preview)
+{
+	EggPlayPreviewPrivate *priv;
+
+	g_return_val_if_fail (EGG_IS_PLAY_PREVIEW (play_preview), NULL);
+
+	priv = GET_PRIVATE (play_preview);
+
+	return priv->artist;
+}
+
+gchar *
+egg_play_preview_get_album (EggPlayPreview *play_preview)
+{
+	EggPlayPreviewPrivate *priv;
+
+	g_return_val_if_fail (EGG_IS_PLAY_PREVIEW (play_preview), NULL);
+
+	priv = GET_PRIVATE (play_preview);
+
+	return priv->album;
+}
+
+gint
+egg_play_preview_get_position (EggPlayPreview *play_preview)
+{
+	EggPlayPreviewPrivate *priv;
+
+	g_return_val_if_fail (EGG_IS_PLAY_PREVIEW (play_preview), 0);
+
+	priv = GET_PRIVATE (play_preview);
+
+	return priv->position;
+}
+
+gint
+egg_play_preview_get_duration (EggPlayPreview *play_preview)
+{
+	EggPlayPreviewPrivate *priv;
+
+	g_return_val_if_fail (EGG_IS_PLAY_PREVIEW (play_preview), -1);
+
+	priv = GET_PRIVATE (play_preview);
+
+	return priv->duration;
+}

Added: trunk/src/egg-play-preview.h
==============================================================================
--- (empty file)
+++ trunk/src/egg-play-preview.h	Thu Apr 17 09:46:39 2008
@@ -0,0 +1,79 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+/*
+ * EggPlayPreview GTK+ Widget - egg-play-preview.h
+ * 
+ * Copyright (C) 2008 Luca Cavalli <luca cavalli gmail 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.
+ *
+ * Authors: Luca Cavalli <luca cavalli gmail com>
+ */
+
+#ifndef __EGG_PLAY_PREVIEW_H__
+#define __EGG_PLAY_PREVIEW_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define EGG_TYPE_PLAY_PREVIEW          (egg_play_preview_get_type ())
+#define EGG_PLAY_PREVIEW(obj)          (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_PLAY_PREVIEW, EggPlayPreview))
+#define EGG_PLAY_PREVIEW_CLASS(obj)    (G_TYPE_CHECK_CLASS_CAST ((obj), EGG_PLAY_PREVIEW, EggPlayPreviewClass))
+#define EGG_IS_PLAY_PREVIEW(obj)       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_PLAY_PREVIEW))
+#define EGG_IS_PLAY_PREVIEW_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), EFF_TYPE_PLAY_PREVIEW))
+#define EGG_PLAY_PREVIEW_GET_CLASS     (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_PLAY_PREVIEW, EggPlayPreviewClass))
+
+#define EGG_PLAYER_PREVIEW_WIDTH 100
+
+typedef struct _EggPlayPreview        EggPlayPreview;
+typedef struct _EggPlayPreviewClass   EggPlayPreviewClass;
+typedef struct _EggPlayPreviewPrivate EggPlayPreviewPrivate;
+
+struct _EggPlayPreview {
+	GtkHBox parent;
+
+	gchar *file;
+
+	/*< private >*/
+	EggPlayPreviewPrivate *priv;
+};
+
+struct _EggPlayPreviewClass {
+	GtkHBoxClass parent_class;
+
+	/* signals */
+	void (* play)  (EggPlayPreview *play_preview);
+	void (* pause) (EggPlayPreview *play_preview);
+	void (* stop)  (EggPlayPreview *play_preview);
+};
+
+GType      egg_play_preview_get_type     (void) G_GNUC_CONST;
+GtkWidget *egg_play_preview_new          (void);
+GtkWidget *egg_play_preview_new_with_uri (const gchar *uri);
+void       egg_play_preview_set_uri      (EggPlayPreview *play_preview,
+										  const gchar *uri);
+void       egg_play_preview_set_position (EggPlayPreview *play_preview,
+										  gint position);
+gchar     *egg_play_preview_get_uri      (EggPlayPreview *play_preview);
+gchar     *egg_play_preview_get_title    (EggPlayPreview *play_preview);
+gchar     *egg_play_preview_get_artist   (EggPlayPreview *play_preview);
+gchar     *egg_play_preview_get_album    (EggPlayPreview *play_preview);
+gint       egg_play_preview_get_position (EggPlayPreview *play_preview);
+gint       egg_play_preview_get_duration (EggPlayPreview *play_preview);
+
+G_END_DECLS
+
+#endif /* __EGG_PLAY_PREVIEW_H__ */

Modified: trunk/src/sj-extracting.c
==============================================================================
--- trunk/src/sj-extracting.c	(original)
+++ trunk/src/sj-extracting.c	Thu Apr 17 09:46:39 2008
@@ -40,6 +40,7 @@
 #include "sj-play.h"
 #include "sj-inhibit.h"
 #include "sj-genres.h"
+#include "egg-play-preview.h"
 
 typedef struct {
   int seconds;
@@ -282,17 +283,24 @@
 { 
   OverwriteDialogResponse ret;
   GtkWidget *dialog;
+  GtkWidget *play_preview;
   char *filename, *size;
- 
+
   filename = gnome_vfs_format_uri_for_display (uri);
   size = gnome_vfs_format_file_size_for_display (info_size);
   dialog = gtk_message_dialog_new (GTK_WINDOW (main_window), GTK_DIALOG_MODAL,
                                    GTK_MESSAGE_QUESTION,
                                    GTK_BUTTONS_NONE,
-                                   _("A file called '%s' exists, size %s.\nDo you want to skip this track or overwrite it?"),
-                                   filename, size);
+                                   _("A file with the same name exists"));
+  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+                                            _("A file called '%s' exists, size %s.\nDo you want to skip this track or overwrite it?"),
+                                            filename, size);
   g_free (filename);
   g_free (size);
+
+  play_preview = egg_play_preview_new_with_uri (uri);
+  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), play_preview);
+
   gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Skip"), BUTTON_SKIP);
   gtk_dialog_add_button (GTK_DIALOG (dialog), _("S_kip All"), BUTTON_SKIP_ALL);
   gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Overwrite"), BUTTON_OVERWRITE);
@@ -321,9 +329,7 @@
       return FALSE;
       break;
   }
-
-
-return ret;
+  return ret;
 }
 
 



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