2010e253a6429d0e3831edd256b8a53615cd3f81
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(), "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(), "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(), "menu-name") ||
71 !strcmp(effect_child->name(), "_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(), "menu-tip") ||
76 !strcmp(effect_child->name(), "_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;
101 }
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;
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;
188 }
190 Effect::~Effect (void)
191 {
192 if (get_last_effect() == this)
193 set_last_effect(NULL);
194 return;
195 }
197 bool
198 Effect::check (void)
199 {
200 if (!Extension::check()) {
201 /** \todo Check to see if parent has this as its only child,
202 if so, delete it too */
203 if (_menu_node != NULL)
204 sp_repr_unparent(_menu_node);
205 _menu_node = NULL;
206 return false;
207 }
208 return true;
209 }
211 bool
212 Effect::prefs (Inkscape::UI::View::View * doc)
213 {
214 if (_prefDialog != NULL) {
215 _prefDialog->raise();
216 return true;
217 }
219 if (param_visible_count() == 0) {
220 effect(doc);
221 return true;
222 }
224 if (!loaded())
225 set_state(Extension::STATE_LOADED);
226 if (!loaded()) return false;
228 _prefDialog = new PrefDialog(this->get_name(), this->get_help(), NULL, this);
229 _prefDialog->show();
231 return true;
232 }
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)
246 {
247 //printf("Execute effect\n");
248 if (!loaded())
249 set_state(Extension::STATE_LOADED);
250 if (!loaded()) return;
253 ExecutionEnv executionEnv(this, doc);
254 timer->lock();
255 executionEnv.run();
256 if (executionEnv.wait()) {
257 executionEnv.commit();
258 } else {
259 executionEnv.cancel();
260 }
261 timer->unlock();
263 return;
264 }
266 /** \brief Sets which effect was called last
267 \param in_effect The effect that has been called
269 This function sets the static variable \c _last_effect and it
270 ensures that the last effect verb is sensitive.
272 If the \c in_effect variable is \c NULL then the last effect
273 verb is made insesitive.
274 */
275 void
276 Effect::set_last_effect (Effect * in_effect)
277 {
278 if (in_effect == NULL) {
279 Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, false);
280 Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, false);
281 } else if (_last_effect == NULL) {
282 Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, true);
283 Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, true);
284 }
286 _last_effect = in_effect;
287 return;
288 }
290 #define EFFECTS_LIST "effects-list"
292 bool
293 Effect::find_effects_list (Inkscape::XML::Node * menustruct)
294 {
295 if (menustruct == NULL) return false;
296 for (Inkscape::XML::Node * child = menustruct;
297 child != NULL;
298 child = child->next()) {
299 if (!strcmp(child->name(), EFFECTS_LIST)) {
300 _effects_list = child;
301 return true;
302 }
303 Inkscape::XML::Node * firstchild = child->firstChild();
304 if (firstchild != NULL)
305 if (find_effects_list(firstchild))
306 return true;
307 }
308 return false;
309 }
311 Gtk::VBox *
312 Effect::get_info_widget(void)
313 {
314 return Extension::get_info_widget();
315 }
317 void
318 Effect::set_pref_dialog (PrefDialog * prefdialog)
319 {
320 _prefDialog = prefdialog;
321 return;
322 }
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)
332 {
333 return make_action_helper(view, &vector, static_cast<void *>(this));
334 }
336 /** \brief Decode the verb code and take appropriate action */
337 void
338 Effect::EffectVerb::perform( SPAction *action, void * data, void */*pdata*/ )
339 {
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;
355 }
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 :