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