Code

Added preferences for controlling external image editing and reload.
[inkscape.git] / src / ui / context-menu.cpp
1 #define __CONTEXT_MENU_C__
3 /*
4  * Unser-interface related object extension
5  *
6  * Authors:
7  *   Lauris Kaplinski <lauris@kaplinski.com>
8  *
9  * This code is in public domain
10  */
12 #ifdef HAVE_CONFIG_H
13 # include "config.h"
14 #endif
16 #include "context-menu.h"
17 #include "../xml/repr.h"
18 #include "desktop.h"
19 #include "document.h"
20 #include "message-stack.h"
21 #include "prefs-utils.h"
22 #include "ui/dialog/dialog-manager.h"
24 static void sp_object_type_menu(GType type, SPObject *object, SPDesktop *desktop, GtkMenu *menu);
26 /* Append object-specific part to context menu */
28 void
29 sp_object_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu)
30 {
31     GObjectClass *klass;
32     klass = G_OBJECT_GET_CLASS(object);
33     while (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_OBJECT)) {
34         GType type;
35         type = G_TYPE_FROM_CLASS(klass);
36         sp_object_type_menu(type, object, desktop, menu);
37         klass = (GObjectClass*)g_type_class_peek_parent(klass);
38     }
39 }
41 /* Implementation */
43 #include <gtk/gtkmenuitem.h>
45 #include <glibmm/i18n.h>
47 #include "sp-anchor.h"
48 #include "sp-image.h"
50 #include "document.h"
51 #include "desktop-handles.h"
52 #include "selection.h"
54 #include "dialogs/item-properties.h"
55 #include "dialogs/object-attributes.h"
57 #include "sp-path.h"
60 static void sp_item_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu);
61 static void sp_group_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu);
62 static void sp_anchor_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu);
63 static void sp_image_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu);
64 static void sp_shape_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu);
66 static void
67 sp_object_type_menu(GType type, SPObject *object, SPDesktop *desktop, GtkMenu *menu)
68 {
69     static GHashTable *t2m = NULL;
70     void (* handler)(SPObject *object, SPDesktop *desktop, GtkMenu *menu);
71     if (!t2m) {
72         t2m = g_hash_table_new(NULL, NULL);
73         g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_ITEM), (void*)sp_item_menu);
74         g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_GROUP), (void*)sp_group_menu);
75         g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_ANCHOR), (void*)sp_anchor_menu);
76         g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_IMAGE), (void*)sp_image_menu);
77         g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_SHAPE), (void*)sp_shape_menu);
78     }
79     handler = (void (*)(SPObject*, SPDesktop*, GtkMenu*))g_hash_table_lookup(t2m, GUINT_TO_POINTER(type));
80     if (handler) handler(object, desktop, menu);
81 }
83 /* SPItem */
85 static void sp_item_properties(GtkMenuItem *menuitem, SPItem *item);
86 static void sp_item_select_this(GtkMenuItem *menuitem, SPItem *item);
87 static void sp_item_create_link(GtkMenuItem *menuitem, SPItem *item);
89 /* Generate context menu item section */
91 static void
92 sp_item_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m)
93 {
94     SPItem *item;
95     GtkWidget *w;
97     item = (SPItem *) object;
99     /* Item dialog */
100     w = gtk_menu_item_new_with_mnemonic(_("Object _Properties"));
101     gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
102     gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_item_properties), item);
103     gtk_widget_show(w);
104     gtk_menu_append(GTK_MENU(m), w);
105     /* Separator */
106     w = gtk_menu_item_new();
107     gtk_widget_show(w);
108     gtk_menu_append(GTK_MENU(m), w);
109     /* Select item */
110     w = gtk_menu_item_new_with_mnemonic(_("_Select This"));
111     if (sp_desktop_selection(desktop)->includes(item)) {
112         gtk_widget_set_sensitive(w, FALSE);
113     } else {
114         gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
115         gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_item_select_this), item);
116     }
117     gtk_widget_show(w);
118     gtk_menu_append(GTK_MENU(m), w);
119     /* Create link */
120     w = gtk_menu_item_new_with_mnemonic(_("_Create Link"));
121     gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
122     gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_item_create_link), item);
123     gtk_widget_set_sensitive(w, !SP_IS_ANCHOR(item));
124     gtk_widget_show(w);
125     gtk_menu_append(GTK_MENU(m), w);
128 static void
129 sp_item_properties(GtkMenuItem *menuitem, SPItem *item)
131     SPDesktop *desktop;
133     g_assert(SP_IS_ITEM(item));
135     desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
136     g_return_if_fail(desktop != NULL);
138     sp_desktop_selection(desktop)->set(item);
140     sp_item_dialog();
143 static void
144 sp_item_select_this(GtkMenuItem *menuitem, SPItem *item)
146     SPDesktop *desktop;
148     g_assert(SP_IS_ITEM(item));
150     desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
151     g_return_if_fail(desktop != NULL);
153     sp_desktop_selection(desktop)->set(item);
156 static void
157 sp_item_create_link(GtkMenuItem *menuitem, SPItem *item)
159     g_assert(SP_IS_ITEM(item));
160     g_assert(!SP_IS_ANCHOR(item));
162     SPDesktop *desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
163     g_return_if_fail(desktop != NULL);
165     Inkscape::XML::Document *xml_doc = sp_document_repr_doc(desktop->doc());
166     Inkscape::XML::Node *repr = xml_doc->createElement("svg:a");
167     SP_OBJECT_REPR(SP_OBJECT_PARENT(item))->addChild(repr, SP_OBJECT_REPR(item));
168     SPObject *object = SP_OBJECT_DOCUMENT(item)->getObjectByRepr(repr);
169     g_return_if_fail(SP_IS_ANCHOR(object));
171     const char *id = SP_OBJECT_REPR(item)->attribute("id");
172     Inkscape::XML::Node *child = SP_OBJECT_REPR(item)->duplicate(xml_doc);
173     SP_OBJECT(item)->deleteObject(false);
174     repr->addChild(child, NULL);
175     child->setAttribute("id", id);
176     sp_document_done(SP_OBJECT_DOCUMENT(object), SP_VERB_NONE,
177                      _("Create link"));
179     sp_object_attributes_dialog(object, "SPAnchor");
181     sp_desktop_selection(desktop)->set(SP_ITEM(object));
184 /* SPGroup */
186 static void sp_item_group_ungroup_activate(GtkMenuItem *menuitem, SPGroup *group);
188 static void
189 sp_group_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu)
191     SPItem *item=SP_ITEM(object);
192     GtkWidget *w;
194     /* "Ungroup" */
195     w = gtk_menu_item_new_with_mnemonic(_("_Ungroup"));
196     gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
197     gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_item_group_ungroup_activate), item);
198     gtk_widget_show(w);
199     gtk_menu_append(GTK_MENU(menu), w);
202 static void
203 sp_item_group_ungroup_activate(GtkMenuItem *menuitem, SPGroup *group)
205     SPDesktop *desktop;
206     GSList *children;
208     g_assert(SP_IS_GROUP(group));
210     desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
211     g_return_if_fail(desktop != NULL);
213     children = NULL;
214     sp_item_group_ungroup(group, &children);
216     sp_desktop_selection(desktop)->setList(children);
217     g_slist_free(children);
220 /* SPAnchor */
222 static void sp_anchor_link_properties(GtkMenuItem *menuitem, SPAnchor *anchor);
223 static void sp_anchor_link_follow(GtkMenuItem *menuitem, SPAnchor *anchor);
224 static void sp_anchor_link_remove(GtkMenuItem *menuitem, SPAnchor *anchor);
226 static void
227 sp_anchor_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m)
229     SPItem *item;
230     GtkWidget *w;
232     item = (SPItem *) object;
234     /* Link dialog */
235     w = gtk_menu_item_new_with_mnemonic(_("Link _Properties"));
236     gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
237     gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_anchor_link_properties), item);
238     gtk_widget_show(w);
239     gtk_menu_append(GTK_MENU(m), w);
240     /* Select item */
241     w = gtk_menu_item_new_with_mnemonic(_("_Follow Link"));
242     gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_anchor_link_follow), item);
243     gtk_widget_show(w);
244     gtk_menu_append(GTK_MENU(m), w);
245     /* Reset transformations */
246     w = gtk_menu_item_new_with_mnemonic(_("_Remove Link"));
247     gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
248     gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_anchor_link_remove), item);
249     gtk_widget_show(w);
250     gtk_menu_append(GTK_MENU(m), w);
253 static void
254 sp_anchor_link_properties(GtkMenuItem */*menuitem*/, SPAnchor *anchor)
256     sp_object_attributes_dialog(SP_OBJECT(anchor), "Link");
259 static void
260 sp_anchor_link_follow(GtkMenuItem */*menuitem*/, SPAnchor *anchor)
262     g_return_if_fail(anchor != NULL);
263     g_return_if_fail(SP_IS_ANCHOR(anchor));
265     /* shell out to an external browser here */
268 static void
269 sp_anchor_link_remove(GtkMenuItem */*menuitem*/, SPAnchor *anchor)
271     GSList *children;
273     g_return_if_fail(anchor != NULL);
274     g_return_if_fail(SP_IS_ANCHOR(anchor));
276     children = NULL;
277     sp_item_group_ungroup(SP_GROUP(anchor), &children);
279     g_slist_free(children);
282 /* Image */
284 static void sp_image_image_properties(GtkMenuItem *menuitem, SPAnchor *anchor);
285 static void sp_image_image_edit(GtkMenuItem *menuitem, SPAnchor *anchor);
287 static void
288 sp_image_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m)
290     SPItem *item = SP_ITEM(object);
291     GtkWidget *w;
293     /* Link dialog */
294     w = gtk_menu_item_new_with_mnemonic(_("Image _Properties"));
295     gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
296     gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_image_image_properties), item);
297     gtk_widget_show(w);
298     gtk_menu_append(GTK_MENU(m), w);
300     w = gtk_menu_item_new_with_mnemonic(_("Edit Externally..."));
301     gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
302     gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_image_image_edit), item);
303     gtk_widget_show(w);
304     gtk_menu_append(GTK_MENU(m), w);
305     Inkscape::XML::Node *ir = SP_OBJECT_REPR(object);
306     const gchar *href = ir->attribute("xlink:href");
307     if ( (!href) || ((strncmp(href, "data:", 5) == 0)) ) {
308         gtk_widget_set_sensitive( w, FALSE );
309     }
312 static void
313 sp_image_image_properties(GtkMenuItem */*menuitem*/, SPAnchor *anchor)
315     sp_object_attributes_dialog(SP_OBJECT(anchor), "Image");
318 static gchar* getImageEditorName() {
319     gchar* value = 0;
320     gchar const *choices = prefs_get_string_attribute("options.bitmapeditor", "choices");
321     if ( choices && choices[0] ) {
322         gchar** splits = g_strsplit(choices, ",", 0);
323         gint numIems = g_strv_length(splits);
325         int setting = prefs_get_int_attribute_limited("options.bitmapeditor", "value", 0, 0, numIems);
326         value = g_strdup(splits[setting]);
328         g_strfreev(splits);
329     }
331     if (!value) {
332         value = g_strdup("gimp");
333     }
334     return value;
337 static void sp_image_image_edit(GtkMenuItem *menuitem, SPAnchor *anchor)
339     SPObject* obj = SP_OBJECT(anchor);
340     Inkscape::XML::Node *ir = SP_OBJECT_REPR(obj);
341     const gchar *href = ir->attribute("xlink:href");
343     GError* errThing = 0;
344     gchar* editorBin = getImageEditorName();
345     gchar const* args[] = {editorBin, href, 0};
346     g_spawn_async(0, // working dir
347                   const_cast<gchar **>(args),
348                   0, //envp
349                   G_SPAWN_SEARCH_PATH,
350                   0, // child_setup
351                   0, // user_data
352                   0, //GPid *child_pid
353                   &errThing);
354     if ( errThing ) {
355         g_warning("Problem launching editor (%d). %s", errThing->code, errThing->message);
356         SPDesktop *desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
357         desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, errThing->message);
358         g_error_free(errThing);
359         errThing = 0;
360     }
361     g_free(editorBin);
364 /* SPShape */
366 static void
367 sp_shape_fill_settings(GtkMenuItem *menuitem, SPItem *item)
369     SPDesktop *desktop;
371     g_assert(SP_IS_ITEM(item));
373     desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
374     g_return_if_fail(desktop != NULL);
376     if (sp_desktop_selection(desktop)->isEmpty()) {
377         sp_desktop_selection(desktop)->set(item);
378     }
380     desktop->_dlg_mgr->showDialog("FillAndStroke");
383 static void
384 sp_shape_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m)
386     SPItem *item;
387     GtkWidget *w;
389     item = (SPItem *) object;
391     /* Item dialog */
392     w = gtk_menu_item_new_with_mnemonic(_("_Fill and Stroke"));
393     gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
394     gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_shape_fill_settings), item);
395     gtk_widget_show(w);
396     gtk_menu_append(GTK_MENU(m), w);
400 /*
401   Local Variables:
402   mode:c++
403   c-file-style:"stroustrup"
404   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
405   indent-tabs-mode:nil
406   fill-column:99
407   End:
408 */
409 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :