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"
53 #include "selection-chemistry.h"
54 #include "dialogs/item-properties.h"
55 #include "dialogs/object-attributes.h"
57 #include "sp-path.h"
58 #include "sp-clippath.h"
59 #include "sp-mask.h"
62 static void sp_item_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu);
63 static void sp_group_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu);
64 static void sp_anchor_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu);
65 static void sp_image_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu);
66 static void sp_shape_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu);
68 static void
69 sp_object_type_menu(GType type, SPObject *object, SPDesktop *desktop, GtkMenu *menu)
70 {
71 static GHashTable *t2m = NULL;
72 void (* handler)(SPObject *object, SPDesktop *desktop, GtkMenu *menu);
73 if (!t2m) {
74 t2m = g_hash_table_new(NULL, NULL);
75 g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_ITEM), (void*)sp_item_menu);
76 g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_GROUP), (void*)sp_group_menu);
77 g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_ANCHOR), (void*)sp_anchor_menu);
78 g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_IMAGE), (void*)sp_image_menu);
79 g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_SHAPE), (void*)sp_shape_menu);
80 }
81 handler = (void (*)(SPObject*, SPDesktop*, GtkMenu*))g_hash_table_lookup(t2m, GUINT_TO_POINTER(type));
82 if (handler) handler(object, desktop, menu);
83 }
85 /* SPItem */
87 static void sp_item_properties(GtkMenuItem *menuitem, SPItem *item);
88 static void sp_item_select_this(GtkMenuItem *menuitem, SPItem *item);
89 static void sp_item_create_link(GtkMenuItem *menuitem, SPItem *item);
90 static void sp_set_mask(GtkMenuItem *menuitem, SPItem *item);
91 static void sp_release_mask(GtkMenuItem *menuitem, SPItem *item);
92 static void sp_set_clip(GtkMenuItem *menuitem, SPItem *item);
93 static void sp_release_clip(GtkMenuItem *menuitem, SPItem *item);
94 /* Generate context menu item section */
96 static void
97 sp_item_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m)
98 {
99 SPItem *item;
100 GtkWidget *w;
102 item = (SPItem *) object;
104 /* Item dialog */
105 w = gtk_menu_item_new_with_mnemonic(_("Object _Properties"));
106 gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
107 gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_item_properties), item);
108 gtk_widget_show(w);
109 gtk_menu_append(GTK_MENU(m), w);
110 /* Separator */
111 w = gtk_menu_item_new();
112 gtk_widget_show(w);
113 gtk_menu_append(GTK_MENU(m), w);
114 /* Select item */
115 w = gtk_menu_item_new_with_mnemonic(_("_Select This"));
116 if (sp_desktop_selection(desktop)->includes(item)) {
117 gtk_widget_set_sensitive(w, FALSE);
118 } else {
119 gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
120 gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_item_select_this), item);
121 }
122 gtk_widget_show(w);
123 gtk_menu_append(GTK_MENU(m), w);
124 /* Create link */
125 w = gtk_menu_item_new_with_mnemonic(_("_Create Link"));
126 gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
127 gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_item_create_link), item);
128 gtk_widget_set_sensitive(w, !SP_IS_ANCHOR(item));
129 gtk_widget_show(w);
130 gtk_menu_append(GTK_MENU(m), w);
131 /* Set mask */
132 w = gtk_menu_item_new_with_mnemonic(_("Set Mask"));
133 gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
134 gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_set_mask), item);
135 if ((item && item->mask_ref && item->mask_ref->getObject()) || (item->clip_ref && item->clip_ref->getObject())) {
136 gtk_widget_set_sensitive(w, FALSE);
137 } else {
138 gtk_widget_set_sensitive(w, TRUE);
139 }
140 gtk_widget_show(w);
141 gtk_menu_append(GTK_MENU(m), w);
142 /* Release mask */
143 w = gtk_menu_item_new_with_mnemonic(_("Release Mask"));
144 gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
145 gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_release_mask), item);
146 if (item && item->mask_ref && item->mask_ref->getObject()) {
147 gtk_widget_set_sensitive(w, TRUE);
148 } else {
149 gtk_widget_set_sensitive(w, FALSE);
150 }
151 gtk_widget_show(w);
152 gtk_menu_append(GTK_MENU(m), w);
153 /* Set Clip */
154 w = gtk_menu_item_new_with_mnemonic(_("Set Clip"));
155 gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
156 gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_set_clip), item);
157 if ((item && item->mask_ref && item->mask_ref->getObject()) || (item->clip_ref && item->clip_ref->getObject())) {
158 gtk_widget_set_sensitive(w, FALSE);
159 } else {
160 gtk_widget_set_sensitive(w, TRUE);
161 }
162 gtk_widget_show(w);
163 gtk_menu_append(GTK_MENU(m), w);
164 /* Release Clip */
165 w = gtk_menu_item_new_with_mnemonic(_("Release Clip"));
166 gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
167 gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_release_clip), item);
168 if (item && item->clip_ref && item->clip_ref->getObject()) {
169 gtk_widget_set_sensitive(w, TRUE);
170 } else {
171 gtk_widget_set_sensitive(w, FALSE);
172 }
173 gtk_widget_show(w);
174 gtk_menu_append(GTK_MENU(m), w);
176 }
178 static void
179 sp_item_properties(GtkMenuItem *menuitem, SPItem *item)
180 {
181 SPDesktop *desktop;
183 g_assert(SP_IS_ITEM(item));
185 desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
186 g_return_if_fail(desktop != NULL);
188 sp_desktop_selection(desktop)->set(item);
190 sp_item_dialog();
191 }
194 static void
195 sp_set_mask(GtkMenuItem *menuitem, SPItem *item)
196 {
197 SPDesktop *desktop;
199 g_assert(SP_IS_ITEM(item));
201 desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
202 g_return_if_fail(desktop != NULL);
204 sp_selection_set_mask(desktop, false, false);
205 }
208 static void
209 sp_release_mask(GtkMenuItem *menuitem, SPItem *item)
210 {
211 SPDesktop *desktop;
213 g_assert(SP_IS_ITEM(item));
215 desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
216 g_return_if_fail(desktop != NULL);
218 sp_selection_unset_mask(desktop, false);
219 }
222 static void
223 sp_set_clip(GtkMenuItem *menuitem, SPItem *item)
224 {
225 SPDesktop *desktop;
227 g_assert(SP_IS_ITEM(item));
229 desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
230 g_return_if_fail(desktop != NULL);
232 sp_selection_set_mask(desktop, true, false);
233 }
236 static void
237 sp_release_clip(GtkMenuItem *menuitem, SPItem *item)
238 {
239 SPDesktop *desktop;
241 g_assert(SP_IS_ITEM(item));
243 desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
244 g_return_if_fail(desktop != NULL);
246 sp_selection_unset_mask(desktop, true);
247 }
250 static void
251 sp_item_select_this(GtkMenuItem *menuitem, SPItem *item)
252 {
253 SPDesktop *desktop;
255 g_assert(SP_IS_ITEM(item));
257 desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
258 g_return_if_fail(desktop != NULL);
260 sp_desktop_selection(desktop)->set(item);
261 }
263 static void
264 sp_item_create_link(GtkMenuItem *menuitem, SPItem *item)
265 {
266 g_assert(SP_IS_ITEM(item));
267 g_assert(!SP_IS_ANCHOR(item));
269 SPDesktop *desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
270 g_return_if_fail(desktop != NULL);
272 Inkscape::XML::Document *xml_doc = sp_document_repr_doc(desktop->doc());
273 Inkscape::XML::Node *repr = xml_doc->createElement("svg:a");
274 SP_OBJECT_REPR(SP_OBJECT_PARENT(item))->addChild(repr, SP_OBJECT_REPR(item));
275 SPObject *object = SP_OBJECT_DOCUMENT(item)->getObjectByRepr(repr);
276 g_return_if_fail(SP_IS_ANCHOR(object));
278 const char *id = SP_OBJECT_REPR(item)->attribute("id");
279 Inkscape::XML::Node *child = SP_OBJECT_REPR(item)->duplicate(xml_doc);
280 SP_OBJECT(item)->deleteObject(false);
281 repr->addChild(child, NULL);
282 child->setAttribute("id", id);
284 Inkscape::GC::release(repr);
285 Inkscape::GC::release(child);
287 sp_document_done(SP_OBJECT_DOCUMENT(object), SP_VERB_NONE,
288 _("Create link"));
290 sp_object_attributes_dialog(object, "SPAnchor");
292 sp_desktop_selection(desktop)->set(SP_ITEM(object));
293 }
295 /* SPGroup */
297 static void sp_item_group_ungroup_activate(GtkMenuItem *menuitem, SPGroup *group);
299 static void
300 sp_group_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu)
301 {
302 SPItem *item=SP_ITEM(object);
303 GtkWidget *w;
305 /* "Ungroup" */
306 w = gtk_menu_item_new_with_mnemonic(_("_Ungroup"));
307 gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
308 gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_item_group_ungroup_activate), item);
309 gtk_widget_show(w);
310 gtk_menu_append(GTK_MENU(menu), w);
311 }
313 static void
314 sp_item_group_ungroup_activate(GtkMenuItem *menuitem, SPGroup *group)
315 {
316 SPDesktop *desktop;
317 GSList *children;
319 g_assert(SP_IS_GROUP(group));
321 desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
322 g_return_if_fail(desktop != NULL);
324 children = NULL;
325 sp_item_group_ungroup(group, &children);
327 sp_desktop_selection(desktop)->setList(children);
328 g_slist_free(children);
329 }
331 /* SPAnchor */
333 static void sp_anchor_link_properties(GtkMenuItem *menuitem, SPAnchor *anchor);
334 static void sp_anchor_link_follow(GtkMenuItem *menuitem, SPAnchor *anchor);
335 static void sp_anchor_link_remove(GtkMenuItem *menuitem, SPAnchor *anchor);
337 static void
338 sp_anchor_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m)
339 {
340 SPItem *item;
341 GtkWidget *w;
343 item = (SPItem *) object;
345 /* Link dialog */
346 w = gtk_menu_item_new_with_mnemonic(_("Link _Properties"));
347 gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
348 gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_anchor_link_properties), item);
349 gtk_widget_show(w);
350 gtk_menu_append(GTK_MENU(m), w);
351 /* Select item */
352 w = gtk_menu_item_new_with_mnemonic(_("_Follow Link"));
353 gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_anchor_link_follow), item);
354 gtk_widget_show(w);
355 gtk_menu_append(GTK_MENU(m), w);
356 /* Reset transformations */
357 w = gtk_menu_item_new_with_mnemonic(_("_Remove Link"));
358 gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
359 gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_anchor_link_remove), item);
360 gtk_widget_show(w);
361 gtk_menu_append(GTK_MENU(m), w);
362 }
364 static void
365 sp_anchor_link_properties(GtkMenuItem */*menuitem*/, SPAnchor *anchor)
366 {
367 sp_object_attributes_dialog(SP_OBJECT(anchor), "Link");
368 }
370 static void
371 sp_anchor_link_follow(GtkMenuItem */*menuitem*/, SPAnchor *anchor)
372 {
373 g_return_if_fail(anchor != NULL);
374 g_return_if_fail(SP_IS_ANCHOR(anchor));
376 /* shell out to an external browser here */
377 }
379 static void
380 sp_anchor_link_remove(GtkMenuItem */*menuitem*/, SPAnchor *anchor)
381 {
382 GSList *children;
384 g_return_if_fail(anchor != NULL);
385 g_return_if_fail(SP_IS_ANCHOR(anchor));
387 children = NULL;
388 sp_item_group_ungroup(SP_GROUP(anchor), &children);
390 g_slist_free(children);
391 }
393 /* Image */
395 static void sp_image_image_properties(GtkMenuItem *menuitem, SPAnchor *anchor);
396 static void sp_image_image_edit(GtkMenuItem *menuitem, SPAnchor *anchor);
398 static void
399 sp_image_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m)
400 {
401 SPItem *item = SP_ITEM(object);
402 GtkWidget *w;
404 /* Link dialog */
405 w = gtk_menu_item_new_with_mnemonic(_("Image _Properties"));
406 gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
407 gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_image_image_properties), item);
408 gtk_widget_show(w);
409 gtk_menu_append(GTK_MENU(m), w);
411 w = gtk_menu_item_new_with_mnemonic(_("Edit Externally..."));
412 gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
413 gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_image_image_edit), item);
414 gtk_widget_show(w);
415 gtk_menu_append(GTK_MENU(m), w);
416 Inkscape::XML::Node *ir = SP_OBJECT_REPR(object);
417 const gchar *href = ir->attribute("xlink:href");
418 if ( (!href) || ((strncmp(href, "data:", 5) == 0)) ) {
419 gtk_widget_set_sensitive( w, FALSE );
420 }
421 }
423 static void
424 sp_image_image_properties(GtkMenuItem */*menuitem*/, SPAnchor *anchor)
425 {
426 sp_object_attributes_dialog(SP_OBJECT(anchor), "Image");
427 }
429 static gchar* getImageEditorName() {
430 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
431 gchar* value = 0;
432 Glib::ustring choices = prefs->getString("/options/bitmapeditor/choices");
433 if (!choices.empty()) {
434 gchar** splits = g_strsplit(choices.data(), ",", 0);
435 gint numIems = g_strv_length(splits);
437 int setting = prefs->getIntLimited("/options/bitmapeditor/value", 0, 0, numIems);
438 value = g_strdup(splits[setting]);
440 g_strfreev(splits);
441 }
443 if (!value) {
444 value = g_strdup("gimp");
445 }
446 return value;
447 }
449 static void sp_image_image_edit(GtkMenuItem *menuitem, SPAnchor *anchor)
450 {
451 SPObject* obj = SP_OBJECT(anchor);
452 Inkscape::XML::Node *ir = SP_OBJECT_REPR(obj);
453 const gchar *href = ir->attribute("xlink:href");
455 GError* errThing = 0;
456 gchar* editorBin = getImageEditorName();
457 gchar const* args[] = {editorBin, href, 0};
458 g_spawn_async(0, // working dir
459 const_cast<gchar **>(args),
460 0, //envp
461 G_SPAWN_SEARCH_PATH,
462 0, // child_setup
463 0, // user_data
464 0, //GPid *child_pid
465 &errThing);
466 if ( errThing ) {
467 g_warning("Problem launching editor (%d). %s", errThing->code, errThing->message);
468 SPDesktop *desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
469 desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, errThing->message);
470 g_error_free(errThing);
471 errThing = 0;
472 }
473 g_free(editorBin);
474 }
476 /* SPShape */
478 static void
479 sp_shape_fill_settings(GtkMenuItem *menuitem, SPItem *item)
480 {
481 SPDesktop *desktop;
483 g_assert(SP_IS_ITEM(item));
485 desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
486 g_return_if_fail(desktop != NULL);
488 if (sp_desktop_selection(desktop)->isEmpty()) {
489 sp_desktop_selection(desktop)->set(item);
490 }
492 desktop->_dlg_mgr->showDialog("FillAndStroke");
493 }
495 static void
496 sp_shape_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m)
497 {
498 SPItem *item;
499 GtkWidget *w;
501 item = (SPItem *) object;
503 /* Item dialog */
504 w = gtk_menu_item_new_with_mnemonic(_("_Fill and Stroke"));
505 gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
506 gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_shape_fill_settings), item);
507 gtk_widget_show(w);
508 gtk_menu_append(GTK_MENU(m), w);
509 }
512 /*
513 Local Variables:
514 mode:c++
515 c-file-style:"stroustrup"
516 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
517 indent-tabs-mode:nil
518 fill-column:99
519 End:
520 */
521 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :