1 /* gtkam-tree.c
2  *
3  * Copyright 2001,2002 Lutz Mueller <lutz@users.sf.net>
4  * Copyright 2004      Andrew Burton <adburton@users.sourceforge.net>
5  *
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 2 of the License, or
9  * (at your option) any later version.
10  *
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.
15  *
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/>.
18  */
19 
20 #include "config.h"
21 #include "gtkam-tree.h"
22 #include "i18n.h"
23 
24 #include <stdio.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <libgen.h>
30 
31 #include <gtk/gtkvbox.h>
32 #include <gtk/gtkhbox.h>
33 #include <gtk/gtklabel.h>
34 #include <gtk/gtksignal.h>
35 #include <gtk/gtkmain.h>
36 #include <gtk/gtkfilesel.h>
37 #include <gtk/gtkbutton.h>
38 #include <gtk/gtktreestore.h>
39 #include <gtk/gtkpixmap.h>
40 #include <gtk/gtkitemfactory.h>
41 #include <gtk/gtkmenu.h>
42 #include <gtk/gtkcellrenderertext.h>
43 #include <gtk/gtktreeselection.h>
44 #include <gtk/gtkstock.h>
45 #include <gtk/gtktooltips.h>
46 #include <gtk/gtkmenuitem.h>
47 
48 #include <gdk-pixbuf/gdk-pixbuf.h>
49 
50 #include <gphoto2/gphoto2-setting.h>
51 #include <gphoto2/gphoto2-camera.h>
52 
53 #include "util.h"
54 
55 #include "gtkam-camera.h"
56 #include "gtkam-chooser.h"
57 #include "gtkam-close.h"
58 #include "gtkam-config.h"
59 #include "gtkam-error.h"
60 #include "gtkam-status.h"
61 #include "gtkam-mkdir.h"
62 #include "gtkam-preview.h"
63 #include "gtkam-cancel.h"
64 
65 struct _GtkamTreePrivate
66 {
67 	GtkTreeStore *store;
68 
69 	GtkItemFactory *factory;
70 	GtkTooltips *tooltips;
71 
72 	GtkTreeIter iter;
73 };
74 
75 #define PARENT_TYPE GTK_TYPE_TREE_VIEW
76 static GtkTreeViewClass *parent_class;
77 
78 enum {
79 	FOLDER_SELECTED,
80 	FOLDER_UNSELECTED,
81 	FILE_ADDED,
82 	NEW_STATUS,
83 	NEW_ERROR,
84 	NEW_DIALOG,
85 	LAST_SIGNAL
86 };
87 
88 static guint signals[LAST_SIGNAL] = {0};
89 
90 enum {
91 	FOLDER_COLUMN = 0,
92 	CAMERA_COLUMN,
93 	NUM_COLUMNS
94 };
95 
96 static void
gtkam_tree_destroy(GtkObject * object)97 gtkam_tree_destroy (GtkObject *object)
98 {
99 	GtkamTree *tree = GTKAM_TREE (object);
100 
101 	if (tree->priv->store) {
102 		g_object_unref (G_OBJECT (tree->priv->store));
103 		tree->priv->store = NULL;
104 	}
105 
106 	if (tree->priv->tooltips) {
107 		g_object_unref (G_OBJECT (tree->priv->tooltips));
108 		tree->priv->tooltips = NULL;
109 	}
110 
111 	GTK_OBJECT_CLASS (parent_class)->destroy (object);
112 }
113 
114 static void
gtkam_tree_finalize(GObject * object)115 gtkam_tree_finalize (GObject *object)
116 {
117 	GtkamTree *tree = GTKAM_TREE (object);
118 
119 	g_free (tree->priv);
120 
121 	G_OBJECT_CLASS (parent_class)->finalize (object);
122 }
123 
124 static void
gtkam_tree_class_init(gpointer g_class,gpointer class_data)125 gtkam_tree_class_init (gpointer g_class, gpointer class_data)
126 {
127 	GtkObjectClass *object_class;
128 	GObjectClass *gobject_class;
129 
130 	object_class = GTK_OBJECT_CLASS (g_class);
131 	object_class->destroy  = gtkam_tree_destroy;
132 
133 	gobject_class = G_OBJECT_CLASS (g_class);
134 	gobject_class->finalize = gtkam_tree_finalize;
135 
136 	signals[FOLDER_SELECTED] = g_signal_new ("folder_selected",
137 		G_TYPE_FROM_CLASS (g_class), G_SIGNAL_RUN_LAST,
138 		G_STRUCT_OFFSET (GtkamTreeClass, folder_selected), NULL, NULL,
139 		g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
140 		G_TYPE_POINTER);
141 	signals[FOLDER_UNSELECTED] = g_signal_new ("folder_unselected",
142 		G_TYPE_FROM_CLASS (g_class), G_SIGNAL_RUN_LAST,
143 		G_STRUCT_OFFSET (GtkamTreeClass, folder_unselected), NULL, NULL,
144 		g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
145 		G_TYPE_POINTER);
146 	signals[FILE_ADDED] = g_signal_new ("file_added",
147 		G_TYPE_FROM_CLASS (g_class), G_SIGNAL_RUN_LAST,
148 		G_STRUCT_OFFSET (GtkamTreeClass, file_added), NULL, NULL,
149 		g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
150 		G_TYPE_POINTER);
151 	signals[NEW_STATUS] = g_signal_new ("new_status",
152 		G_TYPE_FROM_CLASS (g_class), G_SIGNAL_RUN_LAST,
153 		G_STRUCT_OFFSET (GtkamTreeClass, new_status), NULL, NULL,
154 		g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
155 		G_TYPE_POINTER);
156 	signals[NEW_ERROR] = g_signal_new ("new_error",
157 		G_TYPE_FROM_CLASS (g_class), G_SIGNAL_RUN_LAST,
158 		G_STRUCT_OFFSET (GtkamTreeClass, new_error), NULL, NULL,
159 		g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
160 		G_TYPE_POINTER);
161 	signals[NEW_DIALOG] = g_signal_new ("new_dialog",
162 		G_TYPE_FROM_CLASS (g_class), G_SIGNAL_RUN_LAST,
163 		G_STRUCT_OFFSET (GtkamTreeClass, new_dialog), NULL, NULL,
164 		g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
165 		G_TYPE_POINTER);
166 
167 	parent_class = g_type_class_peek_parent (g_class);
168 }
169 
170 static void
gtkam_tree_init(GTypeInstance * instance,gpointer g_class)171 gtkam_tree_init (GTypeInstance *instance, gpointer g_class)
172 {
173 	GtkamTree *tree = GTKAM_TREE (instance);
174 
175 	tree->priv = g_new0 (GtkamTreePrivate, 1);
176 
177 	tree->priv->tooltips = gtk_tooltips_new ();
178 	g_object_ref (G_OBJECT (tree->priv->tooltips));
179 	gtk_object_sink (GTK_OBJECT (tree->priv->tooltips));
180 }
181 
182 GType
gtkam_tree_get_type(void)183 gtkam_tree_get_type (void)
184 {
185 	static GType type = 0;
186 
187 	if (!type) {
188 		GTypeInfo ti;
189 
190 		memset (&ti, 0, sizeof (GTypeInfo));
191 		ti.class_size    = sizeof (GtkamTreeClass);
192 		ti.class_init    = gtkam_tree_class_init;
193 		ti.instance_size = sizeof (GtkamTree);
194 		ti.instance_init = gtkam_tree_init;
195 
196 		type = g_type_register_static (PARENT_TYPE, "GtkamTree",
197 					       &ti, 0);
198 	}
199 
200 	return (type);
201 }
202 
203 static GtkamCamera *
gtkam_tree_get_camera_from_iter(GtkamTree * tree,GtkTreeIter * iter)204 gtkam_tree_get_camera_from_iter (GtkamTree *tree, GtkTreeIter *iter)
205 {
206 	GValue value = {0};
207 	GtkamCamera *camera;
208 
209 	gtk_tree_model_get_value (GTK_TREE_MODEL (tree->priv->store), iter,
210 				  CAMERA_COLUMN, &value);
211 	g_assert (G_VALUE_HOLDS (&value, GTKAM_TYPE_CAMERA));
212 	camera = GTKAM_CAMERA (g_value_peek_pointer (&value));
213 	g_value_unset (&value);
214 
215 	return (camera);
216 }
217 
218 static gchar *
gtkam_tree_get_path_rec(GtkamTree * tree,GtkTreeIter * iter,const gchar * path)219 gtkam_tree_get_path_rec (GtkamTree *tree, GtkTreeIter *iter, const gchar *path)
220 {
221 	GtkTreeIter parent, p;
222 	gchar *new_path = NULL, *new_path_ret = NULL;
223 	GValue value = {0};
224 
225 	if (gtk_tree_model_iter_parent (GTK_TREE_MODEL (tree->priv->store),
226 					&parent, iter)) {
227 		if (gtk_tree_model_iter_parent (
228 			GTK_TREE_MODEL (tree->priv->store), &p, &parent)) {
229 			gtk_tree_model_get_value (
230 				GTK_TREE_MODEL (tree->priv->store),
231 				&parent, FOLDER_COLUMN, &value);
232 			new_path = g_strdup_printf ("%s/%s",
233 					g_value_get_string (&value), path);
234 			g_value_unset (&value);
235 			new_path_ret = gtkam_tree_get_path_rec (tree, &parent,
236 								new_path);
237 			g_free (new_path);
238 			return (new_path_ret);
239 		} else
240 			return (g_strdup_printf ("/%s", path));
241 	} else
242 		return (g_strdup ("/"));
243 }
244 
245 static gchar *
gtkam_tree_get_path_from_iter(GtkamTree * tree,GtkTreeIter * iter)246 gtkam_tree_get_path_from_iter (GtkamTree *tree, GtkTreeIter *iter)
247 {
248 	GtkTreeIter parent;
249 	GValue value = {0};
250 	gchar *path = NULL;
251 
252 	if (gtk_tree_model_iter_parent (GTK_TREE_MODEL (tree->priv->store),
253 					&parent, iter)) {
254 		gtk_tree_model_get_value (GTK_TREE_MODEL (tree->priv->store),
255 					  iter, FOLDER_COLUMN, &value);
256 		path = gtkam_tree_get_path_rec (tree, iter,
257 						g_value_get_string (&value));
258 		g_value_unset (&value);
259 	} else
260 		path = g_strdup ("/");
261 
262 	return (path);
263 }
264 
265 static void
gtkam_tree_update_iter(GtkamTree * tree,GtkTreeIter * iter)266 gtkam_tree_update_iter (GtkamTree *tree, GtkTreeIter *iter)
267 {
268 	gint i, n;
269 	GtkTreeIter child;
270 	CameraList *list;
271 	const char *name;
272 	int result;
273 	GtkamCamera *camera = NULL;
274 	GtkWidget *s;
275 	gchar *folder = NULL, *msg;
276 	GtkamTreeErrorData e;
277 
278 	g_return_if_fail (GTKAM_IS_TREE (tree));
279 
280 	/* Look up the corresponding camera */
281 	camera = gtkam_tree_get_camera_from_iter (tree, iter);
282 	g_return_if_fail (camera != NULL);
283 	g_return_if_fail (GTKAM_IS_CAMERA (camera));
284 
285 	while (gtk_tree_model_iter_n_children (
286 				GTK_TREE_MODEL (tree->priv->store), iter)) {
287 		gtk_tree_model_iter_nth_child (
288 				GTK_TREE_MODEL (tree->priv->store), &child,
289 				iter, 0);
290 		gtk_tree_store_remove (tree->priv->store, &child);
291 	}
292 
293 	/* Which folder? */
294 	folder = gtkam_tree_get_path_from_iter (tree, iter);
295 
296 	s = gtkam_status_new (_("Listing folders in '%s'..."), folder);
297 	g_signal_emit (G_OBJECT (tree), signals[NEW_STATUS], 0, s);
298 	gp_list_new (&list);
299 	result = gp_camera_folder_list_folders (camera->camera, folder, list,
300 					GTKAM_STATUS (s)->context->context);
301 	if (result >= 0) {
302 		n = gp_list_count (list);
303 		for (i = 0; i < n; i++) {
304 			gp_list_get_name (list, i, &name);
305 			gtk_tree_store_append (tree->priv->store, &child,
306 					       iter);
307 			gtk_tree_store_set (tree->priv->store, &child,
308 					FOLDER_COLUMN, name,
309 					CAMERA_COLUMN, camera, -1);
310 		}
311 	} else if (result == GP_ERROR_NOT_SUPPORTED) {
312 		/* Do nothing */
313 	} else {
314 		e.context = GTKAM_STATUS (s)->context;
315 		e.result = result;
316 		e.msg = msg = g_strdup_printf (
317 				_("Could not list folders in '%s'."), folder);
318 		g_signal_emit (G_OBJECT (tree), signals[NEW_ERROR], 0, &e);
319 		g_free (msg);
320 	}
321 	g_free (folder);
322 	gp_list_unref (list);
323 	if (camera->multi)
324 		gp_camera_exit (camera->camera, NULL);
325 
326 	gtk_object_destroy (GTK_OBJECT (s));
327 }
328 
329 static void
on_row_expanded(GtkTreeView * tree_view,GtkTreeIter * iter,GtkTreePath * path,GtkamTree * tree)330 on_row_expanded (GtkTreeView *tree_view, GtkTreeIter *iter,
331                  GtkTreePath *path, GtkamTree *tree)
332 {
333         gint i, n;
334         GtkTreeIter child;
335 
336         n = gtk_tree_model_iter_n_children (
337 			GTK_TREE_MODEL (tree->priv->store), iter);
338         for (i = 0; i < n; i++) {
339                 gtk_tree_model_iter_nth_child (
340                         GTK_TREE_MODEL (tree->priv->store), &child, iter, i);
341 		if (!gtk_tree_model_iter_has_child (
342 				GTK_TREE_MODEL (tree->priv->store), &child))
343 			gtkam_tree_update_iter (tree, &child);
344         }
345 }
346 
347 static gboolean
selection_func(GtkTreeSelection * selection,GtkTreeModel * model,GtkTreePath * path,gboolean path_currently_selected,gpointer data)348 selection_func (GtkTreeSelection *selection, GtkTreeModel *model,
349 		GtkTreePath *path, gboolean path_currently_selected,
350 		gpointer data)
351 {
352 	GtkTreeIter iter;
353 	gchar *folder;
354 	GtkamTree *tree = GTKAM_TREE (data);
355 	GtkamTreeFolderSelectedData sd;
356 	GtkamTreeFolderUnselectedData ud;
357 
358 	gtk_tree_model_get_iter (model, &iter, path);
359 	folder = gtkam_tree_get_path_from_iter (tree, &iter);
360 	if (path_currently_selected) {
361 		ud.camera = gtkam_tree_get_camera_from_iter (tree, &iter);
362 		ud.folder = folder;
363 		g_signal_emit (G_OBJECT (tree), signals[FOLDER_UNSELECTED],
364 			       0, &ud);
365 	} else {
366 		sd.camera = gtkam_tree_get_camera_from_iter (tree, &iter);
367 		sd.folder = folder;
368 		g_signal_emit (G_OBJECT (tree), signals[FOLDER_SELECTED],
369 			       0, &sd);
370 	}
371 	g_free (folder);
372 
373 	return (TRUE);
374 }
375 
376 typedef struct _GtkamTreeUploadData GtkamTreeUploadData;
377 struct _GtkamTreeUploadData {
378 	GtkWidget *fsel;
379 	GtkamTree *tree;
380 	GtkTreeIter *iter;
381 };
382 
383 static void
on_upload_destroy(GtkObject * object,GtkamTreeUploadData * ud)384 on_upload_destroy (GtkObject *object, GtkamTreeUploadData *ud)
385 {
386 	gtk_tree_iter_free (ud->iter);
387 	g_free (ud);
388 }
389 
390 static void
on_upload_cancel_clicked(GtkButton * button,GtkFileSelection * fsel)391 on_upload_cancel_clicked (GtkButton *button, GtkFileSelection *fsel)
392 {
393 	gtk_object_destroy (GTK_OBJECT (fsel));
394 }
395 
396 static void
on_upload_ok_clicked(GtkButton * button,GtkamTreeUploadData * ud)397 on_upload_ok_clicked (GtkButton *button, GtkamTreeUploadData *ud)
398 {
399 	const gchar *path;
400 	int r;
401 	CameraFile *file;
402 	GtkamTreeErrorData e;
403 	GtkamTreeFileAddedData fud;
404 	GtkWidget *s;
405 	gchar *basename, *folder, *msg;
406 	GtkamCamera *c;
407 
408 	path = gtk_file_selection_get_filename (GTK_FILE_SELECTION (ud->fsel));
409 	gp_file_new (&file);
410 	r = gp_file_open (file, path);
411 	if (r < 0) {
412 		e.context = NULL;
413 		e.result = r;
414 		e.msg = msg = g_strdup_printf (_("Could not open '%s'."), path);
415 		g_signal_emit (G_OBJECT (ud->tree), signals[NEW_ERROR], 0, &e);
416 		g_free (msg);
417 	} else {
418 		gtk_widget_hide (ud->fsel);
419 		folder = gtkam_tree_get_path_from_iter (ud->tree, ud->iter);
420 		c = gtkam_tree_get_camera_from_iter (ud->tree, ud->iter);
421 		basename = g_path_get_basename (path);
422 		s = gtkam_status_new (_("Uploading '%s' into "
423 			"folder '%s'..."), basename, folder);
424 		g_signal_emit (G_OBJECT (ud->tree), signals[NEW_STATUS], 0, s);
425 #ifdef HAVE_GP_PORT_INFO_GET_NAME
426 		r = gp_camera_folder_put_file (c->camera, folder, basename, GP_FILE_TYPE_NORMAL, file,
427 				GTKAM_STATUS (s)->context->context);
428 #else
429 		r = gp_camera_folder_put_file (c->camera, folder, file, GTKAM_STATUS (s)->context->context);
430 #endif
431 		if (c->multi)
432 			gp_camera_exit (c->camera, NULL);
433 		switch (r) {
434 		case GP_OK:
435 			fud.camera = c;
436 			fud.folder = folder;
437 			fud.name = basename;
438 			g_signal_emit (G_OBJECT (ud->tree),
439 				       signals[FILE_ADDED], 0, &fud);
440 			break;
441 		case GP_ERROR_CANCEL:
442 			break;
443 		default:
444 			e.context = GTKAM_STATUS (s)->context;
445 			e.result = r;
446 			e.msg = msg = g_strdup_printf (_("Could not upload "
447 				"'%s' into '%s'."), path, folder);
448 			g_signal_emit (G_OBJECT (ud->tree), signals[NEW_ERROR],
449 				       0, &e);
450 			g_free (msg);
451 			break;
452 		}
453 		g_free (basename);
454 		g_free (folder);
455 		gtk_object_destroy (GTK_OBJECT (s));
456 	}
457 	gp_file_unref (file);
458 	gtk_object_destroy (GTK_OBJECT (ud->fsel));
459 }
460 
461 static void
action_upload(gpointer callback_data,guint callback_action,GtkWidget * widget)462 action_upload (gpointer callback_data, guint callback_action,
463 	       GtkWidget *widget)
464 {
465 	GtkWidget *fsel;
466 	GtkamTree *tree = GTKAM_TREE (callback_data);
467 	GtkamTreeUploadData *ud;
468 	gchar *title, *folder;
469 
470 	folder = gtkam_tree_get_path_from_iter (tree, &tree->priv->iter);
471 	title = g_strdup_printf (_("Upload into '%s'..."), folder);
472 	g_free (folder);
473 	fsel = gtk_file_selection_new (title);
474 	g_free (title);
475 	g_signal_emit (G_OBJECT (tree), signals[NEW_DIALOG], 0, fsel);
476 	g_object_unref (G_OBJECT (fsel));
477 	ud = g_new0 (GtkamTreeUploadData, 1);
478 	ud->fsel = fsel;
479 	ud->tree = tree;
480 	ud->iter = gtk_tree_iter_copy (&tree->priv->iter);
481 	g_signal_connect (G_OBJECT (fsel), "destroy",
482 		G_CALLBACK (on_upload_destroy), ud);
483 	g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (fsel)->ok_button),
484 		"clicked", G_CALLBACK (on_upload_ok_clicked), ud);
485 	g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (fsel)->cancel_button),
486 		"clicked", G_CALLBACK (on_upload_cancel_clicked), fsel);
487 }
488 
489 typedef struct _DirCreatedData DirCreatedData;
490 struct _DirCreatedData {
491 	GtkamTree *tree;
492 	GtkTreeIter *iter;
493 };
494 
495 static void
on_dir_created(GtkamMkdir * mkdir,GtkamMkdirDirCreatedData * data,DirCreatedData * d)496 on_dir_created (GtkamMkdir *mkdir, GtkamMkdirDirCreatedData *data,
497 		DirCreatedData *d)
498 {
499 	gtkam_tree_update_iter (d->tree, d->iter);
500 }
501 
502 static void
on_mkdir_destroy(GtkObject * mkdir,DirCreatedData * d)503 on_mkdir_destroy (GtkObject *mkdir, DirCreatedData *d)
504 {
505 	gtk_tree_iter_free (d->iter);
506 	g_free (d);
507 }
508 
509 static void
action_mkdir(gpointer callback_data,guint callback_action,GtkWidget * widget)510 action_mkdir (gpointer callback_data, guint callback_action,
511 	      GtkWidget *widget)
512 {
513 	GtkWidget *d;
514 	GtkamTree *tree = GTKAM_TREE (callback_data);
515 	GtkamCamera *camera;
516 	DirCreatedData *data;
517 	gchar *folder;
518 
519 	camera = gtkam_tree_get_camera_from_iter (tree, &tree->priv->iter);
520 	folder = gtkam_tree_get_path_from_iter (tree, &tree->priv->iter);
521 	d = gtkam_mkdir_new (camera, folder);
522 	g_signal_emit (GTK_OBJECT (tree), signals[NEW_DIALOG], 0, d);
523 	g_object_unref (G_OBJECT (d));
524 	g_free (folder);
525 	data = g_new0 (DirCreatedData, 1);
526 	data->tree = tree;
527 	data->iter = gtk_tree_iter_copy (&tree->priv->iter);
528 	g_signal_connect (G_OBJECT (d), "dir_created",
529 			  G_CALLBACK (on_dir_created), data);
530 	g_signal_connect (G_OBJECT (d), "destroy",
531 			  G_CALLBACK (on_mkdir_destroy), data);
532 }
533 
534 static void
action_rmdir(gpointer callback_data,guint callback_action,GtkWidget * widget)535 action_rmdir (gpointer callback_data, guint callback_action,
536 	      GtkWidget *widget)
537 {
538 	GtkWidget *s;
539 	GtkamTree *tree = GTKAM_TREE (callback_data);
540 	gchar *basename, *folder, *path, *msg;
541 	int r;
542 	GtkamCamera *camera;
543 	GtkamTreeErrorData e;
544 
545 	folder = gtkam_tree_get_path_from_iter (tree, &tree->priv->iter);
546 	camera = gtkam_tree_get_camera_from_iter (tree, &tree->priv->iter);
547 	s = gtkam_status_new (_("Removing directory '%s'..."), folder);
548 	g_signal_emit (G_OBJECT (tree), signals[NEW_STATUS], 0, s);
549 	path = g_strdup (folder);
550 	while (path[strlen (path) - 1] != '/')
551 		path[strlen (path) - 1] = '\0';
552 	basename = g_path_get_basename (folder);
553 	r = gp_camera_folder_remove_dir (camera->camera, path,
554 		basename, GTKAM_STATUS (s)->context->context);
555 	g_free (path);
556 	g_free (basename);
557 	switch (r) {
558 	case GP_OK:
559 		gtk_tree_store_remove (tree->priv->store, &tree->priv->iter);
560 		break;
561 	case GP_ERROR_CANCEL:
562 		break;
563 	default:
564 		e.context = GTKAM_STATUS (s)->context;
565 		e.result = r;
566 		e.msg = msg = g_strdup_printf (_("Could not remove directory "
567 				"'%s'."), folder);
568 		g_signal_emit (G_OBJECT (tree), signals[NEW_ERROR], 0, &e);
569 		g_free (msg);
570 		break;
571 	}
572 	g_free (folder);
573 	gtk_object_destroy (GTK_OBJECT (s));
574 }
575 
576 typedef struct _GtkamTreeDownloadData GtkamTreeDownloadData;
577 struct _GtkamTreeDownloadData {
578 	GtkWidget *fsel;
579 	GtkamTree *tree;
580 	GtkTreeIter *iter;
581 };
582 
583 static void
on_download_destroy(GtkObject * object,GtkamTreeDownloadData * dd)584 on_download_destroy (GtkObject *object, GtkamTreeDownloadData *dd)
585 {
586 	gtk_tree_iter_free (dd->iter);
587 	g_free (dd);
588 }
589 
590 static void
on_download_cancel_clicked(GtkButton * button,GtkFileSelection * fsel)591 on_download_cancel_clicked (GtkButton *button, GtkFileSelection *fsel)
592 {
593 	gtk_object_destroy (GTK_OBJECT (fsel));
594 }
595 
596 static gchar *
tree_concat_dir_and_file(const gchar * dirname,const gchar * filename)597 tree_concat_dir_and_file (const gchar *dirname, const gchar *filename)
598 {
599 	gchar *full_path;
600 
601 	if (!strcmp (dirname, "/"))
602 		full_path = g_strdup_printf ("/%s", filename);
603 	else if (dirname[strlen (dirname) - 1] == '/')
604 		full_path = g_strdup_printf ("%s%s", dirname, filename);
605 	else
606 		full_path = g_strdup_printf ("%s/%s", dirname, filename);
607 	return (full_path);
608 }
609 
610 static int
tree_save_file(CameraFile * file,const char * dest_path,const char * name,GtkWindow * save)611 tree_save_file (CameraFile *file, const char *dest_path, const char *name,
612 		GtkWindow *save)
613 {
614 	gchar *full_path, *msg;
615 	GtkWidget *dialog;
616 	int result;
617 
618 	/* Use filename provided by the CameraFile */
619 	full_path = tree_concat_dir_and_file (dest_path, name);
620 
621 	/* FIXME Check which is user, and prompt the user */
622 	if (file_exists (full_path)) {
623 		msg = g_strdup_printf (_("The file '%s' already exists."),
624 				       full_path);
625 		dialog = gtkam_error_new (GP_ERROR_FILE_EXISTS, NULL,
626 					  GTK_WIDGET (save), msg);
627 		gtk_widget_show (dialog);
628 		g_free (msg);
629 		g_free (full_path);
630 		return -1;
631 	}
632 
633 	/* FIXME Check for sufficient disk space for this file, or
634 	   calculate total disk space required for all files before
635 	   save process starts */
636 
637 	result = gp_file_save (file, full_path);
638 	if (result < 0) {
639 		dialog = gtkam_error_new (result, NULL, GTK_WIDGET (save),
640 				_("Could not save file to '%s'."), full_path);
641 		gtk_widget_show (dialog);
642 	}
643 
644 	g_free (full_path);
645 
646 	return result;
647 }
648 
649 static int
tree_get_file(GtkamCamera * camera,const gchar * dest_path,const gchar * folder,const gchar * name,GtkamContext * context,GtkWindow * save)650 tree_get_file (GtkamCamera *camera,
651 	       const gchar *dest_path, const gchar *folder, const gchar *name,
652 	       GtkamContext *context, GtkWindow *save)
653 {
654 	int result;
655 	GtkWidget *dialog;
656 	CameraFile *file;
657 
658 	gp_file_new (&file);
659 	result = gp_camera_file_get (camera->camera, folder, name,
660 				     GP_FILE_TYPE_NORMAL, file,
661 				     context->context);
662 	if (camera->multi)
663 		gp_camera_exit (camera->camera, NULL);
664 	switch (result) {
665 	case GP_OK:
666 		result = GP_OK;
667 		tree_save_file (file, dest_path, name, save);
668 		break;
669 	case GP_ERROR_CANCEL:
670 		break;
671 	default:
672 		dialog = gtkam_error_new (result, context, GTK_WIDGET (save),
673 					  _("Could not get '%s' "
674 					  "from folder '%s'."), name, folder);
675 		gtk_widget_show (dialog);
676 	}
677 	gp_file_unref (file);
678 
679 	return result;
680 }
681 
682 static int
tree_save_dir(GtkamCamera * camera,GtkamTree * tree,const gchar * path,const gchar * folder,GtkWindow * save)683 tree_save_dir(GtkamCamera *camera, GtkamTree *tree,
684 	      const gchar *path, const gchar *folder, GtkWindow *save)
685 {
686 	GtkWidget *s, *dialog;
687 	const gchar *name;
688 	gchar *new_path;
689 	CameraList *flist, *slist;
690 	gint i, count, id;
691 	int result;
692 	id = 0;
693 
694 	s = gtkam_status_new (_("Listing files in folder '%s'..."), folder);
695 	g_signal_emit (G_OBJECT (tree), signals[NEW_STATUS], 0, s);
696 	gp_list_new (&flist);
697 	result = gp_camera_folder_list_files (camera->camera, folder, flist,
698 					GTKAM_STATUS (s)->context->context);
699 	switch (result) {
700 	case GP_OK:
701 		break;
702 	case GP_ERROR_CANCEL:
703 		if (camera->multi)
704 			gp_camera_exit (camera->camera, NULL);
705 		gtk_object_destroy (GTK_OBJECT (s));
706 		return -1;
707 	default:
708 		if (camera->multi)
709 			gp_camera_exit (camera->camera, NULL);
710 		dialog = gtkam_error_new (result, GTKAM_STATUS (s)->context,
711 			GTK_WIDGET (save), _("Could not get file list "
712 			"for folder '%s'"), folder);
713 		gtk_widget_show (dialog);
714 		gtk_object_destroy (GTK_OBJECT (s));
715 		return -1;
716 	}
717 	gtk_object_destroy (GTK_OBJECT (s));
718 
719 	if (strcmp (folder, "/")) {
720 		new_path = g_strdup_printf ("%s/%s", path,
721 					    basename ((char *) folder));
722 		if (mkdir (new_path, 00755) < 0) {
723 			dialog = gtkam_error_new (result,
724 					GTKAM_STATUS (s)->context,
725 					GTK_WIDGET (save),
726 					_("Could not create directory '%s'"),
727 					new_path);
728 			gtk_widget_show (dialog);
729 			g_free(new_path);
730 			gtk_object_destroy (GTK_OBJECT (s));
731 			return -1;
732 		}
733 	} else
734 		new_path = g_strdup (path);
735 
736 	count = gp_list_count (flist);
737 	if (count == 1)
738 		s = gtkam_cancel_new (_("Downloading file from '%s'"), folder);
739 	else
740 		s = gtkam_cancel_new (_("Downloading %i files from '%s'"),
741 				      count, folder);
742 	gtk_window_set_transient_for (GTK_WINDOW (s), save);
743 	g_signal_emit (G_OBJECT (tree), signals[NEW_DIALOG], 0, s);
744 	gtk_widget_show (s);
745 
746 	if (count > 1)
747 		id = gp_context_progress_start (
748 			GTKAM_CANCEL (s)->context->context, count,
749 			_("Downloading %i files..."), count);
750 
751 	/* Loop through files */
752 	for (i = 0; i < count; i++) {
753 		gp_list_get_name (flist, i, &name);
754 
755 		result = tree_get_file (camera, new_path, folder, name,
756 					GTKAM_CANCEL (s)->context, save);
757 
758 		if (result < 0) {
759 			if (count > 1)
760 				gp_context_progress_stop (
761 					GTKAM_CANCEL (s)->context->context, id);
762 			dialog = gtkam_error_new (result,
763 					GTKAM_CANCEL (s)->context,
764 					GTK_WIDGET(save), _("Problem getting "
765 					"'%s' from folder '%s'."),
766 					name, folder);
767 			gtk_widget_show (dialog);
768 
769 			g_free(new_path);
770 			gtk_object_destroy (GTK_OBJECT (s));
771 			return -1;
772 		}
773 
774 		if (count > 1)
775 			gp_context_progress_update (
776 				GTKAM_CANCEL (s)->context->context, id, i + 1);
777 		gp_context_idle (GTKAM_CANCEL (s)->context->context);
778 		if (gp_context_cancel (GTKAM_CANCEL (s)->context->context) ==
779 				GP_CONTEXT_FEEDBACK_CANCEL)
780 			break;
781 	}
782 	gp_list_unref (flist);
783 
784 	if (count > 1)
785 		gp_context_progress_stop (
786 				GTKAM_CANCEL (s)->context->context, id);
787 	gtk_object_destroy (GTK_OBJECT (s));
788 
789 	/* Recurse into subfolders */
790 	s = gtkam_status_new (_("Listing subfolders in folder '%s'..."),
791 			      folder);
792 	g_signal_emit (G_OBJECT (tree), signals[NEW_STATUS], 0, s);
793 	gp_list_new (&slist);
794 	result = gp_camera_folder_list_folders (camera->camera, folder, slist,
795 					GTKAM_STATUS (s)->context->context);
796 	switch (result) {
797 	case GP_OK:
798 		break;
799 	case GP_ERROR_CANCEL:
800 		if (camera->multi)
801 			gp_camera_exit (camera->camera, NULL);
802 		gtk_object_destroy (GTK_OBJECT (s));
803 		g_free(new_path);
804 		return -1;
805 	default:
806 		if (camera->multi)
807 			gp_camera_exit (camera->camera, NULL);
808 		dialog = gtkam_error_new (result, GTKAM_STATUS (s)->context,
809 			GTK_WIDGET (save), _("Could not get subfolders list "
810 			"for folder '%s'"), folder);
811 		gtk_widget_show (dialog);
812 		gtk_object_destroy (GTK_OBJECT (s));
813 		g_free(new_path);
814 		return -1;
815 	}
816 	gtk_object_destroy (GTK_OBJECT (s));
817 
818 	count = gp_list_count (slist);
819 
820 	for (i = 0; i < count; i++) {
821 		gp_list_get_name (slist, i, &name);
822 		name = tree_concat_dir_and_file (folder, name);
823 
824 		result = tree_save_dir (camera, tree, new_path, name, save);
825 
826 		g_free((gchar *) name);
827 		if (result < 0)
828 			break;
829 	}
830 	gp_list_unref (slist);
831 
832 	g_free(new_path);
833 	return result;
834 }
835 
836 static void
on_download_ok_clicked(GtkButton * button,GtkamTreeDownloadData * dd)837 on_download_ok_clicked (GtkButton *button, GtkamTreeDownloadData *dd)
838 {
839 	const gchar *path, *final_path;
840 	gchar *folder;
841 	GtkamCamera *camera;
842 
843 	gtk_widget_hide (dd->fsel);
844 
845 	path = gtk_file_selection_get_filename (GTK_FILE_SELECTION (dd->fsel));
846 	/* Get the directory path */
847 	if (!g_file_test (path, G_FILE_TEST_EXISTS) ||
848 			g_file_test (path, G_FILE_TEST_IS_REGULAR))
849 		final_path = g_strdup (dirname ((char *) path));
850 	else
851 		final_path = g_strdup (path);
852 
853 	folder = gtkam_tree_get_path_from_iter (dd->tree, dd->iter);
854 	camera = gtkam_tree_get_camera_from_iter (dd->tree, dd->iter);
855 
856 	tree_save_dir(camera, dd->tree, final_path, folder,
857 		      GTK_WINDOW(dd->fsel));
858 	g_free((gchar *) final_path);
859 	gtk_object_destroy (GTK_OBJECT (dd->fsel));
860 }
861 
862 static void
action_download(gpointer callback_data,guint callback_action,GtkWidget * widget)863 action_download (gpointer callback_data, guint callback_action,
864 		 GtkWidget *widget)
865 {
866 	GtkWidget *fsel;
867 	GtkamTree *tree = GTKAM_TREE (callback_data);
868 	GtkamTreeDownloadData *dd;
869 	gchar *title, *folder;
870 
871 	folder = gtkam_tree_get_path_from_iter (tree, &tree->priv->iter);
872 	title = g_strdup_printf (_("Download '%s' subtree to..."), folder);
873 	g_free (folder);
874 	fsel = gtk_file_selection_new (title);
875 	g_free (title);
876 	g_signal_emit (G_OBJECT (tree), signals[NEW_DIALOG], 0, fsel);
877 	g_object_unref (G_OBJECT (fsel));
878 
879 	dd = g_new0 (GtkamTreeDownloadData, 1);
880 	dd->fsel = fsel;
881 	dd->tree = tree;
882 	dd->iter = gtk_tree_iter_copy (&tree->priv->iter);
883 	g_signal_connect (G_OBJECT (fsel), "destroy",
884 		G_CALLBACK (on_download_destroy), dd);
885 	g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (fsel)->ok_button),
886 		"clicked", G_CALLBACK (on_download_ok_clicked), dd);
887 	g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (fsel)->cancel_button),
888 		"clicked", G_CALLBACK (on_download_cancel_clicked), fsel);
889 }
890 
891 typedef enum _CameraTextType CameraTextType;
892 enum _CameraTextType {
893         CAMERA_TEXT_SUMMARY,
894         CAMERA_TEXT_MANUAL,
895         CAMERA_TEXT_ABOUT
896 };
897 
898 static void
action_text(GtkamTree * tree,CameraTextType type)899 action_text (GtkamTree *tree, CameraTextType type)
900 {
901 	GtkamCamera *camera;
902 	GtkWidget *s, *d;
903 	int r;
904 	CameraText text;
905 
906 	camera = gtkam_tree_get_camera_from_iter (tree, &tree->priv->iter);
907 	switch (type) {
908 	case CAMERA_TEXT_SUMMARY:
909 		s = gtkam_status_new (
910 			_("Getting information about the camera..."));
911 		break;
912 	case CAMERA_TEXT_ABOUT:
913 		s = gtkam_status_new (
914 			_("Getting information about the driver..."));
915 		break;
916 	case CAMERA_TEXT_MANUAL:
917 	default:
918 		s = gtkam_status_new (_("Getting manual..."));
919 		break;
920 	}
921 	g_signal_emit (G_OBJECT (tree), signals[NEW_STATUS], 0, s);
922 	switch (type) {
923 	case CAMERA_TEXT_SUMMARY:
924 		r = gp_camera_get_summary (camera->camera, &text,
925 			GTKAM_STATUS (s)->context->context);
926 		break;
927 	case CAMERA_TEXT_ABOUT:
928 		r = gp_camera_get_about (camera->camera, &text,
929 			GTKAM_STATUS (s)->context->context);
930 		break;
931 	case CAMERA_TEXT_MANUAL:
932 	default:
933 		r = gp_camera_get_manual (camera->camera, &text,
934 			GTKAM_STATUS (s)->context->context);
935 		break;
936 	}
937 	if (camera->multi)
938 		gp_camera_exit (camera->camera, NULL);
939 	switch (r) {
940 	case GP_OK:
941 		d = gtkam_close_new (text.text);
942 		g_signal_emit (G_OBJECT (tree), signals[NEW_DIALOG], 0, d);
943 		g_object_unref (G_OBJECT (d));
944 		break;
945 	case GP_ERROR_CANCEL:
946 		break;
947 	default:
948 		d = gtkam_error_new (r, GTKAM_STATUS (s)->context, NULL,
949 			_("Could not retrieve information."));
950 		g_signal_emit (G_OBJECT (tree), signals[NEW_DIALOG], 0, d);
951 		g_object_unref (G_OBJECT (d));
952 	}
953 	gtk_object_destroy (GTK_OBJECT (s));
954 }
955 
956 static void
action_summary(gpointer callback_data,guint callback_action,GtkWidget * widget)957 action_summary (gpointer callback_data, guint callback_action,
958 		GtkWidget *widget)
959 {
960 	GtkamTree *tree = GTKAM_TREE (callback_data);
961 
962 	action_text (tree, CAMERA_TEXT_SUMMARY);
963 }
964 
965 static void
action_preferences(gpointer callback_data,guint callback_action,GtkWidget * widget)966 action_preferences (gpointer callback_data, guint callback_action,
967 		    GtkWidget *widget)
968 {
969 	GtkWidget *d;
970 	GtkamTree *tree = GTKAM_TREE (callback_data);
971 	GtkamCamera *camera;
972 
973 	camera = gtkam_tree_get_camera_from_iter (tree, &tree->priv->iter);
974 	d = gtkam_config_new (camera);
975 	if (!d)
976 		return;
977 	g_signal_emit (G_OBJECT (tree), signals[NEW_DIALOG], 0, d);
978 	g_object_unref (G_OBJECT (d));
979 }
980 
981 static void
action_about(gpointer callback_data,guint callback_action,GtkWidget * widget)982 action_about (gpointer callback_data, guint callback_action,
983 	      GtkWidget *widget)
984 {
985 	GtkamTree *tree = GTKAM_TREE (callback_data);
986 
987 	action_text (tree, CAMERA_TEXT_ABOUT);
988 }
989 
990 typedef struct _CameraSelectedData CameraSelectedData;
991 struct _CameraSelectedData {
992 	GtkamTree *tree;
993 	GtkTreeIter *iter;
994 };
995 
996 static void
on_camera_selected(GtkamChooser * chooser,GtkamCamera * camera,CameraSelectedData * data)997 on_camera_selected (GtkamChooser *chooser, GtkamCamera *camera,
998 		    CameraSelectedData *data)
999 {
1000 	CameraAbilities a;
1001 	GtkTreeSelection *s;
1002 	GtkamTreeFolderUnselectedData fud;
1003 
1004 	s = gtk_tree_view_get_selection (GTK_TREE_VIEW (data->tree));
1005 	if (gtk_tree_selection_iter_is_selected (s, data->iter)) {
1006 		fud.camera = camera;
1007 		fud.folder = "/";
1008 		g_signal_emit (G_OBJECT (data->tree),
1009 			       signals[FOLDER_UNSELECTED], 0, &fud);
1010 	}
1011 
1012 	gp_camera_get_abilities (camera->camera, &a);
1013 	gtk_tree_store_set (data->tree->priv->store, data->iter,
1014 			    FOLDER_COLUMN, a.model,
1015 			    CAMERA_COLUMN, camera, -1);
1016 	gtkam_tree_update_iter (data->tree, data->iter);
1017 	gtkam_tree_save (data->tree);
1018 }
1019 
1020 static void
camera_selected_data_destroy(gpointer data)1021 camera_selected_data_destroy (gpointer data)
1022 {
1023 	CameraSelectedData *d = data;
1024 
1025 	gtk_tree_iter_free (d->iter);
1026 	g_free (d);
1027 }
1028 
1029 static void
action_remove_camera(gpointer callback_data,guint callback_action,GtkWidget * widget)1030 action_remove_camera (gpointer callback_data, guint callback_action,
1031 		      GtkWidget *widget)
1032 {
1033 	GtkamTree *tree = GTKAM_TREE (callback_data);
1034 
1035 	gtk_tree_store_remove (tree->priv->store, &tree->priv->iter);
1036 	gtkam_tree_save (tree);
1037 }
1038 
1039 static void
action_select_camera(gpointer callback_data,guint callback_action,GtkWidget * widget)1040 action_select_camera (gpointer callback_data, guint callback_action,
1041 		      GtkWidget *widget)
1042 {
1043 	GtkWidget *d;
1044 	GtkamTree *tree = GTKAM_TREE (callback_data);
1045 	CameraSelectedData *data;
1046 
1047 	d = gtkam_chooser_new ();
1048 	g_signal_emit (G_OBJECT (tree), signals[NEW_DIALOG], 0, d);
1049 	g_object_unref (G_OBJECT (d));
1050 	gtkam_chooser_set_camera (GTKAM_CHOOSER (d),
1051 		gtkam_tree_get_camera_from_iter (tree, &tree->priv->iter));
1052 	gtk_window_set_title (GTK_WINDOW (d), _("Select Camera"));
1053 	data = g_new0 (CameraSelectedData, 1);
1054 	data->tree = tree;
1055 	data->iter = gtk_tree_iter_copy (&tree->priv->iter);
1056 	g_signal_connect (G_OBJECT (d), "camera_selected",
1057 			  G_CALLBACK (on_camera_selected), data);
1058 	g_object_set_data_full (G_OBJECT (d), "data", data,
1059 				camera_selected_data_destroy);
1060 }
1061 
1062 static void
on_captured(GtkamPreview * preview,GtkamPreviewCapturedData * data,GtkamTree * tree)1063 on_captured (GtkamPreview *preview, GtkamPreviewCapturedData *data,
1064 	     GtkamTree *tree)
1065 {
1066 	GtkamTreeFileAddedData fad;
1067 
1068 	fad.folder = data->folder;
1069 	fad.name = data->name;
1070 	fad.camera = data->camera;
1071 	g_signal_emit (G_OBJECT (tree), signals[FILE_ADDED], 0, &fad);
1072 }
1073 
1074 static void
action_capture(gpointer callback_data,guint callback_action,GtkWidget * widget)1075 action_capture (gpointer callback_data, guint callback_action,
1076 		GtkWidget *widget)
1077 {
1078 	GtkamTree *tree = GTKAM_TREE (callback_data);
1079 	GtkamCamera *camera;
1080 	CameraAbilities a;
1081 	GtkWidget *s, *d;
1082 	int r;
1083 	GtkamTreeErrorData e;
1084 	GtkamTreeFileAddedData fad;
1085 	gchar *msg;
1086 	CameraFilePath path;
1087 
1088 	camera = gtkam_tree_get_camera_from_iter (tree, &tree->priv->iter);
1089 
1090 	/* Let's first check if the camera supports previews */
1091 	gp_camera_get_abilities (camera->camera, &a);
1092 	if (TRUE /*a.operations & GP_OPERATION_CAPTURE_PREVIEW*/) {
1093 		d = gtkam_preview_new (camera);
1094 		g_signal_emit (G_OBJECT (tree), signals[NEW_DIALOG], 0, d);
1095 		g_object_unref (G_OBJECT (d));
1096 		g_signal_connect (G_OBJECT (d), "captured",
1097 				  G_CALLBACK (on_captured), tree);
1098 		return;
1099 	}
1100 
1101 	/* The camera doesn't support previews. Capture an image. */
1102 	s = gtkam_status_new (_("Capturing image..."));
1103 	g_signal_emit (G_OBJECT (tree), signals[NEW_STATUS], 0, s);
1104 	r = gp_camera_capture (camera->camera, GP_CAPTURE_IMAGE, &path,
1105 			       GTKAM_STATUS (s)->context->context);
1106 	if (camera->multi)
1107 		gp_camera_exit (camera->camera, NULL);
1108 	switch (r) {
1109 	case GP_OK:
1110 		fad.camera = camera;
1111 		fad.folder = path.folder;
1112 		fad.name = path.name;
1113 		g_signal_emit (G_OBJECT (tree), signals[FILE_ADDED], 0, &fad);
1114 		break;
1115 	case GP_ERROR_CANCEL:
1116 		break;
1117 	default:
1118 		e.context = GTKAM_STATUS (s)->context;
1119 		e.result = r;
1120 		e.msg = msg = g_strdup (_("Could not capture."));
1121 		g_signal_emit (G_OBJECT (tree), signals[NEW_ERROR], 0, &e);
1122 		g_free (msg);
1123 		break;
1124 	}
1125 	gtk_object_destroy (GTK_OBJECT (s));
1126 }
1127 
1128 static void
action_manual(gpointer callback_data,guint callback_action,GtkWidget * widget)1129 action_manual (gpointer callback_data, guint callback_action,
1130 	       GtkWidget *widget)
1131 {
1132 	GtkamTree *tree = GTKAM_TREE (callback_data);
1133 
1134 	action_text (tree, CAMERA_TEXT_MANUAL);
1135 }
1136 
1137 static void
on_new_camera_selected(GtkamChooser * chooser,GtkamCamera * camera,GtkamTree * tree)1138 on_new_camera_selected (GtkamChooser *chooser, GtkamCamera *camera,
1139 			GtkamTree *tree)
1140 {
1141 	gtkam_tree_add_camera (tree, camera);
1142 }
1143 
1144 static void
on_add_camera_activate(GtkMenuItem * item,GtkamTree * tree)1145 on_add_camera_activate (GtkMenuItem *item, GtkamTree *tree)
1146 {
1147 	GtkWidget *d, *w;
1148 
1149 	w = gtk_widget_get_ancestor (GTK_WIDGET (tree), GTK_TYPE_WINDOW);
1150 	d = gtkam_chooser_new ();
1151 	gtk_window_set_transient_for (GTK_WINDOW (d), GTK_WINDOW (w));
1152 	gtk_widget_show (d);
1153 	g_signal_connect (G_OBJECT (d), "camera_selected",
1154 			  G_CALLBACK (on_new_camera_selected), tree);
1155 }
1156 
1157 static GtkItemFactoryEntry mi[] =
1158 {
1159 	{N_("/Upload file..."), NULL, action_upload, 0, NULL},
1160 	{N_("/Make directory..."), NULL, action_mkdir, 0, NULL},
1161 	{N_("/Delete directory"), NULL, action_rmdir, 0, NULL},
1162 	{N_("/Save directory tree..."), NULL, action_download, 0, NULL},
1163 	{"/sep1", NULL, NULL, 0, "<Separator>"},
1164 	{N_("/Capture image..."), NULL, action_capture, 0, NULL},
1165 	{N_("/View camera preferences"), NULL, action_preferences, 0,
1166 	 "<StockItem>", GTK_STOCK_PREFERENCES},
1167 	{N_("/View camera summary"), NULL, action_summary, 0, NULL},
1168 	{N_("/View camera manual"), NULL, action_manual, 0, NULL},
1169 	{N_("/View driver details"), NULL, action_about, 0, NULL},
1170 	{"/sep2", NULL, NULL, 0, "<Separator>"},
1171 	{N_("/Select camera..."), NULL, action_select_camera, 0, NULL},
1172 	{N_("/Remove camera"), NULL, action_remove_camera, 0, NULL},
1173 };
1174 
1175 #ifdef ENABLE_NLS
1176 
1177 static gchar *
translate_func(const gchar * path,gpointer data)1178 translate_func (const gchar *path, gpointer data)
1179 {
1180     return (_(path));
1181 }
1182 
1183 #endif
1184 
1185 static gint
on_button_press_event(GtkWidget * widget,GdkEventButton * event,GtkamTree * tree)1186 on_button_press_event (GtkWidget *widget, GdkEventButton *event,
1187 		       GtkamTree *tree)
1188 {
1189 	GtkTreePath *path = NULL;
1190 	GtkamCamera *camera;
1191 	GtkWidget *w, *m, *i;
1192 	CameraAbilities a;
1193 
1194 	switch (event->button) {
1195 	case 3:
1196 
1197 		/* Right-click on a tree item? */
1198 		if (!gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (tree),
1199 			event->x, event->y, &path, NULL, NULL, NULL)) {
1200 			m = gtk_menu_new ();
1201 			i = gtk_menu_item_new_with_mnemonic (
1202 							_("_Add camera..."));
1203 			gtk_widget_show (i);
1204 			gtk_container_add (GTK_CONTAINER (m), i);
1205 			g_signal_connect (G_OBJECT (i), "activate",
1206 				G_CALLBACK (on_add_camera_activate), tree);
1207 			gtk_menu_popup (GTK_MENU (m), NULL, NULL, NULL, NULL,
1208 					event->button, event->time);
1209 			return (TRUE);
1210 		}
1211 
1212 		gtk_tree_model_get_iter (GTK_TREE_MODEL (tree->priv->store),
1213 					 &tree->priv->iter, path);
1214 		camera = gtkam_tree_get_camera_from_iter (tree,
1215 							  &tree->priv->iter);
1216 		gp_camera_get_abilities (camera->camera, &a);
1217 		gtk_tree_path_free (path);
1218 
1219 		/* What operations does the camera support? */
1220 		w = gtk_item_factory_get_widget (tree->priv->factory,
1221 						 "/Make directory...");
1222 		gtk_widget_set_sensitive (w,
1223 			a.folder_operations & GP_FOLDER_OPERATION_MAKE_DIR);
1224 		w = gtk_item_factory_get_widget (tree->priv->factory,
1225 						 "/Delete directory");
1226 		gtk_widget_set_sensitive (w,
1227 			a.folder_operations & GP_FOLDER_OPERATION_REMOVE_DIR);
1228 		w = gtk_item_factory_get_widget (tree->priv->factory,
1229 						 "/Upload file...");
1230 		gtk_widget_set_sensitive (w,
1231 			a.folder_operations & GP_FOLDER_OPERATION_PUT_FILE);
1232 		w = gtk_item_factory_get_widget (tree->priv->factory,
1233 						 "/View camera preferences");
1234 		gtk_widget_set_sensitive (w,
1235 			a.operations & GP_OPERATION_CONFIG);
1236 		w = gtk_item_factory_get_widget (tree->priv->factory,
1237 						 "/Capture image...");
1238 		gtk_widget_set_sensitive (w,
1239 			/*a.operations & GP_OPERATION_CAPTURE_IMAGE */ TRUE);
1240 
1241 		gtk_item_factory_popup (tree->priv->factory, event->x_root,
1242 				event->y_root, event->button, event->time);
1243 
1244 		return (TRUE);
1245 	default:
1246 		return (FALSE);
1247 	}
1248 }
1249 
1250 static void
on_row_deleted(GtkTreeModel * model,GtkTreePath * path,GtkamTree * tree)1251 on_row_deleted (GtkTreeModel *model, GtkTreePath *path,
1252 		GtkamTree *tree)
1253 {
1254 	GtkTreeIter iter;
1255 	gchar *folder;
1256 	GtkamTreeFolderUnselectedData fdd;
1257 
1258 	if (!gtk_tree_model_get_iter (model, &iter, path))
1259 		return;
1260 
1261 	fdd.camera = gtkam_tree_get_camera_from_iter (tree, &iter);
1262 	fdd.folder = folder = gtkam_tree_get_path_from_iter (tree, &iter);
1263 	g_signal_emit (G_OBJECT (tree), signals[FOLDER_UNSELECTED], 0, &fdd);
1264 	g_free (folder);
1265 }
1266 
1267 static void
on_drag_data_received(GtkWidget * widget,GdkDragContext * context,gint x,gint y,GtkSelectionData * selection_data,guint info,guint time,GtkamTree * tree)1268 on_drag_data_received (GtkWidget *widget, GdkDragContext *context,
1269 		       gint x, gint y, GtkSelectionData *selection_data,
1270 		       guint info, guint time, GtkamTree *tree)
1271 {
1272 	g_warning ("Fixme: on_drag_data_received");
1273 }
1274 
1275 #if 0
1276 static GtkTargetEntry targets[] = {
1277 	{"text/uri-list", 0, 0}
1278 };
1279 #endif
1280 
1281 GtkWidget *
gtkam_tree_new(void)1282 gtkam_tree_new (void)
1283 {
1284         GtkamTree *tree;
1285         GtkCellRenderer *renderer;
1286 	GtkTreeSelection *selection;
1287 	GtkAccelGroup *ag;
1288 
1289         tree = g_object_new (GTKAM_TYPE_TREE, NULL);
1290 	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree), FALSE);
1291 #if 0
1292 	gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW (tree),
1293 		targets, G_N_ELEMENTS (targets),
1294 		GDK_ACTION_COPY);
1295 #endif
1296 	g_signal_connect (G_OBJECT (tree), "drag_data_received",
1297 			  G_CALLBACK (on_drag_data_received), tree);
1298 	g_signal_connect (G_OBJECT (tree), "button_press_event",
1299 			  G_CALLBACK (on_button_press_event), tree);
1300 
1301 	gtk_tooltips_set_tip (tree->priv->tooltips, GTK_WIDGET (tree),
1302 		(_("Please right-click to access additional menus")), NULL);
1303 
1304 	ag = gtk_accel_group_new ();
1305 	tree->priv->factory = gtk_item_factory_new (GTK_TYPE_MENU,
1306 						    "<popup>", ag);
1307 #ifdef ENABLE_NLS
1308 	gtk_item_factory_set_translate_func (GTK_ITEM_FACTORY (tree->priv->factory),
1309 					translate_func, NULL, NULL);
1310 #endif
1311 	gtk_item_factory_create_items (tree->priv->factory,
1312 				       G_N_ELEMENTS (mi), mi, tree);
1313 	g_object_ref (G_OBJECT (tree->priv->factory));
1314 	gtk_object_sink (GTK_OBJECT (tree->priv->factory));
1315 
1316 	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree));
1317 	gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
1318 	gtk_tree_selection_set_select_function (selection, selection_func,
1319 						tree, NULL);
1320 
1321         tree->priv->store = gtk_tree_store_new (NUM_COLUMNS, G_TYPE_STRING,
1322 						GTKAM_TYPE_CAMERA);
1323 	g_signal_connect (G_OBJECT (tree->priv->store), "row_deleted",
1324 			  G_CALLBACK (on_row_deleted), tree);
1325         gtk_tree_view_set_model (GTK_TREE_VIEW (tree),
1326                                  GTK_TREE_MODEL (tree->priv->store));
1327 
1328         /* Column for folder names. */
1329         renderer = gtk_cell_renderer_text_new ();
1330         gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree),
1331                         -1, _("Folder"), renderer, "text",
1332                         FOLDER_COLUMN, NULL);
1333         g_signal_connect (G_OBJECT (tree), "row_expanded",
1334                           G_CALLBACK (on_row_expanded), tree);
1335 
1336         return (GTK_WIDGET (tree));
1337 }
1338 
1339 void
gtkam_tree_add_camera(GtkamTree * tree,GtkamCamera * camera)1340 gtkam_tree_add_camera (GtkamTree *tree, GtkamCamera *camera)
1341 {
1342         CameraAbilities a;
1343         GtkTreeIter iter;
1344 
1345         g_return_if_fail (GTKAM_IS_TREE (tree));
1346 	g_return_if_fail (GTKAM_IS_CAMERA (camera));
1347 
1348         gp_camera_get_abilities (camera->camera, &a);
1349         gtk_tree_store_append (tree->priv->store, &iter, NULL);
1350         gtk_tree_store_set (tree->priv->store, &iter,
1351                             FOLDER_COLUMN, a.model,
1352 			    CAMERA_COLUMN, camera, -1);
1353         gtkam_tree_update_iter (tree, &iter);
1354         gtkam_tree_save (tree);
1355 }
1356 
1357 #ifdef HAVE_GP_CAMERA_SET_TIMEOUT_FUNCS
1358 
1359 typedef struct _TimeoutData TimeoutData;
1360 struct _TimeoutData {
1361 	Camera *camera;
1362 	CameraTimeoutFunc func;
1363 };
1364 
1365 static gboolean
timeout_func(gpointer data)1366 timeout_func (gpointer data)
1367 {
1368 	TimeoutData *td = data;
1369 
1370 	td->func (td->camera, NULL);
1371 
1372 	/* Repeat forever */
1373 	return (TRUE);
1374 }
1375 
1376 static void
timeout_destroy_notify(gpointer data)1377 timeout_destroy_notify (gpointer data)
1378 {
1379 	TimeoutData *td = data;
1380 
1381 	g_free (td);
1382 }
1383 
1384 static unsigned int
start_timeout_func(Camera * camera,unsigned int timeout,CameraTimeoutFunc func,void * data)1385 start_timeout_func (Camera *camera, unsigned int timeout,
1386 		    CameraTimeoutFunc func, void *data)
1387 {
1388 	TimeoutData *td;
1389 
1390 	td = g_new0 (TimeoutData, 1);
1391 	td->camera = camera;
1392 	td->func = func;
1393 
1394 	return (gtk_timeout_add_full (timeout * 1000, timeout_func, NULL,
1395 				      td, timeout_destroy_notify));
1396 }
1397 
1398 static void
stop_timeout_func(Camera * camera,unsigned int id,void * data)1399 stop_timeout_func (Camera *camera, unsigned int id, void *data)
1400 {
1401 	gtk_timeout_remove (id);
1402 }
1403 
1404 #endif
1405 
1406 void
gtkam_tree_load(GtkamTree * tree)1407 gtkam_tree_load (GtkamTree *tree)
1408 {
1409 	GtkWidget *s;
1410 	char port[1024], speed[1024], model[1024], multi[1024];
1411 	Camera *camera;
1412 	CameraAbilitiesList *al;
1413 	GPPortInfoList *il;
1414 	GPPortInfo info;
1415 	CameraAbilities a;
1416 	int n, p, result;
1417 	gchar *ms;
1418 	guint i;
1419 	GtkTreeIter iter;
1420 	GtkamCamera *c;
1421 
1422 	g_return_if_fail (GTKAM_IS_TREE (tree));
1423 
1424 	s = gtkam_status_new (_("Loading cameras..."));
1425 	g_signal_emit (G_OBJECT (tree), signals[NEW_STATUS], 0, s);
1426 
1427 	gp_abilities_list_new (&al);
1428 	gp_abilities_list_load (al, GTKAM_STATUS (s)->context->context);
1429 	gp_port_info_list_new (&il);
1430 	gp_port_info_list_load (il);
1431 
1432 	gtk_object_destroy (GTK_OBJECT (s));
1433 
1434 	/* Load settings */
1435 	for (i = 1; ; i++) {
1436 		ms = g_strdup_printf ("model-%i", i);
1437 		result = gp_setting_get ("gtkam", ms, model);
1438 		g_free (ms);
1439 		if (result < 0)
1440 			break;
1441 		if (!strcmp (model, ""))
1442 			break;
1443 
1444 		ms = g_strdup_printf ("port-%i", i);
1445 		result = gp_setting_get ("gtkam", ms, port);
1446 		g_free (ms);
1447 		if (result < 0)
1448 			break;
1449 
1450 		ms = g_strdup_printf ("multi-%i", i);
1451 		result = gp_setting_get ("gtkam", ms, multi);
1452 		g_free (ms);
1453 		if (result < 0)
1454 			break;
1455 
1456 		ms = g_strdup_printf ("speed-%i", i);
1457 		result = gp_setting_get ("gtkam", ms, speed);
1458 		g_free (ms);
1459 		if (result < 0)
1460 			break;
1461 
1462 		gp_camera_new (&camera);
1463 #ifdef HAVE_GP_CAMERA_SET_TIMEOUT_FUNCS
1464                 gp_camera_set_timeout_funcs (camera, start_timeout_func,
1465                                              stop_timeout_func, NULL);
1466 #endif
1467 
1468                 n = gp_abilities_list_lookup_model (al, model);
1469                 gp_abilities_list_get_abilities (al, n, &a);
1470 
1471 		if (strcmp (port, "") && strcmp (port, "None") &&
1472 		    strcmp (model, "Directory Browse")) {
1473 	                p = gp_port_info_list_lookup_path (il, port);
1474         	        if (p < 0) {
1475                 	        g_warning ("Could not find '%s' in port "
1476 					"info list (%s)!", port,
1477 					gp_result_as_string (p));
1478 				gp_camera_unref (camera);
1479 				continue;
1480 			}
1481 			gp_port_info_list_get_info (il, p, &info);
1482 			gp_camera_set_port_info (camera, info);
1483 		}
1484 
1485                 gp_camera_set_abilities (camera, a);
1486                 if (atoi (speed))
1487                         gp_camera_set_port_speed (camera, atoi (speed));
1488 
1489                 /* Add this camera to our tree. */
1490 		gtk_tree_store_append (tree->priv->store, &iter, NULL);
1491 		c = gtkam_camera_new (camera, atoi (multi));
1492 		gtk_tree_store_set (tree->priv->store, &iter,
1493 				    FOLDER_COLUMN, model,
1494 				    CAMERA_COLUMN, c, -1);
1495 		g_object_unref (G_OBJECT (c));
1496 		gtkam_tree_update_iter (tree, &iter);
1497 	}
1498 
1499 	gp_abilities_list_free (al);
1500 	gp_port_info_list_free (il);
1501 }
1502 
1503 void
gtkam_tree_save(GtkamTree * tree)1504 gtkam_tree_save (GtkamTree *tree)
1505 {
1506 	GtkTreeIter child;
1507 	guint i, n;
1508 	GtkamCamera *camera;
1509 	GPPortInfo info;
1510 	CameraAbilities a;
1511 	int speed, result;
1512 	gchar *ms, *mm;
1513 	char model[1024];
1514 
1515 	/* Clear the configuration file */
1516 	for (i = 1; ; i++) {
1517 		ms = g_strdup_printf ("model-%i", i);
1518 		result = gp_setting_get ("gtkam", ms, model);
1519 		g_free (ms);
1520 		if (result < 0)
1521 			break;
1522 
1523 		memset (model, 0, sizeof (model));
1524 		ms = g_strdup_printf ("model-%i", i);
1525 		gp_setting_set ("gtkam", ms, model);
1526 		g_free (ms);
1527 	}
1528 
1529 	/* Iterate over all cameras. */
1530 	n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (tree->priv->store),
1531 					    NULL);
1532 	for (i = 0; i < n; i++) {
1533 #ifdef HAVE_GP_PORT_INFO_GET_NAME
1534 		char *xpath;
1535 #endif
1536 		gtk_tree_model_iter_nth_child (
1537 					GTK_TREE_MODEL (tree->priv->store),
1538 					&child, NULL, i);
1539 		camera = gtkam_tree_get_camera_from_iter (tree, &child);
1540 
1541 		gp_camera_get_abilities (camera->camera, &a);
1542 		gp_camera_get_port_info (camera->camera, &info);
1543 		speed = gp_camera_get_port_speed (camera->camera);
1544 
1545 		ms = g_strdup_printf ("model-%i", i + 1);
1546 		gp_setting_set ("gtkam", ms, a.model);
1547 		g_free (ms);
1548 
1549 		ms = g_strdup_printf ("port-%i", i + 1);
1550 #ifdef HAVE_GP_PORT_INFO_GET_NAME
1551 		gp_port_info_get_path (info, &xpath);
1552 		gp_setting_set ("gtkam", ms, xpath);
1553 #else
1554 		gp_setting_set ("gtkam", ms, info.path);
1555 #endif
1556 		g_free (ms);
1557 
1558 		ms = g_strdup_printf ("multi-%i", i + 1);
1559 		mm = g_strdup_printf ("%i", camera->multi ? 1 : 0);
1560 		gp_setting_set ("gtkam", ms, mm);
1561 		g_free (mm);
1562 		g_free (ms);
1563 
1564 		ms = g_strdup_printf ("speed-%i", i + 1);
1565 		mm = g_strdup_printf ("%i", speed);
1566 		gp_setting_set ("gtkam", ms, mm);
1567 		g_free (mm);
1568 		g_free (ms);
1569 	}
1570 }
1571