Code

format string protection/clean up (CVE-2007-1463, CVE-2007-1464)
[inkscape.git] / src / interface.cpp
1 #define __SP_INTERFACE_C__
3 /**
4  * Main UI stuff
5  *
6  * Authors:
7  *   Lauris Kaplinski <lauris@kaplinski.com>
8  *   Frank Felfe <innerspace@iname.com>
9  *   bulia byak <buliabyak@users.sf.net>
10  *
11  * Copyright (C) 1999-2005 authors
12  * Copyright (C) 2001-2002 Ximian, Inc.
13  * Copyright (C) 2004 David Turner
14  *
15  * Released under GNU GPL, read the file 'COPYING' for more information
16  */
18 #ifdef HAVE_CONFIG_H
19 # include "config.h"
20 #endif
22 #include <gtk/gtk.h>
23 #include "inkscape-private.h"
24 #include "extension/effect.h"
25 #include "widgets/icon.h"
26 #include "prefs-utils.h"
27 #include "path-prefix.h"
29 #include "shortcuts.h"
31 #include "document.h"
32 #include "desktop-handles.h"
33 #include "file.h"
34 #include "interface.h"
35 #include "desktop.h"
36 #include "ui/context-menu.h"
37 #include "selection.h"
38 #include "selection-chemistry.h"
39 #include "svg-view-widget.h"
40 #include "widgets/desktop-widget.h"
41 #include "sp-item-group.h"
42 #include "sp-namedview.h"
44 #include "helper/action.h"
45 #include "helper/gnome-utils.h"
46 #include "helper/window.h"
48 #include "io/sys.h"
49 #include "io/stringstream.h"
50 #include "io/base64stream.h"
52 #include "dialogs/dialog-events.h"
54 #include "message-context.h"
56 // Added for color drag-n-drop
57 #if ENABLE_LCMS
58 #include "lcms.h"
59 #endif // ENABLE_LCMS
60 #include "display/sp-canvas.h"
61 #include "color.h"
62 #include "svg/svg-color.h"
63 #include "desktop-style.h"
64 #include "style.h"
67 using Inkscape::IO::StringOutputStream;
68 using Inkscape::IO::Base64OutputStream;
70 /* forward declaration */
71 static gint sp_ui_delete(GtkWidget *widget, GdkEvent *event, Inkscape::UI::View::View *view);
73 /* Drag and Drop */
74 typedef enum {
75     URI_LIST,
76     SVG_XML_DATA,
77     SVG_DATA,
78     PNG_DATA,
79     JPEG_DATA,
80     IMAGE_DATA,
81     APP_X_INKY_COLOR,
82     APP_X_COLOR
83 } ui_drop_target_info;
85 static GtkTargetEntry ui_drop_target_entries [] = {
86     {"text/uri-list", 0, URI_LIST},
87     {"image/svg+xml", 0, SVG_XML_DATA},
88     {"image/svg",     0, SVG_DATA},
89     {"image/png",     0, PNG_DATA},
90     {"image/jpeg",    0, JPEG_DATA},
91 #if ENABLE_MAGIC_COLORS
92     {"application/x-inkscape-color", 0, APP_X_INKY_COLOR},
93 #endif // ENABLE_MAGIC_COLORS
94     {"application/x-color", 0, APP_X_COLOR}
95 };
97 static GtkTargetEntry *completeDropTargets = 0;
98 static int completeDropTargetsCount = 0;
100 #define ENTRIES_SIZE(n) sizeof(n)/sizeof(n[0])
101 static guint nui_drop_target_entries = ENTRIES_SIZE(ui_drop_target_entries);
102 static void sp_ui_import_files(gchar *buffer);
103 static void sp_ui_import_one_file(char const *filename);
104 static void sp_ui_import_one_file_with_check(gpointer filename, gpointer unused);
105 static void sp_ui_drag_data_received(GtkWidget *widget,
106                                      GdkDragContext *drag_context,
107                                      gint x, gint y,
108                                      GtkSelectionData *data,
109                                      guint info,
110                                      guint event_time,
111                                      gpointer user_data);
112 static void sp_ui_menu_item_set_sensitive(SPAction *action,
113                                           unsigned int sensitive,
114                                           void *data);
115 static void sp_ui_menu_item_set_name(SPAction *action, 
116                                      Glib::ustring name,
117                                      void *data);
119 SPActionEventVector menu_item_event_vector = {
120     {NULL},
121     NULL,
122     NULL, /* set_active */
123     sp_ui_menu_item_set_sensitive, /* set_sensitive */
124     NULL, /* set_shortcut */
125     sp_ui_menu_item_set_name /* set_name */
126 };
128 void
129 sp_create_window(SPViewWidget *vw, gboolean editable)
131     g_return_if_fail(vw != NULL);
132     g_return_if_fail(SP_IS_VIEW_WIDGET(vw));
134     GtkWidget *w = sp_window_new("", TRUE);
136     if (editable) {
137       g_object_set_data(G_OBJECT(vw), "window", w);
138       reinterpret_cast<SPDesktopWidget*>(vw)->window =
139         static_cast<GtkWindow*>((void*)w);
140     }
142     if (editable) {
143         /* fixme: */
144         gtk_window_set_default_size((GtkWindow *) w, 640, 480);
145         g_object_set_data(G_OBJECT(w), "desktop", SP_DESKTOP_WIDGET(vw)->desktop);
146         g_object_set_data(G_OBJECT(w), "desktopwidget", vw);
147         g_signal_connect(G_OBJECT(w), "delete_event", G_CALLBACK(sp_ui_delete), vw->view);
148         g_signal_connect(G_OBJECT(w), "focus_in_event", G_CALLBACK(sp_desktop_widget_set_focus), vw);
149     } else {
150         gtk_window_set_policy(GTK_WINDOW(w), TRUE, TRUE, TRUE);
151     }
153     gtk_container_add(GTK_CONTAINER(w), GTK_WIDGET(vw));
154     gtk_widget_show(GTK_WIDGET(vw));
156     if ( completeDropTargets == 0 || completeDropTargetsCount == 0 )
157     {
158         std::vector<gchar*> types;
160         GSList *list = gdk_pixbuf_get_formats();
161         while ( list ) {
162             int i = 0;
163             GdkPixbufFormat *one = (GdkPixbufFormat*)list->data;
164             gchar** typesXX = gdk_pixbuf_format_get_mime_types(one);
165             for ( i = 0; typesXX[i]; i++ ) {
166                 types.push_back(g_strdup(typesXX[i]));
167             }
168             g_strfreev(typesXX);
170             list = g_slist_next(list);
171         }
172         completeDropTargetsCount = nui_drop_target_entries + types.size();
173         completeDropTargets = new GtkTargetEntry[completeDropTargetsCount];
174         for ( int i = 0; i < (int)nui_drop_target_entries; i++ ) {
175             completeDropTargets[i] = ui_drop_target_entries[i];
176         }
177         int pos = nui_drop_target_entries;
179         for (std::vector<gchar*>::iterator it = types.begin() ; it != types.end() ; it++) {
180             completeDropTargets[pos].target = *it;
181             completeDropTargets[pos].flags = 0;
182             completeDropTargets[pos].info = IMAGE_DATA;
183             pos++;
184         }
185     }
187     gtk_drag_dest_set(w,
188                       GTK_DEST_DEFAULT_ALL,
189                       completeDropTargets,
190                       completeDropTargetsCount,
191                       GdkDragAction(GDK_ACTION_COPY | GDK_ACTION_MOVE));
192     g_signal_connect(G_OBJECT(w),
193                      "drag_data_received",
194                      G_CALLBACK(sp_ui_drag_data_received),
195                      NULL);
196     gtk_widget_show(w);
198     // needed because the first ACTIVATE_DESKTOP was sent when there was no window yet
199     inkscape_reactivate_desktop(SP_DESKTOP_WIDGET(vw)->desktop);
202 void
203 sp_ui_new_view()
205     SPDocument *document;
206     SPViewWidget *dtw;
208     document = SP_ACTIVE_DOCUMENT;
209     if (!document) return;
211     dtw = sp_desktop_widget_new(sp_document_namedview(document, NULL));
212     g_return_if_fail(dtw != NULL);
214     sp_create_window(dtw, TRUE);
215     sp_namedview_window_from_document(static_cast<SPDesktop*>(dtw->view));
216     sp_namedview_update_layers_from_document(static_cast<SPDesktop*>(dtw->view));
219 /* TODO: not yet working */
220 /* To be re-enabled (by adding to menu) once it works. */
221 void
222 sp_ui_new_view_preview()
224     SPDocument *document;
225     SPViewWidget *dtw;
227     document = SP_ACTIVE_DOCUMENT;
228     if (!document) return;
230     dtw = (SPViewWidget *) sp_svg_view_widget_new(document);
231     g_return_if_fail(dtw != NULL);
232     sp_svg_view_widget_set_resize(SP_SVG_VIEW_WIDGET(dtw), TRUE, 400.0, 400.0);
234     sp_create_window(dtw, FALSE);
237 /**
238  * \param widget unused
239  */
240 void
241 sp_ui_close_view(GtkWidget *widget)
243     if (SP_ACTIVE_DESKTOP == NULL) {
244         return;
245     }
246     if ((SP_ACTIVE_DESKTOP)->shutdown()) {
247         return;
248     }
249     SP_ACTIVE_DESKTOP->destroyWidget();
253 /**
254  *  sp_ui_close_all
255  *
256  *  This function is called to exit the program, and iterates through all
257  *  open document view windows, attempting to close each in turn.  If the
258  *  view has unsaved information, the user will be prompted to save,
259  *  discard, or cancel.
260  *
261  *  Returns FALSE if the user cancels the close_all operation, TRUE
262  *  otherwise.
263  */
264 unsigned int
265 sp_ui_close_all(void)
267     /* Iterate through all the windows, destroying each in the order they
268        become active */
269     while (SP_ACTIVE_DESKTOP) {
270         if ((SP_ACTIVE_DESKTOP)->shutdown()) {
271             /* The user cancelled the operation, so end doing the close */
272             return FALSE;
273         }
274         SP_ACTIVE_DESKTOP->destroyWidget();
275     }
277     return TRUE;
280 static gint
281 sp_ui_delete(GtkWidget *widget, GdkEvent *event, Inkscape::UI::View::View *view)
283     return view->shutdown();
286 /*
287  * Some day when the right-click menus are ready to start working
288  * smarter with the verbs, we'll need to change this NULL being
289  * sent to sp_action_perform to something useful, or set some kind
290  * of global "right-clicked position" variable for actions to
291  * investigate when they're called.
292  */
293 static void
294 sp_ui_menu_activate(void *object, SPAction *action)
296     sp_action_perform(action, NULL);
299 static void
300 sp_ui_menu_select_action(void *object, SPAction *action)
302     action->view->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, action->tip);
305 static void
306 sp_ui_menu_deselect_action(void *object, SPAction *action)
308     action->view->tipsMessageContext()->clear();
311 static void
312 sp_ui_menu_select(gpointer object, gpointer tip)
314     Inkscape::UI::View::View *view = static_cast<Inkscape::UI::View::View*> (g_object_get_data(G_OBJECT(object), "view"));
315     view->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, (gchar *)tip);
318 static void
319 sp_ui_menu_deselect(gpointer object)
321     Inkscape::UI::View::View *view = static_cast<Inkscape::UI::View::View*>  (g_object_get_data(G_OBJECT(object), "view"));
322     view->tipsMessageContext()->clear();
325 /**
326  * sp_ui_menuitem_add_icon
327  *
328  * Creates and attaches a scaled icon to the given menu item.
329  *
330  */
331 void
332 sp_ui_menuitem_add_icon( GtkWidget *item, gchar *icon_name )
334     GtkWidget *icon;
336     icon = sp_icon_new( Inkscape::ICON_SIZE_MENU, icon_name );
337     gtk_widget_show(icon);
338     gtk_image_menu_item_set_image((GtkImageMenuItem *) item, icon);
339 } // end of sp_ui_menu_add_icon
341 /**
342  * sp_ui_menu_append_item
343  *
344  * Appends a UI item with specific info for Inkscape/Sodipodi.
345  *
346  */
347 static GtkWidget *
348 sp_ui_menu_append_item( GtkMenu *menu, gchar const *stock,
349                         gchar const *label, gchar const *tip, Inkscape::UI::View::View *view, GCallback callback,
350                         gpointer data, gboolean with_mnemonic = TRUE )
352     GtkWidget *item;
354     if (stock) {
355         item = gtk_image_menu_item_new_from_stock(stock, NULL);
356     } else if (label) {
357         item = (with_mnemonic)
358             ? gtk_image_menu_item_new_with_mnemonic(label) :
359             gtk_image_menu_item_new_with_label(label);
360     } else {
361         item = gtk_separator_menu_item_new();
362     }
364     gtk_widget_show(item);
366     if (callback) {
367         g_signal_connect(G_OBJECT(item), "activate", callback, data);
368     }
370     if (tip && view) {
371         g_object_set_data(G_OBJECT(item), "view", (gpointer) view);
372         g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select), (gpointer) tip );
373         g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect), NULL);
374     }
376     gtk_menu_append(GTK_MENU(menu), item);
378     return item;
380 } // end of sp_ui_menu_append_item()
382 /**
383 \brief  a wrapper around gdk_keyval_name producing (when possible) characters, not names
384  */
385 static gchar const *
386 sp_key_name(guint keyval)
388     /* TODO: Compare with the definition of gtk_accel_label_refetch in gtk/gtkaccellabel.c (or
389        simply use GtkAccelLabel as the TODO comment in sp_ui_shortcut_string suggests). */
390     gchar const *n = gdk_keyval_name(gdk_keyval_to_upper(keyval));
392     if      (!strcmp(n, "asciicircum"))  return "^";
393     else if (!strcmp(n, "parenleft"  ))  return "(";
394     else if (!strcmp(n, "parenright" ))  return ")";
395     else if (!strcmp(n, "plus"       ))  return "+";
396     else if (!strcmp(n, "minus"      ))  return "-";
397     else if (!strcmp(n, "asterisk"   ))  return "*";
398     else if (!strcmp(n, "KP_Multiply"))  return "*";
399     else if (!strcmp(n, "Delete"     ))  return "Del";
400     else if (!strcmp(n, "Page_Up"    ))  return "PgUp";
401     else if (!strcmp(n, "Page_Down"  ))  return "PgDn";
402     else if (!strcmp(n, "grave"      ))  return "`";
403     else if (!strcmp(n, "numbersign" ))  return "#";
404     else if (!strcmp(n, "bar" ))  return "|";
405     else if (!strcmp(n, "slash" ))  return "/";
406     else if (!strcmp(n, "exclam" ))  return "!";
407     else return n;
411 /**
412  * \param shortcut A GDK keyval OR'd with SP_SHORTCUT_blah_MASK values.
413  * \param c Points to a buffer at least 256 bytes long.
414  */
415 void
416 sp_ui_shortcut_string(unsigned const shortcut, gchar *const c)
418     /* TODO: This function shouldn't exist.  Our callers should use GtkAccelLabel instead of
419      * a generic GtkLabel containing this string, and should call gtk_widget_add_accelerator.
420      * Will probably need to change sp_shortcut_invoke callers.
421      *
422      * The existing gtk_label_new_with_mnemonic call can be replaced with
423      * g_object_new(GTK_TYPE_ACCEL_LABEL, NULL) followed by
424      * gtk_label_set_text_with_mnemonic(lbl, str).
425      */
426     static GtkAccelLabelClass const &accel_lbl_cls
427         = *(GtkAccelLabelClass const *) g_type_class_peek_static(GTK_TYPE_ACCEL_LABEL);
429     struct { unsigned test; char const *name; } const modifier_tbl[] = {
430         { SP_SHORTCUT_SHIFT_MASK,   accel_lbl_cls.mod_name_shift   },
431         { SP_SHORTCUT_CONTROL_MASK, accel_lbl_cls.mod_name_control },
432         { SP_SHORTCUT_ALT_MASK,     accel_lbl_cls.mod_name_alt     }
433     };
435     gchar *p = c;
436     gchar *end = p + 256;
438     for (unsigned i = 0; i < G_N_ELEMENTS(modifier_tbl); ++i) {
439         if ((shortcut & modifier_tbl[i].test)
440             && (p < end))
441         {
442             p += g_snprintf(p, end - p, "%s%s",
443                             modifier_tbl[i].name,
444                             accel_lbl_cls.mod_separator);
445         }
446     }
447     if (p < end) {
448         p += g_snprintf(p, end - p, "%s", sp_key_name(shortcut & 0xffffff));
449     }
450     end[-1] = '\0';  // snprintf doesn't guarantee to nul-terminate the string.
453 void
454 sp_ui_dialog_title_string(Inkscape::Verb *verb, gchar *c)
456     SPAction     *action;
457     unsigned int shortcut;
458     gchar        *s;
459     gchar        key[256];
460     gchar        *atitle;
462     action = verb->get_action(NULL);
463     if (!action)
464         return;
466     atitle = sp_action_get_title(action);
468     s = g_stpcpy(c, atitle);
470     g_free(atitle);
472     shortcut = sp_shortcut_get_primary(verb);
473     if (shortcut) {
474         s = g_stpcpy(s, " (");
475         sp_ui_shortcut_string(shortcut, key);
476         s = g_stpcpy(s, key);
477         s = g_stpcpy(s, ")");
478     }
482 /**
483  * sp_ui_menu_append_item_from_verb
484  *
485  * Appends a custom menu UI from a verb.
486  *
487  */
489 static GtkWidget *
490 sp_ui_menu_append_item_from_verb(GtkMenu *menu, Inkscape::Verb *verb, Inkscape::UI::View::View *view, bool radio = false, GSList *group = NULL)
492     SPAction *action;
493     GtkWidget *item;
495     if (verb->get_code() == SP_VERB_NONE) {
497         item = gtk_separator_menu_item_new();
499     } else {
500         unsigned int shortcut;
502         action = verb->get_action(view);
504         if (!action) return NULL;
506         shortcut = sp_shortcut_get_primary(verb);
507         if (shortcut) {
508             gchar c[256];
509             sp_ui_shortcut_string(shortcut, c);
510             GtkWidget *const hb = gtk_hbox_new(FALSE, 16);
511             GtkWidget *const name_lbl = gtk_label_new("");
512             gtk_label_set_markup_with_mnemonic(GTK_LABEL(name_lbl), action->name);
513             gtk_misc_set_alignment((GtkMisc *) name_lbl, 0.0, 0.5);
514             gtk_box_pack_start((GtkBox *) hb, name_lbl, TRUE, TRUE, 0);
515             GtkWidget *const accel_lbl = gtk_label_new(c);
516             gtk_misc_set_alignment((GtkMisc *) accel_lbl, 1.0, 0.5);
517             gtk_box_pack_end((GtkBox *) hb, accel_lbl, FALSE, FALSE, 0);
518             gtk_widget_show_all(hb);
519             if (radio) {
520                 item = gtk_radio_menu_item_new (group);
521             } else {
522                 item = gtk_image_menu_item_new();
523             }
524             gtk_container_add((GtkContainer *) item, hb);
525         } else {
526             if (radio) {
527                 item = gtk_radio_menu_item_new (group);
528             } else {
529                 item = gtk_image_menu_item_new ();
530             }
531             GtkWidget *const name_lbl = gtk_label_new("");
532             gtk_label_set_markup_with_mnemonic(GTK_LABEL(name_lbl), action->name);
533             gtk_misc_set_alignment((GtkMisc *) name_lbl, 0.0, 0.5);
534             gtk_container_add((GtkContainer *) item, name_lbl);
535         }
537         nr_active_object_add_listener((NRActiveObject *)action, (NRObjectEventVector *)&menu_item_event_vector, sizeof(SPActionEventVector), item);
538         if (!action->sensitive) {
539             gtk_widget_set_sensitive(item, FALSE);
540         }
542         if (action->image) {
543             sp_ui_menuitem_add_icon(item, action->image);
544         }
545         gtk_widget_set_events(item, GDK_KEY_PRESS_MASK);
546         g_signal_connect( G_OBJECT(item), "activate",
547                           G_CALLBACK(sp_ui_menu_activate), action );
549         g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select_action), action );
550         g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect_action), action );
551     }
553     gtk_widget_show(item);
554     gtk_menu_append(GTK_MENU(menu), item);
556     return item;
558 } // end of sp_ui_menu_append_item_from_verb
561 static void
562 checkitem_toggled(GtkCheckMenuItem *menuitem, gpointer user_data)
564     gchar const *pref = (gchar const *) user_data;
565     Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view");
567     gchar const *pref_path;
568     if (reinterpret_cast<SPDesktop*>(view)->is_fullscreen)
569         pref_path = g_strconcat("fullscreen.", pref, NULL);
570     else
571         pref_path = g_strconcat("window.", pref, NULL);
573     gboolean checked = gtk_check_menu_item_get_active(menuitem);
574     prefs_set_int_attribute(pref_path, "state", checked);
576     reinterpret_cast<SPDesktop*>(view)->layoutWidget();
579 static gboolean
580 checkitem_update(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
582     GtkCheckMenuItem *menuitem=GTK_CHECK_MENU_ITEM(widget);
584     gchar const *pref = (gchar const *) user_data;
585     Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view");
587     gchar const *pref_path;
588     if (static_cast<SPDesktop*>(view)->is_fullscreen)
589         pref_path = g_strconcat("fullscreen.", pref, NULL);
590     else
591         pref_path = g_strconcat("window.", pref, NULL);
593     gint ison = prefs_get_int_attribute_limited(pref_path, "state", 1, 0, 1);
595     g_signal_handlers_block_by_func(G_OBJECT(menuitem), (gpointer)(GCallback)checkitem_toggled, user_data);
596     gtk_check_menu_item_set_active(menuitem, ison);
597     g_signal_handlers_unblock_by_func(G_OBJECT(menuitem), (gpointer)(GCallback)checkitem_toggled, user_data);
599     return FALSE;
603 void
604 sp_ui_menu_append_check_item_from_verb(GtkMenu *menu, Inkscape::UI::View::View *view, gchar const *label, gchar const *tip, gchar const *pref,
605                                        void (*callback_toggle)(GtkCheckMenuItem *, gpointer user_data),
606                                        gboolean (*callback_update)(GtkWidget *widget, GdkEventExpose *event, gpointer user_data),
607                                        Inkscape::Verb *verb)
609     GtkWidget *item;
611     unsigned int shortcut = 0;
612     SPAction *action = NULL;
614     if (verb) {
615         shortcut = sp_shortcut_get_primary(verb);
616         action = verb->get_action(view);
617     }
619     if (verb && shortcut) {
620         gchar c[256];
621         sp_ui_shortcut_string(shortcut, c);
623         GtkWidget *hb = gtk_hbox_new(FALSE, 16);
625         {
626             GtkWidget *l = gtk_label_new_with_mnemonic(action ? action->name : label);
627             gtk_misc_set_alignment((GtkMisc *) l, 0.0, 0.5);
628             gtk_box_pack_start((GtkBox *) hb, l, TRUE, TRUE, 0);
629         }
631         {
632             GtkWidget *l = gtk_label_new(c);
633             gtk_misc_set_alignment((GtkMisc *) l, 1.0, 0.5);
634             gtk_box_pack_end((GtkBox *) hb, l, FALSE, FALSE, 0);
635         }
637         gtk_widget_show_all(hb);
639         item = gtk_check_menu_item_new();
640         gtk_container_add((GtkContainer *) item, hb);
641     } else {
642         GtkWidget *l = gtk_label_new_with_mnemonic(action ? action->name : label);
643         gtk_misc_set_alignment((GtkMisc *) l, 0.0, 0.5);
644         item = gtk_check_menu_item_new();
645         gtk_container_add((GtkContainer *) item, l);
646     }
647 #if 0
648     nr_active_object_add_listener((NRActiveObject *)action, (NRObjectEventVector *)&menu_item_event_vector, sizeof(SPActionEventVector), item);
649     if (!action->sensitive) {
650         gtk_widget_set_sensitive(item, FALSE);
651     }
652 #endif
653     gtk_widget_show(item);
655     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
657     g_object_set_data(G_OBJECT(item), "view", (gpointer) view);
659     g_signal_connect( G_OBJECT(item), "toggled", (GCallback) callback_toggle, (void *) pref);
660     g_signal_connect( G_OBJECT(item), "expose_event", (GCallback) callback_update, (void *) pref);
662     g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select), (gpointer) (action ? action->tip : tip));
663     g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect), NULL);
666 static void
667 sp_recent_open(GtkWidget *widget, gchar const *uri)
669     sp_file_open(uri, NULL);
672 static void
673 sp_file_new_from_template(GtkWidget *widget, gchar const *uri)
675     sp_file_new(uri);
678 void
679 sp_menu_append_new_templates(GtkWidget *menu, Inkscape::UI::View::View *view)
681     std::list<gchar *> sources;
682     sources.push_back( profile_path("templates") ); // first try user's local dir
683     sources.push_back( g_strdup(INKSCAPE_TEMPLATESDIR) ); // then the system templates dir
685     // Use this loop to iterate through a list of possible document locations.
686     while (!sources.empty()) {
687         gchar *dirname = sources.front();
689         if ( Inkscape::IO::file_test( dirname, (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR) ) ) {
690             GError *err = 0;
691             GDir *dir = g_dir_open(dirname, 0, &err);
693             if (dir) {
694                 for (gchar const *file = g_dir_read_name(dir); file != NULL; file = g_dir_read_name(dir)) {
695                     if (!g_str_has_suffix(file, ".svg") && !g_str_has_suffix(file, ".svgz"))
696                         continue; // skip non-svg files
698                     gchar *basename = g_path_get_basename(file);
699                     if (g_str_has_suffix(basename, ".svg") && g_str_has_prefix(basename, "default."))
700                         continue; // skip default.*.svg (i.e. default.svg and translations) - it's in the menu already
702                     gchar const *filepath = g_build_filename(dirname, file, NULL);
703                     gchar *dupfile = g_strndup(file, strlen(file) - 4);
704                     gchar *filename =  g_filename_to_utf8(dupfile,  -1, NULL, NULL, NULL);
705                     g_free(dupfile);
706                     GtkWidget *item = gtk_menu_item_new_with_label(filename);
707                     g_free(filename);
709                     gtk_widget_show(item);
710                     // how does "filepath" ever get freed?
711                     g_signal_connect(G_OBJECT(item),
712                                      "activate",
713                                      G_CALLBACK(sp_file_new_from_template),
714                                      (gpointer) filepath);
716                     if (view) {
717                         // set null tip for now; later use a description from the template file
718                         g_object_set_data(G_OBJECT(item), "view", (gpointer) view);
719                         g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select), (gpointer) NULL );
720                         g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect), NULL);
721                     }
723                     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
724                 }
725                 g_dir_close(dir);
726             }
727         }
729         // toss the dirname
730         g_free(dirname);
731         sources.pop_front();
732     }
735 void
736 sp_menu_append_recent_documents(GtkWidget *menu, Inkscape::UI::View::View* /* view */)
738     gchar const **recent = prefs_get_recent_files();
739     if (recent) {
740         int i;
742         for (i = 0; recent[i] != NULL; i += 2) {
743             gchar const *uri = recent[i];
744             gchar const *name = recent[i + 1];
746             GtkWidget *item = gtk_menu_item_new_with_label(name);
747             gtk_widget_show(item);
748             g_signal_connect(G_OBJECT(item),
749                              "activate",
750                              G_CALLBACK(sp_recent_open),
751                              (gpointer)uri);
752             gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
753         }
755         g_free(recent);
756     } else {
757         GtkWidget *item = gtk_menu_item_new_with_label(_("None"));
758         gtk_widget_show(item);
759         gtk_widget_set_sensitive(item, FALSE);
760         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
761     }
764 void
765 sp_ui_checkboxes_menus(GtkMenu *m, Inkscape::UI::View::View *view)
767     //sp_ui_menu_append_check_item_from_verb(m, view, _("_Menu"), _("Show or hide the menu bar"), "menu",
768     //                                       checkitem_toggled, checkitem_update, 0);
769     sp_ui_menu_append_check_item_from_verb(m, view, _("Commands Bar"), _("Show or hide the Commands bar (under the menu)"), "commands",
770                                            checkitem_toggled, checkitem_update, 0);
771     sp_ui_menu_append_check_item_from_verb(m, view, _("Tool Controls Bar"), _("Show or hide the Tool Controls bar"), "toppanel",
772                                            checkitem_toggled, checkitem_update, 0);
773     sp_ui_menu_append_check_item_from_verb(m, view, _("_Toolbox"), _("Show or hide the main toolbox (on the left)"), "toolbox",
774                                            checkitem_toggled, checkitem_update, 0);
775     sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "rulers",
776                                            checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_RULERS));
777     sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "scrollbars",
778                                            checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_SCROLLBARS));
779     sp_ui_menu_append_check_item_from_verb(m, view, _("_Palette"), _("Show or hide the color palette"), "panels",
780                                            checkitem_toggled, checkitem_update, 0);
781     sp_ui_menu_append_check_item_from_verb(m, view, _("_Statusbar"), _("Show or hide the statusbar (at the bottom of the window)"), "statusbar",
782                                            checkitem_toggled, checkitem_update, 0);
785 /** \brief  This function turns XML into a menu
786     \param  menus  This is the XML that defines the menu
787     \param  menu   Menu to be added to
788     \param  view   The View that this menu is being built for
790     This function is realitively simple as it just goes through the XML
791     and parses the individual elements.  In the case of a submenu, it
792     just calls itself recursively.  Because it is only reasonable to have
793     a couple of submenus, it is unlikely this will go more than two or
794     three times.
796     In the case of an unreconginzed verb, a menu item is made to identify
797     the verb that is missing, and display that.  The menu item is also made
798     insensitive.
799 */
800 void
801 sp_ui_build_dyn_menus(Inkscape::XML::Node *menus, GtkWidget *menu, Inkscape::UI::View::View *view)
803     if (menus == NULL) return;
804     if (menu == NULL)  return;
805     GSList *group = NULL;
807     for (Inkscape::XML::Node *menu_pntr = menus;
808          menu_pntr != NULL;
809          menu_pntr = menu_pntr->next()) {
810         if (!strcmp(menu_pntr->name(), "submenu")) {
811             GtkWidget *mitem = gtk_menu_item_new_with_mnemonic(_(menu_pntr->attribute("name")));
812             GtkWidget *submenu = gtk_menu_new();
813             sp_ui_build_dyn_menus(menu_pntr->firstChild(), submenu, view);
814             gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), GTK_WIDGET(submenu));
815             gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
816             continue;
817         }
818         if (!strcmp(menu_pntr->name(), "verb")) {
819             gchar const *verb_name = menu_pntr->attribute("verb-id");
820             Inkscape::Verb *verb = Inkscape::Verb::getbyid(verb_name);
822             if (verb != NULL) {
823                 if (menu_pntr->attribute("radio") != NULL) {
824                     GtkWidget *item = sp_ui_menu_append_item_from_verb (GTK_MENU(menu), verb, view, true, group);
825                     group = gtk_radio_menu_item_get_group( GTK_RADIO_MENU_ITEM(item));
826                     if (menu_pntr->attribute("default") != NULL) {
827                         gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);
828                     }
829                 } else {
830                     sp_ui_menu_append_item_from_verb(GTK_MENU(menu), verb, view);
831                     group = NULL;
832                 }
833             } else {
834                 gchar string[120];
835                 g_snprintf(string, 120, _("Verb \"%s\" Unknown"), verb_name);
836                 string[119] = '\0'; /* may not be terminated */
837                 GtkWidget *item = gtk_menu_item_new_with_label(string);
838                 gtk_widget_set_sensitive(item, false);
839                 gtk_widget_show(item);
840                 gtk_menu_append(GTK_MENU(menu), item);
841             }
842             continue;
843         }
844         if (!strcmp(menu_pntr->name(), "separator")
845                 // This was spelt wrong in the original version
846                 // and so this is for backward compatibility.  It can
847                 // probably be dropped after the 0.44 release.
848              || !strcmp(menu_pntr->name(), "seperator")) {
849             GtkWidget *item = gtk_separator_menu_item_new();
850             gtk_widget_show(item);
851             gtk_menu_append(GTK_MENU(menu), item);
852             continue;
853         }
854         if (!strcmp(menu_pntr->name(), "template-list")) {
855             sp_menu_append_new_templates(menu, view);
856             continue;
857         }
858         if (!strcmp(menu_pntr->name(), "recent-file-list")) {
859             sp_menu_append_recent_documents(menu, view);
860             continue;
861         }
862         if (!strcmp(menu_pntr->name(), "objects-checkboxes")) {
863             sp_ui_checkboxes_menus(GTK_MENU(menu), view);
864             continue;
865         }
866     }
869 /** \brief  Build the main tool bar
870     \param  view  View to build the bar for
872     Currently the main tool bar is built as a dynamic XML menu using
873     \c sp_ui_build_dyn_menus.  This function builds the bar, and then
874     pass it to get items attached to it.
875 */
876 GtkWidget *
877 sp_ui_main_menubar(Inkscape::UI::View::View *view)
879     GtkWidget *mbar = gtk_menu_bar_new();
881     sp_ui_build_dyn_menus(inkscape_get_menus(INKSCAPE), mbar, view);
883     return mbar;
886 static void leave_group(GtkMenuItem *, SPDesktop *desktop) {
887     desktop->setCurrentLayer(SP_OBJECT_PARENT(desktop->currentLayer()));
890 static void enter_group(GtkMenuItem *mi, SPDesktop *desktop) {
891     desktop->setCurrentLayer(reinterpret_cast<SPObject *>(g_object_get_data(G_OBJECT(mi), "group")));
892     sp_desktop_selection(desktop)->clear();
895 GtkWidget *
896 sp_ui_context_menu(Inkscape::UI::View::View *view, SPItem *item)
898     GtkWidget *m;
899     SPDesktop *dt;
901     dt = static_cast<SPDesktop*>(view);
903     m = gtk_menu_new();
905     /* Undo and Redo */
906     sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_UNDO), view);
907     sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_REDO), view);
909     /* Separator */
910     sp_ui_menu_append_item(GTK_MENU(m), NULL, NULL, NULL, NULL, NULL, NULL);
912     sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_CUT), view);
913     sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_COPY), view);
914     sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_PASTE), view);
916     /* Separator */
917     sp_ui_menu_append_item(GTK_MENU(m), NULL, NULL, NULL, NULL, NULL, NULL);
919     sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_DUPLICATE), view);
920     sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_DELETE), view);
922     /* Item menu */
923     if (item) {
924         sp_ui_menu_append_item(GTK_MENU(m), NULL, NULL, NULL, NULL, NULL, NULL);
925         sp_object_menu((SPObject *) item, dt, GTK_MENU(m));
926     }
928     /* layer menu */
929     SPGroup *group=NULL;
930     if (item) {
931         if (SP_IS_GROUP(item)) {
932             group = SP_GROUP(item);
933         } else if ( item != dt->currentRoot() && SP_IS_GROUP(SP_OBJECT_PARENT(item)) ) {
934             group = SP_GROUP(SP_OBJECT_PARENT(item));
935         }
936     }
938     if (( group && group != dt->currentLayer() ) ||
939         ( dt->currentLayer() != dt->currentRoot() ) ) {
940         sp_ui_menu_append_item(GTK_MENU(m), NULL, NULL, NULL, NULL, NULL, NULL);
941     }
943     if ( group && group != dt->currentLayer() ) {
944         /* TRANSLATORS: #%s is the id of the group e.g. <g id="#g7">, not a number. */
945         gchar *label=g_strdup_printf(_("Enter group #%s"), SP_OBJECT_ID(group));
946         GtkWidget *w = gtk_menu_item_new_with_label(label);
947         g_free(label);
948         g_object_set_data(G_OBJECT(w), "group", group);
949         g_signal_connect(G_OBJECT(w), "activate", GCallback(enter_group), dt);
950         gtk_widget_show(w);
951         gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
952     }
954     if ( dt->currentLayer() != dt->currentRoot() ) {
955         if ( SP_OBJECT_PARENT(dt->currentLayer()) != dt->currentRoot() ) {
956             GtkWidget *w = gtk_menu_item_new_with_label(_("Go to parent"));
957             g_signal_connect(G_OBJECT(w), "activate", GCallback(leave_group), dt);
958             gtk_widget_show(w);
959             gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
961         }
962     }
964     return m;
967 /* Drag and Drop */
968 void
969 sp_ui_drag_data_received(GtkWidget *widget,
970                          GdkDragContext *drag_context,
971                          gint x, gint y,
972                          GtkSelectionData *data,
973                          guint info,
974                          guint event_time,
975                          gpointer user_data)
977     switch (info) {
978 #if ENABLE_MAGIC_COLORS
979         case APP_X_INKY_COLOR:
980         {
981             SPDesktop *desktop = SP_ACTIVE_DESKTOP;
982             int destX = 0;
983             int destY = 0;
984             gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY );
985             NR::Point where( sp_canvas_window_to_world( desktop->canvas, NR::Point( destX, destY ) ) );
987             SPItem *item = desktop->item_at_point( where, true );
988             if ( item )
989             {
990                 if ( data->length >= 8 ) {
991                     cmsHPROFILE srgbProf = cmsCreate_sRGBProfile();
993                     gchar c[64] = {0};
994                     // Careful about endian issues.
995                     guint16* dataVals = (guint16*)data->data;
996                     sp_svg_write_color( c, 64,
997                                         SP_RGBA32_U_COMPOSE(
998                                             0x0ff & (dataVals[0] >> 8),
999                                             0x0ff & (dataVals[1] >> 8),
1000                                             0x0ff & (dataVals[2] >> 8),
1001                                             0xff // can't have transparency in the color itself
1002                                             //0x0ff & (data->data[3] >> 8),
1003                                             ));
1004                     SPCSSAttr *css = sp_repr_css_attr_new();
1005                     bool updatePerformed = false;
1007                     if ( data->length > 14 ) {
1008                         int flags = dataVals[4];
1010                         // piggie-backed palette entry info
1011                         int index = dataVals[5];
1012                         Glib::ustring palName;
1013                         for ( int i = 0; i < dataVals[6]; i++ ) {
1014                             palName += (gunichar)dataVals[7+i];
1015                         }
1017                         // Now hook in a magic tag of some sort.
1018                         if ( !palName.empty() && (flags & 1) ) {
1019                             gchar* str = g_strdup_printf("%d|", index);
1020                             palName.insert( 0, str );
1021                             g_free(str);
1022                             str = 0;
1024                             sp_object_setAttribute( SP_OBJECT(item),
1025                                                     (drag_context->action != GDK_ACTION_MOVE) ? "inkscape:x-fill-tag":"inkscape:x-stroke-tag",
1026                                                     palName.c_str(),
1027                                                     false );
1028                             item->updateRepr();
1030                             sp_repr_css_set_property( css, (drag_context->action != GDK_ACTION_MOVE) ? "fill":"stroke", c );
1031                             updatePerformed = true;
1032                         }
1033                     }
1035                     if ( !updatePerformed ) {
1036                         sp_repr_css_set_property( css, (drag_context->action != GDK_ACTION_MOVE) ? "fill":"stroke", c );
1037                     }
1039                     sp_desktop_apply_css_recursive( item, css, true );
1040                     item->updateRepr();
1042                     SPDocument *doc = SP_ACTIVE_DOCUMENT;
1043                     sp_document_done( doc , SP_VERB_NONE, 
1044                                       _("Drop color"));
1046                     if ( srgbProf ) {
1047                         cmsCloseProfile( srgbProf );
1048                     }
1049                 }
1050             }
1051         }
1052         break;
1053 #endif // ENABLE_MAGIC_COLORS
1055         case APP_X_COLOR:
1056         {
1057             SPDesktop *desktop = SP_ACTIVE_DESKTOP;
1058             int destX = 0;
1059             int destY = 0;
1060             gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY );
1061             NR::Point where( sp_canvas_window_to_world( desktop->canvas, NR::Point( destX, destY ) ) );
1063             SPItem *item = desktop->item_at_point( where, true );
1064             if ( item )
1065             {
1066                 if ( data->length == 8 ) {
1067                     gchar c[64] = {0};
1068                     // Careful about endian issues.
1069                     guint16* dataVals = (guint16*)data->data;
1070                     sp_svg_write_color( c, 64,
1071                                         SP_RGBA32_U_COMPOSE(
1072                                             0x0ff & (dataVals[0] >> 8),
1073                                             0x0ff & (dataVals[1] >> 8),
1074                                             0x0ff & (dataVals[2] >> 8),
1075                                             0xff // can't have transparency in the color itself
1076                                             //0x0ff & (data->data[3] >> 8),
1077                                             ));
1078                     SPCSSAttr *css = sp_repr_css_attr_new();
1079                     sp_repr_css_set_property( css, (drag_context->action != GDK_ACTION_MOVE) ? "fill":"stroke", c );
1081                     sp_desktop_apply_css_recursive( item, css, true );
1082                     item->updateRepr();
1084                     SPDocument *doc = SP_ACTIVE_DOCUMENT;
1085                     sp_document_done( doc , SP_VERB_NONE, 
1086                                       _("Drop color"));
1087                 }
1088             }
1089         }
1090         break;
1092         case SVG_DATA:
1093         case SVG_XML_DATA: {
1094             gchar *svgdata = (gchar *)data->data;
1096             SPDocument *doc = SP_ACTIVE_DOCUMENT;
1098             Inkscape::XML::Document *rnewdoc = sp_repr_read_mem(svgdata, data->length, SP_SVG_NS_URI);
1100             if (rnewdoc == NULL) {
1101                 sp_ui_error_dialog(_("Could not parse SVG data"));
1102                 return;
1103             }
1105             Inkscape::XML::Node *repr = rnewdoc->root();
1106             gchar const *style = repr->attribute("style");
1108             Inkscape::XML::Node *newgroup = rnewdoc->createElement("svg:g");
1109             newgroup->setAttribute("style", style);
1111             for (Inkscape::XML::Node *child = repr->firstChild(); child != NULL; child = child->next()) {
1112                 Inkscape::XML::Node *newchild = child->duplicate();
1113                 newgroup->appendChild(newchild);
1114             }
1116             Inkscape::GC::release(rnewdoc);
1118             SPDesktop *desktop = SP_ACTIVE_DESKTOP;
1119             // Add it to the current layer
1121             // Greg's edits to add intelligent positioning of svg drops
1122             SPObject *new_obj = NULL;
1123             new_obj = desktop->currentLayer()->appendChildRepr(newgroup);
1125             Inkscape::Selection *selection = sp_desktop_selection(desktop);
1126             selection->set(SP_ITEM(new_obj));
1127             // To move the imported object, we must temporarily set the "transform pattern with
1128             // object" option.
1129             {
1130                 int const saved_pref = prefs_get_int_attribute("options.transform", "pattern", 1);
1131                 prefs_set_int_attribute("options.transform", "pattern", 1);
1132                 sp_document_ensure_up_to_date(sp_desktop_document(desktop));
1133                 NR::Maybe<NR::Rect> sel_bbox = selection->bounds();
1134                 if (sel_bbox) {
1135                     NR::Point m( desktop->point() - sel_bbox->midpoint() );
1136                     sp_selection_move_relative(selection, m);
1137                 }
1138                 prefs_set_int_attribute("options.transform", "pattern", saved_pref);
1139             }
1141             Inkscape::GC::release(newgroup);
1142             sp_document_done(doc, SP_VERB_NONE, 
1143                              _("Drop SVG"));
1144             break;
1145         }
1147         case URI_LIST: {
1148             gchar *uri = (gchar *)data->data;
1149             sp_ui_import_files(uri);
1150             break;
1151         }
1153         case PNG_DATA:
1154         case JPEG_DATA:
1155         case IMAGE_DATA: {
1156             char tmp[1024];
1158             StringOutputStream outs;
1159             Base64OutputStream b64out(outs);
1160             b64out.setColumnWidth(0);
1162             SPDocument *doc = SP_ACTIVE_DOCUMENT;
1163             Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
1165             Inkscape::XML::Node *newImage = xml_doc->createElement("svg:image");
1167             for ( int i = 0; i < data->length; i++ ) {
1168                 b64out.put( data->data[i] );
1169             }
1170             b64out.close();
1173             Glib::ustring str = outs.getString();
1175             snprintf( tmp, sizeof(tmp), "data:%s;base64,", gdk_atom_name(data->type) );
1176             str.insert( 0, tmp );
1177             newImage->setAttribute("xlink:href", str.c_str());
1179             GError *error = NULL;
1180             GdkPixbufLoader *loader = gdk_pixbuf_loader_new_with_mime_type( gdk_atom_name(data->type), &error );
1181             if ( loader ) {
1182                 error = NULL;
1183                 if ( gdk_pixbuf_loader_write( loader, data->data, data->length, &error) ) {
1184                     GdkPixbuf *pbuf = gdk_pixbuf_loader_get_pixbuf(loader);
1185                     if ( pbuf ) {
1186                         int width = gdk_pixbuf_get_width(pbuf);
1187                         int height = gdk_pixbuf_get_height(pbuf);
1188                         snprintf( tmp, sizeof(tmp), "%d", width );
1189                         newImage->setAttribute("width", tmp);
1191                         snprintf( tmp, sizeof(tmp), "%d", height );
1192                         newImage->setAttribute("height", tmp);
1193                     }
1194                 }
1195             }
1197             SPDesktop *desktop = SP_ACTIVE_DESKTOP;
1199             // Add it to the current layer
1200             desktop->currentLayer()->appendChildRepr(newImage);
1202             Inkscape::GC::release(newImage);
1203             sp_document_done( doc , SP_VERB_NONE, 
1204                               _("Drop bitmap image"));
1205             break;
1206         }
1207     }
1210 static void
1211 sp_ui_import_files(gchar *buffer)
1213     GList *list = gnome_uri_list_extract_filenames(buffer);
1214     if (!list)
1215         return;
1216     g_list_foreach(list, sp_ui_import_one_file_with_check, NULL);
1217     g_list_foreach(list, (GFunc) g_free, NULL);
1218     g_list_free(list);
1221 static void
1222 sp_ui_import_one_file_with_check(gpointer filename, gpointer unused)
1224     if (filename) {
1225         if (strlen((char const *)filename) > 2)
1226             sp_ui_import_one_file((char const *)filename);
1227     }
1230 static void
1231 sp_ui_import_one_file(char const *filename)
1233     SPDocument *doc = SP_ACTIVE_DOCUMENT;
1234     if (!doc) return;
1236     if (filename == NULL) return;
1238     // Pass off to common implementation
1239     // TODO might need to get the proper type of Inkscape::Extension::Extension
1240     file_import( doc, filename, NULL );
1243 void
1244 sp_ui_error_dialog(gchar const *message)
1246     GtkWidget *dlg;
1247     gchar *safeMsg = Inkscape::IO::sanitizeString(message);
1249     dlg = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,
1250                                  GTK_BUTTONS_CLOSE, "%s", safeMsg);
1251     sp_transientize(dlg);
1252     gtk_window_set_resizable(GTK_WINDOW(dlg), FALSE);
1253     gtk_dialog_run(GTK_DIALOG(dlg));
1254     gtk_widget_destroy(dlg);
1255     g_free(safeMsg);
1258 bool
1259 sp_ui_overwrite_file(gchar const *filename)
1261     bool return_value = FALSE;
1262     GtkWidget *dialog;
1263     GtkWidget *hbox;
1264     GtkWidget *boxdata;
1265     gchar *title;
1266     gchar *text;
1268     if (Inkscape::IO::file_test(filename, G_FILE_TEST_EXISTS)) {
1270         title = g_strdup_printf(_("Overwrite %s"), filename);
1271         dialog = gtk_dialog_new_with_buttons(title,
1272                                              NULL,
1273                                              (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
1274                                              GTK_STOCK_NO,
1275                                              GTK_RESPONSE_NO,
1276                                              GTK_STOCK_YES,
1277                                              GTK_RESPONSE_YES,
1278                                              NULL);
1279         gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_YES);
1281         sp_transientize(dialog);
1282         gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
1284         hbox = gtk_hbox_new(FALSE, 5);
1286         // TODO - replace with Inkscape-specific call
1287         boxdata = gtk_image_new_from_stock(GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG);
1289         gtk_widget_show(boxdata);
1290         gtk_box_pack_start(GTK_BOX(hbox), boxdata, TRUE, TRUE, 5);
1291         text = g_strdup_printf(_("The file %s already exists.  Do you want to overwrite that file with the current document?"), filename);
1292         boxdata = gtk_label_new(text);
1293         gtk_label_set_line_wrap(GTK_LABEL(boxdata), TRUE);
1294         gtk_widget_show(boxdata);
1295         gtk_box_pack_start(GTK_BOX(hbox), boxdata, FALSE, FALSE, 5);
1296         gtk_widget_show(hbox);
1297         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, TRUE, TRUE, 5);
1299         if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES) {
1300             return_value = TRUE;
1301         } else {
1302             return_value = FALSE;
1303         }
1305         gtk_widget_destroy(dialog);
1306         g_free(title);
1307         g_free(text);
1308     } else {
1309         return_value = TRUE;
1310     }
1312     return return_value;
1315 static void
1316 sp_ui_menu_item_set_sensitive(SPAction *action, unsigned int sensitive, void *data)
1318     return gtk_widget_set_sensitive(GTK_WIDGET(data), sensitive);
1321 static void
1322 sp_ui_menu_item_set_name(SPAction *action, Glib::ustring name, void *data)
1324     gtk_label_set_markup_with_mnemonic(
1325         GTK_LABEL (gtk_container_get_children(GTK_CONTAINER (GTK_BIN (data)->child))->data), 
1326         name.c_str());
1330 /*
1331   Local Variables:
1332   mode:c++
1333   c-file-style:"stroustrup"
1334   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1335   indent-tabs-mode:nil
1336   fill-column:99
1337   End:
1338 */
1339 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :