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;
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;
184 }
186 Effect::~Effect (void)
187 {
188 if (get_last_effect() == this)
189 set_last_effect(NULL);
190 return;
191 }
193 bool
194 Effect::check (void)
195 {
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;
205 }
207 bool
208 Effect::prefs (Inkscape::UI::View::View * doc)
209 {
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 SPDesktop * spdesktop = (SPDesktop *)doc;
223 Implementation::ImplementationDocumentCache * docCache = imp->newDocCache(this, spdesktop->doc());
224 controls = imp->prefs_effect(this, doc, changeSignal, docCache);
226 ExecutionEnv executionEnv(this, doc, controls, changeSignal, NULL, docCache);
228 timer->lock();
229 executionEnv.run();
230 timer->unlock();
232 return true;
233 }
235 /**
236 \brief The function that 'does' the effect itself
237 \param doc The Inkscape::UI::View::View to do the effect on
239 This function first insures that the extension is loaded, and if not,
240 loads it. It then calls the implemention to do the actual work. It
241 also resets the last effect pointer to be this effect. Finally, it
242 executes a \c sp_document_done to commit the changes to the undo
243 stack.
244 */
245 void
246 Effect::effect (Inkscape::UI::View::View * doc)
247 {
248 //printf("Execute effect\n");
249 if (!loaded())
250 set_state(Extension::STATE_LOADED);
251 if (!loaded()) return;
254 ExecutionEnv executionEnv(this, doc, NULL);
255 executionEnv.run();
257 return;
258 }
260 /** \brief Sets which effect was called last
261 \param in_effect The effect that has been called
263 This function sets the static variable \c _last_effect and it
264 ensures that the last effect verb is sensitive.
266 If the \c in_effect variable is \c NULL then the last effect
267 verb is made insesitive.
268 */
269 void
270 Effect::set_last_effect (Effect * in_effect)
271 {
272 if (in_effect == NULL) {
273 Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, false);
274 Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, false);
275 } else if (_last_effect == NULL) {
276 Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, true);
277 Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, true);
278 }
280 _last_effect = in_effect;
281 return;
282 }
284 #define EFFECTS_LIST "effects-list"
286 bool
287 Effect::find_effects_list (Inkscape::XML::Node * menustruct)
288 {
289 if (menustruct == NULL) return false;
290 for (Inkscape::XML::Node * child = menustruct;
291 child != NULL;
292 child = child->next()) {
293 if (!strcmp(child->name(), EFFECTS_LIST)) {
294 _effects_list = child;
295 return true;
296 }
297 Inkscape::XML::Node * firstchild = child->firstChild();
298 if (firstchild != NULL)
299 if (find_effects_list(firstchild))
300 return true;
301 }
302 return false;
303 }
305 Gtk::VBox *
306 Effect::get_info_widget(void)
307 {
308 return Extension::get_info_widget();
309 }
311 void
312 Effect::set_pref_dialog (PrefDialog * prefdialog)
313 {
314 _prefDialog = prefdialog;
315 if (_prefDialog == NULL) {
316 timer->unlock();
317 } else {
318 timer->lock();
319 }
320 return;
321 }
323 /** \brief Create an action for a \c EffectVerb
324 \param view Which view the action should be created for
325 \return The built action.
327 Calls \c make_action_helper with the \c vector.
328 */
329 SPAction *
330 Effect::EffectVerb::make_action (Inkscape::UI::View::View * view)
331 {
332 return make_action_helper(view, &vector, static_cast<void *>(this));
333 }
335 /** \brief Decode the verb code and take appropriate action */
336 void
337 Effect::EffectVerb::perform (SPAction *action, void * data, void *pdata)
338 {
339 Inkscape::UI::View::View * current_view = sp_action_get_view(action);
340 // SPDocument * current_document = current_view->doc;
341 Effect::EffectVerb * ev = reinterpret_cast<Effect::EffectVerb *>(data);
342 Effect * effect = ev->_effect;
344 if (effect == NULL) return;
345 if (current_view == NULL) return;
347 if (ev->_showPrefs) {
348 effect->prefs(current_view);
349 } else {
350 effect->effect(current_view);
351 }
353 return;
354 }
356 /**
357 * Action vector to define functions called if a staticly defined file verb
358 * is called.
359 */
360 SPActionEventVector Effect::EffectVerb::vector =
361 {{NULL}, Effect::EffectVerb::perform, NULL, NULL, NULL, NULL};
364 } } /* namespace Inkscape, Extension */
366 /*
367 Local Variables:
368 mode:c++
369 c-file-style:"stroustrup"
370 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
371 indent-tabs-mode:nil
372 fill-column:99
373 End:
374 */
375 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :