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