Showing a message once you have the header instance

Using the default message view components

The basic idea

Using the TnyFolder API tny_folder_get_msg you will get a TnyMsg instance and feed that to the default TnyGtkMsgView component or to your own TnyMsgView implementation.

Sample code

static void 
message_received (TnyFolder *folder, gboolean cancelled, TnyMsg *msg, GError *err, gpointer user_data)
{
	TnyMsgView *msg_view = user_data;
	if (msg)
		tny_msg_view_set_msg (msg_view, msg);
	g_object_unref (msg_view);
}

static void
on_status (GObject *sender, TnyStatus *status, gpointer user_data)
{
	return;
}

static void 
on_header_selected (GtkTreeSelection *selection, gpointer user_data)
{
  GtkTreeIter iter;
  GtkTreeModel *model;
  TnyMsgView *msg_view = user_data;

  if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
	TnyHeader *header;
	gtk_tree_model_get (model, &iter, 
		TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, 
		&header, -1);
	if (header) {
		TnyFolder *folder;
		folder = tny_header_get_folder (header);
		if (folder) {
			tny_folder_get_msg_async (folder, header, 
				message_received, on_status,
				g_object_ref (msg_view));
			g_object_unref (folder);
		}
		g_object_unref (header);
	}
  }
}

static void 
create_ui_in (GtkContainer *container)
{
+   TnyMsgView *msg_view = tny_gtk_msg_view_new ();
+   GtkTreeView *header_view = GTK_TREE_VIEW (gtk_tree_view_new ());
+   GtkTreeSelection *select;
    ...
+   renderer = gtk_cell_renderer_text_new ();
+   column = gtk_tree_view_column_new_with_attributes ("Subject",
+   	renderer, "text", TNY_GTK_HEADER_LIST_MODEL_SUBJECT_COLUMN,
+   	NULL);
+   gtk_tree_view_append_column (header_view, column);
+
+   select = gtk_tree_view_get_selection (header_view);
+   g_signal_connect (G_OBJECT (select), "changed",
+	G_CALLBACK (on_header_selected), msg_view);

    ...
    gtk_widget_show (GTK_WIDGET (msg_view));
    ...

    gtk_container_add (container, GTK_WIDGET (view));
}

More advanced

It's possible within the Tinymail framework to implement your own message -and mime part viewers. That way you can add support for a specific message format and for specific mime part formats.

You can improve or adjust existing support for certain formats. A good example is implementing a text/html mime part viewer or a iCal mime part viewer. You can, for example, replace it with one that integrates with the calendaring software that you ship on the device.

For more information about this, continue reading at the Implementing your own message view component pages.

I want the message in a new window

The Tinymail framework has an implementation of a TnyMsgView as a GtkWindow. In stead of TnyGtkMsgView you can also use TnyGtkMsgWindow. The window type also implements the TnyMsgView interface. Therefore other than the constructor (tny_gtk_msg_window_new in stead of tny_gtk_msg_view_new) and dealing with it just as how you would deal with any other GtkWindow, there are no differences.

The TnyGtkMsgWindow can decorate any TnyGtkMsgView or TnyMsgView that inherits GtkWidget (TnyGtkMsgView does this). This means that if your custom TnyMsgView inherits GtkWidget (so if it inherits TnyGtkMsgView for example), the TnyGtkMsgWindow can decorate it.

The constructor of TnyGtkMsgWindow accepts a TnyMsgView. Just pass your normal (non-window) TnyMsgView implementation. For example ask the platform factory for it (see below) or give it an instance of the TnyMsgView implementation that you want to use. In this sample that would be like this:

static void
emerge_msg_view_window (TnyMsgView *orig_view, TnyMsg *msg)
{
   TnyMsgWindow *msgw = tny_gtk_msg_window_new (orig_view);
   tny_msg_view_set_msg (msgw, msg);
   gtk_widget_show (GTK_WIDGET (msgw));
}

As you can see, you should not perform methods on the orig_view instance anymore. The msgw instance decorates the orig_view instance. Both implement the same TnyMsgView interface. The idea is indeed that you, once decorated, invoke methods on the decorator. If that sounds strange to you, check out the decorator design pattern.

The orig_view instance will be unreferenced with the destruction of the msgw instance and referenced at construction. Just like any other GtkWidget that was put in a GtkContainer (like what the GtkWindow is) within the gtk+ framework. This means that when the user closes the window, the orig_view instance will get unreferenced (and possibly cause of that destroyed too). I guess there is nothing unusual about this. I just mention it because else some people might wonder.

For example:

static void 
message_received (TnyFolder *folder, gboolean cancelled, TnyMsg *msg, GError *err, gpointer user_data)
{
	TnyMsgView *msg_view = user_data;
	if (msg) {
		TnyMsgWindow *msgw = tny_gtk_msg_window_new (msg_view);
		tny_msg_view_set_msg (msgw, msg);
		gtk_widget_show (GTK_WIDGET (msgw));
	}
	g_object_unref (msg_view);
}

In the demos you used a platform factory for getting an instance of a message viewer?

Yes, and this is the preferred way too. When implementing your platform factory, you must create an implementation for the method tny_platform_factory_new_msg_view. The idea is that you return a new instance of the TnyMsgView that you want to use. That can be your own implementation. For example one that you inherited from the default TnyGtkMsgView.

For documentation simplicity I decided to use the constructor of TnyGtkMsgView (tny_gtk_msg_view_new) in stead of the factory creation method here.

References to related other documentation