1 /*
2 * Copyright (C) 2009 - 2011 Vivien Malerba <malerba@gnome-db.org>
3 * Copyright (C) 2010 David King <davidk@openismus.com>
4 * Copyright (C) 2011 Murray Cumming <murrayc@murrayc.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library 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 GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22 #include <libgda/gda-value.h>
23 #include "common-bin.h"
24 #include "../internal/popup-container.h"
25 #include <string.h>
26 #include <gtk/gtk.h>
27 #include <glib/gi18n-lib.h>
28 #include <libgda/gda-blob-op.h>
29
30 #ifdef HAVE_GIO
31 #include <gio/gio.h>
32 #endif
33
34 static void
file_load_cb(GtkWidget * button,BinMenu * menu)35 file_load_cb (GtkWidget *button, BinMenu *menu)
36 {
37 GtkWidget *dlg;
38
39 gtk_widget_hide (menu->popup);
40 dlg = gtk_file_chooser_dialog_new (_("Select file to load"),
41 GTK_WINDOW (gtk_widget_get_toplevel (button)),
42 GTK_FILE_CHOOSER_ACTION_OPEN,
43 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
44 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
45 NULL);
46 if (menu->current_folder)
47 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dlg), menu->current_folder);
48
49 if (gtk_dialog_run (GTK_DIALOG (dlg)) == GTK_RESPONSE_ACCEPT) {
50 char *filename;
51 gsize length;
52 GError *error = NULL;
53 gchar *data;
54
55 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dlg));
56
57 if (menu->entry_type == GDA_TYPE_BLOB) {
58 menu->loaded_value_cb (menu->loaded_value_cb_data,
59 gda_value_new_blob_from_file (filename));
60 }
61 else if (menu->entry_type == GDA_TYPE_BINARY) {
62 if (g_file_get_contents (filename, &data, &length, &error)) {
63 GdaBinary *bin;
64 GValue *nvalue;
65 bin = g_new0 (GdaBinary, 1);
66 bin->data = (guchar*) data;
67 bin->binary_length = length;
68 nvalue = gda_value_new (GDA_TYPE_BINARY);
69 gda_value_take_binary (nvalue, bin);
70
71 menu->loaded_value_cb (menu->loaded_value_cb_data, nvalue);
72 }
73 else {
74 GtkWidget *msg;
75
76 msg = gtk_message_dialog_new_with_markup (GTK_WINDOW (gtk_widget_get_toplevel (button)),
77 GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR,
78 GTK_BUTTONS_CLOSE,
79 _("Could not load the contents of '%s':\n %s"),
80 filename,
81 error && error->message ? error->message : _("No detail"));
82 if (error)
83 g_error_free (error);
84 gtk_widget_destroy (dlg);
85 dlg = NULL;
86
87 gtk_dialog_run (GTK_DIALOG (msg));
88 gtk_widget_destroy (msg);
89 }
90 }
91 else
92 g_assert_not_reached ();
93
94 g_free (filename);
95 }
96
97 if (dlg) {
98 g_free (menu->current_folder);
99 menu->current_folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dlg));
100 gtk_widget_destroy (dlg);
101 }
102 }
103
104 static void
file_save_cb(GtkWidget * button,BinMenu * menu)105 file_save_cb (GtkWidget *button, BinMenu *menu)
106 {
107 GtkWidget *dlg;
108
109 gtk_widget_hide (menu->popup);
110 dlg = gtk_file_chooser_dialog_new (_("Select a file to save data to"),
111 GTK_WINDOW (gtk_widget_get_toplevel (button)),
112 GTK_FILE_CHOOSER_ACTION_SAVE,
113 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
114 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
115 NULL);
116
117 if (menu->current_folder)
118 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dlg), menu->current_folder);
119
120 if (gtk_dialog_run (GTK_DIALOG (dlg)) == GTK_RESPONSE_ACCEPT) {
121 char *filename;
122 gboolean allok = TRUE;
123 GError *error = NULL;
124
125 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dlg));
126 if (menu->entry_type == GDA_TYPE_BINARY) {
127 const GdaBinary *bin;
128 bin = gda_value_get_binary (menu->tmpvalue);
129 allok = g_file_set_contents (filename, (gchar *) bin->data,
130 bin->binary_length, &error);
131 }
132 else if (menu->entry_type == GDA_TYPE_BLOB) {
133 GdaBlob *blob;
134 blob = (GdaBlob*) gda_value_get_blob (menu->tmpvalue);
135 if (blob->op) {
136
137 GValue *dest_value;
138 GdaBlob *dest_blob;
139
140 dest_value = gda_value_new_blob_from_file (filename);
141 dest_blob = (GdaBlob*) gda_value_get_blob (dest_value);
142 allok = gda_blob_op_write_all (dest_blob->op, (GdaBlob*) blob);
143 gda_value_free (dest_value);
144 }
145 else
146 allok = g_file_set_contents (filename, (gchar *) ((GdaBinary*)blob)->data,
147 ((GdaBinary*)blob)->binary_length, &error);
148 }
149 else
150 g_assert_not_reached ();
151 if (!allok) {
152 GtkWidget *msg;
153 msg = gtk_message_dialog_new_with_markup (GTK_WINDOW (gtk_widget_get_toplevel (button)),
154 GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR,
155 GTK_BUTTONS_CLOSE,
156 _("Could not save data to '%s':\n %s"),
157 filename,
158 error && error->message ? error->message : _("No detail"));
159 if (error)
160 g_error_free (error);
161 gtk_widget_destroy (dlg);
162 dlg = NULL;
163
164 gtk_dialog_run (GTK_DIALOG (msg));
165 gtk_widget_destroy (msg);
166 }
167 g_free (filename);
168 }
169
170 if (dlg) {
171 g_free (menu->current_folder);
172 menu->current_folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dlg));
173 gtk_widget_destroy (dlg);
174
175 }
176 }
177
178 void
common_bin_create_menu(BinMenu * binmenu,PopupContainerPositionFunc pos_func,GType entry_type,BinCallback loaded_value_cb,gpointer loaded_value_cb_data)179 common_bin_create_menu (BinMenu *binmenu, PopupContainerPositionFunc pos_func, GType entry_type,
180 BinCallback loaded_value_cb, gpointer loaded_value_cb_data)
181 {
182 GtkWidget *popup, *vbox, *hbox, *bbox, *button, *label;
183 gchar *str;
184
185 binmenu->entry_type = entry_type;
186 binmenu->loaded_value_cb = loaded_value_cb;
187 binmenu->loaded_value_cb_data = loaded_value_cb_data;
188
189 popup = popup_container_new_with_func (pos_func);
190 binmenu->popup = popup;
191
192 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
193 gtk_container_add (GTK_CONTAINER (popup), vbox);
194
195 label = gtk_label_new ("");
196 str = g_strdup_printf ("<b>%s:</b>", _("Properties"));
197 gtk_label_set_markup (GTK_LABEL (label), str);
198 g_free (str);
199 gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
200 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
201
202 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); /* HIG */
203 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 5);
204 gtk_widget_show (hbox);
205 label = gtk_label_new (" ");
206 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
207 gtk_widget_show (label);
208
209 label = gtk_label_new ("");
210 gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
211 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
212 binmenu->props_label = label;
213
214 bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
215 gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
216
217 button = gtk_button_new_from_stock (GTK_STOCK_OPEN);
218 gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
219 g_signal_connect (button, "clicked",
220 G_CALLBACK (file_load_cb), binmenu);
221 binmenu->load_button = button;
222
223 button = gtk_button_new_from_stock (GTK_STOCK_SAVE_AS);
224 gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
225 g_signal_connect (button, "clicked",
226 G_CALLBACK (file_save_cb), binmenu);
227 binmenu->save_button = button;
228
229 gtk_widget_show_all (vbox);
230 }
231
232 static gchar *
format_size(gulong size)233 format_size (gulong size)
234 {
235 if (size < 1024)
236 return g_strdup_printf (ngettext ("%lu Byte", "%lu Bytes", size), size);
237 else if (size < 1048576)
238 return g_strdup_printf ("%.1f Kio", (gfloat) (size / 1024));
239 else if (size < 1073741824)
240 return g_strdup_printf ("%.1f Mio", (gfloat) (size / 1048576));
241 else
242 return g_strdup_printf ("%.1f Gio", (gfloat) (size / 1073741824));
243 }
244
245 /*
246 * adjust the sensitiveness of the menu items in the popup menu
247 */
248 void
common_bin_adjust_menu(BinMenu * binmenu,gboolean editable,const GValue * value)249 common_bin_adjust_menu (BinMenu *binmenu, gboolean editable, const GValue *value)
250 {
251 gchar *size;
252 GString *string;
253 #ifdef HAVE_GIO
254 gchar *ctype = NULL;
255 #endif
256
257 if (!binmenu || !binmenu->popup)
258 return;
259
260 if (binmenu->tmpvalue) {
261 gda_value_free (binmenu->tmpvalue);
262 binmenu->tmpvalue = NULL;
263 }
264 string = g_string_new ("");
265 if (value) {
266 binmenu->tmpvalue = gda_value_copy (value);
267 if (G_VALUE_TYPE (value) == GDA_TYPE_NULL)
268 g_string_append_printf (string, "<i>%s</i>", _("No data"));
269 else if (G_VALUE_TYPE (value) == GDA_TYPE_BINARY) {
270 const GdaBinary *bin;
271 bin = gda_value_get_binary (value);
272 size = format_size (bin->binary_length);
273 g_string_append_printf (string, "%s: %s", _("Data size"), size);
274 g_free (size);
275 #ifdef HAVE_GIO
276 ctype = g_content_type_guess (NULL, bin->data, (gsize) bin->binary_length, NULL);
277 #endif
278 }
279 else if (G_VALUE_TYPE (value) == GDA_TYPE_BLOB) {
280 const GdaBlob *blob;
281 GdaBinary *bin;
282 blob = gda_value_get_blob (value);
283 bin = (GdaBinary *) blob;
284 if (blob->op) {
285 glong len;
286 len = gda_blob_op_get_length (blob->op);
287 if (len >= 0) {
288 size = format_size (len);
289 g_string_append_printf (string, "%s: %s", _("Data size"), size);
290 g_free (size);
291 #ifdef HAVE_GIO
292 GdaBlob *blob2;
293 blob2 = (GdaBlob*) gda_blob_copy ((gpointer) blob);
294 gda_blob_op_read (blob2->op, blob2, 0, 1024);
295 bin = (GdaBinary *) blob2;
296 ctype = g_content_type_guess (NULL, bin->data,
297 (gsize) bin->binary_length, NULL);
298 gda_blob_free ((gpointer) blob2);
299 #endif
300 }
301 else
302 g_string_append_printf (string, "%s: %s", _("Data size"), _("Unknown"));
303 }
304 else {
305 size = format_size (bin->binary_length);
306 g_string_append_printf (string, "%s: %s", _("Data size"), size);
307 g_free (size);
308 #ifdef HAVE_GIO
309 ctype = g_content_type_guess (NULL, bin->data, (gsize) bin->binary_length, NULL);
310 #endif
311 }
312 }
313 else
314 g_assert_not_reached ();
315 }
316 else
317 g_string_append_printf (string, "<i>%s</i>", _("No data"));
318
319 #ifdef HAVE_GIO
320 if (ctype) {
321 GList *list;
322 gchar *descr, *tmp;
323 descr = g_content_type_get_description (ctype);
324 tmp = g_markup_escape_text (descr, -1);
325 g_free (descr);
326 g_string_append_printf (string, "\n%s: %s", _("Data type"), tmp);
327 g_free (tmp);
328
329 list = g_app_info_get_all_for_type (ctype);
330 for (; list; list = list->next) {
331 GAppInfo *ai;
332 ai = (GAppInfo*) list->data;
333 g_print ("\t open with %s (%s)\n", g_app_info_get_name (ai),
334 g_app_info_get_executable (ai));
335 }
336 g_free (ctype);
337 }
338 #endif
339
340
341 gtk_label_set_markup (GTK_LABEL (binmenu->props_label), string->str);
342 g_string_free (string, TRUE);
343
344 gtk_widget_set_sensitive (binmenu->load_button, editable);
345 gtk_widget_set_sensitive (binmenu->save_button, (value && !gda_value_is_null (value)) ? TRUE : FALSE);
346 }
347
348 /*
349 * Reset @bonmenu's contents
350 */
351 void
common_bin_reset(BinMenu * binmenu)352 common_bin_reset (BinMenu *binmenu)
353 {
354 if (binmenu->tmpvalue) {
355 gda_value_free (binmenu->tmpvalue);
356 binmenu->tmpvalue = NULL;
357 }
358 if (binmenu->popup)
359 gtk_widget_destroy (binmenu->popup);
360 g_free (binmenu->current_folder);
361
362 memset (binmenu, 0, sizeof (BinMenu));
363 }
364