[devhelp: 23/36] book-tree: Enabled showing books grouped by language
- From: Aleksander Morgado <aleksm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [devhelp: 23/36] book-tree: Enabled showing books grouped by language
- Date: Mon, 20 Dec 2010 14:33:21 +0000 (UTC)
commit 540a27696d5014ebcf0df21aca72ca12ff7e54ad
Author: Aleksander Morgado <aleksander lanedo com>
Date: Thu Dec 9 23:51:39 2010 +0100
book-tree: Enabled showing books grouped by language
src/dh-book-tree.c | 505 ++++++++++++++++++++++++++++++++++++++++------------
1 files changed, 388 insertions(+), 117 deletions(-)
---
diff --git a/src/dh-book-tree.c b/src/dh-book-tree.c
index 3af8423..b33ec8c 100644
--- a/src/dh-book-tree.c
+++ b/src/dh-book-tree.c
@@ -162,126 +162,352 @@ book_tree_setup_selection (DhBookTree *tree)
tree);
}
+/* Tries to find:
+ * - An exact match of the language group
+ * - The language group which should be just after our given language group.
+ * - Both.
+ */
static void
-book_tree_populate_tree (DhBookTree *tree)
+book_tree_find_language_group (DhBookTree *tree,
+ const gchar *language,
+ GtkTreeIter *exact_iter,
+ gboolean *exact_found,
+ GtkTreeIter *next_iter,
+ gboolean *next_found)
{
DhBookTreePriv *priv = GET_PRIVATE (tree);
- GList *l;
+ GtkTreeIter loop_iter;
- gtk_tree_store_clear (priv->store);
+ g_assert ((exact_iter && exact_found) || (next_iter && next_found));
- /* This list comes in order */
- for (l = dh_book_manager_get_books (priv->book_manager);
- l;
- l = g_list_next (l)) {
- DhBook *book = DH_BOOK (l->data);
- GNode *node;
+ /* Reset all flags to not found */
+ if (exact_found)
+ *exact_found = FALSE;
+ if (next_found)
+ *next_found = FALSE;
- node = dh_book_get_tree (book);
- while (node) {
- GtkTreeIter iter;
+ /* If we're not doing language grouping, return not found */
+ if (!dh_book_manager_get_group_by_language (priv->book_manager))
+ return;
- /* Append new iter */
- gtk_tree_store_append (priv->store, &iter, NULL);
- book_tree_insert_node (tree, node, &iter, book);
- node = g_node_next_sibling (node);
- }
+ if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->store),
+ &loop_iter)) {
+ /* Store is empty, not found */
+ return;
}
+
+ do {
+ gchar *title = NULL;
+
+ /* Look for language titles, which are those where there
+ * is no book object associated in the row */
+ gtk_tree_model_get (GTK_TREE_MODEL (priv->store),
+ &loop_iter,
+ COL_TITLE, &title,
+ -1);
+
+ if (exact_iter &&
+ g_ascii_strcasecmp (title, language) == 0) {
+ /* Exact match found! */
+ *exact_iter = loop_iter;
+ *exact_found = TRUE;
+ if (!next_iter) {
+ /* If we were not requested to look for the next one, end here */
+ g_free (title);
+ return;
+ }
+ } else if (next_iter &&
+ g_ascii_strcasecmp (title, language) > 0) {
+ *next_iter = loop_iter;
+ *next_found = TRUE;
+ /* There's no way to have an exact match after the next, so end here */
+ g_free (title);
+ return;
+ }
+
+ g_free (title);
+ } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->store),
+ &loop_iter));
}
+/* Tries to find, starting at 'first' (if given), and always in the same
+ * level of the tree:
+ * - An exact match of the book
+ * - The book which should be just after our given book
+ * - Both.
+ */
static void
-book_tree_book_created_or_enabled_cb (DhBookManager *book_manager,
- GObject *book_object,
- gpointer user_data)
+book_tree_find_book (DhBookTree *tree,
+ DhBook *book,
+ const GtkTreeIter *first,
+ GtkTreeIter *exact_iter,
+ gboolean *exact_found,
+ GtkTreeIter *next_iter,
+ gboolean *next_found)
{
- DhBookTree *tree = user_data;
DhBookTreePriv *priv = GET_PRIVATE (tree);
- DhBook *book = DH_BOOK (book_object);
- GNode *node;
GtkTreeIter loop_iter;
- GtkTreeIter iter;
-
- node = dh_book_get_tree (book);
- if (!node)
- return;
-
- /* Look for the proper place to add the new item */
- if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->store), &loop_iter)) {
- /* The model is empty now, so just append */
- gtk_tree_store_append (priv->store, &iter, NULL);
+ g_assert ((exact_iter && exact_found) || (next_iter && next_found));
+
+ /* Reset all flags to not found */
+ if (exact_found)
+ *exact_found = FALSE;
+ if (next_found)
+ *next_found = FALSE;
+
+ /* Setup iteration start */
+ if (!first) {
+ /* If no first given, start iterating from the start of the model */
+ if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->store),
+ &loop_iter)) {
+ /* Store is empty, not found */
+ return;
+ }
} else {
- gboolean found = FALSE;
+ loop_iter = *first;
+ }
- do {
- DhBook *in_tree_book = NULL;
+ do {
+ DhBook *in_tree_book = NULL;
- gtk_tree_model_get (GTK_TREE_MODEL (priv->store),
- &loop_iter,
- COL_BOOK, &in_tree_book,
- -1);
- if (in_tree_book == book) {
- /* Book already in tree, so don't add it again */
+ gtk_tree_model_get (GTK_TREE_MODEL (priv->store),
+ &loop_iter,
+ COL_BOOK, &in_tree_book,
+ -1);
+
+ /* We can compare pointers directly as we're playing with references
+ * of the same object */
+ if (exact_iter &&
+ in_tree_book == book) {
+ *exact_iter = loop_iter;
+ *exact_found = TRUE;
+ if (!next_iter) {
+ /* If we were not requested to look for the next one, end here */
g_object_unref (in_tree_book);
return;
}
- if (dh_book_cmp_by_title (in_tree_book, book) > 0) {
- found = TRUE;
- }
+ } else if (next_iter &&
+ dh_book_cmp_by_title (in_tree_book, book) > 0) {
+ *next_iter = loop_iter;
+ *next_found = TRUE;
+ g_object_unref (in_tree_book);
+ return;
+ }
- /* We should always have a DhBook in the top level tree elements */
+ if (in_tree_book)
g_object_unref (in_tree_book);
+ } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->store),
+ &loop_iter));
+}
- } while (!found && gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->store), &loop_iter));
+static void
+book_tree_add_book_to_store (DhBookTree *tree,
+ DhBook *book,
+ gboolean group_by_language)
+{
+ DhBookTreePriv *priv = GET_PRIVATE (tree);
+ GtkTreeIter book_iter;
+
+ /* If grouping by language we need to add the language categories */
+ if (group_by_language) {
+ GtkTreeIter language_iter;
+ gboolean language_iter_found;
+ GtkTreeIter next_language_iter;
+ gboolean next_language_iter_found;
+ const gchar *language_title;
+ gboolean first_in_language = FALSE;
+
+ language_title = dh_book_get_language (book);
+
+ /* Look for the proper language group */
+ book_tree_find_language_group (tree,
+ language_title,
+ &language_iter,
+ &language_iter_found,
+ &next_language_iter,
+ &next_language_iter_found);
+ /* New language group needs to be created? */
+ if (!language_iter_found) {
+ if (!next_language_iter_found) {
+ gtk_tree_store_append (priv->store,
+ &language_iter,
+ NULL);
+ } else {
+ gtk_tree_store_insert_before (priv->store,
+ &language_iter,
+ NULL,
+ &next_language_iter);
+ }
- if (found) {
+ gtk_tree_store_set (priv->store,
+ &language_iter,
+ COL_TITLE, language_title,
+ COL_LINK, NULL,
+ COL_BOOK, NULL,
+ COL_WEIGHT, PANGO_WEIGHT_BOLD,
+ -1);
+ first_in_language = TRUE;
+ }
+
+ /* If we got to add first book in a given language group, just append it. */
+ if (first_in_language) {
+ gtk_tree_store_append (priv->store,
+ &book_iter,
+ &language_iter);
+ } else {
+ GtkTreeIter first_book_iter;
+ GtkTreeIter next_book_iter;
+ gboolean next_book_iter_found;
+
+ /* The language will have at least one book, so we move iter to it */
+ gtk_tree_model_iter_children (GTK_TREE_MODEL (priv->store),
+ &first_book_iter,
+ &language_iter);
+
+ /* Find next possible book in language group */
+ book_tree_find_book (tree,
+ book,
+ &first_book_iter,
+ NULL,
+ NULL,
+ &next_book_iter,
+ &next_book_iter_found);
+ if (!next_book_iter_found) {
+ gtk_tree_store_append (priv->store,
+ &book_iter,
+ &language_iter);
+ } else {
+ gtk_tree_store_insert_before (priv->store,
+ &book_iter,
+ &language_iter,
+ &next_book_iter);
+ }
+ }
+ } else {
+ /* No language grouping, just order by book title */
+ GtkTreeIter next_book_iter;
+ gboolean next_book_iter_found;
+
+ book_tree_find_book (tree,
+ book,
+ NULL,
+ NULL,
+ NULL,
+ &next_book_iter,
+ &next_book_iter_found);
+ if (!next_book_iter_found) {
+ gtk_tree_store_append (priv->store,
+ &book_iter,
+ NULL);
+ } else {
gtk_tree_store_insert_before (priv->store,
- &iter,
+ &book_iter,
NULL,
- &loop_iter);
- } else {
- gtk_tree_store_append (priv->store, &iter, NULL);
+ &next_book_iter);
}
}
- book_tree_insert_node (tree, node, &iter, book);
+
+ /* Now book_iter contains the proper iterator where we'll add the whole
+ * book tree. */
+ book_tree_insert_node (tree,
+ dh_book_get_tree (book),
+ &book_iter,
+ book);
}
static void
-book_tree_book_deleted_or_disabled_cb (DhBookManager *book_manager,
- GObject *book_object,
- gpointer user_data)
+book_tree_populate_tree (DhBookTree *tree)
{
- DhBookTree *tree = user_data;
DhBookTreePriv *priv = GET_PRIVATE (tree);
+ GList *l;
+ gboolean group_by_language;
+
+ group_by_language = dh_book_manager_get_group_by_language (priv->book_manager);
+
+ gtk_tree_store_clear (priv->store);
+
+ /* This list comes in order, but we don't really mind */
+ for (l = dh_book_manager_get_books (priv->book_manager);
+ l;
+ l = g_list_next (l)) {
+ DhBook *book = DH_BOOK (l->data);
+
+ /* Only add enabled books to the tree */
+ if (dh_book_get_enabled (book)) {
+ book_tree_add_book_to_store (tree,
+ book,
+ group_by_language);
+ }
+ }
+}
+
+static void
+book_tree_book_created_or_enabled_cb (DhBookManager *book_manager,
+ GObject *book_object,
+ gpointer user_data)
+{
+ DhBookTree *tree = user_data;
DhBook *book = DH_BOOK (book_object);
- GtkTreeIter iter;
- gboolean found;
+ gboolean group_by_language;
- /* Look for the specific book. */
- if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->store), &iter)) {
- /* The model is empty now */
+ if (!dh_book_get_enabled (book))
return;
- }
- /* Loop top-level elements looking for the book */
- found = FALSE;
- do {
- DhBook *in_tree_book = NULL;
+ group_by_language = dh_book_manager_get_group_by_language (book_manager);
- gtk_tree_model_get (GTK_TREE_MODEL (priv->store),
- &iter,
- COL_BOOK, &in_tree_book,
- -1);
- if (in_tree_book == book) {
- found = TRUE;
+ book_tree_add_book_to_store (tree,
+ book,
+ group_by_language);
+}
+
+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 exact_iter;
+ gboolean exact_iter_found = FALSE;
+
+ if (dh_book_manager_get_group_by_language (book_manager)) {
+ GtkTreeIter first_book_iter;
+ GtkTreeIter language_iter;
+ gboolean language_iter_found;
+
+ book_tree_find_language_group (tree,
+ dh_book_get_language (book),
+ &language_iter,
+ &language_iter_found,
+ NULL,
+ NULL);
+
+ if (language_iter_found &&
+ gtk_tree_model_iter_children (GTK_TREE_MODEL (priv->store),
+ &first_book_iter,
+ &language_iter)) {
+ book_tree_find_book (tree,
+ book,
+ &first_book_iter,
+ &exact_iter,
+ &exact_iter_found,
+ NULL,
+ NULL);
}
- /* 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));
+ } else {
+ book_tree_find_book (tree,
+ book,
+ NULL,
+ &exact_iter,
+ &exact_iter_found,
+ NULL,
+ NULL);
+ }
- /* If found, delete item from the store */
- if (found) {
- gtk_tree_store_remove (priv->store, &iter);
+ if (exact_iter_found) {
+ gtk_tree_store_remove (priv->store, &exact_iter);
}
}
@@ -338,21 +564,79 @@ book_tree_selection_changed_cb (GtkTreeSelection *selection,
&iter,
COL_LINK, &link,
-1);
- if (link != priv->selected_link) {
- g_signal_emit (tree, signals[LINK_SELECTED], 0, link);
- }
- priv->selected_link = link;
+ if (link) {
+ if (link != priv->selected_link) {
+ g_signal_emit (tree, signals[LINK_SELECTED], 0, link);
+ }
+ priv->selected_link = link;
+ }
}
}
+static void
+book_tree_init_selection (DhBookTree *tree)
+{
+ DhBookTreePriv *priv;
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+ gboolean iter_found = FALSE;
+ DhLink *link;
+
+ priv = GET_PRIVATE (tree);
+
+ /* Mark the first item as selected, or it would get automatically
+ * selected when the treeview will get focus; but that's not even
+ * enough as a selection changed would still be emitted when there
+ * is no change, hence the manual tracking of selection in
+ * selected_link.
+ * https://bugzilla.gnome.org/show_bug.cgi?id=492206
+ */
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree));
+ g_signal_handlers_block_by_func (selection,
+ book_tree_selection_changed_cb,
+ tree);
+
+ /* If grouping by languages, get first book in the first language */
+ if (dh_book_manager_get_group_by_language (priv->book_manager)) {
+ GtkTreeIter language_iter;
+
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->store),
+ &language_iter)) {
+ iter_found = gtk_tree_model_iter_children (GTK_TREE_MODEL (priv->store),
+ &iter,
+ &language_iter);
+ }
+ } else {
+ iter_found = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->store),
+ &iter);
+ }
+
+ if (iter_found) {
+ gtk_tree_model_get (GTK_TREE_MODEL (priv->store),
+ &iter,
+ COL_LINK, &link,
+ -1);
+ priv->selected_link = link;
+ gtk_tree_selection_select_iter (selection, &iter);
+ }
+
+ g_signal_handlers_unblock_by_func (selection,
+ book_tree_selection_changed_cb,
+ tree);
+}
+static void
+book_tree_group_by_language_cb (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ book_tree_populate_tree (DH_BOOK_TREE (user_data));
+}
+
GtkWidget *
dh_book_tree_new (DhBookManager *book_manager)
{
DhBookTree *tree;
DhBookTreePriv *priv;
- GtkTreeSelection *selection;
- GtkTreeIter iter;
- DhLink *link;
tree = g_object_new (DH_TYPE_BOOK_TREE, NULL);
priv = GET_PRIVATE (tree);
@@ -375,28 +659,13 @@ dh_book_tree_new (DhBookManager *book_manager)
"book-disabled",
G_CALLBACK (book_tree_book_deleted_or_disabled_cb),
tree);
+ g_signal_connect (priv->book_manager,
+ "notify::group-by-language",
+ G_CALLBACK (book_tree_group_by_language_cb),
+ tree);
book_tree_populate_tree (tree);
-
- /* Mark the first item as selected, or it would get automatically
- * selected when the treeview will get focus; but that's not even
- * enough as a selection changed would still be emitted when there
- * is no change, hence the manual tracking of selection in
- * selected_link.
- * https://bugzilla.gnome.org/show_bug.cgi?id=492206
- */
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree));
- g_signal_handlers_block_by_func (selection,
- book_tree_selection_changed_cb,
- 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);
- priv->selected_link = link;
- gtk_tree_selection_select_iter (selection, &iter);
- g_signal_handlers_unblock_by_func (selection,
- book_tree_selection_changed_cb,
- tree);
+ book_tree_init_selection (tree);
return GTK_WIDGET (tree);
}
@@ -407,20 +676,22 @@ book_tree_find_uri_foreach (GtkTreeModel *model,
GtkTreeIter *iter,
FindURIData *data)
{
- DhLink *link;
- gchar *link_uri;
+ DhLink *link;
gtk_tree_model_get (model, iter,
COL_LINK, &link,
-1);
-
- link_uri = dh_link_get_uri (link);
- if (g_str_has_prefix (data->uri, link_uri)) {
- data->found = TRUE;
- data->iter = *iter;
- data->path = gtk_tree_path_copy (path);
- }
- g_free (link_uri);
+ if (link) {
+ gchar *link_uri;
+
+ link_uri = dh_link_get_uri (link);
+ if (g_str_has_prefix (data->uri, link_uri)) {
+ data->found = TRUE;
+ data->iter = *iter;
+ data->path = gtk_tree_path_copy (path);
+ }
+ g_free (link_uri);
+ }
return data->found;
}
@@ -493,5 +764,5 @@ dh_book_tree_get_selected_book_title (DhBookTree *tree)
COL_LINK, &link,
-1);
- return dh_link_get_name (link);
+ return link ? dh_link_get_name (link) : NULL;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]