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 {
40 Inkscape::XML::Node * local_effects_menu = NULL;
42 // This is a weird hack
43 if (!strcmp(this->get_id(), "org.inkscape.filter.dropshadow"))
44 return;
46 bool hidden = false;
48 no_doc = false;
50 if (repr != NULL) {
52 for (Inkscape::XML::Node *child = sp_repr_children(repr); child != NULL; child = child->next()) {
53 if (!strcmp(child->name(), "effect")) {
54 if (child->attribute("needs-document") && !strcmp(child->attribute("needs-document"), "no")) {
55 no_doc = true;
56 }
57 for (Inkscape::XML::Node *effect_child = sp_repr_children(child); effect_child != NULL; effect_child = effect_child->next()) {
58 if (!strcmp(effect_child->name(), "effects-menu")) {
59 // printf("Found local effects menu in %s\n", this->get_name());
60 local_effects_menu = sp_repr_children(effect_child);
61 if (effect_child->attribute("hidden") && !strcmp(effect_child->attribute("hidden"), "yes")) {
62 hidden = true;
63 }
64 }
65 if (!strcmp(effect_child->name(), "menu-name") ||
66 !strcmp(effect_child->name(), "_menu-name")) {
67 // printf("Found local effects menu in %s\n", this->get_name());
68 _verb.set_name(sp_repr_children(effect_child)->content());
69 }
70 if (!strcmp(effect_child->name(), "menu-tip") ||
71 !strcmp(effect_child->name(), "_menu-tip")) {
72 // printf("Found local effects menu in %s\n", this->get_name());
73 _verb.set_tip(sp_repr_children(effect_child)->content());
74 }
75 } // children of "effect"
76 break; // there can only be one effect
77 } // find "effect"
78 } // children of "inkscape-extension"
79 } // if we have an XML file
81 if (_effects_list == NULL && INKSCAPE != NULL) {
82 find_effects_list(inkscape_get_menus(INKSCAPE));
83 }
85 if (_effects_list != NULL) {
86 Inkscape::XML::Document *xml_doc;
87 xml_doc = _effects_list->document();
88 _menu_node = xml_doc->createElement("verb");
89 _menu_node->setAttribute("verb-id", this->get_id(), false);
91 if (!hidden)
92 merge_menu(_effects_list->parent(), _effects_list, local_effects_menu, _menu_node);
93 }
95 return;
96 }
98 void
99 Effect::merge_menu (Inkscape::XML::Node * base,
100 Inkscape::XML::Node * start,
101 Inkscape::XML::Node * patern,
102 Inkscape::XML::Node * mergee) {
103 Glib::ustring mergename;
104 Inkscape::XML::Node * tomerge = NULL;
105 Inkscape::XML::Node * submenu = NULL;
107 /* printf("Merge menu with '%s' '%s' '%s'\n",
108 base != NULL ? base->name() : "NULL",
109 patern != NULL ? patern->name() : "NULL",
110 mergee != NULL ? mergee->name() : "NULL"); */
112 if (patern == NULL) {
113 // Merge the verb name
114 tomerge = mergee;
115 mergename = _(this->get_name());
116 } else {
117 gchar const * menuname = patern->attribute("name");
118 if (menuname == NULL) menuname = patern->attribute("_name");
119 if (menuname == NULL) return;
121 Inkscape::XML::Document *xml_doc;
122 xml_doc = base->document();
123 tomerge = xml_doc->createElement("submenu");
124 tomerge->setAttribute("name", menuname, false);
126 mergename = _(menuname);
127 }
129 int position = -1;
131 if (start != NULL) {
132 Inkscape::XML::Node * menupass;
133 for (menupass = start->next(); menupass != NULL; menupass = menupass->next()) {
134 gchar const * compare_char = NULL;
135 if (!strcmp(menupass->name(), "verb")) {
136 gchar const * verbid = menupass->attribute("verb-id");
137 Inkscape::Verb * verb = Inkscape::Verb::getbyid(verbid);
138 if (verb == NULL) {
139 continue;
140 }
141 compare_char = verb->get_name();
142 } else if (!strcmp(menupass->name(), "submenu")) {
143 compare_char = menupass->attribute("name");
144 if (compare_char == NULL)
145 compare_char = menupass->attribute("_name");
146 }
148 /* This will cause us to skip tags we don't understand */
149 if (compare_char == NULL) {
150 continue;
151 }
153 Glib::ustring compare(_(compare_char));
155 if (mergename == compare) {
156 Inkscape::GC::release(tomerge);
157 tomerge = NULL;
158 submenu = menupass;
159 break;
160 }
162 if (mergename < compare) {
163 position = menupass->position();
164 break;
165 }
166 } // for menu items
167 } // start != NULL
169 if (tomerge != NULL) {
170 base->appendChild(tomerge);
171 Inkscape::GC::release(tomerge);
172 if (position != -1)
173 tomerge->setPosition(position);
174 }
176 if (patern != NULL) {
177 if (submenu == NULL)
178 submenu = tomerge;
179 merge_menu(submenu, submenu->firstChild(), patern->firstChild(), mergee);
180 }
182 return;
183 }
185 Effect::~Effect (void)
186 {
187 if (get_last_effect() == this)
188 set_last_effect(NULL);
189 return;
190 }
192 bool
193 Effect::check (void)
194 {
195 if (!Extension::check()) {
196 /** \todo Check to see if parent has this as its only child,
197 if so, delete it too */
198 if (_menu_node != NULL)
199 sp_repr_unparent(_menu_node);
200 _menu_node = NULL;
201 return false;
202 }
203 return true;
204 }
206 bool
207 Effect::prefs (Inkscape::UI::View::View * doc)
208 {
209 if (!loaded())
210 set_state(Extension::STATE_LOADED);
211 if (!loaded()) return false;
213 sigc::signal<void> changeSignal;
215 Gtk::Widget * controls;
216 controls = imp->prefs_effect(this, doc, &changeSignal);
218 ExecutionEnv executionEnv(this, doc, controls);
219 changeSignal.connect(sigc::mem_fun(executionEnv, &ExecutionEnv::preferencesChange));
221 timer->lock();
222 executionEnv.run();
223 timer->unlock();
225 return true;
226 }
228 /**
229 \brief The function that 'does' the effect itself
230 \param doc The Inkscape::UI::View::View to do the effect on
232 This function first insures that the extension is loaded, and if not,
233 loads it. It then calls the implemention to do the actual work. It
234 also resets the last effect pointer to be this effect. Finally, it
235 executes a \c sp_document_done to commit the changes to the undo
236 stack.
237 */
238 void
239 Effect::effect (Inkscape::UI::View::View * doc)
240 {
241 if (!loaded())
242 set_state(Extension::STATE_LOADED);
243 if (!loaded()) return;
246 ExecutionEnv executionEnv(this, doc, NULL);
247 executionEnv.run();
249 return;
250 }
252 /** \brief Sets which effect was called last
253 \param in_effect The effect that has been called
255 This function sets the static variable \c _last_effect and it
256 ensures that the last effect verb is sensitive.
258 If the \c in_effect variable is \c NULL then the last effect
259 verb is made insesitive.
260 */
261 void
262 Effect::set_last_effect (Effect * in_effect)
263 {
264 if (in_effect == NULL) {
265 Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, false);
266 Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, false);
267 } else if (_last_effect == NULL) {
268 Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, true);
269 Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, true);
270 }
272 _last_effect = in_effect;
273 return;
274 }
276 #define EFFECTS_LIST "effects-list"
278 bool
279 Effect::find_effects_list (Inkscape::XML::Node * menustruct)
280 {
281 if (menustruct == NULL) return false;
282 for (Inkscape::XML::Node * child = menustruct;
283 child != NULL;
284 child = child->next()) {
285 if (!strcmp(child->name(), EFFECTS_LIST)) {
286 _effects_list = child;
287 return true;
288 }
289 Inkscape::XML::Node * firstchild = child->firstChild();
290 if (firstchild != NULL)
291 if (find_effects_list(firstchild))
292 return true;
293 }
294 return false;
295 }
297 Gtk::VBox *
298 Effect::get_info_widget(void)
299 {
300 return Extension::get_info_widget();
301 }
303 /** \brief Create an action for a \c EffectVerb
304 \param view Which view the action should be created for
305 \return The built action.
307 Calls \c make_action_helper with the \c vector.
308 */
309 SPAction *
310 Effect::EffectVerb::make_action (Inkscape::UI::View::View * view)
311 {
312 return make_action_helper(view, &vector, static_cast<void *>(this));
313 }
315 /** \brief Decode the verb code and take appropriate action */
316 void
317 Effect::EffectVerb::perform (SPAction *action, void * data, void *pdata)
318 {
319 Inkscape::UI::View::View * current_view = sp_action_get_view(action);
320 // SPDocument * current_document = current_view->doc;
321 Effect::EffectVerb * ev = reinterpret_cast<Effect::EffectVerb *>(data);
322 Effect * effect = ev->_effect;
324 if (effect == NULL) return;
325 if (current_view == NULL) return;
327 if (ev->_showPrefs) {
328 effect->prefs(current_view);
329 } else {
330 effect->effect(current_view);
331 }
333 return;
334 }
336 /**
337 * Action vector to define functions called if a staticly defined file verb
338 * is called.
339 */
340 SPActionEventVector Effect::EffectVerb::vector =
341 {{NULL}, Effect::EffectVerb::perform, NULL, NULL, NULL, NULL};
344 } } /* namespace Inkscape, Extension */
346 /*
347 Local Variables:
348 mode:c++
349 c-file-style:"stroustrup"
350 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
351 indent-tabs-mode:nil
352 fill-column:99
353 End:
354 */
355 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :