Code

r17818@shi: ted | 2008-01-31 09:20:06 -0800
[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     timer->lock();
255     executionEnv.run();
256     timer->unlock();
258     return;
261 /** \brief  Sets which effect was called last
262     \param in_effect  The effect that has been called
263     
264     This function sets the static variable \c _last_effect and it
265     ensures that the last effect verb is sensitive.
267     If the \c in_effect variable is \c NULL then the last effect
268     verb is made insesitive.
269 */
270 void
271 Effect::set_last_effect (Effect * in_effect)
273     if (in_effect == NULL) {
274         Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, false);
275         Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, false);
276     } else if (_last_effect == NULL) {
277         Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, true);
278         Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, true);
279     }
281     _last_effect = in_effect;
282     return;
285 #define  EFFECTS_LIST  "effects-list"
287 bool
288 Effect::find_effects_list (Inkscape::XML::Node * menustruct)
290     if (menustruct == NULL) return false;
291     for (Inkscape::XML::Node * child = menustruct;
292             child != NULL;
293             child = child->next()) {
294         if (!strcmp(child->name(), EFFECTS_LIST)) {
295             _effects_list = child;
296             return true;
297         }
298         Inkscape::XML::Node * firstchild = child->firstChild();
299         if (firstchild != NULL)
300             if (find_effects_list(firstchild))
301                 return true;
302     }
303     return false;
306 Gtk::VBox *
307 Effect::get_info_widget(void)
309     return Extension::get_info_widget();
312 void
313 Effect::set_pref_dialog (PrefDialog * prefdialog)
315     _prefDialog = prefdialog;
316     if (_prefDialog == NULL) {
317         timer->unlock();
318     } else {
319         timer->lock();
320     }
321     return;
324 /** \brief  Create an action for a \c EffectVerb
325     \param  view  Which view the action should be created for
326     \return The built action.
328     Calls \c make_action_helper with the \c vector.
329 */
330 SPAction *
331 Effect::EffectVerb::make_action (Inkscape::UI::View::View * view)
333     return make_action_helper(view, &vector, static_cast<void *>(this));
336 /** \brief  Decode the verb code and take appropriate action */
337 void
338 Effect::EffectVerb::perform( SPAction *action, void * data, void */*pdata*/ )
340     Inkscape::UI::View::View * current_view = sp_action_get_view(action);
341 //  SPDocument * current_document = current_view->doc;
342     Effect::EffectVerb * ev = reinterpret_cast<Effect::EffectVerb *>(data);
343     Effect * effect = ev->_effect;
345     if (effect == NULL) return;
346     if (current_view == NULL) return;
348     if (ev->_showPrefs) {
349         effect->prefs(current_view);
350     } else {
351         effect->effect(current_view);
352     }
354     return;
357 /**
358  * Action vector to define functions called if a staticly defined file verb
359  * is called.
360  */
361 SPActionEventVector Effect::EffectVerb::vector =
362             {{NULL}, Effect::EffectVerb::perform, NULL, NULL, NULL, NULL};
365 } }  /* namespace Inkscape, Extension */
367 /*
368   Local Variables:
369   mode:c++
370   c-file-style:"stroustrup"
371   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
372   indent-tabs-mode:nil
373   fill-column:99
374   End:
375 */
376 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :