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 "object-ui.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 #include "display/sp-canvas.h"
58 #include "color.h"
59 #include "svg/svg-color.h"
60 #include "desktop-style.h"
61 #include "style.h"
64 using Inkscape::IO::StringOutputStream;
65 using Inkscape::IO::Base64OutputStream;
67 /* forward declaration */
68 static gint sp_ui_delete(GtkWidget *widget, GdkEvent *event, Inkscape::UI::View::View *view);
70 /* Drag and Drop */
71 typedef enum {
72 URI_LIST,
73 SVG_XML_DATA,
74 SVG_DATA,
75 PNG_DATA,
76 JPEG_DATA,
77 IMAGE_DATA,
78 APP_X_INKY_COLOR,
79 APP_X_COLOR
80 } ui_drop_target_info;
82 static GtkTargetEntry ui_drop_target_entries [] = {
83 {"text/uri-list", 0, URI_LIST},
84 {"image/svg+xml", 0, SVG_XML_DATA},
85 {"image/svg", 0, SVG_DATA},
86 {"image/png", 0, PNG_DATA},
87 {"image/jpeg", 0, JPEG_DATA},
88 {"application/x-inkscape-color", 0, APP_X_INKY_COLOR},
89 {"application/x-color", 0, APP_X_COLOR}
90 };
92 static GtkTargetEntry *completeDropTargets = 0;
93 static int completeDropTargetsCount = 0;
95 #define ENTRIES_SIZE(n) sizeof(n)/sizeof(n[0])
96 static guint nui_drop_target_entries = ENTRIES_SIZE(ui_drop_target_entries);
97 static void sp_ui_import_files(gchar *buffer);
98 static void sp_ui_import_one_file(char const *filename);
99 static void sp_ui_import_one_file_with_check(gpointer filename, gpointer unused);
100 static void sp_ui_drag_data_received(GtkWidget *widget,
101 GdkDragContext *drag_context,
102 gint x, gint y,
103 GtkSelectionData *data,
104 guint info,
105 guint event_time,
106 gpointer user_data);
107 static void sp_ui_menu_item_set_sensitive(SPAction *action,
108 unsigned int sensitive,
109 void *data);
111 SPActionEventVector menu_item_event_vector = {
112 {NULL},
113 NULL,
114 NULL, /* set_active */
115 sp_ui_menu_item_set_sensitive, /* set_sensitive */
116 NULL /* set_shortcut */
117 };
119 void
120 sp_create_window(SPViewWidget *vw, gboolean editable)
121 {
122 GtkWidget *w, *hb;
124 g_return_if_fail(vw != NULL);
125 g_return_if_fail(SP_IS_VIEW_WIDGET(vw));
127 w = sp_window_new("", TRUE);
129 if (editable) {
130 g_object_set_data(G_OBJECT(vw), "window", w);
131 reinterpret_cast<SPDesktopWidget*>(vw)->window =
132 static_cast<GtkWindow*>((void*)w);
133 }
135 hb = gtk_hbox_new(FALSE, 0);
136 gtk_widget_show(hb);
137 gtk_container_add(GTK_CONTAINER(w), hb);
138 g_object_set_data(G_OBJECT(w), "hbox", hb);
140 /* fixme: */
141 if (editable) {
142 gtk_window_set_default_size((GtkWindow *) w, 640, 480);
143 g_object_set_data(G_OBJECT(w), "desktop", SP_DESKTOP_WIDGET(vw)->desktop);
144 g_object_set_data(G_OBJECT(w), "desktopwidget", vw);
145 g_signal_connect(G_OBJECT(w), "delete_event", G_CALLBACK(sp_ui_delete), vw->view);
146 g_signal_connect(G_OBJECT(w), "focus_in_event", G_CALLBACK(sp_desktop_widget_set_focus), vw);
147 } else {
148 gtk_window_set_policy(GTK_WINDOW(w), TRUE, TRUE, TRUE);
149 }
151 gtk_box_pack_end(GTK_BOX(hb), GTK_WIDGET(vw), TRUE, TRUE, 0);
152 gtk_widget_show(GTK_WIDGET(vw));
155 if ( completeDropTargets == 0 || completeDropTargetsCount == 0 )
156 {
157 std::vector<gchar*> types;
159 GSList *list = gdk_pixbuf_get_formats();
160 while ( list ) {
161 int i = 0;
162 GdkPixbufFormat *one = (GdkPixbufFormat*)list->data;
163 gchar** typesXX = gdk_pixbuf_format_get_mime_types(one);
164 for ( i = 0; typesXX[i]; i++ ) {
165 types.push_back(g_strdup(typesXX[i]));
166 }
167 g_strfreev(typesXX);
169 list = g_slist_next(list);
170 }
171 completeDropTargetsCount = nui_drop_target_entries + types.size();
172 completeDropTargets = new GtkTargetEntry[completeDropTargetsCount];
173 for ( int i = 0; i < (int)nui_drop_target_entries; i++ ) {
174 completeDropTargets[i] = ui_drop_target_entries[i];
175 }
176 int pos = nui_drop_target_entries;
178 for (std::vector<gchar*>::iterator it = types.begin() ; it != types.end() ; it++) {
179 completeDropTargets[pos].target = *it;
180 completeDropTargets[pos].flags = 0;
181 completeDropTargets[pos].info = IMAGE_DATA;
182 pos++;
183 }
184 }
186 gtk_drag_dest_set(w,
187 GTK_DEST_DEFAULT_ALL,
188 completeDropTargets,
189 completeDropTargetsCount,
190 GdkDragAction(GDK_ACTION_COPY | GDK_ACTION_MOVE));
191 g_signal_connect(G_OBJECT(w),
192 "drag_data_received",
193 G_CALLBACK(sp_ui_drag_data_received),
194 NULL);
195 gtk_widget_show(w);
197 // needed because the first ACTIVATE_DESKTOP was sent when there was no window yet
198 inkscape_reactivate_desktop(SP_DESKTOP_WIDGET(vw)->desktop);
199 }
201 void
202 sp_ui_new_view()
203 {
204 SPDocument *document;
205 SPViewWidget *dtw;
207 document = SP_ACTIVE_DOCUMENT;
208 if (!document) return;
210 dtw = sp_desktop_widget_new(sp_document_namedview(document, NULL));
211 g_return_if_fail(dtw != NULL);
213 sp_create_window(dtw, TRUE);
214 sp_namedview_window_from_document(static_cast<SPDesktop*>(dtw->view));
215 }
217 /* TODO: not yet working */
218 /* To be re-enabled (by adding to menu) once it works. */
219 void
220 sp_ui_new_view_preview()
221 {
222 SPDocument *document;
223 SPViewWidget *dtw;
225 document = SP_ACTIVE_DOCUMENT;
226 if (!document) return;
228 dtw = (SPViewWidget *) sp_svg_view_widget_new(document);
229 g_return_if_fail(dtw != NULL);
230 sp_svg_view_widget_set_resize(SP_SVG_VIEW_WIDGET(dtw), TRUE, 400.0, 400.0);
232 sp_create_window(dtw, FALSE);
233 }
235 /**
236 * \param widget unused
237 */
238 void
239 sp_ui_close_view(GtkWidget *widget)
240 {
241 if (SP_ACTIVE_DESKTOP == NULL) {
242 return;
243 }
244 if ((SP_ACTIVE_DESKTOP)->shutdown()) {
245 return;
246 }
247 SP_ACTIVE_DESKTOP->destroyWidget();
248 }
251 /**
252 * sp_ui_close_all
253 *
254 * This function is called to exit the program, and iterates through all
255 * open document view windows, attempting to close each in turn. If the
256 * view has unsaved information, the user will be prompted to save,
257 * discard, or cancel.
258 *
259 * Returns FALSE if the user cancels the close_all operation, TRUE
260 * otherwise.
261 */
262 unsigned int
263 sp_ui_close_all(void)
264 {
265 /* Iterate through all the windows, destroying each in the order they
266 become active */
267 while (SP_ACTIVE_DESKTOP) {
268 if ((SP_ACTIVE_DESKTOP)->shutdown()) {
269 /* The user cancelled the operation, so end doing the close */
270 return FALSE;
271 }
272 SP_ACTIVE_DESKTOP->destroyWidget();
273 }
275 return TRUE;
276 }
278 static gint
279 sp_ui_delete(GtkWidget *widget, GdkEvent *event, Inkscape::UI::View::View *view)
280 {
281 return view->shutdown();
282 }
284 /*
285 * Some day when the right-click menus are ready to start working
286 * smarter with the verbs, we'll need to change this NULL being
287 * sent to sp_action_perform to something useful, or set some kind
288 * of global "right-clicked position" variable for actions to
289 * investigate when they're called.
290 */
291 static void
292 sp_ui_menu_activate(void *object, SPAction *action)
293 {
294 sp_action_perform(action, NULL);
295 }
297 static void
298 sp_ui_menu_select_action(void *object, SPAction *action)
299 {
300 action->view->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, action->tip);
301 }
303 static void
304 sp_ui_menu_deselect_action(void *object, SPAction *action)
305 {
306 action->view->tipsMessageContext()->clear();
307 }
309 static void
310 sp_ui_menu_select(gpointer object, gpointer tip)
311 {
312 Inkscape::UI::View::View *view = static_cast<Inkscape::UI::View::View*> (g_object_get_data(G_OBJECT(object), "view"));
313 view->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, (gchar *)tip);
314 }
316 static void
317 sp_ui_menu_deselect(gpointer object)
318 {
319 Inkscape::UI::View::View *view = static_cast<Inkscape::UI::View::View*> (g_object_get_data(G_OBJECT(object), "view"));
320 view->tipsMessageContext()->clear();
321 }
323 /**
324 * sp_ui_menuitem_add_icon
325 *
326 * Creates and attaches a scaled icon to the given menu item.
327 *
328 */
329 void
330 sp_ui_menuitem_add_icon( GtkWidget *item, gchar *icon_name )
331 {
332 GtkWidget *icon;
334 icon = sp_icon_new( GTK_ICON_SIZE_MENU, icon_name );
335 gtk_widget_show(icon);
336 gtk_image_menu_item_set_image((GtkImageMenuItem *) item, icon);
337 } // end of sp_ui_menu_add_icon
339 /**
340 * sp_ui_menu_append_item
341 *
342 * Appends a UI item with specific info for Inkscape/Sodipodi.
343 *
344 */
345 static GtkWidget *
346 sp_ui_menu_append_item( GtkMenu *menu, gchar const *stock,
347 gchar const *label, gchar const *tip, Inkscape::UI::View::View *view, GCallback callback,
348 gpointer data, gboolean with_mnemonic = TRUE )
349 {
350 GtkWidget *item;
352 if (stock) {
353 item = gtk_image_menu_item_new_from_stock(stock, NULL);
354 } else if (label) {
355 item = (with_mnemonic)
356 ? gtk_image_menu_item_new_with_mnemonic(label) :
357 gtk_image_menu_item_new_with_label(label);
358 } else {
359 item = gtk_separator_menu_item_new();
360 }
362 gtk_widget_show(item);
364 if (callback) {
365 g_signal_connect(G_OBJECT(item), "activate", callback, data);
366 }
368 if (tip && view) {
369 g_object_set_data(G_OBJECT(item), "view", (gpointer) view);
370 g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select), (gpointer) tip );
371 g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect), NULL);
372 }
374 gtk_menu_append(GTK_MENU(menu), item);
376 return item;
378 } // end of sp_ui_menu_append_item()
380 /**
381 \brief a wrapper around gdk_keyval_name producing (when possible) characters, not names
382 */
383 static gchar const *
384 sp_key_name(guint keyval)
385 {
386 /* TODO: Compare with the definition of gtk_accel_label_refetch in gtk/gtkaccellabel.c (or
387 simply use GtkAccelLabel as the TODO comment in sp_ui_shortcut_string suggests). */
388 gchar const *n = gdk_keyval_name(gdk_keyval_to_upper(keyval));
390 if (!strcmp(n, "asciicircum")) return "^";
391 else if (!strcmp(n, "parenleft" )) return "(";
392 else if (!strcmp(n, "parenright" )) return ")";
393 else if (!strcmp(n, "plus" )) return "+";
394 else if (!strcmp(n, "minus" )) return "-";
395 else if (!strcmp(n, "asterisk" )) return "*";
396 else if (!strcmp(n, "KP_Multiply")) return "*";
397 else if (!strcmp(n, "Delete" )) return "Del";
398 else if (!strcmp(n, "Page_Up" )) return "PgUp";
399 else if (!strcmp(n, "Page_Down" )) return "PgDn";
400 else if (!strcmp(n, "grave" )) return "`";
401 else if (!strcmp(n, "numbersign" )) return "#";
402 else if (!strcmp(n, "bar" )) return "|";
403 else if (!strcmp(n, "slash" )) return "/";
404 else if (!strcmp(n, "exclam" )) return "!";
405 else return n;
406 }
409 /**
410 * \param shortcut A GDK keyval OR'd with SP_SHORTCUT_blah_MASK values.
411 * \param c Points to a buffer at least 256 bytes long.
412 */
413 void
414 sp_ui_shortcut_string(unsigned const shortcut, gchar *const c)
415 {
416 /* TODO: This function shouldn't exist. Our callers should use GtkAccelLabel instead of
417 * a generic GtkLabel containing this string, and should call gtk_widget_add_accelerator.
418 * Will probably need to change sp_shortcut_invoke callers.
419 *
420 * The existing gtk_label_new_with_mnemonic call can be replaced with
421 * g_object_new(GTK_TYPE_ACCEL_LABEL, NULL) followed by
422 * gtk_label_set_text_with_mnemonic(lbl, str).
423 */
424 static GtkAccelLabelClass const &accel_lbl_cls
425 = *(GtkAccelLabelClass const *) g_type_class_peek_static(GTK_TYPE_ACCEL_LABEL);
427 struct { unsigned test; char const *name; } const modifier_tbl[] = {
428 { SP_SHORTCUT_SHIFT_MASK, accel_lbl_cls.mod_name_shift },
429 { SP_SHORTCUT_CONTROL_MASK, accel_lbl_cls.mod_name_control },
430 { SP_SHORTCUT_ALT_MASK, accel_lbl_cls.mod_name_alt }
431 };
433 gchar *p = c;
434 gchar *end = p + 256;
436 for (unsigned i = 0; i < G_N_ELEMENTS(modifier_tbl); ++i) {
437 if ((shortcut & modifier_tbl[i].test)
438 && (p < end))
439 {
440 p += g_snprintf(p, end - p, "%s%s",
441 modifier_tbl[i].name,
442 accel_lbl_cls.mod_separator);
443 }
444 }
445 if (p < end) {
446 p += g_snprintf(p, end - p, "%s", sp_key_name(shortcut & 0xffffff));
447 }
448 end[-1] = '\0'; // snprintf doesn't guarantee to nul-terminate the string.
449 }
451 void
452 sp_ui_dialog_title_string(Inkscape::Verb *verb, gchar *c)
453 {
454 SPAction *action;
455 unsigned int shortcut;
456 gchar *s;
457 gchar key[256];
458 gchar *atitle;
460 action = verb->get_action(NULL);
461 if (!action)
462 return;
464 atitle = sp_action_get_title(action);
466 s = g_stpcpy(c, atitle);
468 g_free(atitle);
470 shortcut = sp_shortcut_get_primary(verb);
471 if (shortcut) {
472 s = g_stpcpy(s, " (");
473 sp_ui_shortcut_string(shortcut, key);
474 s = g_stpcpy(s, key);
475 s = g_stpcpy(s, ")");
476 }
477 }
480 /**
481 * sp_ui_menu_append_item_from_verb
482 *
483 * Appends a custom menu UI from a verb.
484 *
485 */
487 static GtkWidget *
488 sp_ui_menu_append_item_from_verb(GtkMenu *menu, Inkscape::Verb *verb, Inkscape::UI::View::View *view, bool radio = false, GSList *group = NULL)
489 {
490 SPAction *action;
491 GtkWidget *item;
493 if (verb->get_code() == SP_VERB_NONE) {
495 item = gtk_separator_menu_item_new();
497 } else {
498 unsigned int shortcut;
500 action = verb->get_action(view);
502 if (!action) return NULL;
504 shortcut = sp_shortcut_get_primary(verb);
505 if (shortcut) {
506 gchar c[256];
507 sp_ui_shortcut_string(shortcut, c);
508 GtkWidget *const hb = gtk_hbox_new(FALSE, 16);
509 GtkWidget *const name_lbl = gtk_label_new("");
510 gtk_label_set_markup_with_mnemonic(GTK_LABEL(name_lbl), action->name);
511 gtk_misc_set_alignment((GtkMisc *) name_lbl, 0.0, 0.5);
512 gtk_box_pack_start((GtkBox *) hb, name_lbl, TRUE, TRUE, 0);
513 GtkWidget *const accel_lbl = gtk_label_new(c);
514 gtk_misc_set_alignment((GtkMisc *) accel_lbl, 1.0, 0.5);
515 gtk_box_pack_end((GtkBox *) hb, accel_lbl, FALSE, FALSE, 0);
516 gtk_widget_show_all(hb);
517 if (radio) {
518 item = gtk_radio_menu_item_new (group);
519 } else {
520 item = gtk_image_menu_item_new();
521 }
522 gtk_container_add((GtkContainer *) item, hb);
523 } else {
524 if (radio) {
525 item = gtk_radio_menu_item_new (group);
526 } else {
527 item = gtk_image_menu_item_new ();
528 }
529 GtkWidget *const name_lbl = gtk_label_new("");
530 gtk_label_set_markup_with_mnemonic(GTK_LABEL(name_lbl), action->name);
531 gtk_misc_set_alignment((GtkMisc *) name_lbl, 0.0, 0.5);
532 gtk_container_add((GtkContainer *) item, name_lbl);
533 }
535 nr_active_object_add_listener((NRActiveObject *)action, (NRObjectEventVector *)&menu_item_event_vector, sizeof(SPActionEventVector), item);
536 if (!action->sensitive) {
537 gtk_widget_set_sensitive(item, FALSE);
538 }
540 if (action->image) {
541 sp_ui_menuitem_add_icon(item, action->image);
542 }
543 gtk_widget_set_events(item, GDK_KEY_PRESS_MASK);
544 g_signal_connect( G_OBJECT(item), "activate",
545 G_CALLBACK(sp_ui_menu_activate), action );
547 g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select_action), action );
548 g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect_action), action );
549 }
551 gtk_widget_show(item);
552 gtk_menu_append(GTK_MENU(menu), item);
554 return item;
556 } // end of sp_ui_menu_append_item_from_verb
559 static void
560 checkitem_toggled(GtkCheckMenuItem *menuitem, gpointer user_data)
561 {
562 gchar const *pref = (gchar const *) user_data;
563 Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view");
565 gchar const *pref_path;
566 if (reinterpret_cast<SPDesktop*>(view)->is_fullscreen)
567 pref_path = g_strconcat("fullscreen.", pref, NULL);
568 else
569 pref_path = g_strconcat("window.", pref, NULL);
571 gboolean checked = gtk_check_menu_item_get_active(menuitem);
572 prefs_set_int_attribute(pref_path, "state", checked);
574 reinterpret_cast<SPDesktop*>(view)->layoutWidget();
575 }
577 static gboolean
578 checkitem_update(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
579 {
580 GtkCheckMenuItem *menuitem=GTK_CHECK_MENU_ITEM(widget);
582 gchar const *pref = (gchar const *) user_data;
583 Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view");
585 gchar const *pref_path;
586 if (static_cast<SPDesktop*>(view)->is_fullscreen)
587 pref_path = g_strconcat("fullscreen.", pref, NULL);
588 else
589 pref_path = g_strconcat("window.", pref, NULL);
591 gint ison = prefs_get_int_attribute_limited(pref_path, "state", 1, 0, 1);
593 g_signal_handlers_block_by_func(G_OBJECT(menuitem), (gpointer)(GCallback)checkitem_toggled, user_data);
594 gtk_check_menu_item_set_active(menuitem, ison);
595 g_signal_handlers_unblock_by_func(G_OBJECT(menuitem), (gpointer)(GCallback)checkitem_toggled, user_data);
597 return FALSE;
598 }
601 void
602 sp_ui_menu_append_check_item_from_verb(GtkMenu *menu, Inkscape::UI::View::View *view, gchar const *label, gchar const *tip, gchar const *pref,
603 void (*callback_toggle)(GtkCheckMenuItem *, gpointer user_data),
604 gboolean (*callback_update)(GtkWidget *widget, GdkEventExpose *event, gpointer user_data),
605 Inkscape::Verb *verb)
606 {
607 GtkWidget *item;
609 unsigned int shortcut = 0;
610 SPAction *action = NULL;
612 if (verb) {
613 shortcut = sp_shortcut_get_primary(verb);
614 action = verb->get_action(view);
615 }
617 if (verb && shortcut) {
618 gchar c[256];
619 sp_ui_shortcut_string(shortcut, c);
621 GtkWidget *hb = gtk_hbox_new(FALSE, 16);
623 {
624 GtkWidget *l = gtk_label_new_with_mnemonic(action ? action->name : label);
625 gtk_misc_set_alignment((GtkMisc *) l, 0.0, 0.5);
626 gtk_box_pack_start((GtkBox *) hb, l, TRUE, TRUE, 0);
627 }
629 {
630 GtkWidget *l = gtk_label_new(c);
631 gtk_misc_set_alignment((GtkMisc *) l, 1.0, 0.5);
632 gtk_box_pack_end((GtkBox *) hb, l, FALSE, FALSE, 0);
633 }
635 gtk_widget_show_all(hb);
637 item = gtk_check_menu_item_new();
638 gtk_container_add((GtkContainer *) item, hb);
639 } else {
640 GtkWidget *l = gtk_label_new_with_mnemonic(action ? action->name : label);
641 gtk_misc_set_alignment((GtkMisc *) l, 0.0, 0.5);
642 item = gtk_check_menu_item_new();
643 gtk_container_add((GtkContainer *) item, l);
644 }
645 #if 0
646 nr_active_object_add_listener((NRActiveObject *)action, (NRObjectEventVector *)&menu_item_event_vector, sizeof(SPActionEventVector), item);
647 if (!action->sensitive) {
648 gtk_widget_set_sensitive(item, FALSE);
649 }
650 #endif
651 gtk_widget_show(item);
653 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
655 g_object_set_data(G_OBJECT(item), "view", (gpointer) view);
657 g_signal_connect( G_OBJECT(item), "toggled", (GCallback) callback_toggle, (void *) pref);
658 g_signal_connect( G_OBJECT(item), "expose_event", (GCallback) callback_update, (void *) pref);
660 g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select), (gpointer) (action ? action->tip : tip));
661 g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect), NULL);
662 }
664 static void
665 sp_recent_open(GtkWidget *widget, gchar const *uri)
666 {
667 sp_file_open(uri, NULL);
668 }
670 static void
671 sp_file_new_from_template(GtkWidget *widget, gchar const *uri)
672 {
673 sp_file_new(uri);
674 }
676 void
677 sp_menu_append_new_templates(GtkWidget *menu, Inkscape::UI::View::View *view)
678 {
679 std::list<gchar *> sources;
680 sources.push_back( profile_path("templates") ); // first try user's local dir
681 sources.push_back( g_strdup(INKSCAPE_TEMPLATESDIR) ); // then the system templates dir
683 // Use this loop to iterate through a list of possible document locations.
684 while (!sources.empty()) {
685 gchar *dirname = sources.front();
687 if ( Inkscape::IO::file_test( dirname, (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR) ) ) {
688 GError *err = 0;
689 GDir *dir = g_dir_open(dirname, 0, &err);
691 if (dir) {
692 for (gchar const *file = g_dir_read_name(dir); file != NULL; file = g_dir_read_name(dir)) {
693 if (!g_str_has_suffix(file, ".svg"))
694 continue; // skip non-svg files
696 gchar *basename = g_path_get_basename(file);
697 if (g_str_has_suffix(basename, ".svg") && g_str_has_prefix(basename, "default."))
698 continue; // skip default.*.svg (i.e. default.svg and translations) - it's in the menu already
700 gchar const *filepath = g_build_filename(dirname, file, NULL);
701 gchar *dupfile = g_strndup(file, strlen(file) - 4);
702 gchar *filename = g_filename_to_utf8(dupfile, -1, NULL, NULL, NULL);
703 g_free(dupfile);
704 GtkWidget *item = gtk_menu_item_new_with_label(filename);
705 g_free(filename);
707 gtk_widget_show(item);
708 // how does "filepath" ever get freed?
709 g_signal_connect(G_OBJECT(item),
710 "activate",
711 G_CALLBACK(sp_file_new_from_template),
712 (gpointer) filepath);
714 if (view) {
715 // set null tip for now; later use a description from the template file
716 g_object_set_data(G_OBJECT(item), "view", (gpointer) view);
717 g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select), (gpointer) NULL );
718 g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect), NULL);
719 }
721 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
722 }
723 g_dir_close(dir);
724 }
725 }
727 // toss the dirname
728 g_free(dirname);
729 sources.pop_front();
730 }
731 }
733 void
734 sp_menu_append_recent_documents(GtkWidget *menu, Inkscape::UI::View::View* /* view */)
735 {
736 gchar const **recent = prefs_get_recent_files();
737 if (recent) {
738 int i;
740 for (i = 0; recent[i] != NULL; i += 2) {
741 gchar const *uri = recent[i];
742 gchar const *name = recent[i + 1];
744 GtkWidget *item = gtk_menu_item_new_with_label(name);
745 gtk_widget_show(item);
746 g_signal_connect(G_OBJECT(item),
747 "activate",
748 G_CALLBACK(sp_recent_open),
749 (gpointer)uri);
750 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
751 }
753 g_free(recent);
754 } else {
755 GtkWidget *item = gtk_menu_item_new_with_label(_("None"));
756 gtk_widget_show(item);
757 gtk_widget_set_sensitive(item, FALSE);
758 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
759 }
760 }
762 void
763 sp_ui_checkboxes_menus(GtkMenu *m, Inkscape::UI::View::View *view)
764 {
765 //sp_ui_menu_append_check_item_from_verb(m, view, _("_Menu"), _("Show or hide the menu bar"), "menu",
766 // checkitem_toggled, checkitem_update, 0);
767 sp_ui_menu_append_check_item_from_verb(m, view, _("Commands Bar"), _("Show or hide the Commands bar (under the menu)"), "commands",
768 checkitem_toggled, checkitem_update, 0);
769 sp_ui_menu_append_check_item_from_verb(m, view, _("Tool Controls Bar"), _("Show or hide the Tool Controls bar"), "toppanel",
770 checkitem_toggled, checkitem_update, 0);
771 sp_ui_menu_append_check_item_from_verb(m, view, _("_Toolbox"), _("Show or hide the main toolbox (on the left)"), "toolbox",
772 checkitem_toggled, checkitem_update, 0);
773 sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "rulers",
774 checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_RULERS));
775 sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "scrollbars",
776 checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_SCROLLBARS));
777 sp_ui_menu_append_check_item_from_verb(m, view, _("_Statusbar"), _("Show or hide the statusbar (at the bottom of the window)"), "statusbar",
778 checkitem_toggled, checkitem_update, 0);
779 sp_ui_menu_append_check_item_from_verb(m, view, _("_Palette"), _("Show or hide the color palette"), "panels",
780 checkitem_toggled, checkitem_update, 0);
781 }
783 /** \brief This function turns XML into a menu
784 \param menus This is the XML that defines the menu
785 \param menu Menu to be added to
786 \param view The View that this menu is being built for
788 This function is realitively simple as it just goes through the XML
789 and parses the individual elements. In the case of a submenu, it
790 just calls itself recursively. Because it is only reasonable to have
791 a couple of submenus, it is unlikely this will go more than two or
792 three times.
794 In the case of an unreconginzed verb, a menu item is made to identify
795 the verb that is missing, and display that. The menu item is also made
796 insensitive.
797 */
798 void
799 sp_ui_build_dyn_menus(Inkscape::XML::Node *menus, GtkWidget *menu, Inkscape::UI::View::View *view)
800 {
801 if (menus == NULL) return;
802 if (menu == NULL) return;
803 GSList *group = NULL;
805 for (Inkscape::XML::Node *menu_pntr = menus;
806 menu_pntr != NULL;
807 menu_pntr = menu_pntr->next()) {
808 if (!strcmp(menu_pntr->name(), "submenu")) {
809 if (!strcmp(menu_pntr->attribute("name"), "Effects") && !prefs_get_int_attribute("extensions", "show-effects-menu", 0)) {
810 continue;
811 }
812 GtkWidget *mitem = gtk_menu_item_new_with_mnemonic(_(menu_pntr->attribute("name")));
813 GtkWidget *submenu = gtk_menu_new();
814 sp_ui_build_dyn_menus(menu_pntr->firstChild(), submenu, view);
815 gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), GTK_WIDGET(submenu));
816 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
817 continue;
818 }
819 if (!strcmp(menu_pntr->name(), "verb")) {
820 gchar const *verb_name = menu_pntr->attribute("verb-id");
821 Inkscape::Verb *verb = Inkscape::Verb::getbyid(verb_name);
823 if (verb != NULL) {
824 if (menu_pntr->attribute("radio") != NULL) {
825 GtkWidget *item = sp_ui_menu_append_item_from_verb (GTK_MENU(menu), verb, view, true, group);
826 group = gtk_radio_menu_item_get_group( GTK_RADIO_MENU_ITEM(item));
827 if (menu_pntr->attribute("default") != NULL) {
828 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);
829 }
830 } else {
831 sp_ui_menu_append_item_from_verb(GTK_MENU(menu), verb, view);
832 group = NULL;
833 }
834 } else {
835 gchar string[120];
836 g_snprintf(string, 120, _("Verb \"%s\" Unknown"), verb_name);
837 string[119] = '\0'; /* may not be terminated */
838 GtkWidget *item = gtk_menu_item_new_with_label(string);
839 gtk_widget_set_sensitive(item, false);
840 gtk_widget_show(item);
841 gtk_menu_append(GTK_MENU(menu), item);
842 }
843 continue;
844 }
845 if (!strcmp(menu_pntr->name(), "separator")
846 // This was spelt wrong in the original version
847 // and so this is for backward compatibility. It can
848 // probably be dropped after the 0.44 release.
849 || !strcmp(menu_pntr->name(), "seperator")) {
850 GtkWidget *item = gtk_separator_menu_item_new();
851 gtk_widget_show(item);
852 gtk_menu_append(GTK_MENU(menu), item);
853 continue;
854 }
855 if (!strcmp(menu_pntr->name(), "template-list")) {
856 sp_menu_append_new_templates(menu, view);
857 continue;
858 }
859 if (!strcmp(menu_pntr->name(), "recent-file-list")) {
860 sp_menu_append_recent_documents(menu, view);
861 continue;
862 }
863 if (!strcmp(menu_pntr->name(), "objects-checkboxes")) {
864 sp_ui_checkboxes_menus(GTK_MENU(menu), view);
865 continue;
866 }
867 }
868 }
870 /** \brief Build the main tool bar
871 \param view View to build the bar for
873 Currently the main tool bar is built as a dynamic XML menu using
874 \c sp_ui_build_dyn_menus. This function builds the bar, and then
875 pass it to get items attached to it.
876 */
877 GtkWidget *
878 sp_ui_main_menubar(Inkscape::UI::View::View *view)
879 {
880 GtkWidget *mbar = gtk_menu_bar_new();
882 sp_ui_build_dyn_menus(inkscape_get_menus(INKSCAPE), mbar, view);
884 return mbar;
885 }
887 static void leave_group(GtkMenuItem *, SPDesktop *desktop) {
888 desktop->setCurrentLayer(SP_OBJECT_PARENT(desktop->currentLayer()));
889 }
891 static void enter_group(GtkMenuItem *mi, SPDesktop *desktop) {
892 desktop->setCurrentLayer(reinterpret_cast<SPObject *>(g_object_get_data(G_OBJECT(mi), "group")));
893 SP_DT_SELECTION(desktop)->clear();
894 }
896 GtkWidget *
897 sp_ui_context_menu(Inkscape::UI::View::View *view, SPItem *item)
898 {
899 GtkWidget *m;
900 SPDesktop *dt;
902 dt = static_cast<SPDesktop*>(view);
904 m = gtk_menu_new();
906 /* Undo and Redo */
907 sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_UNDO), view);
908 sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_REDO), view);
910 /* Separator */
911 sp_ui_menu_append_item(GTK_MENU(m), NULL, NULL, NULL, NULL, NULL, NULL);
913 sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_CUT), view);
914 sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_COPY), view);
915 sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_PASTE), view);
917 /* Separator */
918 sp_ui_menu_append_item(GTK_MENU(m), NULL, NULL, NULL, NULL, NULL, NULL);
920 sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_DUPLICATE), view);
921 sp_ui_menu_append_item_from_verb(GTK_MENU(m), Inkscape::Verb::get(SP_VERB_EDIT_DELETE), view);
923 /* Item menu */
924 if (item) {
925 sp_ui_menu_append_item(GTK_MENU(m), NULL, NULL, NULL, NULL, NULL, NULL);
926 sp_object_menu((SPObject *) item, dt, GTK_MENU(m));
927 }
929 /* layer menu */
930 SPGroup *group=NULL;
931 if (item) {
932 if (SP_IS_GROUP(item)) {
933 group = SP_GROUP(item);
934 } else if ( item != dt->currentRoot() && SP_IS_GROUP(SP_OBJECT_PARENT(item)) ) {
935 group = SP_GROUP(SP_OBJECT_PARENT(item));
936 }
937 }
939 if (( group && group != dt->currentLayer() ) ||
940 ( dt->currentLayer() != dt->currentRoot() ) ) {
941 sp_ui_menu_append_item(GTK_MENU(m), NULL, NULL, NULL, NULL, NULL, NULL);
942 }
944 if ( group && group != dt->currentLayer() ) {
945 /* TRANSLATORS: #%s is the id of the group e.g. <g id="#g7">, not a number. */
946 gchar *label=g_strdup_printf(_("Enter group #%s"), SP_OBJECT_ID(group));
947 GtkWidget *w = gtk_menu_item_new_with_label(label);
948 g_free(label);
949 g_object_set_data(G_OBJECT(w), "group", group);
950 g_signal_connect(G_OBJECT(w), "activate", GCallback(enter_group), dt);
951 gtk_widget_show(w);
952 gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
953 }
955 if ( dt->currentLayer() != dt->currentRoot() ) {
956 if ( SP_OBJECT_PARENT(dt->currentLayer()) != dt->currentRoot() ) {
957 GtkWidget *w = gtk_menu_item_new_with_label(_("Go to parent"));
958 g_signal_connect(G_OBJECT(w), "activate", GCallback(leave_group), dt);
959 gtk_widget_show(w);
960 gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
962 }
963 }
965 return m;
966 }
968 /* Drag and Drop */
969 void
970 sp_ui_drag_data_received(GtkWidget *widget,
971 GdkDragContext *drag_context,
972 gint x, gint y,
973 GtkSelectionData *data,
974 guint info,
975 guint event_time,
976 gpointer user_data)
977 {
978 switch (info) {
979 case APP_X_INKY_COLOR:
980 {
981 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
982 int destX = 0;
983 int destY = 0;
984 gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY );
985 NR::Point where( sp_canvas_window_to_world( desktop->canvas, NR::Point( destX, destY ) ) );
987 SPItem *item = desktop->item_at_point( where, true );
988 if ( item )
989 {
990 if ( data->length >= 8 ) {
991 gchar c[64] = {0};
992 // Careful about endian issues.
993 guint16* dataVals = (guint16*)data->data;
994 sp_svg_write_color( c, 64,
995 SP_RGBA32_U_COMPOSE(
996 0x0ff & (dataVals[0] >> 8),
997 0x0ff & (dataVals[1] >> 8),
998 0x0ff & (dataVals[2] >> 8),
999 0xff // can't have transparency in the color itself
1000 //0x0ff & (data->data[3] >> 8),
1001 ));
1002 SPCSSAttr *css = sp_repr_css_attr_new();
1003 sp_repr_css_set_property( css, (drag_context->action != GDK_ACTION_MOVE) ? "fill":"stroke", c );
1005 sp_desktop_apply_css_recursive( item, css, true );
1006 item->updateRepr();
1008 if ( data->length > 14 ) {
1009 int flags = dataVals[4];
1011 // piggie-backed palette entry info
1012 int index = dataVals[5];
1013 Glib::ustring palName;
1014 for ( int i = 0; i < dataVals[6]; i++ ) {
1015 palName += (gunichar)dataVals[7+i];
1016 }
1018 // Now hook in a magic tag of some sort.
1019 if ( !palName.empty() && (flags & 1) ) {
1020 gchar* str = g_strdup_printf("%d|", index);
1021 palName.insert( 0, str );
1022 g_free(str);
1023 str = 0;
1025 sp_object_setAttribute( SP_OBJECT(item),
1026 (drag_context->action != GDK_ACTION_MOVE) ? "inkscape:x-fill-tag":"inkscape:x-stroke-tag",
1027 palName.c_str(),
1028 false );
1029 item->updateRepr();
1030 }
1031 }
1033 SPDocument *doc = SP_ACTIVE_DOCUMENT;
1034 sp_document_done( doc );
1035 }
1036 }
1037 }
1038 break;
1040 case APP_X_COLOR:
1041 {
1042 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
1043 int destX = 0;
1044 int destY = 0;
1045 gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY );
1046 NR::Point where( sp_canvas_window_to_world( desktop->canvas, NR::Point( destX, destY ) ) );
1048 SPItem *item = desktop->item_at_point( where, true );
1049 if ( item )
1050 {
1051 if ( data->length == 8 ) {
1052 gchar c[64] = {0};
1053 // Careful about endian issues.
1054 guint16* dataVals = (guint16*)data->data;
1055 sp_svg_write_color( c, 64,
1056 SP_RGBA32_U_COMPOSE(
1057 0x0ff & (dataVals[0] >> 8),
1058 0x0ff & (dataVals[1] >> 8),
1059 0x0ff & (dataVals[2] >> 8),
1060 0xff // can't have transparency in the color itself
1061 //0x0ff & (data->data[3] >> 8),
1062 ));
1063 SPCSSAttr *css = sp_repr_css_attr_new();
1064 sp_repr_css_set_property( css, (drag_context->action != GDK_ACTION_MOVE) ? "fill":"stroke", c );
1066 sp_desktop_apply_css_recursive( item, css, true );
1067 item->updateRepr();
1069 SPDocument *doc = SP_ACTIVE_DOCUMENT;
1070 sp_document_done( doc );
1071 }
1072 }
1073 }
1074 break;
1076 case SVG_DATA:
1077 case SVG_XML_DATA: {
1078 gchar *svgdata = (gchar *)data->data;
1080 SPDocument *doc = SP_ACTIVE_DOCUMENT;
1082 Inkscape::XML::Document *rnewdoc = sp_repr_read_mem(svgdata, data->length, SP_SVG_NS_URI);
1084 if (rnewdoc == NULL) {
1085 sp_ui_error_dialog(_("Could not parse SVG data"));
1086 return;
1087 }
1089 Inkscape::XML::Node *repr = sp_repr_document_root(rnewdoc);
1090 gchar const *style = repr->attribute("style");
1092 Inkscape::XML::Node *newgroup = sp_repr_new("svg:g");
1093 newgroup->setAttribute("style", style);
1095 for (Inkscape::XML::Node *child = repr->firstChild(); child != NULL; child = child->next()) {
1096 Inkscape::XML::Node *newchild = child->duplicate();
1097 newgroup->appendChild(newchild);
1098 }
1100 Inkscape::GC::release(rnewdoc);
1102 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
1103 // Add it to the current layer
1105 // Greg's edits to add intelligent positioning of svg drops
1106 SPObject *new_obj = NULL;
1107 new_obj = desktop->currentLayer()->appendChildRepr(newgroup);
1109 Inkscape::Selection *selection = SP_DT_SELECTION(desktop);
1110 selection->set(SP_ITEM(new_obj));
1111 // To move the imported object, we must temporarily set the "transform pattern with
1112 // object" option.
1113 {
1114 int const saved_pref = prefs_get_int_attribute("options.transform", "pattern", 1);
1115 prefs_set_int_attribute("options.transform", "pattern", 1);
1116 sp_document_ensure_up_to_date(SP_DT_DOCUMENT(desktop));
1117 NR::Point m( desktop->point() - selection->bounds().midpoint() );
1118 sp_selection_move_relative(selection, m);
1119 prefs_set_int_attribute("options.transform", "pattern", saved_pref);
1120 }
1122 Inkscape::GC::release(newgroup);
1123 sp_document_done(doc);
1124 break;
1125 }
1127 case URI_LIST: {
1128 gchar *uri = (gchar *)data->data;
1129 sp_ui_import_files(uri);
1130 break;
1131 }
1133 case PNG_DATA:
1134 case JPEG_DATA:
1135 case IMAGE_DATA: {
1136 char tmp[1024];
1138 StringOutputStream outs;
1139 Base64OutputStream b64out(outs);
1140 b64out.setColumnWidth(0);
1142 SPDocument *doc = SP_ACTIVE_DOCUMENT;
1144 Inkscape::XML::Node *newImage = sp_repr_new("svg:image");
1146 for ( int i = 0; i < data->length; i++ ) {
1147 b64out.put( data->data[i] );
1148 }
1149 b64out.close();
1152 Glib::ustring str = outs.getString();
1154 snprintf( tmp, sizeof(tmp), "data:%s;base64,", gdk_atom_name(data->type) );
1155 str.insert( 0, tmp );
1156 newImage->setAttribute("xlink:href", str.c_str());
1158 GError *error = NULL;
1159 GdkPixbufLoader *loader = gdk_pixbuf_loader_new_with_mime_type( gdk_atom_name(data->type), &error );
1160 if ( loader ) {
1161 error = NULL;
1162 if ( gdk_pixbuf_loader_write( loader, data->data, data->length, &error) ) {
1163 GdkPixbuf *pbuf = gdk_pixbuf_loader_get_pixbuf(loader);
1164 if ( pbuf ) {
1165 int width = gdk_pixbuf_get_width(pbuf);
1166 int height = gdk_pixbuf_get_height(pbuf);
1167 snprintf( tmp, sizeof(tmp), "%d", width );
1168 newImage->setAttribute("width", tmp);
1170 snprintf( tmp, sizeof(tmp), "%d", height );
1171 newImage->setAttribute("height", tmp);
1172 }
1173 }
1174 }
1176 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
1178 // Add it to the current layer
1179 desktop->currentLayer()->appendChildRepr(newImage);
1181 Inkscape::GC::release(newImage);
1182 sp_document_done( doc );
1183 break;
1184 }
1185 }
1186 }
1188 static void
1189 sp_ui_import_files(gchar *buffer)
1190 {
1191 GList *list = gnome_uri_list_extract_filenames(buffer);
1192 if (!list)
1193 return;
1194 g_list_foreach(list, sp_ui_import_one_file_with_check, NULL);
1195 g_list_foreach(list, (GFunc) g_free, NULL);
1196 g_list_free(list);
1197 }
1199 static void
1200 sp_ui_import_one_file_with_check(gpointer filename, gpointer unused)
1201 {
1202 if (filename) {
1203 if (strlen((char const *)filename) > 2)
1204 sp_ui_import_one_file((char const *)filename);
1205 }
1206 }
1208 static void
1209 sp_ui_import_one_file(char const *filename)
1210 {
1211 SPDocument *doc = SP_ACTIVE_DOCUMENT;
1212 if (!doc) return;
1214 if (filename == NULL) return;
1216 // Pass off to common implementation
1217 // TODO might need to get the proper type of Inkscape::Extension::Extension
1218 file_import( doc, filename, NULL );
1219 }
1221 void
1222 sp_ui_error_dialog(gchar const *message)
1223 {
1224 GtkWidget *dlg;
1225 gchar *safeMsg = Inkscape::IO::sanitizeString(message);
1227 dlg = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,
1228 GTK_BUTTONS_CLOSE, safeMsg);
1229 sp_transientize(dlg);
1230 gtk_window_set_resizable(GTK_WINDOW(dlg), FALSE);
1231 gtk_dialog_run(GTK_DIALOG(dlg));
1232 gtk_widget_destroy(dlg);
1233 g_free(safeMsg);
1234 }
1236 bool
1237 sp_ui_overwrite_file(gchar const *filename)
1238 {
1239 bool return_value = FALSE;
1240 GtkWidget *dialog;
1241 GtkWidget *hbox;
1242 GtkWidget *boxdata;
1243 gchar *title;
1244 gchar *text;
1246 if (Inkscape::IO::file_test(filename, G_FILE_TEST_EXISTS)) {
1248 title = g_strdup_printf(_("Overwrite %s"), filename);
1249 dialog = gtk_dialog_new_with_buttons(title,
1250 NULL,
1251 (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
1252 GTK_STOCK_NO,
1253 GTK_RESPONSE_NO,
1254 GTK_STOCK_YES,
1255 GTK_RESPONSE_YES,
1256 NULL);
1257 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_YES);
1259 sp_transientize(dialog);
1260 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
1262 hbox = gtk_hbox_new(FALSE, 5);
1263 boxdata = gtk_image_new_from_stock(GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG);
1264 gtk_widget_show(boxdata);
1265 gtk_box_pack_start(GTK_BOX(hbox), boxdata, TRUE, TRUE, 5);
1266 text = g_strdup_printf(_("The file %s already exists. Do you want to overwrite that file with the current document?"), filename);
1267 boxdata = gtk_label_new(text);
1268 gtk_label_set_line_wrap(GTK_LABEL(boxdata), TRUE);
1269 gtk_widget_show(boxdata);
1270 gtk_box_pack_start(GTK_BOX(hbox), boxdata, FALSE, FALSE, 5);
1271 gtk_widget_show(hbox);
1272 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, TRUE, TRUE, 5);
1274 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES) {
1275 return_value = TRUE;
1276 } else {
1277 return_value = FALSE;
1278 }
1280 gtk_widget_destroy(dialog);
1281 g_free(title);
1282 g_free(text);
1283 } else {
1284 return_value = TRUE;
1285 }
1287 return return_value;
1288 }
1290 static void
1291 sp_ui_menu_item_set_sensitive(SPAction *action, unsigned int sensitive, void *data)
1292 {
1293 return gtk_widget_set_sensitive(GTK_WIDGET(data), sensitive);
1294 }
1296 /*
1297 Local Variables:
1298 mode:c++
1299 c-file-style:"stroustrup"
1300 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1301 indent-tabs-mode:nil
1302 fill-column:99
1303 End:
1304 */
1305 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :