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