PageRenderTime 75ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/evolution-3.5.4/widgets/misc/e-picture-gallery.c

#
C | 434 lines | 327 code | 85 blank | 22 comment | 53 complexity | 4d7273cb43cf40eaa26801b8458460fd MD5 | raw file
Possible License(s): LGPL-2.1, LGPL-3.0, MPL-2.0-no-copyleft-exception
  1. /*
  2. * e-picture-gallery.c
  3. *
  4. * This program 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) version 3.
  8. *
  9. * This program 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 the program; if not, see <http://www.gnu.org/licenses/>
  16. *
  17. *
  18. * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  19. *
  20. */
  21. #ifdef HAVE_CONFIG_H
  22. #include <config.h>
  23. #endif
  24. #include "e-util/e-icon-factory.h"
  25. #include "e-picture-gallery.h"
  26. #define E_PICTURE_GALLERY_GET_PRIVATE(obj) \
  27. (G_TYPE_INSTANCE_GET_PRIVATE \
  28. ((obj), E_TYPE_PICTURE_GALLERY, EPictureGalleryPrivate))
  29. struct _EPictureGalleryPrivate {
  30. gboolean initialized;
  31. gchar *path;
  32. GFileMonitor *monitor;
  33. };
  34. enum {
  35. PROP_0,
  36. PROP_PATH
  37. };
  38. enum {
  39. COL_PIXBUF = 0,
  40. COL_URI,
  41. COL_FILENAME_TEXT
  42. };
  43. G_DEFINE_TYPE (EPictureGallery, e_picture_gallery, GTK_TYPE_ICON_VIEW)
  44. static gboolean
  45. update_file_iter (GtkListStore *list_store,
  46. GtkTreeIter *iter,
  47. GFile *file,
  48. gboolean force_thumbnail_update)
  49. {
  50. GFileInfo *file_info;
  51. gchar *uri;
  52. gboolean res = FALSE;
  53. g_return_val_if_fail (list_store != NULL, FALSE);
  54. g_return_val_if_fail (iter != NULL, FALSE);
  55. g_return_val_if_fail (file != NULL, FALSE);
  56. uri = g_file_get_uri (file);
  57. file_info = g_file_query_info (file,
  58. G_FILE_ATTRIBUTE_THUMBNAIL_PATH ","
  59. G_FILE_ATTRIBUTE_THUMBNAILING_FAILED ","
  60. G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME ","
  61. G_FILE_ATTRIBUTE_STANDARD_SIZE,
  62. G_FILE_QUERY_INFO_NONE,
  63. NULL,
  64. NULL);
  65. if (file_info != NULL) {
  66. const gchar *existing_thumb = g_file_info_get_attribute_byte_string (file_info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH);
  67. gchar *new_thumb = NULL;
  68. if (!existing_thumb || force_thumbnail_update) {
  69. gchar *filename;
  70. filename = g_file_get_path (file);
  71. if (filename) {
  72. new_thumb = e_icon_factory_create_thumbnail (filename);
  73. if (new_thumb)
  74. existing_thumb = new_thumb;
  75. g_free (filename);
  76. }
  77. }
  78. if (existing_thumb && !g_file_info_get_attribute_boolean (file_info, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED)) {
  79. GdkPixbuf * pixbuf;
  80. pixbuf = gdk_pixbuf_new_from_file (existing_thumb, NULL);
  81. if (pixbuf) {
  82. const gchar *filename;
  83. gchar *filename_text = NULL;
  84. guint64 filesize;
  85. filename = g_file_info_get_attribute_string (file_info, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME);
  86. if (filename) {
  87. filesize = g_file_info_get_attribute_uint64 (file_info, G_FILE_ATTRIBUTE_STANDARD_SIZE);
  88. if (filesize) {
  89. gchar *tmp = g_format_size_for_display ((goffset) filesize);
  90. filename_text = g_strdup_printf ("%s (%s)", filename, tmp);
  91. g_free (tmp);
  92. }
  93. res = TRUE;
  94. gtk_list_store_set (list_store, iter,
  95. COL_PIXBUF, pixbuf,
  96. COL_URI, uri,
  97. COL_FILENAME_TEXT, filename_text ? filename_text : filename,
  98. -1);
  99. }
  100. g_object_unref (pixbuf);
  101. g_free (filename_text);
  102. }
  103. }
  104. g_free (new_thumb);
  105. }
  106. g_free (uri);
  107. return res;
  108. }
  109. static void
  110. add_file (GtkListStore *list_store,
  111. GFile *file)
  112. {
  113. GtkTreeIter iter;
  114. g_return_if_fail (list_store != NULL);
  115. g_return_if_fail (file != NULL);
  116. gtk_list_store_append (list_store, &iter);
  117. if (!update_file_iter (list_store, &iter, file, FALSE))
  118. gtk_list_store_remove (list_store, &iter);
  119. }
  120. static gboolean
  121. find_file_uri (GtkListStore *list_store,
  122. const gchar *uri,
  123. GtkTreeIter *iter)
  124. {
  125. GtkTreeModel *model;
  126. g_return_val_if_fail (list_store != NULL, FALSE);
  127. g_return_val_if_fail (uri != NULL, FALSE);
  128. g_return_val_if_fail (iter != NULL, FALSE);
  129. model = GTK_TREE_MODEL (list_store);
  130. g_return_val_if_fail (model != NULL, FALSE);
  131. if (!gtk_tree_model_get_iter_first (model, iter))
  132. return FALSE;
  133. do {
  134. gchar *iter_uri = NULL;
  135. gtk_tree_model_get (model, iter,
  136. COL_URI, &iter_uri,
  137. -1);
  138. if (iter_uri && g_ascii_strcasecmp (uri, iter_uri) == 0) {
  139. g_free (iter_uri);
  140. return TRUE;
  141. }
  142. g_free (iter_uri);
  143. } while (gtk_tree_model_iter_next (model, iter));
  144. return FALSE;
  145. }
  146. static void
  147. picture_gallery_dir_changed_cb (GFileMonitor *monitor,
  148. GFile *file,
  149. GFile *other_file,
  150. GFileMonitorEvent event_type,
  151. EPictureGallery *gallery)
  152. {
  153. gchar *uri;
  154. GtkListStore *list_store;
  155. GtkTreeIter iter;
  156. g_return_if_fail (file != NULL);
  157. list_store = GTK_LIST_STORE (gtk_icon_view_get_model (GTK_ICON_VIEW (gallery)));
  158. g_return_if_fail (list_store != NULL);
  159. uri = g_file_get_uri (file);
  160. if (!uri)
  161. return;
  162. switch (event_type) {
  163. case G_FILE_MONITOR_EVENT_CREATED:
  164. if (find_file_uri (list_store, uri, &iter)) {
  165. if (!update_file_iter (list_store, &iter, file, TRUE))
  166. gtk_list_store_remove (list_store, &iter);
  167. } else {
  168. add_file (list_store, file);
  169. }
  170. break;
  171. case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
  172. if (find_file_uri (list_store, uri, &iter)) {
  173. if (!update_file_iter (list_store, &iter, file, TRUE))
  174. gtk_list_store_remove (list_store, &iter);
  175. }
  176. break;
  177. case G_FILE_MONITOR_EVENT_DELETED:
  178. if (find_file_uri (list_store, uri, &iter))
  179. gtk_list_store_remove (list_store, &iter);
  180. break;
  181. default:
  182. break;
  183. }
  184. g_free (uri);
  185. }
  186. static gboolean
  187. picture_gallery_start_loading_cb (EPictureGallery *gallery)
  188. {
  189. GtkIconView *icon_view;
  190. GtkListStore *list_store;
  191. GDir *dir;
  192. const gchar *dirname;
  193. icon_view = GTK_ICON_VIEW (gallery);
  194. list_store = GTK_LIST_STORE (gtk_icon_view_get_model (icon_view));
  195. g_return_val_if_fail (list_store != NULL, FALSE);
  196. dirname = e_picture_gallery_get_path (gallery);
  197. if (!dirname)
  198. return FALSE;
  199. dir = g_dir_open (dirname, 0, NULL);
  200. if (dir) {
  201. GFile *file;
  202. const gchar *basename;
  203. while ((basename = g_dir_read_name (dir)) != NULL) {
  204. gchar *filename;
  205. filename = g_build_filename (dirname, basename, NULL);
  206. file = g_file_new_for_path (filename);
  207. add_file (list_store, file);
  208. g_free (filename);
  209. g_object_unref (file);
  210. }
  211. g_dir_close (dir);
  212. file = g_file_new_for_path (dirname);
  213. gallery->priv->monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL);
  214. g_object_unref (file);
  215. if (gallery->priv->monitor)
  216. g_signal_connect (
  217. gallery->priv->monitor, "changed",
  218. G_CALLBACK (picture_gallery_dir_changed_cb),
  219. gallery);
  220. }
  221. g_object_unref (icon_view);
  222. return FALSE;
  223. }
  224. const gchar *
  225. e_picture_gallery_get_path (EPictureGallery *gallery)
  226. {
  227. g_return_val_if_fail (gallery != NULL, NULL);
  228. g_return_val_if_fail (E_IS_PICTURE_GALLERY (gallery), NULL);
  229. g_return_val_if_fail (gallery->priv != NULL, NULL);
  230. return gallery->priv->path;
  231. }
  232. static void
  233. picture_gallery_set_path (EPictureGallery *gallery,
  234. const gchar *path)
  235. {
  236. g_return_if_fail (E_IS_PICTURE_GALLERY (gallery));
  237. g_return_if_fail (gallery->priv != NULL);
  238. g_free (gallery->priv->path);
  239. if (!path || !*path || !g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
  240. gallery->priv->path = g_strdup (g_get_user_special_dir (G_USER_DIRECTORY_PICTURES));
  241. else
  242. gallery->priv->path = g_strdup (path);
  243. }
  244. static void
  245. picture_gallery_get_property (GObject *object,
  246. guint property_id,
  247. GValue *value,
  248. GParamSpec *pspec)
  249. {
  250. switch (property_id) {
  251. case PROP_PATH:
  252. g_value_set_string (value, e_picture_gallery_get_path (E_PICTURE_GALLERY (object)));
  253. return;
  254. }
  255. G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
  256. }
  257. static void
  258. picture_gallery_set_property (GObject *object,
  259. guint property_id,
  260. const GValue *value,
  261. GParamSpec *pspec)
  262. {
  263. switch (property_id) {
  264. case PROP_PATH:
  265. picture_gallery_set_path (E_PICTURE_GALLERY (object), g_value_get_string (value));
  266. return;
  267. }
  268. G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
  269. }
  270. static void
  271. visible_cb (EPictureGallery *gallery)
  272. {
  273. if (!gallery->priv->initialized && gtk_widget_get_visible (GTK_WIDGET (gallery))) {
  274. gallery->priv->initialized = TRUE;
  275. g_idle_add ((GSourceFunc) picture_gallery_start_loading_cb, gallery);
  276. }
  277. }
  278. static void
  279. picture_gallery_constructed (GObject *object)
  280. {
  281. GtkIconView *icon_view;
  282. GtkListStore *list_store;
  283. GtkTargetEntry *targets;
  284. GtkTargetList *list;
  285. gint n_targets;
  286. /* Chain up to parent's constructed() method. */
  287. G_OBJECT_CLASS (e_picture_gallery_parent_class)->constructed (object);
  288. icon_view = GTK_ICON_VIEW (object);
  289. list_store = gtk_list_store_new (3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
  290. gtk_icon_view_set_model (icon_view, GTK_TREE_MODEL (list_store));
  291. g_object_unref (list_store);
  292. gtk_icon_view_set_pixbuf_column (icon_view, COL_PIXBUF);
  293. gtk_icon_view_set_text_column (icon_view, COL_FILENAME_TEXT);
  294. gtk_icon_view_set_tooltip_column (icon_view, -1);
  295. list = gtk_target_list_new (NULL, 0);
  296. gtk_target_list_add_uri_targets (list, 0);
  297. targets = gtk_target_table_new_from_list (list, &n_targets);
  298. gtk_icon_view_enable_model_drag_source (
  299. icon_view, GDK_BUTTON1_MASK,
  300. targets, n_targets, GDK_ACTION_COPY);
  301. gtk_target_table_free (targets, n_targets);
  302. gtk_target_list_unref (list);
  303. g_signal_connect (object, "notify::visible", G_CALLBACK (visible_cb), NULL);
  304. }
  305. static void
  306. picture_gallery_dispose (GObject *object)
  307. {
  308. EPictureGallery *gallery;
  309. gallery = E_PICTURE_GALLERY (object);
  310. if (gallery->priv->monitor) {
  311. g_object_unref (gallery->priv->monitor);
  312. gallery->priv->monitor = NULL;
  313. }
  314. /* Chain up to parent's dispose() method. */
  315. G_OBJECT_CLASS (e_picture_gallery_parent_class)->dispose (object);
  316. }
  317. static void
  318. e_picture_gallery_class_init (EPictureGalleryClass *class)
  319. {
  320. GObjectClass *object_class;
  321. g_type_class_add_private (class, sizeof (EPictureGalleryPrivate));
  322. object_class = G_OBJECT_CLASS (class);
  323. object_class->get_property = picture_gallery_get_property;
  324. object_class->set_property = picture_gallery_set_property;
  325. object_class->constructed = picture_gallery_constructed;
  326. object_class->dispose = picture_gallery_dispose;
  327. g_object_class_install_property (
  328. object_class,
  329. PROP_PATH,
  330. g_param_spec_string (
  331. "path",
  332. "Gallery path",
  333. NULL,
  334. NULL,
  335. G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
  336. }
  337. static void
  338. e_picture_gallery_init (EPictureGallery *gallery)
  339. {
  340. gallery->priv = E_PICTURE_GALLERY_GET_PRIVATE (gallery);
  341. gallery->priv->initialized = FALSE;
  342. gallery->priv->monitor = NULL;
  343. picture_gallery_set_path (gallery, NULL);
  344. }
  345. GtkWidget *
  346. e_picture_gallery_new (const gchar *path)
  347. {
  348. return g_object_new (E_TYPE_PICTURE_GALLERY, "path", path, NULL);
  349. }