1 /*
2 * Authors:
3 * Ted Gould <ted@gould.cx>
4 *
5 * Copyright (C) 2002-2006 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 "document.h"
13 #include "prefdialog.h"
14 #include "implementation/implementation.h"
15 #include "effect.h"
16 #include "ui/view/view.h"
18 /* Inkscape::Extension::Effect */
20 namespace Inkscape {
21 namespace Extension {
23 Effect * Effect::_last_effect = NULL;
24 Inkscape::XML::Node * Effect::_effects_list = NULL;
26 Effect::Effect (Inkscape::XML::Node * in_repr, Implementation::Implementation * in_imp)
27 : Extension(in_repr, in_imp), _verb(get_id(), get_name(), NULL, NULL, this), _menu_node(NULL)
28 {
29 Inkscape::XML::Node * local_effects_menu = NULL;
31 // This is a weird hack
32 if (!strcmp(this->get_id(), "org.inkscape.filter.dropshadow"))
33 return;
35 bool hidden = false;
37 no_doc = false;
39 if (repr != NULL) {
41 for (Inkscape::XML::Node *child = sp_repr_children(repr); child != NULL; child = child->next()) {
42 if (!strcmp(child->name(), "effect")) {
43 if (child->attribute("needs-document") && !strcmp(child->attribute("needs-document"), "no")) {
44 no_doc = true;
45 }
46 for (Inkscape::XML::Node *effect_child = sp_repr_children(child); effect_child != NULL; effect_child = effect_child->next()) {
47 if (!strcmp(effect_child->name(), "effects-menu")) {
48 // printf("Found local effects menu in %s\n", this->get_name());
49 local_effects_menu = sp_repr_children(effect_child);
50 if (effect_child->attribute("hidden") && !strcmp(effect_child->attribute("hidden"), "yes")) {
51 hidden = true;
52 }
53 }
54 if (!strcmp(effect_child->name(), "menu-name") ||
55 !strcmp(effect_child->name(), "_menu-name")) {
56 // printf("Found local effects menu in %s\n", this->get_name());
57 _verb.set_name(sp_repr_children(effect_child)->content());
58 }
59 if (!strcmp(effect_child->name(), "menu-tip") ||
60 !strcmp(effect_child->name(), "_menu-tip")) {
61 // printf("Found local effects menu in %s\n", this->get_name());
62 _verb.set_tip(sp_repr_children(effect_child)->content());
63 }
64 } // children of "effect"
65 break; // there can only be one effect
66 } // find "effect"
67 } // children of "inkscape-extension"
68 } // if we have an XML file
70 if (_effects_list == NULL)
71 find_effects_list(inkscape_get_menus(INKSCAPE));
73 if (_effects_list != NULL) {
74 Inkscape::XML::Document *xml_doc;
75 xml_doc = _effects_list->document();
76 _menu_node = xml_doc->createElement("verb");
77 _menu_node->setAttribute("verb-id", this->get_id(), false);
79 if (!hidden)
80 merge_menu(_effects_list->parent(), _effects_list, local_effects_menu, _menu_node);
81 }
83 return;
84 }
86 void
87 Effect::merge_menu (Inkscape::XML::Node * base,
88 Inkscape::XML::Node * start,
89 Inkscape::XML::Node * patern,
90 Inkscape::XML::Node * mergee) {
91 Glib::ustring mergename;
92 Inkscape::XML::Node * tomerge = NULL;
93 Inkscape::XML::Node * submenu = NULL;
95 /* printf("Merge menu with '%s' '%s' '%s'\n",
96 base != NULL ? base->name() : "NULL",
97 patern != NULL ? patern->name() : "NULL",
98 mergee != NULL ? mergee->name() : "NULL"); */
100 if (patern == NULL) {
101 // Merge the verb name
102 tomerge = mergee;
103 mergename = _(this->get_name());
104 } else {
105 gchar const * menuname = patern->attribute("name");
106 if (menuname == NULL) menuname = patern->attribute("_name");
107 if (menuname == NULL) return;
109 Inkscape::XML::Document *xml_doc;
110 xml_doc = base->document();
111 tomerge = xml_doc->createElement("submenu");
112 tomerge->setAttribute("name", menuname, false);
114 mergename = _(menuname);
115 }
117 int position = -1;
119 if (start != NULL) {
120 Inkscape::XML::Node * menupass;
121 for (menupass = start->next(); menupass != NULL; menupass = menupass->next()) {
122 gchar const * compare_char = NULL;
123 if (!strcmp(menupass->name(), "verb")) {
124 gchar const * verbid = menupass->attribute("verb-id");
125 Inkscape::Verb * verb = Inkscape::Verb::getbyid(verbid);
126 if (verb == NULL) {
127 continue;
128 }
129 compare_char = verb->get_name();
130 } else if (!strcmp(menupass->name(), "submenu")) {
131 compare_char = menupass->attribute("name");
132 if (compare_char == NULL)
133 compare_char = menupass->attribute("_name");
134 }
136 /* This will cause us to skip tags we don't understand */
137 if (compare_char == NULL) {
138 continue;
139 }
141 Glib::ustring compare(_(compare_char));
143 if (mergename == compare) {
144 Inkscape::GC::release(tomerge);
145 tomerge = NULL;
146 submenu = menupass;
147 break;
148 }
150 if (mergename < compare) {
151 position = menupass->position();
152 break;
153 }
154 } // for menu items
155 } // start != NULL
157 if (tomerge != NULL) {
158 base->appendChild(tomerge);
159 Inkscape::GC::release(tomerge);
160 if (position != -1)
161 tomerge->setPosition(position);
162 }
164 if (patern != NULL) {
165 if (submenu == NULL)
166 submenu = tomerge;
167 merge_menu(submenu, submenu->firstChild(), patern->firstChild(), mergee);
168 }
170 return;
171 }
173 Effect::~Effect (void)
174 {
175 if (get_last_effect() == this)
176 set_last_effect(NULL);
177 return;
178 }
180 bool
181 Effect::check (void)
182 {
183 if (!Extension::check()) {
184 /** \todo Check to see if parent has this as its only child,
185 if so, delete it too */
186 if (_menu_node != NULL)
187 sp_repr_unparent(_menu_node);
188 _menu_node = NULL;
189 return false;
190 }
191 return true;
192 }
194 bool
195 Effect::prefs (Inkscape::UI::View::View * doc)
196 {
197 if (!loaded())
198 set_state(Extension::STATE_LOADED);
199 if (!loaded()) return false;
201 Gtk::Widget * controls;
202 controls = imp->prefs_effect(this, doc);
203 if (controls == NULL) {
204 // std::cout << "No preferences for Effect" << std::endl;
205 return true;
206 }
208 PrefDialog * dialog = new PrefDialog(this->get_name(), this->get_help(), controls);
209 int response = dialog->run();
210 dialog->hide();
212 delete dialog;
214 if (response == Gtk::RESPONSE_OK) return true;
216 return false;
217 }
219 /**
220 \brief The function that 'does' the effect itself
221 \param doc The Inkscape::UI::View::View to do the effect on
223 This function first insures that the extension is loaded, and if not,
224 loads it. It then calls the implemention to do the actual work. It
225 also resets the last effect pointer to be this effect. Finally, it
226 executes a \c sp_document_done to commit the changes to the undo
227 stack.
228 */
229 void
230 Effect::effect (Inkscape::UI::View::View * doc)
231 {
232 if (!loaded())
233 set_state(Extension::STATE_LOADED);
234 if (!loaded()) return;
236 set_last_effect(this);
237 imp->effect(this, doc);
239 sp_document_done(doc->doc(), SP_VERB_NONE, _(this->get_name()));
241 return;
242 }
244 void
245 Effect::set_last_effect (Effect * in_effect)
246 {
247 if (in_effect == NULL) {
248 Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, false);
249 Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, false);
250 } else if (_last_effect == NULL) {
251 Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, true);
252 Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, true);
253 }
255 _last_effect = in_effect;
256 return;
257 }
259 #define EFFECTS_LIST "effects-list"
261 bool
262 Effect::find_effects_list (Inkscape::XML::Node * menustruct)
263 {
264 if (menustruct == NULL) return false;
265 for (Inkscape::XML::Node * child = menustruct;
266 child != NULL;
267 child = child->next()) {
268 if (!strcmp(child->name(), EFFECTS_LIST)) {
269 _effects_list = child;
270 return true;
271 }
272 Inkscape::XML::Node * firstchild = child->firstChild();
273 if (firstchild != NULL)
274 if (find_effects_list(firstchild))
275 return true;
276 }
277 return false;
278 }
280 Gtk::VBox *
281 Effect::get_info_widget(void)
282 {
283 return Extension::get_info_widget();
284 }
286 /** \brief Create an action for a \c EffectVerb
287 \param view Which view the action should be created for
288 \return The built action.
290 Calls \c make_action_helper with the \c vector.
291 */
292 SPAction *
293 Effect::EffectVerb::make_action (Inkscape::UI::View::View * view)
294 {
295 return make_action_helper(view, &vector, static_cast<void *>(_effect));
296 }
298 /** \brief Decode the verb code and take appropriate action */
299 void
300 Effect::EffectVerb::perform (SPAction *action, void * data, void *pdata)
301 {
302 Inkscape::UI::View::View * current_view = sp_action_get_view(action);
303 // SPDocument * current_document = current_view->doc;
304 Effect * effect = reinterpret_cast<Effect *>(data);
306 if (effect == NULL) return;
307 if (current_view == NULL) return;
309 // std::cout << "Executing: " << effect->get_name() << std::endl;
310 if (effect->prefs(current_view))
311 effect->effect(current_view);
313 return;
314 }
316 /**
317 * Action vector to define functions called if a staticly defined file verb
318 * is called.
319 */
320 SPActionEventVector Effect::EffectVerb::vector =
321 {{NULL}, Effect::EffectVerb::perform, NULL, NULL, NULL, NULL};
324 } } /* namespace Inkscape, Extension */
326 /*
327 Local Variables:
328 mode:c++
329 c-file-style:"stroustrup"
330 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
331 indent-tabs-mode:nil
332 fill-column:99
333 End:
334 */
335 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :