Code

fix 1633451: mark the help commands as not needing the document and avoid saving...
[inkscape.git] / src / extension / effect.cpp
1 /*
2  * Authors:
3  *   Ted Gould <ted@gould.cx>
4  *
5  * Copyright (C) 2002-2006 Authors
6  *
7  * Released under GNU GPL, read the file 'COPYING' for more information
8  */
10 #include "inkscape-private.h"
11 #include "helper/action.h"
12 #include "document.h"
13 #include "prefdialog.h"
14 #include "implementation/implementation.h"
15 #include "effect.h"
16 #include "ui/view/view.h"
18 /* Inkscape::Extension::Effect */
20 namespace Inkscape {
21 namespace Extension {
23 Effect * Effect::_last_effect = NULL;
24 Inkscape::XML::Node * Effect::_effects_list = NULL;
26 Effect::Effect (Inkscape::XML::Node * in_repr, Implementation::Implementation * in_imp)
27     : Extension(in_repr, in_imp), _verb(get_id(), get_name(), NULL, NULL, this), _menu_node(NULL)
28 {
29     Inkscape::XML::Node * local_effects_menu = NULL;
31     // This is a weird hack
32     if (!strcmp(this->get_id(), "org.inkscape.filter.dropshadow"))
33         return;
35     bool hidden = false;
37     no_doc = false;
39     if (repr != NULL) {
41         for (Inkscape::XML::Node *child = sp_repr_children(repr); child != NULL; child = child->next()) {
42             if (!strcmp(child->name(), "effect")) {
43                 if (child->attribute("needs-document") && !strcmp(child->attribute("needs-document"), "no")) {
44                   no_doc = true;
45                 }
46                 for (Inkscape::XML::Node *effect_child = sp_repr_children(child); effect_child != NULL; effect_child = effect_child->next()) {
47                     if (!strcmp(effect_child->name(), "effects-menu")) {
48                         // printf("Found local effects menu in %s\n", this->get_name());
49                         local_effects_menu = sp_repr_children(effect_child);
50                         if (effect_child->attribute("hidden") && !strcmp(effect_child->attribute("hidden"), "yes")) {
51                             hidden = true;
52                         }
53                     }
54                     if (!strcmp(effect_child->name(), "menu-name") ||
55                             !strcmp(effect_child->name(), "_menu-name")) {
56                         // printf("Found local effects menu in %s\n", this->get_name());
57                         _verb.set_name(sp_repr_children(effect_child)->content());
58                     }
59                     if (!strcmp(effect_child->name(), "menu-tip") ||
60                             !strcmp(effect_child->name(), "_menu-tip")) {
61                         // printf("Found local effects menu in %s\n", this->get_name());
62                         _verb.set_tip(sp_repr_children(effect_child)->content());
63                     }
64                 } // children of "effect"
65                 break; // there can only be one effect
66             } // find "effect"
67         } // children of "inkscape-extension"
68     } // if we have an XML file
70     if (_effects_list == NULL)
71         find_effects_list(inkscape_get_menus(INKSCAPE));
73     if (_effects_list != NULL) {
74         _menu_node = sp_repr_new("verb");
75         _menu_node->setAttribute("verb-id", this->get_id(), false);
77         if (!hidden)
78             merge_menu(_effects_list->parent(), _effects_list, local_effects_menu, _menu_node);
79     }
81     return;
82 }
84 void
85 Effect::merge_menu (Inkscape::XML::Node * base,
86                     Inkscape::XML::Node * start,
87                     Inkscape::XML::Node * patern,
88                     Inkscape::XML::Node * mergee) {
89     Glib::ustring mergename;
90     Inkscape::XML::Node * tomerge = NULL;
91     Inkscape::XML::Node * submenu = NULL;
93     /* printf("Merge menu with '%s' '%s' '%s'\n",
94             base != NULL ? base->name() : "NULL",
95             patern != NULL ? patern->name() : "NULL",
96             mergee != NULL ? mergee->name() : "NULL"); */
98     if (patern == NULL) {
99         // Merge the verb name
100         tomerge = mergee;
101         mergename = _(this->get_name());
102     } else {
103         gchar const * menuname = patern->attribute("name");
104         if (menuname == NULL) menuname = patern->attribute("_name");
105         if (menuname == NULL) return;
107         tomerge = sp_repr_new("submenu");
108         tomerge->setAttribute("name", menuname, false);
110         mergename = _(menuname);
111     }
113     int position = -1;
115     if (start != NULL) {
116         Inkscape::XML::Node * menupass;
117         for (menupass = start->next(); menupass != NULL; menupass = menupass->next()) {
118             gchar const * compare_char = NULL;
119             if (!strcmp(menupass->name(), "verb")) {
120                 gchar const * verbid = menupass->attribute("verb-id");
121                 Inkscape::Verb * verb = Inkscape::Verb::getbyid(verbid);
122                 if (verb == NULL) {
123                     continue;
124                 }
125                 compare_char = verb->get_name();
126             } else if (!strcmp(menupass->name(), "submenu")) {
127                 compare_char = menupass->attribute("name");
128                 if (compare_char == NULL)
129                     compare_char = menupass->attribute("_name");
130             }
132             /* This will cause us to skip tags we don't understand */
133             if (compare_char == NULL) {
134                 continue;
135             }
137             Glib::ustring compare(_(compare_char));
139             if (mergename == compare) {
140                 Inkscape::GC::release(tomerge);
141                 tomerge = NULL;
142                 submenu = menupass;
143                 break;
144             }
146             if (mergename < compare) {
147                 position = menupass->position();
148                 break;
149             }
150         } // for menu items
151     } // start != NULL
153     if (tomerge != NULL) {
154         base->appendChild(tomerge);
155         Inkscape::GC::release(tomerge);
156         if (position != -1)
157             tomerge->setPosition(position);
158     }
160     if (patern != NULL) {
161         if (submenu == NULL)
162             submenu = tomerge;
163         merge_menu(submenu, submenu->firstChild(), patern->firstChild(), mergee);
164     }
166     return;
169 Effect::~Effect (void)
171     if (get_last_effect() == this)
172         set_last_effect(NULL);
173     return;
176 bool
177 Effect::check (void)
179     if (!Extension::check()) {
180         /** \todo  Check to see if parent has this as its only child,
181                    if so, delete it too */
182         if (_menu_node != NULL)
183             sp_repr_unparent(_menu_node);
184         _menu_node = NULL;
185         return false;
186     }
187     return true;
190 bool
191 Effect::prefs (Inkscape::UI::View::View * doc)
193     if (!loaded())
194         set_state(Extension::STATE_LOADED);
195     if (!loaded()) return false;
197     Gtk::Widget * controls;
198     controls = imp->prefs_effect(this, doc);
199     if (controls == NULL) {
200         // std::cout << "No preferences for Effect" << std::endl;
201         return true;
202     }
204     PrefDialog * dialog = new PrefDialog(this->get_name(), this->get_help(), controls);
205     int response = dialog->run();
206     dialog->hide();
208     delete dialog;
210     if (response == Gtk::RESPONSE_OK) return true;
212     return false;
215 /**
216     \brief  The function that 'does' the effect itself
217     \param  doc  The Inkscape::UI::View::View to do the effect on
219     This function first insures that the extension is loaded, and if not,
220     loads it.  It then calls the implemention to do the actual work.  It
221     also resets the last effect pointer to be this effect.  Finally, it
222     executes a \c sp_document_done to commit the changes to the undo
223     stack.
224 */
225 void
226 Effect::effect (Inkscape::UI::View::View * doc)
228     if (!loaded())
229         set_state(Extension::STATE_LOADED);
230     if (!loaded()) return;
232     set_last_effect(this);
233     imp->effect(this, doc);
235     sp_document_done(doc->doc(), SP_VERB_NONE, _(this->get_name()));
237     return;
240 void
241 Effect::set_last_effect (Effect * in_effect)
243     if (in_effect == NULL) {
244         Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, false);
245         Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, false);
246     } else if (_last_effect == NULL) {
247         Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, true);
248         Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, true);
249     }
251     _last_effect = in_effect;
252     return;
255 #define  EFFECTS_LIST  "effects-list"
257 bool
258 Effect::find_effects_list (Inkscape::XML::Node * menustruct)
260     if (menustruct == NULL) return false;
261     for (Inkscape::XML::Node * child = menustruct;
262             child != NULL;
263             child = child->next()) {
264         if (!strcmp(child->name(), EFFECTS_LIST)) {
265             _effects_list = child;
266             return true;
267         }
268         Inkscape::XML::Node * firstchild = child->firstChild();
269         if (firstchild != NULL)
270             if (find_effects_list(firstchild))
271                 return true;
272     }
273     return false;
276 Gtk::VBox *
277 Effect::get_info_widget(void)
279     return Extension::get_info_widget();
282 /** \brief  Create an action for a \c EffectVerb
283     \param  view  Which view the action should be created for
284     \return The built action.
286     Calls \c make_action_helper with the \c vector.
287 */
288 SPAction *
289 Effect::EffectVerb::make_action (Inkscape::UI::View::View * view)
291     return make_action_helper(view, &vector, static_cast<void *>(_effect));
294 /** \brief  Decode the verb code and take appropriate action */
295 void
296 Effect::EffectVerb::perform (SPAction *action, void * data, void *pdata)
298     Inkscape::UI::View::View * current_view = sp_action_get_view(action);
299 //  SPDocument * current_document = current_view->doc;
300     Effect * effect = reinterpret_cast<Effect *>(data);
302     if (effect == NULL) return;
303     if (current_view == NULL) return;
305     // std::cout << "Executing: " << effect->get_name() << std::endl;
306     if (effect->prefs(current_view))
307         effect->effect(current_view);
309     return;
312 /**
313  * Action vector to define functions called if a staticly defined file verb
314  * is called.
315  */
316 SPActionEventVector Effect::EffectVerb::vector =
317             {{NULL}, Effect::EffectVerb::perform, NULL, NULL, NULL, NULL};
320 } }  /* namespace Inkscape, Extension */
322 /*
323   Local Variables:
324   mode:c++
325   c-file-style:"stroustrup"
326   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
327   indent-tabs-mode:nil
328   fill-column:99
329   End:
330 */
331 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :