root/trunk/libtinymailui-gtk/tny-gtk-attach-list-model.c

Revision 3666 (checked in by jdapena, 7 months ago)

* Use GOnce registering all types in tinymail to make

registering thread-safe.

Line 
1 /* libtinymailui-gtk - The Tiny Mail UI library for Gtk+
2  * Copyright (C) 2006-2007 Philip Van Hoof <pvanhoof@gnome.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with self library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 /**
21  * TnyGtkAttachListModel:
22  *
23  * A #GtkTreeModel for #TnyMimePart instances that happen to be attachments too.
24  *
25  * Note that a #TnyGtkAttachListModel is a #TnyList too. You can use the
26  * #TnyList API on instances of this type too.
27  *
28  * Note that you must make sure that you unreference #TnyMimePart instances
29  * that you get out of the instance column of this type using the #GtkTreeModel
30  * API gtk_tree_model_get().
31  *
32  * free-function: g_object_unref
33  **/
34
35 #include <config.h>
36
37 #include <glib.h>
38 #include <gtk/gtk.h>
39
40 #ifdef GNOME
41 #include <libgnomeui/libgnomeui.h>
42 #endif
43
44 #include <tny-gtk-attach-list-model.h>
45 #include <tny-mime-part.h>
46 #include <tny-iterator.h>
47 #include <tny-mime-part.h>
48 #include <tny-folder.h>
49
50 #include "tny-gtk-attach-list-model-priv.h"
51 #include "tny-gtk-attach-list-model-iterator-priv.h"
52
53
54 static GObjectClass *parent_class = NULL;
55
56
57 #define TNY_GTK_ATTACH_LIST_MODEL_GET_PRIVATE(o)        \
58         (G_TYPE_INSTANCE_GET_PRIVATE ((o), TNY_TYPE_GTK_ATTACH_LIST_MODEL, TnyGtkAttachListModelPriv))
59
60 typedef void (*listaddfunc) (GtkListStore *list_store, GtkTreeIter *iter);
61
62 static void
63 tny_gtk_attach_list_model_add (TnyGtkAttachListModel *self, TnyMimePart *part, listaddfunc func)
64 {
65         GtkListStore *model = GTK_LIST_STORE (self);
66         GtkTreeIter iter;
67         TnyGtkAttachListModelPriv *priv = TNY_GTK_ATTACH_LIST_MODEL_GET_PRIVATE (self);
68         static GdkPixbuf *stock_file_pixbuf = NULL;
69         GdkPixbuf *pixbuf;
70         gchar *icon;
71
72         if (tny_mime_part_get_content_type (part) &&
73                         tny_mime_part_is_attachment (part))
74         {
75
76                 if (!priv->theme || !GTK_IS_ICON_THEME (priv->theme))
77                 {
78                         priv->theme = gtk_icon_theme_get_default ();
79                         g_object_ref (priv->theme);
80                 }
81
82 #ifdef GNOME
83                 if (priv->theme && GTK_IS_ICON_THEME (priv->theme))
84                 {
85                         icon = gnome_icon_lookup (priv->theme, NULL,
86                                 tny_mime_part_get_filename (part), NULL, NULL,
87                                 tny_mime_part_get_content_type (part), 0, NULL);
88                 }
89 #else
90                 icon = GTK_STOCK_FILE;
91 #endif
92
93                 if (G_LIKELY (icon) && priv->theme && GTK_IS_ICON_THEME (priv->theme))
94                 {
95                         pixbuf = gtk_icon_theme_load_icon (priv->theme, icon,
96                                 GTK_ICON_SIZE_LARGE_TOOLBAR, 0, NULL);
97 #ifdef GNOME
98                         g_free (icon);
99 #endif
100                 } else {
101                         if (G_UNLIKELY (!stock_file_pixbuf) && priv->theme && GTK_IS_ICON_THEME (priv->theme))
102                                 stock_file_pixbuf = gtk_icon_theme_load_icon (priv->theme,
103                                         GTK_STOCK_FILE, GTK_ICON_SIZE_LARGE_TOOLBAR,
104                                         0, NULL);
105
106                         pixbuf = stock_file_pixbuf;
107                 }
108
109                 func (model, &iter);
110
111                 gtk_list_store_set (model, &iter,
112                         TNY_GTK_ATTACH_LIST_MODEL_PIXBUF_COLUMN,
113                         pixbuf,
114                         TNY_GTK_ATTACH_LIST_MODEL_FILENAME_COLUMN,
115                         tny_mime_part_get_filename (part),
116                         TNY_GTK_ATTACH_LIST_MODEL_INSTANCE_COLUMN,
117                         part, -1);
118         } else {
119
120                 func (model, &iter);
121
122                 gtk_list_store_set (model, &iter,
123                         TNY_GTK_ATTACH_LIST_MODEL_FILENAME_COLUMN,
124                         tny_mime_part_get_description (part)?
125                                 tny_mime_part_get_description (part):
126                                 "Unknown attachment",
127                         TNY_GTK_ATTACH_LIST_MODEL_INSTANCE_COLUMN,
128                         part, -1);
129         }
130
131         return;
132 }
133
134
135 /**
136  * tny_gtk_attach_list_model_new:
137  *
138  * Get a new #GtkTreeModel for #TnyMimePart instances that are attachments.
139  *
140  * returns: (caller-owns) a new #GtkTreeModel #TnyMimePart instances
141  * since: 1.0
142  * audience: application-developer
143  **/
144 GtkTreeModel*
145 tny_gtk_attach_list_model_new (void)
146 {
147         TnyGtkAttachListModel *self = g_object_new (TNY_TYPE_GTK_ATTACH_LIST_MODEL, NULL);
148
149         return GTK_TREE_MODEL (self);
150 }
151
152 static void
153 tny_gtk_attach_list_model_finalize (GObject *object)
154 {
155         TnyGtkAttachListModelPriv *priv = TNY_GTK_ATTACH_LIST_MODEL_GET_PRIVATE (object);
156         TnyGtkAttachListModel *me = (TnyGtkAttachListModel*) object;
157
158         g_mutex_lock (me->iterator_lock);
159         if (me->first) {
160                 if (me->first_needs_unref)
161                         g_list_foreach (me->first, (GFunc)g_object_unref, NULL);
162                 me->first_needs_unref = FALSE;
163                 g_list_free (me->first);
164         }
165         me->first = NULL;
166         g_mutex_unlock (me->iterator_lock);
167
168         g_mutex_free (me->iterator_lock);
169         me->iterator_lock = NULL;
170
171         if (priv->theme)
172                 g_object_unref (G_OBJECT (priv->theme));
173
174         (*parent_class->finalize) (object);
175 }
176
177 static void
178 tny_gtk_attach_list_model_class_init (TnyGtkAttachListModelClass *class)
179 {
180         GObjectClass *object_class;
181
182         parent_class = g_type_class_peek_parent (class);
183         object_class = (GObjectClass*) class;
184
185         object_class->finalize = tny_gtk_attach_list_model_finalize;
186
187         g_type_class_add_private (object_class, sizeof (TnyGtkAttachListModelPriv));
188
189         return;
190 }
191
192 static void
193 tny_gtk_attach_list_model_instance_init (GTypeInstance *instance, gpointer g_class)
194 {
195         GtkListStore *store = (GtkListStore*) instance;
196         TnyGtkAttachListModel *me = (TnyGtkAttachListModel*) instance;
197         TnyGtkAttachListModelPriv *priv = TNY_GTK_ATTACH_LIST_MODEL_GET_PRIVATE (instance);
198         static GType types[] = { G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_OBJECT };
199
200
201         priv->theme = NULL;
202         types[0] = GDK_TYPE_PIXBUF;
203         me->iterator_lock = g_mutex_new ();
204         me->first = NULL;
205         me->first_needs_unref = FALSE;
206
207         gtk_list_store_set_column_types (store,
208                 TNY_GTK_ATTACH_LIST_MODEL_N_COLUMNS, types);
209
210         return;
211 }
212
213 static TnyIterator*
214 tny_gtk_attach_list_model_create_iterator (TnyList *self)
215 {
216         TnyGtkAttachListModel *me = (TnyGtkAttachListModel*)self;
217
218         /* Return a new iterator */
219
220         return TNY_ITERATOR (_tny_gtk_attach_list_model_iterator_new (me));
221 }
222
223
224
225 static void
226 tny_gtk_attach_list_model_prepend (TnyList *self, GObject* item)
227 {
228         TnyGtkAttachListModel *me = (TnyGtkAttachListModel*)self;
229
230         g_mutex_lock (me->iterator_lock);
231
232         /* Prepend something to the list */
233
234         tny_gtk_attach_list_model_add (me, TNY_MIME_PART (item),
235                 gtk_list_store_prepend);
236
237         me->first = g_list_prepend (me->first, item);
238
239         g_mutex_unlock (me->iterator_lock);
240 }
241
242 static void
243 tny_gtk_attach_list_model_append (TnyList *self, GObject* item)
244 {
245         TnyGtkAttachListModel *me = (TnyGtkAttachListModel*)self;
246
247         g_mutex_lock (me->iterator_lock);
248
249         /* Append something to the list */
250
251         tny_gtk_attach_list_model_add (me, TNY_MIME_PART (item),
252                 gtk_list_store_append);
253         me->first = g_list_append (me->first, item);
254
255         g_mutex_unlock (me->iterator_lock);
256 }
257
258 static guint
259 tny_gtk_attach_list_model_get_length (TnyList *self)
260 {
261         TnyGtkAttachListModel *me = (TnyGtkAttachListModel*)self;
262         guint retval = 0;
263
264         g_mutex_lock (me->iterator_lock);
265
266         retval = me->first?g_list_length (me->first):0;
267
268         g_mutex_unlock (me->iterator_lock);
269
270         return retval;
271 }
272
273 static void
274 tny_gtk_attach_list_model_remove (TnyList *self, GObject* item)
275 {
276         TnyGtkAttachListModel *me = (TnyGtkAttachListModel*)self;
277         GtkTreeModel *model = GTK_TREE_MODEL (me);
278         GtkTreeIter iter;
279
280         g_return_if_fail (G_IS_OBJECT (item));
281         g_return_if_fail (G_IS_OBJECT (me));
282
283         /* Remove something from the list */
284
285         g_mutex_lock (me->iterator_lock);
286
287         me->first = g_list_remove (me->first, (gconstpointer)item);
288
289         if (gtk_tree_model_get_iter_first (model, &iter))
290           do
291           {
292                 GObject *citem;
293
294                 gtk_tree_model_get (model, &iter,
295                         TNY_GTK_ATTACH_LIST_MODEL_INSTANCE_COLUMN,
296                         &citem, -1);
297
298                 if (citem == item)
299                 {
300                         gtk_list_store_remove (GTK_LIST_STORE (me), &iter);
301                         g_object_unref (item);
302                         break;
303                 }
304                 g_object_unref (citem);
305           } while (gtk_tree_model_iter_next (model, &iter));
306
307         g_mutex_unlock (me->iterator_lock);
308 }
309
310
311 static TnyList*
312 tny_gtk_attach_list_model_copy_the_list (TnyList *self)
313 {
314         TnyGtkAttachListModel *me = (TnyGtkAttachListModel*)self;
315         TnyGtkAttachListModel *copy = g_object_new (TNY_TYPE_GTK_ATTACH_LIST_MODEL, NULL);
316         GList *list_copy = NULL;
317
318         /* This only copies the TnyList pieces. The result is not a
319            correct or good TnyHeaderListModel. But it will be a correct
320            TnyList instance. It is the only thing the user of this
321            method expects.
322
323            The new list will point to the same instances, of course. It's
324            only a copy of the list-nodes of course. */
325
326         g_mutex_lock (me->iterator_lock);
327         list_copy = g_list_copy (me->first);
328         g_list_foreach (list_copy, (GFunc)g_object_ref, NULL);
329         copy->first_needs_unref = TRUE;
330         copy->first = list_copy;
331         g_mutex_unlock (me->iterator_lock);
332
333         return TNY_LIST (copy);
334 }
335
336 static void
337 tny_gtk_attach_list_model_foreach_in_the_list (TnyList *self, GFunc func, gpointer user_data)
338 {
339         TnyGtkAttachListModel *me = (TnyGtkAttachListModel*)self;
340
341         /* Foreach item in the list (without using a slower iterator) */
342
343         g_mutex_lock (me->iterator_lock);
344         g_list_foreach (me->first, func, user_data);
345         g_mutex_unlock (me->iterator_lock);
346
347         return;
348 }
349
350 static void
351 tny_list_init (TnyListIface *klass)
352 {
353         klass->get_length= tny_gtk_attach_list_model_get_length;
354         klass->prepend= tny_gtk_attach_list_model_prepend;
355         klass->append= tny_gtk_attach_list_model_append;
356         klass->remove= tny_gtk_attach_list_model_remove;
357         klass->create_iterator= tny_gtk_attach_list_model_create_iterator;
358         klass->copy= tny_gtk_attach_list_model_copy_the_list;
359         klass->foreach= tny_gtk_attach_list_model_foreach_in_the_list;
360
361         return;
362 }
363
364 static gpointer
365 tny_gtk_attach_list_model_register_type (gpointer notused)
366 {
367         GType type = 0;
368
369         static const GTypeInfo info =
370                 {
371                   sizeof (TnyGtkAttachListModelClass),
372                   NULL,   /* base_init */
373                   NULL,   /* base_finalize */
374                   (GClassInitFunc) tny_gtk_attach_list_model_class_init,   /* class_init */
375                   NULL,   /* class_finalize */
376                   NULL,   /* class_data */
377                   sizeof (TnyGtkAttachListModel),
378                   0,      /* n_preallocs */
379                   tny_gtk_attach_list_model_instance_init,    /* instance_init */
380                   NULL
381                 };
382
383
384         static const GInterfaceInfo tny_list_info = {
385                 (GInterfaceInitFunc) tny_list_init,
386                 NULL,
387                 NULL
388         };
389
390         type = g_type_register_static (GTK_TYPE_LIST_STORE, "TnyGtkAttachListModel",
391                                        &info, 0);
392
393         g_type_add_interface_static (type, TNY_TYPE_LIST,
394                                      &tny_list_info);
395
396         return GUINT_TO_POINTER (type);
397 }
398
399 /**
400  * tny_gtk_attach_list_model_get_type:
401  *
402  * GType system helper function
403  *
404  * returns: a #GType
405  **/
406 GType
407 tny_gtk_attach_list_model_get_type (void)
408 {
409         static GOnce once = G_ONCE_INIT;
410         g_once (&once, tny_gtk_attach_list_model_register_type, NULL);
411         return GPOINTER_TO_UINT (once.retval);
412 }
413
414 static gpointer
415 tny_gtk_attach_list_model_column_register_type (gpointer notused)
416 {
417   GType etype = 0;
418   static const GEnumValue values[] = {
419       { TNY_GTK_ATTACH_LIST_MODEL_PIXBUF_COLUMN, "TNY_GTK_ATTACH_LIST_MODEL_PIXBUF_COLUMN", "pixbuf" },
420       { TNY_GTK_ATTACH_LIST_MODEL_FILENAME_COLUMN, "TNY_GTK_ATTACH_LIST_MODEL_FILENAME_COLUMN", "filename" },
421       { TNY_GTK_ATTACH_LIST_MODEL_INSTANCE_COLUMN, "TNY_GTK_ATTACH_LIST_MODEL_INSTANCE_COLUMN", "instance" },
422       { TNY_GTK_ATTACH_LIST_MODEL_N_COLUMNS, "TNY_GTK_ATTACH_LIST_MODEL_N_COLUMNS", "n" },
423       { 0, NULL, NULL }
424   };
425   etype = g_enum_register_static ("TnyGtkAttachListModelColumn", values);
426   return GUINT_TO_POINTER (etype);
427 }
428
429 /**
430  * tny_gtk_attach_list_model_column_get_type:
431  *
432  * GType system helper function
433  *
434  * returns: a #GType
435  **/
436 GType
437 tny_gtk_attach_list_model_column_get_type (void)
438 {
439         static GOnce once = G_ONCE_INIT;
440         g_once (&once, tny_gtk_attach_list_model_column_register_type, NULL);
441         return GPOINTER_TO_UINT (once.retval);
442 }
Note: See TracBrowser for help on using the browser.