Code

fix linking
[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;
51     if (repr != NULL) {
53         for (Inkscape::XML::Node *child = sp_repr_children(repr); child != NULL; child = child->next()) {
54             if (!strcmp(child->name(), "effect")) {
55                 if (child->attribute("needs-document") && !strcmp(child->attribute("needs-document"), "no")) {
56                   no_doc = true;
57                 }
58                 for (Inkscape::XML::Node *effect_child = sp_repr_children(child); effect_child != NULL; effect_child = effect_child->next()) {
59                     if (!strcmp(effect_child->name(), "effects-menu")) {
60                         // printf("Found local effects menu in %s\n", this->get_name());
61                         local_effects_menu = sp_repr_children(effect_child);
62                         if (effect_child->attribute("hidden") && !strcmp(effect_child->attribute("hidden"), "yes")) {
63                             hidden = true;
64                         }
65                     }
66                     if (!strcmp(effect_child->name(), "menu-name") ||
67                             !strcmp(effect_child->name(), "_menu-name")) {
68                         // printf("Found local effects menu in %s\n", this->get_name());
69                         _verb.set_name(sp_repr_children(effect_child)->content());
70                     }
71                     if (!strcmp(effect_child->name(), "menu-tip") ||
72                             !strcmp(effect_child->name(), "_menu-tip")) {
73                         // printf("Found local effects menu in %s\n", this->get_name());
74                         _verb.set_tip(sp_repr_children(effect_child)->content());
75                     }
76                 } // children of "effect"
77                 break; // there can only be one effect
78             } // find "effect"
79         } // children of "inkscape-extension"
80     } // if we have an XML file
82     if (_effects_list == NULL && INKSCAPE != NULL) {
83         find_effects_list(inkscape_get_menus(INKSCAPE));
84     }
86     if (_effects_list != NULL) {
87         Inkscape::XML::Document *xml_doc;
88         xml_doc = _effects_list->document();
89         _menu_node = xml_doc->createElement("verb");
90         _menu_node->setAttribute("verb-id", this->get_id(), false);
92         if (!hidden)
93             merge_menu(_effects_list->parent(), _effects_list, local_effects_menu, _menu_node);
94     }
96     return;
97 }
99 void
100 Effect::merge_menu (Inkscape::XML::Node * base,
101                     Inkscape::XML::Node * start,
102                     Inkscape::XML::Node * patern,
103                     Inkscape::XML::Node * mergee) {
104     Glib::ustring mergename;
105     Inkscape::XML::Node * tomerge = NULL;
106     Inkscape::XML::Node * submenu = NULL;
108     /* printf("Merge menu with '%s' '%s' '%s'\n",
109             base != NULL ? base->name() : "NULL",
110             patern != NULL ? patern->name() : "NULL",
111             mergee != NULL ? mergee->name() : "NULL"); */
113     if (patern == NULL) {
114         // Merge the verb name
115         tomerge = mergee;
116         mergename = _(this->get_name());
117     } else {
118         gchar const * menuname = patern->attribute("name");
119         if (menuname == NULL) menuname = patern->attribute("_name");
120         if (menuname == NULL) return;
121         
122         Inkscape::XML::Document *xml_doc;
123         xml_doc = base->document();
124         tomerge = xml_doc->createElement("submenu");
125         tomerge->setAttribute("name", menuname, false);
127         mergename = _(menuname);
128     }
130     int position = -1;
132     if (start != NULL) {
133         Inkscape::XML::Node * menupass;
134         for (menupass = start->next(); menupass != NULL; menupass = menupass->next()) {
135             gchar const * compare_char = NULL;
136             if (!strcmp(menupass->name(), "verb")) {
137                 gchar const * verbid = menupass->attribute("verb-id");
138                 Inkscape::Verb * verb = Inkscape::Verb::getbyid(verbid);
139                 if (verb == NULL) {
140                     continue;
141                 }
142                 compare_char = verb->get_name();
143             } else if (!strcmp(menupass->name(), "submenu")) {
144                 compare_char = menupass->attribute("name");
145                 if (compare_char == NULL)
146                     compare_char = menupass->attribute("_name");
147             }
149             /* This will cause us to skip tags we don't understand */
150             if (compare_char == NULL) {
151                 continue;
152             }
154             Glib::ustring compare(_(compare_char));
156             if (mergename == compare) {
157                 Inkscape::GC::release(tomerge);
158                 tomerge = NULL;
159                 submenu = menupass;
160                 break;
161             }
163             if (mergename < compare) {
164                 position = menupass->position();
165                 break;
166             }
167         } // for menu items
168     } // start != NULL
170     if (tomerge != NULL) {
171         base->appendChild(tomerge);
172         Inkscape::GC::release(tomerge);
173         if (position != -1)
174             tomerge->setPosition(position);
175     }
177     if (patern != NULL) {
178         if (submenu == NULL)
179             submenu = tomerge;
180         merge_menu(submenu, submenu->firstChild(), patern->firstChild(), mergee);
181     }
183     return;
186 Effect::~Effect (void)
188     if (get_last_effect() == this)
189         set_last_effect(NULL);
190     return;
193 bool
194 Effect::check (void)
196     if (!Extension::check()) {
197         /** \todo  Check to see if parent has this as its only child,
198                    if so, delete it too */
199         if (_menu_node != NULL)
200             sp_repr_unparent(_menu_node);
201         _menu_node = NULL;
202         return false;
203     }
204     return true;
207 bool
208 Effect::prefs (Inkscape::UI::View::View * doc)
210     if (_prefDialog != NULL) {
211         _prefDialog->raise();
212         return true;
213     }
215     if (!loaded())
216         set_state(Extension::STATE_LOADED);
217     if (!loaded()) return false;
219     sigc::signal<void> * changeSignal = new sigc::signal<void>;
221     Gtk::Widget * controls;
222         Implementation::ImplementationDocumentCache * docCache = imp->newDocCache(this, doc);
223     controls = imp->prefs_effect(this, doc, changeSignal, docCache);
225     ExecutionEnv executionEnv(this, doc, controls, changeSignal, NULL, docCache);
227     timer->lock();
228     executionEnv.run();
229     timer->unlock();
231     return true;
234 /**
235     \brief  The function that 'does' the effect itself
236     \param  doc  The Inkscape::UI::View::View to do the effect on
238     This function first insures that the extension is loaded, and if not,
239     loads it.  It then calls the implemention to do the actual work.  It
240     also resets the last effect pointer to be this effect.  Finally, it
241     executes a \c sp_document_done to commit the changes to the undo
242     stack.
243 */
244 void
245 Effect::effect (Inkscape::UI::View::View * doc)
247     //printf("Execute effect\n");
248     if (!loaded())
249         set_state(Extension::STATE_LOADED);
250     if (!loaded()) return;
253     ExecutionEnv executionEnv(this, doc, NULL);
254     executionEnv.run();
256     return;
259 /** \brief  Sets which effect was called last
260     \param in_effect  The effect that has been called
261     
262     This function sets the static variable \c _last_effect and it
263     ensures that the last effect verb is sensitive.
265     If the \c in_effect variable is \c NULL then the last effect
266     verb is made insesitive.
267 */
268 void
269 Effect::set_last_effect (Effect * in_effect)
271     if (in_effect == NULL) {
272         Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, false);
273         Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, false);
274     } else if (_last_effect == NULL) {
275         Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, true);
276         Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, true);
277     }
279     _last_effect = in_effect;
280     return;
283 #define  EFFECTS_LIST  "effects-list"
285 bool
286 Effect::find_effects_list (Inkscape::XML::Node * menustruct)
288     if (menustruct == NULL) return false;
289     for (Inkscape::XML::Node * child = menustruct;
290             child != NULL;
291             child = child->next()) {
292         if (!strcmp(child->name(), EFFECTS_LIST)) {
293             _effects_list = child;
294             return true;
295         }
296         Inkscape::XML::Node * firstchild = child->firstChild();
297         if (firstchild != NULL)
298             if (find_effects_list(firstchild))
299                 return true;
300     }
301     return false;
304 Gtk::VBox *
305 Effect::get_info_widget(void)
307     return Extension::get_info_widget();
310 void
311 Effect::set_pref_dialog (PrefDialog * prefdialog)
313     _prefDialog = prefdialog;
314     if (_prefDialog == NULL) {
315         timer->unlock();
316     } else {
317         timer->lock();
318     }
319     return;
322 /** \brief  Create an action for a \c EffectVerb
323     \param  view  Which view the action should be created for
324     \return The built action.
326     Calls \c make_action_helper with the \c vector.
327 */
328 SPAction *
329 Effect::EffectVerb::make_action (Inkscape::UI::View::View * view)
331     return make_action_helper(view, &vector, static_cast<void *>(this));
334 /** \brief  Decode the verb code and take appropriate action */
335 void
336 Effect::EffectVerb::perform( SPAction *action, void * data, void */*pdata*/ )
338     Inkscape::UI::View::View * current_view = sp_action_get_view(action);
339 //  SPDocument * current_document = current_view->doc;
340     Effect::EffectVerb * ev = reinterpret_cast<Effect::EffectVerb *>(data);
341     Effect * effect = ev->_effect;
343     if (effect == NULL) return;
344     if (current_view == NULL) return;
346     if (ev->_showPrefs) {
347         effect->prefs(current_view);
348     } else {
349         effect->effect(current_view);
350     }
352     return;
355 /**
356  * Action vector to define functions called if a staticly defined file verb
357  * is called.
358  */
359 SPActionEventVector Effect::EffectVerb::vector =
360             {{NULL}, Effect::EffectVerb::perform, NULL, NULL, NULL, NULL};
363 } }  /* namespace Inkscape, Extension */
365 /*
366   Local Variables:
367   mode:c++
368   c-file-style:"stroustrup"
369   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
370   indent-tabs-mode:nil
371   fill-column:99
372   End:
373 */
374 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :