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)
130 {
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);
200 }
202 void
203 sp_ui_new_view()
204 {
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));
217 }
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()
223 {
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);
235 }
237 /**
238 * \param widget unused
239 */
240 void
241 sp_ui_close_view(GtkWidget *widget)
242 {
243 if (SP_ACTIVE_DESKTOP == NULL) {
244 return;
245 }
246 if ((SP_ACTIVE_DESKTOP)->shutdown()) {
247 return;
248 }
249 SP_ACTIVE_DESKTOP->destroyWidget();
250 }
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)
266 {
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;
278 }
280 static gint
281 sp_ui_delete(GtkWidget *widget, GdkEvent *event, Inkscape::UI::View::View *view)
282 {
283 return view->shutdown();
284 }
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)
295 {
296 sp_action_perform(action, NULL);
297 }
299 static void
300 sp_ui_menu_select_action(void *object, SPAction *action)
301 {
302 action->view->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, action->tip);
303 }
305 static void
306 sp_ui_menu_deselect_action(void *object, SPAction *action)
307 {
308 action->view->tipsMessageContext()->clear();
309 }
311 static void
312 sp_ui_menu_select(gpointer object, gpointer tip)
313 {
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);
316 }
318 static void
319 sp_ui_menu_deselect(gpointer object)
320 {
321 Inkscape::UI::View::View *view = static_cast<Inkscape::UI::View::View*> (g_object_get_data(G_OBJECT(object), "view"));
322 view->tipsMessageContext()->clear();
323 }
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 )
333 {
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 )
351 {
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)
387 {
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;
408 }
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)
417 {
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.
451 }
453 void
454 sp_ui_dialog_title_string(Inkscape::Verb *verb, gchar *c)
455 {
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 }
479 }
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)
491 {
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)
563 {
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();
577 }
579 static gboolean
580 checkitem_update(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
581 {
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;
600 }
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)
608 {
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);
664 }
666 static void
667 sp_recent_open(GtkWidget *widget, gchar const *uri)
668 {
669 sp_file_open(uri, NULL);
670 }
672 static void
673 sp_file_new_from_template(GtkWidget *widget, gchar const *uri)
674 {
675 sp_file_new(uri);
676 }
678 void
679 sp_menu_append_new_templates(GtkWidget *menu, Inkscape::UI::View::View *view)
680 {
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 }
733 }
735 void
736 sp_menu_append_recent_documents(GtkWidget *menu, Inkscape::UI::View::View* /* view */)
737 {
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 }
762 }
764 void
765 sp_ui_checkboxes_menus(GtkMenu *m, Inkscape::UI::View::View *view)
766 {
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);
783 }
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)
802 {
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 }
867 }
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)
878 {
879 GtkWidget *mbar = gtk_menu_bar_new();
881 sp_ui_build_dyn_menus(inkscape_get_menus(INKSCAPE), mbar, view);
883 return mbar;
884 }
886 static void leave_group(GtkMenuItem *, SPDesktop *desktop) {
887 desktop->setCurrentLayer(SP_OBJECT_PARENT(desktop->currentLayer()));
888 }
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();
893 }
895 GtkWidget *
896 sp_ui_context_menu(Inkscape::UI::View::View *view, SPItem *item)
897 {
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;
966 }
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)
977 {
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 }
1203 }
1205 static void
1206 sp_ui_import_files(gchar *buffer)
1207 {
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);
1214 }
1216 static void
1217 sp_ui_import_one_file_with_check(gpointer filename, gpointer unused)
1218 {
1219 if (filename) {
1220 if (strlen((char const *)filename) > 2)
1221 sp_ui_import_one_file((char const *)filename);
1222 }
1223 }
1225 static void
1226 sp_ui_import_one_file(char const *filename)
1227 {
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 );
1236 }
1238 void
1239 sp_ui_error_dialog(gchar const *message)
1240 {
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);
1251 }
1253 bool
1254 sp_ui_overwrite_file(gchar const *filename)
1255 {
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;
1295 }
1297 static void
1298 sp_ui_menu_item_set_sensitive(SPAction *action, unsigned int sensitive, void *data)
1299 {
1300 return gtk_widget_set_sensitive(GTK_WIDGET(data), sensitive);
1301 }
1303 static void
1304 sp_ui_menu_item_set_name(SPAction *action, Glib::ustring name, void *data)
1305 {
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());
1309 }
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 :