5de76aff170a9bfc6dacf880730887e0e9c825d0
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 > 12 ) {
1009 // piggie-backed palette entry info
1010 int index = dataVals[4];
1011 Glib::ustring palName;
1012 for ( int i = 0; i < dataVals[5]; i++ ) {
1013 palName += (gunichar)dataVals[6+i];
1014 }
1016 // Now hook in a magic tag of some sort.
1017 if ( !palName.empty() ) {
1018 gchar* str = g_strdup_printf("%d|", index);
1019 palName.insert( 0, str );
1020 g_free(str);
1021 str = 0;
1023 sp_object_setAttribute( SP_OBJECT(item),
1024 (drag_context->action != GDK_ACTION_MOVE) ? "HOTFill":"HOTStroke",
1025 palName.c_str(),
1026 false );
1027 item->updateRepr();
1028 }
1029 }
1031 SPDocument *doc = SP_ACTIVE_DOCUMENT;
1032 sp_document_done( doc );
1033 }
1034 }
1035 }
1036 break;
1038 case APP_X_COLOR:
1039 {
1040 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
1041 int destX = 0;
1042 int destY = 0;
1043 gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY );
1044 NR::Point where( sp_canvas_window_to_world( desktop->canvas, NR::Point( destX, destY ) ) );
1046 SPItem *item = desktop->item_at_point( where, true );
1047 if ( item )
1048 {
1049 if ( data->length == 8 ) {
1050 gchar c[64] = {0};
1051 // Careful about endian issues.
1052 guint16* dataVals = (guint16*)data->data;
1053 sp_svg_write_color( c, 64,
1054 SP_RGBA32_U_COMPOSE(
1055 0x0ff & (dataVals[0] >> 8),
1056 0x0ff & (dataVals[1] >> 8),
1057 0x0ff & (dataVals[2] >> 8),
1058 0xff // can't have transparency in the color itself
1059 //0x0ff & (data->data[3] >> 8),
1060 ));
1061 SPCSSAttr *css = sp_repr_css_attr_new();
1062 sp_repr_css_set_property( css, (drag_context->action != GDK_ACTION_MOVE) ? "fill":"stroke", c );
1064 sp_desktop_apply_css_recursive( item, css, true );
1065 item->updateRepr();
1067 SPDocument *doc = SP_ACTIVE_DOCUMENT;
1068 sp_document_done( doc );
1069 }
1070 }
1071 }
1072 break;
1074 case SVG_DATA:
1075 case SVG_XML_DATA: {
1076 gchar *svgdata = (gchar *)data->data;
1078 SPDocument *doc = SP_ACTIVE_DOCUMENT;
1080 Inkscape::XML::Document *rnewdoc = sp_repr_read_mem(svgdata, data->length, SP_SVG_NS_URI);
1082 if (rnewdoc == NULL) {
1083 sp_ui_error_dialog(_("Could not parse SVG data"));
1084 return;
1085 }
1087 Inkscape::XML::Node *repr = sp_repr_document_root(rnewdoc);
1088 gchar const *style = repr->attribute("style");
1090 Inkscape::XML::Node *newgroup = sp_repr_new("svg:g");
1091 newgroup->setAttribute("style", style);
1093 for (Inkscape::XML::Node *child = repr->firstChild(); child != NULL; child = child->next()) {
1094 Inkscape::XML::Node *newchild = child->duplicate();
1095 newgroup->appendChild(newchild);
1096 }
1098 Inkscape::GC::release(rnewdoc);
1100 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
1101 // Add it to the current layer
1103 // Greg's edits to add intelligent positioning of svg drops
1104 SPObject *new_obj = NULL;
1105 new_obj = desktop->currentLayer()->appendChildRepr(newgroup);
1107 Inkscape::Selection *selection = SP_DT_SELECTION(desktop);
1108 selection->set(SP_ITEM(new_obj));
1109 // To move the imported object, we must temporarily set the "transform pattern with
1110 // object" option.
1111 {
1112 int const saved_pref = prefs_get_int_attribute("options.transform", "pattern", 1);
1113 prefs_set_int_attribute("options.transform", "pattern", 1);
1114 sp_document_ensure_up_to_date(SP_DT_DOCUMENT(desktop));
1115 NR::Point m( desktop->point() - selection->bounds().midpoint() );
1116 sp_selection_move_relative(selection, m);
1117 prefs_set_int_attribute("options.transform", "pattern", saved_pref);
1118 }
1120 Inkscape::GC::release(newgroup);
1121 sp_document_done(doc);
1122 break;
1123 }
1125 case URI_LIST: {
1126 gchar *uri = (gchar *)data->data;
1127 sp_ui_import_files(uri);
1128 break;
1129 }
1131 case PNG_DATA:
1132 case JPEG_DATA:
1133 case IMAGE_DATA: {
1134 char tmp[1024];
1136 StringOutputStream outs;
1137 Base64OutputStream b64out(outs);
1138 b64out.setColumnWidth(0);
1140 SPDocument *doc = SP_ACTIVE_DOCUMENT;
1142 Inkscape::XML::Node *newImage = sp_repr_new("svg:image");
1144 for ( int i = 0; i < data->length; i++ ) {
1145 b64out.put( data->data[i] );
1146 }
1147 b64out.close();
1150 Glib::ustring str = outs.getString();
1152 snprintf( tmp, sizeof(tmp), "data:%s;base64,", gdk_atom_name(data->type) );
1153 str.insert( 0, tmp );
1154 newImage->setAttribute("xlink:href", str.c_str());
1156 GError *error = NULL;
1157 GdkPixbufLoader *loader = gdk_pixbuf_loader_new_with_mime_type( gdk_atom_name(data->type), &error );
1158 if ( loader ) {
1159 error = NULL;
1160 if ( gdk_pixbuf_loader_write( loader, data->data, data->length, &error) ) {
1161 GdkPixbuf *pbuf = gdk_pixbuf_loader_get_pixbuf(loader);
1162 if ( pbuf ) {
1163 int width = gdk_pixbuf_get_width(pbuf);
1164 int height = gdk_pixbuf_get_height(pbuf);
1165 snprintf( tmp, sizeof(tmp), "%d", width );
1166 newImage->setAttribute("width", tmp);
1168 snprintf( tmp, sizeof(tmp), "%d", height );
1169 newImage->setAttribute("height", tmp);
1170 }
1171 }
1172 }
1174 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
1176 // Add it to the current layer
1177 desktop->currentLayer()->appendChildRepr(newImage);
1179 Inkscape::GC::release(newImage);
1180 sp_document_done( doc );
1181 break;
1182 }
1183 }
1184 }
1186 static void
1187 sp_ui_import_files(gchar *buffer)
1188 {
1189 GList *list = gnome_uri_list_extract_filenames(buffer);
1190 if (!list)
1191 return;
1192 g_list_foreach(list, sp_ui_import_one_file_with_check, NULL);
1193 g_list_foreach(list, (GFunc) g_free, NULL);
1194 g_list_free(list);
1195 }
1197 static void
1198 sp_ui_import_one_file_with_check(gpointer filename, gpointer unused)
1199 {
1200 if (filename) {
1201 if (strlen((char const *)filename) > 2)
1202 sp_ui_import_one_file((char const *)filename);
1203 }
1204 }
1206 static void
1207 sp_ui_import_one_file(char const *filename)
1208 {
1209 SPDocument *doc = SP_ACTIVE_DOCUMENT;
1210 if (!doc) return;
1212 if (filename == NULL) return;
1214 // Pass off to common implementation
1215 // TODO might need to get the proper type of Inkscape::Extension::Extension
1216 file_import( doc, filename, NULL );
1217 }
1219 void
1220 sp_ui_error_dialog(gchar const *message)
1221 {
1222 GtkWidget *dlg;
1223 gchar *safeMsg = Inkscape::IO::sanitizeString(message);
1225 dlg = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,
1226 GTK_BUTTONS_CLOSE, safeMsg);
1227 sp_transientize(dlg);
1228 gtk_window_set_resizable(GTK_WINDOW(dlg), FALSE);
1229 gtk_dialog_run(GTK_DIALOG(dlg));
1230 gtk_widget_destroy(dlg);
1231 g_free(safeMsg);
1232 }
1234 bool
1235 sp_ui_overwrite_file(gchar const *filename)
1236 {
1237 bool return_value = FALSE;
1238 GtkWidget *dialog;
1239 GtkWidget *hbox;
1240 GtkWidget *boxdata;
1241 gchar *title;
1242 gchar *text;
1244 if (Inkscape::IO::file_test(filename, G_FILE_TEST_EXISTS)) {
1246 title = g_strdup_printf(_("Overwrite %s"), filename);
1247 dialog = gtk_dialog_new_with_buttons(title,
1248 NULL,
1249 (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
1250 GTK_STOCK_NO,
1251 GTK_RESPONSE_NO,
1252 GTK_STOCK_YES,
1253 GTK_RESPONSE_YES,
1254 NULL);
1255 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_YES);
1257 sp_transientize(dialog);
1258 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
1260 hbox = gtk_hbox_new(FALSE, 5);
1261 boxdata = gtk_image_new_from_stock(GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG);
1262 gtk_widget_show(boxdata);
1263 gtk_box_pack_start(GTK_BOX(hbox), boxdata, TRUE, TRUE, 5);
1264 text = g_strdup_printf(_("The file %s already exists. Do you want to overwrite that file with the current document?"), filename);
1265 boxdata = gtk_label_new(text);
1266 gtk_label_set_line_wrap(GTK_LABEL(boxdata), TRUE);
1267 gtk_widget_show(boxdata);
1268 gtk_box_pack_start(GTK_BOX(hbox), boxdata, FALSE, FALSE, 5);
1269 gtk_widget_show(hbox);
1270 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, TRUE, TRUE, 5);
1272 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES) {
1273 return_value = TRUE;
1274 } else {
1275 return_value = FALSE;
1276 }
1278 gtk_widget_destroy(dialog);
1279 g_free(title);
1280 g_free(text);
1281 } else {
1282 return_value = TRUE;
1283 }
1285 return return_value;
1286 }
1288 static void
1289 sp_ui_menu_item_set_sensitive(SPAction *action, unsigned int sensitive, void *data)
1290 {
1291 return gtk_widget_set_sensitive(GTK_WIDGET(data), sensitive);
1292 }
1294 /*
1295 Local Variables:
1296 mode:c++
1297 c-file-style:"stroustrup"
1298 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1299 indent-tabs-mode:nil
1300 fill-column:99
1301 End:
1302 */
1303 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :