1 /* gtkam-cancel.c
2  *
3  * Copyright 2001-2002 Lutz Mueller <lutz@users.sf.net>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "config.h"
20 #include "gtkam-cancel.h"
21 #include "i18n.h"
22 
23 #include <string.h>
24 
25 #include <gtk/gtkbutton.h>
26 #include <gtk/gtkmain.h>
27 #include <gtk/gtklabel.h>
28 #include <gtk/gtksignal.h>
29 #include <gtk/gtkhbox.h>
30 #include <gtk/gtkprogressbar.h>
31 #include <gtk/gtkpixmap.h>
32 #include <gtk/gtkmarshal.h>
33 #include <gtk/gtkimage.h>
34 #include <gtk/gtkstock.h>
35 
36 #include <gphoto2/gphoto2-result.h>
37 
38 #include "gtkam-close.h"
39 
40 struct _GtkamCancelPrivate
41 {
42 	GPtrArray *array_hbox, *array_progress;
43 	GArray *target;
44 
45 	gboolean cancelled;
46 };
47 
48 #define PARENT_TYPE GTKAM_TYPE_DIALOG
49 static GtkamDialogClass *parent_class;
50 
51 enum {
52 	CANCEL,
53 	LAST_SIGNAL
54 };
55 
56 static guint signals[LAST_SIGNAL] = {0};
57 
58 static void
gtkam_cancel_destroy(GtkObject * object)59 gtkam_cancel_destroy (GtkObject *object)
60 {
61 	GtkamCancel *cancel = GTKAM_CANCEL (object);
62 
63 	if (cancel->context) {
64 		g_object_unref (G_OBJECT (cancel->context));
65 		cancel->context = NULL;
66 	}
67 
68 	g_ptr_array_set_size (cancel->priv->array_hbox, 0);
69 	g_ptr_array_set_size (cancel->priv->array_progress, 0);
70 	g_array_set_size (cancel->priv->target, 0);
71 
72 	GTK_OBJECT_CLASS (parent_class)->destroy (object);
73 }
74 
75 static void
gtkam_cancel_finalize(GObject * object)76 gtkam_cancel_finalize (GObject *object)
77 {
78 	GtkamCancel *cancel = GTKAM_CANCEL (object);
79 
80 	g_array_free (cancel->priv->target, TRUE);
81 	g_ptr_array_free (cancel->priv->array_hbox, TRUE);
82 	g_ptr_array_free (cancel->priv->array_progress, TRUE);
83 	g_free (cancel->priv);
84 
85 	G_OBJECT_CLASS (parent_class)->finalize (object);
86 }
87 
88 static void
gtkam_cancel_class_init(gpointer g_class,gpointer class_data)89 gtkam_cancel_class_init (gpointer g_class, gpointer class_data)
90 {
91 	GtkObjectClass *object_class;
92 	GObjectClass *gobject_class;
93 
94 	object_class = GTK_OBJECT_CLASS (g_class);
95 	object_class->destroy  = gtkam_cancel_destroy;
96 
97 	gobject_class = G_OBJECT_CLASS (g_class);
98 	gobject_class->finalize = gtkam_cancel_finalize;
99 
100 	signals[CANCEL] = g_signal_new ("cancel",
101 		G_TYPE_FROM_CLASS (g_class), G_SIGNAL_RUN_LAST,
102 		G_STRUCT_OFFSET (GtkamCancelClass, cancel), NULL, NULL,
103 		g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
104 
105 	parent_class = g_type_class_peek_parent (g_class);
106 }
107 
108 static void
gtkam_cancel_init(GTypeInstance * instance,gpointer g_class)109 gtkam_cancel_init (GTypeInstance *instance, gpointer g_class)
110 {
111 	GtkamCancel *cancel = GTKAM_CANCEL (instance);
112 
113 	cancel->context = gtkam_context_new ();
114 
115 	cancel->priv = g_new0 (GtkamCancelPrivate, 1);
116 	cancel->priv->array_hbox = g_ptr_array_new ();
117 	cancel->priv->array_progress = g_ptr_array_new ();
118 	cancel->priv->target = g_array_new (FALSE, TRUE, sizeof (float));
119 }
120 
121 GType
gtkam_cancel_get_type(void)122 gtkam_cancel_get_type (void)
123 {
124 	static GType type = 0;
125 
126 	if (!type) {
127 		GTypeInfo ti;
128 
129 		memset (&ti, 0, sizeof (GTypeInfo));
130 		ti.class_size     = sizeof (GtkamCancelClass);
131 		ti.class_init     = gtkam_cancel_class_init;
132 		ti.instance_size  = sizeof (GtkamCancel);
133 		ti.instance_init  = gtkam_cancel_init;
134 
135 		type = g_type_register_static (PARENT_TYPE, "GtkamCancel",
136 					        &ti, 0);
137 	}
138 
139 	return (type);
140 }
141 
142 static void
on_cancel_clicked(GtkButton * button,GtkamCancel * cancel)143 on_cancel_clicked (GtkButton *button, GtkamCancel *cancel)
144 {
145 	cancel->priv->cancelled = TRUE;
146 	g_signal_emit (GTK_OBJECT (cancel), signals[CANCEL], 0);
147 }
148 
149 static GPContextFeedback
cancel_func(GPContext * c,void * data)150 cancel_func (GPContext *c, void *data)
151 {
152 	GtkamCancel *cancel = GTKAM_CANCEL (data);
153 
154 	return (cancel->priv->cancelled ? GP_CONTEXT_FEEDBACK_CANCEL :
155 					  GP_CONTEXT_FEEDBACK_OK);
156 }
157 
158 static void
message_func(GPContext * context,const char * msg,void * data)159 message_func (GPContext *context, const char *msg, void *data)
160 {
161 	GtkamCancel *cancel = GTKAM_CANCEL (data);
162         GtkWidget *d;
163 
164 	cancel = NULL;
165         d = gtkam_close_new (msg);
166         gtk_widget_show (d);
167 }
168 
169 static unsigned int
start_func(GPContext * c,float target,const char * msg,void * data)170 start_func (GPContext *c, float target, const char *msg, void *data)
171 {
172 	GtkamCancel *cancel = GTKAM_CANCEL (data);
173 	GtkWidget *p, *label, *hbox;
174 	unsigned int i;
175 
176 	hbox = gtk_hbox_new (FALSE, 5);
177 	gtk_widget_show (hbox);
178 	gtk_box_pack_start (GTK_BOX (GTKAM_DIALOG (cancel)->vbox), hbox,
179 			    TRUE, TRUE, 0);
180 
181 	label = gtk_label_new (msg);
182 	gtk_widget_show (label);
183 	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
184 
185 	p = gtk_progress_bar_new ();
186 	gtk_widget_show (p);
187 	gtk_box_pack_start (GTK_BOX (hbox), p, TRUE, TRUE, 0);
188 
189 	for (i = 0; i < cancel->priv->array_progress->len; i++)
190 		if (!cancel->priv->array_progress->pdata[i])
191 			break;
192 	if (i == cancel->priv->array_progress->len) {
193 		g_ptr_array_add (cancel->priv->array_hbox, hbox);
194 		g_ptr_array_add (cancel->priv->array_progress, p);
195 		g_array_append_val (cancel->priv->target, target);
196 	} else {
197 		cancel->priv->array_hbox->pdata[i] = hbox;
198 		cancel->priv->array_progress->pdata[i] = p;
199 		g_array_index (cancel->priv->target, gfloat, i) = target;
200 	}
201 
202 	return (cancel->priv->array_progress->len - 1);
203 }
204 
205 static void
update_func(GPContext * c,unsigned int id,float current,void * data)206 update_func (GPContext *c, unsigned int id, float current, void *data)
207 {
208 	GtkamCancel *cancel = GTKAM_CANCEL (data);
209 	GtkProgressBar *p;
210 
211 	g_return_if_fail (id < cancel->priv->array_progress->len);
212 
213 	p = cancel->priv->array_progress->pdata[id];
214 	gtk_progress_bar_set_fraction (p,
215 		current / g_array_index (cancel->priv->target, float, id));
216 
217 	while (gtk_events_pending ())
218 		gtk_main_iteration ();
219 }
220 
221 static void
stop_func(GPContext * c,unsigned int id,void * data)222 stop_func (GPContext *c, unsigned int id, void *data)
223 {
224 	GtkamCancel *cancel = GTKAM_CANCEL (data);
225 
226 	g_return_if_fail (id < cancel->priv->array_progress->len);
227 
228 	gtk_object_destroy (GTK_OBJECT (cancel->priv->array_hbox->pdata[id]));
229 
230 	cancel->priv->array_hbox->pdata[id] = NULL;
231 	cancel->priv->array_progress->pdata[id] = NULL;
232 	g_array_index (cancel->priv->target, gfloat, id) = 0.;
233 }
234 
235 static void
idle_func(GPContext * context,void * data)236 idle_func (GPContext *context, void *data)
237 {
238 	while (gtk_events_pending ())
239 		gtk_main_iteration ();
240 }
241 
242 GtkWidget *
gtkam_cancel_new(const gchar * format,...)243 gtkam_cancel_new (const gchar *format, ...)
244 {
245 	GtkamCancel *cancel;
246 	GtkWidget *label, *button;
247 	va_list args;
248 	gchar *msg;
249 
250 	cancel = g_object_new (GTKAM_TYPE_CANCEL, NULL);
251 
252 	va_start (args, format);
253 	msg = g_strdup_vprintf (format, args);
254 	va_end (args);
255 	label = gtk_label_new (msg);
256 	g_free (msg);
257 	gtk_widget_show (label);
258 	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
259 	gtk_misc_set_alignment (GTK_MISC (label), 0., 0.);
260 	gtk_box_pack_start (GTK_BOX (GTKAM_DIALOG (cancel)->vbox),
261 			    label, TRUE, TRUE, 0);
262 
263 	button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
264 	gtk_widget_show (button);
265 	g_signal_connect (GTK_OBJECT (button), "clicked",
266 			    GTK_SIGNAL_FUNC (on_cancel_clicked), cancel);
267 	gtk_container_add (GTK_CONTAINER (GTK_DIALOG (cancel)->action_area),
268 			   button);
269 	gtk_widget_grab_focus (button);
270 
271 	gp_context_set_progress_funcs (cancel->context->context, start_func,
272 				       update_func, stop_func, cancel);
273 	gp_context_set_idle_func (cancel->context->context, idle_func, cancel);
274 	gp_context_set_cancel_func (cancel->context->context,
275 				    cancel_func, cancel);
276 	gp_context_set_message_func (cancel->context->context,
277 				     message_func, cancel);
278 
279 	return (GTK_WIDGET (cancel));
280 }
281