* implement icons in the folder view
[modest] / src / modest-tny-folder-tree-view.c
1 /* modest-tny-folder-tree-view.c */
2
3 /* insert (c)/licensing information) */
4 #include <glib/gi18n.h>
5
6 #include <tny-account-tree-model.h>
7 #include <tny-account-store-iface.h>
8 #include <tny-account-iface.h>
9 #include <tny-msg-folder-iface.h>
10 #include <tny-summary-window-iface.h>
11
12 #include "modest-tny-folder-tree-view.h"
13
14 #include <modest-icon-names.h>
15 #include "modest-icon-factory.h"
16
17
18 /* 'private'/'protected' functions */
19 static void modest_tny_folder_tree_view_class_init  (ModestTnyFolderTreeViewClass *klass);
20 static void modest_tny_folder_tree_view_init        (ModestTnyFolderTreeView *obj);
21 static void modest_tny_folder_tree_view_finalize    (GObject *obj);
22
23 //static void modest_tny_folder_tree_view_iface_init   (gpointer iface, gpointer data);
24 static void modest_tny_folder_tree_view_set_account_store (TnySummaryWindowIface *self,
25                                                            TnyAccountStoreIface *account_store);
26 static gboolean update_model (ModestTnyFolderTreeView *self,TnyAccountStoreIface *iface);
27 static gboolean update_model_empty (ModestTnyFolderTreeView *self);
28
29 static void selection_changed (GtkTreeSelection *sel, gpointer data);
30
31 enum {
32         FOLDER_SELECTED_SIGNAL,
33         LAST_SIGNAL
34 };
35
36 typedef struct _ModestTnyFolderTreeViewPrivate ModestTnyFolderTreeViewPrivate;
37 struct _ModestTnyFolderTreeViewPrivate {
38         TnyAccountStoreIface *tny_account_store;
39         gboolean view_is_empty;
40 };
41 #define MODEST_TNY_FOLDER_TREE_VIEW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
42                                                          MODEST_TYPE_TNY_FOLDER_TREE_VIEW, \
43                                                          ModestTnyFolderTreeViewPrivate))
44 /* globals */
45 static GObjectClass *parent_class = NULL;
46
47 static guint signals[LAST_SIGNAL] = {0}; 
48
49 GType
50 modest_tny_folder_tree_view_get_type (void)
51 {
52         static GType my_type = 0;
53         if (!my_type) {
54                 static const GTypeInfo my_info = {
55                         sizeof(ModestTnyFolderTreeViewClass),
56                         NULL,           /* base init */
57                         NULL,           /* base finalize */
58                         (GClassInitFunc) modest_tny_folder_tree_view_class_init,
59                         NULL,           /* class finalize */
60                         NULL,           /* class data */
61                         sizeof(ModestTnyFolderTreeView),
62                         1,              /* n_preallocs */
63                         (GInstanceInitFunc) modest_tny_folder_tree_view_init,
64                 };
65                                 
66                 my_type = g_type_register_static (GTK_TYPE_TREE_VIEW,
67                                                   "ModestTnyFolderTreeView",
68                                                   &my_info, 0);         
69         }
70         return my_type;
71 }
72
73 static void
74 modest_tny_folder_tree_view_class_init (ModestTnyFolderTreeViewClass *klass)
75 {
76         GObjectClass *gobject_class;
77         gobject_class = (GObjectClass*) klass;
78
79         parent_class            = g_type_class_peek_parent (klass);
80         gobject_class->finalize = modest_tny_folder_tree_view_finalize;
81
82         g_type_class_add_private (gobject_class,
83                                   sizeof(ModestTnyFolderTreeViewPrivate));
84         
85         signals[FOLDER_SELECTED_SIGNAL] = 
86                 g_signal_new ("folder_selected",
87                               G_TYPE_FROM_CLASS (gobject_class),
88                               G_SIGNAL_RUN_FIRST,
89                               G_STRUCT_OFFSET (ModestTnyFolderTreeViewClass,folder_selected),
90                               NULL, NULL,
91                               g_cclosure_marshal_VOID__POINTER,
92                               G_TYPE_NONE, 1, G_TYPE_POINTER); 
93 }
94
95
96
97 static void
98 text_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
99                    GtkTreeModel *tree_model,  GtkTreeIter *iter,  gpointer data)
100 {
101         GObject *rendobj;
102         gchar *fname;
103         gchar *type_name;
104         guint unread;
105         TnyMsgFolderType type;
106         
107         gtk_tree_model_get (tree_model, iter,
108                             TNY_ACCOUNT_TREE_MODEL_NAME_COLUMN, &fname,
109                             TNY_ACCOUNT_TREE_MODEL_TYPE_COLUMN, &type,
110                             TNY_ACCOUNT_TREE_MODEL_UNREAD_COLUMN, &unread, -1);
111         rendobj = G_OBJECT(renderer);
112
113         if (unread > 0) {
114                 gchar *folder_title = g_strdup_printf ("%s (%d)", fname, unread);
115                 g_object_set (rendobj,"text", folder_title,  "weight", 800, NULL);
116                 g_free (folder_title);
117         } else 
118                 g_object_set (rendobj,"text", fname, "weight", 400, NULL);
119                 
120         g_free (fname);
121 }
122
123
124 static void
125 icon_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
126                  GtkTreeModel *tree_model,  GtkTreeIter *iter, gpointer data)
127 {
128         GObject *rendobj;
129         GdkPixbuf *pixbuf;
130         TnyMsgFolderType type;
131         int unread;
132         
133         rendobj = G_OBJECT(renderer);
134         gtk_tree_model_get (tree_model, iter,
135                             TNY_ACCOUNT_TREE_MODEL_TYPE_COLUMN, &type,
136                             TNY_ACCOUNT_TREE_MODEL_UNREAD_COLUMN, &unread, -1);
137         rendobj = G_OBJECT(renderer);
138
139         switch (type) {
140         case TNY_MSG_FOLDER_TYPE_INBOX:
141                 pixbuf = modest_icon_factory_get_icon (MODEST_FOLDER_ICON_INBOX);
142                 break;
143         case TNY_MSG_FOLDER_TYPE_OUTBOX:
144                 pixbuf = modest_icon_factory_get_icon (MODEST_FOLDER_ICON_OUTBOX);
145                 break;
146         case TNY_MSG_FOLDER_TYPE_JUNK:
147                 pixbuf = modest_icon_factory_get_icon (MODEST_FOLDER_ICON_JUNK);
148                 break;
149         case TNY_MSG_FOLDER_TYPE_SENT:
150                 pixbuf = modest_icon_factory_get_icon (MODEST_FOLDER_ICON_SENT);
151                 break;
152         case TNY_MSG_FOLDER_TYPE_NORMAL:
153         default:
154                 pixbuf = modest_icon_factory_get_icon (MODEST_FOLDER_ICON_NORMAL);
155                 break;
156         }
157
158         g_object_set (rendobj,
159                       "pixbuf-expander-open",
160                       modest_icon_factory_get_icon (MODEST_FOLDER_ICON_OPEN),
161                       "pixbuf-expander-closed",
162                       modest_icon_factory_get_icon (MODEST_FOLDER_ICON_CLOSED),
163                       "pixbuf", pixbuf,
164                       NULL);
165 }
166
167 static void
168 modest_tny_folder_tree_view_init (ModestTnyFolderTreeView *obj)
169 {
170         ModestTnyFolderTreeViewPrivate *priv;
171         GtkTreeViewColumn *column;
172         GtkCellRenderer *renderer;
173         GtkTreeSelection *sel;
174         
175         priv =  MODEST_TNY_FOLDER_TREE_VIEW_GET_PRIVATE(obj);
176         
177         priv->view_is_empty     = TRUE;
178         priv->tny_account_store = NULL;
179
180         column = gtk_tree_view_column_new ();
181         gtk_tree_view_column_set_title (column,
182                                         _("All Mail Folders"));
183         
184         gtk_tree_view_append_column (GTK_TREE_VIEW(obj),
185                                      column);
186         
187         renderer = gtk_cell_renderer_pixbuf_new();
188         gtk_tree_view_column_pack_start (column, renderer, FALSE);
189         gtk_tree_view_column_set_cell_data_func(column, renderer,
190                                                 icon_cell_data, NULL, NULL);
191         
192         renderer = gtk_cell_renderer_text_new();
193         gtk_tree_view_column_pack_start (column, renderer, FALSE);
194         gtk_tree_view_column_set_cell_data_func(column, renderer,
195                                                 text_cell_data, NULL, NULL);
196         
197         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW(obj));
198         gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE);
199
200         gtk_tree_view_column_set_spacing (column, 2);
201         gtk_tree_view_column_set_resizable (column, TRUE);
202         gtk_tree_view_column_set_fixed_width (column, TRUE);            
203         gtk_tree_view_set_headers_visible   (GTK_TREE_VIEW(obj), TRUE);
204         gtk_tree_view_set_headers_clickable (GTK_TREE_VIEW(obj), FALSE);
205
206 }
207
208
209 static void
210 modest_tny_folder_tree_view_finalize (GObject *obj)
211 {
212         int i;
213         ModestTnyFolderTreeViewPrivate *priv;
214
215         g_return_if_fail (obj);
216         
217         priv =  MODEST_TNY_FOLDER_TREE_VIEW_GET_PRIVATE(obj);
218         if (priv->tny_account_store) {
219                 g_object_unref (G_OBJECT(priv->tny_account_store));
220                 priv->tny_account_store = NULL;
221         }
222
223         (*parent_class->finalize)(obj);
224 }
225
226
227 static void
228 modest_tny_folder_tree_view_set_account_store (TnySummaryWindowIface *self,
229                                                TnyAccountStoreIface *account_store)
230 {
231         ModestTnyFolderTreeViewPrivate *priv;
232
233         g_return_if_fail (self);
234         g_return_if_fail (account_store);
235         
236         priv = MODEST_TNY_FOLDER_TREE_VIEW_GET_PRIVATE(self);
237         if (priv->tny_account_store) {
238                 g_object_unref (priv->tny_account_store);
239                 priv->tny_account_store = NULL;
240         }
241
242         g_object_ref (G_OBJECT(priv->tny_account_store = account_store));
243 }
244
245
246
247 GtkWidget*
248 modest_tny_folder_tree_view_new (TnyAccountStoreIface *iface)
249 {
250         GObject *self;
251         ModestTnyFolderTreeViewPrivate *priv;
252         GtkTreeSelection *sel;
253
254         self = G_OBJECT(g_object_new(MODEST_TYPE_TNY_FOLDER_TREE_VIEW, NULL));
255         priv = MODEST_TNY_FOLDER_TREE_VIEW_GET_PRIVATE(self);
256
257         g_return_val_if_fail (iface, NULL);
258         
259         if (!update_model (MODEST_TNY_FOLDER_TREE_VIEW(self), iface))
260                 g_warning ("failed or update model");
261
262         sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(self));
263         g_signal_connect (sel, "changed",
264                           G_CALLBACK(selection_changed), self);
265                 
266         return GTK_WIDGET(self);
267 }
268
269
270
271
272 static gboolean
273 update_model_empty (ModestTnyFolderTreeView *self)
274 {
275         GtkTreeIter  iter;
276         GtkTreeStore *store;
277         ModestTnyFolderTreeViewPrivate *priv;
278         
279         g_return_val_if_fail (self, FALSE);
280         
281         store = gtk_tree_store_new (1, G_TYPE_STRING);
282         gtk_tree_store_append (store, &iter, NULL);
283
284         gtk_tree_store_set (store, &iter, 0,
285                             _("(empty)"), -1);
286
287         gtk_tree_view_set_model (GTK_TREE_VIEW(self),
288                                  GTK_TREE_MODEL(store));
289         g_object_unref (store);
290
291         priv = MODEST_TNY_FOLDER_TREE_VIEW_GET_PRIVATE(self);
292         priv->view_is_empty = TRUE;
293         
294         return TRUE;
295 }
296
297
298 static gboolean
299 update_model (ModestTnyFolderTreeView *self,TnyAccountStoreIface *iface)
300 {
301         const GList *accounts;
302         TnyAccountTreeModel *folder_model;
303         ModestTnyFolderTreeViewPrivate *priv;
304                 
305         g_return_val_if_fail (iface, FALSE);
306
307         priv =  MODEST_TNY_FOLDER_TREE_VIEW_GET_PRIVATE(self);
308         priv->view_is_empty = TRUE;
309
310         accounts = tny_account_store_iface_get_store_accounts (iface);
311         if (!accounts) {
312                 g_warning ("no accounts have been defined yet");
313                 return update_model_empty (self);
314         }
315         
316         folder_model = tny_account_tree_model_new ();
317         if (!folder_model) {
318                 g_warning ("failed to get account tree model");
319                 return update_model_empty (self);
320         }
321         
322         while (accounts) {
323                 TnyStoreAccountIface *account =
324                         TNY_STORE_ACCOUNT_IFACE(accounts->data);
325                 if (!account) {
326                         g_warning ("invalid account");
327                         g_object_unref (folder_model);
328                         return update_model_empty (self);
329                 }
330                 tny_account_tree_model_add (TNY_ACCOUNT_TREE_MODEL (folder_model),
331                                             account);
332                 accounts = accounts->next;
333         }
334         
335         gtk_tree_view_set_model (GTK_TREE_VIEW(self),
336                                  GTK_TREE_MODEL(folder_model)); 
337         g_object_unref (G_OBJECT(folder_model));
338         
339         priv->view_is_empty = FALSE; /* were not empty anymore! */
340         return TRUE;
341 }
342
343
344 void
345 selection_changed (GtkTreeSelection *sel, gpointer user_data)
346 {
347         GtkTreeModel            *model;
348         TnyMsgFolderIface       *folder = NULL;
349         GtkTreeIter             iter;
350         ModestTnyFolderTreeView *tree_view;
351         ModestTnyFolderTreeViewPrivate *priv;
352
353         g_return_if_fail (sel);
354         g_return_if_fail (user_data);
355
356         priv = MODEST_TNY_FOLDER_TREE_VIEW_GET_PRIVATE(user_data);
357
358         /* is_empty means that there is only the 'empty' item */
359         if (priv->view_is_empty)
360                 return;
361         
362         if (!gtk_tree_selection_get_selected (sel, &model, &iter))
363                 return; /* folder was _un_selected */
364
365         tree_view = MODEST_TNY_FOLDER_TREE_VIEW (user_data);
366
367         gtk_tree_model_get (model, &iter,
368                             TNY_ACCOUNT_TREE_MODEL_INSTANCE_COLUMN,
369                             &folder, -1);
370         
371         /* folder will not be defined if you click eg. on the root node */
372         if (folder)
373                 g_signal_emit (G_OBJECT(tree_view), signals[FOLDER_SELECTED_SIGNAL], 0,
374                                folder);
375 }
376
377
378
379