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 }
218 /* TODO: not yet working */
219 /* To be re-enabled (by adding to menu) once it works. */
220 void
221 sp_ui_new_view_preview()
222 {
223 SPDocument *document;
224 SPViewWidget *dtw;
226 document = SP_ACTIVE_DOCUMENT;
227 if (!document) return;
229 dtw = (SPViewWidget *) sp_svg_view_widget_new(document);
230 g_return_if_fail(dtw != NULL);
231 sp_svg_view_widget_set_resize(SP_SVG_VIEW_WIDGET(dtw), TRUE, 400.0, 400.0);
233 sp_create_window(dtw, FALSE);
234 }
236 /**
237 * \param widget unused
238 */
239 void
240 sp_ui_close_view(GtkWidget *widget)
241 {
242 if (SP_ACTIVE_DESKTOP == NULL) {
243 return;
244 }
245 if ((SP_ACTIVE_DESKTOP)->shutdown()) {
246 return;
247 }
248 SP_ACTIVE_DESKTOP->destroyWidget();
249 }
252 /**
253 * sp_ui_close_all
254 *
255 * This function is called to exit the program, and iterates through all
256 * open document view windows, attempting to close each in turn. If the
257 * view has unsaved information, the user will be prompted to save,
258 * discard, or cancel.
259 *
260 * Returns FALSE if the user cancels the close_all operation, TRUE
261 * otherwise.
262 */
263 unsigned int
264 sp_ui_close_all(void)
265 {
266 /* Iterate through all the windows, destroying each in the order they
267 become active */
268 while (SP_ACTIVE_DESKTOP) {
269 if ((SP_ACTIVE_DESKTOP)->shutdown()) {
270 /* The user cancelled the operation, so end doing the close */
271 return FALSE;
272 }
273 SP_ACTIVE_DESKTOP->destroyWidget();
274 }
276 return TRUE;
277 }
279 static gint
280 sp_ui_delete(GtkWidget *widget, GdkEvent *event, Inkscape::UI::View::View *view)
281 {
282 return view->shutdown();
283 }
285 /*
286 * Some day when the right-click menus are ready to start working
287 * smarter with the verbs, we'll need to change this NULL being
288 * sent to sp_action_perform to something useful, or set some kind
289 * of global "right-clicked position" variable for actions to
290 * investigate when they're called.
291 */
292 static void
293 sp_ui_menu_activate(void *object, SPAction *action)
294 {
295 sp_action_perform(action, NULL);
296 }
298 static void
299 sp_ui_menu_select_action(void *object, SPAction *action)
300 {
301 action->view->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, action->tip);
302 }
304 static void
305 sp_ui_menu_deselect_action(void *object, SPAction *action)
306 {
307 action->view->tipsMessageContext()->clear();
308 }
310 static void
311 sp_ui_menu_select(gpointer object, gpointer tip)
312 {
313 Inkscape::UI::View::View *view = static_cast<Inkscape::UI::View::View*> (g_object_get_data(G_OBJECT(object), "view"));
314 view->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, (gchar *)tip);
315 }
317 static void
318 sp_ui_menu_deselect(gpointer object)
319 {
320 Inkscape::UI::View::View *view = static_cast<Inkscape::UI::View::View*> (g_object_get_data(G_OBJECT(object), "view"));
321 view->tipsMessageContext()->clear();
322 }
324 /**
325 * sp_ui_menuitem_add_icon
326 *
327 * Creates and attaches a scaled icon to the given menu item.
328 *
329 */
330 void
331 sp_ui_menuitem_add_icon( GtkWidget *item, gchar *icon_name )
332 {
333 GtkWidget *icon;
335 icon = sp_icon_new( Inkscape::ICON_SIZE_MENU, icon_name );
336 gtk_widget_show(icon);
337 gtk_image_menu_item_set_image((GtkImageMenuItem *) item, icon);
338 } // end of sp_ui_menu_add_icon
340 /**
341 * sp_ui_menu_append_item
342 *
343 * Appends a UI item with specific info for Inkscape/Sodipodi.
344 *
345 */
346 static GtkWidget *
347 sp_ui_menu_append_item( GtkMenu *menu, gchar const *stock,
348 gchar const *label, gchar const *tip, Inkscape::UI::View::View *view, GCallback callback,
349 gpointer data, gboolean with_mnemonic = TRUE )
350 {
351 GtkWidget *item;
353 if (stock) {
354 item = gtk_image_menu_item_new_from_stock(stock, NULL);
355 } else if (label) {
356 item = (with_mnemonic)
357 ? gtk_image_menu_item_new_with_mnemonic(label) :
358 gtk_image_menu_item_new_with_label(label);
359 } else {
360 item = gtk_separator_menu_item_new();
361 }
363 gtk_widget_show(item);
365 if (callback) {
366 g_signal_connect(G_OBJECT(item), "activate", callback, data);
367 }
369 if (tip && view) {
370 g_object_set_data(G_OBJECT(item), "view", (gpointer) view);
371 g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select), (gpointer) tip );
372 g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect), NULL);
373 }
375 gtk_menu_append(GTK_MENU(menu), item);
377 return item;
379 } // end of sp_ui_menu_append_item()
381 /**
382 \brief a wrapper around gdk_keyval_name producing (when possible) characters, not names
383 */
384 static gchar const *
385 sp_key_name(guint keyval)
386 {
387 /* TODO: Compare with the definition of gtk_accel_label_refetch in gtk/gtkaccellabel.c (or
388 simply use GtkAccelLabel as the TODO comment in sp_ui_shortcut_string suggests). */
389 gchar const *n = gdk_keyval_name(gdk_keyval_to_upper(keyval));
391 if (!strcmp(n, "asciicircum")) return "^";
392 else if (!strcmp(n, "parenleft" )) return "(";
393 else if (!strcmp(n, "parenright" )) return ")";
394 else if (!strcmp(n, "plus" )) return "+";
395 else if (!strcmp(n, "minus" )) return "-";
396 else if (!strcmp(n, "asterisk" )) return "*";
397 else if (!strcmp(n, "KP_Multiply")) return "*";
398 else if (!strcmp(n, "Delete" )) return "Del";
399 else if (!strcmp(n, "Page_Up" )) return "PgUp";
400 else if (!strcmp(n, "Page_Down" )) return "PgDn";
401 else if (!strcmp(n, "grave" )) return "`";
402 else if (!strcmp(n, "numbersign" )) return "#";
403 else if (!strcmp(n, "bar" )) return "|";
404 else if (!strcmp(n, "slash" )) return "/";
405 else if (!strcmp(n, "exclam" )) return "!";
406 else return n;
407 }
410 /**
411 * \param shortcut A GDK keyval OR'd with SP_SHORTCUT_blah_MASK values.
412 * \param c Points to a buffer at least 256 bytes long.
413 */
414 void
415 sp_ui_shortcut_string(unsigned const shortcut, gchar *const c)
416 {
417 /* TODO: This function shouldn't exist. Our callers should use GtkAccelLabel instead of
418 * a generic GtkLabel containing this string, and should call gtk_widget_add_accelerator.
419 * Will probably need to change sp_shortcut_invoke callers.
420 *
421 * The existing gtk_label_new_with_mnemonic call can be replaced with
422 * g_object_new(GTK_TYPE_ACCEL_LABEL, NULL) followed by
423 * gtk_label_set_text_with_mnemonic(lbl, str).
424 */
425 static GtkAccelLabelClass const &accel_lbl_cls
426 = *(GtkAccelLabelClass const *) g_type_class_peek_static(GTK_TYPE_ACCEL_LABEL);
428 struct { unsigned test; char const *name; } const modifier_tbl[] = {
429 { SP_SHORTCUT_SHIFT_MASK, accel_lbl_cls.mod_name_shift },
430 { SP_SHORTCUT_CONTROL_MASK, accel_lbl_cls.mod_name_control },
431 { SP_SHORTCUT_ALT_MASK, accel_lbl_cls.mod_name_alt }
432 };
434 gchar *p = c;
435 gchar *end = p + 256;
437 for (unsigned i = 0; i < G_N_ELEMENTS(modifier_tbl); ++i) {
438 if ((shortcut & modifier_tbl[i].test)
439 && (p < end))
440 {
441 p += g_snprintf(p, end - p, "%s%s",
442 modifier_tbl[i].name,
443 accel_lbl_cls.mod_separator);
444 }
445 }
446 if (p < end) {
447 p += g_snprintf(p, end - p, "%s", sp_key_name(shortcut & 0xffffff));
448 }
449 end[-1] = '\0'; // snprintf doesn't guarantee to nul-terminate the string.
450 }
452 void
453 sp_ui_dialog_title_string(Inkscape::Verb *verb, gchar *c)
454 {
455 SPAction *action;
456 unsigned int shortcut;
457 gchar *s;
458 gchar key[256];
459 gchar *atitle;
461 action = verb->get_action(NULL);
462 if (!action)
463 return;
465 atitle = sp_action_get_title(action);
467 s = g_stpcpy(c, atitle);
469 g_free(atitle);
471 shortcut = sp_shortcut_get_primary(verb);
472 if (shortcut) {
473 s = g_stpcpy(s, " (");
474 sp_ui_shortcut_string(shortcut, key);
475 s = g_stpcpy(s, key);
476 s = g_stpcpy(s, ")");
477 }
478 }
481 /**
482 * sp_ui_menu_append_item_from_verb
483 *
484 * Appends a custom menu UI from a verb.
485 *
486 */
488 static GtkWidget *
489 sp_ui_menu_append_item_from_verb(GtkMenu *menu, Inkscape::Verb *verb, Inkscape::UI::View::View *view, bool radio = false, GSList *group = NULL)
490 {
491 SPAction *action;
492 GtkWidget *item;
494 if (verb->get_code() == SP_VERB_NONE) {
496 item = gtk_separator_menu_item_new();
498 } else {
499 unsigned int shortcut;
501 action = verb->get_action(view);
503 if (!action) return NULL;
505 shortcut = sp_shortcut_get_primary(verb);
506 if (shortcut) {
507 gchar c[256];
508 sp_ui_shortcut_string(shortcut, c);
509 GtkWidget *const hb = gtk_hbox_new(FALSE, 16);
510 GtkWidget *const name_lbl = gtk_label_new("");
511 gtk_label_set_markup_with_mnemonic(GTK_LABEL(name_lbl), action->name);
512 gtk_misc_set_alignment((GtkMisc *) name_lbl, 0.0, 0.5);
513 gtk_box_pack_start((GtkBox *) hb, name_lbl, TRUE, TRUE, 0);
514 GtkWidget *const accel_lbl = gtk_label_new(c);
515 gtk_misc_set_alignment((GtkMisc *) accel_lbl, 1.0, 0.5);
516 gtk_box_pack_end((GtkBox *) hb, accel_lbl, FALSE, FALSE, 0);
517 gtk_widget_show_all(hb);
518 if (radio) {
519 item = gtk_radio_menu_item_new (group);
520 } else {
521 item = gtk_image_menu_item_new();
522 }
523 gtk_container_add((GtkContainer *) item, hb);
524 } else {
525 if (radio) {
526 item = gtk_radio_menu_item_new (group);
527 } else {
528 item = gtk_image_menu_item_new ();
529 }
530 GtkWidget *const name_lbl = gtk_label_new("");
531 gtk_label_set_markup_with_mnemonic(GTK_LABEL(name_lbl), action->name);
532 gtk_misc_set_alignment((GtkMisc *) name_lbl, 0.0, 0.5);
533 gtk_container_add((GtkContainer *) item, name_lbl);
534 }
536 nr_active_object_add_listener((NRActiveObject *)action, (NRObjectEventVector *)&menu_item_event_vector, sizeof(SPActionEventVector), item);
537 if (!action->sensitive) {
538 gtk_widget_set_sensitive(item, FALSE);
539 }
541 if (action->image) {
542 sp_ui_menuitem_add_icon(item, action->image);
543 }
544 gtk_widget_set_events(item, GDK_KEY_PRESS_MASK);
545 g_signal_connect( G_OBJECT(item), "activate",
546 G_CALLBACK(sp_ui_menu_activate), action );
548 g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select_action), action );
549 g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect_action), action );
550 }
552 gtk_widget_show(item);
553 gtk_menu_append(GTK_MENU(menu), item);
555 return item;
557 } // end of sp_ui_menu_append_item_from_verb
560 static void
561 checkitem_toggled(GtkCheckMenuItem *menuitem, gpointer user_data)
562 {
563 gchar const *pref = (gchar const *) user_data;
564 Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view");
566 gchar const *pref_path;
567 if (reinterpret_cast<SPDesktop*>(view)->is_fullscreen)
568 pref_path = g_strconcat("fullscreen.", pref, NULL);
569 else
570 pref_path = g_strconcat("window.", pref, NULL);
572 gboolean checked = gtk_check_menu_item_get_active(menuitem);
573 prefs_set_int_attribute(pref_path, "state", checked);
575 reinterpret_cast<SPDesktop*>(view)->layoutWidget();
576 }
578 static gboolean
579 checkitem_update(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
580 {
581 GtkCheckMenuItem *menuitem=GTK_CHECK_MENU_ITEM(widget);
583 gchar const *pref = (gchar const *) user_data;
584 Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view");
586 gchar const *pref_path;
587 if (static_cast<SPDesktop*>(view)->is_fullscreen)
588 pref_path = g_strconcat("fullscreen.", pref, NULL);
589 else
590 pref_path = g_strconcat("window.", pref, NULL);
592 gint ison = prefs_get_int_attribute_limited(pref_path, "state", 1, 0, 1);
594 g_signal_handlers_block_by_func(G_OBJECT(menuitem), (gpointer)(GCallback)checkitem_toggled, user_data);
595 gtk_check_menu_item_set_active(menuitem, ison);
596 g_signal_handlers_unblock_by_func(G_OBJECT(menuitem), (gpointer)(GCallback)checkitem_toggled, user_data);
598 return FALSE;
599 }
602 void
603 sp_ui_menu_append_check_item_from_verb(GtkMenu *menu, Inkscape::UI::View::View *view, gchar const *label, gchar const *tip, gchar const *pref,
604 void (*callback_toggle)(GtkCheckMenuItem *, gpointer user_data),
605 gboolean (*callback_update)(GtkWidget *widget, GdkEventExpose *event, gpointer user_data),
606 Inkscape::Verb *verb)
607 {
608 GtkWidget *item;
610 unsigned int shortcut = 0;
611 SPAction *action = NULL;
613 if (verb) {
614 shortcut = sp_shortcut_get_primary(verb);
615 action = verb->get_action(view);
616 }
618 if (verb && shortcut) {
619 gchar c[256];
620 sp_ui_shortcut_string(shortcut, c);
622 GtkWidget *hb = gtk_hbox_new(FALSE, 16);
624 {
625 GtkWidget *l = gtk_label_new_with_mnemonic(action ? action->name : label);
626 gtk_misc_set_alignment((GtkMisc *) l, 0.0, 0.5);
627 gtk_box_pack_start((GtkBox *) hb, l, TRUE, TRUE, 0);
628 }
630 {
631 GtkWidget *l = gtk_label_new(c);
632 gtk_misc_set_alignment((GtkMisc *) l, 1.0, 0.5);
633 gtk_box_pack_end((GtkBox *) hb, l, FALSE, FALSE, 0);
634 }
636 gtk_widget_show_all(hb);
638 item = gtk_check_menu_item_new();
639 gtk_container_add((GtkContainer *) item, hb);
640 } else {
641 GtkWidget *l = gtk_label_new_with_mnemonic(action ? action->name : label);
642 gtk_misc_set_alignment((GtkMisc *) l, 0.0, 0.5);
643 item = gtk_check_menu_item_new();
644 gtk_container_add((GtkContainer *) item, l);
645 }
646 #if 0
647 nr_active_object_add_listener((NRActiveObject *)action, (NRObjectEventVector *)&menu_item_event_vector, sizeof(SPActionEventVector), item);
648 if (!action->sensitive) {
649 gtk_widget_set_sensitive(item, FALSE);
650 }
651 #endif
652 gtk_widget_show(item);
654 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
656 g_object_set_data(G_OBJECT(item), "view", (gpointer) view);
658 g_signal_connect( G_OBJECT(item), "toggled", (GCallback) callback_toggle, (void *) pref);
659 g_signal_connect( G_OBJECT(item), "expose_event", (GCallback) callback_update, (void *) pref);
661 g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select), (gpointer) (action ? action->tip : tip));
662 g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect), NULL);
663 }
665 static void
666 sp_recent_open(GtkWidget *widget, gchar const *uri)
667 {
668 sp_file_open(uri, NULL);
669 }
671 static void
672 sp_file_new_from_template(GtkWidget *widget, gchar const *uri)
673 {
674 sp_file_new(uri);
675 }
677 void
678 sp_menu_append_new_templates(GtkWidget *menu, Inkscape::UI::View::View *view)
679 {
680 std::list<gchar *> sources;
681 sources.push_back( profile_path("templates") ); // first try user's local dir
682 sources.push_back( g_strdup(INKSCAPE_TEMPLATESDIR) ); // then the system templates dir
684 // Use this loop to iterate through a list of possible document locations.
685 while (!sources.empty()) {
686 gchar *dirname = sources.front();
688 if ( Inkscape::IO::file_test( dirname, (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR) ) ) {
689 GError *err = 0;
690 GDir *dir = g_dir_open(dirname, 0, &err);
692 if (dir) {
693 for (gchar const *file = g_dir_read_name(dir); file != NULL; file = g_dir_read_name(dir)) {
694 if (!g_str_has_suffix(file, ".svg") && !g_str_has_suffix(file, ".svgz"))
695 continue; // skip non-svg files
697 gchar *basename = g_path_get_basename(file);
698 if (g_str_has_suffix(basename, ".svg") && g_str_has_prefix(basename, "default."))
699 continue; // skip default.*.svg (i.e. default.svg and translations) - it's in the menu already
701 gchar const *filepath = g_build_filename(dirname, file, NULL);
702 gchar *dupfile = g_strndup(file, strlen(file) - 4);
703 gchar *filename = g_filename_to_utf8(dupfile, -1, NULL, NULL, NULL);
704 g_free(dupfile);
705 GtkWidget *item = gtk_menu_item_new_with_label(filename);
706 g_free(filename);
708 gtk_widget_show(item);
709 // how does "filepath" ever get freed?
710 g_signal_connect(G_OBJECT(item),
711 "activate",
712 G_CALLBACK(sp_file_new_from_template),
713 (gpointer) filepath);
715 if (view) {
716 // set null tip for now; later use a description from the template file
717 g_object_set_data(G_OBJECT(item), "view", (gpointer) view);
718 g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select), (gpointer) NULL );
719 g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect), NULL);
720 }
722 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
723 }
724 g_dir_close(dir);
725 }
726 }
728 // toss the dirname
729 g_free(dirname);
730 sources.pop_front();
731 }
732 }
734 void
735 sp_menu_append_recent_documents(GtkWidget *menu, Inkscape::UI::View::View* /* view */)
736 {
737 gchar const **recent = prefs_get_recent_files();
738 if (recent) {
739 int i;
741 for (i = 0; recent[i] != NULL; i += 2) {
742 gchar const *uri = recent[i];
743 gchar const *name = recent[i + 1];
745 GtkWidget *item = gtk_menu_item_new_with_label(name);
746 gtk_widget_show(item);
747 g_signal_connect(G_OBJECT(item),
748 "activate",
749 G_CALLBACK(sp_recent_open),
750 (gpointer)uri);
751 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
752 }
754 g_free(recent);
755 } else {
756 GtkWidget *item = gtk_menu_item_new_with_label(_("None"));
757 gtk_widget_show(item);
758 gtk_widget_set_sensitive(item, FALSE);
759 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
760 }
761 }
763 void
764 sp_ui_checkboxes_menus(GtkMenu *m, Inkscape::UI::View::View *view)
765 {
766 //sp_ui_menu_append_check_item_from_verb(m, view, _("_Menu"), _("Show or hide the menu bar"), "menu",
767 // checkitem_toggled, checkitem_update, 0);
768 sp_ui_menu_append_check_item_from_verb(m, view, _("Commands Bar"), _("Show or hide the Commands bar (under the menu)"), "commands",
769 checkitem_toggled, checkitem_update, 0);
770 sp_ui_menu_append_check_item_from_verb(m, view, _("Tool Controls Bar"), _("Show or hide the Tool Controls bar"), "toppanel",
771 checkitem_toggled, checkitem_update, 0);
772 sp_ui_menu_append_check_item_from_verb(m, view, _("_Toolbox"), _("Show or hide the main toolbox (on the left)"), "toolbox",
773 checkitem_toggled, checkitem_update, 0);
774 sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "rulers",
775 checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_RULERS));
776 sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "scrollbars",
777 checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_SCROLLBARS));
778 sp_ui_menu_append_check_item_from_verb(m, view, _("_Palette"), _("Show or hide the color palette"), "panels",
779 checkitem_toggled, checkitem_update, 0);
780 sp_ui_menu_append_check_item_from_verb(m, view, _("_Statusbar"), _("Show or hide the statusbar (at the bottom of the window)"), "statusbar",
781 checkitem_toggled, checkitem_update, 0);
782 }
784 /** \brief This function turns XML into a menu
785 \param menus This is the XML that defines the menu
786 \param menu Menu to be added to
787 \param view The View that this menu is being built for
789 This function is realitively simple as it just goes through the XML
790 and parses the individual elements. In the case of a submenu, it
791 just calls itself recursively. Because it is only reasonable to have
792 a couple of submenus, it is unlikely this will go more than two or
793 three times.
795 In the case of an unreconginzed verb, a menu item is made to identify
796 the verb that is missing, and display that. The menu item is also made
797 insensitive.
798 */
799 void
800 sp_ui_build_dyn_menus(Inkscape::XML::Node *menus, GtkWidget *menu, Inkscape::UI::View::View *view)
801 {
802 if (menus == NULL) return;
803 if (menu == NULL) return;
804 GSList *group = NULL;
806 for (Inkscape::XML::Node *menu_pntr = menus;
807 menu_pntr != NULL;
808 menu_pntr = menu_pntr->next()) {
809 if (!strcmp(menu_pntr->name(), "submenu")) {
810 GtkWidget *mitem = gtk_menu_item_new_with_mnemonic(_(menu_pntr->attribute("name")));
811 GtkWidget *submenu = gtk_menu_new();
812 sp_ui_build_dyn_menus(menu_pntr->firstChild(), submenu, view);
813 gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), GTK_WIDGET(submenu));
814 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
815 continue;
816 }
817 if (!strcmp(menu_pntr->name(), "verb")) {
818 gchar const *verb_name = menu_pntr->attribute("verb-id");
819 Inkscape::Verb *verb = Inkscape::Verb::getbyid(verb_name);
821 if (verb != NULL) {
822 if (menu_pntr->attribute("radio") != NULL) {
823 GtkWidget *item = sp_ui_menu_append_item_from_verb (GTK_MENU(menu), verb, view, true, group);
824 group = gtk_radio_menu_item_get_group( GTK_RADIO_MENU_ITEM(item));
825 if (menu_pntr->attribute("default") != NULL) {
826 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);
827 }
828 } else {
829 sp_ui_menu_append_item_from_verb(GTK_MENU(menu), verb, view);
830 group = NULL;
831 }
832 } else {
833 gchar string[120];
834 g_snprintf(string, 120, _("Verb \"%s\" Unknown"), verb_name);
835 string[119] = '\0'; /* may not be terminated */
836 GtkWidget *item = gtk_menu_item_new_with_label(string);
837 gtk_widget_set_sensitive(item, false);
838 gtk_widget_show(item);
839 gtk_menu_append(GTK_MENU(menu), item);
840 }
841 continue;
842 }
843 if (!strcmp(menu_pntr->name(), "separator")
844 // This was spelt wrong in the original version
845 // and so this is for backward compatibility. It can
846 // probably be dropped after the 0.44 release.
847 || !strcmp(menu_pntr->name(), "seperator")) {
848 GtkWidget *item = gtk_separator_menu_item_new();
849 gtk_widget_show(item);
850 gtk_menu_append(GTK_MENU(menu), item);
851 continue;
852 }
853 if (!strcmp(menu_pntr->name(), "template-list")) {
854 sp_menu_append_new_templates(menu, view);
855 continue;
856 }
857 if (!strcmp(menu_pntr->name(), "recent-file-list")) {
858 sp_menu_append_recent_documents(menu, view);
859 continue;
860 }
861 if (!strcmp(menu_pntr->name(), "objects-checkboxes")) {
862 sp_ui_checkboxes_menus(GTK_MENU(menu), view);
863 continue;
864 }
865 }
866 }
868 /** \brief Build the main tool bar
869 \param view View to build the bar for
871 Currently the main tool bar is built as a dynamic XML menu using
872 \c sp_ui_build_dyn_menus. This function builds the bar, and then
873 pass it to get items attached to it.
874 */
875 GtkWidget *
876 sp_ui_main_menubar(Inkscape::UI::View::View *view)
877 {
878 GtkWidget *mbar = gtk_menu_bar_new();
880 sp_ui_build_dyn_menus(inkscape_get_menus(INKSCAPE), mbar, view);
882 return mbar;
883 }
885 static void leave_group(GtkMenuItem *, SPDesktop *desktop) {
886 desktop->setCurrentLayer(SP_OBJECT_PARENT(desktop->currentLayer()));
887 }
889 static void enter_group(GtkMenuItem *mi, SPDesktop *desktop) {
890 desktop->setCurrentLayer(reinterpret_cast<SPObject *>(g_object_get_data(G_OBJECT(mi), "group")));
891 sp_desktop_selection(desktop)->clear();
892 }
894 GtkWidget *
895 sp_ui_context_menu(Inkscape::UI::View::View *view, SPItem *item)
896 {
897 GtkWidget *m;
898 SPDesktop *dt;
900 dt = static_cast<SPDesktop*>(view);
902 m = gtk_menu_new();
904 /* Undo and Redo */
905 sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_UNDO), view);
906 sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_REDO), view);
908 /* Separator */
909 sp_ui_menu_append_item(GTK_MENU(m), NULL, NULL, NULL, NULL, NULL, NULL);
911 sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_CUT), view);
912 sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_COPY), view);
913 sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_PASTE), view);
915 /* Separator */
916 sp_ui_menu_append_item(GTK_MENU(m), NULL, NULL, NULL, NULL, NULL, NULL);
918 sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_DUPLICATE), view);
919 sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_DELETE), view);
921 /* Item menu */
922 if (item) {
923 sp_ui_menu_append_item(GTK_MENU(m), NULL, NULL, NULL, NULL, NULL, NULL);
924 sp_object_menu((SPObject *) item, dt, GTK_MENU(m));
925 }
927 /* layer menu */
928 SPGroup *group=NULL;
929 if (item) {
930 if (SP_IS_GROUP(item)) {
931 group = SP_GROUP(item);
932 } else if ( item != dt->currentRoot() && SP_IS_GROUP(SP_OBJECT_PARENT(item)) ) {
933 group = SP_GROUP(SP_OBJECT_PARENT(item));
934 }
935 }
937 if (( group && group != dt->currentLayer() ) ||
938 ( dt->currentLayer() != dt->currentRoot() ) ) {
939 sp_ui_menu_append_item(GTK_MENU(m), NULL, NULL, NULL, NULL, NULL, NULL);
940 }
942 if ( group && group != dt->currentLayer() ) {
943 /* TRANSLATORS: #%s is the id of the group e.g. <g id="#g7">, not a number. */
944 gchar *label=g_strdup_printf(_("Enter group #%s"), SP_OBJECT_ID(group));
945 GtkWidget *w = gtk_menu_item_new_with_label(label);
946 g_free(label);
947 g_object_set_data(G_OBJECT(w), "group", group);
948 g_signal_connect(G_OBJECT(w), "activate", GCallback(enter_group), dt);
949 gtk_widget_show(w);
950 gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
951 }
953 if ( dt->currentLayer() != dt->currentRoot() ) {
954 if ( SP_OBJECT_PARENT(dt->currentLayer()) != dt->currentRoot() ) {
955 GtkWidget *w = gtk_menu_item_new_with_label(_("Go to parent"));
956 g_signal_connect(G_OBJECT(w), "activate", GCallback(leave_group), dt);
957 gtk_widget_show(w);
958 gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
960 }
961 }
963 return m;
964 }
966 /* Drag and Drop */
967 void
968 sp_ui_drag_data_received(GtkWidget *widget,
969 GdkDragContext *drag_context,
970 gint x, gint y,
971 GtkSelectionData *data,
972 guint info,
973 guint event_time,
974 gpointer user_data)
975 {
976 switch (info) {
977 #if ENABLE_MAGIC_COLORS
978 case APP_X_INKY_COLOR:
979 {
980 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
981 int destX = 0;
982 int destY = 0;
983 gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY );
984 NR::Point where( sp_canvas_window_to_world( desktop->canvas, NR::Point( destX, destY ) ) );
986 SPItem *item = desktop->item_at_point( where, true );
987 if ( item )
988 {
989 if ( data->length >= 8 ) {
990 cmsHPROFILE srgbProf = cmsCreate_sRGBProfile();
992 gchar c[64] = {0};
993 // Careful about endian issues.
994 guint16* dataVals = (guint16*)data->data;
995 sp_svg_write_color( c, 64,
996 SP_RGBA32_U_COMPOSE(
997 0x0ff & (dataVals[0] >> 8),
998 0x0ff & (dataVals[1] >> 8),
999 0x0ff & (dataVals[2] >> 8),
1000 0xff // can't have transparency in the color itself
1001 //0x0ff & (data->data[3] >> 8),
1002 ));
1003 SPCSSAttr *css = sp_repr_css_attr_new();
1004 bool updatePerformed = false;
1006 if ( data->length > 14 ) {
1007 int flags = dataVals[4];
1009 // piggie-backed palette entry info
1010 int index = dataVals[5];
1011 Glib::ustring palName;
1012 for ( int i = 0; i < dataVals[6]; i++ ) {
1013 palName += (gunichar)dataVals[7+i];
1014 }
1016 // Now hook in a magic tag of some sort.
1017 if ( !palName.empty() && (flags & 1) ) {
1018 gchar* str = g_strdup_printf("%d|", index);
1019 palName.insert( 0, str );
1020 g_free(str);
1021 str = 0;
1023 sp_object_setAttribute( SP_OBJECT(item),
1024 (drag_context->action != GDK_ACTION_MOVE) ? "inkscape:x-fill-tag":"inkscape:x-stroke-tag",
1025 palName.c_str(),
1026 false );
1027 item->updateRepr();
1029 sp_repr_css_set_property( css, (drag_context->action != GDK_ACTION_MOVE) ? "fill":"stroke", c );
1030 updatePerformed = true;
1031 }
1032 }
1034 if ( !updatePerformed ) {
1035 sp_repr_css_set_property( css, (drag_context->action != GDK_ACTION_MOVE) ? "fill":"stroke", c );
1036 }
1038 sp_desktop_apply_css_recursive( item, css, true );
1039 item->updateRepr();
1041 SPDocument *doc = SP_ACTIVE_DOCUMENT;
1042 sp_document_done( doc , SP_VERB_NONE,
1043 _("Drop color"));
1045 if ( srgbProf ) {
1046 cmsCloseProfile( srgbProf );
1047 }
1048 }
1049 }
1050 }
1051 break;
1052 #endif // ENABLE_MAGIC_COLORS
1054 case APP_X_COLOR:
1055 {
1056 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
1057 int destX = 0;
1058 int destY = 0;
1059 gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY );
1060 NR::Point where( sp_canvas_window_to_world( desktop->canvas, NR::Point( destX, destY ) ) );
1062 SPItem *item = desktop->item_at_point( where, true );
1063 if ( item )
1064 {
1065 if ( data->length == 8 ) {
1066 gchar c[64] = {0};
1067 // Careful about endian issues.
1068 guint16* dataVals = (guint16*)data->data;
1069 sp_svg_write_color( c, 64,
1070 SP_RGBA32_U_COMPOSE(
1071 0x0ff & (dataVals[0] >> 8),
1072 0x0ff & (dataVals[1] >> 8),
1073 0x0ff & (dataVals[2] >> 8),
1074 0xff // can't have transparency in the color itself
1075 //0x0ff & (data->data[3] >> 8),
1076 ));
1077 SPCSSAttr *css = sp_repr_css_attr_new();
1078 sp_repr_css_set_property( css, (drag_context->action != GDK_ACTION_MOVE) ? "fill":"stroke", c );
1080 sp_desktop_apply_css_recursive( item, css, true );
1081 item->updateRepr();
1083 SPDocument *doc = SP_ACTIVE_DOCUMENT;
1084 sp_document_done( doc , SP_VERB_NONE,
1085 _("Drop color"));
1086 }
1087 }
1088 }
1089 break;
1091 case SVG_DATA:
1092 case SVG_XML_DATA: {
1093 gchar *svgdata = (gchar *)data->data;
1095 SPDocument *doc = SP_ACTIVE_DOCUMENT;
1097 Inkscape::XML::Document *rnewdoc = sp_repr_read_mem(svgdata, data->length, SP_SVG_NS_URI);
1099 if (rnewdoc == NULL) {
1100 sp_ui_error_dialog(_("Could not parse SVG data"));
1101 return;
1102 }
1104 Inkscape::XML::Node *repr = sp_repr_document_root(rnewdoc);
1105 gchar const *style = repr->attribute("style");
1107 Inkscape::XML::Node *newgroup = sp_repr_new("svg:g");
1108 newgroup->setAttribute("style", style);
1110 for (Inkscape::XML::Node *child = repr->firstChild(); child != NULL; child = child->next()) {
1111 Inkscape::XML::Node *newchild = child->duplicate();
1112 newgroup->appendChild(newchild);
1113 }
1115 Inkscape::GC::release(rnewdoc);
1117 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
1118 // Add it to the current layer
1120 // Greg's edits to add intelligent positioning of svg drops
1121 SPObject *new_obj = NULL;
1122 new_obj = desktop->currentLayer()->appendChildRepr(newgroup);
1124 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1125 selection->set(SP_ITEM(new_obj));
1126 // To move the imported object, we must temporarily set the "transform pattern with
1127 // object" option.
1128 {
1129 int const saved_pref = prefs_get_int_attribute("options.transform", "pattern", 1);
1130 prefs_set_int_attribute("options.transform", "pattern", 1);
1131 sp_document_ensure_up_to_date(sp_desktop_document(desktop));
1132 NR::Point m( desktop->point() - selection->bounds().midpoint() );
1133 sp_selection_move_relative(selection, m);
1134 prefs_set_int_attribute("options.transform", "pattern", saved_pref);
1135 }
1137 Inkscape::GC::release(newgroup);
1138 sp_document_done(doc, SP_VERB_NONE,
1139 _("Drop SVG"));
1140 break;
1141 }
1143 case URI_LIST: {
1144 gchar *uri = (gchar *)data->data;
1145 sp_ui_import_files(uri);
1146 break;
1147 }
1149 case PNG_DATA:
1150 case JPEG_DATA:
1151 case IMAGE_DATA: {
1152 char tmp[1024];
1154 StringOutputStream outs;
1155 Base64OutputStream b64out(outs);
1156 b64out.setColumnWidth(0);
1158 SPDocument *doc = SP_ACTIVE_DOCUMENT;
1160 Inkscape::XML::Node *newImage = sp_repr_new("svg:image");
1162 for ( int i = 0; i < data->length; i++ ) {
1163 b64out.put( data->data[i] );
1164 }
1165 b64out.close();
1168 Glib::ustring str = outs.getString();
1170 snprintf( tmp, sizeof(tmp), "data:%s;base64,", gdk_atom_name(data->type) );
1171 str.insert( 0, tmp );
1172 newImage->setAttribute("xlink:href", str.c_str());
1174 GError *error = NULL;
1175 GdkPixbufLoader *loader = gdk_pixbuf_loader_new_with_mime_type( gdk_atom_name(data->type), &error );
1176 if ( loader ) {
1177 error = NULL;
1178 if ( gdk_pixbuf_loader_write( loader, data->data, data->length, &error) ) {
1179 GdkPixbuf *pbuf = gdk_pixbuf_loader_get_pixbuf(loader);
1180 if ( pbuf ) {
1181 int width = gdk_pixbuf_get_width(pbuf);
1182 int height = gdk_pixbuf_get_height(pbuf);
1183 snprintf( tmp, sizeof(tmp), "%d", width );
1184 newImage->setAttribute("width", tmp);
1186 snprintf( tmp, sizeof(tmp), "%d", height );
1187 newImage->setAttribute("height", tmp);
1188 }
1189 }
1190 }
1192 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
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, 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;
1257 GtkWidget *dialog;
1258 GtkWidget *hbox;
1259 GtkWidget *boxdata;
1260 gchar *title;
1261 gchar *text;
1263 if (Inkscape::IO::file_test(filename, G_FILE_TEST_EXISTS)) {
1265 title = g_strdup_printf(_("Overwrite %s"), filename);
1266 dialog = gtk_dialog_new_with_buttons(title,
1267 NULL,
1268 (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
1269 GTK_STOCK_NO,
1270 GTK_RESPONSE_NO,
1271 GTK_STOCK_YES,
1272 GTK_RESPONSE_YES,
1273 NULL);
1274 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_YES);
1276 sp_transientize(dialog);
1277 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
1279 hbox = gtk_hbox_new(FALSE, 5);
1281 // TODO - replace with Inkscape-specific call
1282 boxdata = gtk_image_new_from_stock(GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG);
1284 gtk_widget_show(boxdata);
1285 gtk_box_pack_start(GTK_BOX(hbox), boxdata, TRUE, TRUE, 5);
1286 text = g_strdup_printf(_("The file %s already exists. Do you want to overwrite that file with the current document?"), filename);
1287 boxdata = gtk_label_new(text);
1288 gtk_label_set_line_wrap(GTK_LABEL(boxdata), TRUE);
1289 gtk_widget_show(boxdata);
1290 gtk_box_pack_start(GTK_BOX(hbox), boxdata, FALSE, FALSE, 5);
1291 gtk_widget_show(hbox);
1292 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, TRUE, TRUE, 5);
1294 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES) {
1295 return_value = TRUE;
1296 } else {
1297 return_value = FALSE;
1298 }
1300 gtk_widget_destroy(dialog);
1301 g_free(title);
1302 g_free(text);
1303 } else {
1304 return_value = TRUE;
1305 }
1307 return return_value;
1308 }
1310 static void
1311 sp_ui_menu_item_set_sensitive(SPAction *action, unsigned int sensitive, void *data)
1312 {
1313 return gtk_widget_set_sensitive(GTK_WIDGET(data), sensitive);
1314 }
1316 static void
1317 sp_ui_menu_item_set_name(SPAction *action, Glib::ustring name, void *data)
1318 {
1319 gtk_label_set_markup_with_mnemonic(
1320 GTK_LABEL (gtk_container_get_children(GTK_CONTAINER (GTK_BIN (data)->child))->data),
1321 name.c_str());
1322 }
1325 /*
1326 Local Variables:
1327 mode:c++
1328 c-file-style:"stroustrup"
1329 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1330 indent-tabs-mode:nil
1331 fill-column:99
1332 End:
1333 */
1334 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :