Code

Updated overwrite confirmation dialog to be similar to the new stock GTK+ one
[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() && SP_OBJECT_PARENT(dt->currentLayer()) != dt->currentRoot() ) ) {
940         /* Separator */
941         sp_ui_menu_append_item(GTK_MENU(m), NULL, NULL, NULL, NULL, NULL, NULL);
942     }
944     if ( group && group != dt->currentLayer() ) {
945         /* TRANSLATORS: #%s is the id of the group e.g. <g id="#g7">, not a number. */
946         gchar *label=g_strdup_printf(_("Enter group #%s"), SP_OBJECT_ID(group));
947         GtkWidget *w = gtk_menu_item_new_with_label(label);
948         g_free(label);
949         g_object_set_data(G_OBJECT(w), "group", group);
950         g_signal_connect(G_OBJECT(w), "activate", GCallback(enter_group), dt);
951         gtk_widget_show(w);
952         gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
953     }
955     if ( dt->currentLayer() != dt->currentRoot() ) {
956         if ( SP_OBJECT_PARENT(dt->currentLayer()) != dt->currentRoot() ) {
957             GtkWidget *w = gtk_menu_item_new_with_label(_("Go to parent"));
958             g_signal_connect(G_OBJECT(w), "activate", GCallback(leave_group), dt);
959             gtk_widget_show(w);
960             gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
962         }
963     }
965     return m;
968 /* Drag and Drop */
969 void
970 sp_ui_drag_data_received(GtkWidget *widget,
971                          GdkDragContext *drag_context,
972                          gint x, gint y,
973                          GtkSelectionData *data,
974                          guint info,
975                          guint event_time,
976                          gpointer user_data)
978     SPDocument *doc = SP_ACTIVE_DOCUMENT;
979     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
981     switch (info) {
982 #if ENABLE_MAGIC_COLORS
983         case APP_X_INKY_COLOR:
984         {
985             int destX = 0;
986             int destY = 0;
987             gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY );
988             NR::Point where( sp_canvas_window_to_world( desktop->canvas, NR::Point( destX, destY ) ) );
990             SPItem *item = desktop->item_at_point( where, true );
991             if ( item )
992             {
993                 if ( data->length >= 8 ) {
994                     cmsHPROFILE srgbProf = cmsCreate_sRGBProfile();
996                     gchar c[64] = {0};
997                     // Careful about endian issues.
998                     guint16* dataVals = (guint16*)data->data;
999                     sp_svg_write_color( c, 64,
1000                                         SP_RGBA32_U_COMPOSE(
1001                                             0x0ff & (dataVals[0] >> 8),
1002                                             0x0ff & (dataVals[1] >> 8),
1003                                             0x0ff & (dataVals[2] >> 8),
1004                                             0xff // can't have transparency in the color itself
1005                                             //0x0ff & (data->data[3] >> 8),
1006                                             ));
1007                     SPCSSAttr *css = sp_repr_css_attr_new();
1008                     bool updatePerformed = false;
1010                     if ( data->length > 14 ) {
1011                         int flags = dataVals[4];
1013                         // piggie-backed palette entry info
1014                         int index = dataVals[5];
1015                         Glib::ustring palName;
1016                         for ( int i = 0; i < dataVals[6]; i++ ) {
1017                             palName += (gunichar)dataVals[7+i];
1018                         }
1020                         // Now hook in a magic tag of some sort.
1021                         if ( !palName.empty() && (flags & 1) ) {
1022                             gchar* str = g_strdup_printf("%d|", index);
1023                             palName.insert( 0, str );
1024                             g_free(str);
1025                             str = 0;
1027                             sp_object_setAttribute( SP_OBJECT(item),
1028                                                     (drag_context->action != GDK_ACTION_MOVE) ? "inkscape:x-fill-tag":"inkscape:x-stroke-tag",
1029                                                     palName.c_str(),
1030                                                     false );
1031                             item->updateRepr();
1033                             sp_repr_css_set_property( css, (drag_context->action != GDK_ACTION_MOVE) ? "fill":"stroke", c );
1034                             updatePerformed = true;
1035                         }
1036                     }
1038                     if ( !updatePerformed ) {
1039                         sp_repr_css_set_property( css, (drag_context->action != GDK_ACTION_MOVE) ? "fill":"stroke", c );
1040                     }
1042                     sp_desktop_apply_css_recursive( item, css, true );
1043                     item->updateRepr();
1045                     sp_document_done( doc , SP_VERB_NONE, 
1046                                       _("Drop color"));
1048                     if ( srgbProf ) {
1049                         cmsCloseProfile( srgbProf );
1050                     }
1051                 }
1052             }
1053         }
1054         break;
1055 #endif // ENABLE_MAGIC_COLORS
1057         case APP_X_COLOR:
1058         {
1059             int destX = 0;
1060             int destY = 0;
1061             gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY );
1062             NR::Point where( sp_canvas_window_to_world( desktop->canvas, NR::Point( destX, destY ) ) );
1064             SPItem *item = desktop->item_at_point( where, true );
1065             if ( item )
1066             {
1067                 if ( data->length == 8 ) {
1068                     gchar c[64] = {0};
1069                     // Careful about endian issues.
1070                     guint16* dataVals = (guint16*)data->data;
1071                     sp_svg_write_color( c, 64,
1072                                         SP_RGBA32_U_COMPOSE(
1073                                             0x0ff & (dataVals[0] >> 8),
1074                                             0x0ff & (dataVals[1] >> 8),
1075                                             0x0ff & (dataVals[2] >> 8),
1076                                             0xff // can't have transparency in the color itself
1077                                             //0x0ff & (data->data[3] >> 8),
1078                                             ));
1079                     SPCSSAttr *css = sp_repr_css_attr_new();
1080                     sp_repr_css_set_property( css, (drag_context->action != GDK_ACTION_MOVE) ? "fill":"stroke", c );
1082                     sp_desktop_apply_css_recursive( item, css, true );
1083                     item->updateRepr();
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             Inkscape::XML::Document *rnewdoc = sp_repr_read_mem(svgdata, data->length, SP_SVG_NS_URI);
1098             if (rnewdoc == NULL) {
1099                 sp_ui_error_dialog(_("Could not parse SVG data"));
1100                 return;
1101             }
1103             Inkscape::XML::Node *repr = rnewdoc->root();
1104             gchar const *style = repr->attribute("style");
1106             Inkscape::XML::Node *newgroup = rnewdoc->createElement("svg:g");
1107             newgroup->setAttribute("style", style);
1109             Inkscape::XML::Document * xml_doc =  sp_document_repr_doc(doc);
1110             for (Inkscape::XML::Node *child = repr->firstChild(); child != NULL; child = child->next()) {
1111                 Inkscape::XML::Node *newchild = child->duplicate(xml_doc);
1112                 newgroup->appendChild(newchild);
1113             }
1115             Inkscape::GC::release(rnewdoc);
1117             // Add it to the current layer
1119             // Greg's edits to add intelligent positioning of svg drops
1120             SPObject *new_obj = NULL;
1121             new_obj = desktop->currentLayer()->appendChildRepr(newgroup);
1123             Inkscape::Selection *selection = sp_desktop_selection(desktop);
1124             selection->set(SP_ITEM(new_obj));
1125             // To move the imported object, we must temporarily set the "transform pattern with
1126             // object" option.
1127             {
1128                 int const saved_pref = prefs_get_int_attribute("options.transform", "pattern", 1);
1129                 prefs_set_int_attribute("options.transform", "pattern", 1);
1130                 sp_document_ensure_up_to_date(sp_desktop_document(desktop));
1131                 NR::Maybe<NR::Rect> sel_bbox = selection->bounds();
1132                 if (sel_bbox) {
1133                     NR::Point m( desktop->point() - sel_bbox->midpoint() );
1134                     sp_selection_move_relative(selection, m);
1135                 }
1136                 prefs_set_int_attribute("options.transform", "pattern", saved_pref);
1137             }
1139             Inkscape::GC::release(newgroup);
1140             sp_document_done(doc, SP_VERB_NONE, 
1141                              _("Drop SVG"));
1142             break;
1143         }
1145         case URI_LIST: {
1146             gchar *uri = (gchar *)data->data;
1147             sp_ui_import_files(uri);
1148             break;
1149         }
1151         case PNG_DATA:
1152         case JPEG_DATA:
1153         case IMAGE_DATA: {
1154             char tmp[1024];
1156             StringOutputStream outs;
1157             Base64OutputStream b64out(outs);
1158             b64out.setColumnWidth(0);
1160             Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
1162             Inkscape::XML::Node *newImage = xml_doc->createElement("svg:image");
1164             for ( int i = 0; i < data->length; i++ ) {
1165                 b64out.put( data->data[i] );
1166             }
1167             b64out.close();
1170             Glib::ustring str = outs.getString();
1172             snprintf( tmp, sizeof(tmp), "data:%s;base64,", gdk_atom_name(data->type) );
1173             str.insert( 0, tmp );
1174             newImage->setAttribute("xlink:href", str.c_str());
1176             GError *error = NULL;
1177             GdkPixbufLoader *loader = gdk_pixbuf_loader_new_with_mime_type( gdk_atom_name(data->type), &error );
1178             if ( loader ) {
1179                 error = NULL;
1180                 if ( gdk_pixbuf_loader_write( loader, data->data, data->length, &error) ) {
1181                     GdkPixbuf *pbuf = gdk_pixbuf_loader_get_pixbuf(loader);
1182                     if ( pbuf ) {
1183                         int width = gdk_pixbuf_get_width(pbuf);
1184                         int height = gdk_pixbuf_get_height(pbuf);
1185                         snprintf( tmp, sizeof(tmp), "%d", width );
1186                         newImage->setAttribute("width", tmp);
1188                         snprintf( tmp, sizeof(tmp), "%d", height );
1189                         newImage->setAttribute("height", tmp);
1190                     }
1191                 }
1192             }
1194             // Add it to the current layer
1195             desktop->currentLayer()->appendChildRepr(newImage);
1197             Inkscape::GC::release(newImage);
1198             sp_document_done( doc , SP_VERB_NONE, 
1199                               _("Drop bitmap image"));
1200             break;
1201         }
1202     }
1205 static void
1206 sp_ui_import_files(gchar *buffer)
1208     GList *list = gnome_uri_list_extract_filenames(buffer);
1209     if (!list)
1210         return;
1211     g_list_foreach(list, sp_ui_import_one_file_with_check, NULL);
1212     g_list_foreach(list, (GFunc) g_free, NULL);
1213     g_list_free(list);
1216 static void
1217 sp_ui_import_one_file_with_check(gpointer filename, gpointer unused)
1219     if (filename) {
1220         if (strlen((char const *)filename) > 2)
1221             sp_ui_import_one_file((char const *)filename);
1222     }
1225 static void
1226 sp_ui_import_one_file(char const *filename)
1228     SPDocument *doc = SP_ACTIVE_DOCUMENT;
1229     if (!doc) return;
1231     if (filename == NULL) return;
1233     // Pass off to common implementation
1234     // TODO might need to get the proper type of Inkscape::Extension::Extension
1235     file_import( doc, filename, NULL );
1238 void
1239 sp_ui_error_dialog(gchar const *message)
1241     GtkWidget *dlg;
1242     gchar *safeMsg = Inkscape::IO::sanitizeString(message);
1244     dlg = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,
1245                                  GTK_BUTTONS_CLOSE, "%s", safeMsg);
1246     sp_transientize(dlg);
1247     gtk_window_set_resizable(GTK_WINDOW(dlg), FALSE);
1248     gtk_dialog_run(GTK_DIALOG(dlg));
1249     gtk_widget_destroy(dlg);
1250     g_free(safeMsg);
1253 bool
1254 sp_ui_overwrite_file(gchar const *filename)
1256     bool return_value = FALSE;
1258     if (Inkscape::IO::file_test(filename, G_FILE_TEST_EXISTS)) {
1259         GtkWidget* ancestor = 0;
1260         SPDesktop *desktop = SP_ACTIVE_DESKTOP;
1261         if ( desktop ) {
1262             desktop->getToplevel( ancestor );
1263         }
1264         GtkWindow *window = GTK_WIDGET_TOPLEVEL(ancestor) ? GTK_WINDOW( ancestor ) : 0;
1265         gchar* baseName = g_path_get_basename( filename );
1266         gchar* dirName = g_path_get_dirname( filename );
1267         GtkWidget* dialog = gtk_message_dialog_new_with_markup( window,
1268                                                                 (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
1269                                                                 GTK_MESSAGE_QUESTION,
1270                                                                 GTK_BUTTONS_NONE,
1271                                                                 _( "<span weight=\"bold\" size=\"larger\">A file named \"%s\" already exists. Do you want to replace it?</span>\n\n"
1272                                                                    "The file already exists in \"%s\". Replacing it will overwrite its contents." ),
1273                                                                 baseName,
1274                                                                 dirName
1275             );
1276         gtk_dialog_add_buttons( GTK_DIALOG(dialog),
1277                                 GTK_STOCK_CANCEL, GTK_RESPONSE_NO,
1278                                 _("Replace"), GTK_RESPONSE_YES,
1279                                 NULL );
1280         gtk_dialog_set_default_response( GTK_DIALOG(dialog), GTK_RESPONSE_YES );
1282         if ( gtk_dialog_run( GTK_DIALOG(dialog) ) == GTK_RESPONSE_YES ) {
1283             return_value = TRUE;
1284         } else {
1285             return_value = FALSE;
1286         }
1287         gtk_widget_destroy(dialog);
1288         g_free( baseName );
1289         g_free( dirName );
1290     } else {
1291         return_value = TRUE;
1292     }
1294     return return_value;
1297 static void
1298 sp_ui_menu_item_set_sensitive(SPAction *action, unsigned int sensitive, void *data)
1300     return gtk_widget_set_sensitive(GTK_WIDGET(data), sensitive);
1303 static void
1304 sp_ui_menu_item_set_name(SPAction *action, Glib::ustring name, void *data)
1306     gtk_label_set_markup_with_mnemonic(
1307         GTK_LABEL (gtk_container_get_children(GTK_CONTAINER (GTK_BIN (data)->child))->data), 
1308         name.c_str());
1312 /*
1313   Local Variables:
1314   mode:c++
1315   c-file-style:"stroustrup"
1316   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1317   indent-tabs-mode:nil
1318   fill-column:99
1319   End:
1320 */
1321 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :