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;
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; 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 g_warning("Unable to find verb '%s' which is referred to in the menus.", verbid);
145 continue;
146 }
147 compare_char = verb->get_name();
148 } else if (!strcmp(menupass->name(), "submenu")) {
149 compare_char = menupass->attribute("name");
150 if (compare_char == NULL)
151 compare_char = menupass->attribute("_name");
152 }
154 /* This will cause us to skip tags we don't understand */
155 if (compare_char == NULL) {
156 continue;
157 }
159 Glib::ustring compare(_(compare_char));
161 if (mergename == compare) {
162 Inkscape::GC::release(tomerge);
163 tomerge = NULL;
164 submenu = menupass;
165 break;
166 }
168 if (mergename < compare) {
169 position = menupass->position();
170 break;
171 }
172 } // for menu items
173 } // start != NULL
175 if (tomerge != NULL) {
176 base->appendChild(tomerge);
177 Inkscape::GC::release(tomerge);
178 if (position != -1)
179 tomerge->setPosition(position);
180 }
182 if (patern != NULL) {
183 if (submenu == NULL)
184 submenu = tomerge;
185 merge_menu(submenu, submenu->firstChild(), patern->firstChild(), mergee);
186 }
188 return;
189 }
191 Effect::~Effect (void)
192 {
193 if (get_last_effect() == this)
194 set_last_effect(NULL);
195 if (_menu_node)
196 Inkscape::GC::release(_menu_node);
197 return;
198 }
200 bool
201 Effect::check (void)
202 {
203 if (!Extension::check()) {
204 /** \todo Check to see if parent has this as its only child,
205 if so, delete it too */
206 if (_menu_node != NULL)
207 sp_repr_unparent(_menu_node);
208 _menu_node = NULL;
209 return false;
210 }
211 return true;
212 }
214 bool
215 Effect::prefs (Inkscape::UI::View::View * doc)
216 {
217 if (_prefDialog != NULL) {
218 _prefDialog->raise();
219 return true;
220 }
222 if (param_visible_count() == 0) {
223 effect(doc);
224 return true;
225 }
227 if (!loaded())
228 set_state(Extension::STATE_LOADED);
229 if (!loaded()) return false;
231 _prefDialog = new PrefDialog(this->get_name(), this->get_help(), NULL, this);
232 _prefDialog->show();
234 return true;
235 }
237 /**
238 \brief The function that 'does' the effect itself
239 \param doc The Inkscape::UI::View::View to do the effect on
241 This function first insures that the extension is loaded, and if not,
242 loads it. It then calls the implemention to do the actual work. It
243 also resets the last effect pointer to be this effect. Finally, it
244 executes a \c sp_document_done to commit the changes to the undo
245 stack.
246 */
247 void
248 Effect::effect (Inkscape::UI::View::View * doc)
249 {
250 //printf("Execute effect\n");
251 if (!loaded())
252 set_state(Extension::STATE_LOADED);
253 if (!loaded()) return;
256 ExecutionEnv executionEnv(this, doc);
257 timer->lock();
258 executionEnv.run();
259 if (executionEnv.wait()) {
260 executionEnv.commit();
261 } else {
262 executionEnv.cancel();
263 }
264 timer->unlock();
266 return;
267 }
269 /** \brief Sets which effect was called last
270 \param in_effect The effect that has been called
272 This function sets the static variable \c _last_effect and it
273 ensures that the last effect verb is sensitive.
275 If the \c in_effect variable is \c NULL then the last effect
276 verb is made insesitive.
277 */
278 void
279 Effect::set_last_effect (Effect * in_effect)
280 {
281 if (in_effect == NULL) {
282 Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, false);
283 Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, false);
284 } else if (_last_effect == NULL) {
285 Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, true);
286 Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, true);
287 }
289 _last_effect = in_effect;
290 return;
291 }
293 #define EFFECTS_LIST "effects-list"
295 bool
296 Effect::find_effects_list (Inkscape::XML::Node * menustruct)
297 {
298 if (menustruct == NULL) return false;
299 for (Inkscape::XML::Node * child = menustruct;
300 child != NULL;
301 child = child->next()) {
302 if (!strcmp(child->name(), EFFECTS_LIST)) {
303 _effects_list = child;
304 return true;
305 }
306 Inkscape::XML::Node * firstchild = child->firstChild();
307 if (firstchild != NULL)
308 if (find_effects_list(firstchild))
309 return true;
310 }
311 return false;
312 }
314 Gtk::VBox *
315 Effect::get_info_widget(void)
316 {
317 return Extension::get_info_widget();
318 }
320 void
321 Effect::set_pref_dialog (PrefDialog * prefdialog)
322 {
323 _prefDialog = prefdialog;
324 return;
325 }
327 /** \brief Create an action for a \c EffectVerb
328 \param view Which view the action should be created for
329 \return The built action.
331 Calls \c make_action_helper with the \c vector.
332 */
333 SPAction *
334 Effect::EffectVerb::make_action (Inkscape::UI::View::View * view)
335 {
336 return make_action_helper(view, &vector, static_cast<void *>(this));
337 }
339 /** \brief Decode the verb code and take appropriate action */
340 void
341 Effect::EffectVerb::perform( SPAction *action, void * data, void */*pdata*/ )
342 {
343 Inkscape::UI::View::View * current_view = sp_action_get_view(action);
344 // SPDocument * current_document = current_view->doc;
345 Effect::EffectVerb * ev = reinterpret_cast<Effect::EffectVerb *>(data);
346 Effect * effect = ev->_effect;
348 if (effect == NULL) return;
349 if (current_view == NULL) return;
351 if (ev->_showPrefs) {
352 effect->prefs(current_view);
353 } else {
354 effect->effect(current_view);
355 }
357 return;
358 }
360 /**
361 * Action vector to define functions called if a staticly defined file verb
362 * is called.
363 */
364 SPActionEventVector Effect::EffectVerb::vector =
365 {{NULL}, Effect::EffectVerb::perform, NULL, NULL, NULL, NULL};
368 } } /* namespace Inkscape, Extension */
370 /*
371 Local Variables:
372 mode:c++
373 c-file-style:"stroustrup"
374 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
375 indent-tabs-mode:nil
376 fill-column:99
377 End:
378 */
379 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :