Code

Added descriptions to Undo/Redo commands in the menus
[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     GtkWidget *w, *hb;
133     g_return_if_fail(vw != NULL);
134     g_return_if_fail(SP_IS_VIEW_WIDGET(vw));
136     w = sp_window_new("", TRUE);
138     if (editable) {
139       g_object_set_data(G_OBJECT(vw), "window", w);
140       reinterpret_cast<SPDesktopWidget*>(vw)->window =
141         static_cast<GtkWindow*>((void*)w);
142     }
144     hb = gtk_hbox_new(FALSE, 0);
145     gtk_widget_show(hb);
146     gtk_container_add(GTK_CONTAINER(w), hb);
147     g_object_set_data(G_OBJECT(w), "hbox", hb);
149     /* fixme: */
150     if (editable) {
151         gtk_window_set_default_size((GtkWindow *) w, 640, 480);
152         g_object_set_data(G_OBJECT(w), "desktop", SP_DESKTOP_WIDGET(vw)->desktop);
153         g_object_set_data(G_OBJECT(w), "desktopwidget", vw);
154         g_signal_connect(G_OBJECT(w), "delete_event", G_CALLBACK(sp_ui_delete), vw->view);
155         g_signal_connect(G_OBJECT(w), "focus_in_event", G_CALLBACK(sp_desktop_widget_set_focus), vw);
156     } else {
157         gtk_window_set_policy(GTK_WINDOW(w), TRUE, TRUE, TRUE);
158     }
160     gtk_box_pack_end(GTK_BOX(hb), GTK_WIDGET(vw), TRUE, TRUE, 0);
161     gtk_widget_show(GTK_WIDGET(vw));
164     if ( completeDropTargets == 0 || completeDropTargetsCount == 0 )
165     {
166         std::vector<gchar*> types;
168         GSList *list = gdk_pixbuf_get_formats();
169         while ( list ) {
170             int i = 0;
171             GdkPixbufFormat *one = (GdkPixbufFormat*)list->data;
172             gchar** typesXX = gdk_pixbuf_format_get_mime_types(one);
173             for ( i = 0; typesXX[i]; i++ ) {
174                 types.push_back(g_strdup(typesXX[i]));
175             }
176             g_strfreev(typesXX);
178             list = g_slist_next(list);
179         }
180         completeDropTargetsCount = nui_drop_target_entries + types.size();
181         completeDropTargets = new GtkTargetEntry[completeDropTargetsCount];
182         for ( int i = 0; i < (int)nui_drop_target_entries; i++ ) {
183             completeDropTargets[i] = ui_drop_target_entries[i];
184         }
185         int pos = nui_drop_target_entries;
187         for (std::vector<gchar*>::iterator it = types.begin() ; it != types.end() ; it++) {
188             completeDropTargets[pos].target = *it;
189             completeDropTargets[pos].flags = 0;
190             completeDropTargets[pos].info = IMAGE_DATA;
191             pos++;
192         }
193     }
195     gtk_drag_dest_set(w,
196                       GTK_DEST_DEFAULT_ALL,
197                       completeDropTargets,
198                       completeDropTargetsCount,
199                       GdkDragAction(GDK_ACTION_COPY | GDK_ACTION_MOVE));
200     g_signal_connect(G_OBJECT(w),
201                      "drag_data_received",
202                      G_CALLBACK(sp_ui_drag_data_received),
203                      NULL);
204     gtk_widget_show(w);
206     // needed because the first ACTIVATE_DESKTOP was sent when there was no window yet
207     inkscape_reactivate_desktop(SP_DESKTOP_WIDGET(vw)->desktop);
210 void
211 sp_ui_new_view()
213     SPDocument *document;
214     SPViewWidget *dtw;
216     document = SP_ACTIVE_DOCUMENT;
217     if (!document) return;
219     dtw = sp_desktop_widget_new(sp_document_namedview(document, NULL));
220     g_return_if_fail(dtw != NULL);
222     sp_create_window(dtw, TRUE);
223     sp_namedview_window_from_document(static_cast<SPDesktop*>(dtw->view));
226 /* TODO: not yet working */
227 /* To be re-enabled (by adding to menu) once it works. */
228 void
229 sp_ui_new_view_preview()
231     SPDocument *document;
232     SPViewWidget *dtw;
234     document = SP_ACTIVE_DOCUMENT;
235     if (!document) return;
237     dtw = (SPViewWidget *) sp_svg_view_widget_new(document);
238     g_return_if_fail(dtw != NULL);
239     sp_svg_view_widget_set_resize(SP_SVG_VIEW_WIDGET(dtw), TRUE, 400.0, 400.0);
241     sp_create_window(dtw, FALSE);
244 /**
245  * \param widget unused
246  */
247 void
248 sp_ui_close_view(GtkWidget *widget)
250     if (SP_ACTIVE_DESKTOP == NULL) {
251         return;
252     }
253     if ((SP_ACTIVE_DESKTOP)->shutdown()) {
254         return;
255     }
256     SP_ACTIVE_DESKTOP->destroyWidget();
260 /**
261  *  sp_ui_close_all
262  *
263  *  This function is called to exit the program, and iterates through all
264  *  open document view windows, attempting to close each in turn.  If the
265  *  view has unsaved information, the user will be prompted to save,
266  *  discard, or cancel.
267  *
268  *  Returns FALSE if the user cancels the close_all operation, TRUE
269  *  otherwise.
270  */
271 unsigned int
272 sp_ui_close_all(void)
274     /* Iterate through all the windows, destroying each in the order they
275        become active */
276     while (SP_ACTIVE_DESKTOP) {
277         if ((SP_ACTIVE_DESKTOP)->shutdown()) {
278             /* The user cancelled the operation, so end doing the close */
279             return FALSE;
280         }
281         SP_ACTIVE_DESKTOP->destroyWidget();
282     }
284     return TRUE;
287 static gint
288 sp_ui_delete(GtkWidget *widget, GdkEvent *event, Inkscape::UI::View::View *view)
290     return view->shutdown();
293 /*
294  * Some day when the right-click menus are ready to start working
295  * smarter with the verbs, we'll need to change this NULL being
296  * sent to sp_action_perform to something useful, or set some kind
297  * of global "right-clicked position" variable for actions to
298  * investigate when they're called.
299  */
300 static void
301 sp_ui_menu_activate(void *object, SPAction *action)
303     sp_action_perform(action, NULL);
306 static void
307 sp_ui_menu_select_action(void *object, SPAction *action)
309     action->view->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, action->tip);
312 static void
313 sp_ui_menu_deselect_action(void *object, SPAction *action)
315     action->view->tipsMessageContext()->clear();
318 static void
319 sp_ui_menu_select(gpointer object, gpointer tip)
321     Inkscape::UI::View::View *view = static_cast<Inkscape::UI::View::View*> (g_object_get_data(G_OBJECT(object), "view"));
322     view->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, (gchar *)tip);
325 static void
326 sp_ui_menu_deselect(gpointer object)
328     Inkscape::UI::View::View *view = static_cast<Inkscape::UI::View::View*>  (g_object_get_data(G_OBJECT(object), "view"));
329     view->tipsMessageContext()->clear();
332 /**
333  * sp_ui_menuitem_add_icon
334  *
335  * Creates and attaches a scaled icon to the given menu item.
336  *
337  */
338 void
339 sp_ui_menuitem_add_icon( GtkWidget *item, gchar *icon_name )
341     GtkWidget *icon;
343     icon = sp_icon_new( Inkscape::ICON_SIZE_MENU, icon_name );
344     gtk_widget_show(icon);
345     gtk_image_menu_item_set_image((GtkImageMenuItem *) item, icon);
346 } // end of sp_ui_menu_add_icon
348 /**
349  * sp_ui_menu_append_item
350  *
351  * Appends a UI item with specific info for Inkscape/Sodipodi.
352  *
353  */
354 static GtkWidget *
355 sp_ui_menu_append_item( GtkMenu *menu, gchar const *stock,
356                         gchar const *label, gchar const *tip, Inkscape::UI::View::View *view, GCallback callback,
357                         gpointer data, gboolean with_mnemonic = TRUE )
359     GtkWidget *item;
361     if (stock) {
362         item = gtk_image_menu_item_new_from_stock(stock, NULL);
363     } else if (label) {
364         item = (with_mnemonic)
365             ? gtk_image_menu_item_new_with_mnemonic(label) :
366             gtk_image_menu_item_new_with_label(label);
367     } else {
368         item = gtk_separator_menu_item_new();
369     }
371     gtk_widget_show(item);
373     if (callback) {
374         g_signal_connect(G_OBJECT(item), "activate", callback, data);
375     }
377     if (tip && view) {
378         g_object_set_data(G_OBJECT(item), "view", (gpointer) view);
379         g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select), (gpointer) tip );
380         g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect), NULL);
381     }
383     gtk_menu_append(GTK_MENU(menu), item);
385     return item;
387 } // end of sp_ui_menu_append_item()
389 /**
390 \brief  a wrapper around gdk_keyval_name producing (when possible) characters, not names
391  */
392 static gchar const *
393 sp_key_name(guint keyval)
395     /* TODO: Compare with the definition of gtk_accel_label_refetch in gtk/gtkaccellabel.c (or
396        simply use GtkAccelLabel as the TODO comment in sp_ui_shortcut_string suggests). */
397     gchar const *n = gdk_keyval_name(gdk_keyval_to_upper(keyval));
399     if      (!strcmp(n, "asciicircum"))  return "^";
400     else if (!strcmp(n, "parenleft"  ))  return "(";
401     else if (!strcmp(n, "parenright" ))  return ")";
402     else if (!strcmp(n, "plus"       ))  return "+";
403     else if (!strcmp(n, "minus"      ))  return "-";
404     else if (!strcmp(n, "asterisk"   ))  return "*";
405     else if (!strcmp(n, "KP_Multiply"))  return "*";
406     else if (!strcmp(n, "Delete"     ))  return "Del";
407     else if (!strcmp(n, "Page_Up"    ))  return "PgUp";
408     else if (!strcmp(n, "Page_Down"  ))  return "PgDn";
409     else if (!strcmp(n, "grave"      ))  return "`";
410     else if (!strcmp(n, "numbersign" ))  return "#";
411     else if (!strcmp(n, "bar" ))  return "|";
412     else if (!strcmp(n, "slash" ))  return "/";
413     else if (!strcmp(n, "exclam" ))  return "!";
414     else return n;
418 /**
419  * \param shortcut A GDK keyval OR'd with SP_SHORTCUT_blah_MASK values.
420  * \param c Points to a buffer at least 256 bytes long.
421  */
422 void
423 sp_ui_shortcut_string(unsigned const shortcut, gchar *const c)
425     /* TODO: This function shouldn't exist.  Our callers should use GtkAccelLabel instead of
426      * a generic GtkLabel containing this string, and should call gtk_widget_add_accelerator.
427      * Will probably need to change sp_shortcut_invoke callers.
428      *
429      * The existing gtk_label_new_with_mnemonic call can be replaced with
430      * g_object_new(GTK_TYPE_ACCEL_LABEL, NULL) followed by
431      * gtk_label_set_text_with_mnemonic(lbl, str).
432      */
433     static GtkAccelLabelClass const &accel_lbl_cls
434         = *(GtkAccelLabelClass const *) g_type_class_peek_static(GTK_TYPE_ACCEL_LABEL);
436     struct { unsigned test; char const *name; } const modifier_tbl[] = {
437         { SP_SHORTCUT_SHIFT_MASK,   accel_lbl_cls.mod_name_shift   },
438         { SP_SHORTCUT_CONTROL_MASK, accel_lbl_cls.mod_name_control },
439         { SP_SHORTCUT_ALT_MASK,     accel_lbl_cls.mod_name_alt     }
440     };
442     gchar *p = c;
443     gchar *end = p + 256;
445     for (unsigned i = 0; i < G_N_ELEMENTS(modifier_tbl); ++i) {
446         if ((shortcut & modifier_tbl[i].test)
447             && (p < end))
448         {
449             p += g_snprintf(p, end - p, "%s%s",
450                             modifier_tbl[i].name,
451                             accel_lbl_cls.mod_separator);
452         }
453     }
454     if (p < end) {
455         p += g_snprintf(p, end - p, "%s", sp_key_name(shortcut & 0xffffff));
456     }
457     end[-1] = '\0';  // snprintf doesn't guarantee to nul-terminate the string.
460 void
461 sp_ui_dialog_title_string(Inkscape::Verb *verb, gchar *c)
463     SPAction     *action;
464     unsigned int shortcut;
465     gchar        *s;
466     gchar        key[256];
467     gchar        *atitle;
469     action = verb->get_action(NULL);
470     if (!action)
471         return;
473     atitle = sp_action_get_title(action);
475     s = g_stpcpy(c, atitle);
477     g_free(atitle);
479     shortcut = sp_shortcut_get_primary(verb);
480     if (shortcut) {
481         s = g_stpcpy(s, " (");
482         sp_ui_shortcut_string(shortcut, key);
483         s = g_stpcpy(s, key);
484         s = g_stpcpy(s, ")");
485     }
489 /**
490  * sp_ui_menu_append_item_from_verb
491  *
492  * Appends a custom menu UI from a verb.
493  *
494  */
496 static GtkWidget *
497 sp_ui_menu_append_item_from_verb(GtkMenu *menu, Inkscape::Verb *verb, Inkscape::UI::View::View *view, bool radio = false, GSList *group = NULL)
499     SPAction *action;
500     GtkWidget *item;
502     if (verb->get_code() == SP_VERB_NONE) {
504         item = gtk_separator_menu_item_new();
506     } else {
507         unsigned int shortcut;
509         action = verb->get_action(view);
511         if (!action) return NULL;
513         shortcut = sp_shortcut_get_primary(verb);
514         if (shortcut) {
515             gchar c[256];
516             sp_ui_shortcut_string(shortcut, c);
517             GtkWidget *const hb = gtk_hbox_new(FALSE, 16);
518             GtkWidget *const name_lbl = gtk_label_new("");
519             gtk_label_set_markup_with_mnemonic(GTK_LABEL(name_lbl), action->name);
520             gtk_misc_set_alignment((GtkMisc *) name_lbl, 0.0, 0.5);
521             gtk_box_pack_start((GtkBox *) hb, name_lbl, TRUE, TRUE, 0);
522             GtkWidget *const accel_lbl = gtk_label_new(c);
523             gtk_misc_set_alignment((GtkMisc *) accel_lbl, 1.0, 0.5);
524             gtk_box_pack_end((GtkBox *) hb, accel_lbl, FALSE, FALSE, 0);
525             gtk_widget_show_all(hb);
526             if (radio) {
527                 item = gtk_radio_menu_item_new (group);
528             } else {
529                 item = gtk_image_menu_item_new();
530             }
531             gtk_container_add((GtkContainer *) item, hb);
532         } else {
533             if (radio) {
534                 item = gtk_radio_menu_item_new (group);
535             } else {
536                 item = gtk_image_menu_item_new ();
537             }
538             GtkWidget *const name_lbl = gtk_label_new("");
539             gtk_label_set_markup_with_mnemonic(GTK_LABEL(name_lbl), action->name);
540             gtk_misc_set_alignment((GtkMisc *) name_lbl, 0.0, 0.5);
541             gtk_container_add((GtkContainer *) item, name_lbl);
542         }
544         nr_active_object_add_listener((NRActiveObject *)action, (NRObjectEventVector *)&menu_item_event_vector, sizeof(SPActionEventVector), item);
545         if (!action->sensitive) {
546             gtk_widget_set_sensitive(item, FALSE);
547         }
549         if (action->image) {
550             sp_ui_menuitem_add_icon(item, action->image);
551         }
552         gtk_widget_set_events(item, GDK_KEY_PRESS_MASK);
553         g_signal_connect( G_OBJECT(item), "activate",
554                           G_CALLBACK(sp_ui_menu_activate), action );
556         g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select_action), action );
557         g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect_action), action );
558     }
560     gtk_widget_show(item);
561     gtk_menu_append(GTK_MENU(menu), item);
563     return item;
565 } // end of sp_ui_menu_append_item_from_verb
568 static void
569 checkitem_toggled(GtkCheckMenuItem *menuitem, gpointer user_data)
571     gchar const *pref = (gchar const *) user_data;
572     Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view");
574     gchar const *pref_path;
575     if (reinterpret_cast<SPDesktop*>(view)->is_fullscreen)
576         pref_path = g_strconcat("fullscreen.", pref, NULL);
577     else
578         pref_path = g_strconcat("window.", pref, NULL);
580     gboolean checked = gtk_check_menu_item_get_active(menuitem);
581     prefs_set_int_attribute(pref_path, "state", checked);
583     reinterpret_cast<SPDesktop*>(view)->layoutWidget();
586 static gboolean
587 checkitem_update(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
589     GtkCheckMenuItem *menuitem=GTK_CHECK_MENU_ITEM(widget);
591     gchar const *pref = (gchar const *) user_data;
592     Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view");
594     gchar const *pref_path;
595     if (static_cast<SPDesktop*>(view)->is_fullscreen)
596         pref_path = g_strconcat("fullscreen.", pref, NULL);
597     else
598         pref_path = g_strconcat("window.", pref, NULL);
600     gint ison = prefs_get_int_attribute_limited(pref_path, "state", 1, 0, 1);
602     g_signal_handlers_block_by_func(G_OBJECT(menuitem), (gpointer)(GCallback)checkitem_toggled, user_data);
603     gtk_check_menu_item_set_active(menuitem, ison);
604     g_signal_handlers_unblock_by_func(G_OBJECT(menuitem), (gpointer)(GCallback)checkitem_toggled, user_data);
606     return FALSE;
610 void
611 sp_ui_menu_append_check_item_from_verb(GtkMenu *menu, Inkscape::UI::View::View *view, gchar const *label, gchar const *tip, gchar const *pref,
612                                        void (*callback_toggle)(GtkCheckMenuItem *, gpointer user_data),
613                                        gboolean (*callback_update)(GtkWidget *widget, GdkEventExpose *event, gpointer user_data),
614                                        Inkscape::Verb *verb)
616     GtkWidget *item;
618     unsigned int shortcut = 0;
619     SPAction *action = NULL;
621     if (verb) {
622         shortcut = sp_shortcut_get_primary(verb);
623         action = verb->get_action(view);
624     }
626     if (verb && shortcut) {
627         gchar c[256];
628         sp_ui_shortcut_string(shortcut, c);
630         GtkWidget *hb = gtk_hbox_new(FALSE, 16);
632         {
633             GtkWidget *l = gtk_label_new_with_mnemonic(action ? action->name : label);
634             gtk_misc_set_alignment((GtkMisc *) l, 0.0, 0.5);
635             gtk_box_pack_start((GtkBox *) hb, l, TRUE, TRUE, 0);
636         }
638         {
639             GtkWidget *l = gtk_label_new(c);
640             gtk_misc_set_alignment((GtkMisc *) l, 1.0, 0.5);
641             gtk_box_pack_end((GtkBox *) hb, l, FALSE, FALSE, 0);
642         }
644         gtk_widget_show_all(hb);
646         item = gtk_check_menu_item_new();
647         gtk_container_add((GtkContainer *) item, hb);
648     } else {
649         GtkWidget *l = gtk_label_new_with_mnemonic(action ? action->name : label);
650         gtk_misc_set_alignment((GtkMisc *) l, 0.0, 0.5);
651         item = gtk_check_menu_item_new();
652         gtk_container_add((GtkContainer *) item, l);
653     }
654 #if 0
655     nr_active_object_add_listener((NRActiveObject *)action, (NRObjectEventVector *)&menu_item_event_vector, sizeof(SPActionEventVector), item);
656     if (!action->sensitive) {
657         gtk_widget_set_sensitive(item, FALSE);
658     }
659 #endif
660     gtk_widget_show(item);
662     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
664     g_object_set_data(G_OBJECT(item), "view", (gpointer) view);
666     g_signal_connect( G_OBJECT(item), "toggled", (GCallback) callback_toggle, (void *) pref);
667     g_signal_connect( G_OBJECT(item), "expose_event", (GCallback) callback_update, (void *) pref);
669     g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select), (gpointer) (action ? action->tip : tip));
670     g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect), NULL);
673 static void
674 sp_recent_open(GtkWidget *widget, gchar const *uri)
676     sp_file_open(uri, NULL);
679 static void
680 sp_file_new_from_template(GtkWidget *widget, gchar const *uri)
682     sp_file_new(uri);
685 void
686 sp_menu_append_new_templates(GtkWidget *menu, Inkscape::UI::View::View *view)
688     std::list<gchar *> sources;
689     sources.push_back( profile_path("templates") ); // first try user's local dir
690     sources.push_back( g_strdup(INKSCAPE_TEMPLATESDIR) ); // then the system templates dir
692     // Use this loop to iterate through a list of possible document locations.
693     while (!sources.empty()) {
694         gchar *dirname = sources.front();
696         if ( Inkscape::IO::file_test( dirname, (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR) ) ) {
697             GError *err = 0;
698             GDir *dir = g_dir_open(dirname, 0, &err);
700             if (dir) {
701                 for (gchar const *file = g_dir_read_name(dir); file != NULL; file = g_dir_read_name(dir)) {
702                     if (!g_str_has_suffix(file, ".svg"))
703                         continue; // skip non-svg files
705                     gchar *basename = g_path_get_basename(file);
706                     if (g_str_has_suffix(basename, ".svg") && g_str_has_prefix(basename, "default."))
707                         continue; // skip default.*.svg (i.e. default.svg and translations) - it's in the menu already
709                     gchar const *filepath = g_build_filename(dirname, file, NULL);
710                     gchar *dupfile = g_strndup(file, strlen(file) - 4);
711                     gchar *filename =  g_filename_to_utf8(dupfile,  -1, NULL, NULL, NULL);
712                     g_free(dupfile);
713                     GtkWidget *item = gtk_menu_item_new_with_label(filename);
714                     g_free(filename);
716                     gtk_widget_show(item);
717                     // how does "filepath" ever get freed?
718                     g_signal_connect(G_OBJECT(item),
719                                      "activate",
720                                      G_CALLBACK(sp_file_new_from_template),
721                                      (gpointer) filepath);
723                     if (view) {
724                         // set null tip for now; later use a description from the template file
725                         g_object_set_data(G_OBJECT(item), "view", (gpointer) view);
726                         g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select), (gpointer) NULL );
727                         g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect), NULL);
728                     }
730                     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
731                 }
732                 g_dir_close(dir);
733             }
734         }
736         // toss the dirname
737         g_free(dirname);
738         sources.pop_front();
739     }
742 void
743 sp_menu_append_recent_documents(GtkWidget *menu, Inkscape::UI::View::View* /* view */)
745     gchar const **recent = prefs_get_recent_files();
746     if (recent) {
747         int i;
749         for (i = 0; recent[i] != NULL; i += 2) {
750             gchar const *uri = recent[i];
751             gchar const *name = recent[i + 1];
753             GtkWidget *item = gtk_menu_item_new_with_label(name);
754             gtk_widget_show(item);
755             g_signal_connect(G_OBJECT(item),
756                              "activate",
757                              G_CALLBACK(sp_recent_open),
758                              (gpointer)uri);
759             gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
760         }
762         g_free(recent);
763     } else {
764         GtkWidget *item = gtk_menu_item_new_with_label(_("None"));
765         gtk_widget_show(item);
766         gtk_widget_set_sensitive(item, FALSE);
767         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
768     }
771 void
772 sp_ui_checkboxes_menus(GtkMenu *m, Inkscape::UI::View::View *view)
774     //sp_ui_menu_append_check_item_from_verb(m, view, _("_Menu"), _("Show or hide the menu bar"), "menu",
775     //                                       checkitem_toggled, checkitem_update, 0);
776     sp_ui_menu_append_check_item_from_verb(m, view, _("Commands Bar"), _("Show or hide the Commands bar (under the menu)"), "commands",
777                                            checkitem_toggled, checkitem_update, 0);
778     sp_ui_menu_append_check_item_from_verb(m, view, _("Tool Controls Bar"), _("Show or hide the Tool Controls bar"), "toppanel",
779                                            checkitem_toggled, checkitem_update, 0);
780     sp_ui_menu_append_check_item_from_verb(m, view, _("_Toolbox"), _("Show or hide the main toolbox (on the left)"), "toolbox",
781                                            checkitem_toggled, checkitem_update, 0);
782     sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "rulers",
783                                            checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_RULERS));
784     sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "scrollbars",
785                                            checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_SCROLLBARS));
786     sp_ui_menu_append_check_item_from_verb(m, view, _("_Palette"), _("Show or hide the color palette"), "panels",
787                                            checkitem_toggled, checkitem_update, 0);
788     sp_ui_menu_append_check_item_from_verb(m, view, _("_Statusbar"), _("Show or hide the statusbar (at the bottom of the window)"), "statusbar",
789                                            checkitem_toggled, checkitem_update, 0);
792 /** \brief  This function turns XML into a menu
793     \param  menus  This is the XML that defines the menu
794     \param  menu   Menu to be added to
795     \param  view   The View that this menu is being built for
797     This function is realitively simple as it just goes through the XML
798     and parses the individual elements.  In the case of a submenu, it
799     just calls itself recursively.  Because it is only reasonable to have
800     a couple of submenus, it is unlikely this will go more than two or
801     three times.
803     In the case of an unreconginzed verb, a menu item is made to identify
804     the verb that is missing, and display that.  The menu item is also made
805     insensitive.
806 */
807 void
808 sp_ui_build_dyn_menus(Inkscape::XML::Node *menus, GtkWidget *menu, Inkscape::UI::View::View *view)
810     if (menus == NULL) return;
811     if (menu == NULL)  return;
812     GSList *group = NULL;
814     for (Inkscape::XML::Node *menu_pntr = menus;
815          menu_pntr != NULL;
816          menu_pntr = menu_pntr->next()) {
817         if (!strcmp(menu_pntr->name(), "submenu")) {
818             GtkWidget *mitem = gtk_menu_item_new_with_mnemonic(_(menu_pntr->attribute("name")));
819             GtkWidget *submenu = gtk_menu_new();
820             sp_ui_build_dyn_menus(menu_pntr->firstChild(), submenu, view);
821             gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), GTK_WIDGET(submenu));
822             gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
823             continue;
824         }
825         if (!strcmp(menu_pntr->name(), "verb")) {
826             gchar const *verb_name = menu_pntr->attribute("verb-id");
827             Inkscape::Verb *verb = Inkscape::Verb::getbyid(verb_name);
829             if (verb != NULL) {
830                 if (menu_pntr->attribute("radio") != NULL) {
831                     GtkWidget *item = sp_ui_menu_append_item_from_verb (GTK_MENU(menu), verb, view, true, group);
832                     group = gtk_radio_menu_item_get_group( GTK_RADIO_MENU_ITEM(item));
833                     if (menu_pntr->attribute("default") != NULL) {
834                         gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);
835                     }
836                 } else {
837                     sp_ui_menu_append_item_from_verb(GTK_MENU(menu), verb, view);
838                     group = NULL;
839                 }
840             } else {
841                 gchar string[120];
842                 g_snprintf(string, 120, _("Verb \"%s\" Unknown"), verb_name);
843                 string[119] = '\0'; /* may not be terminated */
844                 GtkWidget *item = gtk_menu_item_new_with_label(string);
845                 gtk_widget_set_sensitive(item, false);
846                 gtk_widget_show(item);
847                 gtk_menu_append(GTK_MENU(menu), item);
848             }
849             continue;
850         }
851         if (!strcmp(menu_pntr->name(), "separator")
852                 // This was spelt wrong in the original version
853                 // and so this is for backward compatibility.  It can
854                 // probably be dropped after the 0.44 release.
855              || !strcmp(menu_pntr->name(), "seperator")) {
856             GtkWidget *item = gtk_separator_menu_item_new();
857             gtk_widget_show(item);
858             gtk_menu_append(GTK_MENU(menu), item);
859             continue;
860         }
861         if (!strcmp(menu_pntr->name(), "template-list")) {
862             sp_menu_append_new_templates(menu, view);
863             continue;
864         }
865         if (!strcmp(menu_pntr->name(), "recent-file-list")) {
866             sp_menu_append_recent_documents(menu, view);
867             continue;
868         }
869         if (!strcmp(menu_pntr->name(), "objects-checkboxes")) {
870             sp_ui_checkboxes_menus(GTK_MENU(menu), view);
871             continue;
872         }
873     }
876 /** \brief  Build the main tool bar
877     \param  view  View to build the bar for
879     Currently the main tool bar is built as a dynamic XML menu using
880     \c sp_ui_build_dyn_menus.  This function builds the bar, and then
881     pass it to get items attached to it.
882 */
883 GtkWidget *
884 sp_ui_main_menubar(Inkscape::UI::View::View *view)
886     GtkWidget *mbar = gtk_menu_bar_new();
888     sp_ui_build_dyn_menus(inkscape_get_menus(INKSCAPE), mbar, view);
890     return mbar;
893 static void leave_group(GtkMenuItem *, SPDesktop *desktop) {
894     desktop->setCurrentLayer(SP_OBJECT_PARENT(desktop->currentLayer()));
897 static void enter_group(GtkMenuItem *mi, SPDesktop *desktop) {
898     desktop->setCurrentLayer(reinterpret_cast<SPObject *>(g_object_get_data(G_OBJECT(mi), "group")));
899     sp_desktop_selection(desktop)->clear();
902 GtkWidget *
903 sp_ui_context_menu(Inkscape::UI::View::View *view, SPItem *item)
905     GtkWidget *m;
906     SPDesktop *dt;
908     dt = static_cast<SPDesktop*>(view);
910     m = gtk_menu_new();
912     /* Undo and Redo */
913     sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_UNDO), view);
914     sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_REDO), 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_CUT), view);
920     sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_COPY), view);
921     sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_PASTE), view);
923     /* Separator */
924     sp_ui_menu_append_item(GTK_MENU(m), NULL, NULL, NULL, NULL, NULL, NULL);
926     sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_DUPLICATE), view);
927     sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_DELETE), view);
929     /* Item menu */
930     if (item) {
931         sp_ui_menu_append_item(GTK_MENU(m), NULL, NULL, NULL, NULL, NULL, NULL);
932         sp_object_menu((SPObject *) item, dt, GTK_MENU(m));
933     }
935     /* layer menu */
936     SPGroup *group=NULL;
937     if (item) {
938         if (SP_IS_GROUP(item)) {
939             group = SP_GROUP(item);
940         } else if ( item != dt->currentRoot() && SP_IS_GROUP(SP_OBJECT_PARENT(item)) ) {
941             group = SP_GROUP(SP_OBJECT_PARENT(item));
942         }
943     }
945     if (( group && group != dt->currentLayer() ) ||
946         ( dt->currentLayer() != dt->currentRoot() ) ) {
947         sp_ui_menu_append_item(GTK_MENU(m), NULL, NULL, NULL, NULL, NULL, NULL);
948     }
950     if ( group && group != dt->currentLayer() ) {
951         /* TRANSLATORS: #%s is the id of the group e.g. <g id="#g7">, not a number. */
952         gchar *label=g_strdup_printf(_("Enter group #%s"), SP_OBJECT_ID(group));
953         GtkWidget *w = gtk_menu_item_new_with_label(label);
954         g_free(label);
955         g_object_set_data(G_OBJECT(w), "group", group);
956         g_signal_connect(G_OBJECT(w), "activate", GCallback(enter_group), dt);
957         gtk_widget_show(w);
958         gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
959     }
961     if ( dt->currentLayer() != dt->currentRoot() ) {
962         if ( SP_OBJECT_PARENT(dt->currentLayer()) != dt->currentRoot() ) {
963             GtkWidget *w = gtk_menu_item_new_with_label(_("Go to parent"));
964             g_signal_connect(G_OBJECT(w), "activate", GCallback(leave_group), dt);
965             gtk_widget_show(w);
966             gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
968         }
969     }
971     return m;
974 /* Drag and Drop */
975 void
976 sp_ui_drag_data_received(GtkWidget *widget,
977                          GdkDragContext *drag_context,
978                          gint x, gint y,
979                          GtkSelectionData *data,
980                          guint info,
981                          guint event_time,
982                          gpointer user_data)
984     switch (info) {
985 #if ENABLE_MAGIC_COLORS
986         case APP_X_INKY_COLOR:
987         {
988             SPDesktop *desktop = SP_ACTIVE_DESKTOP;
989             int destX = 0;
990             int destY = 0;
991             gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY );
992             NR::Point where( sp_canvas_window_to_world( desktop->canvas, NR::Point( destX, destY ) ) );
994             SPItem *item = desktop->item_at_point( where, true );
995             if ( item )
996             {
997                 if ( data->length >= 8 ) {
998                     cmsHPROFILE srgbProf = cmsCreate_sRGBProfile();
1000                     gchar c[64] = {0};
1001                     // Careful about endian issues.
1002                     guint16* dataVals = (guint16*)data->data;
1003                     sp_svg_write_color( c, 64,
1004                                         SP_RGBA32_U_COMPOSE(
1005                                             0x0ff & (dataVals[0] >> 8),
1006                                             0x0ff & (dataVals[1] >> 8),
1007                                             0x0ff & (dataVals[2] >> 8),
1008                                             0xff // can't have transparency in the color itself
1009                                             //0x0ff & (data->data[3] >> 8),
1010                                             ));
1011                     SPCSSAttr *css = sp_repr_css_attr_new();
1012                     bool updatePerformed = false;
1014                     if ( data->length > 14 ) {
1015                         int flags = dataVals[4];
1017                         // piggie-backed palette entry info
1018                         int index = dataVals[5];
1019                         Glib::ustring palName;
1020                         for ( int i = 0; i < dataVals[6]; i++ ) {
1021                             palName += (gunichar)dataVals[7+i];
1022                         }
1024                         // Now hook in a magic tag of some sort.
1025                         if ( !palName.empty() && (flags & 1) ) {
1026                             gchar* str = g_strdup_printf("%d|", index);
1027                             palName.insert( 0, str );
1028                             g_free(str);
1029                             str = 0;
1031                             sp_object_setAttribute( SP_OBJECT(item),
1032                                                     (drag_context->action != GDK_ACTION_MOVE) ? "inkscape:x-fill-tag":"inkscape:x-stroke-tag",
1033                                                     palName.c_str(),
1034                                                     false );
1035                             item->updateRepr();
1037                             sp_repr_css_set_property( css, (drag_context->action != GDK_ACTION_MOVE) ? "fill":"stroke", c );
1038                             updatePerformed = true;
1039                         }
1040                     }
1042                     if ( !updatePerformed ) {
1043                         sp_repr_css_set_property( css, (drag_context->action != GDK_ACTION_MOVE) ? "fill":"stroke", c );
1044                     }
1046                     sp_desktop_apply_css_recursive( item, css, true );
1047                     item->updateRepr();
1049                     SPDocument *doc = SP_ACTIVE_DOCUMENT;
1050                     sp_document_done( doc , SP_VERB_NONE, 
1051                                       /* TODO: annotate */ "interface.cpp:1047");
1053                     if ( srgbProf ) {
1054                         cmsCloseProfile( srgbProf );
1055                     }
1056                 }
1057             }
1058         }
1059         break;
1060 #endif // ENABLE_MAGIC_COLORS
1062         case APP_X_COLOR:
1063         {
1064             SPDesktop *desktop = SP_ACTIVE_DESKTOP;
1065             int destX = 0;
1066             int destY = 0;
1067             gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY );
1068             NR::Point where( sp_canvas_window_to_world( desktop->canvas, NR::Point( destX, destY ) ) );
1070             SPItem *item = desktop->item_at_point( where, true );
1071             if ( item )
1072             {
1073                 if ( data->length == 8 ) {
1074                     gchar c[64] = {0};
1075                     // Careful about endian issues.
1076                     guint16* dataVals = (guint16*)data->data;
1077                     sp_svg_write_color( c, 64,
1078                                         SP_RGBA32_U_COMPOSE(
1079                                             0x0ff & (dataVals[0] >> 8),
1080                                             0x0ff & (dataVals[1] >> 8),
1081                                             0x0ff & (dataVals[2] >> 8),
1082                                             0xff // can't have transparency in the color itself
1083                                             //0x0ff & (data->data[3] >> 8),
1084                                             ));
1085                     SPCSSAttr *css = sp_repr_css_attr_new();
1086                     sp_repr_css_set_property( css, (drag_context->action != GDK_ACTION_MOVE) ? "fill":"stroke", c );
1088                     sp_desktop_apply_css_recursive( item, css, true );
1089                     item->updateRepr();
1091                     SPDocument *doc = SP_ACTIVE_DOCUMENT;
1092                     sp_document_done( doc , SP_VERB_NONE, 
1093                                       /* TODO: annotate */ "interface.cpp:1089");
1094                 }
1095             }
1096         }
1097         break;
1099         case SVG_DATA:
1100         case SVG_XML_DATA: {
1101             gchar *svgdata = (gchar *)data->data;
1103             SPDocument *doc = SP_ACTIVE_DOCUMENT;
1105             Inkscape::XML::Document *rnewdoc = sp_repr_read_mem(svgdata, data->length, SP_SVG_NS_URI);
1107             if (rnewdoc == NULL) {
1108                 sp_ui_error_dialog(_("Could not parse SVG data"));
1109                 return;
1110             }
1112             Inkscape::XML::Node *repr = sp_repr_document_root(rnewdoc);
1113             gchar const *style = repr->attribute("style");
1115             Inkscape::XML::Node *newgroup = sp_repr_new("svg:g");
1116             newgroup->setAttribute("style", style);
1118             for (Inkscape::XML::Node *child = repr->firstChild(); child != NULL; child = child->next()) {
1119                 Inkscape::XML::Node *newchild = child->duplicate();
1120                 newgroup->appendChild(newchild);
1121             }
1123             Inkscape::GC::release(rnewdoc);
1125             SPDesktop *desktop = SP_ACTIVE_DESKTOP;
1126             // Add it to the current layer
1128             // Greg's edits to add intelligent positioning of svg drops
1129             SPObject *new_obj = NULL;
1130             new_obj = desktop->currentLayer()->appendChildRepr(newgroup);
1132             Inkscape::Selection *selection = sp_desktop_selection(desktop);
1133             selection->set(SP_ITEM(new_obj));
1134             // To move the imported object, we must temporarily set the "transform pattern with
1135             // object" option.
1136             {
1137                 int const saved_pref = prefs_get_int_attribute("options.transform", "pattern", 1);
1138                 prefs_set_int_attribute("options.transform", "pattern", 1);
1139                 sp_document_ensure_up_to_date(sp_desktop_document(desktop));
1140                 NR::Point m( desktop->point() - selection->bounds().midpoint() );
1141                 sp_selection_move_relative(selection, m);
1142                 prefs_set_int_attribute("options.transform", "pattern", saved_pref);
1143             }
1145             Inkscape::GC::release(newgroup);
1146             sp_document_done(doc, SP_VERB_NONE, 
1147                              /* TODO: annotate */ "interface.cpp:1143");
1148             break;
1149         }
1151         case URI_LIST: {
1152             gchar *uri = (gchar *)data->data;
1153             sp_ui_import_files(uri);
1154             break;
1155         }
1157         case PNG_DATA:
1158         case JPEG_DATA:
1159         case IMAGE_DATA: {
1160             char tmp[1024];
1162             StringOutputStream outs;
1163             Base64OutputStream b64out(outs);
1164             b64out.setColumnWidth(0);
1166             SPDocument *doc = SP_ACTIVE_DOCUMENT;
1168             Inkscape::XML::Node *newImage = sp_repr_new("svg:image");
1170             for ( int i = 0; i < data->length; i++ ) {
1171                 b64out.put( data->data[i] );
1172             }
1173             b64out.close();
1176             Glib::ustring str = outs.getString();
1178             snprintf( tmp, sizeof(tmp), "data:%s;base64,", gdk_atom_name(data->type) );
1179             str.insert( 0, tmp );
1180             newImage->setAttribute("xlink:href", str.c_str());
1182             GError *error = NULL;
1183             GdkPixbufLoader *loader = gdk_pixbuf_loader_new_with_mime_type( gdk_atom_name(data->type), &error );
1184             if ( loader ) {
1185                 error = NULL;
1186                 if ( gdk_pixbuf_loader_write( loader, data->data, data->length, &error) ) {
1187                     GdkPixbuf *pbuf = gdk_pixbuf_loader_get_pixbuf(loader);
1188                     if ( pbuf ) {
1189                         int width = gdk_pixbuf_get_width(pbuf);
1190                         int height = gdk_pixbuf_get_height(pbuf);
1191                         snprintf( tmp, sizeof(tmp), "%d", width );
1192                         newImage->setAttribute("width", tmp);
1194                         snprintf( tmp, sizeof(tmp), "%d", height );
1195                         newImage->setAttribute("height", tmp);
1196                     }
1197                 }
1198             }
1200             SPDesktop *desktop = SP_ACTIVE_DESKTOP;
1202             // Add it to the current layer
1203             desktop->currentLayer()->appendChildRepr(newImage);
1205             Inkscape::GC::release(newImage);
1206             sp_document_done( doc , SP_VERB_NONE, 
1207                               /* TODO: annotate */ "interface.cpp:1203");
1208             break;
1209         }
1210     }
1213 static void
1214 sp_ui_import_files(gchar *buffer)
1216     GList *list = gnome_uri_list_extract_filenames(buffer);
1217     if (!list)
1218         return;
1219     g_list_foreach(list, sp_ui_import_one_file_with_check, NULL);
1220     g_list_foreach(list, (GFunc) g_free, NULL);
1221     g_list_free(list);
1224 static void
1225 sp_ui_import_one_file_with_check(gpointer filename, gpointer unused)
1227     if (filename) {
1228         if (strlen((char const *)filename) > 2)
1229             sp_ui_import_one_file((char const *)filename);
1230     }
1233 static void
1234 sp_ui_import_one_file(char const *filename)
1236     SPDocument *doc = SP_ACTIVE_DOCUMENT;
1237     if (!doc) return;
1239     if (filename == NULL) return;
1241     // Pass off to common implementation
1242     // TODO might need to get the proper type of Inkscape::Extension::Extension
1243     file_import( doc, filename, NULL );
1246 void
1247 sp_ui_error_dialog(gchar const *message)
1249     GtkWidget *dlg;
1250     gchar *safeMsg = Inkscape::IO::sanitizeString(message);
1252     dlg = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,
1253                                  GTK_BUTTONS_CLOSE, safeMsg);
1254     sp_transientize(dlg);
1255     gtk_window_set_resizable(GTK_WINDOW(dlg), FALSE);
1256     gtk_dialog_run(GTK_DIALOG(dlg));
1257     gtk_widget_destroy(dlg);
1258     g_free(safeMsg);
1261 bool
1262 sp_ui_overwrite_file(gchar const *filename)
1264     bool return_value = FALSE;
1265     GtkWidget *dialog;
1266     GtkWidget *hbox;
1267     GtkWidget *boxdata;
1268     gchar *title;
1269     gchar *text;
1271     if (Inkscape::IO::file_test(filename, G_FILE_TEST_EXISTS)) {
1273         title = g_strdup_printf(_("Overwrite %s"), filename);
1274         dialog = gtk_dialog_new_with_buttons(title,
1275                                              NULL,
1276                                              (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
1277                                              GTK_STOCK_NO,
1278                                              GTK_RESPONSE_NO,
1279                                              GTK_STOCK_YES,
1280                                              GTK_RESPONSE_YES,
1281                                              NULL);
1282         gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_YES);
1284         sp_transientize(dialog);
1285         gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
1287         hbox = gtk_hbox_new(FALSE, 5);
1289         // TODO - replace with Inkscape-specific call
1290         boxdata = gtk_image_new_from_stock(GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG);
1292         gtk_widget_show(boxdata);
1293         gtk_box_pack_start(GTK_BOX(hbox), boxdata, TRUE, TRUE, 5);
1294         text = g_strdup_printf(_("The file %s already exists.  Do you want to overwrite that file with the current document?"), filename);
1295         boxdata = gtk_label_new(text);
1296         gtk_label_set_line_wrap(GTK_LABEL(boxdata), TRUE);
1297         gtk_widget_show(boxdata);
1298         gtk_box_pack_start(GTK_BOX(hbox), boxdata, FALSE, FALSE, 5);
1299         gtk_widget_show(hbox);
1300         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, TRUE, TRUE, 5);
1302         if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES) {
1303             return_value = TRUE;
1304         } else {
1305             return_value = FALSE;
1306         }
1308         gtk_widget_destroy(dialog);
1309         g_free(title);
1310         g_free(text);
1311     } else {
1312         return_value = TRUE;
1313     }
1315     return return_value;
1318 static void
1319 sp_ui_menu_item_set_sensitive(SPAction *action, unsigned int sensitive, void *data)
1321     return gtk_widget_set_sensitive(GTK_WIDGET(data), sensitive);
1324 static void
1325 sp_ui_menu_item_set_name(SPAction *action, Glib::ustring name, void *data)
1327     gtk_label_set_markup_with_mnemonic(
1328         GTK_LABEL (gtk_container_get_children(GTK_CONTAINER (GTK_BIN (data)->child))->data), 
1329         name.c_str());
1333 /*
1334   Local Variables:
1335   mode:c++
1336   c-file-style:"stroustrup"
1337   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1338   indent-tabs-mode:nil
1339   fill-column:99
1340   End:
1341 */
1342 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :