summaryrefslogtreecommitdiff
path: root/src/totem-search-entry.c
diff options
context:
space:
mode:
authorBastien Nocera <hadess@hadess.net>2014-01-30 13:02:45 +0100
committerBastien Nocera <hadess@hadess.net>2014-01-30 16:54:54 +0100
commit172eda6fc83820d02fc12ef62672f4da77ebd7cd (patch)
treee43a0d6220e0a0efa6dac34c18a9c10d2e19f95d /src/totem-search-entry.c
parent17299064ea6fca785909e9fd2be64b019dbeb12c (diff)
downloadtotem-172eda6fc83820d02fc12ef62672f4da77ebd7cd.tar.gz
grilo: Move grilo plugin to the core
Diffstat (limited to 'src/totem-search-entry.c')
-rw-r--r--src/totem-search-entry.c404
1 files changed, 404 insertions, 0 deletions
diff --git a/src/totem-search-entry.c b/src/totem-search-entry.c
new file mode 100644
index 000000000..6ea50fe94
--- /dev/null
+++ b/src/totem-search-entry.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2012 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser 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 Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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
+ *
+ * Author: Bastien Nocera <hadess@hadess.net>
+ *
+ */
+
+#include "totem-search-entry.h"
+#include "libgd/gd-tagged-entry.h"
+
+G_DEFINE_TYPE (TotemSearchEntry, totem_search_entry, GTK_TYPE_BOX)
+
+enum {
+ SIGNAL_ACTIVATE,
+ LAST_SIGNAL
+};
+
+enum {
+ PROP_0,
+ PROP_SELECTED_ID
+};
+
+static guint signals[LAST_SIGNAL] = { 0, };
+
+struct _TotemSearchEntryPrivate {
+ GtkWidget *entry;
+ GtkWidget *popover;
+ GtkWidget *listbox;
+ GdTaggedEntryTag *tag;
+};
+
+static void
+totem_search_entry_finalize (GObject *obj)
+{
+ TotemSearchEntry *self = TOTEM_SEARCH_ENTRY (obj);
+
+ g_clear_object (&self->priv->tag);
+ g_clear_object (&self->priv->popover);
+
+ G_OBJECT_CLASS (totem_search_entry_parent_class)->finalize (obj);
+}
+
+static void
+entry_activate_cb (GtkEntry *entry,
+ TotemSearchEntry *self)
+{
+ const char *text;
+
+ text = gtk_entry_get_text (GTK_ENTRY (self->priv->entry));
+ if (text == NULL || *text == '\0')
+ return;
+ g_signal_emit (self, signals[SIGNAL_ACTIVATE], 0);
+}
+
+static void
+tag_clicked_cb (GdTaggedEntry *entry,
+ GdTaggedEntryTag *tag,
+ TotemSearchEntry *self)
+{
+ cairo_rectangle_int_t rect;
+
+ if (gd_tagged_entry_tag_get_area (tag, &rect)) {
+ gtk_popover_set_pointing_to (GTK_POPOVER (self->priv->popover), &rect);
+ gtk_widget_show (self->priv->popover);
+ }
+}
+
+static void
+listbox_row_activated (GtkListBox *list_box,
+ GtkListBoxRow *row,
+ gpointer user_data)
+{
+ TotemSearchEntry *self = user_data;
+ GList *children, *l;
+
+ children = gtk_container_get_children (GTK_CONTAINER (list_box));
+ for (l = children; l != NULL; l = l->next) {
+ GtkWidget *check;
+
+ check = g_object_get_data (G_OBJECT (l->data), "check");
+ if (l->data == row) {
+ const char *label;
+
+ gtk_widget_set_opacity (check, 1.0);
+ label = g_object_get_data (G_OBJECT (l->data), "label");
+ gd_tagged_entry_tag_set_label (self->priv->tag, label);
+ g_object_notify (G_OBJECT (self), "selected-id");
+ } else {
+ gtk_widget_set_opacity (check, 0.0);
+ }
+ }
+ g_list_free (children);
+}
+
+static int
+sort_sources (GtkListBoxRow *row_a,
+ GtkListBoxRow *row_b,
+ gpointer user_data)
+{
+ int prio_a, prio_b;
+ const char *name_a, *name_b;
+
+ prio_a = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (row_a), "priority"));
+ prio_b = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (row_b), "priority"));
+
+ if (prio_a > prio_b)
+ return -1;
+ if (prio_b > prio_a)
+ return 1;
+
+ name_a = g_object_get_data (G_OBJECT (row_a), "label");
+ name_b = g_object_get_data (G_OBJECT (row_b), "label");
+
+ return 0 - g_utf8_collate (name_a, name_b);
+}
+
+static void
+totem_search_entry_init (TotemSearchEntry *self)
+{
+ GtkWidget *entry;
+
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TOTEM_TYPE_SEARCH_ENTRY, TotemSearchEntryPrivate);
+
+ /* Entry */
+ entry = GTK_WIDGET (gd_tagged_entry_new ());
+ gd_tagged_entry_set_tag_button_visible (GD_TAGGED_ENTRY (entry), FALSE);
+ gtk_box_pack_start (GTK_BOX (self),
+ entry,
+ TRUE, TRUE, 0);
+ gtk_widget_show (entry);
+
+ self->priv->entry = entry;
+
+ /* Popover */
+ self->priv->popover = gtk_popover_new (GTK_WIDGET (self));
+ gtk_popover_set_modal (GTK_POPOVER (self->priv->popover), TRUE);
+ gtk_popover_set_position (GTK_POPOVER (self->priv->popover), GTK_POS_BOTTOM);
+
+ self->priv->listbox = gtk_list_box_new ();
+ gtk_list_box_set_activate_on_single_click (GTK_LIST_BOX (self->priv->listbox), TRUE);
+ gtk_list_box_set_sort_func (GTK_LIST_BOX (self->priv->listbox), sort_sources, self, NULL);
+ gtk_widget_show (self->priv->listbox);
+ gtk_container_add (GTK_CONTAINER (self->priv->popover), self->priv->listbox);
+
+ g_signal_connect (self->priv->listbox, "row-activated",
+ G_CALLBACK (listbox_row_activated), self);
+
+ /* Connect signals */
+ g_signal_connect (self->priv->entry, "tag-clicked",
+ G_CALLBACK (tag_clicked_cb), self);
+ g_signal_connect (self->priv->entry, "activate",
+ G_CALLBACK (entry_activate_cb), self);
+}
+
+static void
+totem_search_entry_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec * pspec)
+{
+ switch (property_id) {
+ case PROP_SELECTED_ID:
+ totem_search_entry_set_selected_id (TOTEM_SEARCH_ENTRY (object),
+ g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+totem_search_entry_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SELECTED_ID:
+ g_value_set_string (value,
+ totem_search_entry_get_selected_id (TOTEM_SEARCH_ENTRY (object)));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+totem_search_entry_class_init (TotemSearchEntryClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = totem_search_entry_finalize;
+ gobject_class->set_property = totem_search_entry_set_property;
+ gobject_class->get_property = totem_search_entry_get_property;
+
+ signals[SIGNAL_ACTIVATE] =
+ g_signal_new ("activate",
+ TOTEM_TYPE_SEARCH_ENTRY,
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED,
+ 0, NULL, NULL, NULL,
+ G_TYPE_NONE,
+ 0, G_TYPE_NONE);
+
+ g_object_class_install_property (gobject_class, PROP_SELECTED_ID,
+ g_param_spec_string ("selected-id", "Selected ID", "The ID for the currently selected source.",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_type_class_add_private (klass, sizeof (TotemSearchEntryPrivate));
+}
+
+TotemSearchEntry *
+totem_search_entry_new (void)
+{
+ return g_object_new (TOTEM_TYPE_SEARCH_ENTRY, NULL);
+}
+
+static GtkWidget *
+padded_label_new (const char *text)
+{
+ GtkWidget *widget;
+
+ widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
+ gtk_widget_set_margin_top (widget, 10);
+ gtk_widget_set_margin_bottom (widget, 10);
+ gtk_widget_set_margin_start (widget, 10);
+ gtk_widget_set_margin_end (widget, 10);
+ gtk_box_pack_start (GTK_BOX (widget), gtk_label_new (text), FALSE, FALSE, 0);
+
+ return widget;
+}
+
+void
+totem_search_entry_add_source (TotemSearchEntry *self,
+ const gchar *id,
+ const gchar *label,
+ int priority)
+{
+ GtkWidget *item;
+ GtkWidget *check;
+ GtkWidget *box;
+
+ g_return_if_fail (TOTEM_IS_SEARCH_ENTRY (self));
+
+ if (self->priv->tag == NULL) {
+ self->priv->tag = gd_tagged_entry_tag_new (label);
+ gd_tagged_entry_tag_set_has_close_button (self->priv->tag, FALSE);
+ gd_tagged_entry_insert_tag (GD_TAGGED_ENTRY (self->priv->entry), self->priv->tag, -1);
+ gtk_widget_set_sensitive (GTK_WIDGET (self), TRUE);
+ }
+
+ item = gtk_list_box_row_new ();
+ box = padded_label_new (label);
+ gtk_container_add (GTK_CONTAINER (item), box);
+
+ check = gtk_image_new ();
+ gtk_image_set_from_icon_name (GTK_IMAGE (check), "object-select-symbolic", GTK_ICON_SIZE_MENU);
+ gtk_widget_set_opacity (check, 0.0);
+ g_object_set (check, "icon-size", GTK_ICON_SIZE_MENU, NULL);
+ gtk_box_pack_start (GTK_BOX (box), check, FALSE, FALSE, 0);
+ gtk_box_reorder_child (GTK_BOX (box), check, 0);
+
+ g_object_set_data (G_OBJECT (item), "check", check);
+ g_object_set_data_full (G_OBJECT (item), "id", g_strdup (id), g_free);
+ g_object_set_data_full (G_OBJECT (item), "label", g_strdup (label), g_free);
+ g_object_set_data (G_OBJECT (item), "priority", GINT_TO_POINTER (priority));
+
+ gtk_widget_show_all (item);
+ gtk_list_box_insert (GTK_LIST_BOX (self->priv->listbox), item, -1);
+
+ /* Is this the local one? */
+ if (priority == 50) {
+ listbox_row_activated (GTK_LIST_BOX (self->priv->listbox),
+ GTK_LIST_BOX_ROW (item),
+ self);
+ }
+}
+
+void
+totem_search_entry_remove_source (TotemSearchEntry *self,
+ const gchar *id)
+{
+ GList *children, *l;
+ guint num_items;
+ gboolean current_removed = FALSE;
+
+ g_return_if_fail (TOTEM_IS_SEARCH_ENTRY (self));
+
+ children = gtk_container_get_children (GTK_CONTAINER (self->priv->listbox));
+ if (children == NULL)
+ return;
+
+ num_items = g_list_length (children) - 1;
+ for (l = children; l != NULL; l = l->next) {
+ const char *tmp_id;
+
+ tmp_id = g_object_get_data (G_OBJECT (l->data), "id");
+ if (g_strcmp0 (id, tmp_id) == 0) {
+ GtkWidget *check;
+
+ check = g_object_get_data (G_OBJECT (l->data), "check");
+ if (gtk_widget_get_opacity (check) == 1.0)
+ current_removed = TRUE;
+
+ gtk_widget_destroy (l->data);
+ }
+ }
+
+ if (current_removed) {
+ /* FIXME
+ * - don't forget to remove tag
+ * - check if it's the currently selected source and notify of the change if so */
+ }
+
+ if (num_items == 0) {
+ gd_tagged_entry_remove_tag (GD_TAGGED_ENTRY (self->priv->entry), self->priv->tag);
+ g_clear_object (&self->priv->tag);
+ gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE);
+ }
+}
+
+const char *
+totem_search_entry_get_text (TotemSearchEntry *self)
+{
+ g_return_val_if_fail (TOTEM_IS_SEARCH_ENTRY (self), NULL);
+
+ return gtk_entry_get_text (GTK_ENTRY (self->priv->entry));
+}
+
+const char *
+totem_search_entry_get_selected_id (TotemSearchEntry *self)
+{
+ GList *children, *l;
+ const char *id = NULL;
+
+ g_return_val_if_fail (TOTEM_IS_SEARCH_ENTRY (self), NULL);
+ children = gtk_container_get_children (GTK_CONTAINER (self->priv->listbox));
+ for (l = children; l != NULL; l = l->next) {
+ GtkWidget *check;
+
+ check = g_object_get_data (G_OBJECT (l->data), "check");
+ if (gtk_widget_get_opacity (check) == 1.0) {
+ id = g_object_get_data (G_OBJECT (l->data), "id");
+ break;
+ }
+ }
+ g_list_free (children);
+
+ return id;
+}
+
+gboolean
+totem_search_entry_set_selected_id (TotemSearchEntry *self,
+ const char *id)
+{
+ GList *children, *l;
+ gboolean ret = FALSE;
+
+ g_return_if_fail (TOTEM_IS_SEARCH_ENTRY (self));
+ g_return_if_fail (id != NULL);
+
+ children = gtk_container_get_children (GTK_CONTAINER (self->priv->listbox));
+ for (l = children; l != NULL; l = l->next) {
+ const char *item_id;
+
+ item_id = g_object_get_data (G_OBJECT (l->data), "id");
+ if (g_strcmp0 (item_id, id) == 0) {
+ listbox_row_activated (GTK_LIST_BOX (self->priv->listbox),
+ GTK_LIST_BOX_ROW (l->data),
+ self);
+ ret = TRUE;
+ goto end;
+ }
+ }
+
+ g_debug ("Could not find ID '%s' in TotemSearchEntry %p", id, self);
+
+end:
+ g_list_free (children);
+ return ret;
+}
+
+GtkEntry *
+totem_search_entry_get_entry (TotemSearchEntry *self)
+{
+ g_return_val_if_fail (TOTEM_IS_SEARCH_ENTRY (self), NULL);
+
+ return GTK_ENTRY (self->priv->entry);
+}