A type for showing folders in a tree-style

Tinymail 1.0

http://tinymail.org/API/libtinymail-1.0/TnyGtkFolderStoreTreeModel.html

About

This type is a Gtk+ type. This means that it depends on the Gtk+ ui toolkit. It can be used to display the folders of your accounts, using for example GtkTreeView & co. It's called a folder-store tree model because it accepts any folder-store type, not just store-accounts (who are folder-stores too).

The type is also both a TnyFolderObserver and a TnyFolderStoreObserver. It uses the functionality of being an observer for observing changes to the folders and folder-stores that it will display. This way it automatically updates itself whenever renames, creations and deletions of folders and subfolders happen. It also updates itself whenever the read-count or all-count of a folder changed.

To put it in another way: you, being the MUA application developer, don't have to care about it.

Usage

GtkTreeView *view;
TnyPlatformFactory *platfact = tny_gnome_platform_factory_get_instance ();
TnyAccountStore *astore = tny_platform_factory_new_account_store (platfact);
TnyFolderStoreQuery *query = NULL;
GtkTreeModel *model = tny_gtk_folder_store_tree_model_new (FALSE, query);
GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes 
	(_("Folder"), renderer,
	"text", TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, NULL);

view = gtk_tree_view_new ();
gtk_tree_view_column_set_sort_column_id (column, 
	TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN);
gtk_tree_view_append_column (view, column);

tny_account_store_get_accounts (astore, TNY_LIST (model),
	TNY_ACCOUNT_STORE_STORE_ACCOUNTS);

gtk_tree_view_set_model (view, model);
 
g_object_unref (G_OBJECT (astore));
g_object_unref (G_OBJECT (platfact));

It's a TnyList too!

What this means

This means that you can use all of the TnyList API on this type. This includes tny_list_prepend and tny_list_append. The type is intelligent about when a account type (a store account) got added for determining the root name. It will then use this little bit of logic:

static const gchar*
get_root_name (GObject *is_being_added)
{
	const gchar *root_name;
	if (TNY_IS_ACCOUNT (is_being_added))
		root_name = tny_account_get_name (TNY_ACCOUNT (is_being_added));
	else
		root_name = _("Folder bag");
	return root_name;
}

What will I iterate when I use a TnyIterator on it?

You will iterate the items that where added using tny_list_prepend, tny_list_append and the extra API which is described below. Although they will be added to the GtkTreeModel, You will not iterate the subfolders of those items. If you want to iterate those items too, you can of course use the normal GtkTreeModel API for this.

This will give you foldersto1, foldersto2, and foldersto3 in the loop. It will not give you subfolders of foldersto1 nor subfolders of foldersto2 nor subfolders foldersto3:

GtkTreeModel *model = tny_gtk_folder_store_tree_model_new (FALSE, query);
TnyIterator *iter = tny_list_create_iterator (TNY_LIST (model));

tny_list_prepend (TNY_LIST (model), foldersto1);
tny_list_prepend (TNY_LIST (model), foldersto2);
tny_list_prepend (TNY_LIST (model), foldersto3);

while (!tny_iterator_is_done (iter))
{
    TnyFolderStore *fstore = tny_iterator_get_current (iter);
    g_object_unref (G_OBJECT (fstore));
    tny_iterator_next (iter);
}
g_object_unref (G_OBJECT (iter));
g_object_unref (G_OBJECT (model));

It's a GtkTreeModel too!

Yes, it is. It's both a TnyList and a fully qualified GtkTreeModel. If the TnyList API and behavior of this type isn't enough for you, you can use the GtkTreeModel and GtkTreeStore API with it (for example iterating recursively all the items, which isn't possible if you use the TnyList API).

Mind though, that the GtkTreeModel API is Gtk+ specific. It's a nice side effect of the fact that this type was implemented using the Gtk+ infrastructure. It of course means that the type depends on the availability of Gtk+ too. But it's at your own risk how you use this. By that I mean that the Tinymail framework developers are not responsible for changes that happen to the Gtk+ framework.

Also note that the internal implementation might not cope with the changes that you inflict on the instance by using the GtkTreeModel and GtkTreeStore API. Especially not when you changed the state of things that are not to be changed. If you are going to use such API, you are advised to at least take a look at the implementation of TnyGtkFolderStoreTreeModel.

In general it's safe to say that if you use the API in a read-only way, that you probably wont do any harm. So be very careful when doing non-read-only things. Consider reimplementing the type (copypaste it, mind the license though) or inherit it (but then still, what if the Tinymail developers decide to change the implementation of the type?). It's a bit tricky so make sure that you make a clever decision.

At this moment the Tinymail developers can give no guarantees about the stability of the implementation of this type. It might very well change drastically.

This example, however, will give you foldersto1, foldersto2, foldersto3 and all of their subfolders:

static gboolean
myforeach (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data1)
{
    gint type;
    gtk_tree_model_get (model, iter,
            TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN,
            &type, -1);
    if (type != TNY_FOLDER_TYPE_ROOT)
    {
        GObject *fol;
        gtk_tree_model_get (model, iter,
                TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN,
                &fol, -1);
        printf ("%s\n", tny_folder_get_name (TNY_FOLDER (fol)));         
        g_object_unref (G_OBJECT (fol));
    }
    return FALSE;
}

static void myfunc (GtkTreeModel *model)
{
   gtk_tree_model_foreach (model, myforeach, NULL);
}

What about this TNY_FOLDER_TYPE_ROOT thing?

The folder-id column is used in the GtkTreeView to indicate both the type of the treenode and the type of the folder. If that type is TNY_FOLDER_TYPE_ROOT, it means that the node was a "root_name" node and that there's no folder instance behind the node. The root_name is often used to put the name of the account in it (the tny_account_get_name API). Also take a look at the "Extra API" section of this documentation for more information (below this section).

Extra API

If you want to override the functionality of above, there are two extra functions available for you:

tny_gtk_folder_store_tree_model_prepend (self, item, root_name)
tny_gtk_folder_store_tree_model_append (self, item, root_name)

As you can see in the API you can enter the root_name yourself. These APIs will in functionality do the same as tny_list_append and tny_list_prepend. With the exception that they will not magically try to figure out the root name. In stead they will use the root_name which you gave it.

If you want to add an item while not caring about the root_name, just use the tny_list_prepend and tny_list_append API. Remember, the type is a TnyList too.

You can add any folder-store instance

A TnyFolder is a folder-store too. You can add that (it doesn't have to be a store-account type). You can even add or re-add a folder that belongs to another folder store (as a child of it). If you don't want to see that "Folder bag" root item, you should use the extra API as explained above.

Auto updating creations, renames, deletes, read count and all count

On creation, deletion and rename of any of the folders or folder-stores being stored should the TnyGtkFolderStoreTreeModel update itself. The documentation about dealing with folder removals explains how this type implemented this (in case you want to extend this one, or create such a type yourself). You can read about the internals of Tinymail here, to learn how this works.

On creation

This means that if in a folder store (like a folder), being stored in the model, a child folder gets created, that the model will automatically get a new folder at the correct location (being in a child node of the node on which the now parent folder was located)

On deletion

This means that if in a folder store (like a folder), being stored in the model, a child folder gets removed, that the model will automatically remove that folder from the model. Including all its subfolders, if any.

On rename

This means that if a folder got renamed, that the model will auto-update itself. This means that the folder will get its displayable name adjusted in the model.

On read count changed

This means that if a folder's "amount of read items" changed, that the model will auto-update itself. This includes such updates coming from Push E-mail style features or components like IMAP IDLE for IMAP accounts and SyncML for SyncML-enabled such accounts and folders.

On all count changed

This means that if a folder's "amount of all items" changed, that the model will auto-update itself. This includes such updates coming from Push E-mail style features or components like IMAP IDLE for IMAP accounts and SyncML for SyncML-enabled such accounts and folders.

Turning off the auto-updating

This is at this moment not possible. On request can this feature be implemented. Patches for making it possible to enable & disable this feature are of course welcome.

References to related other documentation