[devhelp: 3/22] Refactoring to use the book manager



commit 335e031e343c55748801438c0b4c31048be76aca
Author: Aleksander Morgado <aleksander lanedo com>
Date:   Wed May 19 21:57:57 2010 +0200

    Refactoring to use the book manager

 src/Makefile.am         |    2 +
 src/dh-assistant-view.c |   56 +++++---
 src/dh-base.c           |  342 +++--------------------------------------------
 src/dh-base.h           |   21 ++--
 src/dh-book-manager.c   |  189 +++++++++++---------------
 src/dh-book-manager.h   |    6 +-
 src/dh-book-tree.c      |   33 +++--
 src/dh-book-tree.h      |    9 +-
 src/dh-book.c           |  190 ++++++++++++++++++++++++++
 src/dh-book.h           |   61 +++++++++
 src/dh-keyword-model.c  |  129 ++++++++++--------
 src/dh-keyword-model.h  |    3 +-
 src/dh-parser.c         |   16 +--
 src/dh-parser.h         |    2 +-
 src/dh-search.c         |   95 ++++++++-----
 src/dh-search.h         |    9 +-
 src/dh-window.c         |   67 ++++++----
 17 files changed, 612 insertions(+), 618 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 2c392ae..0ea5bce 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -53,6 +53,7 @@ INST_H_FILES = 						\
 	dh-assistant-view.h				\
 	dh-base.h					\
 	dh-book-manager.h				\
+	dh-book.h					\
 	dh-book-tree.h					\
 	dh-error.h					\
 	dh-keyword-model.h				\
@@ -72,6 +73,7 @@ libdevhelp_1_la_SOURCES =				\
 	dh-assistant-view.c				\
 	dh-base.c					\
 	dh-book-manager.c				\
+	dh-book.c					\
 	dh-book-tree.c					\
 	dh-error.c					\
 	dh-keyword-model.c				\
diff --git a/src/dh-assistant-view.c b/src/dh-assistant-view.c
index f2aa1ef..c4f3762 100644
--- a/src/dh-assistant-view.c
+++ b/src/dh-assistant-view.c
@@ -26,6 +26,8 @@
 #include "dh-assistant-view.h"
 #include "dh-link.h"
 #include "dh-util.h"
+#include "dh-book-manager.h"
+#include "dh-book.h"
 #include "dh-window.h"
 
 typedef struct {
@@ -306,7 +308,7 @@ dh_assistant_view_set_link (DhAssistantView *view,
                                                           "assistant",
                                                           "assistant.js",
                                                           NULL);
-                
+
                 html = g_strdup_printf (
                         "<html>"
                         "<head>"
@@ -362,11 +364,12 @@ dh_assistant_view_search (DhAssistantView *view,
                           const gchar     *str)
 {
         DhAssistantViewPriv *priv;
-        GList               *keywords, *l;
         const gchar         *name;
         DhLink              *link;
         DhLink              *exact_link;
         DhLink              *prefix_link;
+        DhBookManager       *book_manager;
+        GList               *books;
 
         g_return_val_if_fail (DH_IS_ASSISTANT_VIEW (view), FALSE);
         g_return_val_if_fail (str, FALSE);
@@ -384,34 +387,43 @@ dh_assistant_view_search (DhAssistantView *view,
         g_free (priv->current_search);
         priv->current_search = g_strdup (str);
 
-        keywords = dh_base_get_keywords (dh_assistant_view_get_base (view));
+        book_manager = dh_base_get_book_manager (dh_assistant_view_get_base (view));
 
         prefix_link = NULL;
         exact_link = NULL;
-        for (l = keywords; l && exact_link == NULL; l = l->next) {
-                DhLinkType type;
 
-                link = l->data;
+        for (books = dh_book_manager_get_books (book_manager);
+             !exact_link && books;
+             books = g_list_next (books)) {
+                GList *l;
 
-                type = dh_link_get_link_type (link);
+                for (l = dh_book_get_keywords (DH_BOOK (books->data));
+                     l && exact_link == NULL;
+                     l = l->next) {
+                        DhLinkType type;
 
-                if (type == DH_LINK_TYPE_BOOK ||
-                    type == DH_LINK_TYPE_PAGE ||
-                    type == DH_LINK_TYPE_KEYWORD) {
-                        continue;
-                }
+                        link = l->data;
 
-                name = dh_link_get_name (link);
-                if (strcmp (name, str) == 0) {
-                        exact_link = link;
-                }
-                else if (g_str_has_prefix (name, str)) {
-                        /* Prefer shorter prefix matches. */
-                        if (!prefix_link) {
-                                prefix_link = link;
+                        type = dh_link_get_link_type (link);
+
+                        if (type == DH_LINK_TYPE_BOOK ||
+                            type == DH_LINK_TYPE_PAGE ||
+                            type == DH_LINK_TYPE_KEYWORD) {
+                                continue;
+                        }
+
+                        name = dh_link_get_name (link);
+                        if (strcmp (name, str) == 0) {
+                                exact_link = link;
                         }
-                        else if (strlen (dh_link_get_name (prefix_link)) > strlen (name)) {
-                                prefix_link = link;
+                        else if (g_str_has_prefix (name, str)) {
+                                /* Prefer shorter prefix matches. */
+                                if (!prefix_link) {
+                                        prefix_link = link;
+                                }
+                                else if (strlen (dh_link_get_name (prefix_link)) > strlen (name)) {
+                                        prefix_link = link;
+                                }
                         }
                 }
         }
diff --git a/src/dh-base.c b/src/dh-base.c
index 9d10bd6..4dc8415 100644
--- a/src/dh-base.c
+++ b/src/dh-base.c
@@ -39,69 +39,51 @@
 #include "dh-util.h"
 #include "ige-conf.h"
 #include "dh-base.h"
+#include "dh-book-manager.h"
 
 typedef struct {
-        GSList      *windows;
-        GSList      *assistants;
-        GNode       *book_tree;
-        GList       *keywords;
-        GHashTable  *books;
+        GSList        *windows;
+        GSList        *assistants;
+        DhBookManager *book_manager;
 } DhBasePriv;
 
 G_DEFINE_TYPE (DhBase, dh_base, G_TYPE_OBJECT);
 
 #define GET_PRIVATE(instance) G_TYPE_INSTANCE_GET_PRIVATE \
-  (instance, DH_TYPE_BASE, DhBasePriv);
+  (instance, DH_TYPE_BASE, DhBasePriv)
 
 static void dh_base_init           (DhBase      *base);
 static void dh_base_class_init     (DhBaseClass *klass);
-static void base_init_books        (DhBase      *base);
-static void base_add_books         (DhBase      *base,
-                                    const gchar *directory);
-
-#ifdef GDK_WINDOWING_QUARTZ
-static void base_add_xcode_docsets (DhBase      *base,
-                                    const gchar *path);
-#endif
 
 static DhBase *base_instance;
 
 static void
-unref_node_link (GNode *node, gpointer data)
+base_finalize (GObject *object)
 {
-    dh_link_unref (node->data);
-    dh_link_unref (node->data);
+        G_OBJECT_CLASS (dh_base_parent_class)->finalize (object);
 }
 
 static void
-base_finalize (GObject *object)
+base_dispose (GObject *object)
 {
         DhBasePriv *priv;
 
         priv = GET_PRIVATE (object);
 
-        /* FIXME: Free things... */
-        g_hash_table_destroy (priv->books);
-        g_node_traverse (priv->book_tree,
-                         G_IN_ORDER,
-                         G_TRAVERSE_ALL,
-                         -1,
-                         (GNodeTraverseFunc)unref_node_link,
-                         NULL);
-        g_node_destroy (priv->book_tree);
-
-        g_list_foreach (priv->keywords, (GFunc)dh_link_unref, NULL);
-        g_list_free (priv->keywords);
-
-        G_OBJECT_CLASS (dh_base_parent_class)->finalize (object);
+        if (priv->book_manager) {
+                g_object_unref (priv->book_manager);
+                priv->book_manager = NULL;
+        }
 }
 
+
 static void
 dh_base_class_init (DhBaseClass *klass)
 {
         GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
         object_class->finalize = base_finalize;
+        object_class->dispose = base_dispose;
 
 	g_type_class_add_private (klass, sizeof (DhBasePriv));
 }
@@ -118,9 +100,8 @@ dh_base_init (DhBase *base)
         ige_conf_add_defaults (conf, path);
         g_free (path);
 
-        priv->book_tree = g_node_new (NULL);
-        priv->books = g_hash_table_new_full (g_str_hash, g_str_equal,
-                                             g_free, g_free);
+        priv->book_manager = dh_book_manager_new ();
+        dh_book_manager_populate (priv->book_manager);
 
 #ifdef GDK_WINDOWING_X11
         {
@@ -153,284 +134,11 @@ base_window_or_assistant_finalized_cb (DhBase   *base,
         }
 }
 
-static gint
-book_sort_func (gconstpointer a,
-                gconstpointer b)
-{
-        DhLink      *link_a;
-        DhLink      *link_b;
-
-        link_a = ((GNode *) a)->data;
-        link_b = ((GNode *) b)->data;
-
-        return dh_util_cmp_book (link_a, link_b);
-}
-
-static void
-base_sort_books (DhBase *base)
-{
-        DhBasePriv *priv = GET_PRIVATE (base);
-        GNode      *n;
-        DhLink     *link;
-        GList      *list = NULL, *l;
-
-        if (priv->book_tree) {
-                n = priv->book_tree->children;
-
-                while (n) {
-                        list = g_list_prepend (list, n);
-                        n = n->next;
-                }
-
-                list = g_list_sort (list, book_sort_func);
-        }
-
-        for (l = list; l; l = l->next) {
-                n = l->data;
-                link = n->data;
-                g_node_unlink (n);
-        }
-
-        for (l = list; l; l = l->next) {
-                n = l->data;
-
-                g_node_append (priv->book_tree, n);
-        }
-
-        g_list_free (list);
-}
-
-static void
-base_add_books_in_data_dir (DhBase      *base,
-                            const gchar *data_dir)
-{
-        gchar *dir;
-
-        dir = g_build_filename (data_dir, "gtk-doc", "html", NULL);
-        base_add_books (base, dir);
-        g_free (dir);
-
-        dir = g_build_filename (data_dir, "devhelp", "books", NULL);
-        base_add_books (base, dir);
-        g_free (dir);
-}
-
-static void
-base_init_books (DhBase *base)
-{
-        const gchar * const * system_dirs;
-
-        base_add_books_in_data_dir (base, g_get_user_data_dir ());
-
-        system_dirs = g_get_system_data_dirs ();
-        while (*system_dirs) {
-                base_add_books_in_data_dir (base, *system_dirs);
-                system_dirs++;
-        }
-
-#ifdef GDK_WINDOWING_QUARTZ
-        base_add_xcode_docsets (
-                base,
-                "/Library/Developer/Shared/Documentation/DocSets");
-#endif
-
-        base_sort_books (base);
-}
-
-static gchar *
-base_get_book_path (DhBase      *base,
-                    const gchar *base_path,
-                    const gchar *name,
-                    const gchar *suffix)
-{
-        gchar *tmp;
-        gchar *book_path;
-
-        tmp = g_build_filename (base_path, name, name, NULL);
-        book_path = g_strconcat (tmp, ".", suffix, NULL);
-        g_free (tmp);
-
-        if (!g_file_test (book_path, G_FILE_TEST_EXISTS)) {
-                g_free (book_path);
-                return NULL;
-        }
-
-        return book_path;
-}
-
-#ifdef GDK_WINDOWING_QUARTZ
-static void
-base_add_xcode_docset (DhBase      *base,
-                       const gchar *path)
-{
-        DhBasePriv  *priv = GET_PRIVATE (base);
-        gchar       *tmp;
-        gboolean     seems_like_devhelp = FALSE;
-        GDir        *dir;
-        const gchar *name;
-
-        /* Do some sanity checking on the directory first so we don't have
-         * to go through several hundreds of files in every docset.
-         */
-        tmp = g_build_filename (path, "style.css", NULL);
-        if (g_file_test (tmp, G_FILE_TEST_EXISTS)) {
-                gchar *tmp;
-
-                tmp = g_build_filename (path, "index.sgml", NULL);
-                if (g_file_test (tmp, G_FILE_TEST_EXISTS)) {
-                        seems_like_devhelp = TRUE;
-                }
-                g_free (tmp);
-        }
-        g_free (tmp);
-
-        if (!seems_like_devhelp) {
-                return;
-        }
-
-        dir = g_dir_open (path, 0, NULL);
-        if (!dir) {
-                return;
-        }
-
-        while ((name = g_dir_read_name (dir)) != NULL) {
-                gchar  *p;
-                GError *error = NULL;
-
-                p = strrchr (name, '.');
-                if (strcmp (p, ".devhelp2") == 0) {
-                        gchar *book_name;
-                        gchar *book_path;
-
-                        book_name = g_strdup (name);
-                        p = strrchr (book_name, '.');
-                        p[0] = '\0';
-
-                        if (g_hash_table_lookup (priv->books, book_name)) {
-                                g_free (book_name);
-                                continue;
-                        }
-
-                        book_path = g_build_filename (path, name, NULL);
-
-                        if (!dh_parser_read_file  (book_path,
-                                                   priv->book_tree,
-                                                   &priv->keywords,
-                                                   &error)) {
-                                g_warning ("Failed to read '%s': %s",
-                                           book_path, error->message);
-                                g_clear_error (&error);
-
-                                g_free (book_path);
-                                g_free (book_name);
-                        } else {
-                                g_hash_table_insert (priv->books,
-                                                     book_name,
-                                                     book_path);
-                        }
-                }
-        }
-
-        g_dir_close (dir);
-}
-
-
-/* This isn't really -any- Xcode docset, just gtk-doc docs converted to
- * docsets.
- *
- * Path should point to a DocSets directory.
- */
-static void
-base_add_xcode_docsets (DhBase      *base,
-                        const gchar *path)
-{
-        GDir        *dir;
-        const gchar *name;
-
-        dir = g_dir_open (path, 0, NULL);
-        if (!dir) {
-                return;
-        }
-
-        while ((name = g_dir_read_name (dir)) != NULL) {
-                gchar *docset_path;
-
-                docset_path = g_build_filename (path,
-                                                name,
-                                                "Contents",
-                                                "Resources",
-                                                "Documents",
-                                                NULL);
-                base_add_xcode_docset (base, docset_path);
-                g_free (docset_path);
-        }
-
-        g_dir_close (dir);
-}
-#endif
-
-static void
-base_add_books (DhBase      *base,
-                const gchar *path)
-{
-        DhBasePriv  *priv = GET_PRIVATE (base);
-        GDir        *dir;
-        const gchar *name;
-
-        dir = g_dir_open (path, 0, NULL);
-        if (!dir) {
-                return;
-        }
-
-        while ((name = g_dir_read_name (dir)) != NULL) {
-                gchar  *book_path;
-                GError *error = NULL;
-
-                if (g_hash_table_lookup (priv->books, name)) {
-                        continue;
-                }
-
-                book_path = base_get_book_path (base, path, name, "devhelp2");
-                if (!book_path) {
-                        book_path = base_get_book_path (base, path, name, "devhelp2.gz");
-                }
-                if (!book_path) {
-                        book_path = base_get_book_path (base, path, name, "devhelp");
-                }
-                if (!book_path) {
-                        book_path = base_get_book_path (base, path, name, "devhelp.gz");
-                }
-
-                if (!book_path) {
-                        continue;
-                }
-
-                if (!dh_parser_read_file  (book_path,
-                                           priv->book_tree,
-                                           &priv->keywords,
-                                           &error)) {
-                        g_warning ("Failed to read '%s': %s",
-                                   book_path, error->message);
-                        g_clear_error (&error);
-
-                        g_free (book_path);
-                } else {
-                        g_hash_table_insert (priv->books,
-                                             g_strdup (name),
-                                             book_path);
-                }
-        }
-
-        g_dir_close (dir);
-}
-
 DhBase *
 dh_base_get (void)
 {
         if (!base_instance) {
                 base_instance = g_object_new (DH_TYPE_BASE, NULL);
-
-                base_init_books (base_instance);
         }
 
         return base_instance;
@@ -488,20 +196,8 @@ dh_base_new_assistant (DhBase *base)
         return assistant;
 }
 
-GNode *
-dh_base_get_book_tree (DhBase *base)
-{
-        DhBasePriv *priv;
-
-        g_return_val_if_fail (DH_IS_BASE (base), NULL);
-
-        priv = GET_PRIVATE (base);
-
-        return priv->book_tree;
-}
-
-GList *
-dh_base_get_keywords (DhBase *base)
+DhBookManager *
+dh_base_get_book_manager (DhBase *base)
 {
         DhBasePriv *priv;
 
@@ -509,7 +205,7 @@ dh_base_get_keywords (DhBase *base)
 
         priv = GET_PRIVATE (base);
 
-        return priv->keywords;
+        return priv->book_manager;
 }
 
 GtkWidget *
diff --git a/src/dh-base.h b/src/dh-base.h
index bb76930..6971652 100644
--- a/src/dh-base.h
+++ b/src/dh-base.h
@@ -25,6 +25,8 @@
 
 #include <gtk/gtk.h>
 
+#include <dh-book-manager.h>
+
 G_BEGIN_DECLS
 
 typedef struct _DhBase      DhBase;
@@ -45,16 +47,15 @@ struct _DhBaseClass {
         GObjectClass parent_class;
 };
 
-GType        dh_base_get_type                        (void) G_GNUC_CONST;
-DhBase *     dh_base_get                             (void);
-DhBase *     dh_base_new                             (void);
-GtkWidget *  dh_base_new_window                      (DhBase *base);
-GtkWidget *  dh_base_new_assistant                   (DhBase *base);
-GtkWidget *  dh_base_get_window                      (DhBase *base);
-GtkWidget *  dh_base_get_window_on_current_workspace (DhBase *base);
-GNode *      dh_base_get_book_tree                   (DhBase *base);
-GList *      dh_base_get_keywords                    (DhBase *base);
-void         dh_base_quit                            (DhBase *base);
+GType          dh_base_get_type                        (void) G_GNUC_CONST;
+DhBase *       dh_base_get                             (void);
+DhBase *       dh_base_new                             (void);
+GtkWidget *    dh_base_new_window                      (DhBase *base);
+GtkWidget *    dh_base_new_assistant                   (DhBase *base);
+GtkWidget *    dh_base_get_window                      (DhBase *base);
+GtkWidget *    dh_base_get_window_on_current_workspace (DhBase *base);
+DhBookManager *dh_base_get_book_manager                (DhBase *base);
+void           dh_base_quit                            (DhBase *base);
 
 G_END_DECLS
 
diff --git a/src/dh-book-manager.c b/src/dh-book-manager.c
index 7add6fb..927f21e 100644
--- a/src/dh-book-manager.c
+++ b/src/dh-book-manager.c
@@ -25,21 +25,9 @@
 #include <string.h>
 
 #include "dh-link.h"
-#include "dh-parser.h"
+#include "dh-book.h"
 #include "dh-book-manager.h"
 
-/* Structure defining basic contents to store about every book */
-typedef struct {
-        /* File path of the book */
-        gchar    *path;
-        /* Enable or disabled? */
-        gboolean  enabled;
-        /* Generated book tree */
-        GNode    *tree;
-        /* Generated list of keywords in the book */
-        GList    *keywords;
-} DhBook;
-
 typedef struct {
         /* The list of all books found in the system */
         GList *books;
@@ -47,8 +35,8 @@ typedef struct {
 
 G_DEFINE_TYPE (DhBookManager, dh_book_manager, G_TYPE_OBJECT);
 
-#define GET_PRIVATE(instance) G_TYPE_INSTANCE_GET_PRIVATE \
-        (instance, DH_TYPE_BOOK_MANAGER, DhBookManagerPriv);
+#define GET_PRIVATE(instance) G_TYPE_INSTANCE_GET_PRIVATE       \
+        (instance, DH_TYPE_BOOK_MANAGER, DhBookManagerPriv)
 
 static void    dh_book_manager_init       (DhBookManager      *book_manager);
 static void    dh_book_manager_class_init (DhBookManagerClass *klass);
@@ -63,22 +51,23 @@ static void    book_manager_add_from_xcode_docset (DhBookManager *book_manager,
                                                    const gchar   *dir_path);
 #endif
 
-static DhBook *book_new                   (const gchar  *book_path);
-static void    book_free                  (DhBook       *book);
-static gint    book_cmp                   (const DhBook *a,
-                                           const DhBook *b);
+static void    unref_node_link                  (GNode *node,
+                                                 gpointer data);
+static void    ref_node_link                    (GNode *node,
+                                                 gpointer data);
 
 static void
 book_manager_finalize (GObject *object)
 {
         DhBookManagerPriv *priv;
-        GList *walker;
+        GList             *walker;
 
         priv = GET_PRIVATE (object);
 
+        /* Destroy all books */
         walker = priv->books;
         while (walker) {
-                book_free ((DhBook *)walker->data);
+                g_object_unref (walker->data);
                 walker = g_list_next (walker);
         }
         g_list_free (priv->books);
@@ -101,10 +90,60 @@ dh_book_manager_init (DhBookManager *book_manager)
 {
         DhBookManagerPriv *priv = GET_PRIVATE (book_manager);
 
-        /* Empty list of books */
         priv->books = NULL;
 }
 
+static void
+unref_node_link (GNode *node,
+                 gpointer data)
+{
+        dh_link_unref (node->data);
+}
+
+static void
+ref_node_link (GNode *node,
+               gpointer data)
+{
+        dh_link_ref (node->data);
+}
+
+static void
+book_manager_add_books_in_data_dir (DhBookManager *book_manager,
+                                    const gchar   *data_dir)
+{
+        gchar *dir;
+
+        dir = g_build_filename (data_dir, "gtk-doc", "html", NULL);
+        book_manager_add_from_dir (book_manager, dir);
+        g_free (dir);
+
+        dir = g_build_filename (data_dir, "devhelp", "books", NULL);
+        book_manager_add_from_dir (book_manager, dir);
+        g_free (dir);
+}
+
+void
+dh_book_manager_populate (DhBookManager *book_manager)
+{
+        const gchar * const * system_dirs;
+
+        book_manager_add_books_in_data_dir (book_manager,
+                                            g_get_user_data_dir ());
+
+        system_dirs = g_get_system_data_dirs ();
+        while (*system_dirs) {
+                book_manager_add_books_in_data_dir (book_manager,
+                                                    *system_dirs);
+                system_dirs++;
+        }
+
+#ifdef GDK_WINDOWING_QUARTZ
+        book_manager_add_from_xcode_docset (
+                book_manager,
+                "/Library/Developer/Shared/Documentation/DocSets");
+#endif
+}
+
 static gchar *
 book_manager_get_book_path (const gchar *base_path,
                             const gchar *name)
@@ -137,7 +176,6 @@ static void
 book_manager_add_from_dir (DhBookManager *book_manager,
                            const gchar   *dir_path)
 {
-        GError      *error = NULL;
         GDir        *dir;
         const gchar *name;
 
@@ -145,11 +183,8 @@ book_manager_add_from_dir (DhBookManager *book_manager,
         g_return_if_fail (dir_path);
 
         /* Open directory */
-        dir = g_dir_open (dir_path, 0, &error);
+        dir = g_dir_open (dir_path, 0, NULL);
         if (!dir) {
-                g_warning ("Failed to open directory '%s': %s",
-                           dir_path, error->message);
-                g_error_free (error);
                 return;
         }
 
@@ -200,7 +235,6 @@ static void
 book_manager_add_from_xcode_docset (DhBookManager *book_manager,
                                     const gchar   *dir_path)
 {
-        GError      *error = NULL;
         GDir        *dir;
         const gchar *name;
 
@@ -212,11 +246,8 @@ book_manager_add_from_xcode_docset (DhBookManager *book_manager,
         }
 
         /* Open directory */
-        dir = g_dir_open (dir_path, 0, &error);
+        dir = g_dir_open (dir_path, 0, NULL);
         if (!dir) {
-                g_warning ("Failed to open directory '%s': %s",
-                           dir_path, error->message);
-                g_error_free (error);
                 return;
         }
 
@@ -242,105 +273,43 @@ static void
 book_manager_add_from_filepath (DhBookManager *book_manager,
                                 const gchar   *book_path)
 {
-        DhBookManagerPriv *priv = GET_PRIVATE (book_manager);
-        DhBook *book;
-        GError *error = NULL;
+        DhBookManagerPriv *priv;
+        DhBook            *book;
 
         g_return_if_fail (book_manager);
         g_return_if_fail (book_path);
 
+        priv = GET_PRIVATE (book_manager);
+
         /* Allocate new book struct */
-        book = book_new (book_path);
+        book = dh_book_new (book_path);
 
         /* Check if book was already loaded in the manager */
         if (g_list_find_custom (priv->books,
                                 book,
-                                (GCompareFunc)book_cmp)) {
-                book_free (book);
-                return;
-        }
-
-        /* Parse file storing contents in the book struct */
-        if (!dh_parser_read_file  (book_path,
-                                   book->tree,
-                                   &book->keywords,
-                                   &error)) {
-                g_warning ("Failed to read '%s': %s",
-                           book_path, error->message);
-                g_error_free (error);
-
-                /* Deallocate the book, as we are not going to add it
-                 *  in the manager */
-                book_free (book);
+                                (GCompareFunc)dh_book_cmp)) {
+                g_object_unref (book);
                 return;
         }
 
+        g_debug ("Adding '%s'...", book_path);
         /* Add the book to the book list */
         priv->books = g_list_insert_sorted (priv->books,
                                             book,
-                                            (GCompareFunc)book_cmp);
+                                            (GCompareFunc)dh_book_cmp);
 }
 
-
-DhBookManager *
-dh_book_manager_new (void)
+GList *
+dh_book_manager_get_books (DhBookManager *book_manager)
 {
-        return g_object_new (DH_TYPE_BOOK_MANAGER, NULL);
-}
-
-/* Single book creation/destruction/management */
-
-static DhBook *
-book_new (const gchar *book_path)
-{
-        DhBook *book;
-
-        g_return_val_if_fail (book_path, NULL);
-
-        /* Allocate and initialize new book struct, by default
-         *  enabled */
-        book = g_malloc0 (sizeof (*book));
-        book->path = g_strdup (book_path);
-        book->enabled = TRUE;
-        book->tree = g_node_new (NULL);
-        book->keywords = NULL;
-
-        return book;
-}
+        g_return_val_if_fail (book_manager, NULL);
 
-static void
-unref_node_link (GNode *node,
-                 gpointer data)
-{
-        dh_link_unref (node->data);
+        return GET_PRIVATE (book_manager)->books;
 }
 
-static void
-book_free (DhBook *book)
+DhBookManager *
+dh_book_manager_new (void)
 {
-        g_return_if_fail (book);
-
-        if (book->tree) {
-                g_node_traverse (book->tree,
-                                 G_IN_ORDER,
-                                 G_TRAVERSE_ALL,
-                                 -1,
-                                 (GNodeTraverseFunc)unref_node_link,
-                                 NULL);
-                g_node_destroy (book->tree);
-        }
-
-        if (book->keywords) {
-                g_list_foreach (book->keywords, (GFunc)dh_link_unref, NULL);
-                g_list_free (book->keywords);
-        }
-
-        g_free (book->path);
-        g_free (book);
+        return g_object_new (DH_TYPE_BOOK_MANAGER, NULL);
 }
 
-static gint book_cmp (const DhBook *a,
-                      const DhBook *b)
-{
-        return (a && b) ? g_strcmp0 (a->path, b->path) : -1;
-}
diff --git a/src/dh-book-manager.h b/src/dh-book-manager.h
index 65a024e..6fcc4c7 100644
--- a/src/dh-book-manager.h
+++ b/src/dh-book-manager.h
@@ -46,8 +46,10 @@ struct _DhBookManagerClass {
         GObjectClass parent_class;
 };
 
-GType          dh_book_manager_get_type              (void) G_GNUC_CONST;
-DhBookManager *dh_book_manager_new                   (void);
+GType          dh_book_manager_get_type     (void) G_GNUC_CONST;
+DhBookManager *dh_book_manager_new          (void);
+void           dh_book_manager_populate     (DhBookManager *book_manager);
+GList         *dh_book_manager_get_books    (DhBookManager *book_manager);
 
 
 G_END_DECLS
diff --git a/src/dh-book-tree.c b/src/dh-book-tree.c
index 482d162..37d250a 100644
--- a/src/dh-book-tree.c
+++ b/src/dh-book-tree.c
@@ -27,6 +27,7 @@
 
 #include "dh-marshal.h"
 #include "dh-book-tree.h"
+#include "dh-book.h"
 
 typedef struct {
         const gchar *uri;
@@ -36,9 +37,9 @@ typedef struct {
 } FindURIData;
 
 typedef struct {
-        GtkTreeStore *store;
-        GNode        *link_tree;
-        DhLink       *selected_link;
+        GtkTreeStore  *store;
+        DhBookManager *book_manager;
+        DhLink        *selected_link;
 } DhBookTreePriv;
 
 static void dh_book_tree_class_init        (DhBookTreeClass  *klass);
@@ -77,6 +78,7 @@ book_tree_finalize (GObject *object)
 	DhBookTreePriv *priv = GET_PRIVATE (object);
 
 	g_object_unref (priv->store);
+        g_object_unref (priv->book_manager);
 
         G_OBJECT_CLASS (dh_book_tree_parent_class)->finalize (object);
 }
@@ -162,13 +164,20 @@ static void
 book_tree_populate_tree (DhBookTree *tree)
 {
         DhBookTreePriv *priv = GET_PRIVATE (tree);
-	GNode          *node;
-
-	for (node = g_node_first_child (priv->link_tree);
-	     node;
-	     node = g_node_next_sibling (node)) {
-		book_tree_insert_node (tree, node, NULL);
-	}
+        GList          *l;
+
+        for (l = dh_book_manager_get_books (priv->book_manager);
+             l;
+             l = g_list_next (l)) {
+                DhBook *book = DH_BOOK (l->data);
+                GNode  *node;
+
+                node = dh_book_get_tree (book);
+                while(node) {
+                        book_tree_insert_node (tree, node, NULL);
+                        node = g_node_next_sibling (node);
+                }
+        }
 }
 
 static void
@@ -228,7 +237,7 @@ book_tree_selection_changed_cb (GtkTreeSelection *selection,
 }
 
 GtkWidget *
-dh_book_tree_new (GNode *books)
+dh_book_tree_new (DhBookManager *book_manager)
 {
         DhBookTree     *tree;
         DhBookTreePriv *priv;
@@ -239,7 +248,7 @@ dh_book_tree_new (GNode *books)
 	tree = g_object_new (DH_TYPE_BOOK_TREE, NULL);
         priv = GET_PRIVATE (tree);
 
-        priv->link_tree = books;
+        priv->book_manager = g_object_ref (book_manager);
         book_tree_populate_tree (tree);
 
 	/* Mark the first item as selected, or it would get automatically
diff --git a/src/dh-book-tree.h b/src/dh-book-tree.h
index 87c75f5..885b09c 100644
--- a/src/dh-book-tree.h
+++ b/src/dh-book-tree.h
@@ -23,6 +23,7 @@
 
 #include <gtk/gtk.h>
 #include "dh-link.h"
+#include "dh-book-manager.h"
 
 G_BEGIN_DECLS
 
@@ -44,10 +45,10 @@ struct _DhBookTreeClass {
 };
 
 GType        dh_book_tree_get_type                (void) G_GNUC_CONST;
-GtkWidget *  dh_book_tree_new                     (GNode       *books);
-void         dh_book_tree_select_uri              (DhBookTree  *book_tree,
-                                                   const gchar *uri);
-const gchar *dh_book_tree_get_selected_book_title (DhBookTree  *tree);
+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);
 
 G_END_DECLS
 
diff --git a/src/dh-book.c b/src/dh-book.c
new file mode 100644
index 0000000..56de271
--- /dev/null
+++ b/src/dh-book.c
@@ -0,0 +1,190 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2002 CodeFactory AB
+ * Copyright (C) 2002 Mikael Hallendal <micke imendio com>
+ * Copyright (C) 2004-2008 Imendio AB
+ * Copyright (C) 2010 Lanedo GmbH
+ *
+ * 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 "dh-link.h"
+#include "dh-parser.h"
+#include "dh-book.h"
+
+/* Structure defining basic contents to store about every book */
+typedef struct {
+        /* File path of the book */
+        gchar    *path;
+        /* Enable or disabled? */
+        gboolean  enabled;
+        /* Generated book tree */
+        GNode    *tree;
+        /* Generated list of keywords in the book */
+        GList    *keywords;
+} DhBookPriv;
+
+G_DEFINE_TYPE (DhBook, dh_book, G_TYPE_OBJECT);
+
+#define GET_PRIVATE(instance) G_TYPE_INSTANCE_GET_PRIVATE       \
+        (instance, DH_TYPE_BOOK, DhBookPriv)
+
+static void    dh_book_init       (DhBook      *book);
+static void    dh_book_class_init (DhBookClass *klass);
+
+static void    unref_node_link    (GNode *node,
+                                   gpointer data);
+
+static void
+book_finalize (GObject *object)
+{
+        DhBookPriv *priv;
+
+        priv = GET_PRIVATE (object);
+
+        if (priv->tree) {
+                g_node_traverse (priv->tree,
+                                 G_IN_ORDER,
+                                 G_TRAVERSE_ALL,
+                                 -1,
+                                 (GNodeTraverseFunc)unref_node_link,
+                                 NULL);
+                g_node_destroy (priv->tree);
+        }
+
+        if (priv->keywords) {
+                g_list_foreach (priv->keywords, (GFunc)dh_link_unref, NULL);
+                g_list_free (priv->keywords);
+        }
+
+        g_free (priv->path);
+
+        G_OBJECT_CLASS (dh_book_parent_class)->finalize (object);
+}
+
+static void
+dh_book_class_init (DhBookClass *klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+        object_class->finalize = book_finalize;
+
+	g_type_class_add_private (klass, sizeof (DhBookPriv));
+}
+
+static void
+dh_book_init (DhBook *book)
+{
+        DhBookPriv *priv = GET_PRIVATE (book);
+
+        priv->path = NULL;
+        priv->enabled = TRUE;
+        priv->tree = NULL;
+        priv->keywords = NULL;
+}
+
+static void
+unref_node_link (GNode *node,
+                 gpointer data)
+{
+        dh_link_unref (node->data);
+}
+
+DhBook *
+dh_book_new (const gchar  *book_path)
+{
+        DhBookPriv *priv;
+        DhBook     *book;
+        GError     *error = NULL;
+
+        g_return_val_if_fail (book_path, NULL);
+
+        book = g_object_new (DH_TYPE_BOOK, NULL);
+        priv = GET_PRIVATE (book);
+
+        /* Store path */
+        priv->path = g_strdup (book_path);
+
+        /* Parse file storing contents in the book struct */
+        if (!dh_parser_read_file  (priv->path,
+                                   &priv->tree,
+                                   &priv->keywords,
+                                   &error)) {
+                g_warning ("Failed to read '%s': %s",
+                           priv->path, error->message);
+                g_error_free (error);
+
+                /* Deallocate the book, as we are not going to add it
+                 *  in the manager */
+                g_object_unref (book);
+                return NULL;
+        }
+
+        return book;
+}
+
+GList *
+dh_book_get_keywords (DhBook *book)
+{
+        DhBookPriv *priv;
+
+        g_return_val_if_fail (DH_IS_BOOK (book), NULL);
+
+        priv = GET_PRIVATE (book);
+
+        return priv->enabled ? priv->keywords : NULL;
+}
+
+GNode *
+dh_book_get_tree (DhBook *book)
+{
+        DhBookPriv *priv;
+
+        g_return_val_if_fail (DH_IS_BOOK (book), NULL);
+
+        priv = GET_PRIVATE (book);
+
+        return priv->enabled ? priv->tree : NULL;
+}
+
+gboolean
+dh_book_get_enabled (DhBook *book)
+{
+        g_return_val_if_fail (DH_IS_BOOK (book), FALSE);
+
+        return GET_PRIVATE (book)->enabled;
+}
+
+void
+dh_book_set_enabled (DhBook *book,
+                     gboolean enabled)
+{
+        g_return_if_fail (DH_IS_BOOK (book));
+
+        GET_PRIVATE (book)->enabled = enabled;
+}
+
+gint
+dh_book_cmp (const DhBook *a,
+             const DhBook *b)
+{
+        return ((a && b) ?
+                g_strcmp0 (GET_PRIVATE (a)->path, GET_PRIVATE (b)->path) :
+                -1);
+}
diff --git a/src/dh-book.h b/src/dh-book.h
new file mode 100644
index 0000000..46d994c
--- /dev/null
+++ b/src/dh-book.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2002 CodeFactory AB
+ * Copyright (C) 2002 Mikael Hallendal <micke imendio com>
+ * Copyright (C) 2005-2008 Imendio AB
+ * Copyright (C) 2010 Lanedo GmbH
+ *
+ * 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_BOOK_H_
+#define _DH_BOOK_H_
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+typedef struct _DhBook      DhBook;
+typedef struct _DhBookClass DhBookClass;
+
+#define DH_TYPE_BOOK         (dh_book_get_type ())
+#define DH_BOOK(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), DH_TYPE_BOOK, DhBook))
+#define DH_BOOK_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), DH_TYPE_BOOK, DhBookClass))
+#define DH_IS_BOOK(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), DH_TYPE_BOOK))
+#define DH_IS_BOOK_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), DH_TYPE_BOOK))
+#define DH_BOOK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), DH_TYPE_BOOK, DhBookClass))
+
+struct _DhBook {
+        GObject parent_instance;
+};
+
+struct _DhBookClass {
+        GObjectClass parent_class;
+};
+
+GType     dh_book_get_type     (void) G_GNUC_CONST;
+DhBook   *dh_book_new          (const gchar  *book_path);
+GList    *dh_book_get_keywords (DhBook *book);
+GNode    *dh_book_get_tree     (DhBook *book);
+gboolean  dh_book_get_enabled  (DhBook *book);
+void      dh_book_set_enabled  (DhBook *book,
+                                gboolean enabled);
+gint      dh_book_cmp           (const DhBook *a,
+                                 const DhBook *b);
+
+G_END_DECLS
+
+#endif /* _DH_BOOK_H_ */
diff --git a/src/dh-keyword-model.c b/src/dh-keyword-model.c
index c46872a..3ff7b7a 100644
--- a/src/dh-keyword-model.c
+++ b/src/dh-keyword-model.c
@@ -25,10 +25,11 @@
 #include <string.h>
 
 #include "dh-link.h"
+#include "dh-book.h"
 #include "dh-keyword-model.h"
 
 struct _DhKeywordModelPriv {
-        GList *original_list;
+        DhBookManager *book_manager;
 
         GList *keyword_words;
         gint   keyword_words_length;
@@ -48,13 +49,26 @@ G_DEFINE_TYPE_WITH_CODE (DhKeywordModel, dh_keyword_model, G_TYPE_OBJECT,
                                                 dh_keyword_model_tree_model_init));
 
 static void
+keyword_model_dispose (GObject *object)
+{
+        DhKeywordModel     *model = DH_KEYWORD_MODEL (object);
+        DhKeywordModelPriv *priv = model->priv;
+
+        if (priv->book_manager) {
+                g_object_unref (priv->book_manager);
+                priv->book_manager = NULL;
+        }
+
+        G_OBJECT_CLASS (dh_keyword_model_parent_class)->dispose (object);
+}
+
+static void
 keyword_model_finalize (GObject *object)
 {
         DhKeywordModel     *model = DH_KEYWORD_MODEL (object);
         DhKeywordModelPriv *priv = model->priv;
 
         g_list_free (priv->keyword_words);
-        g_list_free (priv->original_list);
 
         g_free (model->priv);
 
@@ -67,6 +81,7 @@ dh_keyword_model_class_init (DhKeywordModelClass *klass)
         GObjectClass *object_class = G_OBJECT_CLASS (klass);;
 
         object_class->finalize = keyword_model_finalize;
+        object_class->dispose = keyword_model_dispose;
 }
 
 static void
@@ -314,16 +329,11 @@ dh_keyword_model_new (void)
 
 void
 dh_keyword_model_set_words (DhKeywordModel *model,
-                            GList          *keyword_words)
+                            DhBookManager  *book_manager)
 {
-        DhKeywordModelPriv *priv;
-
         g_return_if_fail (DH_IS_KEYWORD_MODEL (model));
 
-        priv = model->priv;
-
-        g_list_free (priv->original_list);
-        priv->original_list = g_list_copy (keyword_words);
+        model->priv->book_manager = g_object_ref (book_manager);
 }
 
 static GList *
@@ -335,7 +345,7 @@ keyword_model_search (DhKeywordModel  *model,
                       DhLink         **exact_link)
 {
         DhKeywordModelPriv *priv;
-        GList              *new_list = NULL, *l;
+        GList              *new_list = NULL, *b;
         gint                hits = 0;
         gchar              *page_id = NULL;
         gchar              *page_filename_prefix = NULL;
@@ -352,63 +362,74 @@ keyword_model_search (DhKeywordModel  *model,
                 stringv++;
         }
 
-        for (l = priv->original_list; l && hits < MAX_HITS; l = l->next) {
-                DhLink   *link;
-                gboolean  found;
-                gchar    *name;
+        for (b = dh_book_manager_get_books (priv->book_manager);
+             b && hits < MAX_HITS;
+             b = g_list_next (b)) {
+                DhBook *book;
+                GList *l;
 
-                link = l->data;
-                found = FALSE;
+                book = DH_BOOK (b->data);
 
-                if (book_id &&
-                    dh_link_get_book_id (link) &&
-                    strcmp (dh_link_get_book_id (link), book_id) != 0) {
-                        continue;
-                }
+                for (l = dh_book_get_keywords (book);
+                     l && hits < MAX_HITS;
+                     l = g_list_next (l)) {
+                        DhLink   *link;
+                        gboolean  found;
+                        gchar    *name;
 
-                if (page_id && 
-                    (dh_link_get_link_type (link) != DH_LINK_TYPE_PAGE &&
-                     !g_str_has_prefix (dh_link_get_file_name (link), page_filename_prefix))) {
-                        continue;
-                }
+                        link = l->data;
+                        found = FALSE;
 
-                if (!case_sensitive) {
-                        name = g_ascii_strdown (dh_link_get_name (link), -1);
-                } else {
-                        name = g_strdup (dh_link_get_name (link));
-                }
+                        if (book_id &&
+                            dh_link_get_book_id (link) &&
+                            strcmp (dh_link_get_book_id (link), book_id) != 0) {
+                                continue;
+                        }
 
-                if (!found) {
-                        gint i;
+                        if (page_id &&
+                            (dh_link_get_link_type (link) != DH_LINK_TYPE_PAGE &&
+                             !g_str_has_prefix (dh_link_get_file_name (link), page_filename_prefix))) {
+                                continue;
+                        }
 
-                        if (stringv[0] == NULL) {
-                                /* means only a page was specified, no keyword */
-                                if (g_strrstr (dh_link_get_name(link), page_id))
-                                        found = TRUE;
+                        if (!case_sensitive) {
+                                name = g_ascii_strdown (dh_link_get_name (link), -1);
                         } else {
-                                found = TRUE;
-                                for (i = 0; stringv[i] != NULL; i++) {
-                                        if (!g_strrstr (name, stringv[i])) {
-                                                found = FALSE;
-                                                break;
+                                name = g_strdup (dh_link_get_name (link));
+                        }
+
+                        if (!found) {
+                                gint i;
+
+                                if (stringv[0] == NULL) {
+                                        /* means only a page was specified, no keyword */
+                                        if (g_strrstr (dh_link_get_name(link), page_id))
+                                                found = TRUE;
+                                } else {
+                                        found = TRUE;
+                                        for (i = 0; stringv[i] != NULL; i++) {
+                                                if (!g_strrstr (name, stringv[i])) {
+                                                        found = FALSE;
+                                                        break;
+                                                }
                                         }
                                 }
                         }
-                }
 
-                g_free (name);
+                        g_free (name);
 
-                if (found) {
-                        /* Include in the new list. */
-                        new_list = g_list_prepend (new_list, link);
-                        hits++;
+                        if (found) {
+                                /* Include in the new list. */
+                                new_list = g_list_prepend (new_list, link);
+                                hits++;
 
-                        if (!*exact_link &&
-                            dh_link_get_name (link) && (
-                            (dh_link_get_link_type (link) == DH_LINK_TYPE_PAGE &&
-                             page_id && strcmp (dh_link_get_name (link), page_id) == 0) ||
-                            (strcmp (dh_link_get_name (link), string) == 0))) {
-                                *exact_link = link;
+                                if (!*exact_link &&
+                                    dh_link_get_name (link) && (
+                                            (dh_link_get_link_type (link) == DH_LINK_TYPE_PAGE &&
+                                             page_id && strcmp (dh_link_get_name (link), page_id) == 0) ||
+                                            (strcmp (dh_link_get_name (link), string) == 0))) {
+                                        *exact_link = link;
+                                }
                         }
                 }
         }
diff --git a/src/dh-keyword-model.h b/src/dh-keyword-model.h
index 7c2aa3e..d2ba70d 100644
--- a/src/dh-keyword-model.h
+++ b/src/dh-keyword-model.h
@@ -24,6 +24,7 @@
 
 #include <gtk/gtk.h>
 #include "dh-link.h"
+#include "dh-book-manager.h"
 
 G_BEGIN_DECLS
 
@@ -58,7 +59,7 @@ enum {
 GType           dh_keyword_model_get_type  (void);
 DhKeywordModel *dh_keyword_model_new       (void);
 void            dh_keyword_model_set_words (DhKeywordModel *model,
-                                            GList          *keywords);
+                                            DhBookManager  *book_manager);
 DhLink *        dh_keyword_model_filter    (DhKeywordModel *model,
                                             const gchar    *string,
                                             const gchar    *book_id);
diff --git a/src/dh-parser.c b/src/dh-parser.c
index 94fc135..9530c54 100644
--- a/src/dh-parser.c
+++ b/src/dh-parser.c
@@ -48,7 +48,7 @@ typedef struct {
 	gboolean             parsing_chapters;
 	gboolean             parsing_keywords;
 
- 	GNode               *book_tree;
+ 	GNode              **book_tree;
 	GList              **keywords;
 
 	/* Version 2 uses <keyword> instead of <function>. */
@@ -160,7 +160,7 @@ parser_start_node_book (DhParser             *parser,
         *parser->keywords = g_list_prepend (*parser->keywords, dh_link_ref (link));
 
         parser->book_node = g_node_new (dh_link_ref (link));
-        g_node_prepend (parser->book_tree, parser->book_node);
+        *parser->book_tree = parser->book_node;
         parser->parent = parser->book_node;
         g_free (title);
         dh_link_unref (link);
@@ -214,7 +214,7 @@ parser_start_node_chapter (DhParser             *parser,
         link = dh_link_new (DH_LINK_TYPE_PAGE,
                             NULL,
                             NULL,
-                            name, 
+                            name,
                             parser->book_node->data,
                             NULL,
                             uri);
@@ -264,7 +264,7 @@ parser_start_node_keyword (DhParser             *parser,
                              "function", node_name, line, col);
                 return;
         }
-		
+
         for (i = 0; attribute_names[i]; ++i) {
                 if (g_ascii_strcasecmp (attribute_names[i], "type") == 0) {
                         type = attribute_values[i];
@@ -375,7 +375,7 @@ parser_start_node_keyword (DhParser             *parser,
         link = dh_link_new (link_type,
                             NULL,
                             NULL,
-                            name, 
+                            name,
                             parser->book_node->data,
                             parser->parent->data,
                             uri);
@@ -475,8 +475,6 @@ parser_error_cb (GMarkupParseContext *context,
 static gboolean
 parser_read_gz_file (DhParser     *parser,
                      const gchar  *path,
-		     GNode        *book_tree,
-		     GList       **keywords,
 		     GError      **error)
 {
 	gchar  buf[BYTES_PER_READ];
@@ -525,7 +523,7 @@ parser_read_gz_file (DhParser     *parser,
 
 gboolean
 dh_parser_read_file (const gchar  *path,
-		     GNode        *book_tree,
+		     GNode       **book_tree,
 		     GList       **keywords,
 		     GError      **error)
 {
@@ -569,8 +567,6 @@ dh_parser_read_file (const gchar  *path,
         if (gz) {
                 if (!parser_read_gz_file (parser,
                                           path,
-                                          book_tree,
-                                          keywords,
                                           error)) {
                         result = FALSE;
                 }
diff --git a/src/dh-parser.h b/src/dh-parser.h
index fc053d7..9de1409 100644
--- a/src/dh-parser.h
+++ b/src/dh-parser.h
@@ -27,7 +27,7 @@
 G_BEGIN_DECLS
 
 gboolean dh_parser_read_file (const gchar  *path,
-                              GNode        *book_tree,
+                              GNode       **book_tree,
                               GList       **keywords,
                               GError      **error);
 
diff --git a/src/dh-search.c b/src/dh-search.c
index af59651..3dc60a0 100644
--- a/src/dh-search.c
+++ b/src/dh-search.c
@@ -31,10 +31,14 @@
 #include "dh-preferences.h"
 #include "dh-base.h"
 #include "dh-util.h"
+#include "dh-book-manager.h"
+#include "dh-book.h"
 
 typedef struct {
         DhKeywordModel *model;
 
+        DhBookManager  *book_manager;
+
         DhLink         *selected_link;
 
         GtkWidget      *book_combo;
@@ -93,6 +97,7 @@ search_finalize (GObject *object)
         priv = GET_PRIVATE (object);
 
         g_completion_free (priv->completion);
+        g_object_unref (priv->book_manager);
 
         G_OBJECT_CLASS (dh_search_parent_class)->finalize (object);
 }
@@ -146,7 +151,7 @@ search_grab_focus (GtkWidget *widget)
 
         gtk_widget_grab_focus (priv->entry);
 }
-                   
+
 static void
 search_selection_changed_cb (GtkTreeSelection *selection,
                              DhSearch         *search)
@@ -294,7 +299,7 @@ search_combo_set_active_id (DhSearch    *search,
         } else {
                 gtk_combo_box_set_active (GTK_COMBO_BOX (priv->book_combo), 0);
         }
-        
+
         g_signal_handlers_unblock_by_func (priv->book_combo,
                                            search_combo_changed_cb,
                                            search);
@@ -318,7 +323,7 @@ search_combo_get_active_id (DhSearch *search)
         gtk_tree_model_get (model, &iter,
                             1, &id,
                             -1);
-        
+
         return id;
 }
 
@@ -466,12 +471,6 @@ search_cell_data_func (GtkTreeViewColumn *tree_column,
                       NULL);
 }
 
-static gint
-book_cmp (DhLink **a, DhLink **b)
-{
-        return dh_util_cmp_book (*a, *b);
-}
-
 static gboolean
 search_combo_row_separator_func (GtkTreeModel *model,
                                  GtkTreeIter  *iter,
@@ -491,16 +490,16 @@ search_combo_row_separator_func (GtkTreeModel *model,
 }
 
 static GtkWidget *
-search_combo_create (DhSearch *search,
-                     GList    *keywords)
+search_combo_create (DhSearch *search)
 {
         GtkTreeIter      iter;
         GtkListStore    *store;
-        GList           *l;
         GtkWidget       *combo;
         GtkCellRenderer *cell;
-        GArray          *books;
-        int              i, nb_books = 0;
+        GList           *l;
+        DhSearchPriv    *priv;
+
+        priv = GET_PRIVATE (search);
 
         store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
 
@@ -517,31 +516,26 @@ search_combo_create (DhSearch *search,
                             1, NULL,
                             -1);
 
-        books = g_array_sized_new (FALSE, FALSE, sizeof(DhLink*), 50);
-        for (l = keywords; l; l = l->next) {
-                DhLink *link = l->data;
-
-                if (dh_link_get_link_type (link) != DH_LINK_TYPE_BOOK) {
-                        continue;
-                }
+        for (l = dh_book_manager_get_books (priv->book_manager);
+             l;
+             l = g_list_next (l)) {
+                DhBook *book = DH_BOOK (l->data);
+                GNode  *node;
 
-                g_array_append_val (books, link);
-                nb_books++;
-        }
+                node = dh_book_get_tree (book);
+                if (node) {
+                        DhLink *link;
 
-        g_array_sort (books, (GCompareFunc)book_cmp);
+                        link = node->data;
 
-        for (i = 0; i < nb_books; i++) {
-                DhLink *link = g_array_index(books, DhLink*, i);
-                gtk_list_store_append (store, &iter);
-                gtk_list_store_set (store, &iter,
-                                    0, dh_link_get_name (link),
-                                    1, dh_link_get_book_id (link),
-                                    -1);
+                        gtk_list_store_append (store, &iter);
+                        gtk_list_store_set (store, &iter,
+                                            0, dh_link_get_name (link),
+                                            1, dh_link_get_book_id (link),
+                                            -1);
+                }
         }
 
-        g_array_free (books, TRUE);
-
         combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
         g_object_unref (store);
 
@@ -562,8 +556,31 @@ search_combo_create (DhSearch *search,
         return combo;
 }
 
+static void
+completion_add_items (DhSearch *search)
+{
+        DhSearchPriv *priv;
+        GList        *l;
+
+        priv = GET_PRIVATE (search);
+
+        for (l = dh_book_manager_get_books (priv->book_manager);
+             l;
+             l = g_list_next (l)) {
+                DhBook *book = DH_BOOK (l->data);
+                GList  *keywords;
+
+                keywords = dh_book_get_keywords(book);
+
+                if (keywords) {
+                        g_completion_add_items (priv->completion,
+                                                keywords);
+                }
+        }
+}
+
 GtkWidget *
-dh_search_new (GList *keywords)
+dh_search_new (DhBookManager *book_manager)
 {
         DhSearch         *search;
         DhSearchPriv     *priv;
@@ -577,9 +594,11 @@ dh_search_new (GList *keywords)
 
         priv = GET_PRIVATE (search);
 
+        priv->book_manager = g_object_ref (book_manager);
+
         gtk_container_set_border_width (GTK_CONTAINER (search), 2);
 
-        priv->book_combo = search_combo_create (search, keywords);
+        priv->book_combo = search_combo_create (search);
         g_signal_connect (priv->book_combo, "changed",
                           G_CALLBACK (search_combo_changed_cb),
                           search);
@@ -651,8 +670,8 @@ dh_search_new (GList *keywords)
 
         gtk_box_pack_end (GTK_BOX (search), list_sw, TRUE, TRUE, 0);
 
-        g_completion_add_items (priv->completion, keywords);
-        dh_keyword_model_set_words (priv->model, keywords);
+        completion_add_items (search);
+        dh_keyword_model_set_words (priv->model, book_manager);
 
         gtk_widget_show_all (GTK_WIDGET (search));
 
diff --git a/src/dh-search.h b/src/dh-search.h
index 343d0be..33af9cb 100644
--- a/src/dh-search.h
+++ b/src/dh-search.h
@@ -24,6 +24,7 @@
 
 #include <gtk/gtk.h>
 #include "dh-link.h"
+#include "dh-book-manager.h"
 
 G_BEGIN_DECLS
 
@@ -49,10 +50,10 @@ struct _DhSearchClass {
 };
 
 GType      dh_search_get_type          (void);
-GtkWidget *dh_search_new               (GList       *keywords);
-void       dh_search_set_search_string (DhSearch    *search,
-                                        const gchar *str,
-                                        const gchar *book_id);
+GtkWidget *dh_search_new               (DhBookManager *book_manager);
+void       dh_search_set_search_string (DhSearch      *search,
+                                        const gchar   *str,
+                                        const gchar   *book_id);
 
 G_END_DECLS
 
diff --git a/src/dh-window.c b/src/dh-window.c
index d1eecbf..3dd44ce 100644
--- a/src/dh-window.c
+++ b/src/dh-window.c
@@ -37,6 +37,8 @@
 #endif
 
 #include "dh-book-tree.h"
+#include "dh-book-manager.h"
+#include "dh-book.h"
 #include "dh-preferences.h"
 #include "dh-search.h"
 #include "dh-window.h"
@@ -386,16 +388,16 @@ run_fullscreen_animation (gpointer data)
 	GdkScreen *screen;
 	GdkRectangle fs_rect;
 	gint x, y;
-	
+
 	screen = gtk_window_get_screen (GTK_WINDOW (window));
 	gdk_screen_get_monitor_geometry (screen,
 					 gdk_screen_get_monitor_at_window (screen,
 									   gtk_widget_get_window (GTK_WIDGET (window))),
 					 &fs_rect);
-					 
+
 	gtk_window_get_position (GTK_WINDOW (window->priv->fullscreen_controls),
 				 &x, &y);
-	
+
 	if (window->priv->fullscreen_animation_enter)
 	{
 		if (y == fs_rect.y)
@@ -413,10 +415,10 @@ run_fullscreen_animation (gpointer data)
 	else
 	{
 		gint w, h;
-	
+
 		gtk_window_get_size (GTK_WINDOW (window->priv->fullscreen_controls),
 				     &w, &h);
-	
+
 		if (y == fs_rect.y - h + 1)
 		{
 			window->priv->fullscreen_animation_timeout_id = 0;
@@ -1057,13 +1059,12 @@ window_web_view_switch_page_after_cb (GtkNotebook     *notebook,
 static void
 window_populate (DhWindow *window)
 {
-        DhWindowPriv *priv;
-        gchar        *path;
-        GtkWidget    *book_tree_sw;
-        GNode        *contents_tree;
-        GList        *keywords;
-        GtkWidget    *menubar;
-        GtkWidget    *toolbar;
+        DhWindowPriv  *priv;
+        gchar         *path;
+        GtkWidget     *book_tree_sw;
+        DhBookManager *book_manager;
+        GtkWidget     *menubar;
+        GtkWidget     *toolbar;
 
         priv = window->priv;
 
@@ -1141,10 +1142,9 @@ window_populate (DhWindow *window)
                                              GTK_SHADOW_IN);
         gtk_container_set_border_width (GTK_CONTAINER (book_tree_sw), 2);
 
-        contents_tree = dh_base_get_book_tree (priv->base);
-        keywords = dh_base_get_keywords (priv->base);
+        book_manager = dh_base_get_book_manager (priv->base);
 
-        priv->book_tree = dh_book_tree_new (contents_tree);
+        priv->book_tree = dh_book_tree_new (book_manager);
         gtk_container_add (GTK_CONTAINER (book_tree_sw),
                            priv->book_tree);
         dh_util_state_set_notebook_page_name (book_tree_sw, "content");
@@ -1156,7 +1156,7 @@ window_populate (DhWindow *window)
                           G_CALLBACK (window_tree_link_selected_cb),
                           window);
 
-        priv->search = dh_search_new (keywords);
+        priv->search = dh_search_new (book_manager);
         dh_util_state_set_notebook_page_name (priv->search, "search");
         gtk_notebook_append_page (GTK_NOTEBOOK (priv->control_notebook),
                                   priv->search,
@@ -1219,7 +1219,7 @@ window_populate (DhWindow *window)
 }
 
 
-static gchar*
+static gchar *
 find_library_equivalent (DhWindow    *window,
                          const gchar *uri)
 {
@@ -1227,26 +1227,39 @@ find_library_equivalent (DhWindow    *window,
         gchar **components;
         GList *iter;
         DhLink *link;
+        DhBookManager *book_manager;
         gchar *book_id;
         gchar *filename;
         gchar *local_uri = NULL;
+        GList *books;
 
         components = g_strsplit (uri, "/", 0);
         book_id = components[4];
         filename = components[6];
 
         priv = window->priv;
+        book_manager = dh_base_get_book_manager (priv->base);
 
-        for (iter = dh_base_get_keywords (priv->base); iter; iter = g_list_next (iter)) {
-                link = iter->data;
-                if (g_strcmp0 (dh_link_get_book_id (link), book_id) != 0) {
-                        continue;
-                }
-                if (g_strcmp0 (dh_link_get_file_name (link), filename) != 0) {
-                        continue;
+
+        /* use list pointer to iterate */
+        for (books = dh_book_manager_get_books (book_manager);
+             !local_uri && books;
+             books = g_list_next (books)) {
+                DhBook *book = DH_BOOK (books->data);
+
+                for (iter = dh_book_get_keywords (book);
+                     iter;
+                     iter = g_list_next (iter)) {
+                        link = iter->data;
+                        if (g_strcmp0 (dh_link_get_book_id (link), book_id) != 0) {
+                                continue;
+                        }
+                        if (g_strcmp0 (dh_link_get_file_name (link), filename) != 0) {
+                                continue;
+                        }
+                        local_uri = dh_link_get_uri (link);
+                        break;
                 }
-                local_uri = dh_link_get_uri (link);
-                break;
         }
 
         g_strfreev (components);



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