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 "preferences.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);
126 }
128 static void
129 sp_item_properties(GtkMenuItem *menuitem, SPItem *item)
130 {
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();
141 }
143 static void
144 sp_item_select_this(GtkMenuItem *menuitem, SPItem *item)
145 {
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);
154 }
156 static void
157 sp_item_create_link(GtkMenuItem *menuitem, SPItem *item)
158 {
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);
177 Inkscape::GC::release(repr);
178 Inkscape::GC::release(child);
180 sp_document_done(SP_OBJECT_DOCUMENT(object), SP_VERB_NONE,
181 _("Create link"));
183 sp_object_attributes_dialog(object, "SPAnchor");
185 sp_desktop_selection(desktop)->set(SP_ITEM(object));
186 }
188 /* SPGroup */
190 static void sp_item_group_ungroup_activate(GtkMenuItem *menuitem, SPGroup *group);
192 static void
193 sp_group_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu)
194 {
195 SPItem *item=SP_ITEM(object);
196 GtkWidget *w;
198 /* "Ungroup" */
199 w = gtk_menu_item_new_with_mnemonic(_("_Ungroup"));
200 gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
201 gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_item_group_ungroup_activate), item);
202 gtk_widget_show(w);
203 gtk_menu_append(GTK_MENU(menu), w);
204 }
206 static void
207 sp_item_group_ungroup_activate(GtkMenuItem *menuitem, SPGroup *group)
208 {
209 SPDesktop *desktop;
210 GSList *children;
212 g_assert(SP_IS_GROUP(group));
214 desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
215 g_return_if_fail(desktop != NULL);
217 children = NULL;
218 sp_item_group_ungroup(group, &children);
220 sp_desktop_selection(desktop)->setList(children);
221 g_slist_free(children);
222 }
224 /* SPAnchor */
226 static void sp_anchor_link_properties(GtkMenuItem *menuitem, SPAnchor *anchor);
227 static void sp_anchor_link_follow(GtkMenuItem *menuitem, SPAnchor *anchor);
228 static void sp_anchor_link_remove(GtkMenuItem *menuitem, SPAnchor *anchor);
230 static void
231 sp_anchor_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m)
232 {
233 SPItem *item;
234 GtkWidget *w;
236 item = (SPItem *) object;
238 /* Link dialog */
239 w = gtk_menu_item_new_with_mnemonic(_("Link _Properties"));
240 gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
241 gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_anchor_link_properties), item);
242 gtk_widget_show(w);
243 gtk_menu_append(GTK_MENU(m), w);
244 /* Select item */
245 w = gtk_menu_item_new_with_mnemonic(_("_Follow Link"));
246 gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_anchor_link_follow), item);
247 gtk_widget_show(w);
248 gtk_menu_append(GTK_MENU(m), w);
249 /* Reset transformations */
250 w = gtk_menu_item_new_with_mnemonic(_("_Remove Link"));
251 gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
252 gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_anchor_link_remove), item);
253 gtk_widget_show(w);
254 gtk_menu_append(GTK_MENU(m), w);
255 }
257 static void
258 sp_anchor_link_properties(GtkMenuItem */*menuitem*/, SPAnchor *anchor)
259 {
260 sp_object_attributes_dialog(SP_OBJECT(anchor), "Link");
261 }
263 static void
264 sp_anchor_link_follow(GtkMenuItem */*menuitem*/, SPAnchor *anchor)
265 {
266 g_return_if_fail(anchor != NULL);
267 g_return_if_fail(SP_IS_ANCHOR(anchor));
269 /* shell out to an external browser here */
270 }
272 static void
273 sp_anchor_link_remove(GtkMenuItem */*menuitem*/, SPAnchor *anchor)
274 {
275 GSList *children;
277 g_return_if_fail(anchor != NULL);
278 g_return_if_fail(SP_IS_ANCHOR(anchor));
280 children = NULL;
281 sp_item_group_ungroup(SP_GROUP(anchor), &children);
283 g_slist_free(children);
284 }
286 /* Image */
288 static void sp_image_image_properties(GtkMenuItem *menuitem, SPAnchor *anchor);
289 static void sp_image_image_edit(GtkMenuItem *menuitem, SPAnchor *anchor);
291 static void
292 sp_image_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m)
293 {
294 SPItem *item = SP_ITEM(object);
295 GtkWidget *w;
297 /* Link dialog */
298 w = gtk_menu_item_new_with_mnemonic(_("Image _Properties"));
299 gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
300 gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_image_image_properties), item);
301 gtk_widget_show(w);
302 gtk_menu_append(GTK_MENU(m), w);
304 w = gtk_menu_item_new_with_mnemonic(_("Edit Externally..."));
305 gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
306 gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_image_image_edit), item);
307 gtk_widget_show(w);
308 gtk_menu_append(GTK_MENU(m), w);
309 Inkscape::XML::Node *ir = SP_OBJECT_REPR(object);
310 const gchar *href = ir->attribute("xlink:href");
311 if ( (!href) || ((strncmp(href, "data:", 5) == 0)) ) {
312 gtk_widget_set_sensitive( w, FALSE );
313 }
314 }
316 static void
317 sp_image_image_properties(GtkMenuItem */*menuitem*/, SPAnchor *anchor)
318 {
319 sp_object_attributes_dialog(SP_OBJECT(anchor), "Image");
320 }
322 static gchar* getImageEditorName() {
323 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
324 gchar* value = 0;
325 Glib::ustring choices = prefs->getString("options.bitmapeditor", "choices");
326 if (!choices.empty()) {
327 gchar** splits = g_strsplit(choices.data(), ",", 0);
328 gint numIems = g_strv_length(splits);
330 int setting = prefs->getIntLimited("options.bitmapeditor", "value", 0, 0, numIems);
331 value = g_strdup(splits[setting]);
333 g_strfreev(splits);
334 }
336 if (!value) {
337 value = g_strdup("gimp");
338 }
339 return value;
340 }
342 static void sp_image_image_edit(GtkMenuItem *menuitem, SPAnchor *anchor)
343 {
344 SPObject* obj = SP_OBJECT(anchor);
345 Inkscape::XML::Node *ir = SP_OBJECT_REPR(obj);
346 const gchar *href = ir->attribute("xlink:href");
348 GError* errThing = 0;
349 gchar* editorBin = getImageEditorName();
350 gchar const* args[] = {editorBin, href, 0};
351 g_spawn_async(0, // working dir
352 const_cast<gchar **>(args),
353 0, //envp
354 G_SPAWN_SEARCH_PATH,
355 0, // child_setup
356 0, // user_data
357 0, //GPid *child_pid
358 &errThing);
359 if ( errThing ) {
360 g_warning("Problem launching editor (%d). %s", errThing->code, errThing->message);
361 SPDesktop *desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
362 desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, errThing->message);
363 g_error_free(errThing);
364 errThing = 0;
365 }
366 g_free(editorBin);
367 }
369 /* SPShape */
371 static void
372 sp_shape_fill_settings(GtkMenuItem *menuitem, SPItem *item)
373 {
374 SPDesktop *desktop;
376 g_assert(SP_IS_ITEM(item));
378 desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
379 g_return_if_fail(desktop != NULL);
381 if (sp_desktop_selection(desktop)->isEmpty()) {
382 sp_desktop_selection(desktop)->set(item);
383 }
385 desktop->_dlg_mgr->showDialog("FillAndStroke");
386 }
388 static void
389 sp_shape_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m)
390 {
391 SPItem *item;
392 GtkWidget *w;
394 item = (SPItem *) object;
396 /* Item dialog */
397 w = gtk_menu_item_new_with_mnemonic(_("_Fill and Stroke"));
398 gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
399 gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_shape_fill_settings), item);
400 gtk_widget_show(w);
401 gtk_menu_append(GTK_MENU(m), w);
402 }
405 /*
406 Local Variables:
407 mode:c++
408 c-file-style:"stroustrup"
409 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
410 indent-tabs-mode:nil
411 fill-column:99
412 End:
413 */
414 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :