summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: b388912)
raw | patch | inline | side by side (parent: b388912)
author | knutux <knutux@users.sourceforge.net> | |
Thu, 20 Apr 2006 16:06:59 +0000 (16:06 +0000) | ||
committer | knutux <knutux@users.sourceforge.net> | |
Thu, 20 Apr 2006 16:06:59 +0000 (16:06 +0000) |
Two more W3C SVG Test Suite testes pass after this change.
15 files changed:
src/Makefile_insert | patch | blob | history | |
src/attributes.cpp | patch | blob | history | |
src/attributes.h | patch | blob | history | |
src/conditions.cpp | [new file with mode: 0644] | patch | blob |
src/conditions.h | [new file with mode: 0644] | patch | blob |
src/display/sp-canvas.cpp | patch | blob | history | |
src/document.cpp | patch | blob | history | |
src/document.h | patch | blob | history | |
src/sp-item-group.cpp | patch | blob | history | |
src/sp-item-group.h | patch | blob | history | |
src/sp-item.cpp | patch | blob | history | |
src/sp-item.h | patch | blob | history | |
src/sp-object-repr.cpp | patch | blob | history | |
src/sp-switch.cpp | [new file with mode: 0644] | patch | blob |
src/sp-switch.h | [new file with mode: 0644] | patch | blob |
diff --git a/src/Makefile_insert b/src/Makefile_insert
index a9c565af0b4353607f9cb8ed56fae0e43a7579b3..12b766bb3e01dafb878c17ed9fc865cd802ceadf 100644 (file)
--- a/src/Makefile_insert
+++ b/src/Makefile_insert
color-rgba.h \
color-profile.cpp color-profile.h \
color-profile-fns.h \
+ conditions.cpp conditions.h\
conn-avoid-ref.cpp conn-avoid-ref.h \
connector-context.cpp connector-context.h \
context-fns.cpp context-fns.h \
sp-stop.h \
sp-string.cpp sp-string.h \
sp-symbol.cpp sp-symbol.h \
+ sp-switch.cpp sp-switch.h\
sp-text.cpp sp-text.h \
sp-textpath.h \
sp-tspan.cpp sp-tspan.h \
diff --git a/src/attributes.cpp b/src/attributes.cpp
index 39163c010f812a79671134f64fa9757bd7d0da25..541acfc0cfda10c5752e77a823001e270fe489dd 100644 (file)
--- a/src/attributes.cpp
+++ b/src/attributes.cpp
{SP_PROP_STROKE_OPACITY, "stroke-opacity"},
{SP_PROP_STROKE_WIDTH, "stroke-width"},
{SP_PROP_TEXT_RENDERING, "text-rendering"},
+ /* Conditional */
+ {SP_PROP_SYSTEM_LANGUAGE, "systemLanguage"},
+ {SP_PROP_REQUIRED_FEATURES, "requiredFeatures"},
+ {SP_PROP_REQUIRED_EXTENSIONS, "requiredExtensions"},
};
#define n_attrs (sizeof(props) / sizeof(props[0]))
diff --git a/src/attributes.h b/src/attributes.h
index 897656845779ab8a356efba6c144005a3e63d08d..bcbed50d0f45aedb3d4bf96189cc8dbe128f44ca 100644 (file)
--- a/src/attributes.h
+++ b/src/attributes.h
SP_PROP_STROKE_MITERLIMIT,
SP_PROP_STROKE_OPACITY,
SP_PROP_STROKE_WIDTH,
- SP_PROP_TEXT_RENDERING
+ SP_PROP_TEXT_RENDERING,
+ /* Conditional */
+ SP_PROP_SYSTEM_LANGUAGE,
+ SP_PROP_REQUIRED_FEATURES,
+ SP_PROP_REQUIRED_EXTENSIONS,
};
#endif
diff --git a/src/conditions.cpp b/src/conditions.cpp
--- /dev/null
+++ b/src/conditions.cpp
@@ -0,0 +1,462 @@
+#define __SP_CONDITIONS_CPP__
+
+/*
+ * SVG conditional attribute evaluation
+ *
+ * Authors:
+ * Andrius R. <knutux@gmail.com>
+ *
+ * Copyright (C) 2006 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <set>
+#include <glibmm/ustring.h>
+#include "conditions.h"
+#include "xml/repr.h"
+#include "dialogs/rdf.h"
+
+typedef bool (* condition_evaluator)(SPItem const *item, gchar const *value);
+
+struct Condition {
+ gchar const *attribute;
+ condition_evaluator evaluator;
+};
+
+static bool evaluateSystemLanguage(SPItem const *item, gchar const *value);
+static bool evaluateRequiredFeatures(SPItem const *item, gchar const *value);
+static bool evaluateRequiredExtensions(SPItem const *item, gchar const *value);
+
+/* define any conditional attributes and their handler functions in this array */
+static Condition _condition_handlers[] = {
+ { "systemLanguage", evaluateSystemLanguage },
+ { "requiredFeatures", evaluateRequiredFeatures },
+ { "requiredExtensions", evaluateRequiredExtensions },
+};
+
+/* function which evaluates if item should be displayed */
+bool sp_item_evaluate(SPItem const *item) {
+ Inkscape::XML::Node *grepr = SP_OBJECT_REPR (item);
+
+ for ( unsigned int i = 0 ; i < sizeof(_condition_handlers)/sizeof(_condition_handlers[0]) ; i++ ) {
+ gchar const *value = grepr->attribute(_condition_handlers[i].attribute);
+ if ( NULL == value )
+ continue;
+
+ if (!_condition_handlers[i].evaluator(item, value))
+ return false;
+ }
+
+ return true;
+}
+
+#define ISALNUM(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z') || ((c) >= '0' && (c) <= '9'))
+
+static gchar *preprocessLanguageCode(gchar *lngcode) {
+ if ( NULL == lngcode )
+ return NULL;
+
+ lngcode = g_strstrip(lngcode);
+ if ( 0 == *lngcode )
+ return lngcode;
+ for ( unsigned int i = 0 ; i < strlen(lngcode) ; i++ ) {
+ if ( lngcode[i] >= 'A' && lngcode[i] <= 'Z' ) {
+ lngcode[i] = g_ascii_tolower(lngcode[i]);
+ } else if ( '_' == lngcode[i] ) {
+ lngcode[i] = '-';
+ } else if ( !ISALNUM(lngcode[i]) && '-' != lngcode[i] ) {
+ // only alpha numeric characters and '-' may be contained in language code
+ lngcode[0] = 0;
+ break;
+ }
+ }
+
+ return lngcode;
+}
+
+static bool evaluateSystemLanguage(SPItem const *item, gchar const *value) {
+ if ( NULL == value )
+ return true;
+
+ std::set<Glib::ustring> language_codes;
+ gchar *str = NULL;
+ gchar **strlist = g_strsplit( value, ",", 0);
+
+ for ( int i = 0 ; (str = strlist[i]) ; i++ ) {
+ gchar *lngcode = preprocessLanguageCode(str);
+ if ( 0 == *lngcode )
+ continue;
+ language_codes.insert(lngcode);
+
+ gchar *pos = strchr (lngcode, '-');
+ if (pos)
+ {
+ // if subtag is used, primary tag is still a perfect match
+ *pos = 0;
+ if ( language_codes.find(lngcode) == language_codes.end() ) {
+ language_codes.insert(lngcode);
+ }
+ }
+ }
+ g_strfreev(strlist);
+
+ if (language_codes.empty())
+ return false;
+
+ SPDocument *document = SP_OBJECT_DOCUMENT(item);
+ Glib::ustring document_language = document->getLanguage();
+
+ if (document_language.size() == 0)
+ return false;
+
+ bool match = true;
+ strlist = g_strsplit( document_language.c_str(), ",", 0);
+ for ( int i = 0 ; (str = strlist[i]) ; i++ ) {
+ gchar *lngcode = preprocessLanguageCode(str);
+ if ( 0 == *lngcode )
+ continue;
+ if ( language_codes.find(lngcode) != language_codes.end() ) {
+ match = true;
+ break;
+ }
+ match = false;
+ }
+ g_strfreev(strlist);
+ return match;
+}
+
+static std::vector<Glib::ustring> splitByWhitespace(gchar const *value) {
+ std::vector<Glib::ustring> parts;
+ gchar *str = NULL;
+ gchar **strlist = g_strsplit( value, ",", 0);
+
+ for ( int i = 0 ; (str = strlist[i]) ; i++ ) {
+ gchar *part = g_strstrip(str);
+ if ( 0 == *part )
+ continue;
+ parts.push_back(part);
+ }
+ g_strfreev(strlist);
+ return parts;
+}
+
+#define SVG11FEATURE "http://www.w3.org/TR/SVG11/feature#"
+#define SVG10FEATURE "org.w3c."
+
+static bool evaluateSVG11Feature(gchar const *feature) {
+ static gchar *_supported_features[] = {
+ "SVG", // incomplete "SVG-static" - missing support for "Filter"
+ /* SVG - user agent supports at least one of the following:
+ "SVG-static", "SVG-animation", "SVG-dynamic" or "SVGDOM" */
+ // "SVGDOM", // not sure
+ /* SVGDOM - user agent supports at least one of the following:
+ "SVGDOM-static", "SVGDOM-animation" or "SVGDOM-dynamic" */
+ "SVG-static", // incomplete - missing support for "Filter"
+ /* SVG-static - user agent supports the following features:
+ "CoreAttribute", "Structure", "ContainerAttribute",
+ "ConditionalProcessing", "Image", "Style", "ViewportAttribute",
+ "Shape", "Text", "PaintAttribute", "OpacityAttribute",
+ "GraphicsAttribute", "Marker", "ColorProfile",
+ "Gradient", "Pattern", "Clip", "Mask", "Filter",
+ "XlinkAttribute", "Font", "Extensibility" */
+ // "SVGDOM-static", // not sure
+ /* SVGDOM-static - All of the DOM interfaces and methods
+ that correspond to SVG-static */
+ // "SVG-animation", // no support
+ /* SVG-animation - All of the language features from "SVG-static"
+ plus the feature "feature#Animation" */
+ // "SVGDOM-animation", // no support
+ /* SVGDOM-animation - All of the DOM interfaces and methods
+ that correspond to SVG-animation */
+ // "SVG-dynamic", // no support
+ /* SVG-dynamic - user agent supports all "SVG-animation" and the following features:
+ "Hyperlinking", "Scripting", "View", "Cursor",
+ "GraphicalEventsAttribute", "DocumentEventsAttribute", "AnimationEventsAttribute" */
+ // "SVGDOM-dynamic", // no support
+ /* SVGDOM-dynamic - All of the DOM interfaces and methods
+ that correspond to SVG-dynamic */
+ "CoreAttribute",
+ "Structure",
+ "BasicStructure",
+ "ContainerAttribute",
+ "ConditionalProcessing",
+ "Image",
+ "Style",
+ "ViewportAttribute", // not sure
+ "Shape",
+ "Text",
+ "BasicText",
+ "PaintAttribute",
+ "BasicPaintAttribute",
+ "OpacityAttribute",
+ "GraphicsAttribute",
+ "BasicGraphicsAttribute",
+ "Marker",
+ "ColorProfile",
+ "Gradient",
+ "Pattern",
+ "Clip",
+ "BasicClip",
+ "Mask",
+ // "Filter",
+ // "BasicFilter",
+ // "DocumentEventsAttribute",
+ // "GraphicalEventsAttribute",
+ // "AnimationEventsAttribute",
+ // "Cursor", // not sure
+ "Hyperlinking", // not sure
+ "XlinkAttribute", // not sure
+ "ExternalResourcesRequired", // not sure
+ "View",
+ // "Script",
+ // "Animation",
+ "Font",
+ "BasicFont",
+ "Extensibility", // not sure
+ };
+
+ for ( unsigned int i = 0 ; i < sizeof(_supported_features)/sizeof(_supported_features[0]); i++ ) {
+ if ( 0 == strcasecmp(feature, _supported_features[0]) )
+ return true;
+ }
+ return false;
+}
+
+static bool evaluateSVG10Feature(gchar const *feature) {
+ static gchar *_supported_features[] = {
+ "svg.static", // incomplete - no filter effects
+ "dom.svg.static", // not sure
+ // "svg.animation",
+ // "dom.svg.animation",
+ // "svg.dynamic",
+ // "dom.svg.dynamic"
+ // "svg.all",
+ // "dom.svg.all"
+ };
+ for ( unsigned int i = 0 ; i < sizeof(_supported_features)/sizeof(_supported_features[0]); i++ ) {
+ if ( 0 == strcasecmp(feature, _supported_features[0]) )
+ return true;
+ }
+ return false;
+}
+
+static bool evaluateSingleFeature(gchar const *value) {
+ if ( NULL == value )
+ return false;
+ gchar const *found;
+ found = strstr(value, SVG11FEATURE);
+ if ( value == found )
+ return evaluateSVG11Feature(found + strlen(SVG11FEATURE));
+ found = strstr(value, SVG10FEATURE);
+ if ( value == found )
+ return evaluateSVG10Feature(found + strlen(SVG10FEATURE));
+ return false;
+}
+
+static bool evaluateRequiredFeatures(SPItem const *item, gchar const *value) {
+ if ( NULL == value )
+ return true;
+
+ std::vector<Glib::ustring> parts = splitByWhitespace(value);
+ if ( 0 == parts.size() )
+ return false;
+
+ for ( unsigned int i = 0 ; i < parts.size() ; i++ ) {
+ if (!evaluateSingleFeature(parts[i].c_str())) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool evaluateRequiredExtensions(SPItem const *item, gchar const *value) {
+ if ( NULL == value )
+ return true;
+ return false;
+}
+
+/*
+ * Language codes and names:
+aa Afar
+ab Abkhazian
+af Afrikaans
+am Amharic
+ar Arabic
+as Assamese
+ay Aymara
+az Azerbaijani
+
+ba Bashkir
+be Byelorussian
+bg Bulgarian
+bh Bihari
+bi Bislama
+bn Bengali; Bangla
+bo Tibetan
+br Breton
+
+ca Catalan
+co Corsican
+cs Czech
+cy Welsh
+
+da Danish
+de German
+dz Bhutani
+
+el Greek
+en English
+eo Esperanto
+es Spanish
+et Estonian
+eu Basque
+
+fa Persian
+fi Finnish
+fj Fiji
+fo Faroese
+fr French
+fy Frisian
+
+ga Irish
+gd Scots Gaelic
+gl Galician
+gn Guarani
+gu Gujarati
+
+ha Hausa
+he Hebrew (formerly iw)
+hi Hindi
+hr Croatian
+hu Hungarian
+hy Armenian
+
+ia Interlingua
+id Indonesian (formerly in)
+ie Interlingue
+ik Inupiak
+is Icelandic
+it Italian
+iu Inuktitut
+
+ja Japanese
+jw Javanese
+
+ka Georgian
+kk Kazakh
+kl Greenlandic
+km Cambodian
+kn Kannada
+ko Korean
+ks Kashmiri
+ku Kurdish
+ky Kirghiz
+
+la Latin
+ln Lingala
+lo Laothian
+lt Lithuanian
+lv Latvian, Lettish
+
+mg Malagasy
+mi Maori
+mk Macedonian
+ml Malayalam
+mn Mongolian
+mo Moldavian
+mr Marathi
+ms Malay
+mt Maltese
+my Burmese
+
+na Nauru
+ne Nepali
+nl Dutch
+no Norwegian
+
+oc Occitan
+om (Afan) Oromo
+or Oriya
+
+pa Punjabi
+pl Polish
+ps Pashto, Pushto
+pt Portuguese
+
+qu Quechua
+
+rm Rhaeto-Romance
+rn Kirundi
+ro Romanian
+ru Russian
+rw Kinyarwanda
+
+sa Sanskrit
+sd Sindhi
+sg Sangho
+sh Serbo-Croatian
+si Sinhalese
+sk Slovak
+sl Slovenian
+sm Samoan
+sn Shona
+so Somali
+sq Albanian
+sr Serbian
+ss Siswati
+st Sesotho
+su Sundanese
+sv Swedish
+sw Swahili
+
+ta Tamil
+te Telugu
+tg Tajik
+th Thai
+ti Tigrinya
+tk Turkmen
+tl Tagalog
+tn Setswana
+to Tonga
+tr Turkish
+ts Tsonga
+tt Tatar
+tw Twi
+
+ug Uighur
+uk Ukrainian
+ur Urdu
+uz Uzbek
+
+vi Vietnamese
+vo Volapuk
+
+wo Wolof
+
+xh Xhosa
+
+yi Yiddish (formerly ji)
+yo Yoruba
+
+za Zhuang
+zh Chinese
+zu Zulu
+ */
+
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/conditions.h b/src/conditions.h
--- /dev/null
+++ b/src/conditions.h
@@ -0,0 +1,8 @@
+#ifndef CONDITIONS_H_
+#define CONDITIONS_H_
+
+#include "sp-item.h"
+
+bool sp_item_evaluate(SPItem const *item);
+
+#endif /*CONDITIONS_H_*/
index 5e19539f37bf9293e0116798259b5a75d71ca9c7..edd429f0d10b2a40cd4a2dc7aefef865172eaf68 100644 (file)
static int
pick_current_item (SPCanvas *canvas, GdkEvent *event)
{
- int button_down;
+ int button_down = 0;
double x, y;
int retval = FALSE;
diff --git a/src/document.cpp b/src/document.cpp
index 863266c051321f49d663f4be8e16409fcdb9514c..ef04735ef6252f78aeaf95c658eb0e04abbfe617 100644 (file)
--- a/src/document.cpp
+++ b/src/document.cpp
return (SPObject*)g_hash_table_lookup(priv->reprdef, repr);
}
+Glib::ustring SPDocument::getLanguage() {
+ gchar const *document_language = rdf_get_work_entity(this, rdf_find_entity("language"));
+ if (document_language) {
+ while (isspace(*document_language))
+ document_language++;
+ }
+ if ( !document_language || 0 == *document_language) {
+ // retrieve system language
+ document_language = getenv("LC_ALL");
+ if ( NULL == document_language || *document_language == 0 ) {
+ document_language = getenv ("LC_MESSAGES");
+ }
+ if ( NULL == document_language || *document_language == 0 ) {
+ document_language = getenv ("LANG");
+ }
+
+ if ( NULL != document_language ) {
+ gchar *pos = strchr(document_language, '_');
+ if ( NULL != pos ) {
+ return Glib::ustring(document_language, pos - document_language);
+ }
+ }
+ }
+
+ if ( NULL == document_language )
+ return Glib::ustring();
+ return document_language;
+}
+
/* Object modification root handler */
void
diff --git a/src/document.h b/src/document.h
index f06ad2f6d9ab86fc770cb8aa46a8827b2c98e74f..f601b15ff168a705f614ef9715a5daab62c03cea 100644 (file)
--- a/src/document.h
+++ b/src/document.h
#include "gc-managed.h"
#include "gc-finalized.h"
#include "gc-anchored.h"
+#include <glibmm/ustring.h>
namespace Avoid {
class Router;
void bindObjectToRepr(Inkscape::XML::Node *repr, SPObject *object);
SPObject *getObjectByRepr(Inkscape::XML::Node *repr);
+ Glib::ustring getLanguage();
+
void queueForOrphanCollection(SPObject *object);
void collectOrphans();
diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp
index b4b69e1e488db966d4183af78709242897dff0d2..3ce551b983199f763841b7acdaaa622dbfa0be80 100644 (file)
--- a/src/sp-item-group.cpp
+++ b/src/sp-item-group.cpp
static void sp_group_init (SPGroup *group);
static void sp_group_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
static void sp_group_release(SPObject *object);
-static void sp_group_dispose (GObject *object);
+static void sp_group_dispose(GObject *object);
static void sp_group_child_added (SPObject * object, Inkscape::XML::Node * child, Inkscape::XML::Node * ref);
static void sp_group_remove_child (SPObject * object, Inkscape::XML::Node * child);
sp_group_init (SPGroup *group)
{
group->_layer_mode = SPGroup::GROUP;
+ group->group = new CGroup(group);
new (&group->_display_modes) std::map<unsigned int, SPGroup::LayerMode>();
}
sp_group_dispose(GObject *object)
{
SP_GROUP(object)->_display_modes.~map();
+ delete SP_GROUP(object)->group;
}
static void
@@ -153,46 +155,7 @@ sp_group_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XM
if (((SPObjectClass *) (parent_class))->child_added)
(* ((SPObjectClass *) (parent_class))->child_added) (object, child, ref);
- SPObject *last_child = object->lastChild();
- if (last_child && SP_OBJECT_REPR(last_child) == child) {
- // optimization for the common special case where the child is being added at the end
- SPObject *ochild = last_child;
- if ( SP_IS_ITEM(ochild) ) {
- /* TODO: this should be moved into SPItem somehow */
- SPItemView *v;
- NRArenaItem *ac;
-
- for (v = item->display; v != NULL; v = v->next) {
- ac = sp_item_invoke_show (SP_ITEM (ochild), NR_ARENA_ITEM_ARENA (v->arenaitem), v->key, v->flags);
-
- if (ac) {
- nr_arena_item_append_child (v->arenaitem, ac);
- nr_arena_item_unref (ac);
- }
- }
- }
- } else { // general case
- SPObject *ochild = sp_object_get_child_by_repr(object, child);
- if ( ochild && SP_IS_ITEM(ochild) ) {
- /* TODO: this should be moved into SPItem somehow */
- SPItemView *v;
- NRArenaItem *ac;
-
- unsigned position = sp_item_pos_in_parent(SP_ITEM(ochild));
-
- for (v = item->display; v != NULL; v = v->next) {
- ac = sp_item_invoke_show (SP_ITEM (ochild), NR_ARENA_ITEM_ARENA (v->arenaitem), v->key, v->flags);
-
- if (ac) {
- nr_arena_item_add_child (v->arenaitem, ac, NULL);
- nr_arena_item_set_order (ac, position);
- nr_arena_item_unref (ac);
- }
- }
- }
- }
-
- object->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ SP_GROUP(object)->group->onChildAdded(child);
}
/* fixme: hide (Lauris) */
if (((SPObjectClass *) (parent_class))->remove_child)
(* ((SPObjectClass *) (parent_class))->remove_child) (object, child);
- object->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ SP_GROUP(object)->group->onChildRemoved(child);
}
static void
@@ -212,86 +175,22 @@ sp_group_order_changed (SPObject *object, Inkscape::XML::Node *child, Inkscape::
if (((SPObjectClass *) (parent_class))->order_changed)
(* ((SPObjectClass *) (parent_class))->order_changed) (object, child, old_ref, new_ref);
- SPObject *ochild = sp_object_get_child_by_repr(object, child);
- if ( ochild && SP_IS_ITEM(ochild) ) {
- /* TODO: this should be moved into SPItem somehow */
- SPItemView *v;
- unsigned position = sp_item_pos_in_parent(SP_ITEM(ochild));
- for ( v = SP_ITEM (ochild)->display ; v != NULL ; v = v->next ) {
- nr_arena_item_set_order (v->arenaitem, position);
- }
- }
-
- object->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ SP_GROUP(object)->group->onOrderChanged(child, old_ref, new_ref);
}
static void
sp_group_update (SPObject *object, SPCtx *ctx, unsigned int flags)
{
- SPGroup *group;
- SPObject *child;
- SPItemCtx *ictx, cctx;
- GSList *l;
-
- group = SP_GROUP (object);
- ictx = (SPItemCtx *) ctx;
- cctx = *ictx;
+ if (((SPObjectClass *) (parent_class))->update)
+ ((SPObjectClass *) (parent_class))->update (object, ctx, flags);
- if (((SPObjectClass *) (parent_class))->update)
- ((SPObjectClass *) (parent_class))->update (object, ctx, flags);
-
- if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
- flags &= SP_OBJECT_MODIFIED_CASCADE;
-
- l = NULL;
- for (child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
- g_object_ref (G_OBJECT (child));
- l = g_slist_prepend (l, child);
- }
- l = g_slist_reverse (l);
- while (l) {
- child = SP_OBJECT (l->data);
- l = g_slist_remove (l, child);
- if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
- if (SP_IS_ITEM (child)) {
- SPItem const &chi = *SP_ITEM(child);
- cctx.i2doc = chi.transform * ictx->i2doc;
- cctx.i2vp = chi.transform * ictx->i2vp;
- child->updateDisplay((SPCtx *)&cctx, flags);
- } else {
- child->updateDisplay(ctx, flags);
- }
- }
- g_object_unref (G_OBJECT (child));
- }
+ SP_GROUP(object)->group->onUpdate(ctx, flags);
}
static void
sp_group_modified (SPObject *object, guint flags)
{
- SPGroup *group;
- SPObject *child;
- GSList *l;
-
- group = SP_GROUP (object);
-
- if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
- flags &= SP_OBJECT_MODIFIED_CASCADE;
-
- l = NULL;
- for (child = sp_object_first_child(object) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
- g_object_ref (G_OBJECT (child));
- l = g_slist_prepend (l, child);
- }
- l = g_slist_reverse (l);
- while (l) {
- child = SP_OBJECT (l->data);
- l = g_slist_remove (l, child);
- if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
- child->emitModified(flags);
- }
- g_object_unref (G_OBJECT (child));
- }
+ SP_GROUP(object)->group->onModified(flags);
}
static Inkscape::XML::Node *
static void
sp_group_bbox(SPItem const *item, NRRect *bbox, NR::Matrix const &transform, unsigned const flags)
{
- for (SPObject *o = sp_object_first_child(SP_OBJECT(item)); o != NULL; o = SP_OBJECT_NEXT(o)) {
- if (SP_IS_ITEM(o)) {
- SPItem *child = SP_ITEM(o);
- NR::Matrix const ct(child->transform * transform);
- sp_item_invoke_bbox_full(child, bbox, ct, flags, FALSE);
- }
- }
+ SP_GROUP(item)->group->calculateBBox(bbox, transform, flags);
}
static void
sp_group_print (SPItem * item, SPPrintContext *ctx)
{
- SPGroup * group;
- SPItem * child;
- SPObject * o;
-
- group = SP_GROUP (item);
-
- for (o = sp_object_first_child(SP_OBJECT(item)) ; o != NULL ; o = SP_OBJECT_NEXT(o) ) {
- if (SP_IS_ITEM (o)) {
- child = SP_ITEM (o);
- sp_item_invoke_print (SP_ITEM (o), ctx);
- }
- }
+ SP_GROUP(item)->group->onPrint(ctx);
}
static gchar * sp_group_description (SPItem * item)
{
- SPGroup * group;
- SPObject * o;
- gint len;
-
- group = SP_GROUP (item);
-
- len = 0;
- for ( o = sp_object_first_child(SP_OBJECT(item)) ; o != NULL ; o = SP_OBJECT_NEXT(o) ) {
- if (SP_IS_ITEM(o)) {
- len += 1;
- }
- }
-
- return g_strdup_printf(
- ngettext("<b>Group</b> of <b>%d</b> object",
- "<b>Group</b> of <b>%d</b> objects",
- len), len);
+ return SP_GROUP(item)->group->getDescription();
}
static void sp_group_set(SPObject *object, unsigned key, char const *value) {
static NRArenaItem *
sp_group_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags)
{
- SPGroup *group;
- NRArenaItem *ai, *ac, *ar;
- SPItem * child;
- SPObject * o;
-
- group = (SPGroup *) item;
-
- ai = NRArenaGroup::create(arena);
- nr_arena_group_set_transparent(NR_ARENA_GROUP (ai),
- group->effectiveLayerMode(key) ==
- SPGroup::LAYER);
-
- ar = NULL;
-
- for (o = sp_object_first_child(SP_OBJECT(item)) ; o != NULL; o = SP_OBJECT_NEXT(o) ) {
- if (SP_IS_ITEM (o)) {
- child = SP_ITEM (o);
- ac = sp_item_invoke_show (child, arena, key, flags);
- if (ac) {
- nr_arena_item_add_child (ai, ac, ar);
- ar = ac;
- nr_arena_item_unref (ac);
- }
- }
- }
-
- return ai;
+ return SP_GROUP(item)->group->show(arena, key, flags);
}
static void
sp_group_hide (SPItem *item, unsigned int key)
{
- SPGroup * group;
- SPItem * child;
- SPObject * o;
-
- group = (SPGroup *) item;
-
- for (o = sp_object_first_child(SP_OBJECT(item)) ; o != NULL; o = SP_OBJECT_NEXT(o) ) {
- if (SP_IS_ITEM (o)) {
- child = SP_ITEM (o);
- sp_item_invoke_hide (child, key);
- }
- }
-
- if (((SPItemClass *) parent_class)->hide)
- ((SPItemClass *) parent_class)->hide (item, key);
+ SP_GROUP(item)->group->hide(key);
}
static void sp_group_snappoints (SPItem const *item, SnapPointsIter p)
}
}
}
+
+CGroup::CGroup(SPGroup *group) {
+ _group = group;
+}
+
+CGroup::~CGroup() {
+}
+
+void CGroup::onChildAdded(Inkscape::XML::Node *child) {
+ SPObject *last_child = _group->lastChild();
+ if (last_child && SP_OBJECT_REPR(last_child) == child) {
+ // optimization for the common special case where the child is being added at the end
+ SPObject *ochild = last_child;
+ if ( SP_IS_ITEM(ochild) ) {
+ /* TODO: this should be moved into SPItem somehow */
+ SPItemView *v;
+ NRArenaItem *ac;
+
+ for (v = _group->display; v != NULL; v = v->next) {
+ ac = sp_item_invoke_show (SP_ITEM (ochild), NR_ARENA_ITEM_ARENA (v->arenaitem), v->key, v->flags);
+
+ if (ac) {
+ nr_arena_item_append_child (v->arenaitem, ac);
+ nr_arena_item_unref (ac);
+ }
+ }
+ }
+ } else { // general case
+ SPObject *ochild = sp_object_get_child_by_repr(_group, child);
+ if ( ochild && SP_IS_ITEM(ochild) ) {
+ /* TODO: this should be moved into SPItem somehow */
+ SPItemView *v;
+ NRArenaItem *ac;
+
+ unsigned position = sp_item_pos_in_parent(SP_ITEM(ochild));
+
+ for (v = _group->display; v != NULL; v = v->next) {
+ ac = sp_item_invoke_show (SP_ITEM (ochild), NR_ARENA_ITEM_ARENA (v->arenaitem), v->key, v->flags);
+
+ if (ac) {
+ nr_arena_item_add_child (v->arenaitem, ac, NULL);
+ nr_arena_item_set_order (ac, position);
+ nr_arena_item_unref (ac);
+ }
+ }
+ }
+ }
+
+ _group->requestModified(SP_OBJECT_MODIFIED_FLAG);
+}
+
+void CGroup::onChildRemoved(Inkscape::XML::Node */*child*/) {
+ _group->requestModified(SP_OBJECT_MODIFIED_FLAG);
+}
+
+void CGroup::onUpdate(SPCtx *ctx, unsigned int flags) {
+ SPObject *child;
+ SPItemCtx *ictx, cctx;
+
+ ictx = (SPItemCtx *) ctx;
+ cctx = *ictx;
+
+ if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
+ flags &= SP_OBJECT_MODIFIED_CASCADE;
+
+ GSList *l = g_slist_reverse(_childList(true, ActionUpdate));
+ while (l) {
+ child = SP_OBJECT (l->data);
+ l = g_slist_remove (l, child);
+ if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
+ if (SP_IS_ITEM (child)) {
+ SPItem const &chi = *SP_ITEM(child);
+ cctx.i2doc = chi.transform * ictx->i2doc;
+ cctx.i2vp = chi.transform * ictx->i2vp;
+ child->updateDisplay((SPCtx *)&cctx, flags);
+ } else {
+ child->updateDisplay(ctx, flags);
+ }
+ }
+ g_object_unref (G_OBJECT (child));
+ }
+}
+
+GSList *CGroup::_childList(bool add_ref, Action) {
+ GSList *l = NULL;
+ for (SPObject *child = sp_object_first_child(_group) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
+ if (add_ref)
+ g_object_ref (G_OBJECT (child));
+
+ l = g_slist_prepend (l, child);
+ }
+ return l;
+}
+
+void CGroup::onModified(guint flags) {
+ SPObject *child;
+
+ if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
+ flags &= SP_OBJECT_MODIFIED_CASCADE;
+
+ GSList *l = g_slist_reverse(_childList(true));
+ while (l) {
+ child = SP_OBJECT (l->data);
+ l = g_slist_remove (l, child);
+ if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
+ child->emitModified(flags);
+ }
+ g_object_unref (G_OBJECT (child));
+ }
+}
+
+void CGroup::calculateBBox(NRRect *bbox, NR::Matrix const &transform, unsigned const flags) {
+ GSList *l = _childList(false, ActionBBox);
+ while (l) {
+ SPObject *o = SP_OBJECT (l->data);
+ if (SP_IS_ITEM(o)) {
+ SPItem *child = SP_ITEM(o);
+ NR::Matrix const ct(child->transform * transform);
+ sp_item_invoke_bbox_full(child, bbox, ct, flags, FALSE);
+ }
+ l = g_slist_remove (l, o);
+ }
+}
+
+void CGroup::onPrint(SPPrintContext *ctx) {
+ GSList *l = _childList(false);
+ while (l) {
+ SPObject *o = SP_OBJECT (l->data);
+ if (SP_IS_ITEM(o)) {
+ sp_item_invoke_print (SP_ITEM (o), ctx);
+ }
+ l = g_slist_remove (l, o);
+ }
+}
+
+gint CGroup::getItemCount() {
+ gint len = 0;
+ for (SPObject *o = sp_object_first_child(SP_OBJECT(_group)) ; o != NULL ; o = SP_OBJECT_NEXT(o) ) {
+ if (SP_IS_ITEM(o)) {
+ len++;
+ }
+ }
+
+ return len;
+}
+
+gchar *CGroup::getDescription() {
+ gint len = getItemCount();
+ return g_strdup_printf(
+ ngettext("<b>Group</b> of <b>%d</b> object",
+ "<b>Group</b> of <b>%d</b> objects",
+ len), len);
+}
+
+NRArenaItem *CGroup::show (NRArena *arena, unsigned int key, unsigned int flags) {
+ NRArenaItem *ai;
+
+ ai = NRArenaGroup::create(arena);
+ nr_arena_group_set_transparent(NR_ARENA_GROUP (ai),
+ _group->effectiveLayerMode(key) ==
+ SPGroup::LAYER);
+
+ _showChildren(arena, ai, key, flags);
+ return ai;
+}
+
+void CGroup::_showChildren (NRArena *arena, NRArenaItem *ai, unsigned int key, unsigned int flags) {
+ NRArenaItem *ac = NULL;
+ NRArenaItem *ar = NULL;
+ SPItem * child = NULL;
+ GSList *l = _childList(false, ActionShow);
+ while (l) {
+ SPObject *o = SP_OBJECT (l->data);
+ if (SP_IS_ITEM (o)) {
+ child = SP_ITEM (o);
+ ac = sp_item_invoke_show (child, arena, key, flags);
+ if (ac) {
+ nr_arena_item_add_child (ai, ac, ar);
+ ar = ac;
+ nr_arena_item_unref (ac);
+ }
+ }
+ l = g_slist_remove (l, o);
+ }
+}
+
+void CGroup::hide (unsigned int key) {
+ SPItem * child;
+
+ GSList *l = _childList(false, ActionShow);
+ while (l) {
+ SPObject *o = SP_OBJECT (l->data);
+ if (SP_IS_ITEM (o)) {
+ child = SP_ITEM (o);
+ sp_item_invoke_hide (child, key);
+ }
+ l = g_slist_remove (l, o);
+ }
+
+ if (((SPItemClass *) parent_class)->hide)
+ ((SPItemClass *) parent_class)->hide (_group, key);
+}
+
+void CGroup::onOrderChanged (Inkscape::XML::Node *child, Inkscape::XML::Node *, Inkscape::XML::Node *)
+{
+ SPObject *ochild = sp_object_get_child_by_repr(_group, child);
+ if ( ochild && SP_IS_ITEM(ochild) ) {
+ /* TODO: this should be moved into SPItem somehow */
+ SPItemView *v;
+ unsigned position = sp_item_pos_in_parent(SP_ITEM(ochild));
+ for ( v = SP_ITEM (ochild)->display ; v != NULL ; v = v->next ) {
+ nr_arena_item_set_order (v->arenaitem, position);
+ }
+ }
+
+ _group->requestModified(SP_OBJECT_MODIFIED_FLAG);
+}
diff --git a/src/sp-item-group.h b/src/sp-item-group.h
index 578454c9237e6591ad55fa7389c8168ab6cc8d47..ebf5c040272fe4b21a7490a8250e8b93e74db6d9 100644 (file)
--- a/src/sp-item-group.h
+++ b/src/sp-item-group.h
#define SP_IS_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_GROUP))
#define SP_IS_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_GROUP))
+class CGroup;
+
struct SPGroup : public SPItem {
enum LayerMode { GROUP, LAYER };
LayerMode layerDisplayMode(unsigned int display_key) const;
void setLayerDisplayMode(unsigned int display_key, LayerMode mode);
+ CGroup *group;
+
private:
void _updateLayerMode(unsigned int display_key=0);
};
SPItemClass parent_class;
};
+/*
+ * Virtual methods of SPGroup
+ */
+class CGroup {
+public:
+ CGroup(SPGroup *group);
+ virtual ~CGroup();
+
+ virtual void onChildAdded(Inkscape::XML::Node *child);
+ virtual void onChildRemoved(Inkscape::XML::Node *child);
+ virtual void onUpdate(SPCtx *ctx, unsigned int flags);
+ virtual void onModified(guint flags);
+ virtual void calculateBBox(NRRect *bbox, NR::Matrix const &transform, unsigned const flags);
+ virtual void onPrint(SPPrintContext *ctx);
+ virtual void onOrderChanged(Inkscape::XML::Node *child, Inkscape::XML::Node *old_ref, Inkscape::XML::Node *new_ref);
+ virtual gchar *getDescription();
+ virtual NRArenaItem *show (NRArena *arena, unsigned int key, unsigned int flags);
+ virtual void hide (unsigned int key);
+
+ gint getItemCount();
+
+protected:
+ enum Action { ActionGeneral, ActionBBox, ActionUpdate, ActionShow };
+ virtual GSList *_childList(bool add_ref, Action action = ActionGeneral);
+ virtual void _showChildren (NRArena *arena, NRArenaItem *ai, unsigned int key, unsigned int flags);
+
+ SPGroup *_group;
+};
+
GType sp_group_get_type (void);
void sp_item_group_ungroup (SPGroup *group, GSList **children, bool do_done = true);
diff --git a/src/sp-item.cpp b/src/sp-item.cpp
index 0e45bc7f43df067a961ba81326effdf2cc51ddcd..c2e3bb1bfcf24b76f5e4805b40843c8cd0338918 100644 (file)
--- a/src/sp-item.cpp
+++ b/src/sp-item.cpp
#include "sp-text.h"
#include "sp-item-rm-unsatisfied-cns.h"
#include "sp-pattern.h"
+#include "sp-switch.h"
#include "gradient-chemistry.h"
#include "prefs-utils.h"
#include "conn-avoid-ref.h"
+#include "conditions.h"
#include "libnr/nr-matrix-div.h"
#include "libnr/nr-matrix-fns.h"
static void
sp_item_init(SPItem *item)
{
- SPObject *object = SP_OBJECT(item);
+ item->init();
+}
- item->sensitive = TRUE;
+void SPItem::init() {
+ this->sensitive = TRUE;
- item->transform_center_x = 0;
- item->transform_center_y = 0;
+ this->transform_center_x = 0;
+ this->transform_center_y = 0;
- item->transform = NR::identity();
+ this->_is_evaluated = true;
+ this->_evaluated_status = StatusCalculated;
- item->display = NULL;
+ this->transform = NR::identity();
- item->clip_ref = new SPClipPathReference(SP_OBJECT(item));
+ this->display = NULL;
+
+ this->clip_ref = new SPClipPathReference(this);
{
- sigc::signal<void, SPObject *, SPObject *> cs1=item->clip_ref->changedSignal();
- sigc::slot2<void,SPObject*, SPObject *> sl1=sigc::bind(sigc::ptr_fun(clip_ref_changed), item);
+ sigc::signal<void, SPObject *, SPObject *> cs1=this->clip_ref->changedSignal();
+ sigc::slot2<void,SPObject*, SPObject *> sl1=sigc::bind(sigc::ptr_fun(clip_ref_changed), this);
cs1.connect(sl1);
}
- item->mask_ref = new SPMaskReference(SP_OBJECT(item));
- sigc::signal<void, SPObject *, SPObject *> cs2=item->mask_ref->changedSignal();
- sigc::slot2<void,SPObject*, SPObject *> sl2=sigc::bind(sigc::ptr_fun(mask_ref_changed), item);
+ this->mask_ref = new SPMaskReference(this);
+ sigc::signal<void, SPObject *, SPObject *> cs2=this->mask_ref->changedSignal();
+ sigc::slot2<void,SPObject*, SPObject *> sl2=sigc::bind(sigc::ptr_fun(mask_ref_changed), this);
cs2.connect(sl2);
- if (!object->style) object->style = sp_style_new_from_object(SP_OBJECT(item));
+ if (!this->style) this->style = sp_style_new_from_object(this);
- item->avoidRef = new SPAvoidRef(item);
+ this->avoidRef = new SPAvoidRef(this);
- new (&item->_transformed_signal) sigc::signal<void, NR::Matrix const *, SPItem *>();
+ new (&this->_transformed_signal) sigc::signal<void, NR::Matrix const *, SPItem *>();
}
bool SPItem::isVisibleAndUnlocked() const {
}
bool SPItem::isHidden() const {
+ if (!isEvaluated())
+ return true;
return style->display.computed == SP_CSS_DISPLAY_NONE;
}
}
bool SPItem::isHidden(unsigned display_key) const {
+ if (!isEvaluated())
+ return true;
for ( SPItemView *view(display) ; view ; view = view->next ) {
if ( view->key == display_key ) {
g_assert(view->arenaitem != NULL);
return true;
}
+void SPItem::setEvaluated(bool evaluated) {
+ _is_evaluated = evaluated;
+ _evaluated_status = StatusSet;
+}
+
+void SPItem::resetEvaluated() {
+ if ( StatusCalculated == _evaluated_status ) {
+ _evaluated_status = StatusUnknown;
+ bool oldValue = _is_evaluated;
+ if ( oldValue != isEvaluated() ) {
+ requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
+ }
+ } if ( StatusSet == _evaluated_status ) {
+ SPObject const *const parent = SP_OBJECT_PARENT(this);
+ if (SP_IS_SWITCH(parent)) {
+ SP_SWITCH(parent)->resetChildEvaluated();
+ }
+ }
+}
+
+bool SPItem::isEvaluated() const {
+ if ( StatusUnknown == _evaluated_status ) {
+ _is_evaluated = sp_item_evaluate(this);
+ _evaluated_status = StatusCalculated;
+ }
+ return _is_evaluated;
+}
+
/**
* Returns something suitable for the `Hide' checkbox in the Object Properties dialog box.
* Corresponds to setExplicitlyHidden.
item->transform_center_y = 0;
}
break;
+ case SP_PROP_SYSTEM_LANGUAGE:
+ case SP_PROP_REQUIRED_FEATURES:
+ case SP_PROP_REQUIRED_EXTENSIONS:
+ {
+ item->resetEvaluated();
+ // pass to default handler
+ }
default:
if (SP_ATTRIBUTE_IS_CSS(key)) {
sp_style_read_from_object(object->style, object);
NR::Rect sp_item_bbox_desktop(SPItem *item)
{
NRRect ret;
- sp_item_bbox_desktop(item, &ret);
+ sp_item_invoke_bbox(item, &ret, sp_item_i2d_affine(item), TRUE);
return NR::Rect(ret);
}
diff --git a/src/sp-item.h b/src/sp-item.h
index 141d3f88119d0dd5e774243adf615e28036f5529..cb34817e53bed9dcfe52b323a62ace2a7b1fc8a9 100644 (file)
--- a/src/sp-item.h
+++ b/src/sp-item.h
std::vector<SPGuideConstraint> constraints;
sigc::signal<void, NR::Matrix const *, SPItem *> _transformed_signal;
-
+
+ void init();
bool isLocked() const;
void setLocked(bool lock);
bool isHidden() const;
void setHidden(bool hidden);
+
+ bool isEvaluated() const;
+ void setEvaluated(bool visible);
+ void resetEvaluated();
bool isHidden(unsigned display_key) const;
sigc::connection connectTransformed(sigc::slot<void, NR::Matrix const *, SPItem *> slot) {
return _transformed_signal.connect(slot);
}
+
+private:
+ enum EvaluatedStatus
+ {
+ StatusUnknown, StatusCalculated, StatusSet
+ };
+
+ mutable bool _is_evaluated;
+ mutable EvaluatedStatus _evaluated_status;
};
typedef std::back_insert_iterator<std::vector<NR::Point> > SnapPointsIter;
diff --git a/src/sp-object-repr.cpp b/src/sp-object-repr.cpp
index 3987dbcbb99aa54edd291845317aec98aa1cd6ff..0f2ff9e6a5f7439c318b85459116e726c2cd0ddc 100644 (file)
--- a/src/sp-object-repr.cpp
+++ b/src/sp-object-repr.cpp
#include "sp-flowregion.h"
#include "sp-flowtext.h"
#include "sp-style-elem.h"
+#include "sp-switch.h"
#include "color-profile-fns.h"
#include "xml/repr.h"
{ "svg:stop", SP_TYPE_STOP },
{ "svg:svg", SP_TYPE_ROOT },
{ "svg:style", SP_TYPE_STYLE_ELEM },
- { "svg:switch", SP_TYPE_GROUP },
+ { "svg:switch", SP_TYPE_SWITCH },
{ "svg:symbol", SP_TYPE_SYMBOL },
{ "svg:text", SP_TYPE_TEXT },
{ "svg:textPath", SP_TYPE_TEXTPATH },
diff --git a/src/sp-switch.cpp b/src/sp-switch.cpp
--- /dev/null
+++ b/src/sp-switch.cpp
@@ -0,0 +1,182 @@
+#define __SP_SWITCH_CPP__
+
+/*
+ * SVG <switch> implementation
+ *
+ * Authors:
+ * Andrius R. <knutux@gmail.com>
+ *
+ * Copyright (C) 2006 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#if defined(WIN32) || defined(__APPLE__)
+# include <glibmm/i18n.h>
+#endif
+
+#include "sp-switch.h"
+#include "display/nr-arena-group.h"
+#include "conditions.h"
+
+static void sp_switch_class_init (SPSwitchClass *klass);
+static void sp_switch_init (SPSwitch *group);
+
+static SPGroupClass * parent_class;
+
+GType CSwitch::getType (void)
+{
+ static GType switch_type = 0;
+ if (!switch_type) {
+ GTypeInfo switch_info = {
+ sizeof (SPSwitchClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) sp_switch_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (SPSwitch),
+ 16, /* n_preallocs */
+ (GInstanceInitFunc) sp_switch_init,
+ NULL, /* value_table */
+ };
+ switch_type = g_type_register_static (SP_TYPE_GROUP, "SPSwitch", &switch_info, (GTypeFlags)0);
+ }
+ return switch_type;
+}
+
+static void
+sp_switch_class_init (SPSwitchClass *) {
+ parent_class = (SPGroupClass *)g_type_class_ref (SP_TYPE_GROUP);
+}
+
+static void sp_switch_init (SPSwitch *group)
+{
+ if (group->group)
+ delete group->group;
+
+ group->group = new CSwitch(group);
+}
+
+CSwitch::CSwitch(SPGroup *group) : CGroup(group), _cached_item(NULL), _release_handler_id(0) {
+}
+
+CSwitch::~CSwitch() {
+ _releaseLastItem(_cached_item);
+}
+
+SPObject *CSwitch::_evaluateFirst() {
+ for (SPObject *child = sp_object_first_child(_group) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
+ if (sp_item_evaluate(SP_ITEM(child)))
+ return child;
+ }
+ return NULL;
+}
+
+GSList *CSwitch::_childList(bool add_ref, Action action) {
+ if ( ActionGeneral != action ) {
+ return CGroup::_childList(add_ref, action);
+ }
+
+ SPObject *child = _evaluateFirst();
+ if (NULL == child)
+ return NULL;
+
+ if (add_ref)
+ g_object_ref (G_OBJECT (child));
+
+ return g_slist_prepend (NULL, child);
+}
+
+gchar *CSwitch::getDescription() {
+ gint len = getItemCount();
+ return g_strdup_printf(
+ ngettext("<b>Conditional group</b> of <b>%d</b> object",
+ "<b>Conditional group</b> of <b>%d</b> objects",
+ len), len);
+}
+
+void CSwitch::onChildAdded(Inkscape::XML::Node *) {
+ _reevaluate(true);
+}
+
+void CSwitch::onChildRemoved(Inkscape::XML::Node *) {
+ _reevaluate();
+}
+
+void CSwitch::onOrderChanged (Inkscape::XML::Node *, Inkscape::XML::Node *, Inkscape::XML::Node *)
+{
+ _reevaluate();
+}
+
+void CSwitch::_reevaluate(bool add_to_arena) {
+ SPObject *evaluated_child = _evaluateFirst();
+ if (!evaluated_child || _cached_item == evaluated_child) {
+ return;
+ }
+
+ _releaseLastItem(_cached_item);
+
+ SPItem * child;
+ for ( GSList *l = _childList(false, ActionShow);
+ NULL != l ; l = g_slist_remove (l, l->data))
+ {
+ SPObject *o = SP_OBJECT (l->data);
+ if ( !SP_IS_ITEM (o) ) {
+ continue;
+ }
+
+ child = SP_ITEM (o);
+ child->setEvaluated(o == evaluated_child);
+ }
+
+ _cached_item = evaluated_child;
+ _release_handler_id = g_signal_connect(
+ G_OBJECT(evaluated_child), "release",
+ G_CALLBACK(&CSwitch::_releaseItem),
+ this);
+
+ _group->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
+}
+
+void CSwitch::_releaseItem(SPObject *obj, CSwitch *selection)
+{
+ selection->_releaseLastItem(obj);
+}
+
+void CSwitch::_releaseLastItem(SPObject *obj)
+{
+ if (NULL == _cached_item || _cached_item != obj)
+ return;
+
+ g_signal_handler_disconnect(G_OBJECT(_cached_item), _release_handler_id);
+ _release_handler_id = 0;
+ _cached_item = NULL;
+}
+
+void CSwitch::_showChildren (NRArena *arena, NRArenaItem *ai, unsigned int key, unsigned int flags) {
+ SPObject *evaluated_child = _evaluateFirst();
+
+ NRArenaItem *ac = NULL;
+ NRArenaItem *ar = NULL;
+ SPItem * child;
+ GSList *l = _childList(false, ActionShow);
+ while (l) {
+ SPObject *o = SP_OBJECT (l->data);
+ if (SP_IS_ITEM (o)) {
+ child = SP_ITEM (o);
+ child->setEvaluated(o == evaluated_child);
+ ac = sp_item_invoke_show (child, arena, key, flags);
+ if (ac) {
+ nr_arena_item_add_child (ai, ac, ar);
+ ar = ac;
+ nr_arena_item_unref (ac);
+ }
+ }
+ l = g_slist_remove (l, o);
+ }
+}
diff --git a/src/sp-switch.h b/src/sp-switch.h
--- /dev/null
+++ b/src/sp-switch.h
@@ -0,0 +1,61 @@
+#ifndef __SP_SWITCH_H__
+#define __SP_SWITCH_H__
+
+/*
+ * SVG <switch> implementation
+ *
+ * Authors:
+ * Andrius R. <knutux@gmail.com>
+ *
+ * Copyright (C) 2006 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "sp-item-group.h"
+
+#define SP_TYPE_SWITCH (CSwitch::getType())
+#define SP_SWITCH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_SWITCH, SPSwitch))
+#define SP_SWITCH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_SWITCH, SPSwitchClass))
+#define SP_IS_SWITCH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_SWITCH))
+#define SP_IS_SWITCH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_SWITCH))
+
+/*
+ * Virtual methods of SPSwitch
+ */
+class CSwitch : public CGroup {
+public:
+ CSwitch(SPGroup *group);
+ virtual ~CSwitch();
+
+ friend class SPSwitch;
+
+ static GType getType();
+
+ virtual void onChildAdded(Inkscape::XML::Node *child);
+ virtual void onChildRemoved(Inkscape::XML::Node *child);
+ virtual void onOrderChanged(Inkscape::XML::Node *child, Inkscape::XML::Node *old_ref, Inkscape::XML::Node *new_ref);
+ virtual gchar *getDescription();
+
+protected:
+ virtual GSList *_childList(bool add_ref, Action action);
+ virtual void _showChildren (NRArena *arena, NRArenaItem *ai, unsigned int key, unsigned int flags);
+
+ SPObject *_evaluateFirst();
+ void _reevaluate(bool add_to_arena = false);
+ static void _releaseItem(SPObject *obj, CSwitch *selection);
+ void _releaseLastItem(SPObject *obj);
+
+private:
+ SPObject *_cached_item;
+ gulong _release_handler_id;
+};
+
+struct SPSwitch : public SPGroup {
+ void resetChildEvaluated() { ((CSwitch *)group)->_reevaluate(); }
+};
+
+struct SPSwitchClass : public SPGroupClass {
+};
+
+#endif