[rhythmbox] add a task list display widget



commit 7c9444746cb01cc4a3be9b19cb832f7129ab4ff5
Author: Jonathan Matthew <jonathan d14n org>
Date:   Tue May 14 21:55:33 2013 +1000

    add a task list display widget
    
    This displays tasks (things that implement the RBTaskProgress
    interface) stored in a list model.

 widgets/Makefile.am            |    6 +-
 widgets/rb-task-list-display.c |  243 ++++++++++++++++++++++++++++++++++++++++
 widgets/rb-task-list-display.h |   66 +++++++++++
 3 files changed, 313 insertions(+), 2 deletions(-)
---
diff --git a/widgets/Makefile.am b/widgets/Makefile.am
index 10456a3..b55076e 100644
--- a/widgets/Makefile.am
+++ b/widgets/Makefile.am
@@ -17,7 +17,8 @@ widgetinclude_HEADERS =                                       \
        rb-fading-image.h                               \
        rb-object-property-editor.h                     \
        rb-import-dialog.h                              \
-       rb-button-bar.h
+       rb-button-bar.h                                 \
+       rb-task-list-display.h
 
 librbwidgets_la_SOURCES =                              \
        $(widgetinclude_HEADERS)                        \
@@ -52,7 +53,8 @@ librbwidgets_la_SOURCES =                             \
        rb-fading-image.c                               \
        rb-object-property-editor.c                     \
        rb-import-dialog.c                              \
-       rb-button-bar.c
+       rb-button-bar.c                                 \
+       rb-task-list-display.c
 
 INCLUDES =                                             \
        -DGNOMELOCALEDIR=\""$(datadir)/locale"\"        \
diff --git a/widgets/rb-task-list-display.c b/widgets/rb-task-list-display.c
new file mode 100644
index 0000000..3339901
--- /dev/null
+++ b/widgets/rb-task-list-display.c
@@ -0,0 +1,243 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ *  Copyright (C) 2013 Jonathan Matthew <jonathan d14n org>
+ *
+ *  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.
+ *
+ *  The Rhythmbox authors hereby grant permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your 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 St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#include <config.h>
+
+#include <widgets/rb-task-list-display.h>
+#include <lib/rb-task-progress.h>
+#include <lib/rb-list-model.h>
+#include <lib/rb-util.h>
+
+#define TASK_REMOVE_DELAY      15
+
+static void rb_task_list_display_class_init (RBTaskListDisplayClass *klass);
+static void rb_task_list_display_init (RBTaskListDisplay *list);
+
+struct _RBTaskListDisplayPrivate
+{
+       RBListModel *model;
+       GArray *widgets;
+};
+
+G_DEFINE_TYPE (RBTaskListDisplay, rb_task_list_display, GTK_TYPE_GRID);
+
+enum {
+       PROP_0,
+       PROP_MODEL
+};
+
+static void
+stop_clicked_cb (GtkButton *button, RBTaskProgress *task)
+{
+       rb_task_progress_cancel (task);
+}
+
+static gboolean
+transform_outcome (GBinding *binding, const GValue *source, GValue *target, gpointer data)
+{
+       RBTaskOutcome outcome;
+       gboolean sensitive;
+
+       outcome = g_value_get_enum (source);
+       switch (outcome) {
+       case RB_TASK_OUTCOME_NONE:
+               sensitive = TRUE;
+               break;
+       case RB_TASK_OUTCOME_COMPLETE:
+       case RB_TASK_OUTCOME_CANCELLED:
+               sensitive = FALSE;
+               break;
+       default:
+               g_assert_not_reached ();
+       }
+
+       g_value_set_boolean (target, sensitive);
+       return TRUE;
+}
+
+static void
+task_list_changed_cb (RBListModel *model, int position, int removed, int added, RBTaskListDisplay *list)
+{
+       int i;
+
+       for (i = 0; i < removed; i++) {
+               GtkWidget *w;
+
+               w = g_array_index (list->priv->widgets, GtkWidget *, position);
+               gtk_container_remove (GTK_CONTAINER (list), w);
+       }
+
+       for (i = 0; i < added; i++) {
+               GtkWidget *tw, *w;
+               RBTaskProgress *task;
+               gboolean cancellable;
+
+               task = RB_TASK_PROGRESS (rb_list_model_get (model, position + i));
+               tw = gtk_grid_new ();
+               g_object_set (tw,
+                             "column-spacing", 12,
+                             "margin", 6,
+                             NULL);
+
+               w = gtk_label_new (NULL);
+               g_object_bind_property (task, "task-label", w, "label", G_BINDING_SYNC_CREATE);
+               g_object_set (w, "hexpand", TRUE, "halign", GTK_ALIGN_START, NULL);
+               gtk_grid_attach (GTK_GRID (tw), w, 0, 0, 1, 1);
+
+               w = gtk_label_new (NULL);
+               gtk_style_context_add_class (gtk_widget_get_style_context (w), GTK_STYLE_CLASS_DIM_LABEL);
+               g_object_bind_property (task, "task-detail", w, "label", G_BINDING_SYNC_CREATE);
+               g_object_set (w, "hexpand", TRUE, "halign", GTK_ALIGN_START, NULL);
+               gtk_grid_attach (GTK_GRID (tw), w, 1, 0, 1, 1);
+
+               w = gtk_progress_bar_new ();
+               g_object_bind_property (task, "task-progress", w, "fraction", G_BINDING_SYNC_CREATE);
+               g_object_set (w, "hexpand", TRUE, NULL);
+               gtk_grid_attach (GTK_GRID (tw), w, 2, 0, 1, 1);
+
+               /* pause/resume button? */
+
+               g_object_get (task, "task-cancellable", &cancellable, NULL);
+               w = gtk_button_new ();
+               gtk_container_add (GTK_CONTAINER (w), gtk_image_new_from_icon_name ("process-stop-symbolic", 
GTK_ICON_SIZE_MENU));
+               if (cancellable) {
+                       g_object_bind_property_full (task, "task-outcome",
+                                                    w, "sensitive",
+                                                    G_BINDING_SYNC_CREATE,
+                                                    transform_outcome,
+                                                    NULL,
+                                                    NULL,
+                                                    NULL);
+               } else {
+                       g_object_set (w, "sensitive", FALSE, NULL);
+               }
+               g_signal_connect_object (w, "clicked", G_CALLBACK (stop_clicked_cb), task, 0);
+               gtk_grid_attach (GTK_GRID (tw), w, 3, 0, 1, 1);
+
+               gtk_grid_insert_column (GTK_GRID (list), position + i);
+               gtk_grid_attach (GTK_GRID (list), tw, position + i, 0, 1, 1);
+               gtk_widget_show_all (tw);
+               g_array_insert_val (list->priv->widgets, position + i, tw);
+       }
+}
+
+static void
+impl_constructed (GObject *object)
+{
+       RBTaskListDisplay *list;
+
+       RB_CHAIN_GOBJECT_METHOD (rb_task_list_display_parent_class, constructed, object);
+
+       list = RB_TASK_LIST_DISPLAY (object);
+       g_signal_connect (list->priv->model, "items-changed", G_CALLBACK (task_list_changed_cb), list);
+       task_list_changed_cb (list->priv->model, 0, 0, rb_list_model_n_items (list->priv->model), list);
+}
+
+static void
+impl_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+       RBTaskListDisplay *list = RB_TASK_LIST_DISPLAY (object);
+       
+       switch (prop_id) {
+       case PROP_MODEL:
+               g_value_set_object (value, list->priv->model);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+impl_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+       RBTaskListDisplay *list = RB_TASK_LIST_DISPLAY (object);
+       
+       switch (prop_id) {
+       case PROP_MODEL:
+               list->priv->model = g_value_dup_object (value);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+impl_dispose (GObject *object)
+{
+       RBTaskListDisplay *list = RB_TASK_LIST_DISPLAY (object);
+       
+       if (list->priv->model != NULL) {
+               g_signal_handlers_disconnect_by_func (list->priv->model, task_list_changed_cb, list);
+               g_clear_object (&list->priv->model);
+       }
+       if (list->priv->widgets != NULL) {
+               g_array_free (list->priv->widgets, TRUE);
+               list->priv->widgets = NULL;
+       }
+       G_OBJECT_CLASS (rb_task_list_display_parent_class)->dispose (object);
+}
+
+static void
+rb_task_list_display_init (RBTaskListDisplay *list)
+{
+       list->priv = G_TYPE_INSTANCE_GET_PRIVATE (list, RB_TYPE_TASK_LIST_DISPLAY, RBTaskListDisplayPrivate);
+
+       list->priv->widgets = g_array_new (FALSE, FALSE, sizeof (GtkWidget *));
+}
+
+static void
+rb_task_list_display_class_init (RBTaskListDisplayClass *klass)
+{
+       GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+       g_type_class_add_private (klass, sizeof (RBTaskListDisplayPrivate));
+
+       gobject_class->constructed = impl_constructed;
+       gobject_class->dispose = impl_dispose;
+       gobject_class->set_property = impl_set_property;
+       gobject_class->get_property = impl_get_property;
+
+       g_object_class_install_property (gobject_class,
+                                        PROP_MODEL,
+                                        g_param_spec_object ("model",
+                                                             "model",
+                                                             "model",
+                                                             RB_TYPE_LIST_MODEL,
+                                                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+GtkWidget *
+rb_task_list_display_new (RBListModel *model)
+{
+       return GTK_WIDGET (g_object_new (RB_TYPE_TASK_LIST_DISPLAY,
+                                        "model", model,
+                                        "row-spacing", 12,
+                                        NULL));
+}
diff --git a/widgets/rb-task-list-display.h b/widgets/rb-task-list-display.h
new file mode 100644
index 0000000..579906c
--- /dev/null
+++ b/widgets/rb-task-list-display.h
@@ -0,0 +1,66 @@
+/*
+ *  Copyright (C) 2013 Jonathan Matthew  <jonathan d14n org>
+ *
+ *  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.
+ *
+ *  The Rhythmbox authors hereby grant permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your 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 St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#ifndef RB_TASK_LIST_DISPLAY_H
+#define RB_TASK_LIST_DISPLAY_H
+
+#include <gtk/gtk.h>
+
+#include <lib/rb-list-model.h>
+
+G_BEGIN_DECLS
+
+#define RB_TYPE_TASK_LIST_DISPLAY         (rb_task_list_display_get_type ())
+#define RB_TASK_LIST_DISPLAY(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_TASK_LIST_DISPLAY, 
RBTaskListDisplay))
+#define RB_TASK_LIST_DISPLAY_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_TASK_LIST_DISPLAY, 
RBTaskListDisplayClass))
+#define RB_IS_TASK_LIST_DISPLAY(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_TASK_LIST_DISPLAY))
+#define RB_IS_TASK_LIST_DISPLAY_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_TASK_LIST_DISPLAY))
+#define RB_TASK_LIST_DISPLAY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_TASK_LIST_DISPLAY, 
RBTaskListDisplayClass))
+
+typedef struct _RBTaskListDisplay RBTaskListDisplay;
+typedef struct _RBTaskListDisplayClass RBTaskListDisplayClass;
+typedef struct _RBTaskListDisplayPrivate RBTaskListDisplayPrivate;
+
+struct _RBTaskListDisplay
+{
+       GtkGrid parent;
+
+       RBTaskListDisplayPrivate *priv;
+};
+
+struct _RBTaskListDisplayClass
+{
+       GtkGridClass parent;
+};
+
+GType          rb_task_list_display_get_type           (void);
+
+GtkWidget *    rb_task_list_display_new                (RBListModel *model);
+
+G_END_DECLS
+
+#endif /* RB_TASK_LIST_DISPLAY_H */


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