[devhelp: 21/36] preferences: Manage the list of books also in group by language mode
- From: Aleksander Morgado <aleksm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [devhelp: 21/36] preferences: Manage the list of books also in group by language mode
- Date: Mon, 20 Dec 2010 14:33:11 +0000 (UTC)
commit 07ed49c4f05694ed87717a798ca889268b5fc9cf
Author: Aleksander Morgado <aleksander lanedo com>
Date: Thu Dec 9 20:39:27 2010 +0100
preferences: Manage the list of books also in group by language mode
data/ui/devhelp.builder | 6 +
src/dh-book.c | 18 ++-
src/dh-preferences.c | 507 ++++++++++++++++++++++++++++++++++++++++-------
3 files changed, 450 insertions(+), 81 deletions(-)
---
diff --git a/data/ui/devhelp.builder b/data/ui/devhelp.builder
index 0db7485..405bdc4 100644
--- a/data/ui/devhelp.builder
+++ b/data/ui/devhelp.builder
@@ -10,6 +10,10 @@
<column type="gchararray"/>
<!-- column-name book -->
<column type="GObject"/>
+ <!-- column-name weight -->
+ <column type="gint"/>
+ <!-- column-name inconsistent -->
+ <column type="gboolean"/>
</columns>
</object>
<object class="GtkDialog" id="preferences_dialog">
@@ -218,6 +222,7 @@
</object>
<attributes>
<attribute name="active">0</attribute>
+ <attribute name="inconsistent">4</attribute>
</attributes>
</child>
</object>
@@ -230,6 +235,7 @@
<object class="GtkCellRendererText" id="cellrenderertext1"/>
<attributes>
<attribute name="text">1</attribute>
+ <attribute name="weight">3</attribute>
</attributes>
</child>
</object>
diff --git a/src/dh-book.c b/src/dh-book.c
index 65d9d22..0ac849e 100644
--- a/src/dh-book.c
+++ b/src/dh-book.c
@@ -24,6 +24,8 @@
#include "config.h"
#include <string.h>
+#include <glib/gi18n.h>
+
#include "dh-link.h"
#include "dh-parser.h"
#include "dh-book.h"
@@ -386,7 +388,7 @@ dh_book_get_language (DhBook *book)
priv = GET_PRIVATE (book);
- return priv->language;
+ return priv->language ? priv->language : _("Undefined language");
}
const gchar *
@@ -413,13 +415,17 @@ void
dh_book_set_enabled (DhBook *book,
gboolean enabled)
{
- g_return_if_fail (DH_IS_BOOK (book));
+ DhBookPriv *priv;
- GET_PRIVATE (book)->enabled = enabled;
+ g_return_if_fail (DH_IS_BOOK (book));
- g_signal_emit (book,
- enabled ? signals[BOOK_ENABLED] : signals[BOOK_DISABLED],
- 0);
+ priv = GET_PRIVATE (book);
+ if (priv->enabled != enabled) {
+ priv->enabled = enabled;
+ g_signal_emit (book,
+ enabled ? signals[BOOK_ENABLED] : signals[BOOK_DISABLED],
+ 0);
+ }
}
gint
diff --git a/src/dh-preferences.c b/src/dh-preferences.c
index d32a8a4..0ecef11 100644
--- a/src/dh-preferences.c
+++ b/src/dh-preferences.c
@@ -74,12 +74,29 @@ static void preferences_bookshelf_tree_selection_toggled_cb (GtkCellRende
gchar *path,
gpointer user_data);
static void preferences_bookshelf_populate_store (void);
+static void preferences_bookshelf_clean_store (void);
+static void preferences_bookshelf_add_book_to_store (DhBook *book,
+ gboolean group_by_language);
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);
+static void preferences_bookshelf_find_language_group (const gchar *language,
+ GtkTreeIter *exact_iter,
+ gboolean *exact_found,
+ GtkTreeIter *next_iter,
+ gboolean *next_found);
+static void preferences_bookshelf_find_book (DhBook *book,
+ const GtkTreeIter *first,
+ GtkTreeIter *exact_iter,
+ gboolean *exact_found,
+ GtkTreeIter *next_iter,
+ gboolean *next_found);
+static void preferences_bookshelf_group_by_language_cb (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data);
static void preferences_bookshelf_group_by_language_toggled_cb (GtkToggleButton *button,
gpointer user_data);
@@ -92,9 +109,11 @@ static void preferences_bookshelf_group_by_language_toggled_cb (GtkToggleBut
#define DH_CONF_GROUP_BY_LANGUAGE DH_CONF_PATH "/ui/use_system_fonts"
/* Book list store columns... */
-#define LTCOLUMN_ENABLED 0
-#define LTCOLUMN_TITLE 1
-#define LTCOLUMN_BOOK 2
+#define LTCOLUMN_ENABLED 0
+#define LTCOLUMN_TITLE 1
+#define LTCOLUMN_BOOK 2
+#define LTCOLUMN_WEIGHT 3
+#define LTCOLUMN_INCONSISTENT 4
static DhPreferences *prefs;
@@ -112,6 +131,10 @@ preferences_init (void)
"book-deleted",
G_CALLBACK (preferences_bookshelf_book_deleted_cb),
NULL);
+ g_signal_connect (prefs->book_manager,
+ "notify::group-by-language",
+ G_CALLBACK (preferences_bookshelf_group_by_language_cb),
+ NULL);
}
}
@@ -303,6 +326,65 @@ preferences_fonts_get_font_names (gboolean use_system_fonts,
}
static void
+preferences_bookshelf_set_language_inconsistent (const gchar *language)
+{
+ GtkTreeIter loop_iter;
+ GtkTreeIter language_iter;
+ gboolean language_iter_found;
+ gboolean one_book_enabled = FALSE;
+ gboolean one_book_disabled = FALSE;
+
+ preferences_bookshelf_find_language_group (language,
+ &language_iter,
+ &language_iter_found,
+ NULL,
+ NULL);
+ if (!language_iter_found) {
+ return;
+ }
+
+ loop_iter = language_iter;
+ while (gtk_tree_model_iter_next (GTK_TREE_MODEL (prefs->booklist_store),
+ &loop_iter)) {
+ DhBook *book;
+ gboolean enabled;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (prefs->booklist_store),
+ &loop_iter,
+ LTCOLUMN_BOOK, &book,
+ LTCOLUMN_ENABLED, &enabled,
+ -1);
+ if (!book) {
+ /* Reached next language group */
+ break;
+ }
+ g_object_unref (book);
+
+ if (enabled)
+ one_book_enabled = TRUE;
+ else
+ one_book_disabled = TRUE;
+
+ if (one_book_enabled == one_book_disabled)
+ break;
+ }
+
+ /* If at least one book is enabled AND another book is disabled,
+ * we need to set inconsistent state */
+ if (one_book_enabled == one_book_disabled) {
+ gtk_list_store_set (prefs->booklist_store, &language_iter,
+ LTCOLUMN_INCONSISTENT, TRUE,
+ -1);
+ return;
+ }
+
+ gtk_list_store_set (prefs->booklist_store, &language_iter,
+ LTCOLUMN_ENABLED, one_book_enabled,
+ LTCOLUMN_INCONSISTENT, FALSE,
+ -1);
+}
+
+static void
preferences_bookshelf_tree_selection_toggled_cb (GtkCellRendererToggle *cell_renderer,
gchar *path,
gpointer user_data)
@@ -329,98 +411,371 @@ preferences_bookshelf_tree_selection_toggled_cb (GtkCellRendererToggle *cell_ren
gtk_list_store_set (prefs->booklist_store, &iter,
LTCOLUMN_ENABLED, !enabled,
-1);
+ /* Now we need to look for the language group of this item,
+ * in order to set the inconsistent state if applies */
+ if (dh_book_manager_get_group_by_language (prefs->book_manager)) {
+ preferences_bookshelf_set_language_inconsistent (dh_book_get_language (book));
+ }
+
+ } else {
+ GtkTreeIter loop_iter;
+
+ /* We should only reach this if we are grouping by language */
+ g_assert (dh_book_manager_get_group_by_language (prefs->book_manager) == TRUE);
+
+ /* Set new status in the language group item */
+ gtk_list_store_set (prefs->booklist_store, &iter,
+ LTCOLUMN_ENABLED, !enabled,
+ LTCOLUMN_INCONSISTENT, FALSE,
+ -1);
+
+ /* And set new status in all books of the same language */
+ loop_iter = iter;
+ while (gtk_tree_model_iter_next (GTK_TREE_MODEL (prefs->booklist_store),
+ &loop_iter)) {
+ gtk_tree_model_get (GTK_TREE_MODEL (prefs->booklist_store),
+ &loop_iter,
+ LTCOLUMN_BOOK, &book,
+ -1);
+ if (!book) {
+ /* Found next language group, finish */
+ return;
+ }
+
+ /* Update book conf */
+ dh_book_set_enabled (book, !enabled);
+
+ gtk_list_store_set (prefs->booklist_store,
+ &loop_iter,
+ LTCOLUMN_ENABLED, !enabled,
+ -1);
+ }
}
}
}
static void
+preferences_bookshelf_group_by_language_cb (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ preferences_bookshelf_clean_store ();
+ preferences_bookshelf_populate_store ();
+}
+
+static void
preferences_bookshelf_book_created_cb (DhBookManager *book_manager,
GObject *book_object,
gpointer user_data)
{
+ preferences_bookshelf_add_book_to_store (DH_BOOK (book_object),
+ dh_book_manager_get_group_by_language (prefs->book_manager));
+}
+
+static void
+preferences_bookshelf_book_deleted_cb (DhBookManager *book_manager,
+ GObject *book_object,
+ gpointer user_data)
+{
DhBook *book = DH_BOOK (book_object);
- GtkTreeIter iter;
- GtkTreeIter loop_iter;
+ GtkTreeIter exact_iter;
+ gboolean exact_iter_found;
+
+ preferences_bookshelf_find_book (book,
+ NULL,
+ &exact_iter,
+ &exact_iter_found,
+ NULL,
+ NULL);
+ if (exact_iter_found) {
+ gtk_list_store_remove (prefs->booklist_store, &exact_iter);
+ preferences_bookshelf_set_language_inconsistent (dh_book_get_language (book));
+ }
+}
- if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (prefs->booklist_store), &loop_iter)) {
- /* The model is empty now, so just append */
- gtk_list_store_append (prefs->booklist_store, &iter);
- } else {
- gboolean found = FALSE;
+/* 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
+preferences_bookshelf_find_language_group (const gchar *language,
+ GtkTreeIter *exact_iter,
+ gboolean *exact_found,
+ GtkTreeIter *next_iter,
+ gboolean *next_found)
+{
+ GtkTreeIter loop_iter;
- do {
- DhBook *in_list_book = NULL;
+ g_assert ((exact_iter && exact_found) || (next_iter && next_found));
- gtk_tree_model_get (GTK_TREE_MODEL (prefs->booklist_store),
- &loop_iter,
- LTCOLUMN_BOOK, &in_list_book,
- -1);
- if (in_list_book == book) {
- /* Book already in list, so don't add it again */
- g_object_unref (in_list_book);
- return;
- }
- if (dh_book_cmp_by_title (in_list_book, book) > 0) {
- found = TRUE;
- }
+ /* Reset all flags to not found */
+ if (exact_found)
+ *exact_found = FALSE;
+ if (next_found)
+ *next_found = FALSE;
- if (in_list_book)
- g_object_unref (in_list_book);
- } while (!found &&
- gtk_tree_model_iter_next (GTK_TREE_MODEL (prefs->booklist_store), &loop_iter));
+ if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (prefs->booklist_store),
+ &loop_iter)) {
+ /* Store is empty, not found */
+ return;
+ }
- if (found) {
- gtk_list_store_insert_before (prefs->booklist_store,
- &iter,
- &loop_iter);
- } else {
- gtk_list_store_append (prefs->booklist_store, &iter);
+ do {
+ DhBook *book = NULL;
+ 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 (prefs->booklist_store),
+ &loop_iter,
+ LTCOLUMN_TITLE, &title,
+ LTCOLUMN_BOOK, &book,
+ -1);
+
+ /* If we got a book, it's not a language row */
+ if (book) {
+ g_free (title);
+ g_object_unref (book);
+ continue;
}
- }
- 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);
+ 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 (prefs->booklist_store),
+ &loop_iter));
}
+/* Tries to find, starting at 'first' (if given):
+ * - An exact match of the book
+ * - The book which should be just after our given book:
+ * - If first is set, the next book must be in the same language group
+ * as the given book.
+ * - If first is NOT set, we don't care about language groups as we're
+ * iterating from the beginning of the list.
+ * - Both.
+ */
static void
-preferences_bookshelf_book_deleted_cb (DhBookManager *book_manager,
- GObject *book_object,
- gpointer user_data)
+preferences_bookshelf_find_book (DhBook *book,
+ const GtkTreeIter *first,
+ GtkTreeIter *exact_iter,
+ gboolean *exact_found,
+ GtkTreeIter *next_iter,
+ gboolean *next_found)
{
- 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;
+ GtkTreeIter loop_iter;
+
+ 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 (prefs->booklist_store), &loop_iter)) {
+ /* Store is empty, not found */
+ return;
+ }
+ } else {
+ loop_iter = *first;
}
- /* 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,
+ &loop_iter,
LTCOLUMN_BOOK, &in_list_book,
-1);
- if (in_list_book == book) {
- found = TRUE;
+
+ /* We may have reached the start of the next language group here */
+ if (first && !in_list_book) {
+ *next_iter = loop_iter;
+ *next_found = TRUE;
+ return;
+ }
+
+ /* We can compare pointers directly as we're playing with references
+ * of the same object */
+ if (exact_iter &&
+ in_list_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_list_book);
+ return;
+ }
+ } else if (next_iter &&
+ dh_book_cmp_by_title (in_list_book, book) > 0) {
+ *next_iter = loop_iter;
+ *next_found = TRUE;
+ g_object_unref (in_list_book);
+ return;
}
if (in_list_book)
g_object_unref (in_list_book);
- } while (!found &&
- gtk_tree_model_iter_next (GTK_TREE_MODEL (prefs->booklist_store), &iter));
+ } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (prefs->booklist_store),
+ &loop_iter));
+}
+
+static void
+preferences_bookshelf_add_book_to_store (DhBook *book,
+ gboolean group_by_language)
+{
+ GtkTreeIter book_iter;
+
+ /* If grouping by language we need to add the language categories */
+ if (group_by_language) {
+ gchar *indented_title;
+ GtkTreeIter language_iter;
+ gboolean language_iter_found;
+ GtkTreeIter next_language_iter;
+ gboolean next_language_iter_found;
+ gchar *language_title;
+ gboolean first_in_language = FALSE;
+
+ language_title = g_ascii_strup (dh_book_get_language (book), -1);
+
+ /* Look for the proper language group */
+ preferences_bookshelf_find_language_group (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_list_store_append (prefs->booklist_store,
+ &language_iter);
+ } else {
+ gtk_list_store_insert_before (prefs->booklist_store,
+ &language_iter,
+ &next_language_iter);
+ }
+
+ gtk_list_store_set (prefs->booklist_store,
+ &language_iter,
+ LTCOLUMN_ENABLED, dh_book_get_enabled (book),
+ LTCOLUMN_TITLE, language_title,
+ LTCOLUMN_BOOK, NULL,
+ LTCOLUMN_WEIGHT, PANGO_WEIGHT_BOLD,
+ LTCOLUMN_INCONSISTENT, FALSE,
+ -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_list_store_insert_after (prefs->booklist_store,
+ &book_iter,
+ &language_iter);
+ } else {
+ GtkTreeIter first_book_iter;
+ GtkTreeIter next_book_iter;
+ gboolean next_book_iter_found;
+ gboolean language_inconsistent = FALSE;
+ gboolean language_enabled = FALSE;
- /* If found, delete item from the store */
- if (found) {
- gtk_list_store_remove (prefs->booklist_store, &iter);
+ /* We may need to reset the inconsistent status of the language item */
+ gtk_tree_model_get (GTK_TREE_MODEL (prefs->booklist_store),
+ &language_iter,
+ LTCOLUMN_ENABLED, &language_enabled,
+ LTCOLUMN_INCONSISTENT, &language_inconsistent,
+ -1);
+ /* If inconsistent already, do nothing */
+ if (!language_inconsistent) {
+ if (language_enabled != dh_book_get_enabled (book)) {
+ gtk_list_store_set (prefs->booklist_store,
+ &language_iter,
+ LTCOLUMN_INCONSISTENT, TRUE,
+ -1);
+ }
+ }
+
+ /* The language will have at least one book, so we move iter to it */
+ first_book_iter = language_iter;
+ gtk_tree_model_iter_next (GTK_TREE_MODEL (prefs->booklist_store), &first_book_iter);
+
+ /* Find next possible book in language group */
+ preferences_bookshelf_find_book (book,
+ &first_book_iter,
+ NULL,
+ NULL,
+ &next_book_iter,
+ &next_book_iter_found);
+ if (!next_book_iter_found) {
+ gtk_list_store_append (prefs->booklist_store,
+ &book_iter);
+ } else {
+ gtk_list_store_insert_before (prefs->booklist_store,
+ &book_iter,
+ &next_book_iter);
+ }
+ }
+
+ /* Add new item with indented title */
+ indented_title = g_strdup_printf (" %s", dh_book_get_title (book));
+ gtk_list_store_set (prefs->booklist_store,
+ &book_iter,
+ LTCOLUMN_ENABLED, dh_book_get_enabled (book),
+ LTCOLUMN_TITLE, indented_title,
+ LTCOLUMN_BOOK, book,
+ LTCOLUMN_WEIGHT, PANGO_WEIGHT_NORMAL,
+ LTCOLUMN_INCONSISTENT, FALSE,
+ -1);
+ g_free (indented_title);
+ } else {
+ /* No language grouping, just order by book title */
+ GtkTreeIter next_book_iter;
+ gboolean next_book_iter_found;
+
+ preferences_bookshelf_find_book (book,
+ NULL,
+ NULL,
+ NULL,
+ &next_book_iter,
+ &next_book_iter_found);
+ if (!next_book_iter_found) {
+ gtk_list_store_append (prefs->booklist_store,
+ &book_iter);
+ } else {
+ gtk_list_store_insert_before (prefs->booklist_store,
+ &book_iter,
+ &next_book_iter);
+ }
+
+ gtk_list_store_set (prefs->booklist_store,
+ &book_iter,
+ LTCOLUMN_ENABLED, dh_book_get_enabled (book),
+ LTCOLUMN_TITLE, dh_book_get_title (book),
+ LTCOLUMN_BOOK, book,
+ LTCOLUMN_WEIGHT, PANGO_WEIGHT_NORMAL,
+ -1);
}
}
@@ -428,22 +783,16 @@ static void
preferences_bookshelf_populate_store (void)
{
GList *l;
+ gboolean group_by_language;
+
+ group_by_language = dh_book_manager_get_group_by_language (prefs->book_manager);
- /* This list already comes ordered */
+ /* This list already comes ordered, but we don't care */
for (l = dh_book_manager_get_books (prefs->book_manager);
l;
l = g_list_next (l)) {
- GtkTreeIter iter;
- DhBook *book;
-
- book = DH_BOOK (l->data);
-
- 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);
+ preferences_bookshelf_add_book_to_store (DH_BOOK (l->data),
+ group_by_language);
}
}
@@ -456,6 +805,12 @@ preferences_dialog_response (GtkDialog *dialog,
}
static void
+preferences_bookshelf_clean_store (void)
+{
+ gtk_list_store_clear (prefs->booklist_store);
+}
+
+static void
preferences_bookshelf_group_by_language_toggled_cb (GtkToggleButton *button,
gpointer user_data)
{
@@ -464,8 +819,10 @@ preferences_bookshelf_group_by_language_toggled_cb (GtkToggleButton *button,
active = gtk_toggle_button_get_active (button);
- dh_book_manager_set_group_by_language (prefs->book_manager,
- active);
+ if (dh_book_manager_get_group_by_language (prefs->book_manager) != active) {
+ dh_book_manager_set_group_by_language (prefs->book_manager,
+ active);
+ }
}
void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]