Code

e6b1bf60be0c5d0f791c76f6fd74a67127e96af1
[inkscape.git] / src / extension / effect.cpp
1 /*
2  * Authors:
3  *   Ted Gould <ted@gould.cx>
4  *
5  * Copyright (C) 2002-2007 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 "ui/view/view.h"
13 #include "desktop-handles.h"
14 #include "selection.h"
15 #include "sp-namedview.h"
16 #include "desktop.h"
17 #include "implementation/implementation.h"
18 #include "effect.h"
19 #include "execution-env.h"
20 #include "timer.h"
24 /* Inkscape::Extension::Effect */
26 namespace Inkscape {
27 namespace Extension {
29 Effect * Effect::_last_effect = NULL;
30 Inkscape::XML::Node * Effect::_effects_list = NULL;
32 Effect::Effect (Inkscape::XML::Node * in_repr, Implementation::Implementation * in_imp)
33     : Extension(in_repr, in_imp),
34       _id_noprefs(Glib::ustring(get_id()) + ".noprefs"),
35       _name_noprefs(Glib::ustring(get_name()) + _(" (No preferences)")),
36       _verb(get_id(), get_name(), NULL, NULL, this, true),
37       _verb_nopref(_id_noprefs.c_str(), _name_noprefs.c_str(), NULL, NULL, this, false),
38       _menu_node(NULL), _workingDialog(true),
39       _prefDialog(NULL)
40 {
41     Inkscape::XML::Node * local_effects_menu = NULL;
43     // This is a weird hack
44     if (!strcmp(this->get_id(), "org.inkscape.filter.dropshadow"))
45         return;
47     bool hidden = false;
49     no_doc = false;
50     no_live_preview = false;
52     if (repr != NULL) {
54         for (Inkscape::XML::Node *child = sp_repr_children(repr); child != NULL; child = child->next()) {
55             if (!strcmp(child->name(), INKSCAPE_EXTENSION_NS "effect")) {
56                 if (child->attribute("needs-document") && !strcmp(child->attribute("needs-document"), "false")) {
57                   no_doc = true;
58                 }
59                 if (child->attribute("needs-live-preview") && !strcmp(child->attribute("needs-live-preview"), "false")) {
60                   no_live_preview = true;
61                 }
62                 for (Inkscape::XML::Node *effect_child = sp_repr_children(child); effect_child != NULL; effect_child = effect_child->next()) {
63                     if (!strcmp(effect_child->name(), INKSCAPE_EXTENSION_NS "effects-menu")) {
64                         // printf("Found local effects menu in %s\n", this->get_name());
65                         local_effects_menu = sp_repr_children(effect_child);
66                         if (effect_child->attribute("hidden") && !strcmp(effect_child->attribute("hidden"), "true")) {
67                             hidden = true;
68                         }
69                     }
70                     if (!strcmp(effect_child->name(), INKSCAPE_EXTENSION_NS "menu-name") ||
71                             !strcmp(effect_child->name(), INKSCAPE_EXTENSION_NS "_menu-name")) {
72                         // printf("Found local effects menu in %s\n", this->get_name());
73                         _verb.set_name(sp_repr_children(effect_child)->content());
74                     }
75                     if (!strcmp(effect_child->name(), INKSCAPE_EXTENSION_NS "menu-tip") ||
76                             !strcmp(effect_child->name(), INKSCAPE_EXTENSION_NS "_menu-tip")) {
77                         // printf("Found local effects menu in %s\n", this->get_name());
78                         _verb.set_tip(sp_repr_children(effect_child)->content());
79                     }
80                 } // children of "effect"
81                 break; // there can only be one effect
82             } // find "effect"
83         } // children of "inkscape-extension"
84     } // if we have an XML file
86     if (_effects_list == NULL && INKSCAPE != NULL) {
87         find_effects_list(inkscape_get_menus(INKSCAPE));
88     }
90     if (_effects_list != NULL) {
91         Inkscape::XML::Document *xml_doc;
92         xml_doc = _effects_list->document();
93         _menu_node = xml_doc->createElement("verb");
94         _menu_node->setAttribute("verb-id", this->get_id(), false);
96         if (!hidden)
97             merge_menu(_effects_list->parent(), _effects_list, local_effects_menu, _menu_node);
98     }
100     return;
103 void
104 Effect::merge_menu (Inkscape::XML::Node * base,
105                     Inkscape::XML::Node * start,
106                     Inkscape::XML::Node * patern,
107                     Inkscape::XML::Node * mergee) {
108     Glib::ustring mergename;
109     Inkscape::XML::Node * tomerge = NULL;
110     Inkscape::XML::Node * submenu = NULL;
112     /* printf("Merge menu with '%s' '%s' '%s'\n",
113             base != NULL ? base->name() : "NULL",
114             patern != NULL ? patern->name() : "NULL",
115             mergee != NULL ? mergee->name() : "NULL"); */
117     if (patern == NULL) {
118         // Merge the verb name
119         tomerge = mergee;
120         mergename = _(this->get_name());
121     } else {
122         gchar const * menuname = patern->attribute("name");
123         if (menuname == NULL) menuname = patern->attribute("_name");
124         if (menuname == NULL) return;
125         
126         Inkscape::XML::Document *xml_doc;
127         xml_doc = base->document();
128         tomerge = xml_doc->createElement("submenu");
129         tomerge->setAttribute("name", menuname, false);
131         mergename = _(menuname);
132     }
134     int position = -1;
136     if (start != NULL) {
137         Inkscape::XML::Node * menupass;
138         for (menupass = start->next(); menupass != NULL; menupass = menupass->next()) {
139             gchar const * compare_char = NULL;
140             if (!strcmp(menupass->name(), "verb")) {
141                 gchar const * verbid = menupass->attribute("verb-id");
142                 Inkscape::Verb * verb = Inkscape::Verb::getbyid(verbid);
143                 if (verb == NULL) {
144                     continue;
145                 }
146                 compare_char = verb->get_name();
147             } else if (!strcmp(menupass->name(), "submenu")) {
148                 compare_char = menupass->attribute("name");
149                 if (compare_char == NULL)
150                     compare_char = menupass->attribute("_name");
151             }
153             /* This will cause us to skip tags we don't understand */
154             if (compare_char == NULL) {
155                 continue;
156             }
158             Glib::ustring compare(_(compare_char));
160             if (mergename == compare) {
161                 Inkscape::GC::release(tomerge);
162                 tomerge = NULL;
163                 submenu = menupass;
164                 break;
165             }
167             if (mergename < compare) {
168                 position = menupass->position();
169                 break;
170             }
171         } // for menu items
172     } // start != NULL
174     if (tomerge != NULL) {
175         base->appendChild(tomerge);
176         Inkscape::GC::release(tomerge);
177         if (position != -1)
178             tomerge->setPosition(position);
179     }
181     if (patern != NULL) {
182         if (submenu == NULL)
183             submenu = tomerge;
184         merge_menu(submenu, submenu->firstChild(), patern->firstChild(), mergee);
185     }
187     return;
190 Effect::~Effect (void)
192     if (get_last_effect() == this)
193         set_last_effect(NULL);
194     if (_menu_node)
195         Inkscape::GC::release(_menu_node);
196     return;
199 bool
200 Effect::check (void)
202     if (!Extension::check()) {
203         /** \todo  Check to see if parent has this as its only child,
204                    if so, delete it too */
205         if (_menu_node != NULL)
206             sp_repr_unparent(_menu_node);
207         _menu_node = NULL;
208         return false;
209     }
210     return true;
213 bool
214 Effect::prefs (Inkscape::UI::View::View * doc)
216     if (_prefDialog != NULL) {
217         _prefDialog->raise();
218         return true;
219     }
221     if (param_visible_count() == 0) {
222         effect(doc);
223         return true;
224     }
226     if (!loaded())
227         set_state(Extension::STATE_LOADED);
228     if (!loaded()) return false;
230     _prefDialog = new PrefDialog(this->get_name(), this->get_help(), NULL, this);
231     _prefDialog->show();
233     return true;
236 /**
237     \brief  The function that 'does' the effect itself
238     \param  doc  The Inkscape::UI::View::View to do the effect on
240     This function first insures that the extension is loaded, and if not,
241     loads it.  It then calls the implemention to do the actual work.  It
242     also resets the last effect pointer to be this effect.  Finally, it
243     executes a \c sp_document_done to commit the changes to the undo
244     stack.
245 */
246 void
247 Effect::effect (Inkscape::UI::View::View * doc)
249     //printf("Execute effect\n");
250     if (!loaded())
251         set_state(Extension::STATE_LOADED);
252     if (!loaded()) return;
255     ExecutionEnv executionEnv(this, doc);
256     timer->lock();
257     executionEnv.run();
258     if (executionEnv.wait()) {
259         executionEnv.commit();
260     } else {
261         executionEnv.cancel();
262     }
263     timer->unlock();
265     return;
268 /** \brief  Sets which effect was called last
269     \param in_effect  The effect that has been called
270     
271     This function sets the static variable \c _last_effect and it
272     ensures that the last effect verb is sensitive.
274     If the \c in_effect variable is \c NULL then the last effect
275     verb is made insesitive.
276 */
277 void
278 Effect::set_last_effect (Effect * in_effect)
280     if (in_effect == NULL) {
281         Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, false);
282         Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, false);
283     } else if (_last_effect == NULL) {
284         Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, true);
285         Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, true);
286     }
288     _last_effect = in_effect;
289     return;
292 #define  EFFECTS_LIST  "effects-list"
294 bool
295 Effect::find_effects_list (Inkscape::XML::Node * menustruct)
297     if (menustruct == NULL) return false;
298     for (Inkscape::XML::Node * child = menustruct;
299             child != NULL;
300             child = child->next()) {
301         if (!strcmp(child->name(), EFFECTS_LIST)) {
302             _effects_list = child;
303             return true;
304         }
305         Inkscape::XML::Node * firstchild = child->firstChild();
306         if (firstchild != NULL)
307             if (find_effects_list(firstchild))
308                 return true;
309     }
310     return false;
313 Gtk::VBox *
314 Effect::get_info_widget(void)
316     return Extension::get_info_widget();
319 void
320 Effect::set_pref_dialog (PrefDialog * prefdialog)
322     _prefDialog = prefdialog;
323     return;
326 /** \brief  Create an action for a \c EffectVerb
327     \param  view  Which view the action should be created for
328     \return The built action.
330     Calls \c make_action_helper with the \c vector.
331 */
332 SPAction *
333 Effect::EffectVerb::make_action (Inkscape::UI::View::View * view)
335     return make_action_helper(view, &vector, static_cast<void *>(this));
338 /** \brief  Decode the verb code and take appropriate action */
339 void
340 Effect::EffectVerb::perform( SPAction *action, void * data, void */*pdata*/ )
342     Inkscape::UI::View::View * current_view = sp_action_get_view(action);
343 //  SPDocument * current_document = current_view->doc;
344     Effect::EffectVerb * ev = reinterpret_cast<Effect::EffectVerb *>(data);
345     Effect * effect = ev->_effect;
347     if (effect == NULL) return;
348     if (current_view == NULL) return;
350     if (ev->_showPrefs) {
351         effect->prefs(current_view);
352     } else {
353         effect->effect(current_view);
354     }
356     return;
359 /**
360  * Action vector to define functions called if a staticly defined file verb
361  * is called.
362  */
363 SPActionEventVector Effect::EffectVerb::vector =
364             {{NULL}, Effect::EffectVerb::perform, NULL, NULL, NULL, NULL};
367 } }  /* namespace Inkscape, Extension */
369 /*
370   Local Variables:
371   mode:c++
372   c-file-style:"stroustrup"
373   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
374   indent-tabs-mode:nil
375   fill-column:99
376   End:
377 */
378 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :