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 move_byte_forward(char * dest_m,const char * src_m,size_t count)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 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 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 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 * 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 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 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