[devhelp] sidebar: merge 'Contents' and 'Search' tabs into a new 'Sidebar'



commit 671e0e87f17c1d6885dbace94f3f7f68cbdd497f
Author: Aleksander Morgado <aleksander lanedo com>
Date:   Fri Feb 1 12:59:50 2013 +0100

    sidebar: merge 'Contents' and 'Search' tabs into a new 'Sidebar'
    
    Contents tree will be shown when no search string is given.

 src/Makefile.am    |    4 +-
 src/devhelp.h      |    2 +-
 src/dh-book-tree.c |    6 +-
 src/dh-book-tree.h |   10 +-
 src/dh-search.c    | 1217 ----------------------------------------------------
 src/dh-search.h    |   60 ---
 src/dh-sidebar.c   |  584 +++++++++++++++++++++++++
 src/dh-sidebar.h   |   66 +++
 src/dh-window.c    |  193 +--------
 9 files changed, 681 insertions(+), 1461 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 8cea1b4..8b0d3d7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -72,7 +72,7 @@ INST_H_FILES = 						\
 	dh-error.h					\
 	dh-keyword-model.h				\
 	dh-link.h					\
-	dh-search.h					\
+	dh-sidebar.h					\
 	dh-window.h
 
 devhelpincludedir = $(includedir)/devhelp-3.0/devhelp
@@ -94,7 +94,7 @@ libdevhelp_3_la_SOURCES =				\
 	dh-error.c					\
 	dh-keyword-model.c				\
 	dh-link.c					\
-	dh-search.c					\
+	dh-sidebar.c					\
 	dh-parser.c					\
 	dh-preferences.c				\
 	dh-util.c					\
diff --git a/src/devhelp.h b/src/devhelp.h
index 4072d8f..c71471d 100644
--- a/src/devhelp.h
+++ b/src/devhelp.h
@@ -33,7 +33,7 @@
 #include "dh-error.h"
 #include "dh-keyword-model.h"
 #include "dh-link.h"
-#include "dh-search.h"
+#include "dh-sidebar.h"
 #include "dh-window.h"
 
 G_BEGIN_DECLS
diff --git a/src/dh-book-tree.c b/src/dh-book-tree.c
index 3bbdb4a..44dfa23 100644
--- a/src/dh-book-tree.c
+++ b/src/dh-book-tree.c
@@ -765,8 +765,8 @@ dh_book_tree_select_uri (DhBookTree  *tree,
 	gtk_tree_path_free (data.path);
 }
 
-const gchar *
-dh_book_tree_get_selected_book_title (DhBookTree *tree)
+DhLink *
+dh_book_tree_get_selected_book (DhBookTree *tree)
 {
 	GtkTreeSelection *selection;
 	GtkTreeModel     *model;
@@ -797,5 +797,5 @@ dh_book_tree_get_selected_book_title (DhBookTree *tree)
 			    COL_LINK, &link,
 			    -1);
 
-	return link ? dh_link_get_name (link) : NULL;
+	return link;
 }
diff --git a/src/dh-book-tree.h b/src/dh-book-tree.h
index 885b09c..f5dc34a 100644
--- a/src/dh-book-tree.h
+++ b/src/dh-book-tree.h
@@ -44,11 +44,11 @@ struct _DhBookTreeClass {
         GtkTreeViewClass parent_class;
 };
 
-GType        dh_book_tree_get_type                (void) G_GNUC_CONST;
-GtkWidget *  dh_book_tree_new                     (DhBookManager *book_manager);
-void         dh_book_tree_select_uri              (DhBookTree    *book_tree,
-                                                   const gchar   *uri);
-const gchar *dh_book_tree_get_selected_book_title (DhBookTree    *tree);
+GType        dh_book_tree_get_type          (void) G_GNUC_CONST;
+GtkWidget *  dh_book_tree_new               (DhBookManager *book_manager);
+void         dh_book_tree_select_uri        (DhBookTree    *book_tree,
+                                             const gchar   *uri);
+DhLink      *dh_book_tree_get_selected_book (DhBookTree    *tree);
 
 G_END_DECLS
 
diff --git a/src/dh-sidebar.c b/src/dh-sidebar.c
new file mode 100644
index 0000000..c985f91
--- /dev/null
+++ b/src/dh-sidebar.c
@@ -0,0 +1,584 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2001-2003 CodeFactory AB
+ * Copyright (C) 2001-2003 Mikael Hallendal <micke imendio com>
+ * Copyright (C) 2005-2008 Imendio AB
+ * Copyright (C) 2010 Lanedo GmbH
+ * Copyright (C) 2013 Aleksander Morgado <aleksander gnu 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.
+ *
+ * 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-lib.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+
+#include "dh-marshal.h"
+#include "dh-keyword-model.h"
+#include "dh-sidebar.h"
+#include "dh-util.h"
+#include "dh-book-manager.h"
+#include "dh-book.h"
+#include "dh-book-tree.h"
+
+G_DEFINE_TYPE (DhSidebar, dh_sidebar, GTK_TYPE_VBOX)
+
+enum {
+        LINK_SELECTED,
+        LAST_SIGNAL
+};
+
+struct _DhSidebarPrivate {
+        DhKeywordModel *model;
+
+        DhBookManager  *book_manager;
+
+        DhLink         *selected_link;
+
+        GtkWidget      *search_all_button;
+        GtkWidget      *search_current_button;
+        GtkWidget      *entry;
+        GtkWidget      *hitlist;
+        GtkWidget      *sw_hitlist;
+        GtkWidget      *book_tree;
+        GtkWidget      *sw_book_tree;
+
+        GCompletion    *completion;
+        guint           idle_complete;
+        guint           idle_filter;
+};
+
+static gint signals[LAST_SIGNAL] = { 0 };
+
+/******************************************************************************/
+
+static gboolean
+sidebar_filter_idle (DhSidebar *self)
+{
+        const gchar *str;
+        DhLink      *link;
+        DhLink      *book_link;
+
+        self->priv->idle_filter = 0;
+
+        str = gtk_entry_get_text (GTK_ENTRY (self->priv->entry));
+
+        book_link = (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->priv->search_all_button)) ?
+                     NULL :
+                     dh_sidebar_get_selected_book (self));
+
+        link = dh_keyword_model_filter (self->priv->model,
+                                        str,
+                                        book_link ? dh_link_get_book_id (book_link) : NULL,
+                                        NULL);
+
+        if (link)
+                g_signal_emit (self, signals[LINK_SELECTED], 0, link);
+
+        return FALSE;
+}
+
+static void
+sidebar_search_run_idle (DhSidebar *self)
+{
+        if (!self->priv->idle_filter)
+                self->priv->idle_filter =
+                        g_idle_add ((GSourceFunc) sidebar_filter_idle, self);
+}
+
+/******************************************************************************/
+
+static void
+sidebar_completion_add_book (DhSidebar *self,
+                             DhBook    *book)
+{
+        GList *completions;
+
+        if (G_UNLIKELY (!self->priv->completion))
+                self->priv->completion = g_completion_new (NULL);
+
+        completions = dh_book_get_completions (book);
+        if (completions)
+                g_completion_add_items (self->priv->completion, completions);
+}
+
+static void
+sidebar_completion_delete_book (DhSidebar *self,
+                                DhBook    *book)
+{
+        GList *completions;
+
+        if (G_UNLIKELY (!self->priv->completion))
+                return;
+
+        completions = dh_book_get_completions (book);
+        if (completions)
+                g_completion_remove_items (self->priv->completion, completions);
+}
+
+static void
+sidebar_book_created_or_enabled_cb (DhBookManager *book_manager,
+                                    DhBook        *book,
+                                    DhSidebar     *self)
+{
+        sidebar_completion_add_book (self, book);
+        /* Update current search if any */
+        sidebar_search_run_idle (self);
+}
+
+static void
+sidebar_book_deleted_or_disabled_cb (DhBookManager *book_manager,
+                                     DhBook        *book,
+                                     DhSidebar     *self)
+{
+        sidebar_completion_delete_book (self, book);
+        /* Update current search if any */
+        sidebar_search_run_idle (self);
+}
+
+static void
+sidebar_completion_populate (DhSidebar *self)
+{
+        GList        *l;
+
+        for (l = dh_book_manager_get_books (self->priv->book_manager);
+             l;
+             l = g_list_next (l)) {
+                sidebar_completion_add_book (self, DH_BOOK (l->data));
+        }
+}
+
+/******************************************************************************/
+
+static void
+sidebar_selection_changed_cb (GtkTreeSelection *selection,
+                              DhSidebar        *self)
+{
+        GtkTreeIter   iter;
+
+        if (gtk_tree_selection_get_selected (selection, NULL, &iter)) {
+                DhLink *link;
+
+                gtk_tree_model_get (GTK_TREE_MODEL (self->priv->model), &iter,
+                                    DH_KEYWORD_MODEL_COL_LINK, &link,
+                                    -1);
+
+                if (link != self->priv->selected_link) {
+                        self->priv->selected_link = link;
+                        g_signal_emit (self, signals[LINK_SELECTED], 0, link);
+                }
+        }
+}
+
+/* Make it possible to jump back to the currently selected item, useful when the
+ * html view has been scrolled away.
+ */
+static gboolean
+sidebar_tree_button_press_cb (GtkTreeView    *view,
+                              GdkEventButton *event,
+                              DhSidebar      *self)
+{
+        GtkTreePath  *path;
+        GtkTreeIter   iter;
+        DhLink       *link;
+
+        gtk_tree_view_get_path_at_pos (view, event->x, event->y, &path,
+                                       NULL, NULL, NULL);
+        if (!path)
+                return FALSE;
+
+        gtk_tree_model_get_iter (GTK_TREE_MODEL (self->priv->model), &iter, path);
+        gtk_tree_path_free (path);
+
+        gtk_tree_model_get (GTK_TREE_MODEL (self->priv->model),
+                            &iter,
+                            DH_KEYWORD_MODEL_COL_LINK, &link,
+                            -1);
+
+        self->priv->selected_link = link;
+
+        g_signal_emit (self, signals[LINK_SELECTED], 0, link);
+
+        /* Always return FALSE so the tree view gets the event and can update
+         * the selection etc.
+         */
+        return FALSE;
+}
+
+static gboolean
+sidebar_entry_key_press_event_cb (GtkEntry    *entry,
+                                  GdkEventKey *event,
+                                  DhSidebar   *self)
+{
+        if (event->keyval == GDK_KEY_Tab) {
+                if (event->state & GDK_CONTROL_MASK) {
+                        gtk_widget_grab_focus (self->priv->hitlist);
+                } else {
+                        gtk_editable_set_position (GTK_EDITABLE (entry), -1);
+                        gtk_editable_select_region (GTK_EDITABLE (entry), -1, -1);
+                }
+                return TRUE;
+        }
+
+        if (event->keyval == GDK_KEY_Return ||
+            event->keyval == GDK_KEY_KP_Enter) {
+                GtkTreeIter  iter;
+                DhLink      *link;
+                gchar       *name;
+
+                /* Get the first entry found. */
+                if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->priv->model), &iter)) {
+                        gtk_tree_model_get (GTK_TREE_MODEL (self->priv->model),
+                                            &iter,
+                                            DH_KEYWORD_MODEL_COL_LINK, &link,
+                                            DH_KEYWORD_MODEL_COL_NAME, &name,
+                                            -1);
+
+                        gtk_entry_set_text (GTK_ENTRY (entry), name);
+                        g_free (name);
+
+                        gtk_editable_set_position (GTK_EDITABLE (entry), -1);
+                        gtk_editable_select_region (GTK_EDITABLE (entry), -1, -1);
+
+                        g_signal_emit (self, signals[LINK_SELECTED], 0, link);
+
+                        return TRUE;
+                }
+        }
+
+        return FALSE;
+}
+
+static void
+sidebar_entry_changed_cb (GtkEntry  *entry,
+                          DhSidebar *self)
+{
+        /* If search entry is empty, hide the hitlist */
+        if (strcmp (gtk_entry_get_text (entry), "") == 0) {
+                gtk_widget_hide (self->priv->sw_hitlist);
+                gtk_widget_show (self->priv->sw_book_tree);
+                return;
+        }
+
+        gtk_widget_hide (self->priv->sw_book_tree);
+        gtk_widget_show (self->priv->sw_hitlist);
+        sidebar_search_run_idle (self);
+}
+
+static gboolean
+sidebar_complete_idle (DhSidebar *self)
+{
+        const gchar  *str;
+        gchar        *completed = NULL;
+        gsize         length;
+
+        str = gtk_entry_get_text (GTK_ENTRY (self->priv->entry));
+
+        g_completion_complete (self->priv->completion, str, &completed);
+        if (completed) {
+                length = strlen (str);
+
+                gtk_entry_set_text (GTK_ENTRY (self->priv->entry), completed);
+                gtk_editable_set_position (GTK_EDITABLE (self->priv->entry), length);
+                gtk_editable_select_region (GTK_EDITABLE (self->priv->entry),
+                                            length, -1);
+                g_free (completed);
+        }
+
+        self->priv->idle_complete = 0;
+
+        return FALSE;
+}
+
+static void
+sidebar_entry_text_inserted_cb (GtkEntry    *entry,
+                                const gchar *text,
+                                gint         length,
+                                gint        *position,
+                                DhSidebar   *self)
+{
+        if (!self->priv->idle_complete)
+                self->priv->idle_complete =
+                        g_idle_add ((GSourceFunc) sidebar_complete_idle, self);
+}
+
+/******************************************************************************/
+
+void
+dh_sidebar_set_search_string (DhSidebar   *self,
+                              const gchar *str)
+{
+        g_return_if_fail (DH_IS_SIDEBAR (self));
+
+        /* Mark "All books" as active */
+        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->priv->search_all_button), TRUE);
+
+        g_signal_handlers_block_by_func (self->priv->entry,
+                                         sidebar_entry_changed_cb,
+                                         self);
+
+        gtk_entry_set_text (GTK_ENTRY (self->priv->entry), str);
+        gtk_editable_set_position (GTK_EDITABLE (self->priv->entry), -1);
+        gtk_editable_select_region (GTK_EDITABLE (self->priv->entry), -1, -1);
+
+        g_signal_handlers_unblock_by_func (self->priv->entry,
+                                           sidebar_entry_changed_cb,
+                                           self);
+
+        sidebar_search_run_idle (self);
+}
+
+/******************************************************************************/
+
+static void
+search_cell_data_func (GtkTreeViewColumn *tree_column,
+                       GtkCellRenderer   *cell,
+                       GtkTreeModel      *tree_model,
+                       GtkTreeIter       *iter,
+                       gpointer           data)
+{
+        DhLink       *link;
+        PangoStyle    style;
+
+        gtk_tree_model_get (tree_model, iter,
+                            DH_KEYWORD_MODEL_COL_LINK, &link,
+                            -1);
+
+        style = PANGO_STYLE_NORMAL;
+
+        if (dh_link_get_flags (link) & DH_LINK_FLAGS_DEPRECATED)
+                style |= PANGO_STYLE_ITALIC;
+
+        g_object_set (cell,
+                      "text", dh_link_get_name (link),
+                      "style", style,
+                      NULL);
+}
+
+/******************************************************************************/
+
+static void
+search_filter_button_toggled (GtkToggleButton *button,
+                              DhSidebar       *self)
+{
+        sidebar_search_run_idle (self);
+}
+
+/******************************************************************************/
+
+static void
+sidebar_book_tree_link_selected_cb (GObject   *ignored,
+                                    DhLink    *link,
+                                    DhSidebar *self)
+{
+        if (link != self->priv->selected_link) {
+                self->priv->selected_link = link;
+                g_signal_emit (self, signals[LINK_SELECTED], 0, link);
+        }
+}
+
+DhLink *
+dh_sidebar_get_selected_book (DhSidebar *self)
+{
+        return dh_book_tree_get_selected_book (DH_BOOK_TREE (self->priv->book_tree));
+}
+
+void
+dh_sidebar_select_uri (DhSidebar   *self,
+                       const gchar *uri)
+{
+        dh_book_tree_select_uri (DH_BOOK_TREE (self->priv->book_tree), uri);
+}
+
+/******************************************************************************/
+
+GtkWidget *
+dh_sidebar_new (DhBookManager *book_manager)
+{
+        DhSidebar        *self;
+        GtkCellRenderer  *cell;
+        GtkWidget        *hbox;
+        GtkWidget        *button_box;
+
+        self = g_object_new (DH_TYPE_SIDEBAR, NULL);
+        gtk_container_set_border_width (GTK_CONTAINER (self), 2);
+        gtk_box_set_spacing (GTK_BOX (self), 4);
+
+        /* Setup keyword model */
+        self->priv->model = dh_keyword_model_new ();
+
+        /* Setup hitlist */
+        self->priv->hitlist = gtk_tree_view_new ();
+        gtk_tree_view_set_model (GTK_TREE_VIEW (self->priv->hitlist), GTK_TREE_MODEL (self->priv->model));
+        gtk_tree_view_set_enable_search (GTK_TREE_VIEW (self->priv->hitlist), FALSE);
+
+        /* Setup book manager */
+        self->priv->book_manager = g_object_ref (book_manager);
+        g_signal_connect (self->priv->book_manager,
+                          "book-created",
+                          G_CALLBACK (sidebar_book_created_or_enabled_cb),
+                          self);
+        g_signal_connect (self->priv->book_manager,
+                          "book-deleted",
+                          G_CALLBACK (sidebar_book_deleted_or_disabled_cb),
+                          self);
+        g_signal_connect (self->priv->book_manager,
+                          "book-enabled",
+                          G_CALLBACK (sidebar_book_created_or_enabled_cb),
+                          self);
+        g_signal_connect (self->priv->book_manager,
+                          "book-disabled",
+                          G_CALLBACK (sidebar_book_deleted_or_disabled_cb),
+                          self);
+
+        /* Setup the top-level box with entry search and Current|All buttons */
+	hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+        gtk_box_pack_start (GTK_BOX (self), hbox, FALSE, FALSE, 0);
+
+        /* Setup the search entry */
+        self->priv->entry = gtk_search_entry_new ();
+	gtk_box_pack_start (GTK_BOX (hbox), self->priv->entry, TRUE, TRUE, 0);
+        g_signal_connect (self->priv->entry, "key-press-event",
+                          G_CALLBACK (sidebar_entry_key_press_event_cb),
+                          self);
+        g_signal_connect (self->priv->hitlist, "button-press-event",
+                          G_CALLBACK (sidebar_tree_button_press_cb),
+                          self);
+        g_signal_connect (self->priv->entry, "changed",
+                          G_CALLBACK (sidebar_entry_changed_cb),
+                          self);
+        g_signal_connect (self->priv->entry, "insert-text",
+                          G_CALLBACK (sidebar_entry_text_inserted_cb),
+                          self);
+        gtk_box_pack_start (GTK_BOX (self), self->priv->entry, FALSE, FALSE, 0);
+
+	/* Setup the Current/All Files selector */
+	self->priv->search_current_button = gtk_radio_button_new_with_label (NULL, _("Current"));
+	gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (self->priv->search_current_button), FALSE);
+	self->priv->search_all_button = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (self->priv->search_current_button),
+                                                                                     _("All Books"));
+	gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (self->priv->search_all_button), FALSE);
+        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->priv->search_all_button), TRUE);
+	g_signal_connect (self->priv->search_current_button,
+                          "toggled",
+			  G_CALLBACK (search_filter_button_toggled),
+                          self);
+	button_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+	gtk_box_pack_start (GTK_BOX (hbox), button_box, FALSE, FALSE, 0);
+	gtk_style_context_add_class (gtk_widget_get_style_context (button_box),
+				     GTK_STYLE_CLASS_LINKED);
+	gtk_style_context_add_class (gtk_widget_get_style_context (button_box),
+				     GTK_STYLE_CLASS_RAISED);
+	gtk_box_pack_start (GTK_BOX (button_box), self->priv->search_current_button, FALSE, FALSE, 0);
+	gtk_box_pack_start (GTK_BOX (button_box), self->priv->search_all_button, FALSE, FALSE, 0);
+
+        /* Setup the hitlist */
+        self->priv->sw_hitlist = gtk_scrolled_window_new (NULL, NULL);
+        gtk_widget_set_no_show_all (self->priv->sw_hitlist, TRUE);
+        gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (self->priv->sw_hitlist), GTK_SHADOW_IN);
+        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (self->priv->sw_hitlist),
+                                        GTK_POLICY_NEVER,
+                                        GTK_POLICY_AUTOMATIC);
+        cell = gtk_cell_renderer_text_new ();
+        g_object_set (cell,
+                      "ellipsize", PANGO_ELLIPSIZE_END,
+                      NULL);
+        gtk_tree_view_insert_column_with_data_func (
+                GTK_TREE_VIEW (self->priv->hitlist),
+                -1,
+                NULL,
+                cell,
+                search_cell_data_func,
+                self,
+                NULL);
+        gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (self->priv->hitlist), FALSE);
+        gtk_tree_view_set_search_column (GTK_TREE_VIEW (self->priv->hitlist), DH_KEYWORD_MODEL_COL_NAME);
+        g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (self->priv->hitlist)),
+                          "changed",
+                          G_CALLBACK (sidebar_selection_changed_cb),
+                          self);
+        gtk_widget_show (self->priv->hitlist);
+        gtk_container_add (GTK_CONTAINER (self->priv->sw_hitlist), self->priv->hitlist);
+        gtk_box_pack_start (GTK_BOX (self), self->priv->sw_hitlist, TRUE, TRUE, 0);
+
+        /* Setup the book tree */
+        self->priv->sw_book_tree = gtk_scrolled_window_new (NULL, NULL);
+        gtk_widget_show (self->priv->sw_book_tree);
+        gtk_widget_set_no_show_all (self->priv->sw_book_tree, TRUE);
+        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (self->priv->sw_book_tree),
+                                        GTK_POLICY_NEVER,
+                                        GTK_POLICY_AUTOMATIC);
+        gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (self->priv->sw_book_tree),
+                                             GTK_SHADOW_IN);
+        gtk_container_set_border_width (GTK_CONTAINER (self->priv->sw_book_tree), 2);
+        self->priv->book_tree = dh_book_tree_new (self->priv->book_manager);
+        gtk_widget_show (self->priv->book_tree);
+        g_signal_connect (self->priv->book_tree,
+                          "link-selected",
+                          G_CALLBACK (sidebar_book_tree_link_selected_cb),
+                          self);
+        gtk_container_add (GTK_CONTAINER (self->priv->sw_book_tree), self->priv->book_tree);
+        gtk_box_pack_end (GTK_BOX (self), self->priv->sw_book_tree, TRUE, TRUE, 0);
+
+        sidebar_completion_populate (self);
+
+        dh_keyword_model_set_words (self->priv->model, self->priv->book_manager);
+
+        gtk_widget_show_all (GTK_WIDGET (self));
+
+        return GTK_WIDGET (self);
+}
+
+static void
+sidebar_finalize (GObject *object)
+{
+        DhSidebar *self = DH_SIDEBAR (object);
+
+        g_completion_free (self->priv->completion);
+        g_object_unref (self->priv->book_manager);
+
+        G_OBJECT_CLASS (dh_sidebar_parent_class)->finalize (object);
+}
+
+static void
+dh_sidebar_init (DhSidebar *self)
+{
+        self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+                                                  DH_TYPE_SIDEBAR,
+                                                  DhSidebarPrivate);
+}
+
+static void
+dh_sidebar_class_init (DhSidebarClass *klass)
+{
+        GObjectClass   *object_class = (GObjectClass *) klass;
+
+        object_class->finalize = sidebar_finalize;
+        g_type_class_add_private (klass, sizeof (DhSidebarPrivate));
+
+        signals[LINK_SELECTED] =
+                g_signal_new ("link_selected",
+                              G_TYPE_FROM_CLASS (klass),
+                              G_SIGNAL_RUN_LAST,
+                              G_STRUCT_OFFSET (DhSidebarClass, link_selected),
+                              NULL, NULL,
+                              _dh_marshal_VOID__POINTER,
+                              G_TYPE_NONE,
+                              1, G_TYPE_POINTER);
+}
diff --git a/src/dh-sidebar.h b/src/dh-sidebar.h
new file mode 100644
index 0000000..8245e79
--- /dev/null
+++ b/src/dh-sidebar.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2001-2002 CodeFactory AB
+ * Copyright (C) 2001-2002 Mikael Hallendal <micke imendio com>
+ * Copyright (C) 2013 Aleksander Morgado <aleksander gnu 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.
+ *
+ * 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.
+ */
+
+#ifndef __DH_SIDEBAR_H__
+#define __DH_SIDEBAR_H__
+
+#include <gtk/gtk.h>
+#include "dh-link.h"
+#include "dh-book-manager.h"
+
+G_BEGIN_DECLS
+
+#define DH_TYPE_SIDEBAR           (dh_sidebar_get_type ())
+#define DH_SIDEBAR(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), DH_TYPE_SIDEBAR, DhSidebar))
+#define DH_SIDEBAR_CLASS(klass)   (G_TYPE_CHECK_CLASS_CAST ((klass), DH_TYPE_SIDEBAR, DhSidebarClass))
+#define DH_IS_SIDEBAR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DH_TYPE_SIDEBAR))
+#define DH_IS_SIDEBAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DH_TYPE_SIDEBAR))
+
+typedef struct _DhSidebar        DhSidebar;
+typedef struct _DhSidebarClass   DhSidebarClass;
+typedef struct _DhSidebarPrivate DhSidebarPrivate;
+
+struct _DhSidebar {
+        GtkVBox           parent_instance;
+        DhSidebarPrivate *priv;
+};
+
+struct _DhSidebarClass {
+        GtkVBoxClass parent_class;
+
+        /* Signals */
+        void (*link_selected) (DhSidebar *search,
+                               DhLink    *link);
+};
+
+GType      dh_sidebar_get_type (void);
+GtkWidget *dh_sidebar_new      (DhBookManager *book_manager);
+
+DhLink    *dh_sidebar_get_selected_book (DhSidebar *self);
+void       dh_sidebar_select_uri        (DhSidebar   *self,
+                                         const gchar *uri);
+void       dh_sidebar_set_search_string (DhSidebar   *self,
+                                         const gchar *str);
+
+G_END_DECLS
+
+#endif /* __DH_SIDEBAR_H__ */
diff --git a/src/dh-window.c b/src/dh-window.c
index 3137c40..3f1d035 100644
--- a/src/dh-window.c
+++ b/src/dh-window.c
@@ -38,10 +38,9 @@
 
 #include <libgd/gd.h>
 
-#include "dh-book-tree.h"
 #include "dh-book-manager.h"
 #include "dh-book.h"
-#include "dh-search.h"
+#include "dh-sidebar.h"
 #include "dh-window.h"
 #include "dh-util.h"
 #include "dh-marshal.h"
@@ -54,9 +53,7 @@
 struct _DhWindowPriv {
         GtkWidget      *main_box;
         GtkWidget      *hpaned;
-        GtkWidget      *control_notebook;
-        GtkWidget      *book_tree;
-        GtkWidget      *search;
+        GtkWidget      *sidebar;
         GtkWidget      *notebook;
 
         GtkWidget      *vbox;
@@ -110,9 +107,6 @@ static const guint n_zoom_levels = G_N_ELEMENTS (zoom_levels);
 static void           dh_window_class_init           (DhWindowClass   *klass);
 static void           dh_window_init                 (DhWindow        *window);
 static void           window_populate                (DhWindow        *window);
-static void           window_tree_link_selected_cb   (GObject         *ignored,
-                                                      DhLink          *link,
-                                                      DhWindow        *window);
 static void           window_search_link_selected_cb (GObject         *ignored,
                                                       DhLink          *link,
                                                       DhWindow        *window);
@@ -237,7 +231,7 @@ copy_cb (GSimpleAction *action,
         if (GTK_IS_EDITABLE (widget)) {
                 gtk_editable_copy_clipboard (GTK_EDITABLE (widget));
         } else if (GTK_IS_TREE_VIEW (widget) &&
-                   gtk_widget_is_ancestor (widget, priv->search) &&
+                   gtk_widget_is_ancestor (widget, priv->sidebar) &&
                    priv->selected_search_link) {
                 GtkClipboard *clipboard;
                 clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
@@ -435,34 +429,6 @@ go_forward_cb (GSimpleAction *action,
 }
 
 static void
-go_contents_tab_cb (GSimpleAction *action,
-                    GVariant      *parameter,
-                    gpointer       user_data)
-{
-        DhWindow     *window = user_data;
-        DhWindowPriv *priv;
-
-        priv = window->priv;
-
-        gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->control_notebook), 0);
-        gtk_widget_grab_focus (priv->book_tree);
-}
-
-static void
-go_search_tab_cb (GSimpleAction *action,
-                  GVariant      *parameter,
-                  gpointer       user_data)
-{
-        DhWindow     *window = user_data;
-        DhWindowPriv *priv;
-
-        priv = window->priv;
-
-        gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->control_notebook), 1);
-        gtk_widget_grab_focus (priv->search);
-}
-
-static void
 window_open_link_cb (DhWindow *window,
                      const char *location,
                      DhOpenLinkFlags flags)
@@ -492,8 +458,6 @@ static GActionEntry win_entries[] = {
         /* go */
         { "go-back",          go_back_cb,          NULL, "false", NULL },
         { "go-forward",       go_forward_cb,       NULL, "false", NULL },
-        { "go-contents-tab",  go_contents_tab_cb,  NULL, NULL, NULL },
-        { "go-search-tab",    go_search_tab_cb,    NULL, NULL, NULL },
 };
 
 static void
@@ -537,7 +501,6 @@ dh_window_init (DhWindow *window)
         GtkAccelGroup *accel_group;
         GClosure      *closure;
         gint           i;
-        gchar         *path;
         GError        *error = NULL;
 
         priv = GET_PRIVATE (window);
@@ -628,45 +591,6 @@ dh_window_class_init (DhWindowClass *klass)
                              "style \"devhelp-tab-close-button-style\"");
 }
 
-/* The ugliest hack. When switching tabs, the selection and cursor is changed
- * for the tree view so the web_view content is changed. Block the signal during
- * switch.
- */
-static void
-window_control_switch_page_cb (GtkWidget       *notebook,
-                               gpointer         page,
-                               guint            page_num,
-                               DhWindow        *window)
-{
-        DhWindowPriv *priv;
-
-        priv = window->priv;
-
-        g_signal_handlers_block_by_func (priv->book_tree,
-                                         window_tree_link_selected_cb,
-                                         window);
-}
-
-static void
-window_control_after_switch_page_cb (GtkWidget       *notebook,
-                                     gpointer         page,
-                                     guint            page_num,
-                                     DhWindow        *window)
-{
-        DhWindowPriv *priv;
-
-        priv = window->priv;
-
-        g_signal_handlers_unblock_by_func (priv->book_tree,
-                                           window_tree_link_selected_cb,
-                                           window);
-        /* save the current selected tab */
-        const gchar *label = gtk_notebook_get_tab_label_text (GTK_NOTEBOOK (notebook), page);
-        g_settings_set_string (
-                dh_settings_peek_search_notebook_settings (priv->settings),
-                "selected-tab", label);
-}
-
 static void
 window_web_view_switch_page_cb (GtkNotebook     *notebook,
                                 gpointer         page,
@@ -685,13 +609,12 @@ window_web_view_switch_page_cb (GtkNotebook     *notebook,
 
                 new_web_view = g_object_get_data (G_OBJECT (new_page), "web_view");
 
-                /* Sync the book tree. */
+                /* Sync the book tree */
                 location = webkit_web_view_get_uri (new_web_view);
 
-                if (location) {
-                        dh_book_tree_select_uri (DH_BOOK_TREE (priv->book_tree),
-                                                 location);
-                }
+                if (location)
+                        dh_sidebar_select_uri (DH_SIDEBAR (priv->sidebar), location);
+
                 window_check_history (window, new_web_view);
 
                 window_update_title (window, new_web_view, NULL);
@@ -716,16 +639,14 @@ static void
 window_populate (DhWindow *window)
 {
         DhWindowPriv  *priv;
-        GtkWidget     *book_tree_sw;
         DhBookManager *book_manager;
         GtkWidget     *toolbar;
-        gchar         *selected_tab;
-        guint         i;
         GtkWidget     *back;
         GtkWidget     *forward;
         GtkWidget     *box;
 
         priv = window->priv;
+        book_manager = dh_app_peek_book_manager (DH_APP (gtk_window_get_application (GTK_WINDOW (window))));
 
         toolbar = gd_main_toolbar_new ();
         back = gd_main_toolbar_add_button (GD_MAIN_TOOLBAR (toolbar),
@@ -754,78 +675,20 @@ window_populate (DhWindow *window)
                             FALSE, FALSE, 0);
 
         priv->hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
-
         gtk_box_pack_start (GTK_BOX (priv->main_box), priv->hpaned, TRUE, TRUE, 0);
 
-        /* Search and contents notebook. */
-        priv->control_notebook = gtk_notebook_new ();
-
-        gtk_paned_add1 (GTK_PANED (priv->hpaned), priv->control_notebook);
-
-        book_tree_sw = gtk_scrolled_window_new (NULL, NULL);
-
-        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (book_tree_sw),
-                                        GTK_POLICY_NEVER,
-                                        GTK_POLICY_AUTOMATIC);
-        gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (book_tree_sw),
-                                             GTK_SHADOW_IN);
-        gtk_container_set_border_width (GTK_CONTAINER (book_tree_sw), 2);
-
-        book_manager = dh_app_peek_book_manager (DH_APP (gtk_window_get_application (GTK_WINDOW (window))));
-
-        priv->book_tree = dh_book_tree_new (book_manager);
-        gtk_container_add (GTK_CONTAINER (book_tree_sw),
-                           priv->book_tree);
-        gtk_notebook_append_page (GTK_NOTEBOOK (priv->control_notebook),
-                                  book_tree_sw,
-                                  gtk_label_new (_("Contents")));
-        g_signal_connect (priv->book_tree,
-                          "link-selected",
-                          G_CALLBACK (window_tree_link_selected_cb),
-                          window);
-
-        priv->search = dh_search_new (book_manager);
-        gtk_notebook_append_page (GTK_NOTEBOOK (priv->control_notebook),
-                                  priv->search,
-                                  gtk_label_new (_("Search")));
-        g_signal_connect (priv->search,
+        /* Sidebar */
+        priv->sidebar = dh_sidebar_new (book_manager);
+        gtk_paned_add1 (GTK_PANED (priv->hpaned), priv->sidebar);
+        g_signal_connect (priv->sidebar,
                           "link-selected",
                           G_CALLBACK (window_search_link_selected_cb),
                           window);
 
+        /* Document view */
         priv->vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
         gtk_paned_add2 (GTK_PANED (priv->hpaned), priv->vbox);
 
-        g_signal_connect (priv->control_notebook,
-                          "switch-page",
-                          G_CALLBACK (window_control_switch_page_cb),
-                          window);
-
-        g_signal_connect_after (priv->control_notebook,
-                                "switch-page",
-                                G_CALLBACK (window_control_after_switch_page_cb),
-                                window);
-
-        /* restore selected control notebook page */
-        selected_tab = g_settings_get_string (
-                dh_settings_peek_search_notebook_settings (priv->settings),
-                "selected-tab");
-        for (i = 0; i < gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->control_notebook)); i++) {
-                GtkWidget   *page;
-                const gchar *page_name;
-
-                page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->control_notebook), i);
-                page_name = gtk_notebook_get_tab_label_text (GTK_NOTEBOOK (priv->control_notebook), page);
-
-                if (page_name && strcmp (page_name, selected_tab) == 0) {
-                        gtk_widget_set_visible (GTK_WIDGET (page), TRUE);
-                        gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->control_notebook), i);
-                        gtk_widget_grab_focus (page);
-                        break;
-                }
-        }
-        g_free (selected_tab);
-
         /* HTML tabs notebook. */
         priv->notebook = gtk_notebook_new ();
         gtk_container_set_border_width (GTK_CONTAINER (priv->notebook), 0);
@@ -842,7 +705,7 @@ window_populate (DhWindow *window)
                                 G_CALLBACK (window_web_view_switch_page_after_cb),
                                 window);
 
-        /* Create findbar. */
+        /* Create findbar */
         priv->findbar = egg_find_bar_new ();
         gtk_widget_set_no_show_all (priv->findbar, TRUE);
         gtk_box_pack_start (GTK_BOX (priv->vbox), priv->findbar, FALSE, FALSE, 0);
@@ -996,7 +859,7 @@ window_web_view_navigation_policy_decision_requested (WebKitWebView
         }
 
         if (web_view == window_get_active_web_view (window)) {
-                dh_book_tree_select_uri (DH_BOOK_TREE (priv->book_tree), uri);
+                dh_sidebar_select_uri (DH_SIDEBAR (priv->sidebar), uri);
                 window_check_history (window, web_view);
         }
 
@@ -1047,23 +910,6 @@ window_web_view_load_error_cb (WebKitWebView  *web_view,
 }
 
 static void
-window_tree_link_selected_cb (GObject  *ignored,
-                              DhLink   *link,
-                              DhWindow *window)
-{
-        WebKitWebView *view;
-        gchar         *uri;
-
-        view = window_get_active_web_view (window);
-
-        uri = dh_link_get_uri (link);
-        webkit_web_view_load_uri (view, uri);
-        g_free (uri);
-
-        window_check_history (window, view);
-}
-
-static void
 window_search_link_selected_cb (GObject  *ignored,
                                 DhLink   *link,
                                 DhWindow *window)
@@ -1592,6 +1438,7 @@ window_update_title (DhWindow      *window,
                      const gchar   *web_view_title)
 {
         DhWindowPriv *priv;
+        DhLink       *book_link;
         const gchar  *book_title;
 
         priv = window->priv;
@@ -1603,7 +1450,8 @@ window_update_title (DhWindow      *window,
                 web_view_title = NULL;
         }
 
-        book_title = dh_book_tree_get_selected_book_title (DH_BOOK_TREE (priv->book_tree));
+        book_link = dh_sidebar_get_selected_book (DH_SIDEBAR (priv->sidebar));
+        book_title = book_link ? dh_link_get_name (book_link) : NULL;
 
         /* Don't use both titles if they are the same. */
         if (book_title && web_view_title && strcmp (book_title, web_view_title) == 0) {
@@ -1704,8 +1552,7 @@ dh_window_search (DhWindow    *window,
 
         priv = window->priv;
 
-        gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->control_notebook), 1);
-        dh_search_set_search_string (DH_SEARCH (priv->search), str, NULL);
+        dh_sidebar_set_search_string (DH_SIDEBAR (priv->sidebar), str);
 }
 
 /* Only call this with a URI that is known to be in the docs. */
@@ -1723,5 +1570,5 @@ _dh_window_display_uri (DhWindow    *window,
 
         web_view = window_get_active_web_view (window);
         webkit_web_view_load_uri (web_view, uri);
-        dh_book_tree_select_uri (DH_BOOK_TREE (priv->book_tree), uri);
+        dh_sidebar_select_uri (DH_SIDEBAR (priv->sidebar), uri);
 }



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