Patches: plain list store and show paths parameter
- From: José Dapena Paz <jdapena igalia com>
- To: tinymail-devel-list <tinymail-devel-list gnome org>
- Subject: Patches: plain list store and show paths parameter
- Date: Mon, 24 Nov 2008 10:00:12 +0100
Hi,
Following recommendations from Philip, I prepared two patches for plain
list store and full path view:
* First patch just adds the show path flag support in the gtk folder
store based on tree store.
* Second patch adds a parallel implementation of folder store based on
a GtkListStore, to implement the plain view.
Changelog for first patch (show full path in gtk folder store model
patch):
* libtinymailui-gtk/tny-gtk-folder-store-tree-model.[ch]:
Added support for settings construction flags. Also added a flag
"show path" for the tree model, that makes it store the full path
name.
Changelog for the second patch (gtk foldest list store patch):
* Added new TnyGtkFolderListStore, implementing a plain model (no tree)
for the folder store.
--
José Dapena Paz <jdapena igalia com>
Igalia
Index: libtinymailui-gtk/Makefile.am
===================================================================
--- libtinymailui-gtk/Makefile.am (revisión: 3824)
+++ libtinymailui-gtk/Makefile.am (copia de trabajo)
@@ -20,6 +20,7 @@
tny-gtk-attachment-mime-part-view.h\
tny-gtk-header-list-model.h \
tny-gtk-account-list-model.h \
+ tny-gtk-folder-list-store.h \
tny-gtk-folder-store-tree-model.h \
tny-gtk-attach-list-model.h \
tny-gtk-text-buffer-stream.h \
@@ -37,6 +38,9 @@
tny-gtk-image-mime-part-view.c \
tny-gtk-attachment-mime-part-view.c \
tny-gtk-msg-window.c \
+ tny-gtk-folder-list-store.c \
+ tny-gtk-folder-list-store-iterator-priv.h \
+ tny-gtk-folder-list-store-iterator.c \
tny-gtk-folder-store-tree-model.c \
tny-gtk-folder-store-tree-model-iterator-priv.h \
tny-gtk-folder-store-tree-model-iterator.c \
Index: libtinymailui-gtk/tny-gtk-folder-list-store.c
===================================================================
--- libtinymailui-gtk/tny-gtk-folder-list-store.c (revisión: 0)
+++ libtinymailui-gtk/tny-gtk-folder-list-store.c (revisión: 0)
@@ -0,0 +1,1500 @@
+/* libtinymailui-gtk - The Tiny Mail UI library for Gtk+
+ * Copyright (C) 2006-2008 Philip Van Hoof <pvanhoof gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with self library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+/**
+ * TnyGtkFolderListStore:
+ *
+ * A #GtkTreeModel for #TnyFolderStore instances that'll become #TnyFolderStoreObserver
+ * and #TnyFolderObserver (in case the #TnyFolderStore instance is a #TnyFolder
+ * too) of each added #TnyFolderStore and each of its children en grandchildren
+ * (recursively).
+ *
+ * It's based on the implementation of #TnyGtkFolderListTreeModel, but it stores
+ * folders and accounts in a #GtkListStore, using a plain representation.
+ *
+ * It will detect changes in the instance's tree structure this way and it will
+ * adapt itself to a new situation automatically. It also contains columns that
+ * contain certain popular numbers (like the unread and the total counts of
+ * #TnyFolder instances).
+ *
+ * Note that a #TnyGtkFolderListStore is a #TnyList too. You can use the
+ * #TnyList API on instances of this type too.
+ *
+ * Note that you must make sure that you unreference #TnyFolderStore instances
+ * that you get out of the instance column of this type using the #GtkTreeModel
+ * API gtk_tree_model_get().
+ *
+ * free-function: g_object_unref
+ **/
+
+#include <config.h>
+#include <string.h>
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n-lib.h>
+
+#include <tny-list.h>
+#include <tny-iterator.h>
+#include <tny-folder.h>
+#include <tny-folder-store.h>
+#include <tny-simple-list.h>
+#include <tny-merge-folder.h>
+
+#include <tny-store-account.h>
+#include <tny-folder-store-change.h>
+#include <tny-folder-store-observer.h>
+#include <tny-folder-change.h>
+#include <tny-folder-observer.h>
+
+#include <tny-gtk-folder-list-store.h>
+
+#include "tny-gtk-folder-list-store-iterator-priv.h"
+
+#define PATH_SEPARATOR " "
+
+static GObjectClass *parent_class = NULL;
+
+typedef void (*listaddfunc) (GtkListStore *list_store, GtkTreeIter *iter);
+
+
+static void
+add_folder_observer_weak (TnyGtkFolderListStore *self, TnyFolder *folder)
+{
+ if (TNY_IS_FOLDER (folder)) {
+ tny_folder_add_observer (folder, TNY_FOLDER_OBSERVER (self));
+ self->fol_obs = g_list_prepend (self->fol_obs, folder);
+ }
+}
+
+static void
+add_folder_store_observer_weak (TnyGtkFolderListStore *self, TnyFolderStore *store)
+{
+ if (TNY_IS_FOLDER_STORE (store)) {
+ tny_folder_store_add_observer (store, TNY_FOLDER_STORE_OBSERVER (self));
+ self->store_obs = g_list_prepend (self->store_obs, store);
+ }
+}
+
+static void
+remove_folder_observer_weak (TnyGtkFolderListStore *self, TnyFolder *folder, gboolean final)
+{
+ if (TNY_IS_FOLDER (folder)) {
+ if (!final)
+ self->fol_obs = g_list_remove (self->fol_obs, folder);
+ tny_folder_remove_observer (folder, (TnyFolderObserver *) self);
+ }
+}
+
+static void
+remove_folder_store_observer_weak (TnyGtkFolderListStore *self, TnyFolderStore *store, gboolean final)
+{
+ if (TNY_IS_FOLDER_STORE (store)) {
+ if (!final)
+ self->store_obs = g_list_remove (self->store_obs, store);
+ tny_folder_store_remove_observer (store, (TnyFolderStoreObserver *) self);
+ }
+}
+
+static void
+recurse_folders_sync (TnyGtkFolderListStore *self,
+ TnyFolderStore *store,
+ const gchar *parent_name)
+{
+ TnyIterator *iter;
+ TnyList *folders = tny_simple_list_new ();
+
+ /* TODO add error checking and reporting here */
+ tny_folder_store_get_folders (store, folders, self->query, TRUE, NULL);
+ iter = tny_list_create_iterator (folders);
+
+ if (parent_name == NULL)
+ parent_name = "";
+
+ while (!tny_iterator_is_done (iter))
+ {
+ GtkTreeModel *mmodel = (GtkTreeModel *) self;
+ GtkListStore *model = GTK_LIST_STORE (self);
+ GObject *instance = G_OBJECT (tny_iterator_get_current (iter));
+ GtkTreeIter tree_iter;
+ TnyFolder *folder = NULL;
+ TnyFolderStore *folder_store = NULL;
+ GtkTreeIter miter;
+ gboolean found = FALSE;
+ GObject *mark_for_removal = NULL;
+
+ if (instance && (TNY_IS_FOLDER (instance) || TNY_IS_MERGE_FOLDER (instance)))
+ folder = TNY_FOLDER (instance);
+
+ if (instance && (TNY_IS_FOLDER_STORE (instance)))
+ folder_store = TNY_FOLDER_STORE (instance);
+
+ if (gtk_tree_model_get_iter_first (mmodel, &miter))
+ do
+ {
+ GObject *citem = NULL;
+ TnyIterator *niter = NULL;
+
+ gtk_tree_model_get (mmodel, &miter,
+ TNY_GTK_FOLDER_LIST_STORE_INSTANCE_COLUMN,
+ &citem, -1);
+
+ if (citem == instance)
+ {
+ found = TRUE;
+ if (citem)
+ g_object_unref (citem);
+ break;
+ }
+
+ /* We search whether this folder that we have in the
+ * model, still exists in the actual list. Because if
+ * not, it probably got removed remotely (and we need
+ * to get rid of it in the model now) */
+
+ niter = tny_list_create_iterator (folders);
+ while (!tny_iterator_is_done (niter))
+ {
+ TnyFolder *ifound = TNY_FOLDER (tny_iterator_get_current (niter));
+ if (citem == (GObject *) ifound) {
+ if (mark_for_removal)
+ g_object_unref (mark_for_removal);
+ mark_for_removal = g_object_ref (ifound);
+ }
+ g_object_unref (ifound);
+ tny_iterator_next (niter);
+ }
+ g_object_unref (niter);
+
+ if (citem)
+ g_object_unref (citem);
+
+ } while (gtk_tree_model_iter_next (mmodel, &miter));
+
+ /* It was not found, so let's start adding it to the model! */
+
+ if (!found)
+ {
+ gchar *name;
+ gtk_list_store_append (model, &tree_iter);
+
+ /* Making self both a folder-store as a folder observer
+ * of this folder. This way we'll get notified when
+ * both a removal and a creation happens. Also when a
+ * rename happens: that's a removal and a creation. */
+
+ if (folder)
+ {
+ /* This adds a reference count to folder too. When it gets removed, that
+ reference count is decreased automatically by the gtktreestore infra-
+ structure. */
+
+ add_folder_observer_weak (self, folder);
+
+ if (self->flags & TNY_GTK_FOLDER_LIST_STORE_FLAG_SHOW_PATH) {
+ if ((parent_name == NULL) || *parent_name == '\0') {
+ name = g_strdup (tny_folder_get_name (folder));
+ } else {
+ name = g_strconcat (parent_name,
+ PATH_SEPARATOR,
+ tny_folder_get_name (folder),
+ NULL);
+ }
+ } else {
+ name = g_strdup (tny_folder_get_name (folder));
+ }
+
+ gtk_list_store_set (model, &tree_iter,
+ TNY_GTK_FOLDER_LIST_STORE_NAME_COLUMN,
+ name,
+ TNY_GTK_FOLDER_LIST_STORE_UNREAD_COLUMN,
+ tny_folder_get_unread_count (TNY_FOLDER (folder)),
+ TNY_GTK_FOLDER_LIST_STORE_ALL_COLUMN,
+ tny_folder_get_all_count (TNY_FOLDER (folder)),
+ TNY_GTK_FOLDER_LIST_STORE_TYPE_COLUMN,
+ tny_folder_get_folder_type (TNY_FOLDER (folder)),
+ TNY_GTK_FOLDER_LIST_STORE_INSTANCE_COLUMN,
+ folder, -1);
+
+ } else {
+ name = g_strdup (tny_folder_get_name (folder));
+ }
+
+ /* it's a store by itself, so keep on recursing */
+ if (folder_store) {
+ add_folder_store_observer_weak (self, folder_store);
+ recurse_folders_sync (self, folder_store, name);
+ }
+
+ g_free (name);
+
+ /* We're a folder, we'll request a status, since we've
+ * set self to be a folder observers of folder, we'll
+ * receive the status update. This makes it possible to
+ * instantly get the unread and total counts, of course.
+ *
+ * Note that the initial value is read from the cache in
+ * case the account is set offline, in TnyCamelFolder.
+ * In case the account is online a STAT for POP or a
+ * STATUS for IMAP is asked during the poke-status impl.
+ *
+ * This means that no priv->folder must be loaded, no
+ * memory peak will happen, few data must be transmitted
+ * in case we're online. Which is perfect! */
+
+ if (folder)
+ tny_folder_poke_status (TNY_FOLDER (folder));
+
+ if (mark_for_removal) {
+ g_object_unref (mark_for_removal);
+ mark_for_removal = NULL;
+ }
+
+ } else {
+ if (mark_for_removal) {
+ g_object_unref (mark_for_removal);
+ mark_for_removal = NULL;
+ }
+ }
+
+ g_object_unref (instance);
+
+ tny_iterator_next (iter);
+ }
+
+ g_object_unref (iter);
+ g_object_unref (folders);
+}
+
+
+static const gchar*
+get_root_name (TnyFolderStore *folder_store)
+{
+ const gchar *root_name;
+ if (TNY_IS_ACCOUNT (folder_store))
+ root_name = tny_account_get_name (TNY_ACCOUNT (folder_store));
+ else
+ root_name = _("Folder bag");
+ return root_name;
+}
+
+
+static void
+get_folders_cb (TnyFolderStore *fstore, gboolean cancelled, TnyList *list, GError *err, gpointer user_data)
+{
+ TnyGtkFolderListStore *self = (TnyGtkFolderListStore *) user_data;
+ GtkTreeModel *model = GTK_TREE_MODEL (self);
+ GtkTreeIter iter;
+ GtkTreeIter name_iter;
+ gboolean found = FALSE;
+
+ g_object_unref (list);
+
+ /* Note that the very first time, this code will pull all folder info.
+ * Note that when it runs, you'll see LIST commands happen on the IMAP
+ * socket. Especially the first time. You'll also see STATUS commands
+ * happen. This is, indeed, normal behaviour when this component is used.*/
+
+ /* But first, let's find-back that damn account so that we have the
+ * actual iter behind it in the model. */
+
+ if (gtk_tree_model_get_iter_first (model, &iter))
+ do
+ {
+ GObject *citem;
+
+ gtk_tree_model_get (model, &iter,
+ TNY_GTK_FOLDER_LIST_STORE_INSTANCE_COLUMN,
+ &citem, -1);
+
+ if (citem == (GObject *) fstore)
+ {
+ name_iter = iter;
+ found = TRUE;
+ if (citem)
+ g_object_unref (citem);
+ break;
+ }
+
+ g_object_unref (citem);
+
+ } while (gtk_tree_model_iter_next (model, &iter));
+
+ /* We found it, so we'll now just recursively start asking for all its
+ * folders and subfolders. The recurse_folders_sync can indeed cope with
+ * folders that already exist (it wont add them a second time). */
+
+ if (found)
+ recurse_folders_sync (self, fstore, NULL);
+
+ g_object_unref (self);
+
+ return;
+}
+
+static void
+tny_gtk_folder_list_store_on_constatus_changed (TnyAccount *account, TnyConnectionStatus status, TnyGtkFolderListStore *self)
+{
+ TnyList *list = NULL;
+
+ if (!self || !TNY_IS_GTK_FOLDER_LIST_STORE (self))
+ return;
+
+ /* This callback handler deals with connection status changes. In case
+ * we got connected, we can expect that, at least sometimes, new folders
+ * might have arrived. We'll need to scan for those, so we'll recursively
+ * start asking the account about its folders. */
+
+ if (status == TNY_CONNECTION_STATUS_RECONNECTING || status == TNY_CONNECTION_STATUS_DISCONNECTED)
+ return;
+
+ list = tny_simple_list_new ();
+ tny_folder_store_get_folders_async (TNY_FOLDER_STORE (account),
+ list, self->query, TRUE, get_folders_cb, NULL, g_object_ref (self));
+
+ return;
+}
+
+
+
+static void
+tny_gtk_folder_list_store_on_changed (TnyAccount *account, TnyGtkFolderListStore *self)
+{
+ GtkTreeModel *model = GTK_TREE_MODEL (self);
+ GtkTreeIter iter;
+ GtkTreeIter name_iter;
+ gboolean found = FALSE;
+
+ if (gtk_tree_model_get_iter_first (model, &iter))
+ do
+ {
+ GObject *citem = NULL;
+
+ gtk_tree_model_get (model, &iter,
+ TNY_GTK_FOLDER_LIST_STORE_INSTANCE_COLUMN,
+ &citem, -1);
+
+ if (citem == (GObject *) account)
+ {
+ name_iter = iter;
+ found = TRUE;
+ if (citem)
+ g_object_unref (citem);
+ break;
+ }
+
+ if (citem)
+ g_object_unref (citem);
+
+ } while (gtk_tree_model_iter_next (model, &iter));
+
+ if (found) {
+ gtk_list_store_set (GTK_LIST_STORE (model), &name_iter,
+ TNY_GTK_FOLDER_LIST_STORE_NAME_COLUMN,
+ get_root_name (TNY_FOLDER_STORE (account)), -1);
+ }
+}
+
+typedef struct
+{
+ GObject *instance;
+ guint handler_id;
+} SignalSlot;
+
+typedef struct
+{
+ TnyGtkFolderListStore *self;
+ TnyAccount *account;
+} AccNotYetReadyInfo;
+
+static void
+notify_signal_slots (gpointer user_data, GObject *instance)
+{
+ TnyGtkFolderListStore *self = (TnyGtkFolderListStore *) user_data;
+ int i=0;
+
+ for (i=0; i < self->signals->len; i++) {
+ SignalSlot *slot = (SignalSlot *) self->signals->pdata[i];
+ if (slot->instance == instance)
+ slot->instance = NULL;
+ }
+}
+
+static gboolean
+account_was_not_yet_ready_idle (gpointer user_data)
+{
+ AccNotYetReadyInfo *info = (AccNotYetReadyInfo *) user_data;
+ gboolean repeat = TRUE;
+
+ if (tny_account_is_ready (info->account))
+ {
+ SignalSlot *slot;
+
+ slot = g_slice_new (SignalSlot);
+ slot->instance = (GObject *) info->account;
+ slot->handler_id = g_signal_connect (info->account, "connection-status-changed",
+ G_CALLBACK (tny_gtk_folder_list_store_on_constatus_changed), info->self);
+ g_object_weak_ref (G_OBJECT (info->account), notify_signal_slots, info->self);
+ g_ptr_array_add (info->self->signals, slot);
+
+ slot = g_slice_new (SignalSlot);
+ slot->instance = (GObject *) info->account;
+ slot->handler_id = g_signal_connect (info->account, "changed",
+ G_CALLBACK (tny_gtk_folder_list_store_on_changed), info->self);
+ g_object_weak_ref (G_OBJECT (info->account), notify_signal_slots, info->self);
+ g_ptr_array_add (info->self->signals, slot);
+
+ tny_gtk_folder_list_store_on_constatus_changed (info->account,
+ tny_account_get_connection_status (info->account), info->self);
+
+ tny_gtk_folder_list_store_on_changed (info->account,
+ info->self);
+
+ repeat = FALSE;
+ }
+
+ return repeat;
+}
+
+static void
+account_was_not_yet_ready_destroy (gpointer user_data)
+{
+ AccNotYetReadyInfo *info = (AccNotYetReadyInfo *) user_data;
+
+ g_object_unref (info->account);
+ g_object_unref (info->self);
+
+ g_slice_free (AccNotYetReadyInfo, user_data);
+}
+
+
+static void
+tny_gtk_folder_list_store_add_i (TnyGtkFolderListStore *self, TnyFolderStore *folder_store, listaddfunc func, const gchar *root_name)
+{
+ GtkListStore *model = GTK_LIST_STORE (self);
+ TnyList *folders = tny_simple_list_new ();
+ GtkTreeIter name_iter;
+
+ func (model, &name_iter);
+
+ gtk_list_store_set (model, &name_iter,
+ TNY_GTK_FOLDER_LIST_STORE_NAME_COLUMN, root_name,
+ TNY_GTK_FOLDER_LIST_STORE_UNREAD_COLUMN, 0,
+ TNY_GTK_FOLDER_LIST_STORE_ALL_COLUMN, 0,
+ TNY_GTK_FOLDER_LIST_STORE_TYPE_COLUMN, TNY_FOLDER_TYPE_ROOT,
+ TNY_GTK_FOLDER_LIST_STORE_INSTANCE_COLUMN, folder_store,
+ -1);
+
+ /* In case we added a store account, it's possible that the account
+ * will have "the account just got connected" events happening. Accounts
+ * that just got connected might have new folders for us to know about.
+ * That's why we'll handle connection changes. */
+
+ if (TNY_IS_STORE_ACCOUNT (folder_store)) {
+ if (!tny_account_is_ready (TNY_ACCOUNT (folder_store)))
+ {
+ AccNotYetReadyInfo *info = g_slice_new (AccNotYetReadyInfo);
+
+ info->account = TNY_ACCOUNT (g_object_ref (folder_store));
+ info->self = TNY_GTK_FOLDER_LIST_STORE (g_object_ref (self));
+
+ g_timeout_add_full (G_PRIORITY_HIGH, 100,
+ account_was_not_yet_ready_idle,
+ info, account_was_not_yet_ready_destroy);
+
+ } else {
+ SignalSlot *slot;
+
+ slot = g_slice_new (SignalSlot);
+
+ slot->instance = (GObject *)folder_store;
+ slot->handler_id = g_signal_connect (folder_store, "connection-status-changed",
+ G_CALLBACK (tny_gtk_folder_list_store_on_constatus_changed), self);
+ g_object_weak_ref (G_OBJECT (folder_store), notify_signal_slots, self);
+ g_ptr_array_add (self->signals, slot);
+
+ slot = g_slice_new (SignalSlot);
+ slot->instance = (GObject *)folder_store;
+ slot->handler_id = g_signal_connect (folder_store, "changed",
+ G_CALLBACK (tny_gtk_folder_list_store_on_changed), self);
+ g_object_weak_ref (G_OBJECT (folder_store), notify_signal_slots, self);
+ g_ptr_array_add (self->signals, slot);
+ }
+ }
+
+ /* Being online at startup is being punished by this: it'll have to
+ * wait for the connection operation to finish before this queued item
+ * will get its turn. TNY TODO: figure out how we can avoid this and
+ * already return the offline folders (if we had those from a session
+ * before this one) */
+
+ tny_folder_store_get_folders_async (TNY_FOLDER_STORE (folder_store),
+ folders, self->query, TRUE, get_folders_cb, NULL, g_object_ref (self));
+
+ /* Add an observer for the root folder store, so that we can observe
+ * the actual account too. */
+
+ add_folder_store_observer_weak (self, folder_store);
+
+ /* g_object_unref (G_OBJECT (folders)); */
+
+ return;
+}
+
+
+/**
+ * tny_gtk_folder_list_store_new:
+ * @query: the #TnyFolderStoreQuery that will be used to retrieve the child folders of each #TnyFolderStore
+ *
+ * Create a new #GtkTreeModel for showing #TnyFolderStore instances, with default flags
+ *
+ * returns: (caller-owns): a new #GtkTreeModel for #TnyFolderStore instances
+ * since: 1.0
+ * audience: application-developer
+ **/
+GtkTreeModel*
+tny_gtk_folder_list_store_new (TnyFolderStoreQuery *query)
+{
+ return tny_gtk_folder_list_store_new_with_flags (query, 0);
+}
+
+/**
+ * tny_gtk_folder_list_store_new:
+ * @query: the #TnyFolderStoreQuery that will be used to retrieve the child folders of each #TnyFolderStore
+ * @flags: #TnyGtkFolderListStoreFlags for setting the store
+ *
+ * Create a new #GtkTreeModel for showing #TnyFolderStore instances
+ *
+ * returns: (caller-owns): a new #GtkTreeModel for #TnyFolderStore instances
+ * since: 1.0
+ * audience: application-developer
+ **/
+GtkTreeModel*
+tny_gtk_folder_list_store_new_with_flags (TnyFolderStoreQuery *query,
+ TnyGtkFolderListStoreFlags flags)
+{
+ TnyGtkFolderListStore *self = g_object_new (TNY_TYPE_GTK_FOLDER_LIST_STORE, NULL);
+
+ if (query)
+ self->query = g_object_ref (query);
+
+ self->flags = flags;
+
+ return GTK_TREE_MODEL (self);
+}
+
+
+
+static void
+tny_gtk_folder_list_store_finalize (GObject *object)
+{
+ TnyGtkFolderListStore *me = (TnyGtkFolderListStore*) object;
+ int i = 0;
+
+ for (i = 0; i < me->signals->len; i++) {
+ SignalSlot *slot = (SignalSlot *) me->signals->pdata [i];
+ if (slot->instance) {
+ g_signal_handler_disconnect (slot->instance, slot->handler_id);
+ g_object_weak_unref (G_OBJECT (slot->instance), notify_signal_slots, object);
+ }
+ g_slice_free (SignalSlot, slot);
+ }
+
+ g_ptr_array_free (me->signals, TRUE);
+ me->signals = NULL;
+
+ if (me->fol_obs)
+ g_list_free (me->fol_obs);
+ me->fol_obs = NULL;
+
+ if (me->store_obs)
+ g_list_free (me->store_obs);
+ me->store_obs = NULL;
+
+ g_mutex_lock (me->iterator_lock);
+ if (me->first) {
+ if (me->first_needs_unref)
+ g_list_foreach (me->first, (GFunc)g_object_unref, NULL);
+ me->first_needs_unref = FALSE;
+ g_list_free (me->first);
+ }
+ me->first = NULL;
+ g_mutex_unlock (me->iterator_lock);
+
+
+ g_mutex_free (me->iterator_lock);
+ me->iterator_lock = NULL;
+
+ if (me->query)
+ g_object_unref (me->query);
+
+ (*parent_class->finalize) (object);
+}
+
+static void
+tny_gtk_folder_list_store_class_init (TnyGtkFolderListStoreClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ object_class = (GObjectClass*) class;
+
+ object_class->finalize = tny_gtk_folder_list_store_finalize;
+
+ return;
+}
+
+static void
+tny_gtk_folder_list_store_instance_init (GTypeInstance *instance, gpointer g_class)
+{
+ GtkListStore *store = (GtkListStore*) instance;
+ TnyGtkFolderListStore *me = (TnyGtkFolderListStore*) instance;
+ static GType types[] = { G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INT, G_TYPE_OBJECT };
+
+ me->signals = g_ptr_array_new ();
+ me->fol_obs = NULL;
+ me->store_obs = NULL;
+ me->iterator_lock = g_mutex_new ();
+ me->first_needs_unref = FALSE;
+
+ me->flags = 0;
+
+ gtk_list_store_set_column_types (store,
+ TNY_GTK_FOLDER_LIST_STORE_N_COLUMNS, types);
+
+ return;
+}
+
+
+
+static TnyIterator*
+tny_gtk_folder_list_store_create_iterator (TnyList *self)
+{
+ TnyGtkFolderListStore *me = (TnyGtkFolderListStore*)self;
+
+ /* Return a new iterator */
+
+ return TNY_ITERATOR (_tny_gtk_folder_list_store_iterator_new (me));
+}
+
+
+/**
+ * tny_gtk_folder_list_store_prepend:
+ * @self: a #TnyGtkFolderListStore
+ * @item: a #TnyFolderStore to add
+ * @root_name: The node's root name
+ *
+ * Prepends an item to the model
+ *
+ * since: 1.0
+ * audience: application-developer
+ **/
+void
+tny_gtk_folder_list_store_prepend (TnyGtkFolderListStore *self, TnyFolderStore* item, const gchar *root_name)
+{
+ TnyGtkFolderListStore *me = (TnyGtkFolderListStore*)self;
+
+ g_mutex_lock (me->iterator_lock);
+
+ /* Prepend something to the list */
+ me->first = g_list_prepend (me->first, item);
+
+ tny_gtk_folder_list_store_add_i (me, TNY_FOLDER_STORE (item),
+ gtk_list_store_prepend, root_name);
+
+ g_mutex_unlock (me->iterator_lock);
+}
+
+
+static void
+tny_gtk_folder_list_store_prepend_i (TnyList *self, GObject* item)
+{
+ TnyGtkFolderListStore *me = (TnyGtkFolderListStore*)self;
+
+ g_mutex_lock (me->iterator_lock);
+
+ /* Prepend something to the list */
+ me->first = g_list_prepend (me->first, item);
+
+ tny_gtk_folder_list_store_add_i (me, TNY_FOLDER_STORE (item),
+ gtk_list_store_prepend, get_root_name (TNY_FOLDER_STORE (item)));
+
+ g_mutex_unlock (me->iterator_lock);
+}
+
+/**
+ * tny_gtk_folder_list_store_append:
+ * @self: a #TnyGtkFolderListStore
+ * @item: a #TnyFolderStore to add
+ * @root_name: The node's root name
+ *
+ * Appends an item to the model
+ *
+ * since: 1.0
+ * audience: application-developer
+ **/
+void
+tny_gtk_folder_list_store_append (TnyGtkFolderListStore *self, TnyFolderStore* item, const gchar *root_name)
+{
+ TnyGtkFolderListStore *me = (TnyGtkFolderListStore*)self;
+
+ g_mutex_lock (me->iterator_lock);
+
+ /* Append something to the list */
+ me->first = g_list_append (me->first, item);
+
+ tny_gtk_folder_list_store_add_i (me, TNY_FOLDER_STORE (item),
+ gtk_list_store_append, root_name);
+
+ g_mutex_unlock (me->iterator_lock);
+}
+
+static void
+tny_gtk_folder_list_store_append_i (TnyList *self, GObject* item)
+{
+ TnyGtkFolderListStore *me = (TnyGtkFolderListStore*)self;
+
+ g_mutex_lock (me->iterator_lock);
+
+ /* Append something to the list */
+ me->first = g_list_append (me->first, item);
+
+ tny_gtk_folder_list_store_add_i (me, TNY_FOLDER_STORE (item),
+ gtk_list_store_append, get_root_name (TNY_FOLDER_STORE (item)));
+
+ g_mutex_unlock (me->iterator_lock);
+}
+
+static guint
+tny_gtk_folder_list_store_get_length (TnyList *self)
+{
+ TnyGtkFolderListStore *me = (TnyGtkFolderListStore*)self;
+ guint retval = 0;
+
+ g_mutex_lock (me->iterator_lock);
+
+ retval = me->first?g_list_length (me->first):0;
+
+ g_mutex_unlock (me->iterator_lock);
+
+ return retval;
+}
+
+static void
+tny_gtk_folder_list_store_remove (TnyList *self, GObject* item)
+{
+ TnyGtkFolderListStore *me = (TnyGtkFolderListStore*)self;
+ GtkTreeModel *model = GTK_TREE_MODEL (me);
+ GtkTreeIter iter;
+
+ g_return_if_fail (G_IS_OBJECT (item));
+ g_return_if_fail (G_IS_OBJECT (me));
+
+ /* Remove something from the list */
+
+ g_mutex_lock (me->iterator_lock);
+
+ me->first = g_list_remove (me->first, (gconstpointer)item);
+
+ /* This doesn't have to be recursive as only the first-level folders are
+ actually really part of the list. */
+
+ if (gtk_tree_model_get_iter_first (model, &iter))
+ do
+ {
+ GObject *citem = NULL;
+ gtk_tree_model_get (model, &iter,
+ TNY_GTK_FOLDER_LIST_STORE_INSTANCE_COLUMN,
+ &citem, -1);
+ if (citem == item)
+ {
+ /* This removes a reference count */
+ gtk_list_store_remove (GTK_LIST_STORE (me), &iter);
+ if (citem)
+ g_object_unref (citem);
+ break;
+ }
+ if (citem)
+ g_object_unref (citem);
+
+ } while (gtk_tree_model_iter_next (model, &iter));
+
+ g_mutex_unlock (me->iterator_lock);
+}
+
+
+static TnyList*
+tny_gtk_folder_list_store_copy_the_list (TnyList *self)
+{
+ TnyGtkFolderListStore *me = (TnyGtkFolderListStore*)self;
+ TnyGtkFolderListStore *copy = g_object_new (TNY_TYPE_GTK_FOLDER_LIST_STORE, NULL);
+ GList *list_copy = NULL;
+
+ /* This only copies the TnyList pieces. The result is not a correct or good
+ TnyHeaderListModel. But it will be a correct TnyList instance. It's the
+ only thing the user of this method expects (that is the contract of it).
+
+ The new list will point to the same instances, of course. It's only a
+ copy of the list-nodes of course. */
+
+ g_mutex_lock (me->iterator_lock);
+ list_copy = g_list_copy (me->first);
+ g_list_foreach (list_copy, (GFunc)g_object_ref, NULL);
+ copy->first_needs_unref = TRUE;
+ copy->first = list_copy;
+ g_mutex_unlock (me->iterator_lock);
+
+ return TNY_LIST (copy);
+}
+
+static void
+tny_gtk_folder_list_store_foreach_in_the_list (TnyList *self, GFunc func, gpointer user_data)
+{
+ TnyGtkFolderListStore *me = (TnyGtkFolderListStore*)self;
+
+ /* Foreach item in the list (without using a slower iterator) */
+
+ g_mutex_lock (me->iterator_lock);
+ g_list_foreach (me->first, func, user_data);
+ g_mutex_unlock (me->iterator_lock);
+
+ return;
+}
+
+typedef struct _FindParentHelperInfo {
+ GtkTreeIter *iter;
+ TnyFolder *folder;
+ TnyAccount *account;
+ gboolean found;
+} FindParentHelperInfo;
+
+static gboolean
+find_parent_helper (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer userdata)
+{
+ TnyFolderStore *folder_store;
+ FindParentHelperInfo *helper_info = (FindParentHelperInfo *) userdata;
+ TnyList *children;
+ TnyIterator *iterator;
+
+ gtk_tree_model_get (model, iter,
+ TNY_GTK_FOLDER_LIST_STORE_INSTANCE_COLUMN,
+ &folder_store, -1);
+
+ /* Only search on same account */
+ if (TNY_IS_ACCOUNT (folder_store) && ((TnyAccount *)folder_store == helper_info->account))
+ return FALSE;
+
+ if (TNY_IS_FOLDER (folder_store)) {
+ TnyAccount *account = NULL;
+ account = tny_folder_get_account (TNY_FOLDER (folder_store));
+ g_object_unref (account);
+ if (account == helper_info->account)
+ return FALSE;
+ }
+
+ children = TNY_LIST (tny_simple_list_new ());
+ tny_folder_store_get_folders (folder_store, children, NULL, FALSE, NULL);
+ iterator = tny_list_create_iterator (children);
+
+ while (!tny_iterator_is_done (iterator)) {
+ TnyFolderStore *child;
+
+ child = (TnyFolderStore *) tny_iterator_get_current (iterator);
+ g_object_unref (child);
+ if (child == (TnyFolderStore *) helper_info->folder) {
+ helper_info->found = TRUE;
+ *helper_info->iter = *iter;
+ break;
+ }
+ tny_iterator_next (iterator);
+ }
+ g_object_unref (iterator);
+ g_object_unref (children);
+
+ return helper_info->found;
+
+}
+
+static gboolean
+find_parent (GtkTreeModel *model, TnyFolder *folder, GtkTreeIter *iter)
+{
+ FindParentHelperInfo *helper_info;
+ gboolean result;
+
+ helper_info = g_slice_new0 (FindParentHelperInfo);
+
+ helper_info->folder = folder;
+ helper_info->iter = iter;
+ helper_info->account = tny_folder_get_account (folder);
+
+ gtk_tree_model_foreach (model, find_parent_helper, helper_info);
+
+ g_object_unref (helper_info->account);
+ result = helper_info->found;
+ g_slice_free (FindParentHelperInfo, helper_info);
+
+ return result;
+}
+
+typedef struct _FindHelperInfo {
+ GtkTreeIter *iter;
+ TnyFolder *folder;
+ gboolean found;
+} FindHelperInfo;
+
+static gboolean
+find_node_helper (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer userdata)
+{
+ TnyFolderStore *folder_store;
+ FindHelperInfo *helper_info = (FindHelperInfo *) userdata;
+
+ gtk_tree_model_get (model, iter,
+ TNY_GTK_FOLDER_LIST_STORE_INSTANCE_COLUMN,
+ &folder_store, -1);
+
+ if ((TnyFolderStore *) helper_info->folder == folder_store) {
+ helper_info->found = TRUE;
+ *helper_info->iter = *iter;
+ }
+
+ return helper_info->found;
+
+}
+
+static gboolean
+find_node (GtkTreeModel *model, TnyFolder *folder, GtkTreeIter *iter)
+{
+ FindHelperInfo *helper_info;
+ gboolean result;
+
+ helper_info = g_slice_new0 (FindHelperInfo);
+
+ helper_info->folder = folder;
+ helper_info->iter = iter;
+
+ gtk_tree_model_foreach (model, find_node_helper, helper_info);
+
+ result = helper_info->found;
+ g_slice_free (FindHelperInfo, helper_info);
+
+ return result;
+}
+
+static void
+update_children_names (GtkTreeModel *model, TnyFolder *folder, const gchar *name)
+{
+ TnyList *children;
+ TnyIterator *iterator;
+
+ children = TNY_LIST (tny_simple_list_new ());
+ iterator = tny_list_create_iterator (children);
+
+ while (!tny_iterator_is_done (iterator)) {
+ GtkTreeIter iter;
+ TnyFolder *child;
+
+ child = TNY_FOLDER (tny_iterator_get_current (iterator));
+ if (find_node (model, child, &iter)) {
+ gchar *new_name;
+ new_name = g_strconcat (name, PATH_SEPARATOR,
+ tny_folder_get_name (TNY_FOLDER (child)),
+ NULL);
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+ TNY_GTK_FOLDER_LIST_STORE_NAME_COLUMN,
+ new_name,
+ -1);
+ update_children_names (model, child, new_name);
+ g_free (new_name);
+ }
+
+ g_object_unref (folder);
+ tny_iterator_next (iterator);
+ }
+
+ g_object_unref (iterator);
+ g_object_unref (children);
+}
+
+
+static gboolean
+updater (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data1)
+{
+ TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
+ TnyFolderChange *change = user_data1;
+ TnyFolder *changed_folder = tny_folder_change_get_folder (change);
+ TnyFolderChangeChanged changed = tny_folder_change_get_changed (change);
+
+ /* This updater will get the folder out of the model, compare with
+ * the changed_folder pointer, and if there's a match it will update
+ * the values of the model with the values from the folder. */
+
+/*
+ For your debugging advertures:
+
+ print ((TnyCamelFolderPriv *) g_type_instance_get_private \
+ (tny_iterator_get_current (tny_list_create_iterator \
+ (((TnyMergeFolderPriv *) g_type_instance_get_private \
+ (folder, tny_merge_folder_get_type()))->mothers)), \
+ tny_camel_folder_get_type()))->folder->summary->messages->len
+
+ print * (CamelLocalFolder *) ((TnyCamelFolderPriv *) \
+ g_type_instance_get_private (tny_iterator_get_current \
+ (tny_list_create_iterator (((TnyMergeFolderPriv *) \
+ g_type_instance_get_private (folder, \
+ tny_merge_folder_get_type()))->mothers)), \
+ tny_camel_folder_get_type()))->folder
+
+*/
+
+
+ gtk_tree_model_get (model, iter,
+ TNY_GTK_FOLDER_LIST_STORE_TYPE_COLUMN,
+ &type, -1);
+
+ if (type != TNY_FOLDER_TYPE_ROOT)
+ {
+ TnyFolder *folder;
+ gint unread, total;
+
+ gtk_tree_model_get (model, iter,
+ TNY_GTK_FOLDER_LIST_STORE_INSTANCE_COLUMN,
+ &folder, -1);
+
+ if (changed & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
+ total = tny_folder_change_get_new_all_count (change);
+ else
+ total = tny_folder_get_all_count (folder);
+
+ if (changed & TNY_FOLDER_CHANGE_CHANGED_UNREAD_COUNT)
+ unread = tny_folder_change_get_new_unread_count (change);
+ else
+ unread = tny_folder_get_unread_count (folder);
+
+ if (folder == changed_folder)
+ {
+ /* TNY TODO: This is not enough: Subfolders will be incorrect because the
+ the full_name of the subfolders will still be the old full_name!*/
+
+ gtk_list_store_set (GTK_LIST_STORE (model), iter,
+ TNY_GTK_FOLDER_LIST_STORE_UNREAD_COLUMN,
+ unread,
+ TNY_GTK_FOLDER_LIST_STORE_ALL_COLUMN,
+ total, -1);
+
+ if (changed & TNY_FOLDER_CHANGE_CHANGED_FOLDER_RENAME) {
+ GtkTreeIter parent_iter;
+ gchar *name = NULL;
+
+ if (TNY_GTK_FOLDER_LIST_STORE (model)->flags &
+ TNY_GTK_FOLDER_LIST_STORE_FLAG_SHOW_PATH) {
+ if (find_parent (model, folder, &parent_iter)) {
+ gchar *parent_name;
+ gtk_tree_model_get (model, &parent_iter,
+ TNY_GTK_FOLDER_LIST_STORE_NAME_COLUMN,
+ &parent_name, -1);
+ if (parent_name && parent_name[0] == '\0')
+ name = g_strconcat (parent_name, PATH_SEPARATOR,
+ tny_folder_get_name (TNY_FOLDER (folder)),
+ NULL);
+ g_free (parent_name);
+
+
+ }
+ }
+
+
+ if (name == NULL)
+ name = g_strdup (tny_folder_get_name (TNY_FOLDER (folder)));
+
+ gtk_list_store_set (GTK_LIST_STORE (model), iter,
+ TNY_GTK_FOLDER_LIST_STORE_NAME_COLUMN,
+ name,
+ -1);
+ if (TNY_GTK_FOLDER_LIST_STORE (model)->flags &
+ TNY_GTK_FOLDER_LIST_STORE_FLAG_SHOW_PATH) {
+ update_children_names (model, folder, name);
+ }
+ g_free (name);
+ }
+ }
+
+ g_object_unref (folder);
+ }
+
+ g_object_unref (changed_folder);
+
+ return FALSE;
+}
+
+static gboolean
+deleter (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data1)
+{
+ gboolean retval = FALSE;
+ TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
+ GObject *folder = user_data1;
+ TnyGtkFolderListStore *me = (TnyGtkFolderListStore*) model;
+
+ /* The deleter will compare all folders in the model with the deleted
+ * folder @folder, and if there's a match it will delete the folder's
+ * row from the model. */
+
+ gtk_tree_model_get (model, iter,
+ TNY_GTK_FOLDER_LIST_STORE_TYPE_COLUMN,
+ &type, -1);
+
+ if (type != TNY_FOLDER_TYPE_ROOT)
+ {
+ GObject *fol = NULL;
+
+ gtk_tree_model_get (model, iter,
+ TNY_GTK_FOLDER_LIST_STORE_INSTANCE_COLUMN,
+ &fol, -1);
+
+ if (fol == folder) {
+
+ remove_folder_observer_weak (me, TNY_FOLDER (folder), FALSE);
+ remove_folder_store_observer_weak (me, TNY_FOLDER_STORE (folder), FALSE);
+
+ gtk_list_store_remove (GTK_LIST_STORE (model), iter);
+ retval = TRUE;
+ }
+
+ if (fol)
+ g_object_unref (fol);
+ }
+
+ return retval;
+}
+
+static gboolean
+creater (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *in_iter, gpointer user_data)
+{
+ TnyGtkFolderListStore *self = (TnyGtkFolderListStore*) model;
+ TnyFolderStore *fol = NULL;
+ gboolean found = FALSE;
+ const gchar *mid = NULL, *sid = NULL;
+ TnyFolderStoreChange *change = (TnyFolderStoreChange *) user_data;
+ TnyFolderStore *parent_store;
+ GtkTreeIter iter;
+
+ /* This creater will get the store out of the model, compare with
+ * the change's store pointer, and if there's a match it will add the
+ * the created folders to the model at that location. */
+
+ if (!gtk_tree_model_get_iter (model, &iter, path)) {
+ g_warning ("Internal state of the TnyGtkFolderListStore is corrupted\n");
+ return FALSE;
+ }
+
+ parent_store = tny_folder_store_change_get_folder_store (change);
+ gtk_tree_model_get (model, &iter,
+ TNY_GTK_FOLDER_LIST_STORE_INSTANCE_COLUMN,
+ &fol, -1);
+
+ if (fol == parent_store)
+ found = TRUE;
+
+ if (!found) {
+ TnyAccount *maccount = NULL, *saccount = NULL;
+ const gchar *ma_id = NULL, *sa_id = NULL;
+
+ if (fol && TNY_IS_FOLDER (fol)) {
+ mid = tny_folder_get_id (TNY_FOLDER (fol));
+ if (!TNY_IS_MERGE_FOLDER (fol))
+ maccount = tny_folder_get_account (TNY_FOLDER (fol));
+ if (maccount)
+ ma_id = tny_account_get_id (maccount);
+ }
+ if (parent_store && TNY_IS_FOLDER (parent_store)) {
+ sid = tny_folder_get_id (TNY_FOLDER (parent_store));
+ if (!TNY_IS_MERGE_FOLDER (parent_store))
+ saccount = tny_folder_get_account (TNY_FOLDER (parent_store));
+ if (saccount)
+ sa_id = tny_account_get_id (saccount);
+ }
+ if (sid && mid && !strcmp (sid, mid)) {
+ if (ma_id && sa_id) {
+ if (!strcmp (ma_id, sa_id))
+ found = TRUE;
+ } else {
+ found = TRUE;
+ }
+ }
+ if (maccount)
+ g_object_unref (maccount);
+ if (saccount)
+ g_object_unref (saccount);
+ }
+
+ if (found)
+ {
+ TnyList *created = tny_simple_list_new ();
+ TnyIterator *miter;
+ gchar *parent_name;
+
+ tny_folder_store_change_get_created_folders (change, created);
+ miter = tny_list_create_iterator (created);
+
+ /* We assume parent name is already the expected one in full path style */
+ gtk_tree_model_get (model, in_iter,
+ TNY_GTK_FOLDER_LIST_STORE_NAME_COLUMN, &parent_name,
+ -1);
+
+ while (!tny_iterator_is_done (miter))
+ {
+ GtkTreeIter newiter;
+ TnyFolder *folder = TNY_FOLDER (tny_iterator_get_current (miter));
+ gchar *finalname;
+
+ add_folder_observer_weak (self, folder);
+ add_folder_store_observer_weak (self, TNY_FOLDER_STORE (folder));
+
+ /* This adds a reference count to folder_store too. When it gets
+ removed, that reference count is decreased automatically by
+ the gtktreestore infrastructure. */
+
+ if (TNY_GTK_FOLDER_LIST_STORE (self)->flags &
+ TNY_GTK_FOLDER_LIST_STORE_FLAG_SHOW_PATH) {
+ if (parent_name && *parent_name != '\0')
+ finalname = g_strconcat (parent_name, PATH_SEPARATOR,
+ tny_folder_get_name (TNY_FOLDER (folder)), NULL);
+ else
+ finalname = g_strdup (tny_folder_get_name (TNY_FOLDER (folder)));
+ } else {
+ finalname = g_strdup (tny_folder_get_name (TNY_FOLDER (folder)));
+ }
+
+ gtk_list_store_prepend (GTK_LIST_STORE (model), &newiter);
+
+ gtk_list_store_set (GTK_LIST_STORE (model), &newiter,
+ TNY_GTK_FOLDER_LIST_STORE_NAME_COLUMN,
+ finalname,
+ TNY_GTK_FOLDER_LIST_STORE_UNREAD_COLUMN,
+ tny_folder_get_unread_count (TNY_FOLDER (folder)),
+ TNY_GTK_FOLDER_LIST_STORE_ALL_COLUMN,
+ tny_folder_get_all_count (TNY_FOLDER (folder)),
+ TNY_GTK_FOLDER_LIST_STORE_TYPE_COLUMN,
+ tny_folder_get_folder_type (TNY_FOLDER (folder)),
+ TNY_GTK_FOLDER_LIST_STORE_INSTANCE_COLUMN,
+ folder, -1);
+ g_free (finalname);
+
+ g_object_unref (folder);
+ tny_iterator_next (miter);
+ }
+ g_free (parent_name);
+ g_object_unref (miter);
+ g_object_unref (created);
+ }
+
+ if (fol)
+ g_object_unref (fol);
+
+ if (parent_store)
+ g_object_unref (parent_store);
+
+ return found;
+}
+
+
+
+static void
+tny_gtk_folder_list_store_folder_obsr_update (TnyFolderObserver *self, TnyFolderChange *change)
+{
+ TnyFolderChangeChanged changed = tny_folder_change_get_changed (change);
+ GtkTreeModel *model = (GtkTreeModel *) self;
+
+ if (changed & TNY_FOLDER_CHANGE_CHANGED_FOLDER_RENAME ||
+ changed & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT ||
+ changed & TNY_FOLDER_CHANGE_CHANGED_UNREAD_COUNT)
+ {
+ gtk_tree_model_foreach (model, updater, change);
+ }
+
+ return;
+}
+
+static void
+delete_these_folders (GtkTreeModel *model, TnyList *list)
+{
+ TnyIterator *miter;
+ miter = tny_list_create_iterator (list);
+ while (!tny_iterator_is_done (miter))
+ {
+ TnyFolder *folder = TNY_FOLDER (tny_iterator_get_current (miter));
+ gtk_tree_model_foreach (model, deleter, folder);
+ g_object_unref (folder);
+ tny_iterator_next (miter);
+ }
+ g_object_unref (miter);
+}
+
+static void
+tny_gtk_folder_list_store_store_obsr_update (TnyFolderStoreObserver *self, TnyFolderStoreChange *change)
+{
+ TnyFolderStoreChangeChanged changed = tny_folder_store_change_get_changed (change);
+ GtkTreeModel *model = GTK_TREE_MODEL (self);
+
+ if (changed & TNY_FOLDER_STORE_CHANGE_CHANGED_CREATED_FOLDERS) {
+ /* TnyList *created = tny_simple_list_new ();
+ * tny_folder_store_change_get_created_folders (change, created);
+ * delete_these_folders (model, created);
+ * g_object_unref (created); */
+ gtk_tree_model_foreach (model, creater, change);
+ }
+
+ if (changed & TNY_FOLDER_STORE_CHANGE_CHANGED_REMOVED_FOLDERS)
+ {
+ TnyList *removed = tny_simple_list_new ();
+ tny_folder_store_change_get_removed_folders (change, removed);
+ delete_these_folders (model, removed);
+ g_object_unref (removed);
+ }
+
+ return;
+}
+
+static void
+tny_folder_store_observer_init (TnyFolderStoreObserverIface *klass)
+{
+ klass->update= tny_gtk_folder_list_store_store_obsr_update;
+}
+
+static void
+tny_folder_observer_init (TnyFolderObserverIface *klass)
+{
+ klass->update= tny_gtk_folder_list_store_folder_obsr_update;
+}
+
+static void
+tny_list_init (TnyListIface *klass)
+{
+ klass->get_length= tny_gtk_folder_list_store_get_length;
+ klass->prepend= tny_gtk_folder_list_store_prepend_i;
+ klass->append= tny_gtk_folder_list_store_append_i;
+ klass->remove= tny_gtk_folder_list_store_remove;
+ klass->create_iterator= tny_gtk_folder_list_store_create_iterator;
+ klass->copy= tny_gtk_folder_list_store_copy_the_list;
+ klass->foreach= tny_gtk_folder_list_store_foreach_in_the_list;
+
+ return;
+}
+
+static gpointer
+tny_gtk_folder_list_store_register_type (gpointer notused)
+{
+ GType type = 0;
+
+ static const GTypeInfo info =
+ {
+ sizeof (TnyGtkFolderListStoreClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) tny_gtk_folder_list_store_class_init, /* class_init */
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (TnyGtkFolderListStore),
+ 0, /* n_preallocs */
+ tny_gtk_folder_list_store_instance_init /* instance_init */
+ };
+
+ static const GInterfaceInfo tny_list_info = {
+ (GInterfaceInitFunc) tny_list_init,
+ NULL,
+ NULL
+ };
+
+ static const GInterfaceInfo tny_folder_store_observer_info = {
+ (GInterfaceInitFunc) tny_folder_store_observer_init,
+ NULL,
+ NULL
+ };
+
+ static const GInterfaceInfo tny_folder_observer_info = {
+ (GInterfaceInitFunc) tny_folder_observer_init,
+ NULL,
+ NULL
+ };
+
+ type = g_type_register_static (GTK_TYPE_LIST_STORE, "TnyGtkFolderListStore",
+ &info, 0);
+
+ g_type_add_interface_static (type, TNY_TYPE_LIST,
+ &tny_list_info);
+ g_type_add_interface_static (type, TNY_TYPE_FOLDER_STORE_OBSERVER,
+ &tny_folder_store_observer_info);
+ g_type_add_interface_static (type, TNY_TYPE_FOLDER_OBSERVER,
+ &tny_folder_observer_info);
+
+ return GUINT_TO_POINTER (type);
+}
+
+/**
+ * tny_gtk_folder_list_store_get_type:
+ *
+ * GType system helper function
+ *
+ * returns: a #GType
+ **/
+GType
+tny_gtk_folder_list_store_get_type (void)
+{
+ static GOnce once = G_ONCE_INIT;
+ g_once (&once, tny_gtk_folder_list_store_register_type, NULL);
+ return GPOINTER_TO_UINT (once.retval);
+}
+
+static gpointer
+tny_gtk_folder_list_store_column_register_type (gpointer notused)
+{
+ static GType etype = 0;
+ static const GEnumValue values[] = {
+ { TNY_GTK_FOLDER_LIST_STORE_NAME_COLUMN, "TNY_GTK_FOLDER_LIST_STORE_NAME_COLUMN", "name" },
+ { TNY_GTK_FOLDER_LIST_STORE_UNREAD_COLUMN, "TNY_GTK_FOLDER_LIST_STORE_UNREAD_COLUMN", "unread" },
+ { TNY_GTK_FOLDER_LIST_STORE_ALL_COLUMN, "TNY_GTK_FOLDER_LIST_STORE_ALL_COLUMN", "all" },
+ { TNY_GTK_FOLDER_LIST_STORE_TYPE_COLUMN, "TNY_GTK_FOLDER_LIST_STORE_TYPE_COLUMN", "type" },
+ { TNY_GTK_FOLDER_LIST_STORE_INSTANCE_COLUMN, "TNY_GTK_FOLDER_LIST_STORE_INSTANCE_COLUMN", "instance" },
+ { TNY_GTK_FOLDER_LIST_STORE_N_COLUMNS, "TNY_GTK_FOLDER_LIST_STORE_N_COLUMNS", "n" },
+ { 0, NULL, NULL }
+ };
+ etype = g_enum_register_static ("TnyGtkFolderListStoreColumn", values);
+ return GUINT_TO_POINTER (etype);
+}
+
+/**
+ * tny_gtk_folder_list_store_column_get_type:
+ *
+ * GType system helper function
+ *
+ * returns: a #GType
+ **/
+GType
+tny_gtk_folder_list_store_column_get_type (void)
+{
+ static GOnce once = G_ONCE_INIT;
+ g_once (&once, tny_gtk_folder_list_store_column_register_type, NULL);
+ return GPOINTER_TO_UINT (once.retval);
+}
Index: libtinymailui-gtk/tny-gtk-folder-list-store.h
===================================================================
--- libtinymailui-gtk/tny-gtk-folder-list-store.h (revisión: 0)
+++ libtinymailui-gtk/tny-gtk-folder-list-store.h (revisión: 0)
@@ -0,0 +1,91 @@
+#ifndef TNY_GTK_FOLDER_LIST_STORE_H
+#define TNY_GTK_FOLDER_LIST_STORE_H
+
+/* libtinymailui-gtk - The Tiny Mail UI library for Gtk+
+ * Copyright (C) 2006-2008 Philip Van Hoof <pvanhoof gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with self library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <tny-folder-store.h>
+#include <tny-folder-store-query.h>
+#include <tny-list.h>
+
+G_BEGIN_DECLS
+
+#define TNY_TYPE_GTK_FOLDER_LIST_STORE (tny_gtk_folder_list_store_get_type ())
+#define TNY_GTK_FOLDER_LIST_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TNY_TYPE_GTK_FOLDER_LIST_STORE, TnyGtkFolderListStore))
+#define TNY_GTK_FOLDER_LIST_STORE_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), TNY_TYPE_GTK_FOLDER_LIST_STORE, TnyGtkFolderListStoreClass))
+#define TNY_IS_GTK_FOLDER_LIST_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TNY_TYPE_GTK_FOLDER_LIST_STORE))
+#define TNY_IS_GTK_FOLDER_LIST_STORE_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), TNY_TYPE_GTK_FOLDER_LIST_STORE))
+#define TNY_GTK_FOLDER_LIST_STORE_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), TNY_TYPE_GTK_FOLDER_LIST_STORE, TnyGtkFolderListStoreClass))
+
+/* Implements GtkTreeModel and TnyList */
+
+typedef struct _TnyGtkFolderListStore TnyGtkFolderListStore;
+typedef struct _TnyGtkFolderListStoreClass TnyGtkFolderListStoreClass;
+
+#define TNY_TYPE_GTK_FOLDER_LIST_STORE_COLUMN (tny_gtk_folder_list_store_column_get_type())
+
+enum _TnyGtkFolderListStoreColumn
+{
+ TNY_GTK_FOLDER_LIST_STORE_NAME_COLUMN,
+ TNY_GTK_FOLDER_LIST_STORE_UNREAD_COLUMN,
+ TNY_GTK_FOLDER_LIST_STORE_ALL_COLUMN,
+ TNY_GTK_FOLDER_LIST_STORE_TYPE_COLUMN,
+ TNY_GTK_FOLDER_LIST_STORE_INSTANCE_COLUMN,
+ TNY_GTK_FOLDER_LIST_STORE_N_COLUMNS
+};
+
+typedef enum _TnyGtkFolderListStoreColumn TnyGtkFolderListStoreColumn;
+
+enum _TnyGtkFolderListStoreFlags
+{
+ TNY_GTK_FOLDER_LIST_STORE_FLAG_SHOW_PATH = 1<<0,
+};
+
+typedef enum _TnyGtkFolderListStoreFlags TnyGtkFolderListStoreFlags;
+
+struct _TnyGtkFolderListStore
+{
+ GtkTreeStore parent;
+ GList *first, *store_obs, *fol_obs;
+ GMutex *iterator_lock;
+ TnyFolderStoreQuery *query;
+ gboolean first_needs_unref;
+ GPtrArray *signals;
+
+ TnyGtkFolderListStoreFlags flags;
+};
+
+struct _TnyGtkFolderListStoreClass
+{
+ GtkTreeStoreClass parent_class;
+};
+
+GType tny_gtk_folder_list_store_get_type (void);
+GType tny_gtk_folder_list_store_column_get_type (void);
+GtkTreeModel* tny_gtk_folder_list_store_new (TnyFolderStoreQuery *query);
+GtkTreeModel* tny_gtk_folder_list_store_new_with_flags (TnyFolderStoreQuery *query,
+ TnyGtkFolderListStoreFlags flags);
+void tny_gtk_folder_list_store_prepend (TnyGtkFolderListStore *self, TnyFolderStore* item, const gchar *root_name);
+void tny_gtk_folder_list_store_append (TnyGtkFolderListStore *self, TnyFolderStore* item, const gchar *root_name);
+
+G_END_DECLS
+
+#endif
Index: libtinymailui-gtk/tny-gtk-folder-list-store-iterator-priv.h
===================================================================
--- libtinymailui-gtk/tny-gtk-folder-list-store-iterator-priv.h (revisión: 0)
+++ libtinymailui-gtk/tny-gtk-folder-list-store-iterator-priv.h (revisión: 0)
@@ -0,0 +1,62 @@
+#ifndef TNY_GTK_FOLDER_LIST_STORE_ITERATOR_H
+#define TNY_GTK_FOLDER_LIST_STORE_ITERATOR_H
+
+/* libtinymail- The Tiny Mail base library
+ * Copyright (C) 2006-2008 Philip Van Hoof <pvanhoof gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with self library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <tny-shared.h>
+#include <tny-list.h>
+#include <tny-iterator.h>
+#include <tny-gtk-folder-list-store.h>
+
+G_BEGIN_DECLS
+
+#define TNY_TYPE_GTK_FOLDER_LIST_STORE_ITERATOR (_tny_gtk_folder_list_store_iterator_get_type ())
+#define TNY_GTK_FOLDER_LIST_STORE_ITERATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TNY_TYPE_GTK_FOLDER_LIST_STORE_ITERATOR, TnyGtkFolderListStoreIterator))
+#define TNY_GTK_FOLDER_LIST_STORE_ITERATOR_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), TNY_TYPE_GTK_FOLDER_LIST_STORE_ITERATOR, TnyGtkFolderListStoreIteratorClass))
+#define TNY_IS_GTK_FOLDER_LIST_STORE_ITERATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TNY_TYPE_GTK_FOLDER_LIST_STORE_ITERATOR))
+#define TNY_IS_GTK_FOLDER_LIST_STORE_ITERATOR_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), TNY_TYPE_GTK_FOLDER_LIST_STORE_ITERATOR))
+#define TNY_GTK_FOLDER_LIST_STORE_ITERATOR_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), TNY_TYPE_GTK_FOLDER_LIST_STORE_ITERATOR, TnyGtkFolderListStoreIteratorClass))
+
+typedef struct _TnyGtkFolderListStoreIterator TnyGtkFolderListStoreIterator;
+typedef struct _TnyGtkFolderListStoreIteratorClass TnyGtkFolderListStoreIteratorClass;
+
+struct _TnyGtkFolderListStoreIterator
+{
+ GObject parent;
+ TnyGtkFolderListStore *model;
+ GList *current;
+};
+
+struct _TnyGtkFolderListStoreIteratorClass
+{
+ GObjectClass parent;
+};
+
+void _tny_gtk_folder_list_store_iterator_set_model (TnyGtkFolderListStoreIterator *self, TnyGtkFolderListStore *model);
+TnyGtkFolderListStoreIterator* _tny_gtk_folder_list_store_iterator_new (TnyGtkFolderListStore *model);
+
+
+G_END_DECLS
+
+#endif
+
Index: libtinymailui-gtk/tny-gtk-folder-list-store-iterator.c
===================================================================
--- libtinymailui-gtk/tny-gtk-folder-list-store-iterator.c (revisión: 0)
+++ libtinymailui-gtk/tny-gtk-folder-list-store-iterator.c (revisión: 0)
@@ -0,0 +1,274 @@
+/* libtinymail - The Tiny Mail base library
+ * Copyright (C) 2006-2008 Philip Van Hoof <pvanhoof gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with self library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <config.h>
+
+#include <tny-gtk-folder-list-store.h>
+
+static GObjectClass *parent_class = NULL;
+
+#include "tny-gtk-folder-list-store-iterator-priv.h"
+
+GType _tny_gtk_folder_list_store_iterator_get_type (void);
+
+
+void
+_tny_gtk_folder_list_store_iterator_set_model (TnyGtkFolderListStoreIterator *self, TnyGtkFolderListStore *model)
+{
+ if (self->model)
+ g_object_unref (self->model);
+
+ self->model = g_object_ref (model);
+ self->current = model->first;
+
+ return;
+}
+
+
+
+TnyGtkFolderListStoreIterator*
+_tny_gtk_folder_list_store_iterator_new (TnyGtkFolderListStore *model)
+{
+ TnyGtkFolderListStoreIterator *self = g_object_new (TNY_TYPE_GTK_FOLDER_LIST_STORE_ITERATOR, NULL);
+
+ _tny_gtk_folder_list_store_iterator_set_model (self, model);
+
+ return self;
+}
+
+static void
+tny_gtk_folder_list_store_iterator_instance_init (GTypeInstance *instance, gpointer g_class)
+{
+ TnyGtkFolderListStoreIterator *self = (TnyGtkFolderListStoreIterator *)instance;
+
+ self->model = NULL;
+ self->current = NULL;
+
+ return;
+}
+
+static void
+tny_gtk_folder_list_store_iterator_finalize (GObject *object)
+{
+ TnyGtkFolderListStoreIterator *self = (TnyGtkFolderListStoreIterator *) object;
+
+ if (self->model)
+ g_object_unref (self->model);
+
+ (*parent_class->finalize) (object);
+
+ return;
+}
+
+
+static void
+tny_gtk_folder_list_store_iterator_next (TnyIterator *self)
+{
+ TnyGtkFolderListStoreIterator *me = (TnyGtkFolderListStoreIterator*) self;
+
+ if (G_UNLIKELY (!me || !me->current || !me->model))
+ return;
+
+ /* Move the iterator to the next node */
+
+ g_mutex_lock (me->model->iterator_lock);
+ me->current = g_list_next (me->current);
+ g_mutex_unlock (me->model->iterator_lock);
+
+ return;
+}
+
+static void
+tny_gtk_folder_list_store_iterator_prev (TnyIterator *self)
+{
+ TnyGtkFolderListStoreIterator *me = (TnyGtkFolderListStoreIterator*) self;
+
+ if (G_UNLIKELY (!me || !me->current || !me->model))
+ return;
+
+ /* Move the iterator to the previous node */
+
+ g_mutex_lock (me->model->iterator_lock);
+ me->current = g_list_previous (me->current);
+ g_mutex_unlock (me->model->iterator_lock);
+
+ return;
+}
+
+
+static gboolean
+tny_gtk_folder_list_store_iterator_is_done (TnyIterator *self)
+{
+ TnyGtkFolderListStoreIterator *me = (TnyGtkFolderListStoreIterator*) self;
+
+ if (G_UNLIKELY (!me || !me->model))
+ return TRUE;
+
+ return me->current == NULL;
+}
+
+
+
+static void
+tny_gtk_folder_list_store_iterator_first (TnyIterator *self)
+{
+ TnyGtkFolderListStoreIterator *me = (TnyGtkFolderListStoreIterator*) self;
+
+ if (G_UNLIKELY (!me || !me->current || !me->model))
+ return;
+
+ /* Move the iterator to the first node. We know that model always
+ keeps a reference to the first node, there's nothing wrong with
+ using that one. */
+
+ g_mutex_lock (me->model->iterator_lock);
+ me->current = me->model->first;
+ g_mutex_unlock (me->model->iterator_lock);
+
+ return;
+}
+
+
+static void
+tny_gtk_folder_list_store_iterator_nth (TnyIterator *self, guint nth)
+{
+ TnyGtkFolderListStoreIterator *me = (TnyGtkFolderListStoreIterator*) self;
+
+ if (G_UNLIKELY (!me || !me->current || !me->model))
+ return;
+
+ /* Move the iterator to the nth node. We'll count from zero,
+ so we start with the first node of which we know the model
+ stored a reference. */
+
+ g_mutex_lock (me->model->iterator_lock);
+ me->current = g_list_nth (me->model->first, nth);
+ g_mutex_unlock (me->model->iterator_lock);
+
+ return;
+}
+
+
+static GObject*
+tny_gtk_folder_list_store_iterator_get_current (TnyIterator *self)
+{
+ TnyGtkFolderListStoreIterator *me = (TnyGtkFolderListStoreIterator*) self;
+ gpointer ptr;
+
+ if (G_UNLIKELY (!me || !me->model))
+ return NULL;
+
+ /* Give the data of the current node */
+
+ g_mutex_lock (me->model->iterator_lock);
+ ptr = (G_UNLIKELY (me->current)) ? me->current->data : NULL;
+ g_mutex_unlock (me->model->iterator_lock);
+
+ if (ptr)
+ g_object_ref (G_OBJECT(ptr));
+
+ return G_OBJECT(ptr);
+}
+
+
+static TnyList*
+tny_gtk_folder_list_store_iterator_get_list (TnyIterator *self)
+{
+ TnyGtkFolderListStoreIterator *me = (TnyGtkFolderListStoreIterator*) self;
+
+ /* Return the list */
+
+ if (G_UNLIKELY (!me || !me->model))
+ return NULL;
+
+ g_object_ref (G_OBJECT (me->model));
+
+ return TNY_LIST (me->model);
+}
+
+static void
+tny_iterator_init (TnyIteratorIface *klass)
+{
+ klass->next= tny_gtk_folder_list_store_iterator_next;
+ klass->prev= tny_gtk_folder_list_store_iterator_prev;
+ klass->first= tny_gtk_folder_list_store_iterator_first;
+ klass->nth= tny_gtk_folder_list_store_iterator_nth;
+ klass->get_current= tny_gtk_folder_list_store_iterator_get_current;
+ klass->get_list= tny_gtk_folder_list_store_iterator_get_list;
+ klass->is_done = tny_gtk_folder_list_store_iterator_is_done;
+
+ return;
+}
+
+static void
+tny_gtk_folder_list_store_iterator_class_init (TnyGtkFolderListStoreIteratorClass *klass)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (klass);
+ object_class = (GObjectClass*) klass;
+
+ object_class->finalize = tny_gtk_folder_list_store_iterator_finalize;
+
+ return;
+}
+
+static gpointer
+_tny_gtk_folder_list_store_iterator_register_type (gpointer notused)
+{
+ GType type = 0;
+
+ static const GTypeInfo info =
+ {
+ sizeof (TnyGtkFolderListStoreIteratorClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) tny_gtk_folder_list_store_iterator_class_init, /* class_init */
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (TnyGtkFolderListStoreIterator),
+ 0, /* n_preallocs */
+ tny_gtk_folder_list_store_iterator_instance_init, /* instance_init */
+ NULL
+ };
+
+ static const GInterfaceInfo tny_iterator_info =
+ {
+ (GInterfaceInitFunc) tny_iterator_init, /* interface_init */
+ NULL, /* interface_finalize */
+ NULL /* interface_data */
+ };
+
+ type = g_type_register_static (G_TYPE_OBJECT,
+ "TnyGtkFolderListStoreIterator",
+ &info, 0);
+
+ g_type_add_interface_static (type, TNY_TYPE_ITERATOR,
+ &tny_iterator_info);
+
+ return GUINT_TO_POINTER (type);
+}
+
+GType
+_tny_gtk_folder_list_store_iterator_get_type (void)
+{
+ static GOnce once = G_ONCE_INIT;
+ g_once (&once, _tny_gtk_folder_list_store_iterator_register_type, NULL);
+ return GPOINTER_TO_UINT (once.retval);
+}
Index: libtinymailui-gtk/tny-gtk-folder-store-tree-model.c
===================================================================
--- libtinymailui-gtk/tny-gtk-folder-store-tree-model.c (revisión: 3824)
+++ libtinymailui-gtk/tny-gtk-folder-store-tree-model.c (copia de trabajo)
@@ -65,6 +65,8 @@
#include "tny-gtk-folder-store-tree-model-iterator-priv.h"
+#define PATH_SEPARATOR " "
+
static GObjectClass *parent_class = NULL;
typedef void (*treeaddfunc) (GtkTreeStore *tree_store, GtkTreeIter *iter, GtkTreeIter *parent);
@@ -109,7 +111,10 @@
}
static void
-recurse_folders_sync (TnyGtkFolderStoreTreeModel *self, TnyFolderStore *store, GtkTreeIter *parent_tree_iter)
+recurse_folders_sync (TnyGtkFolderStoreTreeModel *self,
+ TnyFolderStore *store,
+ const gchar *parent_name,
+ GtkTreeIter *parent_tree_iter)
{
TnyIterator *iter;
TnyList *folders = tny_simple_list_new ();
@@ -118,6 +123,9 @@
tny_folder_store_get_folders (store, folders, self->query, TRUE, NULL);
iter = tny_list_create_iterator (folders);
+ if (parent_name == NULL)
+ parent_name = "";
+
while (!tny_iterator_is_done (iter))
{
GtkTreeModel *mmodel = (GtkTreeModel *) self;
@@ -186,6 +194,7 @@
if (!found)
{
+ gchar *name;
gtk_tree_store_append (model, &tree_iter, parent_tree_iter);
/* Making self both a folder-store as a folder observer
@@ -201,9 +210,22 @@
add_folder_observer_weak (self, folder);
+ if (self->flags & TNY_GTK_FOLDER_STORE_TREE_MODEL_FLAG_SHOW_PATH) {
+ if ((parent_name == NULL) || *parent_name == '\0') {
+ name = g_strdup (tny_folder_get_name (folder));
+ } else {
+ name = g_strconcat (parent_name,
+ PATH_SEPARATOR,
+ tny_folder_get_name (folder),
+ NULL);
+ }
+ } else {
+ name = g_strdup (tny_folder_get_name (folder));
+ }
+
gtk_tree_store_set (model, &tree_iter,
TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN,
- tny_folder_get_name (TNY_FOLDER (folder)),
+ name,
TNY_GTK_FOLDER_STORE_TREE_MODEL_UNREAD_COLUMN,
tny_folder_get_unread_count (TNY_FOLDER (folder)),
TNY_GTK_FOLDER_STORE_TREE_MODEL_ALL_COLUMN,
@@ -213,14 +235,18 @@
TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN,
folder, -1);
+ } else {
+ name = g_strdup (tny_folder_get_name (folder));
}
/* it's a store by itself, so keep on recursing */
if (folder_store) {
add_folder_store_observer_weak (self, folder_store);
- recurse_folders_sync (self, folder_store, &tree_iter);
+ recurse_folders_sync (self, folder_store, name, &tree_iter);
}
+ g_free (name);
+
/* We're a folder, we'll request a status, since we've
* set self to be a folder observers of folder, we'll
* receive the status update. This makes it possible to
@@ -318,7 +344,7 @@
* folders that already exist (it wont add them a second time). */
if (found)
- recurse_folders_sync (self, fstore, &name_iter);
+ recurse_folders_sync (self, fstore, NULL, &name_iter);
g_object_unref (self);
@@ -542,7 +568,7 @@
* tny_gtk_folder_store_tree_model_new:
* @query: the #TnyFolderStoreQuery that will be used to retrieve the child folders of each #TnyFolderStore
*
- * Create a new #GtkTreeModel for showing #TnyFolderStore instances
+ * Create a new #GtkTreeModel for showing #TnyFolderStore instances, with default flags
*
* returns: (caller-owns): a new #GtkTreeModel for #TnyFolderStore instances
* since: 1.0
@@ -551,11 +577,31 @@
GtkTreeModel*
tny_gtk_folder_store_tree_model_new (TnyFolderStoreQuery *query)
{
+ return tny_gtk_folder_store_tree_model_new_with_flags (query, 0);
+}
+
+/**
+ * tny_gtk_folder_store_tree_model_new:
+ * @query: the #TnyFolderStoreQuery that will be used to retrieve the child folders of each #TnyFolderStore
+ * @flags: #TnyGtkFolderStoreTreeModelFlags for setting the store
+ *
+ * Create a new #GtkTreeModel for showing #TnyFolderStore instances
+ *
+ * returns: (caller-owns): a new #GtkTreeModel for #TnyFolderStore instances
+ * since: 1.0
+ * audience: application-developer
+ **/
+GtkTreeModel*
+tny_gtk_folder_store_tree_model_new_with_flags (TnyFolderStoreQuery *query,
+ TnyGtkFolderStoreTreeModelFlags flags)
+{
TnyGtkFolderStoreTreeModel *self = g_object_new (TNY_TYPE_GTK_FOLDER_STORE_TREE_MODEL, NULL);
if (query)
self->query = g_object_ref (query);
+ self->flags = flags;
+
return GTK_TREE_MODEL (self);
}
@@ -647,6 +693,8 @@
me->iterator_lock = g_mutex_new ();
me->first_needs_unref = FALSE;
+ me->flags = 0;
+
gtk_tree_store_set_column_types (store,
TNY_GTK_FOLDER_STORE_TREE_MODEL_N_COLUMNS, types);
@@ -849,7 +897,167 @@
return;
}
+typedef struct _FindParentHelperInfo {
+ GtkTreeIter *iter;
+ TnyFolder *folder;
+ TnyAccount *account;
+ gboolean found;
+} FindParentHelperInfo;
+static gboolean
+find_parent_helper (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer userdata)
+{
+ TnyFolderStore *folder_store;
+ FindParentHelperInfo *helper_info = (FindParentHelperInfo *) userdata;
+ TnyList *children;
+ TnyIterator *iterator;
+
+ gtk_tree_model_get (model, iter,
+ TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN,
+ &folder_store, -1);
+
+ /* Only search on same account */
+ if (TNY_IS_ACCOUNT (folder_store) && ((TnyAccount *)folder_store == helper_info->account))
+ return FALSE;
+
+ if (TNY_IS_FOLDER (folder_store)) {
+ TnyAccount *account = NULL;
+ account = tny_folder_get_account (TNY_FOLDER (folder_store));
+ g_object_unref (account);
+ if (account == helper_info->account)
+ return FALSE;
+ }
+
+ children = TNY_LIST (tny_simple_list_new ());
+ tny_folder_store_get_folders (folder_store, children, NULL, FALSE, NULL);
+ iterator = tny_list_create_iterator (children);
+
+ while (!tny_iterator_is_done (iterator)) {
+ TnyFolderStore *child;
+
+ child = (TnyFolderStore *) tny_iterator_get_current (iterator);
+ g_object_unref (child);
+ if (child == (TnyFolderStore *) helper_info->folder) {
+ helper_info->found = TRUE;
+ *helper_info->iter = *iter;
+ break;
+ }
+ tny_iterator_next (iterator);
+ }
+ g_object_unref (iterator);
+ g_object_unref (children);
+
+ return helper_info->found;
+
+}
+
+static gboolean
+find_parent (GtkTreeModel *model, TnyFolder *folder, GtkTreeIter *iter)
+{
+ FindParentHelperInfo *helper_info;
+ gboolean result;
+
+ helper_info = g_slice_new0 (FindParentHelperInfo);
+
+ helper_info->folder = folder;
+ helper_info->iter = iter;
+ helper_info->account = tny_folder_get_account (folder);
+
+ gtk_tree_model_foreach (model, find_parent_helper, helper_info);
+
+ g_object_unref (helper_info->account);
+ result = helper_info->found;
+ g_slice_free (FindParentHelperInfo, helper_info);
+
+ return result;
+}
+
+typedef struct _FindHelperInfo {
+ GtkTreeIter *iter;
+ TnyFolder *folder;
+ gboolean found;
+} FindHelperInfo;
+
+static gboolean
+find_node_helper (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer userdata)
+{
+ TnyFolderStore *folder_store;
+ FindHelperInfo *helper_info = (FindHelperInfo *) userdata;
+
+ gtk_tree_model_get (model, iter,
+ TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN,
+ &folder_store, -1);
+
+ if ((TnyFolderStore *) helper_info->folder == folder_store) {
+ helper_info->found = TRUE;
+ *helper_info->iter = *iter;
+ }
+
+ return helper_info->found;
+
+}
+
+static gboolean
+find_node (GtkTreeModel *model, TnyFolder *folder, GtkTreeIter *iter)
+{
+ FindHelperInfo *helper_info;
+ gboolean result;
+
+ helper_info = g_slice_new0 (FindHelperInfo);
+
+ helper_info->folder = folder;
+ helper_info->iter = iter;
+
+ gtk_tree_model_foreach (model, find_node_helper, helper_info);
+
+ result = helper_info->found;
+ g_slice_free (FindHelperInfo, helper_info);
+
+ return result;
+}
+
+static void
+update_children_names (GtkTreeModel *model, TnyFolder *folder, const gchar *name)
+{
+ TnyList *children;
+ TnyIterator *iterator;
+
+ children = TNY_LIST (tny_simple_list_new ());
+ iterator = tny_list_create_iterator (children);
+
+ while (!tny_iterator_is_done (iterator)) {
+ GtkTreeIter iter;
+ TnyFolder *child;
+
+ child = TNY_FOLDER (tny_iterator_get_current (iterator));
+ if (find_node (model, child, &iter)) {
+ gchar *new_name;
+ new_name = g_strconcat (name, PATH_SEPARATOR,
+ tny_folder_get_name (TNY_FOLDER (child)),
+ NULL);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
+ TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN,
+ new_name,
+ -1);
+ update_children_names (model, child, new_name);
+ g_free (new_name);
+ }
+
+ g_object_unref (folder);
+ tny_iterator_next (iterator);
+ }
+
+ g_object_unref (iterator);
+ g_object_unref (children);
+}
+
+
static gboolean
updater (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data1)
{
@@ -906,17 +1114,50 @@
if (folder == changed_folder)
{
-
/* TNY TODO: This is not enough: Subfolders will be incorrect because the
the full_name of the subfolders will still be the old full_name!*/
gtk_tree_store_set (GTK_TREE_STORE (model), iter,
- TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN,
- tny_folder_get_name (TNY_FOLDER (folder)),
TNY_GTK_FOLDER_STORE_TREE_MODEL_UNREAD_COLUMN,
unread,
TNY_GTK_FOLDER_STORE_TREE_MODEL_ALL_COLUMN,
total, -1);
+
+ if (changed & TNY_FOLDER_CHANGE_CHANGED_FOLDER_RENAME) {
+ GtkTreeIter parent_iter;
+ gchar *name = NULL;
+
+ if (TNY_GTK_FOLDER_STORE_TREE_MODEL (model)->flags &
+ TNY_GTK_FOLDER_STORE_TREE_MODEL_FLAG_SHOW_PATH) {
+ if (find_parent (model, folder, &parent_iter)) {
+ gchar *parent_name;
+ gtk_tree_model_get (model, &parent_iter,
+ TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN,
+ &parent_name, -1);
+ if (parent_name && parent_name[0] == '\0')
+ name = g_strconcat (parent_name, PATH_SEPARATOR,
+ tny_folder_get_name (TNY_FOLDER (folder)),
+ NULL);
+ g_free (parent_name);
+
+
+ }
+ }
+
+
+ if (name == NULL)
+ name = g_strdup (tny_folder_get_name (TNY_FOLDER (folder)));
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), iter,
+ TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN,
+ name,
+ -1);
+ if (TNY_GTK_FOLDER_STORE_TREE_MODEL (model)->flags &
+ TNY_GTK_FOLDER_STORE_TREE_MODEL_FLAG_SHOW_PATH) {
+ update_children_names (model, folder, name);
+ }
+ g_free (name);
+ }
}
g_object_unref (folder);
@@ -1031,14 +1272,21 @@
{
TnyList *created = tny_simple_list_new ();
TnyIterator *miter;
+ gchar *parent_name;
tny_folder_store_change_get_created_folders (change, created);
miter = tny_list_create_iterator (created);
+ /* We assume parent name is already the expected one in full path style */
+ gtk_tree_model_get (model, in_iter,
+ TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &parent_name,
+ -1);
+
while (!tny_iterator_is_done (miter))
{
GtkTreeIter newiter;
TnyFolder *folder = TNY_FOLDER (tny_iterator_get_current (miter));
+ gchar *finalname;
add_folder_observer_weak (self, folder);
add_folder_store_observer_weak (self, TNY_FOLDER_STORE (folder));
@@ -1047,12 +1295,22 @@
removed, that reference count is decreased automatically by
the gtktreestore infrastructure. */
+ if (TNY_GTK_FOLDER_STORE_TREE_MODEL (self)->flags &
+ TNY_GTK_FOLDER_STORE_TREE_MODEL_FLAG_SHOW_PATH) {
+ if (parent_name && *parent_name != '\0')
+ finalname = g_strconcat (parent_name, PATH_SEPARATOR,
+ tny_folder_get_name (TNY_FOLDER (folder)), NULL);
+ else
+ finalname = g_strdup (tny_folder_get_name (TNY_FOLDER (folder)));
+ } else {
+ finalname = g_strdup (tny_folder_get_name (TNY_FOLDER (folder)));
+ }
gtk_tree_store_prepend (GTK_TREE_STORE (model), &newiter, in_iter);
gtk_tree_store_set (GTK_TREE_STORE (model), &newiter,
TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN,
- tny_folder_get_name (TNY_FOLDER (folder)),
+ finalname,
TNY_GTK_FOLDER_STORE_TREE_MODEL_UNREAD_COLUMN,
tny_folder_get_unread_count (TNY_FOLDER (folder)),
TNY_GTK_FOLDER_STORE_TREE_MODEL_ALL_COLUMN,
@@ -1061,10 +1319,12 @@
tny_folder_get_folder_type (TNY_FOLDER (folder)),
TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN,
folder, -1);
+ g_free (finalname);
g_object_unref (folder);
tny_iterator_next (miter);
}
+ g_free (parent_name);
g_object_unref (miter);
g_object_unref (created);
}
Index: libtinymailui-gtk/tny-gtk-folder-store-tree-model.h
===================================================================
--- libtinymailui-gtk/tny-gtk-folder-store-tree-model.h (revisión: 3824)
+++ libtinymailui-gtk/tny-gtk-folder-store-tree-model.h (copia de trabajo)
@@ -54,6 +54,13 @@
typedef enum _TnyGtkFolderStoreTreeModelColumn TnyGtkFolderStoreTreeModelColumn;
+enum _TnyGtkFolderStoreTreeModelFlags
+{
+ TNY_GTK_FOLDER_STORE_TREE_MODEL_FLAG_SHOW_PATH = 1<<0,
+};
+
+typedef enum _TnyGtkFolderStoreTreeModelFlags TnyGtkFolderStoreTreeModelFlags;
+
struct _TnyGtkFolderStoreTreeModel
{
GtkTreeStore parent;
@@ -62,6 +69,8 @@
TnyFolderStoreQuery *query;
gboolean first_needs_unref;
GPtrArray *signals;
+
+ TnyGtkFolderStoreTreeModelFlags flags;
};
struct _TnyGtkFolderStoreTreeModelClass
@@ -72,7 +81,8 @@
GType tny_gtk_folder_store_tree_model_get_type (void);
GType tny_gtk_folder_store_tree_model_column_get_type (void);
GtkTreeModel* tny_gtk_folder_store_tree_model_new (TnyFolderStoreQuery *query);
-
+GtkTreeModel* tny_gtk_folder_store_tree_model_new_with_flags (TnyFolderStoreQuery *query,
+ TnyGtkFolderStoreTreeModelFlags flags);
void tny_gtk_folder_store_tree_model_prepend (TnyGtkFolderStoreTreeModel *self, TnyFolderStore* item, const gchar *root_name);
void tny_gtk_folder_store_tree_model_append (TnyGtkFolderStoreTreeModel *self, TnyFolderStore* item, const gchar *root_name);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]