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