Code

Merge and cleanup of GSoC C++-ification project.
[inkscape.git] / src / ui / context-menu.cpp
1 /*
2  * Unser-interface related object extension
3  *
4  * Authors:
5  *   Lauris Kaplinski <lauris@kaplinski.com>
6  *   Jon A. Cruz <jon@joncruz.org>
7  *   Abhishek Sharma
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 using Inkscape::DocumentUndo;
26 static void sp_object_type_menu(GType type, SPObject *object, SPDesktop *desktop, GtkMenu *menu);
28 /* Append object-specific part to context menu */
30 void
31 sp_object_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu)
32 {
33     GObjectClass *klass;
34     klass = G_OBJECT_GET_CLASS(object);
35     while (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_OBJECT)) {
36         GType type;
37         type = G_TYPE_FROM_CLASS(klass);
38         sp_object_type_menu(type, object, desktop, menu);
39         klass = (GObjectClass*)g_type_class_peek_parent(klass);
40     }
41 }
43 /* Implementation */
45 #include <gtk/gtkmenuitem.h>
47 #include <glibmm/i18n.h>
49 #include "sp-anchor.h"
50 #include "sp-image.h"
51 #include "sp-text.h"
53 #include "document.h"
54 #include "desktop-handles.h"
55 #include "selection.h"
56 #include "selection-chemistry.h"
57 #include "dialogs/item-properties.h"
58 #include "dialogs/object-attributes.h"
59 #include "dialogs/text-edit.h"
60 #include "dialogs/spellcheck.h"
62 #include "sp-path.h"
63 #include "sp-clippath.h"
64 #include "sp-mask.h"
67 static void sp_item_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu);
68 static void sp_group_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu);
69 static void sp_anchor_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu);
70 static void sp_image_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu);
71 static void sp_shape_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu);
72 static void sp_text_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu);
74 static void
75 sp_object_type_menu(GType type, SPObject *object, SPDesktop *desktop, GtkMenu *menu)
76 {
77     static GHashTable *t2m = NULL;
78     void (* handler)(SPObject *object, SPDesktop *desktop, GtkMenu *menu);
79     if (!t2m) {
80         t2m = g_hash_table_new(NULL, NULL);
81         g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_ITEM), (void*)sp_item_menu);
82         g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_GROUP), (void*)sp_group_menu);
83         g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_ANCHOR), (void*)sp_anchor_menu);
84         g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_IMAGE), (void*)sp_image_menu);
85         g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_SHAPE), (void*)sp_shape_menu);
86         g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_TEXT), (void*)sp_text_menu);
87     }
88     handler = (void (*)(SPObject*, SPDesktop*, GtkMenu*))g_hash_table_lookup(t2m, GUINT_TO_POINTER(type));
89     if (handler) handler(object, desktop, menu);
90 }
92 /* SPItem */
94 static void sp_item_properties(GtkMenuItem *menuitem, SPItem *item);
95 static void sp_item_select_this(GtkMenuItem *menuitem, SPItem *item);
96 static void sp_item_create_link(GtkMenuItem *menuitem, SPItem *item);
97 static void sp_set_mask(GtkMenuItem *menuitem, SPItem *item);
98 static void sp_release_mask(GtkMenuItem *menuitem, SPItem *item);
99 static void sp_set_clip(GtkMenuItem *menuitem, SPItem *item);
100 static void sp_release_clip(GtkMenuItem *menuitem, SPItem *item);
101 /* Generate context menu item section */
103 static void
104 sp_item_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m)
106     SPItem *item;
107     GtkWidget *w;
109     item = (SPItem *) object;
111     /* Item dialog */
112     w = gtk_menu_item_new_with_mnemonic(_("_Object Properties..."));
113     gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
114     gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_item_properties), item);
115     gtk_widget_show(w);
116     gtk_menu_append(GTK_MENU(m), w);
117     /* Separator */
118     w = gtk_menu_item_new();
119     gtk_widget_show(w);
120     gtk_menu_append(GTK_MENU(m), w);
121     /* Select item */
122     w = gtk_menu_item_new_with_mnemonic(_("_Select This"));
123     if (sp_desktop_selection(desktop)->includes(item)) {
124         gtk_widget_set_sensitive(w, FALSE);
125     } else {
126         gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
127         gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_item_select_this), item);
128     }
129     gtk_widget_show(w);
130     gtk_menu_append(GTK_MENU(m), w);
131     /* Create link */
132     w = gtk_menu_item_new_with_mnemonic(_("_Create Link"));
133     gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
134     gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_item_create_link), item);
135     gtk_widget_set_sensitive(w, !SP_IS_ANCHOR(item));
136     gtk_widget_show(w);
137     gtk_menu_append(GTK_MENU(m), w);
138     /* Set mask */
139     w = gtk_menu_item_new_with_mnemonic(_("Set Mask"));
140     gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
141     gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_set_mask), item);
142     if ((item && item->mask_ref && item->mask_ref->getObject()) || (item->clip_ref && item->clip_ref->getObject())) {
143         gtk_widget_set_sensitive(w, FALSE);
144     } else {
145         gtk_widget_set_sensitive(w, TRUE);
146     }
147     gtk_widget_show(w);
148     gtk_menu_append(GTK_MENU(m), w);
149     /* Release mask */
150     w = gtk_menu_item_new_with_mnemonic(_("Release Mask"));
151     gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
152     gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_release_mask), item);
153     if (item && item->mask_ref && item->mask_ref->getObject()) {
154         gtk_widget_set_sensitive(w, TRUE);
155     } else {
156         gtk_widget_set_sensitive(w, FALSE);
157     }
158     gtk_widget_show(w);
159     gtk_menu_append(GTK_MENU(m), w);
160     /* Set Clip */
161     w = gtk_menu_item_new_with_mnemonic(_("Set _Clip"));
162     gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
163     gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_set_clip), item);
164     if ((item && item->mask_ref && item->mask_ref->getObject()) || (item->clip_ref && item->clip_ref->getObject())) {
165         gtk_widget_set_sensitive(w, FALSE);
166     } else {
167         gtk_widget_set_sensitive(w, TRUE);
168     }
169     gtk_widget_show(w);
170     gtk_menu_append(GTK_MENU(m), w);
171     /* Release Clip */
172     w = gtk_menu_item_new_with_mnemonic(_("Release C_lip"));
173     gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
174     gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_release_clip), item);
175     if (item && item->clip_ref && item->clip_ref->getObject()) {
176         gtk_widget_set_sensitive(w, TRUE);
177     } else {
178         gtk_widget_set_sensitive(w, FALSE);
179     }
180     gtk_widget_show(w);
181     gtk_menu_append(GTK_MENU(m), w);
185 static void
186 sp_item_properties(GtkMenuItem *menuitem, SPItem *item)
188     SPDesktop *desktop;
190     g_assert(SP_IS_ITEM(item));
192     desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
193     g_return_if_fail(desktop != NULL);
195     sp_desktop_selection(desktop)->set(item);
197     sp_item_dialog();
201 static void
202 sp_set_mask(GtkMenuItem *menuitem, SPItem *item)
204     SPDesktop *desktop;
206     g_assert(SP_IS_ITEM(item));
208     desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
209     g_return_if_fail(desktop != NULL);
211         sp_selection_set_mask(desktop, false, false);
215 static void
216 sp_release_mask(GtkMenuItem *menuitem, SPItem *item)
218     SPDesktop *desktop;
220     g_assert(SP_IS_ITEM(item));
222     desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
223     g_return_if_fail(desktop != NULL);
225     sp_selection_unset_mask(desktop, false);
229 static void
230 sp_set_clip(GtkMenuItem *menuitem, SPItem *item)
232     SPDesktop *desktop;
234     g_assert(SP_IS_ITEM(item));
236     desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
237     g_return_if_fail(desktop != NULL);
239         sp_selection_set_mask(desktop, true, false);
243 static void
244 sp_release_clip(GtkMenuItem *menuitem, SPItem *item)
246     SPDesktop *desktop;
248     g_assert(SP_IS_ITEM(item));
250     desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
251     g_return_if_fail(desktop != NULL);
253     sp_selection_unset_mask(desktop, true);
257 static void
258 sp_item_select_this(GtkMenuItem *menuitem, SPItem *item)
260     SPDesktop *desktop;
262     g_assert(SP_IS_ITEM(item));
264     desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
265     g_return_if_fail(desktop != NULL);
267     sp_desktop_selection(desktop)->set(item);
270 static void
271 sp_item_create_link(GtkMenuItem *menuitem, SPItem *item)
273     g_assert(SP_IS_ITEM(item));
274     g_assert(!SP_IS_ANCHOR(item));
276     SPDesktop *desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
277     g_return_if_fail(desktop != NULL);
279     Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc();
280     Inkscape::XML::Node *repr = xml_doc->createElement("svg:a");
281     SP_OBJECT_REPR(SP_OBJECT_PARENT(item))->addChild(repr, SP_OBJECT_REPR(item));
282     SPObject *object = SP_OBJECT_DOCUMENT(item)->getObjectByRepr(repr);
283     g_return_if_fail(SP_IS_ANCHOR(object));
285     const char *id = SP_OBJECT_REPR(item)->attribute("id");
286     Inkscape::XML::Node *child = SP_OBJECT_REPR(item)->duplicate(xml_doc);
287     SP_OBJECT(item)->deleteObject(false);
288     repr->addChild(child, NULL);
289     child->setAttribute("id", id);
291     Inkscape::GC::release(repr);
292     Inkscape::GC::release(child);
294     DocumentUndo::done(SP_OBJECT_DOCUMENT(object), SP_VERB_NONE,
295                        _("Create link"));
297     sp_object_attributes_dialog(object, "SPAnchor");
299     sp_desktop_selection(desktop)->set(SP_ITEM(object));
302 /* SPGroup */
304 static void sp_item_group_ungroup_activate(GtkMenuItem *menuitem, SPGroup *group);
306 static void
307 sp_group_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu)
309     SPItem *item=SP_ITEM(object);
310     GtkWidget *w;
312     /* "Ungroup" */
313     w = gtk_menu_item_new_with_mnemonic(_("_Ungroup"));
314     gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
315     gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_item_group_ungroup_activate), item);
316     gtk_widget_show(w);
317     gtk_menu_append(GTK_MENU(menu), w);
320 static void
321 sp_item_group_ungroup_activate(GtkMenuItem *menuitem, SPGroup *group)
323     SPDesktop *desktop;
324     GSList *children;
326     g_assert(SP_IS_GROUP(group));
328     desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
329     g_return_if_fail(desktop != NULL);
331     children = NULL;
332     sp_item_group_ungroup(group, &children);
334     sp_desktop_selection(desktop)->setList(children);
335     g_slist_free(children);
338 /* SPAnchor */
340 static void sp_anchor_link_properties(GtkMenuItem *menuitem, SPAnchor *anchor);
341 static void sp_anchor_link_follow(GtkMenuItem *menuitem, SPAnchor *anchor);
342 static void sp_anchor_link_remove(GtkMenuItem *menuitem, SPAnchor *anchor);
344 static void
345 sp_anchor_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m)
347     SPItem *item;
348     GtkWidget *w;
350     item = (SPItem *) object;
352     /* Link dialog */
353     w = gtk_menu_item_new_with_mnemonic(_("Link _Properties..."));
354     gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
355     gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_anchor_link_properties), item);
356     gtk_widget_show(w);
357     gtk_menu_append(GTK_MENU(m), w);
358     /* Select item */
359     w = gtk_menu_item_new_with_mnemonic(_("_Follow Link"));
360     gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_anchor_link_follow), item);
361     gtk_widget_show(w);
362     gtk_menu_append(GTK_MENU(m), w);
363     /* Reset transformations */
364     w = gtk_menu_item_new_with_mnemonic(_("_Remove Link"));
365     gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
366     gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_anchor_link_remove), item);
367     gtk_widget_show(w);
368     gtk_menu_append(GTK_MENU(m), w);
371 static void
372 sp_anchor_link_properties(GtkMenuItem */*menuitem*/, SPAnchor *anchor)
374     sp_object_attributes_dialog(SP_OBJECT(anchor), "Link");
377 static void
378 sp_anchor_link_follow(GtkMenuItem */*menuitem*/, SPAnchor *anchor)
380     g_return_if_fail(anchor != NULL);
381     g_return_if_fail(SP_IS_ANCHOR(anchor));
383     /* shell out to an external browser here */
386 static void
387 sp_anchor_link_remove(GtkMenuItem */*menuitem*/, SPAnchor *anchor)
389     GSList *children;
391     g_return_if_fail(anchor != NULL);
392     g_return_if_fail(SP_IS_ANCHOR(anchor));
394     children = NULL;
395     sp_item_group_ungroup(SP_GROUP(anchor), &children);
397     g_slist_free(children);
400 /* Image */
402 static void sp_image_image_properties(GtkMenuItem *menuitem, SPAnchor *anchor);
403 static void sp_image_image_edit(GtkMenuItem *menuitem, SPAnchor *anchor);
405 static void
406 sp_image_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m)
408     SPItem *item = SP_ITEM(object);
409     GtkWidget *w;
411     /* Link dialog */
412     w = gtk_menu_item_new_with_mnemonic(_("Image _Properties..."));
413     gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
414     gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_image_image_properties), item);
415     gtk_widget_show(w);
416     gtk_menu_append(GTK_MENU(m), w);
418     w = gtk_menu_item_new_with_mnemonic(_("Edit Externally..."));
419     gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
420     gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_image_image_edit), item);
421     gtk_widget_show(w);
422     gtk_menu_append(GTK_MENU(m), w);
423     Inkscape::XML::Node *ir = SP_OBJECT_REPR(object);
424     const gchar *href = ir->attribute("xlink:href");
425     if ( (!href) || ((strncmp(href, "data:", 5) == 0)) ) {
426         gtk_widget_set_sensitive( w, FALSE );
427     }
430 static void
431 sp_image_image_properties(GtkMenuItem */*menuitem*/, SPAnchor *anchor)
433     sp_object_attributes_dialog(SP_OBJECT(anchor), "Image");
436 static gchar* getImageEditorName() {
437     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
438     gchar* value = 0;
439     Glib::ustring choices = prefs->getString("/options/bitmapeditor/choices");
440     if (!choices.empty()) {
441         gchar** splits = g_strsplit(choices.data(), ",", 0);
442         gint numIems = g_strv_length(splits);
444         int setting = prefs->getIntLimited("/options/bitmapeditor/value", 0, 0, numIems);
445         value = g_strdup(splits[setting]);
447         g_strfreev(splits);
448     }
450     if (!value) {
451         value = g_strdup("gimp");
452     }
453     return value;
456 static void sp_image_image_edit(GtkMenuItem *menuitem, SPAnchor *anchor)
458     SPObject* obj = SP_OBJECT(anchor);
459     Inkscape::XML::Node *ir = SP_OBJECT_REPR(obj);
460     const gchar *href = ir->attribute("xlink:href");
462     GError* errThing = 0;
463     gchar* editorBin = getImageEditorName();
464     gchar const* args[] = {editorBin, href, 0};
465     g_spawn_async(0, // working dir
466                   const_cast<gchar **>(args),
467                   0, //envp
468                   G_SPAWN_SEARCH_PATH,
469                   0, // child_setup
470                   0, // user_data
471                   0, //GPid *child_pid
472                   &errThing);
473     if ( errThing ) {
474         g_warning("Problem launching editor (%d). %s", errThing->code, errThing->message);
475         SPDesktop *desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
476         desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, errThing->message);
477         g_error_free(errThing);
478         errThing = 0;
479     }
480     g_free(editorBin);
483 /* Fill and Stroke entry */
485 static void
486 sp_fill_settings(GtkMenuItem *menuitem, SPItem *item)
488     SPDesktop *desktop;
490     g_assert(SP_IS_ITEM(item));
492     desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
493     g_return_if_fail(desktop != NULL);
495     if (sp_desktop_selection(desktop)->isEmpty()) {
496         sp_desktop_selection(desktop)->set(item);
497     }
499     desktop->_dlg_mgr->showDialog("FillAndStroke");
502 /* SPShape */
504 static void
505 sp_shape_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m)
507     SPItem *item;
508     GtkWidget *w;
510     item = (SPItem *) object;
512     /* Item dialog */
513     w = gtk_menu_item_new_with_mnemonic(_("_Fill and Stroke..."));
514     gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
515     gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_fill_settings), item);
516     gtk_widget_show(w);
517     gtk_menu_append(GTK_MENU(m), w);
520 /* Edit Text entry */
522 static void
523 sp_text_settings(GtkMenuItem *menuitem, SPItem *item)
525     SPDesktop *desktop;
527     g_assert(SP_IS_ITEM(item));
529     desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
530     g_return_if_fail(desktop != NULL);
532     if (sp_desktop_selection(desktop)->isEmpty()) {
533         sp_desktop_selection(desktop)->set(item);
534     }
536     sp_text_edit_dialog();
539 /* Spellcheck entry */
541 static void
542 sp_spellcheck_settings(GtkMenuItem *menuitem, SPItem *item)
544     SPDesktop *desktop;
546     g_assert(SP_IS_ITEM(item));
548     desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop");
549     g_return_if_fail(desktop != NULL);
551     if (sp_desktop_selection(desktop)->isEmpty()) {
552         sp_desktop_selection(desktop)->set(item);
553     }
555     sp_spellcheck_dialog();
558 /* SPText */
560 static void
561 sp_text_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m)
563     SPItem *item;
564     GtkWidget *w;
566     item = (SPItem *) object;
568     /* Fill and Stroke dialog */
569     w = gtk_menu_item_new_with_mnemonic(_("_Fill and Stroke..."));
570     gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
571     gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_fill_settings), item);
572     gtk_widget_show(w);
573     gtk_menu_append(GTK_MENU(m), w);
574     
575     /* Edit Text dialog */
576     w = gtk_menu_item_new_with_mnemonic(_("_Text and Font..."));
577     gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
578     gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_text_settings), item);
579     gtk_widget_show(w);
580     gtk_menu_append(GTK_MENU(m), w);
582     /* Spellcheck dialog */
583     w = gtk_menu_item_new_with_mnemonic(_("Check Spellin_g..."));
584     gtk_object_set_data(GTK_OBJECT(w), "desktop", desktop);
585     gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_spellcheck_settings), item);
586     gtk_widget_show(w);
587     gtk_menu_append(GTK_MENU(m), w);
589 /*
590   Local Variables:
591   mode:c++
592   c-file-style:"stroustrup"
593   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
594   indent-tabs-mode:nil
595   fill-column:99
596   End:
597 */
598 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :