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