]> www.fi.muni.cz Git - evince.git/blobdiff - libmisc/ev-page-action-widget.c
Move EvPageAction and EvStockIcons from shell to a new internal library
[evince.git] / libmisc / ev-page-action-widget.c
diff --git a/libmisc/ev-page-action-widget.c b/libmisc/ev-page-action-widget.c
new file mode 100644 (file)
index 0000000..28b6759
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ *  Copyright (C) 2003, 2004 Marco Pesenti Gritti
+ *  Copyright (C) 2003, 2004 Christian Persch
+ *
+ *  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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include <evince-document.h>
+#include "ev-page-action.h"
+#include "ev-page-action-widget.h"
+
+/* Widget we pass back */
+static void  ev_page_action_widget_init       (EvPageActionWidget      *action_widget);
+static void  ev_page_action_widget_class_init (EvPageActionWidgetClass *action_widget);
+
+enum
+{
+       WIDGET_ACTIVATE_LINK,
+       WIDGET_N_SIGNALS
+};
+
+static guint widget_signals[WIDGET_N_SIGNALS] = {0, };
+
+G_DEFINE_TYPE (EvPageActionWidget, ev_page_action_widget, GTK_TYPE_TOOL_ITEM)
+
+static void
+ev_page_action_widget_init (EvPageActionWidget *action_widget)
+{
+       return;
+}
+
+void
+ev_page_action_widget_set_page_cache (EvPageActionWidget *action_widget,
+                                     EvPageCache        *page_cache)
+{
+       if (action_widget->page_cache != NULL) {
+               g_object_remove_weak_pointer (G_OBJECT (action_widget->page_cache),
+                                             (gpointer)&action_widget->page_cache);
+               action_widget->page_cache = NULL;
+       }
+
+       if (page_cache != NULL) {
+               action_widget->page_cache = page_cache;
+               g_object_add_weak_pointer (G_OBJECT (page_cache),
+                                          (gpointer)&action_widget->page_cache);
+       }
+}
+
+static void
+ev_page_action_widget_finalize (GObject *object)
+{
+       EvPageActionWidget *action_widget = EV_PAGE_ACTION_WIDGET (object);
+
+       ev_page_action_widget_set_page_cache (action_widget, NULL);
+
+       G_OBJECT_CLASS (ev_page_action_widget_parent_class)->finalize (object);
+}
+
+static void
+ev_page_action_widget_class_init (EvPageActionWidgetClass *class)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+       object_class->finalize = ev_page_action_widget_finalize;
+
+       widget_signals[WIDGET_ACTIVATE_LINK] = g_signal_new ("activate_link",
+                                              G_OBJECT_CLASS_TYPE (object_class),
+                                              G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                                              G_STRUCT_OFFSET (EvPageActionClass, activate_link),
+                                              NULL, NULL,
+                                              g_cclosure_marshal_VOID__OBJECT,
+                                              G_TYPE_NONE, 1,
+                                              G_TYPE_OBJECT);
+
+}
+
+static gboolean
+match_selected_cb (GtkEntryCompletion *completion,
+                  GtkTreeModel       *filter_model,
+                  GtkTreeIter        *filter_iter,
+                  EvPageActionWidget *proxy)
+{
+       EvLink *link;
+       GtkTreeIter *iter;
+
+       gtk_tree_model_get (filter_model, filter_iter,
+                           0, &iter,
+                           -1);
+       gtk_tree_model_get (proxy->model, iter,
+                           EV_DOCUMENT_LINKS_COLUMN_LINK, &link,
+                           -1);
+
+       g_signal_emit (proxy, widget_signals[WIDGET_ACTIVATE_LINK], 0, link);
+
+       if (link)
+               g_object_unref (link);
+
+       gtk_tree_iter_free (iter);
+       
+       return TRUE;
+}
+                  
+
+static void
+display_completion_text (GtkCellLayout      *cell_layout,
+                        GtkCellRenderer    *renderer,
+                        GtkTreeModel       *filter_model,
+                        GtkTreeIter        *filter_iter,
+                        EvPageActionWidget *proxy)
+{
+       EvLink *link;
+       GtkTreeIter *iter;
+
+       gtk_tree_model_get (filter_model, filter_iter,
+                           0, &iter,
+                           -1);
+       gtk_tree_model_get (proxy->model, iter,
+                           EV_DOCUMENT_LINKS_COLUMN_LINK, &link,
+                           -1);
+
+       g_object_set (renderer, "text", ev_link_get_title (link), NULL);
+
+       if (link)
+               g_object_unref (link);
+       
+       gtk_tree_iter_free (iter);
+}
+
+static gboolean
+match_completion (GtkEntryCompletion *completion,
+                 const gchar        *key,
+                 GtkTreeIter        *filter_iter,
+                 EvPageActionWidget *proxy)
+{
+       EvLink *link;
+       GtkTreeIter *iter;
+       const gchar *text = NULL;
+
+       gtk_tree_model_get (gtk_entry_completion_get_model (completion),
+                           filter_iter,
+                           0, &iter,
+                           -1);
+       gtk_tree_model_get (proxy->model, iter,
+                           EV_DOCUMENT_LINKS_COLUMN_LINK, &link,
+                           -1);
+
+
+       if (link) {
+               text = ev_link_get_title (link);
+               g_object_unref (link);
+       }
+
+       gtk_tree_iter_free (iter);
+
+       if (text && key) {
+               gchar *normalized_text;
+               gchar *normalized_key;
+               gchar *case_normalized_text;
+               gchar *case_normalized_key;
+               gboolean retval = FALSE;
+
+               normalized_text = g_utf8_normalize (text, -1, G_NORMALIZE_ALL);
+               normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
+               case_normalized_text = g_utf8_casefold (normalized_text, -1);
+               case_normalized_key = g_utf8_casefold (normalized_key, -1);
+
+               if (strstr (case_normalized_text, case_normalized_key))
+                       retval = TRUE;
+
+               g_free (normalized_text);
+               g_free (normalized_key);
+               g_free (case_normalized_text);
+               g_free (case_normalized_key);
+
+               return retval;
+       }
+
+       return FALSE;
+}
+
+/* user data to set on the widget. */
+#define EPA_FILTER_MODEL_DATA "epa-filter-model"
+
+static gboolean
+build_new_tree_cb (GtkTreeModel *model,
+                  GtkTreePath  *path,
+                  GtkTreeIter  *iter,
+                  gpointer      data)
+{
+       GtkTreeModel *filter_model = GTK_TREE_MODEL (data);
+       EvLink *link;
+       EvLinkAction *action;
+       EvLinkActionType type;
+
+       gtk_tree_model_get (model, iter,
+                           EV_DOCUMENT_LINKS_COLUMN_LINK, &link,
+                           -1);
+
+       if (!link)
+               return FALSE;
+
+       action = ev_link_get_action (link);
+       if (!action) {
+               g_object_unref (link);
+               return FALSE;
+       }
+       
+       type = ev_link_action_get_action_type (action);
+
+       if (type == EV_LINK_ACTION_TYPE_GOTO_DEST) {
+               GtkTreeIter filter_iter;
+
+               gtk_list_store_append (GTK_LIST_STORE (filter_model), &filter_iter);
+               gtk_list_store_set (GTK_LIST_STORE (filter_model), &filter_iter,
+                                   0, iter,
+                                   -1);
+       }
+       
+       g_object_unref (link);
+       
+       return FALSE;
+}
+
+static GtkTreeModel *
+get_filter_model_from_model (GtkTreeModel *model)
+{
+       GtkTreeModel *filter_model;
+
+       filter_model =
+               (GtkTreeModel *) g_object_get_data (G_OBJECT (model), EPA_FILTER_MODEL_DATA);
+       if (filter_model == NULL) {
+               filter_model = (GtkTreeModel *) gtk_list_store_new (1, GTK_TYPE_TREE_ITER);
+
+               gtk_tree_model_foreach (model,
+                                       build_new_tree_cb,
+                                       filter_model);
+               g_object_set_data_full (G_OBJECT (model), EPA_FILTER_MODEL_DATA, filter_model, g_object_unref);
+       }
+
+       return filter_model;
+}
+
+
+void
+ev_page_action_widget_update_model (EvPageActionWidget *proxy, GtkTreeModel *model)
+{
+       GtkTreeModel *filter_model;
+
+       if (model != NULL) {
+               /* Magik */
+               GtkEntryCompletion *completion;
+               GtkCellRenderer *renderer;
+
+               proxy->model = model;
+               filter_model = get_filter_model_from_model (model);
+
+               completion = gtk_entry_completion_new ();
+
+               g_object_set (G_OBJECT (completion),
+                             "popup-set-width", FALSE,
+                             "model", filter_model,
+                             NULL);
+
+               g_signal_connect (completion, "match-selected", G_CALLBACK (match_selected_cb), proxy);
+               gtk_entry_completion_set_match_func (completion,
+                                                    (GtkEntryCompletionMatchFunc) match_completion,
+                                                    proxy, NULL);
+
+               /* Set up the layout */
+               renderer = (GtkCellRenderer *)
+                       g_object_new (GTK_TYPE_CELL_RENDERER_TEXT,
+                                     "ellipsize", PANGO_ELLIPSIZE_END,
+                                     "width_chars", 30,
+                                     NULL);
+               gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion), renderer, TRUE);
+               gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (completion),
+                                                   renderer,
+                                                   (GtkCellLayoutDataFunc) display_completion_text,
+                                                   proxy, NULL);
+               gtk_entry_set_completion (GTK_ENTRY (proxy->entry), completion);
+               
+               g_object_unref (completion);
+               g_object_unref (model);
+       }
+}