2 * Entangle: Entangle Assists Photograph Aquisition
4 * Copyright (C) 2009 Daniel P. Berrange
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "entangle-debug.h"
26 #include "entangle-session-browser.h"
28 #define ENTANGLE_SESSION_BROWSER_GET_PRIVATE(obj) \
29 (G_TYPE_INSTANCE_GET_PRIVATE((obj), ENTANGLE_TYPE_SESSION_BROWSER, EntangleSessionBrowserPrivate))
31 struct _EntangleSessionBrowserPrivate {
32 EntangleSession *session;
33 EntangleThumbnailLoader *loader;
43 G_DEFINE_TYPE(EntangleSessionBrowser, entangle_session_browser, GTK_TYPE_ICON_VIEW);
60 static void do_thumb_loaded(EntanglePixbufLoader *loader,
64 EntangleSessionBrowser *browser = data;
65 EntangleSessionBrowserPrivate *priv = browser->priv;
69 ENTANGLE_DEBUG("Got pixbuf update on %p", image);
71 pixbuf = entangle_pixbuf_loader_get_pixbuf(loader, image);
75 if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(priv->model), &iter))
79 EntangleImage *thisimage;
80 gtk_tree_model_get(GTK_TREE_MODEL(priv->model), &iter, FIELD_IMAGE, &thisimage, -1);
82 if (image == thisimage) {
83 gtk_list_store_set(priv->model, &iter, FIELD_PIXMAP, pixbuf, -1);
87 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(priv->model), &iter));
90 static void do_image_added(EntangleSession *session G_GNUC_UNUSED,
94 EntangleSessionBrowser *browser = data;
95 EntangleSessionBrowserPrivate *priv = browser->priv;
97 GtkTreePath *path = NULL;
98 int mod = entangle_image_get_last_modified(img);
99 gchar *name = g_path_get_basename(entangle_image_get_filename(img));
101 ENTANGLE_DEBUG("Request image %s for new image", entangle_image_get_filename(img));
102 entangle_pixbuf_loader_load(ENTANGLE_PIXBUF_LOADER(priv->loader), img);
104 gtk_list_store_append(priv->model, &iter);
106 /* XXX what's our refcount policy going to be for pixbuf.... */
107 gtk_list_store_set(priv->model, &iter,
109 FIELD_PIXMAP, priv->blank,
113 ENTANGLE_DEBUG("ADD IMAGE EXTRA %p", img);
114 path = gtk_tree_model_get_path(GTK_TREE_MODEL(priv->model), &iter);
116 gtk_icon_view_select_path(GTK_ICON_VIEW(browser), path);
117 gtk_icon_view_scroll_to_path(GTK_ICON_VIEW(browser), path, FALSE, 0, 0);
119 gtk_tree_path_free(path);
121 gtk_widget_queue_resize(GTK_WIDGET(browser));
126 static void do_model_unload(EntangleSessionBrowser *browser)
128 EntangleSessionBrowserPrivate *priv = browser->priv;
131 ENTANGLE_DEBUG("Unload model");
133 g_signal_handler_disconnect(priv->session,
134 priv->sigImageAdded);
135 g_signal_handler_disconnect(priv->loader,
136 priv->sigThumbReady);
138 count = entangle_session_image_count(priv->session);
139 for (int i = 0 ; i < count ; i++) {
140 EntangleImage *img = entangle_session_image_get(priv->session, i);
141 entangle_pixbuf_loader_unload(ENTANGLE_PIXBUF_LOADER(priv->loader), img);
144 g_object_unref(priv->blank);
145 gtk_list_store_clear(priv->model);
148 static void do_model_load(EntangleSessionBrowser *browser)
150 EntangleSessionBrowserPrivate *priv = browser->priv;
155 ENTANGLE_DEBUG("Load model");
157 g_object_get(priv->loader,
162 priv->blank = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height);
163 gdk_pixbuf_fill(priv->blank, 0x000000FF);
165 priv->sigImageAdded = g_signal_connect(priv->session, "session-image-added",
166 G_CALLBACK(do_image_added), browser);
167 priv->sigThumbReady = g_signal_connect(priv->loader, "pixbuf-loaded",
168 G_CALLBACK(do_thumb_loaded), browser);
170 count = entangle_session_image_count(priv->session);
171 for (int i = 0 ; i < count ; i++) {
172 EntangleImage *img = entangle_session_image_get(priv->session, i);
173 int mod = entangle_image_get_last_modified(img);
175 gchar *name = g_path_get_basename(entangle_image_get_filename(img));
177 gtk_list_store_append(priv->model, &iter);
178 ENTANGLE_DEBUG("ADD IMAGE FIRST %p", img);
179 /* XXX what's our refcount policy going to be for pixbuf.... */
180 gtk_list_store_set(priv->model, &iter,
182 FIELD_PIXMAP, priv->blank,
187 entangle_pixbuf_loader_load(ENTANGLE_PIXBUF_LOADER(priv->loader), img);
188 //g_object_unref(cam);
192 GtkTreePath *path = NULL;
193 path = gtk_tree_path_new_from_indices(count - 1, -1);
195 gtk_icon_view_select_path(GTK_ICON_VIEW(browser), path);
196 gtk_icon_view_scroll_to_path(GTK_ICON_VIEW(browser), path, FALSE, 0, 0);
198 gtk_tree_path_free(path);
204 do_image_sort_modified(GtkTreeModel *model,
207 gpointer data G_GNUC_UNUSED)
211 gtk_tree_model_get(model, a, FIELD_LASTMOD, &ai, -1);
212 gtk_tree_model_get(model, b, FIELD_LASTMOD, &bi, -1);
219 static void entangle_session_browser_get_property(GObject *object,
224 EntangleSessionBrowser *browser = ENTANGLE_SESSION_BROWSER(object);
225 EntangleSessionBrowserPrivate *priv = browser->priv;
230 g_value_set_object(value, priv->session);
234 g_value_set_object(value, priv->loader);
238 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
242 static void entangle_session_browser_set_property(GObject *object,
247 EntangleSessionBrowser *browser = ENTANGLE_SESSION_BROWSER(object);
249 ENTANGLE_DEBUG("Set prop on session browser %d", prop_id);
254 entangle_session_browser_set_session(browser, g_value_get_object(value));
258 entangle_session_browser_set_thumbnail_loader(browser, g_value_get_object(value));
262 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
266 static void entangle_session_browser_finalize (GObject *object)
268 EntangleSessionBrowser *browser = ENTANGLE_SESSION_BROWSER(object);
269 EntangleSessionBrowserPrivate *priv = browser->priv;
271 if (priv->session && priv->loader)
272 do_model_unload(browser);
275 g_object_unref(priv->session);
277 g_object_unref(priv->loader);
279 G_OBJECT_CLASS (entangle_session_browser_parent_class)->finalize (object);
283 static void entangle_session_browser_class_init(EntangleSessionBrowserClass *klass)
285 GObjectClass *object_class = G_OBJECT_CLASS(klass);
287 object_class->finalize = entangle_session_browser_finalize;
288 object_class->get_property = entangle_session_browser_get_property;
289 object_class->set_property = entangle_session_browser_set_property;
291 g_object_class_install_property(object_class,
293 g_param_spec_object("session",
295 "Session to be displayed",
296 ENTANGLE_TYPE_SESSION,
298 G_PARAM_STATIC_NAME |
299 G_PARAM_STATIC_NICK |
300 G_PARAM_STATIC_BLURB));
302 g_object_class_install_property(object_class,
304 g_param_spec_object("thumbnail-loader",
307 ENTANGLE_TYPE_THUMBNAIL_LOADER,
309 G_PARAM_STATIC_NAME |
310 G_PARAM_STATIC_NICK |
311 G_PARAM_STATIC_BLURB));
313 g_type_class_add_private(klass, sizeof(EntangleSessionBrowserPrivate));
316 EntangleSessionBrowser *entangle_session_browser_new(void)
318 return ENTANGLE_SESSION_BROWSER(g_object_new(ENTANGLE_TYPE_SESSION_BROWSER, NULL));
322 static void entangle_session_browser_init(EntangleSessionBrowser *browser)
324 EntangleSessionBrowserPrivate *priv;
325 const GtkTargetEntry const targets[] = {
326 { g_strdup("demo"), GTK_TARGET_OTHER_APP, 1 },
330 priv = browser->priv = ENTANGLE_SESSION_BROWSER_GET_PRIVATE(browser);
331 memset(priv, 0, sizeof *priv);
333 priv->model = gtk_list_store_new(FIELD_LAST, ENTANGLE_TYPE_IMAGE, GDK_TYPE_PIXBUF, G_TYPE_INT, G_TYPE_STRING);
335 gtk_icon_view_set_text_column(GTK_ICON_VIEW(browser), FIELD_NAME);
336 gtk_icon_view_set_pixbuf_column(GTK_ICON_VIEW(browser), FIELD_PIXMAP);
337 gtk_icon_view_set_selection_mode(GTK_ICON_VIEW(browser), GTK_SELECTION_SINGLE);
338 gtk_icon_view_set_model(GTK_ICON_VIEW(browser), GTK_TREE_MODEL(priv->model));
340 gtk_tree_sortable_set_default_sort_func(GTK_TREE_SORTABLE(priv->model),
341 do_image_sort_modified, NULL, NULL);
342 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(priv->model),
343 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
346 gtk_icon_view_enable_model_drag_source(GTK_ICON_VIEW(browser),
352 gtk_icon_view_set_orientation(GTK_ICON_VIEW(browser), GTK_ORIENTATION_VERTICAL);
353 /* XXX gross hack - GtkIconView doesn't seem to have a better
354 * way to force everything into a single row. Perhaps we should
355 * just right a new widget for our needs */
356 gtk_icon_view_set_columns(GTK_ICON_VIEW(browser), 10000);
360 EntangleImage *entangle_session_browser_selected_image(EntangleSessionBrowser *browser)
362 EntangleSessionBrowserPrivate *priv = browser->priv;
364 EntangleImage *img = NULL;
369 items = gtk_icon_view_get_selected_items(GTK_ICON_VIEW(browser));
374 path = g_list_nth_data(items, 0);
378 if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(priv->model), &iter, path))
381 memset(&val, 0, sizeof val);
382 gtk_tree_model_get_value(GTK_TREE_MODEL(priv->model), &iter, 0, &val);
384 img = g_value_get_object(&val);
387 g_list_foreach(items, (GFunc)(gtk_tree_path_free), NULL);
393 void entangle_session_browser_set_thumbnail_loader(EntangleSessionBrowser *browser,
394 EntangleThumbnailLoader *loader)
396 EntangleSessionBrowserPrivate *priv = browser->priv;
400 do_model_unload(browser);
402 g_object_unref(priv->loader);
404 priv->loader = loader;
406 g_object_ref(priv->loader);
409 do_model_load(browser);
414 EntangleThumbnailLoader *entangle_session_browser_get_thumbnail_loader(EntangleSessionBrowser *browser)
416 EntangleSessionBrowserPrivate *priv = browser->priv;
422 void entangle_session_browser_set_session(EntangleSessionBrowser *browser,
423 EntangleSession *session)
425 EntangleSessionBrowserPrivate *priv = browser->priv;
429 do_model_unload(browser);
430 g_object_unref(priv->session);
432 priv->session = session;
434 g_object_ref(priv->session);
437 do_model_load(browser);
442 EntangleSession *entangle_session_browser_get_session(EntangleSessionBrowser *browser)
444 EntangleSessionBrowserPrivate *priv = browser->priv;
446 return priv->session;
453 * indent-tabs-mode: nil