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);
52 static void do_thumb_loaded(EntanglePixbufLoader *loader,
56 EntangleSessionBrowser *browser = data;
57 EntangleSessionBrowserPrivate *priv = browser->priv;
58 GdkPixbuf *pixbuf = entangle_pixbuf_loader_get_pixbuf(loader, filename);
61 ENTANGLE_DEBUG("Got pixbuf update on %s", filename);
66 if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(priv->model), &iter))
71 gtk_tree_model_get(GTK_TREE_MODEL(priv->model), &iter, 0, &img, -1);
73 if (strcmp(entangle_image_filename(img), filename) == 0) {
74 gtk_list_store_set(priv->model, &iter, 1, pixbuf, -1);
78 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(priv->model), &iter));
81 static void do_image_added(EntangleSession *session G_GNUC_UNUSED,
85 EntangleSessionBrowser *browser = data;
86 EntangleSessionBrowserPrivate *priv = browser->priv;
88 GtkTreePath *path = NULL;
89 int mod = entangle_image_last_modified(img);
91 ENTANGLE_DEBUG("Request image %s for new image", entangle_image_filename(img));
92 entangle_pixbuf_loader_load(ENTANGLE_PIXBUF_LOADER(priv->loader),
93 entangle_image_filename(img));
95 gtk_list_store_append(priv->model, &iter);
97 /* XXX what's our refcount policy going to be for pixbuf.... */
98 gtk_list_store_set(priv->model, &iter, 0, img, 1, priv->blank, 2, mod, -1);
99 ENTANGLE_DEBUG("ADD IMAGE EXTRA %p", img);
100 path = gtk_tree_model_get_path(GTK_TREE_MODEL(priv->model), &iter);
102 gtk_icon_view_select_path(GTK_ICON_VIEW(browser), path);
103 gtk_icon_view_scroll_to_path(GTK_ICON_VIEW(browser), path, FALSE, 0, 0);
105 gtk_tree_path_free(path);
107 gtk_widget_queue_resize(GTK_WIDGET(browser));
112 static void do_model_unload(EntangleSessionBrowser *browser)
114 EntangleSessionBrowserPrivate *priv = browser->priv;
117 ENTANGLE_DEBUG("Unload model");
119 g_signal_handler_disconnect(priv->session,
120 priv->sigImageAdded);
121 g_signal_handler_disconnect(priv->loader,
122 priv->sigThumbReady);
124 count = entangle_session_image_count(priv->session);
125 for (int i = 0 ; i < count ; i++) {
126 EntangleImage *img = entangle_session_image_get(priv->session, i);
127 entangle_pixbuf_loader_unload(ENTANGLE_PIXBUF_LOADER(priv->loader),
128 entangle_image_filename(img));
131 g_object_unref(priv->blank);
132 gtk_list_store_clear(priv->model);
135 static void do_model_load(EntangleSessionBrowser *browser)
137 EntangleSessionBrowserPrivate *priv = browser->priv;
142 ENTANGLE_DEBUG("Load model");
144 g_object_get(priv->loader,
149 priv->blank = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height);
150 gdk_pixbuf_fill(priv->blank, 0x000000FF);
152 priv->sigImageAdded = g_signal_connect(priv->session, "session-image-added",
153 G_CALLBACK(do_image_added), browser);
154 priv->sigThumbReady = g_signal_connect(priv->loader, "pixbuf-loaded",
155 G_CALLBACK(do_thumb_loaded), browser);
157 count = entangle_session_image_count(priv->session);
158 for (int i = 0 ; i < count ; i++) {
159 EntangleImage *img = entangle_session_image_get(priv->session, i);
160 int mod = entangle_image_last_modified(img);
163 gtk_list_store_append(priv->model, &iter);
164 ENTANGLE_DEBUG("ADD IMAGE FIRST %p", img);
165 /* XXX what's our refcount policy going to be for pixbuf.... */
166 gtk_list_store_set(priv->model, &iter, 0, img, 1, priv->blank, 2, mod, -1);
168 entangle_pixbuf_loader_load(ENTANGLE_PIXBUF_LOADER(priv->loader),
169 entangle_image_filename(img));
170 //g_object_unref(cam);
174 GtkTreePath *path = NULL;
175 path = gtk_tree_path_new_from_indices(count - 1, -1);
177 gtk_icon_view_select_path(GTK_ICON_VIEW(browser), path);
178 gtk_icon_view_scroll_to_path(GTK_ICON_VIEW(browser), path, FALSE, 0, 0);
180 gtk_tree_path_free(path);
186 do_image_sort_modified(GtkTreeModel *model,
189 gpointer data G_GNUC_UNUSED)
193 gtk_tree_model_get(model, a, 2, &ai, -1);
194 gtk_tree_model_get(model, b, 2, &bi, -1);
201 static void entangle_session_browser_get_property(GObject *object,
206 EntangleSessionBrowser *browser = ENTANGLE_SESSION_BROWSER(object);
207 EntangleSessionBrowserPrivate *priv = browser->priv;
212 g_value_set_object(value, priv->session);
216 g_value_set_object(value, priv->loader);
220 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
224 static void entangle_session_browser_set_property(GObject *object,
229 EntangleSessionBrowser *browser = ENTANGLE_SESSION_BROWSER(object);
231 ENTANGLE_DEBUG("Set prop on session browser %d", prop_id);
236 entangle_session_browser_set_session(browser, g_value_get_object(value));
240 entangle_session_browser_set_thumbnail_loader(browser, g_value_get_object(value));
244 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
248 static void entangle_session_browser_finalize (GObject *object)
250 EntangleSessionBrowser *browser = ENTANGLE_SESSION_BROWSER(object);
251 EntangleSessionBrowserPrivate *priv = browser->priv;
253 if (priv->session && priv->loader)
254 do_model_unload(browser);
257 g_object_unref(priv->session);
259 g_object_unref(priv->loader);
261 G_OBJECT_CLASS (entangle_session_browser_parent_class)->finalize (object);
265 static void entangle_session_browser_class_init(EntangleSessionBrowserClass *klass)
267 GObjectClass *object_class = G_OBJECT_CLASS(klass);
269 object_class->finalize = entangle_session_browser_finalize;
270 object_class->get_property = entangle_session_browser_get_property;
271 object_class->set_property = entangle_session_browser_set_property;
273 g_object_class_install_property(object_class,
275 g_param_spec_object("session",
277 "Session to be displayed",
278 ENTANGLE_TYPE_SESSION,
280 G_PARAM_STATIC_NAME |
281 G_PARAM_STATIC_NICK |
282 G_PARAM_STATIC_BLURB));
284 g_object_class_install_property(object_class,
286 g_param_spec_object("thumbnail-loader",
289 ENTANGLE_TYPE_THUMBNAIL_LOADER,
291 G_PARAM_STATIC_NAME |
292 G_PARAM_STATIC_NICK |
293 G_PARAM_STATIC_BLURB));
295 g_type_class_add_private(klass, sizeof(EntangleSessionBrowserPrivate));
298 EntangleSessionBrowser *entangle_session_browser_new(void)
300 return ENTANGLE_SESSION_BROWSER(g_object_new(ENTANGLE_TYPE_SESSION_BROWSER, NULL));
304 static void entangle_session_browser_init(EntangleSessionBrowser *browser)
306 EntangleSessionBrowserPrivate *priv;
307 const GtkTargetEntry const targets[] = {
308 { g_strdup("demo"), GTK_TARGET_OTHER_APP, 1 },
312 priv = browser->priv = ENTANGLE_SESSION_BROWSER_GET_PRIVATE(browser);
313 memset(priv, 0, sizeof *priv);
315 priv->model = gtk_list_store_new(3, ENTANGLE_TYPE_IMAGE, GDK_TYPE_PIXBUF, G_TYPE_INT);
317 gtk_icon_view_set_text_column(GTK_ICON_VIEW(browser), -1);
318 gtk_icon_view_set_pixbuf_column(GTK_ICON_VIEW(browser), 1);
319 gtk_icon_view_set_selection_mode(GTK_ICON_VIEW(browser), GTK_SELECTION_SINGLE);
320 gtk_icon_view_set_model(GTK_ICON_VIEW(browser), GTK_TREE_MODEL(priv->model));
322 gtk_tree_sortable_set_default_sort_func(GTK_TREE_SORTABLE(priv->model),
323 do_image_sort_modified, NULL, NULL);
324 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(priv->model),
325 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
328 gtk_icon_view_enable_model_drag_source(GTK_ICON_VIEW(browser),
334 gtk_icon_view_set_orientation(GTK_ICON_VIEW(browser), GTK_ORIENTATION_HORIZONTAL);
335 /* XXX gross hack - GtkIconView doesn't seem to have a better
336 * way to force everything into a single row. Perhaps we should
337 * just right a new widget for our needs */
338 gtk_icon_view_set_columns(GTK_ICON_VIEW(browser), 1000);
342 EntangleImage *entangle_session_browser_selected_image(EntangleSessionBrowser *browser)
344 EntangleSessionBrowserPrivate *priv = browser->priv;
346 EntangleImage *img = NULL;
351 items = gtk_icon_view_get_selected_items(GTK_ICON_VIEW(browser));
356 path = g_list_nth_data(items, 0);
360 if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(priv->model), &iter, path))
363 memset(&val, 0, sizeof val);
364 gtk_tree_model_get_value(GTK_TREE_MODEL(priv->model), &iter, 0, &val);
366 img = g_value_get_object(&val);
369 g_list_foreach(items, (GFunc)(gtk_tree_path_free), NULL);
375 void entangle_session_browser_set_thumbnail_loader(EntangleSessionBrowser *browser,
376 EntangleThumbnailLoader *loader)
378 EntangleSessionBrowserPrivate *priv = browser->priv;
382 do_model_unload(browser);
384 g_object_unref(priv->loader);
386 priv->loader = loader;
388 g_object_ref(priv->loader);
391 do_model_load(browser);
396 EntangleThumbnailLoader *entangle_session_browser_get_thumbnail_loader(EntangleSessionBrowser *browser)
398 EntangleSessionBrowserPrivate *priv = browser->priv;
404 void entangle_session_browser_set_session(EntangleSessionBrowser *browser,
405 EntangleSession *session)
407 EntangleSessionBrowserPrivate *priv = browser->priv;
411 do_model_unload(browser);
412 g_object_unref(priv->session);
414 priv->session = session;
416 g_object_ref(priv->session);
419 do_model_load(browser);
424 EntangleSession *entangle_session_browser_get_session(EntangleSessionBrowser *browser)
426 EntangleSessionBrowserPrivate *priv = browser->priv;
428 return priv->session;
435 * indent-tabs-mode: nil