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),
28 _id_noprefs(Glib::ustring(get_id()) + ".noprefs"),
29 _name_noprefs(Glib::ustring(get_name()) + _(" (No preferences)")),
30 _verb(get_id(), get_name(), NULL, NULL, this, true),
31 _verb_nopref(_id_noprefs.c_str(), _name_noprefs.c_str(), NULL, NULL, this, false),
32 _menu_node(NULL)
33 {
34 Inkscape::XML::Node * local_effects_menu = NULL;
36 // This is a weird hack
37 if (!strcmp(this->get_id(), "org.inkscape.filter.dropshadow"))
38 return;
40 bool hidden = false;
42 no_doc = false;
44 if (repr != NULL) {
46 for (Inkscape::XML::Node *child = sp_repr_children(repr); child != NULL; child = child->next()) {
47 if (!strcmp(child->name(), "effect")) {
48 if (child->attribute("needs-document") && !strcmp(child->attribute("needs-document"), "no")) {
49 no_doc = true;
50 }
51 for (Inkscape::XML::Node *effect_child = sp_repr_children(child); effect_child != NULL; effect_child = effect_child->next()) {
52 if (!strcmp(effect_child->name(), "effects-menu")) {
53 // printf("Found local effects menu in %s\n", this->get_name());
54 local_effects_menu = sp_repr_children(effect_child);
55 if (effect_child->attribute("hidden") && !strcmp(effect_child->attribute("hidden"), "yes")) {
56 hidden = true;
57 }
58 }
59 if (!strcmp(effect_child->name(), "menu-name") ||
60 !strcmp(effect_child->name(), "_menu-name")) {
61 // printf("Found local effects menu in %s\n", this->get_name());
62 _verb.set_name(sp_repr_children(effect_child)->content());
63 }
64 if (!strcmp(effect_child->name(), "menu-tip") ||
65 !strcmp(effect_child->name(), "_menu-tip")) {
66 // printf("Found local effects menu in %s\n", this->get_name());
67 _verb.set_tip(sp_repr_children(effect_child)->content());
68 }
69 } // children of "effect"
70 break; // there can only be one effect
71 } // find "effect"
72 } // children of "inkscape-extension"
73 } // if we have an XML file
75 if (_effects_list == NULL && INKSCAPE != NULL) {
76 find_effects_list(inkscape_get_menus(INKSCAPE));
77 }
79 if (_effects_list != NULL) {
80 Inkscape::XML::Document *xml_doc;
81 xml_doc = _effects_list->document();
82 _menu_node = xml_doc->createElement("verb");
83 _menu_node->setAttribute("verb-id", this->get_id(), false);
85 if (!hidden)
86 merge_menu(_effects_list->parent(), _effects_list, local_effects_menu, _menu_node);
87 }
89 return;
90 }
92 void
93 Effect::merge_menu (Inkscape::XML::Node * base,
94 Inkscape::XML::Node * start,
95 Inkscape::XML::Node * patern,
96 Inkscape::XML::Node * mergee) {
97 Glib::ustring mergename;
98 Inkscape::XML::Node * tomerge = NULL;
99 Inkscape::XML::Node * submenu = NULL;
101 /* printf("Merge menu with '%s' '%s' '%s'\n",
102 base != NULL ? base->name() : "NULL",
103 patern != NULL ? patern->name() : "NULL",
104 mergee != NULL ? mergee->name() : "NULL"); */
106 if (patern == NULL) {
107 // Merge the verb name
108 tomerge = mergee;
109 mergename = _(this->get_name());
110 } else {
111 gchar const * menuname = patern->attribute("name");
112 if (menuname == NULL) menuname = patern->attribute("_name");
113 if (menuname == NULL) return;
115 Inkscape::XML::Document *xml_doc;
116 xml_doc = base->document();
117 tomerge = xml_doc->createElement("submenu");
118 tomerge->setAttribute("name", menuname, false);
120 mergename = _(menuname);
121 }
123 int position = -1;
125 if (start != NULL) {
126 Inkscape::XML::Node * menupass;
127 for (menupass = start->next(); menupass != NULL; menupass = menupass->next()) {
128 gchar const * compare_char = NULL;
129 if (!strcmp(menupass->name(), "verb")) {
130 gchar const * verbid = menupass->attribute("verb-id");
131 Inkscape::Verb * verb = Inkscape::Verb::getbyid(verbid);
132 if (verb == NULL) {
133 continue;
134 }
135 compare_char = verb->get_name();
136 } else if (!strcmp(menupass->name(), "submenu")) {
137 compare_char = menupass->attribute("name");
138 if (compare_char == NULL)
139 compare_char = menupass->attribute("_name");
140 }
142 /* This will cause us to skip tags we don't understand */
143 if (compare_char == NULL) {
144 continue;
145 }
147 Glib::ustring compare(_(compare_char));
149 if (mergename == compare) {
150 Inkscape::GC::release(tomerge);
151 tomerge = NULL;
152 submenu = menupass;
153 break;
154 }
156 if (mergename < compare) {
157 position = menupass->position();
158 break;
159 }
160 } // for menu items
161 } // start != NULL
163 if (tomerge != NULL) {
164 base->appendChild(tomerge);
165 Inkscape::GC::release(tomerge);
166 if (position != -1)
167 tomerge->setPosition(position);
168 }
170 if (patern != NULL) {
171 if (submenu == NULL)
172 submenu = tomerge;
173 merge_menu(submenu, submenu->firstChild(), patern->firstChild(), mergee);
174 }
176 return;
177 }
179 Effect::~Effect (void)
180 {
181 if (get_last_effect() == this)
182 set_last_effect(NULL);
183 return;
184 }
186 bool
187 Effect::check (void)
188 {
189 if (!Extension::check()) {
190 /** \todo Check to see if parent has this as its only child,
191 if so, delete it too */
192 if (_menu_node != NULL)
193 sp_repr_unparent(_menu_node);
194 _menu_node = NULL;
195 return false;
196 }
197 return true;
198 }
200 bool
201 Effect::prefs (Inkscape::UI::View::View * doc)
202 {
203 if (!loaded())
204 set_state(Extension::STATE_LOADED);
205 if (!loaded()) return false;
207 Gtk::Widget * controls;
208 controls = imp->prefs_effect(this, doc);
209 if (controls == NULL) {
210 // std::cout << "No preferences for Effect" << std::endl;
211 return true;
212 }
214 PrefDialog * dialog = new PrefDialog(this->get_name(), this->get_help(), controls);
215 int response = dialog->run();
216 dialog->hide();
218 delete dialog;
220 if (response == Gtk::RESPONSE_OK) return true;
222 return false;
223 }
225 /**
226 \brief The function that 'does' the effect itself
227 \param doc The Inkscape::UI::View::View to do the effect on
229 This function first insures that the extension is loaded, and if not,
230 loads it. It then calls the implemention to do the actual work. It
231 also resets the last effect pointer to be this effect. Finally, it
232 executes a \c sp_document_done to commit the changes to the undo
233 stack.
234 */
235 void
236 Effect::effect (Inkscape::UI::View::View * doc)
237 {
238 if (!loaded())
239 set_state(Extension::STATE_LOADED);
240 if (!loaded()) return;
242 set_last_effect(this);
243 imp->effect(this, doc);
245 sp_document_done(doc->doc(), SP_VERB_NONE, _(this->get_name()));
247 return;
248 }
250 void
251 Effect::set_last_effect (Effect * in_effect)
252 {
253 if (in_effect == NULL) {
254 Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, false);
255 Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, false);
256 } else if (_last_effect == NULL) {
257 Inkscape::Verb::get(SP_VERB_EFFECT_LAST)->sensitive(NULL, true);
258 Inkscape::Verb::get(SP_VERB_EFFECT_LAST_PREF)->sensitive(NULL, true);
259 }
261 _last_effect = in_effect;
262 return;
263 }
265 #define EFFECTS_LIST "effects-list"
267 bool
268 Effect::find_effects_list (Inkscape::XML::Node * menustruct)
269 {
270 if (menustruct == NULL) return false;
271 for (Inkscape::XML::Node * child = menustruct;
272 child != NULL;
273 child = child->next()) {
274 if (!strcmp(child->name(), EFFECTS_LIST)) {
275 _effects_list = child;
276 return true;
277 }
278 Inkscape::XML::Node * firstchild = child->firstChild();
279 if (firstchild != NULL)
280 if (find_effects_list(firstchild))
281 return true;
282 }
283 return false;
284 }
286 Gtk::VBox *
287 Effect::get_info_widget(void)
288 {
289 return Extension::get_info_widget();
290 }
292 /** \brief Create an action for a \c EffectVerb
293 \param view Which view the action should be created for
294 \return The built action.
296 Calls \c make_action_helper with the \c vector.
297 */
298 SPAction *
299 Effect::EffectVerb::make_action (Inkscape::UI::View::View * view)
300 {
301 return make_action_helper(view, &vector, static_cast<void *>(this));
302 }
304 /** \brief Decode the verb code and take appropriate action */
305 void
306 Effect::EffectVerb::perform (SPAction *action, void * data, void *pdata)
307 {
308 Inkscape::UI::View::View * current_view = sp_action_get_view(action);
309 // SPDocument * current_document = current_view->doc;
310 Effect::EffectVerb * ev = reinterpret_cast<Effect::EffectVerb *>(data);
311 Effect * effect = ev->_effect;
313 if (effect == NULL) return;
314 if (current_view == NULL) return;
316 // std::cout << "Executing: " << effect->get_name() << std::endl;
317 bool execute = true;
319 if (ev->_showPrefs)
320 execute = effect->prefs(current_view);
321 if (execute)
322 effect->effect(current_view);
324 return;
325 }
327 /**
328 * Action vector to define functions called if a staticly defined file verb
329 * is called.
330 */
331 SPActionEventVector Effect::EffectVerb::vector =
332 {{NULL}, Effect::EffectVerb::perform, NULL, NULL, NULL, NULL};
335 } } /* namespace Inkscape, Extension */
337 /*
338 Local Variables:
339 mode:c++
340 c-file-style:"stroustrup"
341 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
342 indent-tabs-mode:nil
343 fill-column:99
344 End:
345 */
346 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :