Getting headers in a GtkTreeView with tinymail

I’ll explain it using the new API for getting headers in tinymail. You can see this code in a working demo (that adds a GtkTreeModelSort) at this location.

You don’t see an ‘iterator‘ here: the TnyListIface is the iteratable type that doesn’t depend on Gtk+. The iterator itself is of course being used in the implementation. It can also be used by the developer who’ll be using the tinymail framework.

Update (fwd reply from Dirk@maemo): Updated “modest” to the new API — works fine here so far.

static void
refresh_current_folder (TnyMsgFolderIface *folder,
	gboolean cancelled, gpointer ud)
{
   GtkTreeView *header_view = ud;
   if (!cancelled) {
      #define TLI TNY_LIST_IFACE
      TnyListIface *model = TLI (tny_msg_headers_list_model_new ());
      tny_msg_folder_iface_get_headers (folder, model, FALSE);
      gtk_tree_view_set_model (header_view, GTK_TREE_MODEL (model));
   }
}
static void
on_folder_view_tree_sel_chgd (GtkTreeSelection *sel, gpointer ud)
{
  GtkTreeModel *model; GtkTreeIter iter;
  if (gtk_tree_selection_get_selected (sel, &model, &iter)) {
     TnyMsgFolderIface *folder;
     gtk_tree_model_get (model, &iter,
       TNY_ACCOUNT_TREE_MODEL_INSTANCE_COLUMN,
       &folder, -1);
     if (USE_ASYNC) {
        tny_msg_folder_iface_refresh_async (folder,
          refresh_current_folder, status_update, ud);
     } else {
        tny_msg_folder_iface_refresh (folder);
        refresh_current_folder (folder, FALSE, ud);
    }
  }
}

11 thoughts on “Getting headers in a GtkTreeView with tinymail”

  1. I’d expect these prev/next functions in
    TnyListIfaceClass
    http://pvanhoof.be/files/libtinymail/html/libtinymail-tny-shared.html#TnyListIface-struct
    to return iterators. Or are they changing the model state somehow?

    This seems to just be about making it easier to implement custom models. Most custom models are indeed just to prevent copying of values or data structures into a TreeStore or ListStore, or to get data on demand. There’s is indeed no way that ListStore or TreeStore could be appropriate for data (such as emails) that is read over a network connection.

    This is easier in language bindings. Most of them have extra APIs to do this kind of thing, and most of the higher level programming languages have iterator concepts that can be reused.

    Jonathan Jongsma seems to be mostly finished on a C++ template for this for gtkmm:
    http://mail.gnome.org/archives/gtkmm-list/2006-May/msg00131.html

  2. Also, I don’t understand how GtkTreeIter isn’t an iterator. It is as far as I can tell, and using Gtk::TreeModel::iterator in C++ is the same as using std::list::iterator. Your iterator just has different semantics and API, because GtkTreeIter isn’t that flexible, due to its own performance needs. You went and spoiled a nice simple blog entry by apparently insulting the GTK+ developers at random.

  3. RE First comment part one: It could be adapted to let it return iterators. I decided it would be more easy to let it return the value. It also saves me a call to tny_iterator_iface_current to get the current value from that iterator. The model state isn’t changed. The iterator instance keeps a state by itself.

    RE Second comment:
    The fact that the GtkTreeIter isn’t flexible in such a way that I can implement it myself, and the fact that it depends on gtk+ makes it unusable as an ‘iterator’ type that I can use in just any layer. It’s only usable in the top layer: the one that implements the user interface. In other words: it’s not usable at all. It’s a tiny type that is completely coupled with the GtkTreeView story.

    I can’t use a higher-language iterator type if I’m developing in C/GObject. Which is what I’m doing with tinymail (whether you like that or not). So using the std::list::iterator is not an option. You went and spoiled a nice simple comment entry by apparently only giving unusable solutions.

  4. RE: This seems to just be about making it easier to implement custom models.

    Exactly. That part, and the question why iterator_next doesn’t return an by iterator are the “nice & simple” part of you comments. The core reason why I implemented all this iterator and list stuff, is for making implementing custom models more easy. The other reason is that I now don’t have to depend all my infrastructure on gtk+. And a last reason is that now both changing the store and playing the role of model for a GtkTreeView is being done in the same type. This makes it more easy to introduce locking and letting the view update itself.

    Sure I could have solved this by proxying signals and other events all the way to the treeview. But that would have been an extremely ugly solution. And probably unmaintainable (for example locking sounds difficult). This solution, however, doesn’t keep me awake at night.

  5. Surely you recognise that making GtkTreeIter a Gobject implmenting a GInterface would have serious performance problems. In your example, the network latency is likely to be far more significant than those problems, of course. The GTK+ developers have made the necessary difficult compromises, knowing they’d have to live with some non-common-case disadvantages so that the common cases would be easier. Despite the difficulty they even left a way for you to do what you need (a custom treemodel) even if it isn’t incredibly easy. But you just decide to tell them that it’s useless.

    If they’d chosen your current priorities over those other priorities then you’d just flame them at some point for that instead. No API can please everyone all the time. This is one of the depressing things about maintaing widely-used projects – Somebody will attack you whichever choice you make, but those people lack the empathy to imagine what it would be like if they had to make the decision. We must demand better behaviour.

    This tendency to look at things in a binary way is a bit annoying to me. There’s no 0/1 value for “is not an iterator” or “is not useful” or “is not fast”. It all depends.

    The comment about higher level languages was just extra information that I thought you might find interesting because you are attempting to solve similar problems.

    Now back to details:
    > First comment part one: It could be adapted to let it return iterators. I
    > decided it would be more easy to let it return the value. It also saves me
    > a call to tny_iterator_iface_current to get the current value from that i
    > iterator. The model state isn’t changed. The iterator instance keeps a
    > state by itself.

    I guess I am just confused that the iterator doesn’s seem to be used in these functions at all. For instance,
    void (*prepend_func) (TnyListIface *self, gpointer item);

    But maybe I am looking in the wrong place.

  6. The GtkTreeModel would return one iterator GObject instance that is defined by an interface (a lot like how I’m using it in tinymail). This doesn’t influence the performance a lot (except for that first instantiation). In fact I am sorting and loading 20,000 items using the technique. This is more than the typical row-count a lot other projects use the GtkTreeView for.

    I also tested the same idea with 100,000 items (not real E-mail items, I don’t have a folder with that many messages). I didn’t experience any slowdowns while for example scrolling. I will soon test the idea with my 3,000,000 rows demo. You can search for the code of that demo in my blog. I’m almost certain it won’t slowdown the treeview scrolling.

    You talked about network latency: note that Camel keeps a cache of summary information on-disk and per loaded folder in memory. The network latency you might see is caused by refreshing the summary information of the CamelFolder. The performance measurements I do are without this network latency. So I first unplug my network and then measure. That way there’s no network latency involved. Showing headers is (for IMAP and NNTP mailboxes) reading things from memory and/or disk (and asking the service for added headers). For POP it’s indeed more often contacting the service. Surprisingly doesn’t the CamelFolder for POP implement summary support. I still have to check how to fix that and/or how Evolution does it.

    Try sorting in tinymail. If I would have to request the date-header of all messages in a 20,000 items folder, sorting would probably take a few days. Note that tinymail doesn’t yet sort by asking the service for a new (sorted) list. It manually sorts. So that is indeed the effective speed of iterating (using the TnyIteratorIface instance) over all 20,000 items (multiple times, depending on the sort algorithm implemented in your GtkTreeModelSort type).

    Note that there’s only one iterator instance and only if it’s needed. It’s not an iterator instance for each row or something like that. So there’s no significant GObject instantiation delay.

    The prepending of items is used in tny-msg-folder.c. Search for tny_list_iface_prepend (headers, header) in “add_message_with_uid”.

  7. Note that sorting a POP box in tinymail is, indeed, slow at this moment. This is because I’m to contacting the service for header information. Which I, indeed, shouldn’t do. As I said, I have to look at the Evolution implementation to fix this. When testing the sort speed, use IMAP or NNTP folders atm.

    Other than that, I’m planning to implement a custom sort model. So soon will sorting also be as fast as for example in Evolution. But that’s a different story (the sorting speed of IMAP folders atm proves the iterator performance).

  8. Oh I see, You wanted to know where the iterator is used: check out the file tny-msg-header-list-model.c (libtinymailui-gtk) which implements the custom tree model for the header summary view. All functionality related to iterating the list is moved to that implementation.

  9. > The GtkTreeModel would return one iterator GObject instance.

    That really isn’t like the general purpose iterators that we find in other languages and APIs, and this doesn’t seem to cover what GtkTreeIter offers. I’m sure it’s great for your purposes, but I’d find that API awkward if that’s all I had.

    You don’t need to persuade me that your system is fast. I didn’t mean to suggest that it isn’t. I just don’t think it’s the best choice for all the other uses of GtkTreeIter.

Comments are closed.