[devhelp: 9/36] Do not fully rebuild trees and lists when books created, deleted, enabled or disabled



commit 370e25afcba0f9a8ceab67113f5c22843061ae84
Author: Aleksander Morgado <aleksander lanedo com>
Date:   Thu Dec 2 20:38:52 2010 +0100

    Do not fully rebuild trees and lists when books created, deleted, enabled or disabled

 src/dh-book-manager.c |  224 ++++++++++++++++++++++++++++++------------------
 src/dh-book-manager.h |    1 -
 src/dh-book-tree.c    |   93 +++++++++++++++++----
 src/dh-book.c         |   66 ++++++++++++---
 src/dh-marshal.list   |    1 +
 src/dh-preferences.c  |   72 ++++++++++++++--
 src/dh-search.c       |  207 ++++++++++++++++++++++++++++++++++++---------
 src/dh-util.c         |    4 +-
 8 files changed, 505 insertions(+), 163 deletions(-)
---
diff --git a/src/dh-book-manager.c b/src/dh-book-manager.c
index 507e6f2..877fc8a 100644
--- a/src/dh-book-manager.c
+++ b/src/dh-book-manager.c
@@ -35,11 +35,15 @@ typedef struct {
         GList      *books;
         /* HT with the monitors setup */
         GHashTable *monitors;
+        /* List of book names currently disabled */
+        GSList     *books_disabled;
 } DhBookManagerPriv;
 
 enum {
-        BOOK_LIST_UPDATED,
-        DISABLED_BOOK_LIST_UPDATED,
+        BOOK_CREATED,
+        BOOK_DELETED,
+        BOOK_ENABLED,
+        BOOK_DISABLED,
         LAST_SIGNAL
 };
 
@@ -68,6 +72,7 @@ book_manager_finalize (GObject *object)
 {
         DhBookManagerPriv *priv;
         GList             *l;
+        GSList            *sl;
 
         priv = GET_PRIVATE (object);
 
@@ -82,6 +87,12 @@ book_manager_finalize (GObject *object)
                 g_hash_table_destroy (priv->monitors);
         }
 
+        /* Clean the list of books disabled */
+        for (sl = priv->books_disabled; sl; sl = g_slist_next (sl)) {
+                g_free (sl->data);
+        }
+        g_slist_free (priv->books_disabled);
+
         G_OBJECT_CLASS (dh_book_manager_parent_class)->finalize (object);
 }
 
@@ -92,24 +103,46 @@ dh_book_manager_class_init (DhBookManagerClass *klass)
 
         object_class->finalize = book_manager_finalize;
 
-        signals[BOOK_LIST_UPDATED] =
-                g_signal_new ("book-list-updated",
+        signals[BOOK_CREATED] =
+                g_signal_new ("book-created",
+                              G_TYPE_FROM_CLASS (klass),
+                              G_SIGNAL_RUN_LAST,
+                              0,
+                              NULL, NULL,
+                              _dh_marshal_VOID__OBJECT,
+                              G_TYPE_NONE,
+                              1,
+                              G_TYPE_OBJECT);
+        signals[BOOK_DELETED] =
+                g_signal_new ("book-deleted",
+                              G_TYPE_FROM_CLASS (klass),
+                              G_SIGNAL_RUN_LAST,
+                              0,
+                              NULL, NULL,
+                              _dh_marshal_VOID__OBJECT,
+                              G_TYPE_NONE,
+                              1,
+                              G_TYPE_OBJECT);
+        signals[BOOK_ENABLED] =
+                g_signal_new ("book-enabled",
                               G_TYPE_FROM_CLASS (klass),
                               G_SIGNAL_RUN_LAST,
                               0,
                               NULL, NULL,
-                              _dh_marshal_VOID__VOID,
+                              _dh_marshal_VOID__OBJECT,
                               G_TYPE_NONE,
-                              0);
-        signals[DISABLED_BOOK_LIST_UPDATED] =
-                g_signal_new ("disabled-book-list-updated",
+                              1,
+                              G_TYPE_OBJECT);
+        signals[BOOK_DISABLED] =
+                g_signal_new ("book-disabled",
                               G_TYPE_FROM_CLASS (klass),
                               G_SIGNAL_RUN_LAST,
                               0,
                               NULL, NULL,
-                              _dh_marshal_VOID__VOID,
+                              _dh_marshal_VOID__OBJECT,
                               G_TYPE_NONE,
-                              0);
+                              1,
+                              G_TYPE_OBJECT);
 
 	g_type_class_add_private (klass, sizeof (DhBookManagerPriv));
 }
@@ -120,37 +153,26 @@ dh_book_manager_init (DhBookManager *book_manager)
         DhBookManagerPriv *priv = GET_PRIVATE (book_manager);
 
         priv->books = NULL;
-}
-
-static void
-book_manager_clean_list_of_books_disabled (GSList *books_disabled)
-{
-        GSList *sl;
+        priv->monitors = NULL;
 
-        for (sl = books_disabled; sl; sl = g_slist_next (sl)) {
-                g_free (sl->data);
-        }
-        g_slist_free (sl);
+        priv->books_disabled = dh_util_state_load_books_disabled ();
 }
 
-static void
-book_manager_check_status_from_conf (DhBookManager *book_manager)
+static gboolean
+book_manager_is_book_disabled_in_conf (DhBookManager *book_manager,
+                                       DhBook        *book)
 {
-        GSList *books_disabled, *sl;
-
-        books_disabled = dh_util_state_load_books_disabled ();
-
-        for (sl = books_disabled; sl; sl = g_slist_next (sl)) {
-                DhBook *book;
+        DhBookManagerPriv *priv = GET_PRIVATE (book_manager);
+        GSList *li;
 
-                book = dh_book_manager_get_book_by_name (book_manager,
-                                                         (const gchar *)sl->data);
-                if (book) {
-                        dh_book_set_enabled (book, FALSE);
+        for (li = priv->books_disabled; li; li = g_slist_next (li)) {
+                if (g_strcmp0 (dh_book_get_name (book),
+                               (const gchar *)li->data) == 0) {
+                        return TRUE;
                 }
         }
 
-        book_manager_clean_list_of_books_disabled (books_disabled);
+        return FALSE;
 }
 
 static void
@@ -188,9 +210,6 @@ dh_book_manager_populate (DhBookManager *book_manager)
                 book_manager,
                 "/Library/Developer/Shared/Documentation/DocSets");
 #endif
-
-        /* Once all books are loaded, check enabled status from conf */
-        book_manager_check_status_from_conf (book_manager);
 }
 
 static gchar *
@@ -277,11 +296,6 @@ book_manager_booklist_monitor_event_cb (GFileMonitor      *file_monitor,
                 book_manager_add_from_filepath (book_manager,
                                                 book_path);
                 g_free (book_path);
-
-                /* Emit signal to notify others */
-                g_signal_emit (book_manager,
-                               signals[BOOK_LIST_UPDATED],
-                               0);
         }
 
         g_free (file_path);
@@ -467,14 +481,15 @@ book_manager_book_deleted_cb (DhBook   *book,
                 g_debug ("Deleting book '%s' from the book manager list",
                          dh_book_get_title (book));
 
+                /* Emit signal to notify others */
+                g_signal_emit (book_manager,
+                               signals[BOOK_DELETED],
+                               0,
+                               book);
+
                 /* Remove the item and unref our reference */
                 priv->books = g_list_delete_link (priv->books, li);
                 g_object_unref (book);
-
-                /* Emit signal to notify others */
-                g_signal_emit (book_manager,
-                               signals[BOOK_LIST_UPDATED],
-                               0);
         }
 }
 
@@ -482,15 +497,69 @@ static void
 book_manager_book_updated_cb (DhBook   *book,
                               gpointer  user_data)
 {
-        DhBookManager *book_manager = user_data;
-
         g_debug ("Updating book '%s' in the book manager list",
                  dh_book_get_title (book));
+        /* TODO */
+}
+
+static GSList *
+book_manager_find_book_in_disabled_list (GSList *books_disabled,
+                                         DhBook *book)
+{
+        GSList *li;
+
+        for (li = books_disabled; li; li = g_slist_next (li)) {
+                if (g_strcmp0 (dh_book_get_name (book),
+                               (const gchar *)li->data) == 0) {
+                        return li;
+                }
+        }
+        return NULL;
+}
+
+static void
+book_manager_book_enabled_cb (DhBook   *book,
+                              gpointer  user_data)
+{
+        DhBookManager     *book_manager = user_data;
+        DhBookManagerPriv *priv = GET_PRIVATE (book_manager);
+        GSList            *li;
+
+        li = book_manager_find_book_in_disabled_list (priv->books_disabled,
+                                                      book);
+        /* When setting as enabled a given book, we should have it in the
+         * disabled books list! */
+        g_assert (li != NULL);
+        priv->books_disabled = g_slist_delete_link (priv->books_disabled, li);
+        dh_util_state_store_books_disabled (priv->books_disabled);
+
+        g_signal_emit (book_manager,
+                       signals[BOOK_ENABLED],
+                       0,
+                       book);
+}
+
+static void
+book_manager_book_disabled_cb (DhBook   *book,
+                               gpointer  user_data)
+{
+        DhBookManager     *book_manager = user_data;
+        DhBookManagerPriv *priv = GET_PRIVATE (book_manager);
+        GSList            *li;
+
+        li = book_manager_find_book_in_disabled_list (priv->books_disabled,
+                                                      book);
+        /* When setting as disabled a given book, we shouldn't have it in the
+         * disabled books list! */
+        g_assert (li == NULL);
+        priv->books_disabled = g_slist_append (priv->books_disabled,
+                                               g_strdup (dh_book_get_name (book)));
+        dh_util_state_store_books_disabled (priv->books_disabled);
 
-        /* Emit signal to notify others */
         g_signal_emit (book_manager,
-                       signals[BOOK_LIST_UPDATED],
-                       0);
+                       signals[BOOK_DISABLED],
+                       0,
+                       book);
 }
 
 static void
@@ -498,7 +567,7 @@ book_manager_add_from_filepath (DhBookManager *book_manager,
                                 const gchar   *book_path)
 {
         DhBookManagerPriv *priv;
-        DhBook *book;
+        DhBook            *book;
 
         g_return_if_fail (book_manager);
         g_return_if_fail (book_path);
@@ -533,6 +602,11 @@ book_manager_add_from_filepath (DhBookManager *book_manager,
         g_debug ("Adding book '%s' to the book manager list",
                  dh_book_get_title (book));
 
+        /* Set the proper enabled/disabled state, depending on conf */
+        dh_book_set_enabled (book,
+                             !book_manager_is_book_disabled_in_conf (book_manager,
+                                                                     book));
+
         /* Get notifications of book being deleted or updated */
         g_signal_connect (book,
                           "deleted",
@@ -542,6 +616,20 @@ book_manager_add_from_filepath (DhBookManager *book_manager,
                           "updated",
                           G_CALLBACK (book_manager_book_updated_cb),
                           book_manager);
+        g_signal_connect (book,
+                          "enabled",
+                          G_CALLBACK (book_manager_book_enabled_cb),
+                          book_manager);
+        g_signal_connect (book,
+                          "disabled",
+                          G_CALLBACK (book_manager_book_disabled_cb),
+                          book_manager);
+
+        /* Emit signal to notify others */
+        g_signal_emit (book_manager,
+                       signals[BOOK_CREATED],
+                       0,
+                       book);
 }
 
 GList *
@@ -582,38 +670,6 @@ dh_book_manager_get_book_by_path (DhBookManager *book_manager,
         return l ? l->data : NULL;
 }
 
-void
-dh_book_manager_update_disabled (DhBookManager *book_manager)
-{
-        DhBookManagerPriv *priv;
-        GSList *books_disabled = NULL;
-        GList  *l;
-
-        g_return_if_fail (book_manager);
-
-        priv = GET_PRIVATE (book_manager);
-
-        /* Create list of disabled books */
-        for (l = priv->books; l; l = g_list_next (l)) {
-                DhBook *book = DH_BOOK (l->data);
-
-                if (!dh_book_get_enabled (book)) {
-                        books_disabled = g_slist_append (books_disabled,
-                                                         g_strdup (dh_book_get_name (book)));
-                }
-        }
-
-        /* Store in conf */
-        dh_util_state_store_books_disabled (books_disabled);
-
-        /* Emit signal to notify others */
-        g_signal_emit (book_manager,
-                       signals[DISABLED_BOOK_LIST_UPDATED],
-                       0);
-
-        book_manager_clean_list_of_books_disabled (books_disabled);
-}
-
 DhBookManager *
 dh_book_manager_new (void)
 {
diff --git a/src/dh-book-manager.h b/src/dh-book-manager.h
index 0f6499e..525bace 100644
--- a/src/dh-book-manager.h
+++ b/src/dh-book-manager.h
@@ -53,7 +53,6 @@ DhBook        *dh_book_manager_get_book_by_name     (DhBookManager *book_manager
                                                      const gchar   *name);
 DhBook        *dh_book_manager_get_book_by_path     (DhBookManager *book_manager,
                                                      const gchar   *path);
-void           dh_book_manager_update_disabled      (DhBookManager *book_manager);
 
 G_END_DECLS
 
diff --git a/src/dh-book-tree.c b/src/dh-book-tree.c
index 732e395..e544d56 100644
--- a/src/dh-book-tree.c
+++ b/src/dh-book-tree.c
@@ -46,10 +46,10 @@ static void dh_book_tree_class_init        (DhBookTreeClass  *klass);
 static void dh_book_tree_init              (DhBookTree       *tree);
 static void book_tree_add_columns          (DhBookTree       *tree);
 static void book_tree_setup_selection      (DhBookTree       *tree);
-static void book_tree_populate_tree        (DhBookTree       *tree);
 static void book_tree_insert_node          (DhBookTree       *tree,
                                             GNode            *node,
-                                            GtkTreeIter      *parent_iter);
+                                            GtkTreeIter      *parent_iter,
+                                            DhBook           *book);
 static void book_tree_selection_changed_cb (GtkTreeSelection *selection,
                                             DhBookTree       *tree);
 
@@ -62,6 +62,7 @@ enum {
 	COL_TITLE,
 	COL_LINK,
 	COL_WEIGHT,
+        COL_BOOK,
 	N_COLUMNS
 };
 
@@ -113,7 +114,8 @@ dh_book_tree_init (DhBookTree *tree)
 	priv->store = gtk_tree_store_new (N_COLUMNS,
 					  G_TYPE_STRING,
 					  G_TYPE_POINTER,
-                                          PANGO_TYPE_WEIGHT);
+                                          PANGO_TYPE_WEIGHT,
+                                          G_TYPE_OBJECT);
 	priv->selected_link = NULL;
 	gtk_tree_view_set_model (GTK_TREE_VIEW (tree),
 				 GTK_TREE_MODEL (priv->store));
@@ -168,6 +170,7 @@ book_tree_populate_tree (DhBookTree *tree)
 
         gtk_tree_store_clear (priv->store);
 
+        /* This list comes in order */
         for (l = dh_book_manager_get_books (priv->book_manager);
              l;
              l = g_list_next (l)) {
@@ -175,25 +178,75 @@ book_tree_populate_tree (DhBookTree *tree)
                 GNode  *node;
 
                 node = dh_book_get_tree (book);
-                while(node) {
-                        book_tree_insert_node (tree, node, NULL);
+                while (node) {
+                        book_tree_insert_node (tree, node, NULL, book);
                         node = g_node_next_sibling (node);
                 }
         }
 }
 
 static void
-book_manager_book_list_changed_cb (DhBookManager *book_manager,
-                                   gpointer       user_data)
+book_tree_book_created_or_enabled_cb (DhBookManager *book_manager,
+                                      GObject       *book_object,
+                                      gpointer       user_data)
 {
         DhBookTree *tree = user_data;
-        book_tree_populate_tree (tree);
+        DhBook *book = DH_BOOK (book_object);
+        GNode  *node;
+
+        /* TODO: insert ordered here! */
+
+        node = dh_book_get_tree (book);
+        while (node) {
+                book_tree_insert_node (tree, node, NULL, book);
+                node = g_node_next_sibling (node);
+        }
+}
+
+static void
+book_tree_book_deleted_or_disabled_cb (DhBookManager *book_manager,
+                                       GObject       *book_object,
+                                       gpointer       user_data)
+{
+        DhBookTree *tree = user_data;
+        DhBookTreePriv *priv = GET_PRIVATE (tree);
+        DhBook *book = DH_BOOK (book_object);
+        GtkTreeIter iter;
+        gboolean found;
+
+        /* Look for the specific book. */
+	if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->store), &iter)) {
+                /* The model is empty now */
+                return;
+        }
+
+        /* Loop top-level elements looking for the book */
+        found = FALSE;
+        do {
+                DhBook *in_tree_book = NULL;
+
+                gtk_tree_model_get (GTK_TREE_MODEL (priv->store),
+                                    &iter,
+                                    COL_BOOK, &in_tree_book,
+                                    -1);
+                if (in_tree_book == book) {
+                        found = TRUE;
+                }
+                /* We should always have a DhBook in the top level tree elements */
+                g_object_unref (in_tree_book);
+        } while (!found && gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->store), &iter));
+
+        /* If found, delete item from the store */
+        if (found) {
+                gtk_tree_store_remove (priv->store, &iter);
+        }
 }
 
 static void
 book_tree_insert_node (DhBookTree  *tree,
 		       GNode       *node,
-		       GtkTreeIter *parent_iter)
+		       GtkTreeIter *parent_iter,
+                       DhBook      *book)
 
 {
         DhBookTreePriv *priv = GET_PRIVATE (tree);
@@ -216,12 +269,13 @@ book_tree_insert_node (DhBookTree  *tree,
                             COL_TITLE, dh_link_get_name (link),
                             COL_LINK, link,
                             COL_WEIGHT, weight,
+                            COL_BOOK, book,
                             -1);
 
 	for (child = g_node_first_child (node);
 	     child;
 	     child = g_node_next_sibling (child)) {
-		book_tree_insert_node (tree, child, &iter);
+		book_tree_insert_node (tree, child, &iter, NULL);
 	}
 }
 
@@ -259,13 +313,22 @@ dh_book_tree_new (DhBookManager *book_manager)
         priv = GET_PRIVATE (tree);
 
         priv->book_manager = g_object_ref (book_manager);
+
+        g_signal_connect (priv->book_manager,
+                          "book-created",
+                          G_CALLBACK (book_tree_book_created_or_enabled_cb),
+                          tree);
+        g_signal_connect (priv->book_manager,
+                          "book-deleted",
+                          G_CALLBACK (book_tree_book_deleted_or_disabled_cb),
+                          tree);
         g_signal_connect (priv->book_manager,
-                          "disabled-book-list-updated",
-                          G_CALLBACK (book_manager_book_list_changed_cb),
+                          "book-enabled",
+                          G_CALLBACK (book_tree_book_created_or_enabled_cb),
                           tree);
         g_signal_connect (priv->book_manager,
-                          "book-list-updated",
-                          G_CALLBACK (book_manager_book_list_changed_cb),
+                          "book-disabled",
+                          G_CALLBACK (book_tree_book_deleted_or_disabled_cb),
                           tree);
 
         book_tree_populate_tree (tree);
@@ -283,7 +346,7 @@ dh_book_tree_new (DhBookManager *book_manager)
 					 tree);
 	gtk_tree_model_get_iter_first ( GTK_TREE_MODEL (priv->store), &iter);
 	gtk_tree_model_get (GTK_TREE_MODEL (priv->store),
-			&iter, COL_LINK, &link, -1);
+                            &iter, COL_LINK, &link, -1);
 	priv->selected_link = link;
 	gtk_tree_selection_select_iter (selection, &iter);
 	g_signal_handlers_unblock_by_func (selection,
diff --git a/src/dh-book.c b/src/dh-book.c
index 4f4c33e..5ef6b25 100644
--- a/src/dh-book.c
+++ b/src/dh-book.c
@@ -35,11 +35,19 @@
 
 /* Signals managed by the DhBook */
 enum {
+        BOOK_ENABLED,
+        BOOK_DISABLED,
 	BOOK_UPDATED,
         BOOK_DELETED,
 	BOOK_LAST_SIGNAL
 };
 
+typedef enum {
+        BOOK_MONITOR_EVENT_NONE,
+        BOOK_MONITOR_EVENT_UPDATED,
+        BOOK_MONITOR_EVENT_DELETED
+} DhBookMonitorEvent;
+
 /* Structure defining basic contents to store about every book */
 typedef struct {
         /* File path of the book */
@@ -57,9 +65,8 @@ typedef struct {
 
         /* Monitor of this specific book */
         GFileMonitor *monitor;
-        /* Last received events */
-        gboolean      is_deleted;
-        gboolean      is_updated;
+        /* Last received event */
+        DhBookMonitorEvent monitor_event;
         /* ID of the event source */
         guint         monitor_event_timeout_id;
 } DhBookPriv;
@@ -121,6 +128,27 @@ dh_book_class_init (DhBookClass *klass)
 
         object_class->finalize = book_finalize;
 
+	signals[BOOK_ENABLED] =
+		g_signal_new ("enabled",
+		              G_TYPE_FROM_CLASS (klass),
+		              G_SIGNAL_RUN_LAST,
+		              0,
+		              NULL, NULL,
+                              _dh_marshal_VOID__VOID,
+		              G_TYPE_NONE,
+                              0);
+
+	signals[BOOK_DISABLED] =
+		g_signal_new ("disabled",
+		              G_TYPE_FROM_CLASS (klass),
+		              G_SIGNAL_RUN_LAST,
+		              0,
+		              NULL, NULL,
+                              _dh_marshal_VOID__VOID,
+		              G_TYPE_NONE,
+                              0);
+
+
 	signals[BOOK_UPDATED] =
 		g_signal_new ("updated",
 		              G_TYPE_FROM_CLASS (klass),
@@ -156,8 +184,7 @@ dh_book_init (DhBook *book)
         priv->tree = NULL;
         priv->keywords = NULL;
         priv->monitor = NULL;
-        priv->is_deleted = FALSE;
-        priv->is_updated = FALSE;
+        priv->monitor_event = BOOK_MONITOR_EVENT_NONE;
         priv->monitor_event_timeout_id = 0;
 }
 
@@ -236,18 +263,29 @@ book_monitor_event_timeout_cb  (gpointer data)
 
         /* We'll get either is_deleted OR is_updated,
          * not possible to have both or none */
-        if (priv->is_deleted) {
+        switch (priv->monitor_event)
+        {
+        case BOOK_MONITOR_EVENT_DELETED:
                 /* Emit the signal, but make sure we hold a reference
                  * while doing it */
                 g_object_ref (book);
 		g_signal_emit (book, signals[BOOK_DELETED], 0);
                 g_object_unref (book);
-        } else if (priv->is_updated) {
+                break;
+        case BOOK_MONITOR_EVENT_UPDATED:
+                /* Emit the signal, but make sure we hold a reference
+                 * while doing it */
+                g_object_ref (book);
 		g_signal_emit (book, signals[BOOK_UPDATED], 0);
-        } else {
-                g_warn_if_reached ();
+                g_object_unref (book);
+                break;
+        default:
+                break;
         }
 
+        /* Reset event */
+        priv->monitor_event = BOOK_MONITOR_EVENT_NONE;
+
         return FALSE;
 }
 
@@ -271,13 +309,11 @@ book_monitor_event_cb (GFileMonitor      *file_monitor,
                  * Treat in the same way as a CHANGES_DONE_HINT, so
                  * fall through the case.  */
         case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
-                priv->is_deleted = FALSE; /* Reset any previous one */
-                priv->is_updated = TRUE;
+                priv->monitor_event = BOOK_MONITOR_EVENT_UPDATED;
                 reset_timer = TRUE;
                 break;
         case G_FILE_MONITOR_EVENT_DELETED:
-                priv->is_deleted = TRUE;
-                priv->is_updated = FALSE; /* Reset any previous one */
+                priv->monitor_event = BOOK_MONITOR_EVENT_DELETED;
                 reset_timer = TRUE;
                 break;
         default:
@@ -371,6 +407,10 @@ dh_book_set_enabled (DhBook *book,
         g_return_if_fail (DH_IS_BOOK (book));
 
         GET_PRIVATE (book)->enabled = enabled;
+
+        g_signal_emit (book,
+                       enabled ? signals[BOOK_ENABLED] : signals[BOOK_DISABLED],
+                       0);
 }
 
 gint
diff --git a/src/dh-marshal.list b/src/dh-marshal.list
index 2023eaf..13f9cab 100644
--- a/src/dh-marshal.list
+++ b/src/dh-marshal.list
@@ -1,3 +1,4 @@
+VOID:OBJECT
 VOID:BOOLEAN
 VOID:POINTER
 VOID:STRING
diff --git a/src/dh-preferences.c b/src/dh-preferences.c
index 445b227..2f1d607 100644
--- a/src/dh-preferences.c
+++ b/src/dh-preferences.c
@@ -73,7 +73,11 @@ static void     preferences_bookshelf_tree_selection_toggled_cb (GtkCellRenderer
                                                                  gchar                 *path,
                                                                  gpointer               user_data);
 static void     preferences_bookshelf_populate_store            (void);
-static void     preferences_bookshelf_book_list_changed_cb      (DhBookManager         *book_manager,
+static void     preferences_bookshelf_book_created_cb           (DhBookManager         *book_manager,
+                                                                 GObject               *book_object,
+                                                                 gpointer               user_data);
+static void     preferences_bookshelf_book_deleted_cb           (DhBookManager         *book_manager,
+                                                                 GObject               *book_object,
                                                                  gpointer               user_data);
 
 #define DH_CONF_PATH                  "/apps/devhelp"
@@ -97,8 +101,12 @@ preferences_init (void)
                 prefs = g_new0 (DhPreferences, 1);
                 prefs->book_manager = dh_base_get_book_manager (dh_base_get ());
                 g_signal_connect (prefs->book_manager,
-                                  "book-list-updated",
-                                  G_CALLBACK (preferences_bookshelf_book_list_changed_cb),
+                                  "book-created",
+                                  G_CALLBACK (preferences_bookshelf_book_created_cb),
+                                  NULL);
+                g_signal_connect (prefs->book_manager,
+                                  "book-deleted",
+                                  G_CALLBACK (preferences_bookshelf_book_deleted_cb),
                                   NULL);
         }
 }
@@ -315,18 +323,63 @@ preferences_bookshelf_tree_selection_toggled_cb (GtkCellRendererToggle *cell_ren
                         gtk_list_store_set (prefs->booklist_store, &iter,
                                             LTCOLUMN_ENABLED, !enabled,
                                             -1);
-
-                        dh_book_manager_update_disabled (prefs->book_manager);
                 }
         }
 }
 
 static void
-preferences_bookshelf_book_list_changed_cb (DhBookManager *book_manager,
-                                            gpointer       user_data)
+preferences_bookshelf_book_created_cb (DhBookManager *book_manager,
+                                       GObject       *book_object,
+                                       gpointer       user_data)
 {
-        gtk_list_store_clear (prefs->booklist_store);
-        preferences_bookshelf_populate_store ();
+        DhBook      *book = DH_BOOK (book_object);
+        GtkTreeIter  iter;
+
+        /* TODO: Proper order AND make sure not already there. */
+        gtk_list_store_append (prefs->booklist_store, &iter);
+        gtk_list_store_set (prefs->booklist_store, &iter,
+                            LTCOLUMN_ENABLED,  dh_book_get_enabled (book),
+                            LTCOLUMN_TITLE,    dh_book_get_title (book),
+                            LTCOLUMN_BOOK,     book,
+                            -1);
+}
+
+static void
+preferences_bookshelf_book_deleted_cb (DhBookManager *book_manager,
+                                       GObject       *book_object,
+                                       gpointer       user_data)
+{
+        DhBook      *book = DH_BOOK (book_object);
+        GtkTreeIter  iter;
+        gboolean     found;
+
+        /* Look for the specific book. */
+	if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (prefs->booklist_store), &iter)) {
+                /* The model is empty now */
+                return;
+        }
+
+        /* Loop elements looking for the book */
+        found = FALSE;
+        do {
+                DhBook *in_list_book = NULL;
+
+                gtk_tree_model_get (GTK_TREE_MODEL (prefs->booklist_store),
+                                    &iter,
+                                    LTCOLUMN_BOOK, &in_list_book,
+                                    -1);
+                if (in_list_book == book) {
+                        found = TRUE;
+                }
+
+                if (in_list_book)
+                        g_object_unref (in_list_book);
+        } while (!found && gtk_tree_model_iter_next (GTK_TREE_MODEL (prefs->booklist_store), &iter));
+
+        /* If found, delete item from the store */
+        if (found) {
+                gtk_list_store_remove (prefs->booklist_store, &iter);
+        }
 }
 
 static void
@@ -334,6 +387,7 @@ preferences_bookshelf_populate_store (void)
 {
         GList *l;
 
+        /* This list already comes ordered */
         for (l = dh_book_manager_get_books (prefs->book_manager);
              l;
              l = g_list_next (l)) {
diff --git a/src/dh-search.c b/src/dh-search.c
index 8bdb187..198458c 100644
--- a/src/dh-search.c
+++ b/src/dh-search.c
@@ -82,6 +82,13 @@ enum {
         LAST_SIGNAL
 };
 
+enum {
+	COL_TITLE,
+	COL_LINK,
+        COL_BOOK,
+	N_COLUMNS
+};
+
 G_DEFINE_TYPE (DhSearch, dh_search, GTK_TYPE_VBOX);
 
 #define GET_PRIVATE(instance) G_TYPE_INSTANCE_GET_PRIVATE \
@@ -280,7 +287,7 @@ search_combo_set_active_id (DhSearch    *search,
                         gchar *id;
 
                         gtk_tree_model_get (model, &iter,
-                                            1, &id,
+                                            COL_LINK, &id,
                                             -1);
 
                         if (id && strcmp (book_id, id) == 0) {
@@ -320,7 +327,7 @@ search_combo_get_active_id (DhSearch *search)
         model = gtk_combo_box_get_model (GTK_COMBO_BOX (priv->book_combo));
 
         gtk_tree_model_get (model, &iter,
-                            1, &id,
+                            COL_LINK, &id,
                             -1);
 
         return id;
@@ -477,13 +484,21 @@ search_combo_row_separator_func (GtkTreeModel *model,
 {
         char *label;
         char *link;
+        GObject *book;
         gboolean result;
 
-        gtk_tree_model_get (model, iter, 0, &label, 1, &link, -1);
+        gtk_tree_model_get (model, iter,
+                            COL_TITLE, &label,
+                            COL_LINK, &link,
+                            COL_BOOK, &book,
+                            -1);
 
-        result = (link == NULL && label == NULL);
+        result = (link == NULL && label == NULL && book == NULL);
         g_free (label);
         g_free (link);
+        if (book) {
+                g_object_unref (book);
+        }
 
         return result;
 }
@@ -502,17 +517,20 @@ search_combo_populate (DhSearch *search)
 
         gtk_list_store_clear (store);
 
+        /* Add main title */
         gtk_list_store_append (store, &iter);
         gtk_list_store_set (store, &iter,
-                            0, _("All books"),
-                            1, NULL,
+                            COL_TITLE, _("All books"),
+                            COL_LINK, NULL,
+                            COL_BOOK, NULL,
                             -1);
 
         /* Add a separator */
         gtk_list_store_append (store, &iter);
         gtk_list_store_set (store, &iter,
-                            0, NULL,
-                            1, NULL,
+                            COL_TITLE, NULL,
+                            COL_LINK, NULL,
+                            COL_BOOK, NULL,
                             -1);
 
         for (l = dh_book_manager_get_books (priv->book_manager);
@@ -529,8 +547,9 @@ search_combo_populate (DhSearch *search)
 
                         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),
+                                            COL_TITLE, dh_link_get_name (link),
+                                            COL_LINK, dh_link_get_book_id (link),
+                                            COL_BOOK, book,
                                             -1);
                 }
         }
@@ -538,6 +557,73 @@ search_combo_populate (DhSearch *search)
         gtk_combo_box_set_active (GTK_COMBO_BOX (priv->book_combo), 0);
 }
 
+static void
+search_combo_add_book (DhSearch *search,
+                       DhBook   *book)
+{
+        DhSearchPriv *priv;
+        GtkListStore *store;
+        GNode        *node;
+        GtkTreeIter   iter;
+
+        priv = GET_PRIVATE (search);
+        store = GTK_LIST_STORE (gtk_combo_box_get_model (GTK_COMBO_BOX (priv->book_combo)));
+
+        node = dh_book_get_tree (book);
+        if (node) {
+                DhLink *link;
+
+                link = node->data;
+                /* TODO: Proper order AND make sure not already there */
+                gtk_list_store_append (store, &iter);
+                gtk_list_store_set (store, &iter,
+                                    COL_TITLE, dh_link_get_name (link),
+                                    COL_LINK, dh_link_get_book_id (link),
+                                    COL_BOOK, book,
+                                    -1);
+        }
+}
+
+static void
+search_combo_delete_book (DhSearch *search,
+                          DhBook   *book)
+{
+        DhSearchPriv *priv;
+        GtkListStore *store;
+        GtkTreeIter   iter;
+        gboolean      found;
+
+        priv = GET_PRIVATE (search);
+        store = GTK_LIST_STORE (gtk_combo_box_get_model (GTK_COMBO_BOX (priv->book_combo)));
+
+        /* Look for the specific book. */
+	if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter)) {
+                /* The model is empty now */
+                return;
+        }
+
+        /* Loop elements looking for the book */
+        found = FALSE;
+        do {
+                DhBook *in_list_book = NULL;
+
+                gtk_tree_model_get (GTK_TREE_MODEL (store),
+                                    &iter,
+                                    COL_BOOK, &in_list_book,
+                                    -1);
+                if (in_list_book == book) {
+                        found = TRUE;
+                }
+
+                if (in_list_book)
+                        g_object_unref (in_list_book);
+        } while (!found && gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));
+
+        /* If found, delete item from the store */
+        if (found) {
+                gtk_list_store_remove (store, &iter);
+        }
+}
 
 static void
 search_combo_create (DhSearch *search)
@@ -548,12 +634,10 @@ search_combo_create (DhSearch *search)
 
         priv = GET_PRIVATE (search);
 
-        store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
+        store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_OBJECT);
         priv->book_combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
         g_object_unref (store);
 
-        search_combo_populate (search);
-
         gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (priv->book_combo),
                                               search_combo_row_separator_func,
                                               NULL, NULL);
@@ -565,47 +649,82 @@ search_combo_create (DhSearch *search)
         gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (priv->book_combo),
                                        cell,
                                        "text", 0);
+
+        search_combo_populate (search);
 }
 
 static void
-search_completion_populate (DhSearch *search)
+search_completion_add_book (DhSearch *search,
+                            DhBook   *book)
 {
-        DhSearchPriv *priv;
-        GList        *l;
-
-        priv = GET_PRIVATE (search);
+        DhSearchPriv *priv = GET_PRIVATE (search);
+        GList        *keywords;
 
-        if (priv->completion) {
-                g_completion_free (priv->completion);
+        if (G_UNLIKELY (!priv->completion)) {
+                priv->completion = g_completion_new ((GCompletionFunc) search_complete_func);
         }
 
-        priv->completion = g_completion_new ((GCompletionFunc) search_complete_func);
+        keywords = dh_book_get_keywords (book);
+        if (keywords) {
+                g_completion_add_items (priv->completion, keywords);
+        }
+}
 
-        for (l = dh_book_manager_get_books (priv->book_manager);
-             l;
-             l = g_list_next (l)) {
-                DhBook *book = DH_BOOK (l->data);
-                GList  *keywords;
+static void
+search_completion_delete_book (DhSearch *search,
+                               DhBook   *book)
+{
+        DhSearchPriv *priv = GET_PRIVATE (search);
+        GList        *keywords;
 
-                keywords = dh_book_get_keywords (book);
+        if (G_UNLIKELY (!priv->completion)) {
+                return;
+        }
 
-                if (keywords) {
-                        g_completion_add_items (priv->completion,
-                                                keywords);
-                }
+        keywords = dh_book_get_keywords (book);
+        if (keywords) {
+                g_completion_remove_items (priv->completion, keywords);
         }
 }
 
 static void
-book_manager_book_list_changed_cb (DhBookManager *book_manager,
+search_book_created_or_enabled_cb (DhBookManager *book_manager,
+                                   DhBook        *book,
                                    gpointer       user_data)
 {
-        DhSearch *search = user_data;
+        DhSearch *search = DH_SEARCH (user_data);
 
-        search_completion_populate (search);
-        search_combo_populate (search);
+        search_completion_add_book (search, book);
+        search_combo_add_book (search, book);
+}
+
+static void
+search_book_deleted_or_disabled_cb (DhBookManager *book_manager,
+                                    DhBook        *book,
+                                    gpointer       user_data)
+{
+        DhSearch *search = DH_SEARCH (user_data);
+
+        search_completion_delete_book (search, book);
+        search_combo_delete_book (search, book);
 }
 
+static void
+search_completion_populate (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)) {
+                search_completion_add_book (search, DH_BOOK (l->data));
+        }
+}
+
+
 GtkWidget *
 dh_search_new (DhBookManager *book_manager)
 {
@@ -622,13 +741,22 @@ dh_search_new (DhBookManager *book_manager)
         priv = GET_PRIVATE (search);
 
         priv->book_manager = g_object_ref (book_manager);
+
         g_signal_connect (priv->book_manager,
-                          "disabled-book-list-updated",
-                          G_CALLBACK (book_manager_book_list_changed_cb),
+                          "book-created",
+                          G_CALLBACK (search_book_created_or_enabled_cb),
                           search);
         g_signal_connect (priv->book_manager,
-                          "book-list-updated",
-                          G_CALLBACK (book_manager_book_list_changed_cb),
+                          "book-deleted",
+                          G_CALLBACK (search_book_deleted_or_disabled_cb),
+                          search);
+        g_signal_connect (priv->book_manager,
+                          "book-enabled",
+                          G_CALLBACK (search_book_created_or_enabled_cb),
+                          search);
+        g_signal_connect (priv->book_manager,
+                          "book-disabled",
+                          G_CALLBACK (search_book_deleted_or_disabled_cb),
                           search);
 
         gtk_container_set_border_width (GTK_CONTAINER (search), 2);
@@ -706,6 +834,7 @@ dh_search_new (DhBookManager *book_manager)
         gtk_box_pack_end (GTK_BOX (search), list_sw, TRUE, TRUE, 0);
 
         search_completion_populate (search);
+
         dh_keyword_model_set_words (priv->model, book_manager);
 
         gtk_widget_show_all (GTK_WIDGET (search));
diff --git a/src/dh-util.c b/src/dh-util.c
index 2453c9b..c9ce206 100644
--- a/src/dh-util.c
+++ b/src/dh-util.c
@@ -472,7 +472,7 @@ dh_util_state_load_books_disabled (void)
 
         key = util_state_get_key ("main/contents", "books_disabled");
         ige_conf_get_string_list (ige_conf_get (), key, &books_disabled);
-        g_free(key);
+        g_free (key);
 
         return books_disabled;
 }
@@ -484,7 +484,7 @@ dh_util_state_store_books_disabled (GSList *books_disabled)
 
         key = util_state_get_key ("main/contents", "books_disabled");
         ige_conf_set_string_list (ige_conf_get (), key, books_disabled);
-        g_free(key);
+        g_free (key);
 }
 
 static gboolean



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