Initial import of CSS source editor from GSoC project, see bug 250181: [Tooling][Theming] Integrate theme editor into RAP tooling
https://bugs.eclipse.org/bugs/show_bug.cgi?id=250181
diff --git a/bundles/org.eclipse.rap.themeeditor/.classpath b/bundles/org.eclipse.rap.themeeditor/.classpath
new file mode 100644
index 0000000..97bc37a
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/.classpath
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.4"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="css"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/bundles/org.eclipse.rap.themeeditor/.project b/bundles/org.eclipse.rap.themeeditor/.project
new file mode 100644
index 0000000..b4cfd6c
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.rap.themeeditor</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/bundles/org.eclipse.rap.themeeditor/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.rap.themeeditor/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..60286e6
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+#Sat Dec 05 18:11:56 CET 2009
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2
+org.eclipse.jdt.core.compiler.compliance=1.4
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning
+org.eclipse.jdt.core.compiler.source=1.3
diff --git a/bundles/org.eclipse.rap.themeeditor/META-INF/MANIFEST.MF b/bundles/org.eclipse.rap.themeeditor/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..2f0b4d1
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/META-INF/MANIFEST.MF
@@ -0,0 +1,19 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: CSS Editor
+Bundle-SymbolicName: org.eclipse.rap.themeeditor;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-Activator: org.eclipse.rap.themeeditor.ThemeEditorPlugin
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime
+Bundle-ActivationPolicy: lazy
+Bundle-RequiredExecutionEnvironment: J2SE-1.4
+Import-Package: org.eclipse.core.filebuffers,
+ org.eclipse.jface.text,
+ org.eclipse.jface.text.contentassist,
+ org.eclipse.jface.text.presentation,
+ org.eclipse.jface.text.rules,
+ org.eclipse.jface.text.source,
+ org.eclipse.ui.editors.text,
+ org.eclipse.ui.texteditor,
+ org.eclipse.ui.views.contentoutline
diff --git a/bundles/org.eclipse.rap.themeeditor/build.properties b/bundles/org.eclipse.rap.themeeditor/build.properties
new file mode 100644
index 0000000..c8a64b4
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/build.properties
@@ -0,0 +1,7 @@
+source.. = src/,\
+ css/
+output.. = bin/
+bin.includes = .,\
+ META-INF/,\
+ plugin.xml
+
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/CSSLexicalUnit.java b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/CSSLexicalUnit.java
new file mode 100644
index 0000000..8ce213f
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/CSSLexicalUnit.java
@@ -0,0 +1,428 @@
+/*
+
+ Copyright 2000-2001,2003 The Apache Software Foundation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.apache.batik.css.parser;
+
+import org.w3c.css.sac.LexicalUnit;
+
+/**
+ * This class implements the {@link LexicalUnit} interface.
+ *
+ * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
+ * @version $Id: CSSLexicalUnit.java,v 1.1 2009/12/06 10:40:09 rsternber Exp $
+ */
+public abstract class CSSLexicalUnit implements LexicalUnit {
+
+ public static final String UNIT_TEXT_CENTIMETER = "cm";
+ public static final String UNIT_TEXT_DEGREE = "deg";
+ public static final String UNIT_TEXT_EM = "em";
+ public static final String UNIT_TEXT_EX = "ex";
+ public static final String UNIT_TEXT_GRADIAN = "grad";
+ public static final String UNIT_TEXT_HERTZ = "Hz";
+ public static final String UNIT_TEXT_INCH = "in";
+ public static final String UNIT_TEXT_KILOHERTZ = "kHz";
+ public static final String UNIT_TEXT_MILLIMETER = "mm";
+ public static final String UNIT_TEXT_MILLISECOND = "ms";
+ public static final String UNIT_TEXT_PERCENTAGE = "%";
+ public static final String UNIT_TEXT_PICA = "pc";
+ public static final String UNIT_TEXT_PIXEL = "px";
+ public static final String UNIT_TEXT_POINT = "pt";
+ public static final String UNIT_TEXT_RADIAN = "rad";
+ public static final String UNIT_TEXT_REAL = "";
+ public static final String UNIT_TEXT_SECOND = "s";
+
+
+ /**
+ * The lexical unit type.
+ */
+ protected short lexicalUnitType;
+
+ /**
+ * The next lexical unit.
+ */
+ protected LexicalUnit nextLexicalUnit;
+
+ /**
+ * The previous lexical unit.
+ */
+ protected LexicalUnit previousLexicalUnit;
+
+ /**
+ * Creates a new LexicalUnit.
+ */
+ protected CSSLexicalUnit(short t, LexicalUnit prev) {
+ lexicalUnitType = t;
+ previousLexicalUnit = prev;
+ if (prev != null) {
+ ((CSSLexicalUnit)prev).nextLexicalUnit = this;
+ }
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link LexicalUnit#getLexicalUnitType()}.
+ */
+ public short getLexicalUnitType() {
+ return lexicalUnitType;
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link LexicalUnit#getNextLexicalUnit()}.
+ */
+ public LexicalUnit getNextLexicalUnit() {
+ return nextLexicalUnit;
+ }
+
+ /**
+ * Sets the next lexical unit.
+ */
+ public void setNextLexicalUnit(LexicalUnit lu) {
+ nextLexicalUnit = lu;
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link LexicalUnit#getPreviousLexicalUnit()}.
+ */
+ public LexicalUnit getPreviousLexicalUnit() {
+ return previousLexicalUnit;
+ }
+
+ /**
+ * Sets the previous lexical unit.
+ */
+ public void setPreviousLexicalUnit(LexicalUnit lu) {
+ previousLexicalUnit = lu;
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link LexicalUnit#getIntegerValue()}.
+ */
+ public int getIntegerValue() {
+ throw new IllegalStateException();
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link LexicalUnit#getFloatValue()}.
+ */
+ public float getFloatValue() {
+ throw new IllegalStateException();
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link LexicalUnit#getDimensionUnitText()}.
+ */
+ public String getDimensionUnitText() {
+ switch (lexicalUnitType) {
+ case LexicalUnit.SAC_CENTIMETER: return UNIT_TEXT_CENTIMETER;
+ case LexicalUnit.SAC_DEGREE: return UNIT_TEXT_DEGREE;
+ case LexicalUnit.SAC_EM: return UNIT_TEXT_EM;
+ case LexicalUnit.SAC_EX: return UNIT_TEXT_EX;
+ case LexicalUnit.SAC_GRADIAN: return UNIT_TEXT_GRADIAN;
+ case LexicalUnit.SAC_HERTZ: return UNIT_TEXT_HERTZ;
+ case LexicalUnit.SAC_INCH: return UNIT_TEXT_INCH;
+ case LexicalUnit.SAC_KILOHERTZ: return UNIT_TEXT_KILOHERTZ;
+ case LexicalUnit.SAC_MILLIMETER: return UNIT_TEXT_MILLIMETER;
+ case LexicalUnit.SAC_MILLISECOND: return UNIT_TEXT_MILLISECOND;
+ case LexicalUnit.SAC_PERCENTAGE: return UNIT_TEXT_PERCENTAGE;
+ case LexicalUnit.SAC_PICA: return UNIT_TEXT_PICA;
+ case LexicalUnit.SAC_PIXEL: return UNIT_TEXT_PIXEL;
+ case LexicalUnit.SAC_POINT: return UNIT_TEXT_POINT;
+ case LexicalUnit.SAC_RADIAN: return UNIT_TEXT_RADIAN;
+ case LexicalUnit.SAC_REAL: return UNIT_TEXT_REAL;
+ case LexicalUnit.SAC_SECOND: return UNIT_TEXT_SECOND;
+ default:
+ throw new IllegalStateException("No Unit Text for type: " +
+ lexicalUnitType);
+ }
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link LexicalUnit#getFunctionName()}.
+ */
+ public String getFunctionName() {
+ throw new IllegalStateException();
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link LexicalUnit#getParameters()}.
+ */
+ public LexicalUnit getParameters() {
+ throw new IllegalStateException();
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link LexicalUnit#getStringValue()}.
+ */
+ public String getStringValue() {
+ throw new IllegalStateException();
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link LexicalUnit#getSubValues()}.
+ */
+ public LexicalUnit getSubValues() {
+ throw new IllegalStateException();
+ }
+
+ /**
+ * Creates a new integer lexical unit.
+ */
+ public static CSSLexicalUnit createSimple(short t, LexicalUnit prev) {
+ return new SimpleLexicalUnit(t, prev);
+ }
+
+ /**
+ * This class represents a simple unit.
+ */
+ protected static class SimpleLexicalUnit extends CSSLexicalUnit {
+
+ /**
+ * Creates a new LexicalUnit.
+ */
+ public SimpleLexicalUnit(short t, LexicalUnit prev) {
+ super(t, prev);
+ }
+ }
+
+ /**
+ * Creates a new integer lexical unit.
+ */
+ public static CSSLexicalUnit createInteger(int val, LexicalUnit prev) {
+ return new IntegerLexicalUnit(val, prev);
+ }
+
+ /**
+ * This class represents an integer unit.
+ */
+ protected static class IntegerLexicalUnit extends CSSLexicalUnit {
+
+ /**
+ * The integer value.
+ */
+ protected int value;
+
+ /**
+ * Creates a new LexicalUnit.
+ */
+ public IntegerLexicalUnit(int val, LexicalUnit prev) {
+ super(LexicalUnit.SAC_INTEGER, prev);
+ value = val;
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link LexicalUnit#getIntegerValue()}.
+ */
+ public int getIntegerValue() {
+ return value;
+ }
+ }
+
+ /**
+ * Creates a new float lexical unit.
+ */
+ public static CSSLexicalUnit createFloat(short t, float val, LexicalUnit prev) {
+ return new FloatLexicalUnit(t, val, prev);
+ }
+
+ /**
+ * This class represents a float unit.
+ */
+ protected static class FloatLexicalUnit extends CSSLexicalUnit {
+
+ /**
+ * The float value.
+ */
+ protected float value;
+
+ /**
+ * Creates a new LexicalUnit.
+ */
+ public FloatLexicalUnit(short t, float val, LexicalUnit prev) {
+ super(t, prev);
+ value = val;
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link LexicalUnit#getFloatValue()}.
+ */
+ public float getFloatValue() {
+ return value;
+ }
+ }
+
+ /**
+ * Creates a new float lexical unit.
+ */
+ public static CSSLexicalUnit createDimension(float val, String dim,
+ LexicalUnit prev) {
+ return new DimensionLexicalUnit(val, dim, prev);
+ }
+
+ /**
+ * This class represents a dimension unit.
+ */
+ protected static class DimensionLexicalUnit extends CSSLexicalUnit {
+
+ /**
+ * The float value.
+ */
+ protected float value;
+
+ /**
+ * The dimension.
+ */
+ protected String dimension;
+
+ /**
+ * Creates a new LexicalUnit.
+ */
+ public DimensionLexicalUnit(float val, String dim, LexicalUnit prev) {
+ super(SAC_DIMENSION, prev);
+ value = val;
+ dimension = dim;
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link LexicalUnit#getFloatValue()}.
+ */
+ public float getFloatValue() {
+ return value;
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link LexicalUnit#getDimensionUnitText()}.
+ */
+ public String getDimensionUnitText() {
+ return dimension;
+ }
+ }
+
+ /**
+ * Creates a new function lexical unit.
+ */
+ public static CSSLexicalUnit createFunction(String f, LexicalUnit params,
+ LexicalUnit prev) {
+ return new FunctionLexicalUnit(f, params, prev);
+ }
+
+ /**
+ * This class represents a function unit.
+ */
+ protected static class FunctionLexicalUnit extends CSSLexicalUnit {
+
+ /**
+ * The function name.
+ */
+ protected String name;
+
+ /**
+ * The function parameters.
+ */
+ protected LexicalUnit parameters;
+
+ /**
+ * Creates a new LexicalUnit.
+ */
+ public FunctionLexicalUnit(String f, LexicalUnit params, LexicalUnit prev) {
+ super(SAC_FUNCTION, prev);
+ name = f;
+ parameters = params;
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link LexicalUnit#getFunctionName()}.
+ */
+ public String getFunctionName() {
+ return name;
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link LexicalUnit#getParameters()}.
+ */
+ public LexicalUnit getParameters() {
+ return parameters;
+ }
+
+ }
+
+ /**
+ * Creates a new function lexical unit.
+ */
+ public static CSSLexicalUnit createPredefinedFunction(short t, LexicalUnit params,
+ LexicalUnit prev) {
+ return new PredefinedFunctionLexicalUnit(t, params, prev);
+ }
+
+ /**
+ * This class represents a function unit.
+ */
+ protected static class PredefinedFunctionLexicalUnit extends CSSLexicalUnit {
+
+ /**
+ * The function parameters.
+ */
+ protected LexicalUnit parameters;
+
+ /**
+ * Creates a new LexicalUnit.
+ */
+ public PredefinedFunctionLexicalUnit(short t, LexicalUnit params,
+ LexicalUnit prev) {
+ super(t, prev);
+ parameters = params;
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link LexicalUnit#getParameters()}.
+ */
+ public LexicalUnit getParameters() {
+ return parameters;
+ }
+ }
+
+ /**
+ * Creates a new string lexical unit.
+ */
+ public static CSSLexicalUnit createString(short t, String val, LexicalUnit prev) {
+ return new StringLexicalUnit(t, val, prev);
+ }
+
+ /**
+ * This class represents a string unit.
+ */
+ protected static class StringLexicalUnit extends CSSLexicalUnit {
+
+ /**
+ * The string value.
+ */
+ protected String value;
+
+ /**
+ * Creates a new LexicalUnit.
+ */
+ public StringLexicalUnit(short t, String val, LexicalUnit prev) {
+ super(t, prev);
+ value = val;
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link LexicalUnit#getStringValue()}.
+ */
+ public String getStringValue() {
+ return value;
+ }
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/CSSSACMediaList.java b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/CSSSACMediaList.java
new file mode 100644
index 0000000..cd0b1e4
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/CSSSACMediaList.java
@@ -0,0 +1,71 @@
+/*
+
+ Copyright 2000-2001 The Apache Software Foundation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.apache.batik.css.parser;
+
+import org.w3c.css.sac.SACMediaList;
+
+/**
+ * This class implements the {@link SACMediaList} interface.
+ *
+ * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
+ * @version $Id: CSSSACMediaList.java,v 1.1 2009/12/06 10:40:09 rsternber Exp $
+ */
+public class CSSSACMediaList implements SACMediaList {
+
+ /**
+ * The list.
+ */
+ protected String[] list = new String[3];
+
+ /**
+ * The list length.
+ */
+ protected int length;
+
+ /**
+ * <b>SAC</b>: Returns the length of this selector list
+ */
+ public int getLength() {
+ return length;
+ }
+
+ /**
+ * <b>SAC</b>: Returns the selector at the specified index, or
+ * <code>null</code> if this is not a valid index.
+ */
+ public String item(int index) {
+ if (index < 0 || index >= length) {
+ return null;
+ }
+ return list[index];
+ }
+
+ /**
+ * Appends an item to the list.
+ */
+ public void append(String item) {
+ if (length == list.length) {
+ String[] tmp = list;
+ list = new String[list.length * 3 / 2];
+ for (int i = 0; i < tmp.length; i++) {
+ list[i] = tmp[i];
+ }
+ }
+ list[length++] = item;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/CSSSelectorList.java b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/CSSSelectorList.java
new file mode 100644
index 0000000..c780162
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/CSSSelectorList.java
@@ -0,0 +1,99 @@
+/*
+
+ Copyright 2000-2001 The Apache Software Foundation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.apache.batik.css.parser;
+
+import org.w3c.css.sac.Selector;
+import org.w3c.css.sac.SelectorList;
+
+/**
+ * This class implements the {@link SelectorList} interface.
+ *
+ * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
+ * @version $Id: CSSSelectorList.java,v 1.1 2009/12/06 10:40:09 rsternber Exp $
+ */
+public class CSSSelectorList implements SelectorList {
+
+ /**
+ * The list.
+ */
+ protected Selector[] list = new Selector[3];
+
+ /**
+ * The list length.
+ */
+ protected int length;
+
+ /**
+ * <b>SAC</b>: Returns the length of this selector list
+ */
+ public int getLength() {
+ return length;
+ }
+
+ /**
+ * <b>SAC</b>: Returns the selector at the specified index, or
+ * <code>null</code> if this is not a valid index.
+ */
+ public Selector item(int index) {
+ if (index < 0 || index >= length) {
+ return null;
+ }
+ return list[index];
+ }
+
+ /**
+ * Appends an item to the list.
+ */
+ public void append(Selector item) {
+ if (length == list.length) {
+ Selector[] tmp = list;
+ list = new Selector[list.length * 3 / 2];
+ for (int i = 0; i < tmp.length; i++) {
+ list[i] = tmp[i];
+ }
+ }
+ list[length++] = item;
+ }
+
+ /*
+ * BEGIN Modification for Theme Editor
+ * Removes an item from the list.
+ */
+ public void remove( final Selector item ) {
+ if (item==null) {
+ return;
+ }
+ Selector[] tmp = list;
+ list = new Selector[ tmp.length ];
+ int j = 0;
+ for (int i = 0; i < tmp.length; i++) {
+ if ( tmp[i] != null ) {
+ if ( !tmp[i].toString().equals( item.toString() ) ) {
+ list[j] = tmp[i];
+ j++;
+ }
+ else {
+ length--;
+ }
+ }
+ }
+ }
+ /*
+ * END Modification for Theme Editor
+ */
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/LexicalUnits.java b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/LexicalUnits.java
new file mode 100644
index 0000000..573ff1f
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/LexicalUnits.java
@@ -0,0 +1,302 @@
+/*
+
+ Copyright 2000-2001 The Apache Software Foundation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.apache.batik.css.parser;
+
+/**
+ * This interface defines the constants that represent CSS lexical units.
+ *
+ * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
+ * @version $Id: LexicalUnits.java,v 1.1 2009/12/06 10:40:09 rsternber Exp $
+ */
+public interface LexicalUnits {
+
+ /**
+ * Represents the EOF lexical unit.
+ */
+ int EOF = 0;
+
+ /**
+ * Represents the '{' lexical unit.
+ */
+ int LEFT_CURLY_BRACE = 1;
+
+ /**
+ * Represents the '}' lexical unit.
+ */
+ int RIGHT_CURLY_BRACE = 2;
+
+ /**
+ * Represents the '=' lexical unit.
+ */
+ int EQUAL = 3;
+
+ /**
+ * Represents the '+' lexical unit.
+ */
+ int PLUS = 4;
+
+ /**
+ * Represents the '-' lexical unit.
+ */
+ int MINUS = 5;
+
+ /**
+ * Represents the ',' lexical unit.
+ */
+ int COMMA = 6;
+
+ /**
+ * Represents the '.' lexical unit.
+ */
+ int DOT = 7;
+
+ /**
+ * Represents the ';' lexical unit.
+ */
+ int SEMI_COLON = 8;
+
+ /**
+ * Represents the '>' lexical unit.
+ */
+ int PRECEDE = 9;
+
+ /**
+ * Represents the '/' lexical unit.
+ */
+ int DIVIDE = 10;
+
+ /**
+ * Represents the '[' lexical unit.
+ */
+ int LEFT_BRACKET = 11;
+
+ /**
+ * Represents the ']' lexical unit.
+ */
+ int RIGHT_BRACKET = 12;
+
+ /**
+ * Represents the '*' lexical unit.
+ */
+ int ANY = 13;
+
+ /**
+ * Represents the '(' lexical unit.
+ */
+ int LEFT_BRACE = 14;
+
+ /**
+ * Represents the ')' lexical unit.
+ */
+ int RIGHT_BRACE = 15;
+
+ /**
+ * Represents the ':' lexical unit.
+ */
+ int COLON = 16;
+
+ /**
+ * Represents the white space lexical unit.
+ */
+ int SPACE = 17;
+
+ /**
+ * Represents the comment lexical unit.
+ */
+ int COMMENT = 18;
+
+ /**
+ * Represents the string lexical unit.
+ */
+ int STRING = 19;
+
+ /**
+ * Represents the identifier lexical unit.
+ */
+ int IDENTIFIER = 20;
+
+ /**
+ * Represents the '<!--' lexical unit.
+ */
+ int CDO = 21;
+
+ /**
+ * Represents the '-->' lexical unit.
+ */
+ int CDC = 22;
+
+ /**
+ * Represents the '!important' lexical unit.
+ */
+ int IMPORTANT_SYMBOL = 23;
+
+ /**
+ * Represents an integer.
+ */
+ int INTEGER = 24;
+
+ /**
+ * Represents the '|=' lexical unit.
+ */
+ int DASHMATCH = 25;
+
+ /**
+ * Represents the '~=' lexical unit.
+ */
+ int INCLUDES = 26;
+
+ /**
+ * Represents the '#name' lexical unit.
+ */
+ int HASH = 27;
+
+ /**
+ * Represents the '@import' lexical unit.
+ */
+ int IMPORT_SYMBOL = 28;
+
+ /**
+ * Represents the '@ident' lexical unit.
+ */
+ int AT_KEYWORD = 29;
+
+ /**
+ * Represents the '@charset' lexical unit.
+ */
+ int CHARSET_SYMBOL = 30;
+
+ /**
+ * Represents the '@font-face' lexical unit.
+ */
+ int FONT_FACE_SYMBOL = 31;
+
+ /**
+ * Represents the '@media' lexical unit.
+ */
+ int MEDIA_SYMBOL = 32;
+
+ /**
+ * Represents the '@page' lexical unit.
+ */
+ int PAGE_SYMBOL = 33;
+
+ /**
+ * Represents a dimension lexical unit.
+ */
+ int DIMENSION = 34;
+
+ /**
+ * Represents a ex lexical unit.
+ */
+ int EX = 35;
+
+ /**
+ * Represents a em lexical unit.
+ */
+ int EM = 36;
+
+ /**
+ * Represents a cm lexical unit.
+ */
+ int CM = 37;
+
+ /**
+ * Represents a mm lexical unit.
+ */
+ int MM = 38;
+
+ /**
+ * Represents a in lexical unit.
+ */
+ int IN = 39;
+
+ /**
+ * Represents a ms lexical unit.
+ */
+ int MS = 40;
+
+ /**
+ * Represents a hz lexical unit.
+ */
+ int HZ = 41;
+
+ /**
+ * Represents a % lexical unit.
+ */
+ int PERCENTAGE = 42;
+
+ /**
+ * Represents a s lexical unit.
+ */
+ int S = 43;
+
+ /**
+ * Represents a pc lexical unit.
+ */
+ int PC = 44;
+
+ /**
+ * Represents a pt lexical unit.
+ */
+ int PT = 45;
+
+ /**
+ * Represents a px lexical unit.
+ */
+ int PX = 46;
+
+ /**
+ * Represents a deg lexical unit.
+ */
+ int DEG = 47;
+
+ /**
+ * Represents a rad lexical unit.
+ */
+ int RAD = 48;
+
+ /**
+ * Represents a grad lexical unit.
+ */
+ int GRAD = 49;
+
+ /**
+ * Represents a khz lexical unit.
+ */
+ int KHZ = 50;
+
+ /**
+ * Represents a 'url(URI)' lexical unit.
+ */
+ int URI = 51;
+
+ /**
+ * Represents a 'ident(' lexical unit.
+ */
+ int FUNCTION = 52;
+
+ /**
+ * Represents a unicode range lexical unit.
+ */
+ int UNICODE_RANGE = 53;
+
+ /**
+ * represents a real number.
+ */
+ int REAL = 54;
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/Messages.java b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/Messages.java
new file mode 100644
index 0000000..90786fe
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/Messages.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2002-2006 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+package org.apache.batik.css.parser;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class Messages {
+
+ private static final String BUNDLE_NAME = "org.apache.batik.css.parser.Messages"; //$NON-NLS-1$
+
+ private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle( BUNDLE_NAME );
+
+ private Messages() {
+ }
+
+ public static String getString( String key ) {
+ try {
+ return RESOURCE_BUNDLE.getString( key );
+ } catch( MissingResourceException e ) {
+ return '!' + key + '!';
+ }
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/Messages.properties b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/Messages.properties
new file mode 100644
index 0000000..db7688d
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/Messages.properties
@@ -0,0 +1,83 @@
+###########################################################################
+# Copyright 1999-2003,2005 The Apache Software Foundation.
+###########################################################################
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+###########################################################################
+#
+# The error messages for the CSS parser.
+#
+# Author: stephane@hillion.org
+#
+
+charset.string = \
+A string was expected in a @charset rule.
+
+semicolon = \
+';' expected.
+
+colon = \
+':' expected.
+
+eof = \
+Unexpected end of file.
+
+eof.expected = \
+End of file expected.
+
+character = \
+Unexpected character.
+
+string.or.uri = \
+String or URI expected.
+
+identifier = \
+Identifier expected.
+
+identifier.character = \
+Invalid identifier start character.
+
+identifier.or.string = \
+Identifier or string expected.
+
+left.curly.brace = \
+'{' expected.
+
+right.curly.brace = \
+'}' expected.
+
+right.brace = \
+')' expected.
+
+right.bracket = \
+']' expected.
+
+token = \
+Unexpected token: {0} (see LexicalUnits).
+
+rgb.color = \
+Invalid RGB color: {0}.
+
+encoding = \
+Invalid encoding: {0}.
+
+number.format = \
+Invalid number.
+
+duplicate.pseudo.element = \
+A pseudo element has already been defined.
+
+pseudo.function = \
+Invalid pseudo-function.
+
+empty.source = \
+Empty input source.
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/ParseException.java b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/ParseException.java
new file mode 100644
index 0000000..1ec53fe
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/ParseException.java
@@ -0,0 +1,128 @@
+/*
+
+ Copyright 2000 The Apache Software Foundation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.apache.batik.css.parser;
+
+/**
+ * This class encapsulates a general parse error or warning.
+ *
+ * <p>This class can contain basic error or warning information from
+ * either the parser or the application.
+ *
+ * <p>If the application needs to pass through other types of
+ * exceptions, it must wrap those exceptions in a ParseException.
+ *
+ * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
+ * @version $Id: ParseException.java,v 1.1 2009/12/06 10:40:09 rsternber Exp $
+ */
+public class ParseException extends RuntimeException {
+
+ /**
+ * @serial The embedded exception if tunnelling, or null.
+ */
+ protected Exception exception;
+
+ /**
+ * @serial The line number.
+ */
+ protected int lineNumber;
+
+ /**
+ * @serial The column number.
+ */
+ protected int columnNumber;
+
+ /**
+ * Creates a new ParseException.
+ * @param message The error or warning message.
+ * @param line The line of the last parsed character.
+ * @param column The column of the last parsed character.
+ */
+ public ParseException (String message, int line, int column) {
+ super(message);
+ exception = null;
+ lineNumber = line;
+ columnNumber = column;
+ }
+
+ /**
+ * Creates a new ParseException wrapping an existing exception.
+ *
+ * <p>The existing exception will be embedded in the new
+ * one, and its message will become the default message for
+ * the ParseException.
+ * @param e The exception to be wrapped in a ParseException.
+ */
+ public ParseException (Exception e) {
+ exception = e;
+ lineNumber = -1;
+ columnNumber = -1;
+ }
+
+ /**
+ * Creates a new ParseException from an existing exception.
+ *
+ * <p>The existing exception will be embedded in the new
+ * one, but the new exception will have its own message.
+ * @param message The detail message.
+ * @param e The exception to be wrapped in a SAXException.
+ */
+ public ParseException (String message, Exception e) {
+ super(message);
+ this.exception = e;
+ }
+
+ /**
+ * Return a detail message for this exception.
+ *
+ * <p>If there is a embedded exception, and if the ParseException
+ * has no detail message of its own, this method will return
+ * the detail message from the embedded exception.
+ * @return The error or warning message.
+ */
+ public String getMessage () {
+ String message = super.getMessage();
+
+ if (message == null && exception != null) {
+ return exception.getMessage();
+ } else {
+ return message;
+ }
+ }
+
+ /**
+ * Return the embedded exception, if any.
+ * @return The embedded exception, or null if there is none.
+ */
+ public Exception getException () {
+ return exception;
+ }
+
+ /**
+ * Returns the line of the last parsed character.
+ */
+ public int getLineNumber() {
+ return lineNumber;
+ }
+
+ /**
+ * Returns the column of the last parsed character.
+ */
+ public int getColumnNumber() {
+ return columnNumber;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/Parser.java b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/Parser.java
new file mode 100644
index 0000000..3c05fcb
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/Parser.java
@@ -0,0 +1,1733 @@
+/*
+
+ Copyright 2000-2003 The Apache Software Foundation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.apache.batik.css.parser;
+
+import java.io.*;
+import java.text.MessageFormat;
+import java.util.*;
+
+import org.eclipse.rwt.internal.theme.css.ParserUtil;
+import org.w3c.css.sac.*;
+
+/**
+ * This class implements the {@link _org.w3c.css.sac.Parser} interface.
+ *
+ * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
+ * @version $Id: Parser.java,v 1.1 2009/12/06 10:40:09 rsternber Exp $
+ */
+public class Parser implements org.w3c.css.sac.Parser {
+
+ /**
+ * The default resource bundle base name.
+ */
+ public final static String BUNDLE_CLASSNAME =
+ "org.apache.batik.css.parser.resources.Messages";
+
+ /**
+ * The scanner used to scan the input source.
+ */
+ protected Scanner scanner;
+
+ /**
+ * The current lexical unit.
+ */
+ protected int current;
+
+ /**
+ * The document handler.
+ */
+ protected DocumentHandler documentHandler = null;
+
+ /**
+ * The selector factory.
+ */
+ protected SelectorFactory selectorFactory = null;
+
+ /**
+ * The condition factory.
+ */
+ protected ConditionFactory conditionFactory = null;
+
+ /**
+ * The error handler.
+ */
+ protected ErrorHandler errorHandler = null;
+
+ /**
+ * To store the current pseudo element.
+ */
+ protected String pseudoElement;
+
+ /**
+ * The document URI.
+ */
+ protected String documentURI;
+
+ /**
+ * <b>SAC</b>: Implements {@link
+ * _org.w3c.css.sac.Parser#getParserVersion()}.
+ * @return "http://www.w3.org/TR/REC-CSS2".
+ */
+ public String getParserVersion() {
+ return "http://www.w3.org/TR/REC-CSS2";
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link _org.w3c.css.sac.Parser#setLocale(Locale)}.
+ */
+ public void setLocale(Locale locale) throws CSSException {
+// localizableSupport.setLocale(locale);
+ }
+
+// /**
+// * Implements {@link org.apache.batik.i18n.Localizable#getLocale()}.
+// */
+// public Locale getLocale() {
+// return localizableSupport.getLocale();
+// }
+
+ /**
+ * Implements {@link
+ * org.apache.batik.i18n.Localizable#formatMessage(String,Object[])}.
+ */
+ public String formatMessage(String key, Object[] args)
+ throws MissingResourceException {
+ String pattern = Messages.getString( key );
+ return MessageFormat.format( pattern, args );
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link
+ * _org.w3c.css.sac.Parser#setDocumentHandler(DocumentHandler)}.
+ */
+ public void setDocumentHandler(DocumentHandler handler) {
+ documentHandler = handler;
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link
+ * _org.w3c.css.sac.Parser#setSelectorFactory(SelectorFactory)}.
+ */
+ public void setSelectorFactory(SelectorFactory factory) {
+ selectorFactory = factory;
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link
+ * _org.w3c.css.sac.Parser#setConditionFactory(ConditionFactory)}.
+ */
+ public void setConditionFactory(ConditionFactory factory) {
+ conditionFactory = factory;
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link
+ * _org.w3c.css.sac.Parser#setErrorHandler(ErrorHandler)}.
+ */
+ public void setErrorHandler(ErrorHandler handler) {
+ errorHandler = handler;
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link
+ * _org.w3c.css.sac.Parser#parseStyleSheet(InputSource)}.
+ */
+ public void parseStyleSheet(InputSource source)
+ throws CSSException, IOException {
+ scanner = createScanner(source);
+
+ try {
+ documentHandler.startDocument(source);
+
+ current = scanner.next();
+ switch (current) {
+ case LexicalUnits.CHARSET_SYMBOL:
+ if (nextIgnoreSpaces() != LexicalUnits.STRING) {
+ reportError("charset.string");
+ } else {
+ if (nextIgnoreSpaces() != LexicalUnits.SEMI_COLON) {
+ reportError("semicolon");
+ }
+ next();
+ }
+ break;
+ case LexicalUnits.COMMENT:
+ documentHandler.comment(scanner.getStringValue());
+ }
+
+ skipSpacesAndCDOCDC();
+ for (;;) {
+ if (current == LexicalUnits.IMPORT_SYMBOL) {
+ nextIgnoreSpaces();
+ parseImportRule();
+ nextIgnoreSpaces();
+ } else {
+ break;
+ }
+ }
+
+ loop: for (;;) {
+ switch (current) {
+ case LexicalUnits.PAGE_SYMBOL:
+ nextIgnoreSpaces();
+ parsePageRule();
+ break;
+ case LexicalUnits.MEDIA_SYMBOL:
+ nextIgnoreSpaces();
+ parseMediaRule();
+ break;
+ case LexicalUnits.FONT_FACE_SYMBOL:
+ nextIgnoreSpaces();
+ parseFontFaceRule();
+ break;
+ case LexicalUnits.AT_KEYWORD:
+ nextIgnoreSpaces();
+ parseAtRule();
+ break;
+ case LexicalUnits.EOF:
+ break loop;
+ default:
+ parseRuleSet();
+ }
+ skipSpacesAndCDOCDC();
+ }
+ } finally {
+ documentHandler.endDocument(source);
+ scanner = null;
+ }
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link
+ * _org.w3c.css.sac.Parser#parseStyleSheet(String)}.
+ */
+ public void parseStyleSheet(String uri) throws CSSException, IOException {
+ parseStyleSheet(new InputSource(uri));
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link
+ * _org.w3c.css.sac.Parser#parseStyleDeclaration(InputSource)}.
+ */
+ public void parseStyleDeclaration(InputSource source)
+ throws CSSException, IOException {
+
+ scanner = createScanner(source);
+ parseStyleDeclarationInternal();
+ }
+
+ /**
+ * Parses a style declaration using the current scanner.
+ */
+ protected void parseStyleDeclarationInternal()
+ throws CSSException, IOException {
+ nextIgnoreSpaces();
+ try {
+ parseStyleDeclaration(false);
+ } catch (CSSParseException e) {
+ reportError(e);
+ } finally {
+ scanner = null;
+ }
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link
+ * _org.w3c.css.sac.Parser#parseRule(InputSource)}.
+ */
+ public void parseRule(InputSource source)
+ throws CSSException, IOException {
+ scanner = createScanner(source);
+ parseRuleInternal();
+ }
+
+ /**
+ * Parses a rule using the current scanner.
+ */
+ protected void parseRuleInternal() throws CSSException, IOException {
+ nextIgnoreSpaces();
+ parseRule();
+ scanner = null;
+ }
+
+ /**
+ * <b>SAC</b>: Implements {@link
+ * _org.w3c.css.sac.Parser#parseSelectors(InputSource)}.
+ */
+ public SelectorList parseSelectors(InputSource source)
+ throws CSSException, IOException {
+ scanner = createScanner(source);
+ return parseSelectorsInternal();
+ }
+
+ /**
+ * Parses selectors using the current scanner.
+ */
+ protected SelectorList parseSelectorsInternal()
+ throws CSSException, IOException {
+ nextIgnoreSpaces();
+ SelectorList ret = parseSelectorList();
+ scanner = null;
+ return ret;
+ }
+
+ /**
+ * <b>SAC</b>: Implements
+ * {@link _org.w3c.css.sac.Parser#parsePropertyValue(InputSource)}.
+ */
+ public LexicalUnit parsePropertyValue(InputSource source)
+ throws CSSException, IOException {
+ scanner = createScanner(source);
+ return parsePropertyValueInternal();
+ }
+
+ /**
+ * Parses property value using the current scanner.
+ */
+ protected LexicalUnit parsePropertyValueInternal()
+ throws CSSException, IOException {
+ nextIgnoreSpaces();
+
+ LexicalUnit exp = null;
+
+ try {
+ exp = parseExpression(false);
+ } catch (CSSParseException e) {
+ reportError(e);
+ throw e;
+ }
+
+ CSSParseException exception = null;
+ if (current != LexicalUnits.EOF)
+ exception = createCSSParseException("eof.expected");
+
+ scanner = null;
+
+ if (exception != null) {
+ errorHandler.fatalError(exception);
+ }
+ return exp;
+ }
+
+ /**
+ * <b>SAC</b>: Implements
+ * {@link _org.w3c.css.sac.Parser#parsePriority(InputSource)}.
+ */
+ public boolean parsePriority(InputSource source)
+ throws CSSException, IOException {
+ scanner = createScanner(source);
+ return parsePriorityInternal();
+ }
+
+ /**
+ * Parses the priority using the current scanner.
+ */
+ protected boolean parsePriorityInternal()
+ throws CSSException, IOException {
+ nextIgnoreSpaces();
+
+ scanner = null;
+
+ switch (current) {
+ case LexicalUnits.EOF:
+ return false;
+ case LexicalUnits.IMPORT_SYMBOL:
+ return true;
+ default:
+ reportError("token", new Object[] { new Integer(current) });
+ return false;
+ }
+ }
+
+ /**
+ * Parses a rule.
+ */
+ protected void parseRule() {
+ switch (scanner.getType()) {
+ case LexicalUnits.IMPORT_SYMBOL:
+ nextIgnoreSpaces();
+ parseImportRule();
+ break;
+ case LexicalUnits.AT_KEYWORD:
+ nextIgnoreSpaces();
+ parseAtRule();
+ break;
+ case LexicalUnits.FONT_FACE_SYMBOL:
+ nextIgnoreSpaces();
+ parseFontFaceRule();
+ break;
+ case LexicalUnits.MEDIA_SYMBOL:
+ nextIgnoreSpaces();
+ parseMediaRule();
+ break;
+ case LexicalUnits.PAGE_SYMBOL:
+ nextIgnoreSpaces();
+ parsePageRule();
+ break;
+ default:
+ parseRuleSet();
+ }
+ }
+
+ /**
+ * Parses an unknown rule.
+ */
+ protected void parseAtRule() {
+ scanner.scanAtRule();
+ documentHandler.ignorableAtRule(scanner.getStringValue());
+ nextIgnoreSpaces();
+ }
+
+ /**
+ * Parses an import rule. Assumes the current token is '@import'.
+ */
+ protected void parseImportRule() {
+ String uri = null;
+ switch (current) {
+ default:
+ reportError("string.or.uri");
+ return;
+ case LexicalUnits.STRING:
+ case LexicalUnits.URI:
+ uri = scanner.getStringValue();
+ nextIgnoreSpaces();
+ }
+
+ CSSSACMediaList ml;
+ if (current != LexicalUnits.IDENTIFIER) {
+ ml = new CSSSACMediaList();
+ ml.append("all");
+ } else {
+ ml = parseMediaList();
+ }
+
+ documentHandler.importStyle(uri, ml, null);
+
+ if (current != LexicalUnits.SEMI_COLON) {
+ reportError("semicolon");
+ } else {
+ next();
+ }
+ }
+
+ /**
+ * Parses a media list.
+ */
+ protected CSSSACMediaList parseMediaList() {
+ CSSSACMediaList result = new CSSSACMediaList();
+ result.append(scanner.getStringValue());
+ nextIgnoreSpaces();
+
+ while (current == LexicalUnits.COMMA) {
+ nextIgnoreSpaces();
+
+ switch (current) {
+ default:
+ reportError("identifier");
+ break;
+ case LexicalUnits.IDENTIFIER:
+ result.append(scanner.getStringValue());
+ nextIgnoreSpaces();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Parses a font-face rule.
+ */
+ protected void parseFontFaceRule() {
+ try {
+ documentHandler.startFontFace();
+
+ if (current != LexicalUnits.LEFT_CURLY_BRACE) {
+ reportError("left.curly.brace");
+ } else {
+ nextIgnoreSpaces();
+
+ try {
+ parseStyleDeclaration(true);
+ } catch (CSSParseException e) {
+ reportError(e);
+ }
+ }
+ } finally {
+ documentHandler.endFontFace();
+ }
+ }
+
+ /**
+ * Parses a page rule.
+ */
+ protected void parsePageRule() {
+ String page = null;
+ String ppage = null;
+
+ if (current == LexicalUnits.IDENTIFIER) {
+ page = scanner.getStringValue();
+ nextIgnoreSpaces();
+
+ if (current == LexicalUnits.COLON) {
+ nextIgnoreSpaces();
+
+ if (current != LexicalUnits.IDENTIFIER) {
+ reportError("identifier");
+ return;
+ }
+ ppage = scanner.getStringValue();
+ nextIgnoreSpaces();
+ }
+ }
+
+ try {
+ documentHandler.startPage(page, ppage);
+
+ if (current != LexicalUnits.LEFT_CURLY_BRACE) {
+ reportError("left.curly.brace");
+ } else {
+ nextIgnoreSpaces();
+
+ try {
+ parseStyleDeclaration(true);
+ } catch (CSSParseException e) {
+ reportError(e);
+ }
+ }
+ } finally {
+ documentHandler.endPage(page, ppage);
+ }
+ }
+
+ /**
+ * Parses a media rule.
+ */
+ protected void parseMediaRule() {
+ if (current != LexicalUnits.IDENTIFIER) {
+ reportError("identifier");
+ return;
+ }
+
+ CSSSACMediaList ml = parseMediaList();
+ try {
+ documentHandler.startMedia(ml);
+
+ if (current != LexicalUnits.LEFT_CURLY_BRACE) {
+ reportError("left.curly.brace");
+ } else {
+ nextIgnoreSpaces();
+
+ loop: for (;;) {
+ switch (current) {
+ case LexicalUnits.EOF:
+ case LexicalUnits.RIGHT_CURLY_BRACE:
+ break loop;
+ default:
+ parseRuleSet();
+ }
+ }
+
+ nextIgnoreSpaces();
+ }
+ } finally {
+ documentHandler.endMedia(ml);
+ }
+ }
+
+ /**
+ * Parses a ruleset.
+ */
+ protected void parseRuleSet() {
+ SelectorList sl = null;
+
+ try {
+ sl = parseSelectorList();
+ } catch (CSSParseException e) {
+ reportError(e);
+ return;
+ }
+
+ /* BEGIN Modification for Theme Editor: handle comment reporting bug */
+ boolean callNextIgnoreSpaceAtFinally = false;
+ /* END Modification for Theme Editor */
+ try {
+ documentHandler.startSelector(sl);
+
+ if (current != LexicalUnits.LEFT_CURLY_BRACE) {
+ reportError("left.curly.brace");
+ if (current == LexicalUnits.RIGHT_CURLY_BRACE) {
+ nextIgnoreSpaces();
+ }
+ } else {
+ nextIgnoreSpaces();
+
+ try {
+ parseStyleDeclaration(true);
+ /* BEGIN Modification for Theme Editor: handle comment reporting bug */
+ if ( current == LexicalUnits.RIGHT_CURLY_BRACE ) {
+ callNextIgnoreSpaceAtFinally = true;
+ }
+ /* END Modification for Theme Editor */
+ } catch (CSSParseException e) {
+ reportError(e);
+ }
+ }
+ } finally {
+ documentHandler.endSelector(sl);
+ /* BEGIN Modification for Theme Editor: handle comment reporting bug */
+ if ( callNextIgnoreSpaceAtFinally ) {
+ nextIgnoreSpaces();
+ }
+ /* END Modification for Theme Editor */
+ }
+ }
+
+ /**
+ * Parses a selector list
+ */
+ protected SelectorList parseSelectorList() {
+ CSSSelectorList result = new CSSSelectorList();
+ result.append(parseSelector());
+
+ for (;;) {
+ if (current != LexicalUnits.COMMA) {
+ return result;
+ }
+ nextIgnoreSpaces();
+ result.append(parseSelector());
+ }
+ }
+
+ /**
+ * Parses a selector.
+ */
+ protected Selector parseSelector() {
+ SimpleSelector ss = parseSimpleSelector();
+ Selector result = ss;
+
+ pseudoElement = null;
+
+ loop: for (;;) {
+ switch (current) {
+ default:
+ break loop;
+ case LexicalUnits.IDENTIFIER:
+ case LexicalUnits.ANY:
+ case LexicalUnits.HASH:
+ case LexicalUnits.DOT:
+ case LexicalUnits.LEFT_BRACKET:
+ case LexicalUnits.COLON:
+ result = selectorFactory.createDescendantSelector
+ (result,
+ parseSimpleSelector());
+ break;
+ case LexicalUnits.PLUS:
+ nextIgnoreSpaces();
+ result = selectorFactory.createDirectAdjacentSelector
+ ((short)1,
+ result,
+ parseSimpleSelector());
+ break;
+ case LexicalUnits.PRECEDE:
+ nextIgnoreSpaces();
+ result = selectorFactory.createChildSelector
+ (result,
+ parseSimpleSelector());
+ }
+ }
+ if (pseudoElement != null) {
+ result = selectorFactory.createChildSelector
+ (result,
+ selectorFactory.createPseudoElementSelector
+ (null, pseudoElement));
+ }
+ return result;
+ }
+
+ /**
+ * Parses a simple selector.
+ */
+ protected SimpleSelector parseSimpleSelector() {
+ SimpleSelector result;
+
+ switch (current) {
+ case LexicalUnits.IDENTIFIER:
+ result = selectorFactory.createElementSelector
+ (null, scanner.getStringValue());
+ next();
+ break;
+ case LexicalUnits.ANY:
+ next();
+ default:
+ result = selectorFactory.createElementSelector(null, null);
+ }
+ Condition cond = null;
+ loop: for (;;) {
+ Condition c = null;
+ switch (current) {
+ case LexicalUnits.HASH:
+ c = conditionFactory.createIdCondition
+ (scanner.getStringValue());
+ next();
+ break;
+ case LexicalUnits.DOT:
+ if (next() != LexicalUnits.IDENTIFIER) {
+ throw createCSSParseException("identifier");
+ }
+ c = conditionFactory.createClassCondition
+ (null, scanner.getStringValue());
+ next();
+ break;
+ case LexicalUnits.LEFT_BRACKET:
+ if (nextIgnoreSpaces() != LexicalUnits.IDENTIFIER) {
+ throw createCSSParseException("identifier");
+ }
+ String name = scanner.getStringValue();
+ int op = nextIgnoreSpaces();
+ switch (op) {
+ default:
+ throw createCSSParseException("right.bracket");
+ case LexicalUnits.RIGHT_BRACKET:
+ nextIgnoreSpaces();
+ c = conditionFactory.createAttributeCondition
+ (name, null, false, null);
+ break;
+ case LexicalUnits.EQUAL:
+ case LexicalUnits.INCLUDES:
+ case LexicalUnits.DASHMATCH:
+ String val = null;
+ switch (nextIgnoreSpaces()) {
+ default:
+ throw createCSSParseException("identifier.or.string");
+ case LexicalUnits.STRING:
+ case LexicalUnits.IDENTIFIER:
+ val = scanner.getStringValue();
+ nextIgnoreSpaces();
+ }
+ if (current != LexicalUnits.RIGHT_BRACKET) {
+ throw createCSSParseException("right.bracket");
+ }
+ next();
+ switch (op) {
+ case LexicalUnits.EQUAL:
+ c = conditionFactory.createAttributeCondition
+ (name, null, false, val);
+ break;
+ case LexicalUnits.INCLUDES:
+ c = conditionFactory.createOneOfAttributeCondition
+ (name, null, false, val);
+ break;
+ default:
+ c = conditionFactory.
+ createBeginHyphenAttributeCondition
+ (name, null, false, val);
+ }
+ }
+ break;
+ case LexicalUnits.COLON:
+ switch (nextIgnoreSpaces()) {
+ case LexicalUnits.IDENTIFIER:
+ String val = scanner.getStringValue();
+ if (isPseudoElement(val)) {
+ if (pseudoElement != null) {
+ throw createCSSParseException
+ ("duplicate.pseudo.element");
+ }
+ pseudoElement = val;
+ } else {
+ c = conditionFactory.createPseudoClassCondition
+ (null, val);
+ }
+ next();
+ break;
+ case LexicalUnits.FUNCTION:
+ String func = scanner.getStringValue();
+ if (nextIgnoreSpaces() != LexicalUnits.IDENTIFIER) {
+ throw createCSSParseException("identifier");
+ }
+ String lang = scanner.getStringValue();
+ if (nextIgnoreSpaces() != LexicalUnits.RIGHT_BRACE) {
+ throw createCSSParseException("right.brace");
+ }
+
+ if (!func.equalsIgnoreCase("lang")) {
+ throw createCSSParseException("pseudo.function");
+ }
+
+ c = conditionFactory.createLangCondition(lang);
+
+ next();
+ break;
+ default:
+ throw createCSSParseException("identifier");
+ }
+ break;
+ default:
+ break loop;
+ }
+ if (c != null) {
+ if (cond == null) {
+ cond = c;
+ } else {
+ cond = conditionFactory.createAndCondition(cond, c);
+ }
+ }
+ }
+ skipSpaces();
+ if (cond != null) {
+ result = selectorFactory.createConditionalSelector(result, cond);
+ }
+ return result;
+ }
+
+ /**
+ * Tells whether or not the given string represents a pseudo-element.
+ */
+ protected boolean isPseudoElement(String s) {
+ switch (s.charAt(0)) {
+ case 'a':
+ case 'A':
+ return s.equalsIgnoreCase("after");
+ case 'b':
+ case 'B':
+ return s.equalsIgnoreCase("before");
+ case 'f':
+ case 'F':
+ return s.equalsIgnoreCase("first-letter") ||
+ s.equalsIgnoreCase("first-line");
+ }
+ return false;
+ }
+
+ /**
+ * Parses the given reader.
+ */
+ protected void parseStyleDeclaration(boolean inSheet)
+ throws CSSException {
+ for (;;) {
+ switch (current) {
+ case LexicalUnits.EOF:
+ if (inSheet) {
+ throw createCSSParseException("eof");
+ }
+ return;
+ case LexicalUnits.RIGHT_CURLY_BRACE:
+ if (!inSheet) {
+ throw createCSSParseException("eof.expected");
+ }
+ /* BEGIN Modification for Theme Editor: handle comment reporting bug */
+ // nextIgnoreSpaces();
+ /* END Modification for Theme Editor */
+ return;
+ case LexicalUnits.SEMI_COLON:
+ nextIgnoreSpaces();
+ continue;
+ default:
+ throw createCSSParseException("identifier");
+ case LexicalUnits.IDENTIFIER:
+ }
+
+ String name = scanner.getStringValue();
+
+ if (nextIgnoreSpaces() != LexicalUnits.COLON) {
+ throw createCSSParseException("colon");
+ }
+ /* BEGIN Modification for Theme Editor */
+ scanner.clearCustomBuffer();
+ String propertyString = null;
+ int propertyLine = scanner.getLine();
+ /* END Modification for Theme Editor */
+ nextIgnoreSpaces();
+
+ LexicalUnit exp = null;
+
+ try {
+ exp = parseExpression(false);
+ /* BEGIN Modification for Theme Editor */
+ propertyString = scanner.getCustomBufferData();
+ /* END Modification for Theme Editor */
+ } catch (CSSParseException e) {
+ reportError(e);
+ }
+
+ if (exp != null) {
+ boolean important = false;
+ if (current == LexicalUnits.IMPORTANT_SYMBOL) {
+ important = true;
+ nextIgnoreSpaces();
+ }
+ documentHandler.property(name, exp, important);
+ /* BEGIN Modification for Theme Editor */
+ ParserUtil.handlePropertyString( documentHandler,
+ name,
+ propertyString,
+ propertyLine );
+ /* END Modification for Theme Editor */
+ }
+ }
+ }
+
+ /**
+ * Parses a CSS2 expression.
+ * @param param whether the expression to be parsed is a function parameter
+ */
+ protected LexicalUnit parseExpression(boolean param) {
+ LexicalUnit result = parseTerm(null);
+ LexicalUnit curr = result;
+
+ for (;;) {
+ boolean op = false;
+ switch (current) {
+ case LexicalUnits.COMMA:
+ op = true;
+ curr = CSSLexicalUnit.createSimple
+ (LexicalUnit.SAC_OPERATOR_COMMA, curr);
+ nextIgnoreSpaces();
+ break;
+ case LexicalUnits.DIVIDE:
+ op = true;
+ curr = CSSLexicalUnit.createSimple
+ (LexicalUnit.SAC_OPERATOR_SLASH, curr);
+ nextIgnoreSpaces();
+ }
+ if (param) {
+ if (current == LexicalUnits.RIGHT_BRACE) {
+ if (op) {
+ throw createCSSParseException
+ ("token", new Object[] { new Integer(current) });
+ }
+ return result;
+ }
+ curr = parseTerm(curr);
+ } else {
+ switch (current) {
+ case LexicalUnits.IMPORTANT_SYMBOL:
+ case LexicalUnits.SEMI_COLON:
+ case LexicalUnits.RIGHT_CURLY_BRACE:
+ case LexicalUnits.EOF:
+ if (op) {
+ throw createCSSParseException
+ ("token", new Object[] { new Integer(current) });
+ }
+ return result;
+ default:
+ curr = parseTerm(curr);
+ }
+ }
+ }
+ }
+
+ /**
+ * Parses a CSS2 term.
+ */
+ protected LexicalUnit parseTerm(LexicalUnit prev) {
+ boolean plus = true;
+ boolean sgn = false;
+
+ switch (current) {
+ case LexicalUnits.MINUS:
+ plus = false;
+ case LexicalUnits.PLUS:
+ next();
+ sgn = true;
+ default:
+ switch (current) {
+ case LexicalUnits.INTEGER:
+ String sval = scanner.getStringValue();
+ if (!plus) sval = "-"+sval;
+ int val = Integer.parseInt(sval);
+ nextIgnoreSpaces();
+ return CSSLexicalUnit.createInteger(val, prev);
+ case LexicalUnits.REAL:
+ return CSSLexicalUnit.createFloat(LexicalUnit.SAC_REAL,
+ number(plus), prev);
+ case LexicalUnits.PERCENTAGE:
+ return CSSLexicalUnit.createFloat(LexicalUnit.SAC_PERCENTAGE,
+ number(plus), prev);
+ case LexicalUnits.PT:
+ return CSSLexicalUnit.createFloat(LexicalUnit.SAC_POINT,
+ number(plus), prev);
+ case LexicalUnits.PC:
+ return CSSLexicalUnit.createFloat(LexicalUnit.SAC_PICA,
+ number(plus), prev);
+ case LexicalUnits.PX:
+ return CSSLexicalUnit.createFloat(LexicalUnit.SAC_PIXEL,
+ number(plus), prev);
+ case LexicalUnits.CM:
+ return CSSLexicalUnit.createFloat(LexicalUnit.SAC_CENTIMETER,
+ number(plus), prev);
+ case LexicalUnits.MM:
+ return CSSLexicalUnit.createFloat(LexicalUnit.SAC_MILLIMETER,
+ number(plus), prev);
+ case LexicalUnits.IN:
+ return CSSLexicalUnit.createFloat(LexicalUnit.SAC_INCH,
+ number(plus), prev);
+ case LexicalUnits.EM:
+ return CSSLexicalUnit.createFloat(LexicalUnit.SAC_EM,
+ number(plus), prev);
+ case LexicalUnits.EX:
+ return CSSLexicalUnit.createFloat(LexicalUnit.SAC_EX,
+ number(plus), prev);
+ case LexicalUnits.DEG:
+ return CSSLexicalUnit.createFloat(LexicalUnit.SAC_DEGREE,
+ number(plus), prev);
+ case LexicalUnits.RAD:
+ return CSSLexicalUnit.createFloat(LexicalUnit.SAC_RADIAN,
+ number(plus), prev);
+ case LexicalUnits.GRAD:
+ return CSSLexicalUnit.createFloat(LexicalUnit.SAC_GRADIAN,
+ number(plus), prev);
+ case LexicalUnits.S:
+ return CSSLexicalUnit.createFloat(LexicalUnit.SAC_SECOND,
+ number(plus), prev);
+ case LexicalUnits.MS:
+ return CSSLexicalUnit.createFloat(LexicalUnit.SAC_MILLISECOND,
+ number(plus), prev);
+ case LexicalUnits.HZ:
+ return CSSLexicalUnit.createFloat(LexicalUnit.SAC_HERTZ,
+ number(plus), prev);
+ case LexicalUnits.KHZ:
+ return CSSLexicalUnit.createFloat(LexicalUnit.SAC_KILOHERTZ,
+ number(plus), prev);
+ case LexicalUnits.DIMENSION:
+ return dimension(plus, prev);
+ case LexicalUnits.FUNCTION:
+ return parseFunction(plus, prev);
+ }
+ if (sgn) {
+ throw createCSSParseException
+ ("token",
+ new Object[] { new Integer(current) });
+ }
+ }
+ switch (current) {
+ case LexicalUnits.STRING:
+ String val = scanner.getStringValue();
+ nextIgnoreSpaces();
+ return CSSLexicalUnit.createString(LexicalUnit.SAC_STRING_VALUE,
+ val, prev);
+ case LexicalUnits.IDENTIFIER:
+ val = scanner.getStringValue();
+ nextIgnoreSpaces();
+ if (val.equalsIgnoreCase("inherit")) {
+ return CSSLexicalUnit.createSimple(LexicalUnit.SAC_INHERIT,
+ prev);
+ } else {
+ return CSSLexicalUnit.createString(LexicalUnit.SAC_IDENT,
+ val, prev);
+ }
+ case LexicalUnits.URI:
+ val = scanner.getStringValue();
+ nextIgnoreSpaces();
+ return CSSLexicalUnit.createString(LexicalUnit.SAC_URI,
+ val, prev);
+ case LexicalUnits.HASH:
+ return hexcolor(prev);
+ default:
+ throw createCSSParseException
+ ("token",
+ new Object[] { new Integer(current) });
+ }
+ }
+
+ /**
+ * Parses a CSS2 function.
+ */
+ protected LexicalUnit parseFunction(boolean positive, LexicalUnit prev) {
+ String name = scanner.getStringValue();
+ nextIgnoreSpaces();
+
+ LexicalUnit params = parseExpression(true);
+
+ if (current != LexicalUnits.RIGHT_BRACE) {
+ throw createCSSParseException
+ ("token",
+ new Object[] { new Integer(current) });
+ }
+ nextIgnoreSpaces();
+
+ predefined: switch (name.charAt(0)) {
+ case 'r':
+ case 'R':
+ LexicalUnit lu;
+ if (name.equalsIgnoreCase("rgb")) {
+ lu = params;
+ if (lu == null) {
+ break;
+ }
+ switch (lu.getLexicalUnitType()) {
+ default:
+ break predefined;
+ case LexicalUnit.SAC_INTEGER:
+ case LexicalUnit.SAC_PERCENTAGE:
+ lu = lu.getNextLexicalUnit();
+ }
+ if (lu == null) {
+ break;
+ }
+ switch (lu.getLexicalUnitType()) {
+ default:
+ break predefined;
+ case LexicalUnit.SAC_OPERATOR_COMMA:
+ lu = lu.getNextLexicalUnit();
+ }
+ if (lu == null) {
+ break;
+ }
+ switch (lu.getLexicalUnitType()) {
+ default:
+ break predefined;
+ case LexicalUnit.SAC_INTEGER:
+ case LexicalUnit.SAC_PERCENTAGE:
+ lu = lu.getNextLexicalUnit();
+ }
+ if (lu == null) {
+ break;
+ }
+ switch (lu.getLexicalUnitType()) {
+ default:
+ break predefined;
+ case LexicalUnit.SAC_OPERATOR_COMMA:
+ lu = lu.getNextLexicalUnit();
+ }
+ if (lu == null) {
+ break;
+ }
+ switch (lu.getLexicalUnitType()) {
+ default:
+ break predefined;
+ case LexicalUnit.SAC_INTEGER:
+ case LexicalUnit.SAC_PERCENTAGE:
+ lu = lu.getNextLexicalUnit();
+ }
+ if (lu != null) {
+ break;
+ }
+ return CSSLexicalUnit.createPredefinedFunction
+ (LexicalUnit.SAC_RGBCOLOR, params, prev);
+ } else if (name.equalsIgnoreCase("rect")) {
+ lu = params;
+ if (lu == null) {
+ break;
+ }
+ switch (lu.getLexicalUnitType()) {
+ default:
+ break predefined;
+ case LexicalUnit.SAC_INTEGER:
+ if (lu.getIntegerValue() != 0) {
+ break predefined;
+ }
+ lu = lu.getNextLexicalUnit();
+ break;
+ case LexicalUnit.SAC_IDENT:
+ if (!lu.getStringValue().equalsIgnoreCase("auto")) {
+ break predefined;
+ }
+ lu = lu.getNextLexicalUnit();
+ break;
+ case LexicalUnit.SAC_EM:
+ case LexicalUnit.SAC_EX:
+ case LexicalUnit.SAC_PIXEL:
+ case LexicalUnit.SAC_CENTIMETER:
+ case LexicalUnit.SAC_MILLIMETER:
+ case LexicalUnit.SAC_INCH:
+ case LexicalUnit.SAC_POINT:
+ case LexicalUnit.SAC_PICA:
+ case LexicalUnit.SAC_PERCENTAGE:
+ lu = lu.getNextLexicalUnit();
+ }
+ if (lu == null) {
+ break;
+ }
+ switch (lu.getLexicalUnitType()) {
+ default:
+ break predefined;
+ case LexicalUnit.SAC_OPERATOR_COMMA:
+ lu = lu.getNextLexicalUnit();
+ }
+ if (lu == null) {
+ break;
+ }
+ switch (lu.getLexicalUnitType()) {
+ default:
+ break predefined;
+ case LexicalUnit.SAC_INTEGER:
+ if (lu.getIntegerValue() != 0) {
+ break predefined;
+ }
+ lu = lu.getNextLexicalUnit();
+ break;
+ case LexicalUnit.SAC_IDENT:
+ if (!lu.getStringValue().equalsIgnoreCase("auto")) {
+ break predefined;
+ }
+ lu = lu.getNextLexicalUnit();
+ break;
+ case LexicalUnit.SAC_EM:
+ case LexicalUnit.SAC_EX:
+ case LexicalUnit.SAC_PIXEL:
+ case LexicalUnit.SAC_CENTIMETER:
+ case LexicalUnit.SAC_MILLIMETER:
+ case LexicalUnit.SAC_INCH:
+ case LexicalUnit.SAC_POINT:
+ case LexicalUnit.SAC_PICA:
+ case LexicalUnit.SAC_PERCENTAGE:
+ lu = lu.getNextLexicalUnit();
+ }
+ if (lu == null) {
+ break;
+ }
+ switch (lu.getLexicalUnitType()) {
+ default:
+ break predefined;
+ case LexicalUnit.SAC_OPERATOR_COMMA:
+ lu = lu.getNextLexicalUnit();
+ }
+ if (lu == null) {
+ break;
+ }
+ switch (lu.getLexicalUnitType()) {
+ default:
+ break predefined;
+ case LexicalUnit.SAC_INTEGER:
+ if (lu.getIntegerValue() != 0) {
+ break predefined;
+ }
+ lu = lu.getNextLexicalUnit();
+ break;
+ case LexicalUnit.SAC_IDENT:
+ if (!lu.getStringValue().equalsIgnoreCase("auto")) {
+ break predefined;
+ }
+ lu = lu.getNextLexicalUnit();
+ break;
+ case LexicalUnit.SAC_EM:
+ case LexicalUnit.SAC_EX:
+ case LexicalUnit.SAC_PIXEL:
+ case LexicalUnit.SAC_CENTIMETER:
+ case LexicalUnit.SAC_MILLIMETER:
+ case LexicalUnit.SAC_INCH:
+ case LexicalUnit.SAC_POINT:
+ case LexicalUnit.SAC_PICA:
+ case LexicalUnit.SAC_PERCENTAGE:
+ lu = lu.getNextLexicalUnit();
+ }
+ if (lu == null) {
+ break;
+ }
+ switch (lu.getLexicalUnitType()) {
+ default:
+ break predefined;
+ case LexicalUnit.SAC_OPERATOR_COMMA:
+ lu = lu.getNextLexicalUnit();
+ }
+ if (lu == null) {
+ break;
+ }
+ switch (lu.getLexicalUnitType()) {
+ default:
+ break predefined;
+ case LexicalUnit.SAC_INTEGER:
+ if (lu.getIntegerValue() != 0) {
+ break predefined;
+ }
+ lu = lu.getNextLexicalUnit();
+ break;
+ case LexicalUnit.SAC_IDENT:
+ if (!lu.getStringValue().equalsIgnoreCase("auto")) {
+ break predefined;
+ }
+ lu = lu.getNextLexicalUnit();
+ break;
+ case LexicalUnit.SAC_EM:
+ case LexicalUnit.SAC_EX:
+ case LexicalUnit.SAC_PIXEL:
+ case LexicalUnit.SAC_CENTIMETER:
+ case LexicalUnit.SAC_MILLIMETER:
+ case LexicalUnit.SAC_INCH:
+ case LexicalUnit.SAC_POINT:
+ case LexicalUnit.SAC_PICA:
+ case LexicalUnit.SAC_PERCENTAGE:
+ lu = lu.getNextLexicalUnit();
+ }
+ if (lu != null) {
+ break;
+ }
+ return CSSLexicalUnit.createPredefinedFunction
+ (LexicalUnit.SAC_RECT_FUNCTION, params, prev);
+ }
+ break;
+ case 'c':
+ case 'C':
+ if (name.equalsIgnoreCase("counter")) {
+ lu = params;
+ if (lu == null) {
+ break;
+ }
+ switch (lu.getLexicalUnitType()) {
+ default:
+ break predefined;
+ case LexicalUnit.SAC_IDENT:
+ lu = lu.getNextLexicalUnit();
+ }
+ if (lu == null) {
+ break;
+ }
+ switch (lu.getLexicalUnitType()) {
+ default:
+ break predefined;
+ case LexicalUnit.SAC_OPERATOR_COMMA:
+ lu = lu.getNextLexicalUnit();
+ }
+ if (lu == null) {
+ break;
+ }
+ switch (lu.getLexicalUnitType()) {
+ default:
+ break predefined;
+ case LexicalUnit.SAC_IDENT:
+ lu = lu.getNextLexicalUnit();
+ }
+ if (lu != null) {
+ break;
+ }
+ return CSSLexicalUnit.createPredefinedFunction
+ (LexicalUnit.SAC_COUNTER_FUNCTION, params, prev);
+ } else if (name.equalsIgnoreCase("counters")) {
+ lu = params;
+ if (lu == null) {
+ break;
+ }
+ switch (lu.getLexicalUnitType()) {
+ default:
+ break predefined;
+ case LexicalUnit.SAC_IDENT:
+ lu = lu.getNextLexicalUnit();
+ }
+ if (lu == null) {
+ break;
+ }
+ switch (lu.getLexicalUnitType()) {
+ default:
+ break predefined;
+ case LexicalUnit.SAC_OPERATOR_COMMA:
+ lu = lu.getNextLexicalUnit();
+ }
+ if (lu == null) {
+ break;
+ }
+ switch (lu.getLexicalUnitType()) {
+ default:
+ break predefined;
+ case LexicalUnit.SAC_STRING_VALUE:
+ lu = lu.getNextLexicalUnit();
+ }
+ if (lu == null) {
+ break;
+ }
+ switch (lu.getLexicalUnitType()) {
+ default:
+ break predefined;
+ case LexicalUnit.SAC_OPERATOR_COMMA:
+ lu = lu.getNextLexicalUnit();
+ }
+ if (lu == null) {
+ break;
+ }
+ switch (lu.getLexicalUnitType()) {
+ default:
+ break predefined;
+ case LexicalUnit.SAC_IDENT:
+ lu = lu.getNextLexicalUnit();
+ }
+ if (lu != null) {
+ break;
+ }
+ return CSSLexicalUnit.createPredefinedFunction
+ (LexicalUnit.SAC_COUNTERS_FUNCTION, params, prev);
+ }
+ break;
+ case 'a':
+ case 'A':
+ if (name.equalsIgnoreCase("attr")) {
+ lu = params;
+ if (lu == null) {
+ break;
+ }
+ switch (lu.getLexicalUnitType()) {
+ default:
+ break predefined;
+ case LexicalUnit.SAC_IDENT:
+ lu = lu.getNextLexicalUnit();
+ }
+ if (lu != null) {
+ break;
+ }
+ return CSSLexicalUnit.createString
+ (LexicalUnit.SAC_ATTR, params.getStringValue(), prev);
+ }
+ }
+
+ return CSSLexicalUnit.createFunction(name, params, prev);
+ }
+
+ /**
+ * Converts a hash unit to a RGB color.
+ */
+ protected LexicalUnit hexcolor(LexicalUnit prev) {
+ String val = scanner.getStringValue();
+ int len = val.length();
+ LexicalUnit params = null;
+ switch (len) {
+ case 3:
+ char rc = Character.toLowerCase(val.charAt(0));
+ char gc = Character.toLowerCase(val.charAt(1));
+ char bc = Character.toLowerCase(val.charAt(2));
+ if (!ScannerUtilities.isCSSHexadecimalCharacter(rc) ||
+ !ScannerUtilities.isCSSHexadecimalCharacter(gc) ||
+ !ScannerUtilities.isCSSHexadecimalCharacter(bc)) {
+ throw createCSSParseException
+ ("rgb.color", new Object[] { val });
+ }
+ int t;
+ int r = t = (rc >= '0' && rc <= '9') ? rc - '0' : rc - 'a' + 10;
+ t <<= 4;
+ r |= t;
+ int g = t = (gc >= '0' && gc <= '9') ? gc - '0' : gc - 'a' + 10;
+ t <<= 4;
+ g |= t;
+ int b = t = (bc >= '0' && bc <= '9') ? bc - '0' : bc - 'a' + 10;
+ t <<= 4;
+ b |= t;
+ params = CSSLexicalUnit.createInteger(r, null);
+ LexicalUnit tmp;
+ tmp = CSSLexicalUnit.createSimple
+ (LexicalUnit.SAC_OPERATOR_COMMA, params);
+ tmp = CSSLexicalUnit.createInteger(g, tmp);
+ tmp = CSSLexicalUnit.createSimple
+ (LexicalUnit.SAC_OPERATOR_COMMA, tmp);
+ tmp = CSSLexicalUnit.createInteger(b, tmp);
+ break;
+ case 6:
+ char rc1 = Character.toLowerCase(val.charAt(0));
+ char rc2 = Character.toLowerCase(val.charAt(1));
+ char gc1 = Character.toLowerCase(val.charAt(2));
+ char gc2 = Character.toLowerCase(val.charAt(3));
+ char bc1 = Character.toLowerCase(val.charAt(4));
+ char bc2 = Character.toLowerCase(val.charAt(5));
+ if (!ScannerUtilities.isCSSHexadecimalCharacter(rc1) ||
+ !ScannerUtilities.isCSSHexadecimalCharacter(rc2) ||
+ !ScannerUtilities.isCSSHexadecimalCharacter(gc1) ||
+ !ScannerUtilities.isCSSHexadecimalCharacter(gc2) ||
+ !ScannerUtilities.isCSSHexadecimalCharacter(bc1) ||
+ !ScannerUtilities.isCSSHexadecimalCharacter(bc2)) {
+ throw createCSSParseException("rgb.color");
+ }
+ r = (rc1 >= '0' && rc1 <= '9') ? rc1 - '0' : rc1 - 'a' + 10;
+ r <<= 4;
+ r |= (rc2 >= '0' && rc2 <= '9') ? rc2 - '0' : rc2 - 'a' + 10;
+ g = (gc1 >= '0' && gc1 <= '9') ? gc1 - '0' : gc1 - 'a' + 10;
+ g <<= 4;
+ g |= (gc2 >= '0' && gc2 <= '9') ? gc2 - '0' : gc2 - 'a' + 10;
+ b = (bc1 >= '0' && bc1 <= '9') ? bc1 - '0' : bc1 - 'a' + 10;
+ b <<= 4;
+ b |= (bc2 >= '0' && bc2 <= '9') ? bc2 - '0' : bc2 - 'a' + 10;
+ params = CSSLexicalUnit.createInteger(r, null);
+ tmp = CSSLexicalUnit.createSimple
+ (LexicalUnit.SAC_OPERATOR_COMMA, params);
+ tmp = CSSLexicalUnit.createInteger(g, tmp);
+ tmp = CSSLexicalUnit.createSimple
+ (LexicalUnit.SAC_OPERATOR_COMMA, tmp);
+ tmp = CSSLexicalUnit.createInteger(b, tmp);
+ break;
+ default:
+ throw createCSSParseException("rgb.color", new Object[] { val });
+ }
+ nextIgnoreSpaces();
+ return CSSLexicalUnit.createPredefinedFunction
+ (LexicalUnit.SAC_RGBCOLOR, params, prev);
+ }
+
+ /**
+ * Creates a scanner, given an InputSource.
+ */
+ protected Scanner createScanner(InputSource source) {
+ documentURI = source.getURI();
+ if (documentURI == null) {
+ documentURI = "";
+ }
+
+ Reader r = source.getCharacterStream();
+ if (r != null) {
+ return new Scanner(r);
+ }
+
+ InputStream is = source.getByteStream();
+ if (is != null) {
+ return new Scanner(is, source.getEncoding());
+ }
+
+ String uri = source.getURI();
+ if (uri == null) {
+ throw new CSSException(formatMessage("empty.source", null));
+ }
+
+// try {
+// ParsedURL purl = new ParsedURL(uri);
+// is = purl.openStreamRaw(CSSConstants.CSS_MIME_TYPE);
+// return new Scanner(is, source.getEncoding());
+// } catch (IOException e) {
+// throw new CSSException(e);
+// }
+ return null;
+ }
+
+ /**
+ * Skips the white spaces.
+ */
+ protected int skipSpaces() {
+ int lex = scanner.getType();
+ while (lex == LexicalUnits.SPACE) {
+ lex = next();
+ }
+ return lex;
+ }
+
+ /**
+ * Skips the white spaces and CDO/CDC units.
+ */
+ protected int skipSpacesAndCDOCDC() {
+ loop: for (;;) {
+ switch (current) {
+ default:
+ break loop;
+ case LexicalUnits.COMMENT:
+ case LexicalUnits.SPACE:
+ case LexicalUnits.CDO:
+ case LexicalUnits.CDC:
+ }
+ scanner.clearBuffer();
+ next();
+ }
+ return current;
+ }
+
+ /**
+ * Converts the current lexical unit to a float.
+ */
+ protected float number(boolean positive) {
+ try {
+ float sgn = (positive) ? 1 : -1;
+ String val = scanner.getStringValue();
+ nextIgnoreSpaces();
+ return sgn * Float.parseFloat(val);
+ } catch (NumberFormatException e) {
+ throw createCSSParseException("number.format");
+ }
+ }
+
+ /**
+ * Converts the current lexical unit to a dimension.
+ */
+ protected LexicalUnit dimension(boolean positive, LexicalUnit prev) {
+ try {
+ float sgn = (positive) ? 1 : -1;
+ String val = scanner.getStringValue();
+ int i;
+ loop: for (i = 0; i < val.length(); i++) {
+ switch (val.charAt(i)) {
+ default:
+ break loop;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case '.':
+ }
+ }
+ nextIgnoreSpaces();
+ return CSSLexicalUnit.createDimension
+ (sgn * Float.parseFloat(val.substring(0, i)),
+ val.substring(i),
+ prev);
+ } catch (NumberFormatException e) {
+ throw createCSSParseException("number.format");
+ }
+ }
+
+ /**
+ * Advances to the next token, ignoring comments.
+ */
+ protected int next() {
+ try {
+ for (;;) {
+ scanner.clearBuffer();
+ current = scanner.next();
+ if (current == LexicalUnits.COMMENT) {
+ documentHandler.comment(scanner.getStringValue());
+ } else {
+ break;
+ }
+ }
+ return current;
+ } catch (ParseException e) {
+ reportError(e.getMessage());
+ return current;
+ }
+ }
+
+ /**
+ * Advances to the next token and skip the spaces, ignoring comments.
+ */
+ protected int nextIgnoreSpaces() {
+ try {
+ loop: for (;;) {
+ scanner.clearBuffer();
+ current = scanner.next();
+ switch (current) {
+ case LexicalUnits.COMMENT:
+ documentHandler.comment(scanner.getStringValue());
+ break;
+ default:
+ break loop;
+ case LexicalUnits.SPACE:
+ }
+ }
+ return current;
+ } catch (ParseException e) {
+ errorHandler.error(createCSSParseException(e.getMessage()));
+ return current;
+ }
+ }
+
+ /**
+ * Reports a parsing error.
+ */
+ protected void reportError(String key) {
+ reportError(key, null);
+ }
+
+ /**
+ * Reports a parsing error.
+ */
+ protected void reportError(String key, Object[] params) {
+ reportError(createCSSParseException(key, params));
+ }
+
+ /**
+ * Reports a parsing error.
+ */
+ protected void reportError(CSSParseException e) {
+ errorHandler.error(e);
+
+ int cbraces = 1;
+ for (;;) {
+ switch (current) {
+ case LexicalUnits.EOF:
+ return;
+ case LexicalUnits.SEMI_COLON:
+ case LexicalUnits.RIGHT_CURLY_BRACE:
+ if (--cbraces == 0) {
+ nextIgnoreSpaces();
+ return;
+ }
+ case LexicalUnits.LEFT_CURLY_BRACE:
+ cbraces++;
+ }
+ nextIgnoreSpaces();
+ }
+ }
+
+ /**
+ * Creates a parse exception.
+ */
+ protected CSSParseException createCSSParseException(String key) {
+ return createCSSParseException(key, null);
+ }
+
+ /**
+ * Creates a parse exception.
+ */
+ protected CSSParseException createCSSParseException(String key,
+ Object[] params) {
+ return new CSSParseException(formatMessage(key, params),
+ documentURI,
+ scanner.getLine(),
+ scanner.getColumn());
+ }
+
+ // -----------------------------------------------------------------------
+ // Extended methods
+ // -----------------------------------------------------------------------
+
+ /**
+ * Implements {@link ExtendedParser#parseStyleDeclaration(String)}.
+ */
+ public void parseStyleDeclaration(String source)
+ throws CSSException, IOException {
+ scanner = new Scanner(source);
+ parseStyleDeclarationInternal();
+ }
+
+ /**
+ * Implements {@link ExtendedParser#parseRule(String)}.
+ */
+ public void parseRule(String source) throws CSSException, IOException {
+ scanner = new Scanner(source);
+ parseRuleInternal();
+ }
+
+ /**
+ * Implements {@link ExtendedParser#parseSelectors(String)}.
+ */
+ public SelectorList parseSelectors(String source)
+ throws CSSException, IOException {
+ scanner = new Scanner(source);
+ return parseSelectorsInternal();
+ }
+
+ /**
+ * Implements {@link ExtendedParser#parsePropertyValue(String)}.
+ */
+ public LexicalUnit parsePropertyValue(String source)
+ throws CSSException, IOException {
+ scanner = new Scanner(source);
+ return parsePropertyValueInternal();
+ }
+
+ /**
+ * Implements {@link ExtendedParser#parsePriority(String)}.
+ */
+ public boolean parsePriority(String source)
+ throws CSSException, IOException {
+ scanner = new Scanner(source);
+ return parsePriorityInternal();
+ }
+
+ /**
+ * Implements {@link ExtendedParser#parseMedia(String)}.
+ */
+ public SACMediaList parseMedia(String mediaText)
+ throws CSSException, IOException {
+ CSSSACMediaList result = new CSSSACMediaList();
+ if (!"all".equalsIgnoreCase(mediaText)) {
+ StringTokenizer st = new StringTokenizer(mediaText, " ,");
+ while (st.hasMoreTokens()) {
+ result.append(st.nextToken());
+ }
+ }
+ return result;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/Scanner.java b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/Scanner.java
new file mode 100644
index 0000000..f2332f0
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/Scanner.java
@@ -0,0 +1,1319 @@
+/*
+
+ Copyright 2000-2004 The Apache Software Foundation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.apache.batik.css.parser;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+import org.apache.batik.util.io.NormalizingReader;
+import org.apache.batik.util.io.StreamNormalizingReader;
+import org.apache.batik.util.io.StringNormalizingReader;
+
+/**
+ * This class represents a CSS scanner - an object which decodes CSS lexical
+ * units.
+ *
+ * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
+ * @version $Id: Scanner.java,v 1.1 2009/12/06 10:40:09 rsternber Exp $
+ */
+public class Scanner {
+
+ /**
+ * The reader.
+ */
+ protected NormalizingReader reader;
+
+ /**
+ * The current char.
+ */
+ protected int current;
+
+ /**
+ * The recording buffer.
+ */
+ protected char[] buffer = new char[128];
+
+ /**
+ * The current position in the buffer.
+ */
+ protected int position;
+
+ /**
+ * The type of the current lexical unit.
+ */
+ protected int type;
+
+ /**
+ * The start offset of the last lexical unit.
+ */
+ protected int start;
+
+ /**
+ * The end offset of the last lexical unit.
+ */
+ protected int end;
+
+ /**
+ * The characters to skip to create the string which represents the
+ * current token.
+ */
+ protected int blankCharacters;
+
+ /**
+ * Creates a new Scanner object.
+ * @param r The reader to scan.
+ */
+ public Scanner(Reader r) throws ParseException {
+ try {
+ reader = new StreamNormalizingReader(r);
+ current = nextChar();
+ } catch (IOException e) {
+ throw new ParseException(e);
+ }
+ }
+
+ /**
+ * Creates a new Scanner object.
+ * @param is The input stream to scan.
+ * @param enc The encoding to use to decode the input stream, or null.
+ */
+ public Scanner(InputStream is, String enc) throws ParseException {
+ try {
+ reader = new StreamNormalizingReader(is, enc);
+ current = nextChar();
+ } catch (IOException e) {
+ throw new ParseException(e);
+ }
+ }
+
+ /**
+ * Creates a new Scanner object.
+ * @param s The string to scan.
+ */
+ public Scanner(String s) throws ParseException {
+ try {
+ reader = new StringNormalizingReader(s);
+ current = nextChar();
+ } catch (IOException e) {
+ throw new ParseException(e);
+ }
+ }
+
+ /**
+ * Returns the current line.
+ */
+ public int getLine() {
+ return reader.getLine();
+ }
+
+ /**
+ * Returns the current column.
+ */
+ public int getColumn() {
+ return reader.getColumn();
+ }
+
+ /**
+ * Returns the buffer used to store the chars.
+ */
+ public char[] getBuffer() {
+ return buffer;
+ }
+
+ /**
+ * Returns the start offset of the last lexical unit.
+ */
+ public int getStart() {
+ return start;
+ }
+
+ /**
+ * Returns the end offset of the last lexical unit.
+ */
+ public int getEnd() {
+ return end;
+ }
+
+ /**
+ * Clears the buffer.
+ */
+ public void clearBuffer() {
+ if (position <= 0) {
+ position = 0;
+ } else {
+ buffer[0] = buffer[position-1];
+ position = 1;
+ }
+ }
+
+ /**
+ * The current lexical unit type like defined in LexicalUnits.
+ */
+ public int getType() {
+ return type;
+ }
+
+ /**
+ * Returns the string representation of the current lexical unit.
+ */
+ public String getStringValue() {
+ return new String(buffer, start, end - start);
+ }
+
+ /**
+ * Scans a @rule value. This method assumes that the current
+ * lexical unit is a at keyword.
+ */
+ public void scanAtRule() throws ParseException {
+ try {
+ // waiting for EOF, ';' or '{'
+ loop: for (;;) {
+ switch (current) {
+ case '{':
+ int brackets = 1;
+ for (;;) {
+ nextChar();
+ switch (current) {
+ case '}':
+ if (--brackets > 0) {
+ break;
+ }
+ case -1:
+ break loop;
+ case '{':
+ brackets++;
+ }
+ }
+ case -1:
+ case ';':
+ break loop;
+ }
+ nextChar();
+ }
+ end = position;
+ } catch (IOException e) {
+ throw new ParseException(e);
+ }
+ }
+
+ /**
+ * Returns the next token.
+ */
+ public int next() throws ParseException {
+ blankCharacters = 0;
+ start = position - 1;
+ nextToken();
+ end = position - endGap();
+ return type;
+ }
+
+ /**
+ * Returns the end gap of the current lexical unit.
+ */
+ protected int endGap() {
+ int result = (current == -1) ? 0 : 1;
+ switch (type) {
+ case LexicalUnits.FUNCTION:
+ case LexicalUnits.STRING:
+ case LexicalUnits.S:
+ case LexicalUnits.PERCENTAGE:
+ result += 1;
+ break;
+ case LexicalUnits.COMMENT:
+ case LexicalUnits.HZ:
+ case LexicalUnits.EM:
+ case LexicalUnits.EX:
+ case LexicalUnits.PC:
+ case LexicalUnits.PT:
+ case LexicalUnits.PX:
+ case LexicalUnits.CM:
+ case LexicalUnits.MM:
+ case LexicalUnits.IN:
+ case LexicalUnits.MS:
+ result += 2;
+ break;
+ case LexicalUnits.KHZ:
+ case LexicalUnits.DEG:
+ case LexicalUnits.RAD:
+ result += 3;
+ break;
+ case LexicalUnits.GRAD:
+ result += 4;
+ }
+ return result + blankCharacters;
+ }
+
+ /**
+ * Returns the next token.
+ */
+ protected void nextToken() throws ParseException {
+ try {
+ switch (current) {
+ case -1:
+ type = LexicalUnits.EOF;
+ return;
+ case '{':
+ nextChar();
+ type = LexicalUnits.LEFT_CURLY_BRACE;
+ return;
+ case '}':
+ nextChar();
+ type = LexicalUnits.RIGHT_CURLY_BRACE;
+ return;
+ case '=':
+ nextChar();
+ type = LexicalUnits.EQUAL;
+ return;
+ case '+':
+ nextChar();
+ type = LexicalUnits.PLUS;
+ return;
+ case ',':
+ nextChar();
+ type = LexicalUnits.COMMA;
+ return;
+ case ';':
+ nextChar();
+ type = LexicalUnits.SEMI_COLON;
+ return;
+ case '>':
+ nextChar();
+ type = LexicalUnits.PRECEDE;
+ return;
+ case '[':
+ nextChar();
+ type = LexicalUnits.LEFT_BRACKET;
+ return;
+ case ']':
+ nextChar();
+ type = LexicalUnits.RIGHT_BRACKET;
+ return;
+ case '*':
+ nextChar();
+ type = LexicalUnits.ANY;
+ return;
+ case '(':
+ nextChar();
+ type = LexicalUnits.LEFT_BRACE;
+ return;
+ case ')':
+ nextChar();
+ type = LexicalUnits.RIGHT_BRACE;
+ return;
+ case ':':
+ nextChar();
+ type = LexicalUnits.COLON;
+ return;
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ case '\f':
+ do {
+ nextChar();
+ } while (ScannerUtilities.isCSSSpace((char)current));
+ type = LexicalUnits.SPACE;
+ return;
+ case '/':
+ nextChar();
+ if (current != '*') {
+ type = LexicalUnits.DIVIDE;
+ return;
+ }
+ // Comment
+ nextChar();
+ start = position - 1;
+ do {
+ while (current != -1 && current != '*') {
+ nextChar();
+ }
+ do {
+ nextChar();
+ } while (current != -1 && current == '*');
+ } while (current != -1 && current != '/');
+ if (current == -1) {
+ throw new ParseException("eof",
+ reader.getLine(),
+ reader.getColumn());
+ }
+ nextChar();
+ type = LexicalUnits.COMMENT;
+ return;
+ case '\'': // String1
+ type = string1();
+ return;
+ case '"': // String2
+ type = string2();
+ return;
+ case '<':
+ nextChar();
+ if (current != '!') {
+ throw new ParseException("character",
+ reader.getLine(),
+ reader.getColumn());
+ }
+ nextChar();
+ if (current == '-') {
+ nextChar();
+ if (current == '-') {
+ nextChar();
+ type = LexicalUnits.CDO;
+ return;
+ }
+ }
+ throw new ParseException("character",
+ reader.getLine(),
+ reader.getColumn());
+ case '-':
+ nextChar();
+ if (current != '-') {
+ type = LexicalUnits.MINUS;
+ return;
+ }
+ nextChar();
+ if (current == '>') {
+ nextChar();
+ type = LexicalUnits.CDC;
+ return;
+ }
+ throw new ParseException("character",
+ reader.getLine(),
+ reader.getColumn());
+ case '|':
+ nextChar();
+ if (current == '=') {
+ nextChar();
+ type = LexicalUnits.DASHMATCH;
+ return;
+ }
+ throw new ParseException("character",
+ reader.getLine(),
+ reader.getColumn());
+ case '~':
+ nextChar();
+ if (current == '=') {
+ nextChar();
+ type = LexicalUnits.INCLUDES;
+ return;
+ }
+ throw new ParseException("character",
+ reader.getLine(),
+ reader.getColumn());
+ case '#':
+ nextChar();
+ if (ScannerUtilities.isCSSNameCharacter((char)current)) {
+ start = position - 1;
+ do {
+ nextChar();
+ if (current == '\\') {
+ nextChar();
+ escape();
+ }
+ } while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter
+ ((char)current));
+ type = LexicalUnits.HASH;
+ return;
+ }
+ throw new ParseException("character",
+ reader.getLine(),
+ reader.getColumn());
+ case '@':
+ nextChar();
+ switch (current) {
+ case 'c':
+ case 'C':
+ start = position - 1;
+ if (isEqualIgnoreCase(nextChar(), 'h') &&
+ isEqualIgnoreCase(nextChar(), 'a') &&
+ isEqualIgnoreCase(nextChar(), 'r') &&
+ isEqualIgnoreCase(nextChar(), 's') &&
+ isEqualIgnoreCase(nextChar(), 'e') &&
+ isEqualIgnoreCase(nextChar(), 't')) {
+ nextChar();
+ type = LexicalUnits.CHARSET_SYMBOL;
+ return;
+ }
+ break;
+ case 'f':
+ case 'F':
+ start = position - 1;
+ if (isEqualIgnoreCase(nextChar(), 'o') &&
+ isEqualIgnoreCase(nextChar(), 'n') &&
+ isEqualIgnoreCase(nextChar(), 't') &&
+ isEqualIgnoreCase(nextChar(), '-') &&
+ isEqualIgnoreCase(nextChar(), 'f') &&
+ isEqualIgnoreCase(nextChar(), 'a') &&
+ isEqualIgnoreCase(nextChar(), 'c') &&
+ isEqualIgnoreCase(nextChar(), 'e')) {
+ nextChar();
+ type = LexicalUnits.FONT_FACE_SYMBOL;
+ return;
+ }
+ break;
+ case 'i':
+ case 'I':
+ start = position - 1;
+ if (isEqualIgnoreCase(nextChar(), 'm') &&
+ isEqualIgnoreCase(nextChar(), 'p') &&
+ isEqualIgnoreCase(nextChar(), 'o') &&
+ isEqualIgnoreCase(nextChar(), 'r') &&
+ isEqualIgnoreCase(nextChar(), 't')) {
+ nextChar();
+ type = LexicalUnits.IMPORT_SYMBOL;
+ return;
+ }
+ break;
+ case 'm':
+ case 'M':
+ start = position - 1;
+ if (isEqualIgnoreCase(nextChar(), 'e') &&
+ isEqualIgnoreCase(nextChar(), 'd') &&
+ isEqualIgnoreCase(nextChar(), 'i') &&
+ isEqualIgnoreCase(nextChar(), 'a')) {
+ nextChar();
+ type = LexicalUnits.MEDIA_SYMBOL;
+ return;
+ }
+ break;
+ case 'p':
+ case 'P':
+ start = position - 1;
+ if (isEqualIgnoreCase(nextChar(), 'a') &&
+ isEqualIgnoreCase(nextChar(), 'g') &&
+ isEqualIgnoreCase(nextChar(), 'e')) {
+ nextChar();
+ type = LexicalUnits.PAGE_SYMBOL;
+ return;
+ }
+ break;
+ default:
+ if (!ScannerUtilities.isCSSIdentifierStartCharacter
+ ((char)current)) {
+ throw new ParseException("identifier.character",
+ reader.getLine(),
+ reader.getColumn());
+ }
+ start = position - 1;
+ }
+ do {
+ nextChar();
+ if (current == '\\') {
+ nextChar();
+ escape();
+ }
+ } while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter((char)current));
+ type = LexicalUnits.AT_KEYWORD;
+ return;
+ case '!':
+ do {
+ nextChar();
+ } while (current != -1 &&
+ ScannerUtilities.isCSSSpace((char)current));
+ if (isEqualIgnoreCase(current, 'i') &&
+ isEqualIgnoreCase(nextChar(), 'm') &&
+ isEqualIgnoreCase(nextChar(), 'p') &&
+ isEqualIgnoreCase(nextChar(), 'o') &&
+ isEqualIgnoreCase(nextChar(), 'r') &&
+ isEqualIgnoreCase(nextChar(), 't') &&
+ isEqualIgnoreCase(nextChar(), 'a') &&
+ isEqualIgnoreCase(nextChar(), 'n') &&
+ isEqualIgnoreCase(nextChar(), 't')) {
+ nextChar();
+ type = LexicalUnits.IMPORTANT_SYMBOL;
+ return;
+ }
+ if (current == -1) {
+ throw new ParseException("eof",
+ reader.getLine(),
+ reader.getColumn());
+ } else {
+ throw new ParseException("character",
+ reader.getLine(),
+ reader.getColumn());
+ }
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ type = number();
+ return;
+ case '.':
+ switch (nextChar()) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ type = dotNumber();
+ return;
+ default:
+ type = LexicalUnits.DOT;
+ return;
+ }
+ case 'u':
+ case 'U':
+ nextChar();
+ switch (current) {
+ case '+':
+ boolean range = false;
+ for (int i = 0; i < 6; i++) {
+ nextChar();
+ switch (current) {
+ case '?':
+ range = true;
+ break;
+ default:
+ if (range &&
+ !ScannerUtilities.isCSSHexadecimalCharacter
+ ((char)current)) {
+ throw new ParseException("character",
+ reader.getLine(),
+ reader.getColumn());
+ }
+ }
+ }
+ nextChar();
+ if (range) {
+ type = LexicalUnits.UNICODE_RANGE;
+ return;
+ }
+ if (current == '-') {
+ nextChar();
+ if (!ScannerUtilities.isCSSHexadecimalCharacter
+ ((char)current)) {
+ throw new ParseException("character",
+ reader.getLine(),
+ reader.getColumn());
+ }
+ nextChar();
+ if (!ScannerUtilities.isCSSHexadecimalCharacter
+ ((char)current)) {
+ type = LexicalUnits.UNICODE_RANGE;
+ return;
+ }
+ nextChar();
+ if (!ScannerUtilities.isCSSHexadecimalCharacter
+ ((char)current)) {
+ type = LexicalUnits.UNICODE_RANGE;
+ return;
+ }
+ nextChar();
+ if (!ScannerUtilities.isCSSHexadecimalCharacter
+ ((char)current)) {
+ type = LexicalUnits.UNICODE_RANGE;
+ return;
+ }
+ nextChar();
+ if (!ScannerUtilities.isCSSHexadecimalCharacter
+ ((char)current)) {
+ type = LexicalUnits.UNICODE_RANGE;
+ return;
+ }
+ nextChar();
+ if (!ScannerUtilities.isCSSHexadecimalCharacter
+ ((char)current)) {
+ type = LexicalUnits.UNICODE_RANGE;
+ return;
+ }
+ nextChar();
+ type = LexicalUnits.UNICODE_RANGE;
+ return;
+ }
+ case 'r':
+ case 'R':
+ nextChar();
+ switch (current) {
+ case 'l':
+ case 'L':
+ nextChar();
+ switch (current) {
+ case '(':
+ do {
+ nextChar();
+ } while (current != -1 &&
+ ScannerUtilities.isCSSSpace
+ ((char)current));
+ switch (current) {
+ case '\'':
+ string1();
+ blankCharacters += 2;
+ while (current != -1 &&
+ ScannerUtilities.isCSSSpace
+ ((char)current)) {
+ blankCharacters++;
+ nextChar();
+ }
+ if (current == -1) {
+ throw new ParseException
+ ("eof",
+ reader.getLine(),
+ reader.getColumn());
+ }
+ if (current != ')') {
+ throw new ParseException
+ ("character",
+ reader.getLine(),
+ reader.getColumn());
+ }
+ nextChar();
+ type = LexicalUnits.URI;
+ return;
+ case '"':
+ string2();
+ blankCharacters += 2;
+ while (current != -1 &&
+ ScannerUtilities.isCSSSpace
+ ((char)current)) {
+ blankCharacters++;
+ nextChar();
+ }
+ if (current == -1) {
+ throw new ParseException
+ ("eof",
+ reader.getLine(),
+ reader.getColumn());
+ }
+ if (current != ')') {
+ throw new ParseException
+ ("character",
+ reader.getLine(),
+ reader.getColumn());
+ }
+ nextChar();
+ type = LexicalUnits.URI;
+ return;
+ case ')':
+ throw new ParseException("character",
+ reader.getLine(),
+ reader.getColumn());
+ default:
+ if (!ScannerUtilities.isCSSURICharacter
+ ((char)current)) {
+ throw new ParseException
+ ("character",
+ reader.getLine(),
+ reader.getColumn());
+ }
+ start = position - 1;
+ do {
+ nextChar();
+ } while (current != -1 &&
+ ScannerUtilities.isCSSURICharacter
+ ((char)current));
+ blankCharacters++;
+ while (current != -1 &&
+ ScannerUtilities.isCSSSpace
+ ((char)current)) {
+ blankCharacters++;
+ nextChar();
+ }
+ if (current == -1) {
+ throw new ParseException
+ ("eof",
+ reader.getLine(),
+ reader.getColumn());
+ }
+ if (current != ')') {
+ throw new ParseException
+ ("character",
+ reader.getLine(),
+ reader.getColumn());
+ }
+ nextChar();
+ type = LexicalUnits.URI;
+ return;
+ }
+ }
+ }
+ }
+ while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter((char)current)) {
+ nextChar();
+ }
+ if (current == '(') {
+ nextChar();
+ type = LexicalUnits.FUNCTION;
+ return;
+ }
+ type = LexicalUnits.IDENTIFIER;
+ return;
+ default:
+ if (ScannerUtilities.isCSSIdentifierStartCharacter
+ ((char)current)) {
+ // Identifier
+ do {
+ nextChar();
+ if (current == '\\') {
+ nextChar();
+ escape();
+ }
+ } while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter
+ ((char)current));
+ if (current == '(') {
+ nextChar();
+ type = LexicalUnits.FUNCTION;
+ return;
+ }
+ type = LexicalUnits.IDENTIFIER;
+ return;
+ }
+ nextChar();
+ throw new ParseException("identifier.character",
+ reader.getLine(),
+ reader.getColumn());
+ }
+ } catch (IOException e) {
+ throw new ParseException(e);
+ }
+ }
+
+ /**
+ * Scans a single quoted string.
+ */
+ protected int string1() throws IOException {
+ start = position; // fix bug #29416
+ loop: for (;;) {
+ switch (nextChar()) {
+ case -1:
+ throw new ParseException("eof",
+ reader.getLine(),
+ reader.getColumn());
+ case '\'':
+ break loop;
+ case '"':
+ break;
+ case '\\':
+ switch (nextChar()) {
+ case '\n':
+ case '\f':
+ break;
+ default:
+ escape();
+ }
+ break;
+ default:
+ if (!ScannerUtilities.isCSSStringCharacter((char)current)) {
+ throw new ParseException("character",
+ reader.getLine(),
+ reader.getColumn());
+ }
+ }
+ }
+ nextChar();
+ return LexicalUnits.STRING;
+ }
+
+ /**
+ * Scans a double quoted string.
+ */
+ protected int string2() throws IOException {
+ start = position; // fix bug #29416
+ loop: for (;;) {
+ switch (nextChar()) {
+ case -1:
+ throw new ParseException("eof",
+ reader.getLine(),
+ reader.getColumn());
+ case '\'':
+ break;
+ case '"':
+ break loop;
+ case '\\':
+ switch (nextChar()) {
+ case '\n':
+ case '\f':
+ break;
+ default:
+ escape();
+ }
+ break;
+ default:
+ if (!ScannerUtilities.isCSSStringCharacter((char)current)) {
+ throw new ParseException("character",
+ reader.getLine(),
+ reader.getColumn());
+ }
+ }
+ }
+ nextChar();
+ return LexicalUnits.STRING;
+ }
+
+ /**
+ * Scans a number.
+ */
+ protected int number() throws IOException {
+ loop: for (;;) {
+ switch (nextChar()) {
+ case '.':
+ switch (nextChar()) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ return dotNumber();
+ }
+ throw new ParseException("character",
+ reader.getLine(),
+ reader.getColumn());
+ default:
+ break loop;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ }
+ }
+ return numberUnit(true);
+ }
+
+ /**
+ * Scans the decimal part of a number.
+ */
+ protected int dotNumber() throws IOException {
+ loop: for (;;) {
+ switch (nextChar()) {
+ default:
+ break loop;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ }
+ }
+ return numberUnit(false);
+ }
+
+ /**
+ * Scans the unit of a number.
+ */
+ protected int numberUnit(boolean integer) throws IOException {
+ switch (current) {
+ case '%':
+ nextChar();
+ return LexicalUnits.PERCENTAGE;
+ case 'c':
+ case 'C':
+ switch(nextChar()) {
+ case 'm':
+ case 'M':
+ nextChar();
+ if (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter((char)current)) {
+ do {
+ nextChar();
+ } while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter
+ ((char)current));
+ return LexicalUnits.DIMENSION;
+ }
+ return LexicalUnits.CM;
+ default:
+ while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter((char)current)) {
+ nextChar();
+ }
+ return LexicalUnits.DIMENSION;
+ }
+ case 'd':
+ case 'D':
+ switch(nextChar()) {
+ case 'e':
+ case 'E':
+ switch(nextChar()) {
+ case 'g':
+ case 'G':
+ nextChar();
+ if (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter((char)current)) {
+ do {
+ nextChar();
+ } while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter
+ ((char)current));
+ return LexicalUnits.DIMENSION;
+ }
+ return LexicalUnits.DEG;
+ }
+ default:
+ while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter((char)current)) {
+ nextChar();
+ }
+ return LexicalUnits.DIMENSION;
+ }
+ case 'e':
+ case 'E':
+ switch(nextChar()) {
+ case 'm':
+ case 'M':
+ nextChar();
+ if (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter((char)current)) {
+ do {
+ nextChar();
+ } while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter
+ ((char)current));
+ return LexicalUnits.DIMENSION;
+ }
+ return LexicalUnits.EM;
+ case 'x':
+ case 'X':
+ nextChar();
+ if (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter((char)current)) {
+ do {
+ nextChar();
+ } while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter
+ ((char)current));
+ return LexicalUnits.DIMENSION;
+ }
+ return LexicalUnits.EX;
+ default:
+ while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter((char)current)) {
+ nextChar();
+ }
+ return LexicalUnits.DIMENSION;
+ }
+ case 'g':
+ case 'G':
+ switch(nextChar()) {
+ case 'r':
+ case 'R':
+ switch(nextChar()) {
+ case 'a':
+ case 'A':
+ switch(nextChar()) {
+ case 'd':
+ case 'D':
+ nextChar();
+ if (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter
+ ((char)current)) {
+ do {
+ nextChar();
+ } while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter
+ ((char)current));
+ return LexicalUnits.DIMENSION;
+ }
+ return LexicalUnits.GRAD;
+ }
+ }
+ default:
+ while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter((char)current)) {
+ nextChar();
+ }
+ return LexicalUnits.DIMENSION;
+ }
+ case 'h':
+ case 'H':
+ nextChar();
+ switch(current) {
+ case 'z':
+ case 'Z':
+ nextChar();
+ if (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter((char)current)) {
+ do {
+ nextChar();
+ } while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter
+ ((char)current));
+ return LexicalUnits.DIMENSION;
+ }
+ return LexicalUnits.HZ;
+ default:
+ while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter((char)current)) {
+ nextChar();
+ }
+ return LexicalUnits.DIMENSION;
+ }
+ case 'i':
+ case 'I':
+ switch(nextChar()) {
+ case 'n':
+ case 'N':
+ nextChar();
+ if (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter((char)current)) {
+ do {
+ nextChar();
+ } while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter
+ ((char)current));
+ return LexicalUnits.DIMENSION;
+ }
+ return LexicalUnits.IN;
+ default:
+ while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter((char)current)) {
+ nextChar();
+ }
+ return LexicalUnits.DIMENSION;
+ }
+ case 'k':
+ case 'K':
+ switch(nextChar()) {
+ case 'h':
+ case 'H':
+ switch(nextChar()) {
+ case 'z':
+ case 'Z':
+ nextChar();
+ if (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter((char)current)) {
+ do {
+ nextChar();
+ } while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter
+ ((char)current));
+ return LexicalUnits.DIMENSION;
+ }
+ return LexicalUnits.KHZ;
+ }
+ default:
+ while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter((char)current)) {
+ nextChar();
+ }
+ return LexicalUnits.DIMENSION;
+ }
+ case 'm':
+ case 'M':
+ switch(nextChar()) {
+ case 'm':
+ case 'M':
+ nextChar();
+ if (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter((char)current)) {
+ do {
+ nextChar();
+ } while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter
+ ((char)current));
+ return LexicalUnits.DIMENSION;
+ }
+ return LexicalUnits.MM;
+ case 's':
+ case 'S':
+ nextChar();
+ if (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter((char)current)) {
+ do {
+ nextChar();
+ } while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter
+ ((char)current));
+ return LexicalUnits.DIMENSION;
+ }
+ return LexicalUnits.MS;
+ default:
+ while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter((char)current)) {
+ nextChar();
+ }
+ return LexicalUnits.DIMENSION;
+ }
+ case 'p':
+ case 'P':
+ switch(nextChar()) {
+ case 'c':
+ case 'C':
+ nextChar();
+ if (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter((char)current)) {
+ do {
+ nextChar();
+ } while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter
+ ((char)current));
+ return LexicalUnits.DIMENSION;
+ }
+ return LexicalUnits.PC;
+ case 't':
+ case 'T':
+ nextChar();
+ if (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter((char)current)) {
+ do {
+ nextChar();
+ } while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter
+ ((char)current));
+ return LexicalUnits.DIMENSION;
+ }
+ return LexicalUnits.PT;
+ case 'x':
+ case 'X':
+ nextChar();
+ if (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter((char)current)) {
+ do {
+ nextChar();
+ } while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter
+ ((char)current));
+ return LexicalUnits.DIMENSION;
+ }
+ return LexicalUnits.PX;
+ default:
+ while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter((char)current)) {
+ nextChar();
+ }
+ return LexicalUnits.DIMENSION;
+ }
+ case 'r':
+ case 'R':
+ switch(nextChar()) {
+ case 'a':
+ case 'A':
+ switch(nextChar()) {
+ case 'd':
+ case 'D':
+ nextChar();
+ if (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter((char)current)) {
+ do {
+ nextChar();
+ } while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter
+ ((char)current));
+ return LexicalUnits.DIMENSION;
+ }
+ return LexicalUnits.RAD;
+ }
+ default:
+ while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter((char)current)) {
+ nextChar();
+ }
+ return LexicalUnits.DIMENSION;
+ }
+ case 's':
+ case 'S':
+ nextChar();
+ return LexicalUnits.S;
+ default:
+ if (current != -1 &&
+ ScannerUtilities.isCSSIdentifierStartCharacter
+ ((char)current)) {
+ do {
+ nextChar();
+ } while (current != -1 &&
+ ScannerUtilities.isCSSNameCharacter((char)current));
+ return LexicalUnits.DIMENSION;
+ }
+ return (integer) ? LexicalUnits.INTEGER : LexicalUnits.REAL;
+ }
+ }
+
+ /**
+ * Scans an escape sequence, if one.
+ */
+ protected void escape() throws IOException {
+ if (ScannerUtilities.isCSSHexadecimalCharacter((char)current)) {
+ nextChar();
+ if (!ScannerUtilities.isCSSHexadecimalCharacter((char)current)) {
+ if (ScannerUtilities.isCSSSpace((char)current)) {
+ nextChar();
+ }
+ return;
+ }
+ nextChar();
+ if (!ScannerUtilities.isCSSHexadecimalCharacter((char)current)) {
+ if (ScannerUtilities.isCSSSpace((char)current)) {
+ nextChar();
+ }
+ return;
+ }
+ nextChar();
+ if (!ScannerUtilities.isCSSHexadecimalCharacter((char)current)) {
+ if (ScannerUtilities.isCSSSpace((char)current)) {
+ nextChar();
+ }
+ return;
+ }
+ nextChar();
+ if (!ScannerUtilities.isCSSHexadecimalCharacter((char)current)) {
+ if (ScannerUtilities.isCSSSpace((char)current)) {
+ nextChar();
+ }
+ return;
+ }
+ nextChar();
+ if (!ScannerUtilities.isCSSHexadecimalCharacter((char)current)) {
+ if (ScannerUtilities.isCSSSpace((char)current)) {
+ nextChar();
+ }
+ return;
+ }
+ }
+ if ((current >= ' ' && current <= '~') || current >= 128) {
+ nextChar();
+ return;
+ }
+ throw new ParseException("character",
+ reader.getLine(),
+ reader.getColumn());
+ }
+
+ /**
+ * Compares the given int with the given character, ignoring case.
+ */
+ protected static boolean isEqualIgnoreCase(int i, char c) {
+ return (i == -1) ? false : Character.toLowerCase((char)i) == c;
+ }
+
+ /**
+ * Sets the value of the current char to the next character or -1 if the
+ * end of stream has been reached.
+ */
+ protected int nextChar() throws IOException {
+ current = reader.read();
+
+ if (current == -1) {
+ return current;
+ }
+
+ if (position == buffer.length) {
+ char[] t = new char[position * 3 / 2];
+ for (int i = 0; i < position; i++) {
+ t[i] = buffer[i];
+ }
+ buffer = t;
+ }
+
+ /* BEGIN Modification for Theme Editor */
+ customBuffer.append( (char)current );
+ /* END Modification for Theme Editor */
+
+ return buffer[position++] = (char)current;
+ }
+
+ /* BEGIN Modification for Theme Editor */
+ protected StringBuffer customBuffer = new StringBuffer();
+
+ public void clearCustomBuffer() {
+ customBuffer = new StringBuffer();
+ }
+
+ public String getCustomBufferData() {
+ return customBuffer.toString();
+ }
+ /* END Modification for Theme Editor */
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/ScannerUtilities.java b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/ScannerUtilities.java
new file mode 100644
index 0000000..d6e139a
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/css/parser/ScannerUtilities.java
@@ -0,0 +1,106 @@
+/*
+
+ Copyright 1999-2003 The Apache Software Foundation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+*/
+
+package org.apache.batik.css.parser;
+
+/**
+ * A collection of utility functions for a CSS scanner.
+ *
+ * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
+ * @version $Id: ScannerUtilities.java,v 1.1 2009/12/06 10:40:09 rsternber Exp $
+ */
+public class ScannerUtilities {
+
+ /**
+ * The set of the valid identifier start characters.
+ */
+ protected final static int[] IDENTIFIER_START = { 0, 0, 134217726, 134217726 };
+
+ /**
+ * The set of the valid name characters.
+ */
+ protected final static int[] NAME = { 0, 67051520, 134217726, 134217726 };
+
+ /**
+ * The set of the valid hexadecimal characters.
+ */
+ protected final static int[] HEXADECIMAL = { 0, 67043328, 126, 126 };
+
+ /**
+ * The set of the valid string characters.
+ */
+ protected final static int[] STRING = { 512, -133, -1, 2147483647 };
+
+ /**
+ * The set of the valid uri characters.
+ */
+ protected final static int[] URI = { 0, -902, -1, 2147483647 };
+
+ /**
+ * This class does not need to be instantiated.
+ */
+ protected ScannerUtilities() {
+ }
+
+ /**
+ * Tests whether the given character is a valid space.
+ */
+ public static boolean isCSSSpace(char c) {
+ return (c <= 0x0020) &&
+ (((((1L << '\t') |
+ (1L << '\n') |
+ (1L << '\r') |
+ (1L << '\f') |
+ (1L << 0x0020)) >> c) & 1L) != 0);
+ }
+
+ /**
+ * Tests whether the given character is a valid identifier start character.
+ */
+ public static boolean isCSSIdentifierStartCharacter(char c) {
+ return c >= 128 || ((IDENTIFIER_START[c / 32] & (1 << (c % 32))) != 0);
+ }
+
+ /**
+ * Tests whether the given character is a valid name character.
+ */
+ public static boolean isCSSNameCharacter(char c) {
+ return c >= 128 || ((NAME[c / 32] & (1 << (c % 32))) != 0);
+ }
+
+ /**
+ * Tests whether the given character is a valid hexadecimal character.
+ */
+ public static boolean isCSSHexadecimalCharacter(char c) {
+ return c < 128 && ((HEXADECIMAL[c / 32] & (1 << (c % 32))) != 0);
+ }
+
+ /**
+ * Tests whether the given character is a valid string character.
+ */
+ public static boolean isCSSStringCharacter(char c) {
+ return c >= 128 || ((STRING[c / 32] & (1 << (c % 32))) != 0);
+ }
+
+ /**
+ * Tests whether the given character is a valid URI character.
+ */
+ public static boolean isCSSURICharacter(char c) {
+ return c >= 128 || ((URI[c / 32] & (1 << (c % 32))) != 0);
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/ASCIIDecoder.java b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/ASCIIDecoder.java
new file mode 100644
index 0000000..eae2e20
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/ASCIIDecoder.java
@@ -0,0 +1,56 @@
+/*
+
+ Copyright 2002-2003 The Apache Software Foundation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.apache.batik.util.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * This class represents an object which decodes ASCII characters from
+ * a stream of bytes.
+ *
+ * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
+ * @version $Id: ASCIIDecoder.java,v 1.1 2009/12/06 10:40:09 rsternber Exp $
+ */
+public class ASCIIDecoder extends AbstractCharDecoder {
+
+ /**
+ * Creates a new ASCIIDecoder.
+ */
+ public ASCIIDecoder(InputStream is) {
+ super(is);
+ }
+
+ /**
+ * Reads the next character.
+ * @return a character or END_OF_STREAM.
+ */
+ public int readChar() throws IOException {
+ if (position == count) {
+ fillBuffer();
+ }
+ if (count == -1) {
+ return END_OF_STREAM;
+ }
+ int result = buffer[position++];
+ if (result < 0) {
+ charError("ASCII");
+ }
+ return result;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/AbstractCharDecoder.java b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/AbstractCharDecoder.java
new file mode 100644
index 0000000..7a79451
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/AbstractCharDecoder.java
@@ -0,0 +1,103 @@
+/*
+
+ Copyright 2002-2003 The Apache Software Foundation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.apache.batik.util.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.MessageFormat;
+
+/**
+ * This class is the superclass of all the char decoders.
+ *
+ * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
+ * @version $Id: AbstractCharDecoder.java,v 1.1 2009/12/06 10:40:09 rsternber Exp $
+ */
+public abstract class AbstractCharDecoder implements CharDecoder {
+
+ /**
+ * The buffer size.
+ */
+ protected final static int BUFFER_SIZE = 8192;
+
+ /**
+ * The input stream to read.
+ */
+ protected InputStream inputStream;
+
+ /**
+ * The input buffer.
+ */
+ protected byte[] buffer = new byte[BUFFER_SIZE];
+
+ /**
+ * The current position in the buffer.
+ */
+ protected int position;
+
+ /**
+ * The byte count in the buffer.
+ */
+ protected int count;
+
+ /**
+ * Creates a new CharDecoder object.
+ * @param is The stream to read.
+ */
+ protected AbstractCharDecoder(final InputStream is) {
+ inputStream = is;
+ }
+
+ /**
+ * Disposes the associated resources.
+ */
+ public void dispose() throws IOException {
+ inputStream.close();
+ inputStream = null;
+ }
+
+ /**
+ * Fills the input buffer.
+ */
+ protected void fillBuffer() throws IOException {
+ count = inputStream.read(buffer, 0, BUFFER_SIZE);
+ position = 0;
+ }
+
+ /**
+ * To throws an exception when the input stream contains an
+ * invalid character.
+ * @param encoding The encoding name.
+ */
+ protected void charError(final String encoding) throws IOException {
+ String pattern = "The input stream represents an invalid {0} stream.";
+ Object[] arguments = new Object[] { encoding };
+ String mesg = MessageFormat.format( pattern, arguments );
+ throw new IOException( mesg );
+ }
+
+ /**
+ * To throws an exception when the end of stream was unexpected.
+ * @param encoding The encoding name.
+ */
+ protected void endOfStreamError(final String encoding) throws IOException {
+ String pattern = "Unexpected end of stream while decoding a {0} stream.";
+ Object[] arguments = new Object[] { encoding };
+ String mesg = MessageFormat.format( pattern, arguments );
+ throw new IOException( mesg );
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/CharDecoder.java b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/CharDecoder.java
new file mode 100644
index 0000000..7da19b0
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/CharDecoder.java
@@ -0,0 +1,46 @@
+/*
+
+ Copyright 2002 The Apache Software Foundation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.apache.batik.util.io;
+
+import java.io.IOException;
+
+/**
+ * This interface represents an object which decodes characters from a
+ * stream of bytes.
+ *
+ * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
+ * @version $Id: CharDecoder.java,v 1.1 2009/12/06 10:40:09 rsternber Exp $
+ */
+public interface CharDecoder {
+
+ /**
+ * This constant represents the end of stream character.
+ */
+ int END_OF_STREAM = -1;
+
+ /**
+ * Reads the next character.
+ * @return a character or END_OF_STREAM.
+ */
+ int readChar() throws IOException;
+
+ /**
+ * Disposes the associated resources.
+ */
+ void dispose() throws IOException;
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/GenericDecoder.java b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/GenericDecoder.java
new file mode 100644
index 0000000..f226f38
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/GenericDecoder.java
@@ -0,0 +1,75 @@
+/*
+
+ Copyright 2002-2003 The Apache Software Foundation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.apache.batik.util.io;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+
+/**
+ * This class delegates to a reader the decoding of an input stream.
+ *
+ * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
+ * @version $Id: GenericDecoder.java,v 1.1 2009/12/06 10:40:09 rsternber Exp $
+ */
+public class GenericDecoder implements CharDecoder {
+
+ /**
+ * The reader used to decode the stream.
+ */
+ protected Reader reader;
+
+ /**
+ * Creates a new GenericDecoder.
+ * @param is The input stream to decode.
+ * @param enc The Java encoding name.
+ */
+ public GenericDecoder(InputStream is, String enc) throws IOException {
+ reader = new InputStreamReader(is, enc);
+ reader = new BufferedReader(reader);
+ }
+
+ /**
+ * Creates a new GenericDecoder.
+ * @param r The reader to use.
+ */
+ public GenericDecoder(Reader r) {
+ reader = r;
+ if (!(r instanceof BufferedReader)) {
+ reader = new BufferedReader(reader);
+ }
+ }
+
+ /**
+ * Reads the next character.
+ * @return a character or END_OF_STREAM.
+ */
+ public int readChar() throws IOException {
+ return reader.read();
+ }
+
+ /**
+ * Disposes the associated resources.
+ */
+ public void dispose() throws IOException {
+ reader.close();
+ reader = null;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/ISO_8859_1Decoder.java b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/ISO_8859_1Decoder.java
new file mode 100644
index 0000000..35af46f
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/ISO_8859_1Decoder.java
@@ -0,0 +1,52 @@
+/*
+
+ Copyright 2002-2003 The Apache Software Foundation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.apache.batik.util.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * This class represents an object which decodes ISO-8859-1 characters from
+ * a stream of bytes.
+ *
+ * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
+ * @version $Id: ISO_8859_1Decoder.java,v 1.1 2009/12/06 10:40:09 rsternber Exp $
+ */
+public class ISO_8859_1Decoder extends AbstractCharDecoder {
+
+ /**
+ * Creates a new ISO_8859_1Decoder.
+ */
+ public ISO_8859_1Decoder(InputStream is) {
+ super(is);
+ }
+
+ /**
+ * Reads the next character.
+ * @return a character or END_OF_STREAM.
+ */
+ public int readChar() throws IOException {
+ if (position == count) {
+ fillBuffer();
+ }
+ if (count == -1) {
+ return -1;
+ }
+ return buffer[position++] & 0xff;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/NormalizingReader.java b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/NormalizingReader.java
new file mode 100644
index 0000000..c85a4ee
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/NormalizingReader.java
@@ -0,0 +1,69 @@
+/*
+
+ Copyright 2002-2003 The Apache Software Foundation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.apache.batik.util.io;
+
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * This class represents a reader which normalizes the line break: \n,
+ * \r, \r\n are replaced by \n. The methods of this reader are not
+ * synchronized. The input is buffered.
+ *
+ * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
+ * @version $Id: NormalizingReader.java,v 1.1 2009/12/06 10:40:09 rsternber Exp $
+ */
+public abstract class NormalizingReader extends Reader {
+
+ /**
+ * Read characters into a portion of an array.
+ * @param cbuf Destination buffer
+ * @param off Offset at which to start writing characters
+ * @param len Maximum number of characters to read
+ * @return The number of characters read, or -1 if the end of the
+ * stream has been reached
+ */
+ public int read(char cbuf[], int off, int len) throws IOException {
+ if (len == 0) {
+ return 0;
+ }
+
+ int c = read();
+ if (c == -1) {
+ return -1;
+ }
+ int result = 0;
+ do {
+ cbuf[result + off] = (char)c;
+ result++;
+ c = read();
+ } while (c != -1 && result < len);
+ return result;
+ }
+
+ /**
+ * Returns the current line in the stream.
+ */
+ public abstract int getLine();
+
+ /**
+ * Returns the current column in the stream.
+ */
+ public abstract int getColumn();
+
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/StreamNormalizingReader.java b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/StreamNormalizingReader.java
new file mode 100644
index 0000000..a08d8c8
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/StreamNormalizingReader.java
@@ -0,0 +1,216 @@
+/*
+
+ Copyright 2002-2003 The Apache Software Foundation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.apache.batik.util.io;
+
+import java.io.*;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This class represents a NormalizingReader which handles streams of
+ * bytes.
+ *
+ * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
+ * @version $Id: StreamNormalizingReader.java,v 1.1 2009/12/06 10:40:09 rsternber Exp $
+ */
+public class StreamNormalizingReader extends NormalizingReader {
+
+ /**
+ * The char decoder.
+ */
+ protected CharDecoder charDecoder;
+
+ /**
+ * The next char.
+ */
+ protected int nextChar = -1;
+
+ /**
+ * The current line in the stream.
+ */
+ protected int line = 1;
+
+ /**
+ * The current column in the stream.
+ */
+ protected int column;
+
+ /**
+ * Creates a new NormalizingReader. The encoding is assumed to be
+ * ISO-8859-1.
+ * @param is The input stream to decode.
+ */
+ public StreamNormalizingReader(final InputStream is) throws IOException {
+ this(is, null);
+ }
+
+ /**
+ * Creates a new NormalizingReader.
+ * @param is The input stream to decode.
+ * @param enc The standard encoding name. A null encoding means
+ * ISO-8859-1.
+ */
+ public StreamNormalizingReader(final InputStream is, String enc)
+ throws IOException {
+ if (enc == null) {
+ enc = "ISO-8859-1";
+ }
+ charDecoder = createCharDecoder(is, enc);
+ }
+
+ /**
+ * Creates a new NormalizingReader.
+ * @param r The reader to wrap.
+ */
+ public StreamNormalizingReader(final Reader r) throws IOException {
+ charDecoder = new GenericDecoder(r);
+ }
+
+ /**
+ * This constructor is intended for use by subclasses.
+ */
+ protected StreamNormalizingReader() {
+ }
+
+ /**
+ * Read a single character. This method will block until a
+ * character is available, an I/O error occurs, or the end of the
+ * stream is reached.
+ */
+ public int read() throws IOException {
+ int result = nextChar;
+ if (result != -1) {
+ nextChar = -1;
+ if (result == 13) {
+ column = 0;
+ line++;
+ } else {
+ column++;
+ }
+ return result;
+ }
+ result = charDecoder.readChar();
+ switch (result) {
+ case 13:
+ column = 0;
+ line++;
+ int c = charDecoder.readChar();
+ if (c == 10) {
+ return 10;
+ }
+ nextChar = c;
+ return 10;
+
+ case 10:
+ column = 0;
+ line++;
+ }
+ return result;
+ }
+
+ /**
+ * Returns the current line in the stream.
+ */
+ public int getLine() {
+ return line;
+ }
+
+ /**
+ * Returns the current column in the stream.
+ */
+ public int getColumn() {
+ return column;
+ }
+
+ /**
+ * Close the stream.
+ */
+ public void close() throws IOException {
+ charDecoder.dispose();
+ charDecoder = null;
+ }
+
+ /**
+ * Creates the CharDecoder mapped with the given encoding name.
+ */
+ protected CharDecoder createCharDecoder(final InputStream is, final String enc)
+ throws IOException {
+ CharDecoderFactory cdf =
+ (CharDecoderFactory)charDecoderFactories.get(enc.toUpperCase());
+ if (cdf != null) {
+ return cdf.createCharDecoder(is);
+ }
+// String e = EncodingUtilities.javaEncoding(enc);
+// if (e == null) {
+// e = enc;
+// }
+ return new GenericDecoder(is, enc);
+ }
+
+ /**
+ * The CharDecoder factories map.
+ */
+ protected final static Map charDecoderFactories = new HashMap(11);
+ static {
+ CharDecoderFactory cdf = new ASCIIDecoderFactory();
+ charDecoderFactories.put("ASCII", cdf);
+ charDecoderFactories.put("US-ASCII", cdf);
+ charDecoderFactories.put("ISO-8859-1", new ISO_8859_1DecoderFactory());
+ charDecoderFactories.put("UTF-8", new UTF8DecoderFactory());
+ }
+
+ /**
+ * Represents a CharDecoder factory.
+ */
+ protected interface CharDecoderFactory {
+ CharDecoder createCharDecoder(InputStream is) throws IOException;
+ }
+
+ /**
+ * To create an ASCIIDecoder.
+ */
+ protected static class ASCIIDecoderFactory
+ implements CharDecoderFactory {
+ public CharDecoder createCharDecoder(final InputStream is)
+ throws IOException {
+ return new ASCIIDecoder(is);
+ }
+ }
+
+ /**
+ * To create an ISO_8859_1Decoder.
+ */
+ protected static class ISO_8859_1DecoderFactory
+ implements CharDecoderFactory {
+ public CharDecoder createCharDecoder(final InputStream is)
+ throws IOException {
+ return new ISO_8859_1Decoder(is);
+ }
+ }
+
+ /**
+ * To create a UTF8Decoder.
+ */
+ protected static class UTF8DecoderFactory
+ implements CharDecoderFactory {
+ public CharDecoder createCharDecoder(final InputStream is)
+ throws IOException {
+ return new UTF8Decoder(is);
+ }
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/StringDecoder.java b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/StringDecoder.java
new file mode 100644
index 0000000..43a9360
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/StringDecoder.java
@@ -0,0 +1,70 @@
+/*
+
+ Copyright 2002 The Apache Software Foundation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.apache.batik.util.io;
+
+import java.io.IOException;
+
+/**
+ * This class reads a string.
+ *
+ * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
+ * @version $Id: StringDecoder.java,v 1.1 2009/12/06 10:40:09 rsternber Exp $
+ */
+public class StringDecoder implements CharDecoder {
+
+ /**
+ * The string which contains the decoded characters.
+ */
+ protected String string;
+
+ /**
+ * The number of chars in the string.
+ */
+ protected int length;
+
+ /**
+ * The next char index.
+ */
+ protected int next;
+
+ /**
+ * Creates a new StringDecoder.
+ */
+ public StringDecoder(String s) {
+ string = s;
+ length = s.length();
+ }
+
+ /**
+ * Reads the next character.
+ * @return a character or END_OF_STREAM.
+ */
+ public int readChar() throws IOException {
+ if (next == length) {
+ return END_OF_STREAM;
+ }
+ return string.charAt(next++);
+ }
+
+ /**
+ * Disposes the associated resources.
+ */
+ public void dispose() throws IOException {
+ string = null;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/StringNormalizingReader.java b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/StringNormalizingReader.java
new file mode 100644
index 0000000..4ce4730
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/StringNormalizingReader.java
@@ -0,0 +1,110 @@
+/*
+
+ Copyright 2002 The Apache Software Foundation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.apache.batik.util.io;
+
+import java.io.IOException;
+
+/**
+ * This class represents a NormalizingReader which handles Strings.
+ *
+ * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
+ * @version $Id: StringNormalizingReader.java,v 1.1 2009/12/06 10:40:09 rsternber Exp $
+ */
+public class StringNormalizingReader extends NormalizingReader {
+
+ /**
+ * The characters.
+ */
+ protected String string;
+
+ /**
+ * The length of the string.
+ */
+ protected int length;
+
+ /**
+ * The index of the next character.
+ */
+ protected int next;
+
+ /**
+ * The current line in the stream.
+ */
+ protected int line = 1;
+
+ /**
+ * The current column in the stream.
+ */
+ protected int column;
+
+ /**
+ * Creates a new StringNormalizingReader.
+ * @param s The string to read.
+ */
+ public StringNormalizingReader(String s) {
+ string = s;
+ length = s.length();
+ }
+
+ /**
+ * Read a single character. This method will block until a
+ * character is available, an I/O error occurs, or the end of the
+ * stream is reached.
+ */
+ public int read() throws IOException {
+ int result = (length == next) ? -1 : string.charAt(next++);
+ if (result <= 13) {
+ switch (result) {
+ case 13:
+ column = 0;
+ line++;
+ int c = (length == next) ? -1 : string.charAt(next);
+ if (c == 10) {
+ next++;
+ }
+ return 10;
+
+ case 10:
+ column = 0;
+ line++;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the current line in the stream.
+ */
+ public int getLine() {
+ return line;
+ }
+
+ /**
+ * Returns the current column in the stream.
+ */
+ public int getColumn() {
+ return column;
+ }
+
+ /**
+ * Close the stream.
+ */
+ public void close() throws IOException {
+ string = null;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/UTF8Decoder.java b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/UTF8Decoder.java
new file mode 100644
index 0000000..e85d891
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/apache/batik/util/io/UTF8Decoder.java
@@ -0,0 +1,148 @@
+/*
+
+ Copyright 1999-2003 The Apache Software Foundation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+*/
+
+package org.apache.batik.util.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * This class represents an object which decodes UTF-8 characters from
+ * a stream of bytes.
+ *
+ * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
+ * @version $Id: UTF8Decoder.java,v 1.1 2009/12/06 10:40:09 rsternber Exp $
+ */
+public class UTF8Decoder extends AbstractCharDecoder {
+
+ /**
+ * The number of bytes of a UTF-8 sequence indexed by the first
+ * byte of the sequence.
+ */
+ protected final static byte[] UTF8_BYTES = {
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,
+ };
+
+ /**
+ * The next char, in case of a 4 bytes sequence.
+ */
+ protected int nextChar = -1;
+
+ /**
+ * Creates a new UTF8Decoder.
+ */
+ public UTF8Decoder(InputStream is) {
+ super(is);
+ }
+
+ /**
+ * Reads the next character.
+ * @return a character or END_OF_STREAM.
+ */
+ public int readChar() throws IOException {
+ if (nextChar != -1) {
+ int result = nextChar;
+ nextChar = -1;
+ return result;
+ }
+ if (position == count) {
+ fillBuffer();
+ }
+ if (count == -1) {
+ return END_OF_STREAM;
+ }
+ int b1 = buffer[position++] & 0xff;
+ switch (UTF8_BYTES[b1]) {
+ default:
+ charError("UTF-8");
+
+ case 1:
+ return b1;
+
+ case 2:
+ if (position == count) {
+ fillBuffer();
+ }
+ if (count == -1) {
+ endOfStreamError("UTF-8");
+ }
+ return ((b1 & 0x1f) << 6) | (buffer[position++] & 0x3f);
+
+ case 3:
+ if (position == count) {
+ fillBuffer();
+ }
+ if (count == -1) {
+ endOfStreamError("UTF-8");
+ }
+ int b2 = buffer[position++];
+ if (position == count) {
+ fillBuffer();
+ }
+ if (count == -1) {
+ endOfStreamError("UTF-8");
+ }
+ int b3 = buffer[position++];
+ if ((b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80) {
+ charError("UTF-8");
+ }
+ return ((b1 & 0x1f) << 12) | ((b2 & 0x3f) << 6) | (b3 & 0x1f);
+
+ case 4:
+ if (position == count) {
+ fillBuffer();
+ }
+ if (count == -1) {
+ endOfStreamError("UTF-8");
+ }
+ b2 = buffer[position++];
+ if (position == count) {
+ fillBuffer();
+ }
+ if (count == -1) {
+ endOfStreamError("UTF-8");
+ }
+ b3 = buffer[position++];
+ if (position == count) {
+ fillBuffer();
+ }
+ if (count == -1) {
+ endOfStreamError("UTF-8");
+ }
+ int b4 = buffer[position++];
+ if ((b2 & 0xc0) != 0x80 ||
+ (b3 & 0xc0) != 0x80 ||
+ (b4 & 0xc0) != 0x80) {
+ charError("UTF-8");
+ }
+ int c = ((b1 & 0x1f) << 18)
+ | ((b2 & 0x3f) << 12)
+ | ((b3 & 0x1f) << 6)
+ | (b4 & 0x1f);
+ nextChar = (c - 0x10000) % 0x400 + 0xdc00;
+ return (c - 0x10000) / 0x400 + 0xd800;
+ }
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/AttributeCondition.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/AttributeCondition.java
new file mode 100644
index 0000000..56608df
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/AttributeCondition.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1999 World Wide Web Consortium,
+ * (Massachusetts Institute of Technology, Institut National de
+ * Recherche en Informatique et en Automatique, Keio University). All
+ * Rights Reserved. This program is distributed under the W3C's Software
+ * Intellectual Property License. This program is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
+ *
+ * $Id: AttributeCondition.java,v 1.1 2009/12/06 10:40:07 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+/**
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret
+ * @see Condition#SAC_ATTRIBUTE_CONDITION
+ * @see Condition#SAC_ONE_OF_ATTRIBUTE_CONDITION
+ * @see Condition#SAC_BEGIN_HYPHEN_ATTRIBUTE_CONDITION
+ * @see Condition#SAC_ID_CONDITION
+ * @see Condition#SAC_CLASS_CONDITION
+ * @see Condition#SAC_PSEUDO_CLASS_CONDITION
+ */
+public interface AttributeCondition extends Condition {
+
+ /**
+ * Returns the
+ * <a href="http://www.w3.org/TR/REC-xml-names/#dt-NSName">namespace
+ * URI</a> of this attribute condition.
+ * <p><code>NULL</code> if :
+ * <ul>
+ * <li>this attribute condition can match any namespace.
+ * <li>this attribute is an id attribute.
+ * </ul>
+ */
+ public String getNamespaceURI();
+
+ /**
+ * Returns the
+ * <a href="http://www.w3.org/TR/REC-xml-names/#NT-LocalPart">local part</a>
+ * of the
+ * <a href="http://www.w3.org/TR/REC-xml-names/#ns-qualnames">qualified
+ * name</a> of this attribute.
+ * <p><code>NULL</code> if :
+ * <ul>
+ * <li><p>this attribute condition can match any attribute.
+ * <li><p>this attribute is a class attribute.
+ * <li><p>this attribute is an id attribute.
+ * <li><p>this attribute is a pseudo-class attribute.
+ * </ul>
+ */
+ public String getLocalName();
+
+ /**
+ * Returns <code>true</code> if the attribute must have an explicit value
+ * in the original document, <code>false</code> otherwise. If this is a
+ * pseudo class, the return value is unspecified.
+ * <p><code>false</code> if:
+ * <ul>
+ * <li>if this is an id attribute.
+ * <li>if this is a pseudo class a class attribute.
+ * </ul>
+ */
+ public boolean getSpecified();
+
+ /**
+ * Returns the value of the attribute.
+ * If this attribute is a class or a pseudo class attribute, you'll get
+ * the class name (or psedo class name) without the '.' or ':'.
+ */
+ public String getValue();
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/CSSException.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/CSSException.java
new file mode 100644
index 0000000..bcf01b7
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/CSSException.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 1999 World Wide Web Consortium
+ * (Massachusetts Institute of Technology, Institut National de Recherche
+ * en Informatique et en Automatique, Keio University).
+ * All Rights Reserved. http://www.w3.org/Consortium/Legal/
+ *
+ * The original version of this interface comes from SAX :
+ * http://www.megginson.com/SAX/
+ *
+ * $Id: CSSException.java,v 1.1 2009/12/06 10:40:07 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+/**
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret
+ */
+public class CSSException extends RuntimeException {
+
+ protected String s;
+
+ /**
+ * this error is unspecified.
+ */
+ public static short SAC_UNSPECIFIED_ERR = 0;
+
+ /**
+ * If the operation is not supported
+ */
+ public static short SAC_NOT_SUPPORTED_ERR = 1;
+
+ /**
+ * If an invalid or illegal string is specified
+ */
+ public static short SAC_SYNTAX_ERR = 2;
+
+ /**
+ * The internal exception.
+ */
+ protected Exception e;
+
+ protected short code;
+
+ /**
+ * Creates a new CSSException
+ */
+ public CSSException() {
+ }
+
+ /**
+ * Creates a new CSSException
+ */
+ public CSSException(String s) {
+ this.code = SAC_UNSPECIFIED_ERR;
+ this.s = s;
+ }
+
+ /**
+ * Creates a new CSSException with an embeded exception.
+ * @param e the embeded exception.
+ */
+ public CSSException(Exception e) {
+ this.code = SAC_UNSPECIFIED_ERR;
+ this.e = e;
+ }
+
+ /**
+ * Creates a new CSSException with a specific code.
+ * @param code the embeded exception.
+ */
+ public CSSException(short code) {
+ this.code = code;
+ }
+
+ /**
+ * Creates a new CSSException with an embeded exception and a specified
+ * message.
+ * @param code the specified code.
+ * @param e the embeded exception.
+ */
+ public CSSException(short code, String s, Exception e) {
+ this.code = code;
+ this.s = s;
+ this.e = e;
+ }
+
+ /**
+ * Returns the detail message of this throwable object.
+ *
+ * @return the detail message of this Throwable, or null if this Throwable
+ * does not have a detail message.
+ */
+ public String getMessage() {
+ if (s != null) {
+ return s;
+ } else if (e != null) {
+ return e.getMessage();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * returns the error code for this exception.
+ */
+ public short getCode() {
+ return code;
+ }
+
+ /**
+ * Returns the internal exception if any, null otherwise.
+ */
+ public Exception getException() {
+ return e;
+ }
+
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/CSSParseException.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/CSSParseException.java
new file mode 100644
index 0000000..4d236e2
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/CSSParseException.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 1999 World Wide Web Consortium
+ * (Massachusetts Institute of Technology, Institut National de Recherche
+ * en Informatique et en Automatique, Keio University).
+ * All Rights Reserved. http://www.w3.org/Consortium/Legal/
+ *
+ * The original version of this interface comes from SAX :
+ * http://www.megginson.com/SAX/
+ *
+ * $Id: CSSParseException.java,v 1.1 2009/12/06 10:40:08 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+/**
+ * Encapsulate a CSS parse error or warning.
+ *
+ * <p>This exception will include information for locating the error
+ * in the original CSS document. Note that although the application
+ * will receive a CSSParseException as the argument to the handlers
+ * in the ErrorHandler interface, the application is not actually
+ * required to throw the exception; instead, it can simply read the
+ * information in it and take a different action.</p>
+ *
+ * <p>Since this exception is a subclass of CSSException, it
+ * inherits the ability to wrap another exception.</p>
+ *
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret
+ */
+public class CSSParseException extends CSSException {
+
+ private String uri;
+ private int lineNumber;
+ private int columnNumber;
+
+ /**
+ * Create a new CSSParseException from a message and a Locator.
+ *
+ * <p>This constructor is especially useful when an application is
+ * creating its own exception from within a DocumentHandler
+ * callback.</p>
+ *
+ * @param message The error or warning message.
+ * @param locator The locator object for the error or warning.
+ * @see Locator
+ * @see Parser#setLocale
+ */
+ public CSSParseException(String message, Locator locator) {
+ super(message);
+ this.code = SAC_SYNTAX_ERR;
+ this.uri = locator.getURI();
+ this.lineNumber = locator.getLineNumber();
+ this.columnNumber = locator.getColumnNumber();
+ }
+
+
+ /**
+
+ * Wrap an existing exception in a CSSParseException.
+ *
+ * <p>This constructor is especially useful when an application is
+ * creating its own exception from within a DocumentHandler
+ * callback, and needs to wrap an existing exception that is not a
+ * subclass of CSSException.</p>
+ *
+ * @param message The error or warning message, or null to
+ * use the message from the embedded exception.
+ * @param locator The locator object for the error or warning.
+ * @param e Any exception
+ * @see Locator
+ * @see Parser#setLocale
+ */
+ public CSSParseException(String message, Locator locator,
+ Exception e) {
+ super(SAC_SYNTAX_ERR, message, e);
+ this.uri = locator.getURI();
+ this.lineNumber = locator.getLineNumber();
+ this.columnNumber = locator.getColumnNumber();
+ }
+
+
+ /**
+ * Create a new CSSParseException.
+ *
+ * <p>This constructor is most useful for parser writers.</p>
+ *
+ * <p>the parser must resolve the URI fully before creating the exception.</p>
+ *
+ * @param message The error or warning message.
+ * @param uri The URI of the document that generated the error or warning.
+ * @param lineNumber The line number of the end of the text that
+ * caused the error or warning.
+ * @param columnNumber The column number of the end of the text that
+ * cause the error or warning.
+ * @see Parser#setLocale
+ */
+ public CSSParseException(String message, String uri,
+ int lineNumber, int columnNumber) {
+ super(message);
+ this.code = SAC_SYNTAX_ERR;
+ this.uri = uri;
+ this.lineNumber = lineNumber;
+ this.columnNumber = columnNumber;
+ }
+
+ /**
+ * Create a new CSSParseException with an embedded exception.
+ *
+ * <p>This constructor is most useful for parser writers who
+ * need to wrap an exception that is not a subclass of
+ * CSSException.</p>
+ *
+ * <p>The parser must resolve the URI fully before creating the
+ * exception.</p>
+ *
+ * @param message The error or warning message, or null to use
+ * the message from the embedded exception.
+ * @param uri The URI of the document that generated
+ * the error or warning.
+ * @param lineNumber The line number of the end of the text that
+ * caused the error or warning.
+ * @param columnNumber The column number of the end of the text that
+ * cause the error or warning.
+ * @param e Another exception to embed in this one.
+ * @see Parser#setLocale
+ */
+ public CSSParseException(String message, String uri,
+ int lineNumber, int columnNumber, Exception e) {
+ super(SAC_SYNTAX_ERR, message, e);
+ this.uri = uri;
+ this.lineNumber = lineNumber;
+ this.columnNumber = columnNumber;
+ }
+
+ /**
+ * Get the URI of the document where the exception occurred.
+ *
+ * <p>The URI will be resolved fully.</p>
+ *
+ * @return A string containing the URI, or null
+ * if none is available.
+ * @see Locator#getURI
+ */
+ public String getURI() {
+ return this.uri;
+ }
+
+
+ /**
+ * The line number of the end of the text where the exception occurred.
+ *
+ * @return An integer representing the line number, or -1
+ * if none is available.
+ * @see Locator#getLineNumber
+ */
+ public int getLineNumber() {
+ return this.lineNumber;
+ }
+
+
+ /**
+ * The column number of the end of the text where the exception occurred.
+ *
+ * <p>The first column in a line is position 1.</p>
+ *
+ * @return An integer representing the column number, or -1
+ * if none is available.
+ * @see Locator#getColumnNumber
+ */
+ public int getColumnNumber() {
+ return this.columnNumber;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/CharacterDataSelector.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/CharacterDataSelector.java
new file mode 100644
index 0000000..1b2ba5b
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/CharacterDataSelector.java
@@ -0,0 +1,24 @@
+/*
+ * (c) COPYRIGHT 1999 World Wide Web Consortium
+ * (Massachusetts Institute of Technology, Institut National de Recherche
+ * en Informatique et en Automatique, Keio University).
+ * All Rights Reserved. http://www.w3.org/Consortium/Legal/
+ *
+ * $Id: CharacterDataSelector.java,v 1.1 2009/12/06 10:40:07 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+/**
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret
+ * @see Selector#SAC_TEXT_NODE_SELECTOR
+ * @see Selector#SAC_CDATA_SECTION_NODE_SELECTOR
+ * @see Selector#SAC_COMMENT_NODE_SELECTOR
+ */
+public interface CharacterDataSelector extends SimpleSelector {
+
+ /**
+ * Returns the character data.
+ */
+ public String getData();
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/CombinatorCondition.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/CombinatorCondition.java
new file mode 100644
index 0000000..1b7c248
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/CombinatorCondition.java
@@ -0,0 +1,28 @@
+/*
+ * (c) COPYRIGHT 1999 World Wide Web Consortium
+ * (Massachusetts Institute of Technology, Institut National de Recherche
+ * en Informatique et en Automatique, Keio University).
+ * All Rights Reserved. http://www.w3.org/Consortium/Legal/
+ *
+ * $Id: CombinatorCondition.java,v 1.1 2009/12/06 10:40:08 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+/**
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret
+ * @see Condition#SAC_AND_CONDITION
+ * @see Condition#SAC_OR_CONDITION
+ */
+public interface CombinatorCondition extends Condition {
+
+ /**
+ * Returns the first condition.
+ */
+ public Condition getFirstCondition();
+
+ /**
+ * Returns the second condition.
+ */
+ public Condition getSecondCondition();
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/Condition.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/Condition.java
new file mode 100644
index 0000000..90f7ee8
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/Condition.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 1999 World Wide Web Consortium,
+ * (Massachusetts Institute of Technology, Institut National de
+ * Recherche en Informatique et en Automatique, Keio University). All
+ * Rights Reserved. This program is distributed under the W3C's Software
+ * Intellectual Property License. This program is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
+ *
+ * $Id: Condition.java,v 1.1 2009/12/06 10:40:07 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+/**
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret
+ */
+public interface Condition {
+
+ /**
+ * This condition checks exactly two conditions.
+ * example:
+ * <pre class="example">
+ * .part1:lang(fr)
+ * </pre>
+ * @see CombinatorCondition
+ */
+ public static final short SAC_AND_CONDITION = 0;
+
+ /**
+ * This condition checks one of two conditions.
+ * @see CombinatorCondition
+ */
+ public static final short SAC_OR_CONDITION = 1;
+
+ /**
+ * This condition checks that a condition can't be applied to a node.
+ * @see NegativeCondition
+ */
+ public static final short SAC_NEGATIVE_CONDITION = 2;
+
+ /**
+ * This condition checks a specified position.
+ * example:
+ * <pre class="example">
+ * :first-child
+ * </pre>
+ * @see PositionalCondition
+ */
+ public static final short SAC_POSITIONAL_CONDITION = 3;
+
+ /**
+ * This condition checks an attribute.
+ * example:
+ * <pre class="example">
+ * [simple]
+ * [restart="never"]
+ * </pre>
+ * @see AttributeCondition
+ */
+ public static final short SAC_ATTRIBUTE_CONDITION = 4;
+ /**
+ * This condition checks an id attribute.
+ * example:
+ * <pre class="example">
+ * #myId
+ * </pre>
+ * @see AttributeCondition
+ */
+ public static final short SAC_ID_CONDITION = 5;
+ /**
+ * This condition checks the language of the node.
+ * example:
+ * <pre class="example">
+ * :lang(fr)
+ * </pre>
+ * @see LangCondition
+ */
+ public static final short SAC_LANG_CONDITION = 6;
+ /**
+ * This condition checks for a value in a space-separated values in a
+ * specified attribute.
+ * example:
+ * <pre class="example">
+ * [values~="10"]
+ * </pre>
+ * @see AttributeCondition
+ */
+ public static final short SAC_ONE_OF_ATTRIBUTE_CONDITION = 7;
+ /**
+ * This condition checks if the value is in a hypen-separated list of values
+ * in a specified attribute.
+ * example:
+ * <pre class="example">
+ * [languages|="fr"]
+ * </pre>
+ * @see AttributeCondition
+ */
+ public static final short SAC_BEGIN_HYPHEN_ATTRIBUTE_CONDITION = 8;
+ /**
+ * This condition checks for a specified class.
+ * example:
+ * <pre class="example">
+ * .example
+ * </pre>
+ * @see AttributeCondition
+ */
+ public static final short SAC_CLASS_CONDITION = 9;
+ /**
+ * This condition checks for the link pseudo class.
+ * example:
+ * <pre class="example">
+ * :link
+ * :visited
+ * :hover
+ * </pre>
+ * @see AttributeCondition
+ */
+ public static final short SAC_PSEUDO_CLASS_CONDITION = 10;
+ /**
+ * This condition checks if a node is the only one in the node list.
+ */
+ public static final short SAC_ONLY_CHILD_CONDITION = 11;
+ /**
+ * This condition checks if a node is the only one of his type.
+ */
+ public static final short SAC_ONLY_TYPE_CONDITION = 12;
+ /**
+ * This condition checks the content of a node.
+ * @see ContentCondition
+ */
+ public static final short SAC_CONTENT_CONDITION = 13;
+
+ /**
+ * An integer indicating the type of <code>Condition</code>.
+ */
+ public short getConditionType();
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/ConditionFactory.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/ConditionFactory.java
new file mode 100644
index 0000000..82de332
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/ConditionFactory.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 1999 World Wide Web Consortium,
+ * (Massachusetts Institute of Technology, Institut National de
+ * Recherche en Informatique et en Automatique, Keio University). All
+ * Rights Reserved. This program is distributed under the W3C's Software
+ * Intellectual Property License. This program is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
+ *
+ * $Id: ConditionFactory.java,v 1.1 2009/12/06 10:40:07 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+/**
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret
+ */
+public interface ConditionFactory {
+
+ /**
+ * Creates an and condition
+ *
+ * @param first the first condition
+ * @param second the second condition
+ * @return A combinator condition
+ * @exception CSSException if this exception is not supported.
+ */
+ CombinatorCondition createAndCondition(Condition first, Condition second)
+ throws CSSException;
+
+ /**
+ * Creates an or condition
+ *
+ * @param first the first condition
+ * @param second the second condition
+ * @return A combinator condition
+ * @exception CSSException if this exception is not supported.
+ */
+ CombinatorCondition createOrCondition(Condition first, Condition second)
+ throws CSSException;
+
+ /**
+ * Creates a negative condition
+ *
+ * @param condition the condition
+ * @return A negative condition
+ * @exception CSSException if this exception is not supported.
+ */
+ NegativeCondition createNegativeCondition(Condition condition)
+ throws CSSException;
+
+ /**
+ * Creates a positional condition
+ *
+ * @param position the position of the node in the list.
+ * @param typeNode <code>true</code> if the list should contain
+ * only nodes of the same type (element, text node, ...).
+ * @param type <code>true</code> true if the list should contain
+ * only nodes of the same node (for element, same localName
+ * and same namespaceURI).
+ * @return A positional condition
+ * @exception CSSException if this exception is not supported.
+ */
+ PositionalCondition createPositionalCondition(int position,
+ boolean typeNode,
+ boolean type)
+ throws CSSException;
+
+ /**
+ * Creates an attribute condition
+ *
+ * @param localName the localName of the attribute
+ * @param namespaceURI the namespace URI of the attribute
+ * @param specified <code>true</code> if the attribute must be specified
+ * in the document.
+ * @param value the value of this attribute.
+ * @return An attribute condition
+ * @exception CSSException if this exception is not supported.
+ */
+ AttributeCondition createAttributeCondition(String localName,
+ String namespaceURI,
+ boolean specified,
+ String value)
+ throws CSSException;
+
+ /**
+ * Creates an id condition
+ *
+ * @param value the value of the id.
+ * @return An Id condition
+ * @exception CSSException if this exception is not supported.
+ */
+ AttributeCondition createIdCondition(String value)
+ throws CSSException;
+
+ /**
+ * Creates a lang condition
+ *
+ * @param lang the value of the language.
+ * @return A lang condition
+ * @exception CSSException if this exception is not supported.
+ */
+ LangCondition createLangCondition(String lang)
+ throws CSSException;
+
+ /**
+ * Creates a "one of" attribute condition
+ *
+ * @param localName the localName of the attribute
+ * @param namespaceURI the namespace URI of the attribute
+ * @param specified <code>true</code> if the attribute must be specified
+ * in the document.
+ * @param value the value of this attribute.
+ * @return A "one of" attribute condition
+ * @exception CSSException if this exception is not supported.
+ */
+ AttributeCondition createOneOfAttributeCondition(String localName,
+ String namespaceURI,
+ boolean specified,
+ String value)
+ throws CSSException;
+
+ /**
+ * Creates a "begin hyphen" attribute condition
+ *
+ * @param localName the localName of the attribute
+ * @param namespaceURI the namespace URI of the attribute
+ * @param specified <code>true</code> if the attribute must be specified
+ * in the document.
+ * @param value the value of this attribute.
+ * @return A "begin hyphen" attribute condition
+ * @exception CSSException if this exception is not supported.
+ */
+ AttributeCondition createBeginHyphenAttributeCondition(String localName,
+ String namespaceURI,
+ boolean specified,
+ String value)
+ throws CSSException;
+
+ /**
+ * Creates a class condition
+ *
+ * @param namespaceURI the namespace URI of the attribute
+ * @param value the name of the class.
+ * @return A class condition
+ * @exception CSSException if this exception is not supported.
+ */
+ AttributeCondition createClassCondition(String namespaceURI,
+ String value)
+ throws CSSException;
+
+ /**
+ * Creates a pseudo class condition
+ *
+ * @param namespaceURI the namespace URI of the attribute
+ * @param value the name of the pseudo class
+ * @return A pseudo class condition
+ * @exception CSSException if this exception is not supported.
+ */
+ AttributeCondition createPseudoClassCondition(String namespaceURI,
+ String value)
+ throws CSSException;
+
+ /**
+ * Creates a "only one" child condition
+ *
+ * @return A "only one" child condition
+ * @exception CSSException if this exception is not supported.
+ */
+ Condition createOnlyChildCondition() throws CSSException;
+
+
+ /**
+ * Creates a "only one" type condition
+ *
+ * @return A "only one" type condition
+ * @exception CSSException if this exception is not supported.
+ */
+ Condition createOnlyTypeCondition() throws CSSException;
+
+ /**
+ * Creates a content condition
+ *
+ * @param data the data in the content
+ * @return A content condition
+ * @exception CSSException if this exception is not supported.
+ */
+ ContentCondition createContentCondition(String data)
+ throws CSSException;
+
+
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/ConditionalSelector.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/ConditionalSelector.java
new file mode 100644
index 0000000..266edc9
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/ConditionalSelector.java
@@ -0,0 +1,28 @@
+/*
+ * (c) COPYRIGHT 1999 World Wide Web Consortium
+ * (Massachusetts Institute of Technology, Institut National de Recherche
+ * en Informatique et en Automatique, Keio University).
+ * All Rights Reserved. http://www.w3.org/Consortium/Legal/
+ *
+ * $Id: ConditionalSelector.java,v 1.1 2009/12/06 10:40:08 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+/**
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret
+ * @see Selector#SAC_CONDITIONAL_SELECTOR
+ */
+public interface ConditionalSelector extends SimpleSelector {
+
+ /**
+ * Returns the simple selector.
+ * <p>The simple selector can't be a <code>ConditionalSelector</code>.</p>
+ */
+ public SimpleSelector getSimpleSelector();
+
+ /**
+ * Returns the condition to be applied on the simple selector.
+ */
+ public Condition getCondition();
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/ContentCondition.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/ContentCondition.java
new file mode 100644
index 0000000..ec72810
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/ContentCondition.java
@@ -0,0 +1,21 @@
+/*
+ * (c) COPYRIGHT 1999 World Wide Web Consortium
+ * (Massachusetts Institute of Technology, Institut National de Recherche
+ * en Informatique et en Automatique, Keio University).
+ * All Rights Reserved. http://www.w3.org/Consortium/Legal/
+ *
+ * $Id: ContentCondition.java,v 1.1 2009/12/06 10:40:08 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+/**
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret
+ * @see Condition#SAC_CONTENT_CONDITION
+ */
+public interface ContentCondition extends Condition {
+ /**
+ * Returns the content.
+ */
+ public String getData();
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/DescendantSelector.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/DescendantSelector.java
new file mode 100644
index 0000000..55c06d2
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/DescendantSelector.java
@@ -0,0 +1,28 @@
+/*
+ * (c) COPYRIGHT 1999 World Wide Web Consortium
+ * (Massachusetts Institute of Technology, Institut National de Recherche
+ * en Informatique et en Automatique, Keio University).
+ * All Rights Reserved. http://www.w3.org/Consortium/Legal/
+ *
+ * $Id: DescendantSelector.java,v 1.1 2009/12/06 10:40:08 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+/**
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret
+ * @see Selector#SAC_DESCENDANT_SELECTOR
+ * @see Selector#SAC_CHILD_SELECTOR
+ */
+public interface DescendantSelector extends Selector {
+
+ /**
+ * Returns the parent selector.
+ */
+ public Selector getAncestorSelector();
+
+ /*
+ * Returns the simple selector.
+ */
+ public SimpleSelector getSimpleSelector();
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/DocumentHandler.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/DocumentHandler.java
new file mode 100644
index 0000000..4f89756
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/DocumentHandler.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 1999 World Wide Web Consortium
+ * (Massachusetts Institute of Technology, Institut National de Recherche
+ * en Informatique et en Automatique, Keio University).
+ * All Rights Reserved. http://www.w3.org/Consortium/Legal/
+ *
+ * $Id: DocumentHandler.java,v 1.1 2009/12/06 10:40:08 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+/**
+ * This is the main interface that most CSS applications implement: if the
+ * application needs to be informed of basic parsing events, it implements this
+ * interface and registers an instance with the CSS parser using the
+ * setCSSHandler method.
+ *
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret
+ */
+public interface DocumentHandler {
+
+ /**
+ * Receive notification of the beginning of a style sheet.
+ *
+ * The CSS parser will invoke this method only once, before any other
+ * methods in this interface.
+ *
+ * @param source The source of the style sheet.
+ * @exception CSSException Any CSS exception, possibly wrapping another
+ * exception.
+ */
+ public void startDocument(InputSource source)
+ throws CSSException;
+
+ /**
+ * Receive notification of the end of a document.
+ *
+ * The CSS parser will invoke this method only once, and it will be the
+ * last method invoked during the parse. The parser shall not invoke this
+ * method until it has either abandoned parsing (because of an
+ * unrecoverable error) or reached the end of input.
+ *
+ * @param source The source of the style sheet.
+ * @exception CSSException Any CSS exception, possibly wrapping another
+ * exception.
+ */
+ public void endDocument(InputSource source) throws CSSException;
+
+ /**
+ * Receive notification of a comment.
+ * If the comment appears in a declaration (e.g. color: /* comment * / blue;),
+ * the parser notifies the comment before the declaration.
+ *
+ * @param text The comment.
+ * @exception CSSException Any CSS exception, possibly wrapping another
+ * exception.
+ */
+ public void comment(String text) throws CSSException;
+
+ /**
+ * Receive notification of an unknown rule t-rule not supported by this
+ * parser.
+ *
+ * @param atRule The complete ignored at-rule.
+ * @exception CSSException Any CSS exception, possibly wrapping another
+ * exception.
+ */
+ public void ignorableAtRule(String atRule) throws CSSException;
+
+ /**
+ * Receive notification of an unknown rule t-rule not supported by this
+ * parser.
+ *
+ * @param prefix <code>null</code> if this is the default namespace
+ * @param uri The URI for this namespace.
+ * @exception CSSException Any CSS exception, possibly wrapping another
+ * exception.
+ */
+ public void namespaceDeclaration(String prefix, String uri)
+ throws CSSException;
+
+ /**
+ * Receive notification of a import statement in the style sheet.
+ *
+ * @param uri The URI of the imported style sheet.
+ * @param media The intended destination media for style information.
+ * @param defaultNamespaceURI The default namespace URI for the imported
+ * style sheet.
+ * @exception CSSException Any CSS exception, possibly wrapping another
+ * exception.
+ */
+ public void importStyle(String uri, SACMediaList media,
+ String defaultNamespaceURI)
+ throws CSSException;
+
+ /**
+ * Receive notification of the beginning of a media statement.
+ *
+ * The Parser will invoke this method at the beginning of every media
+ * statement in the style sheet. there will be a corresponding endMedia()
+ * event for every startElement() event.
+ *
+ * @param media The intended destination media for style information.
+ * @exception CSSException Any CSS exception, possibly wrapping another
+ * exception.
+ */
+ public void startMedia(SACMediaList media) throws CSSException;
+
+ /**
+ * Receive notification of the end of a media statement.
+ *
+ * @param media The intended destination media for style information.
+ * @exception CSSException Any CSS exception, possibly wrapping another
+ * exception.
+ */
+ public void endMedia(SACMediaList media) throws CSSException;
+
+ /**
+ * Receive notification of the beginning of a page statement.
+ *
+ * The Parser will invoke this method at the beginning of every page
+ * statement in the style sheet. there will be a corresponding endPage()
+ * event for every startPage() event.
+ *
+ * @param name the name of the page (if any, null otherwise)
+ * @param pseudo_page the pseudo page (if any, null otherwise)
+ * @exception CSSException Any CSS exception, possibly wrapping another
+ * exception.
+ */
+ public void startPage(String name, String pseudo_page) throws CSSException;
+
+ /**
+ * Receive notification of the end of a media statement.
+ *
+ * @param name the name of the page (if any, null otherwise)
+ * @param pseudo_page the pseudo page (if any, null otherwise)
+ * @exception CSSException Any CSS exception, possibly wrapping another
+ * exception.
+ */
+ public void endPage(String name, String pseudo_page) throws CSSException;
+
+ /**
+ * Receive notification of the beginning of a font face statement.
+ *
+ * The Parser will invoke this method at the beginning of every font face
+ * statement in the style sheet. there will be a corresponding endFontFace()
+ * event for every startFontFace() event.
+ *
+ * @exception CSSException Any CSS exception, possibly wrapping another
+ * exception.
+ */
+ public void startFontFace() throws CSSException;
+
+ /**
+ * Receive notification of the end of a font face statement.
+ *
+ * @exception CSSException Any CSS exception, possibly wrapping another
+ * exception.
+ */
+ public void endFontFace() throws CSSException;
+
+ /**
+ * Receive notification of the beginning of a rule statement.
+ *
+ * @param selectors All intended selectors for all declarations.
+ * @exception CSSException Any CSS exception, possibly wrapping another
+ * exception.
+ */
+ public void startSelector(SelectorList selectors) throws CSSException;
+
+ /**
+ * Receive notification of the end of a rule statement.
+ *
+ * @param selectors All intended selectors for all declarations.
+ * @exception CSSException Any CSS exception, possibly wrapping another
+ * exception.
+ */
+ public void endSelector(SelectorList selectors) throws CSSException;
+
+ /**
+ * Receive notification of a declaration.
+ *
+ * @param name the name of the property.
+ * @param value the value of the property. All whitespace are stripped.
+ * @param important is this property important ?
+ * @exception CSSException Any CSS exception, possibly wrapping another
+ * exception.
+ */
+ public void property(String name, LexicalUnit value, boolean important)
+ throws CSSException;
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/ElementSelector.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/ElementSelector.java
new file mode 100644
index 0000000..48b09cb
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/ElementSelector.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 1999 World Wide Web Consortium,
+ * (Massachusetts Institute of Technology, Institut National de
+ * Recherche en Informatique et en Automatique, Keio University). All
+ * Rights Reserved. This program is distributed under the W3C's Software
+ * Intellectual Property License. This program is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
+ *
+ * $Id: ElementSelector.java,v 1.1 2009/12/06 10:40:07 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+/**
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret
+ * @see Selector#SAC_ELEMENT_NODE_SELECTOR
+ */
+public interface ElementSelector extends SimpleSelector {
+
+ /**
+ * Returns the
+ * <a href="http://www.w3.org/TR/REC-xml-names/#dt-NSName">namespace
+ * URI</a> of this element selector.
+ * <p><code>NULL</code> if this element selector can match any namespace.</p>
+ */
+ public String getNamespaceURI();
+
+ /**
+ * Returns the
+ * <a href="http://www.w3.org/TR/REC-xml-names/#NT-LocalPart">local part</a>
+ * of the
+ * <a href="http://www.w3.org/TR/REC-xml-names/#ns-qualnames">qualified
+ * name</a> of this element.
+ * <p><code>NULL</code> if this element selector can match any element.</p>
+ * </ul>
+ */
+ public String getLocalName();
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/ErrorHandler.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/ErrorHandler.java
new file mode 100644
index 0000000..cd4ed4d
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/ErrorHandler.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 1999 World Wide Web Consortium
+ * (Massachusetts Institute of Technology, Institut National de Recherche
+ * en Informatique et en Automatique, Keio University).
+ * All Rights Reserved. http://www.w3.org/Consortium/Legal/
+ *
+ * The original version of this interface comes from SAX :
+ * http://www.megginson.com/SAX/
+ *
+ * $Id: ErrorHandler.java,v 1.1 2009/12/06 10:40:08 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+/**
+ * Basic interface for CSS error handlers.
+ *
+ * <p>If a CSS application needs to implement customized error
+ * handling, it must implement this interface and then register an
+ * instance with the CSS parser using the parser's setErrorHandler
+ * method. The parser will then report all errors and warnings
+ * through this interface.</p>
+ *
+ * <p> The parser shall use this interface instead of throwing an
+ * exception: it is up to the application whether to throw an
+ * exception for different types of errors and warnings. Note,
+ * however, that there is no requirement that the parser continue to
+ * provide useful information after a call to fatalError (in other
+ * words, a CSS driver class could catch an exception and report a
+ * fatalError).</p>
+ *
+ * <p>The HandlerBase class provides a default implementation of this
+ * interface, ignoring warnings and recoverable errors and throwing a
+ * SAXParseException for fatal errors. An application may extend
+ * that class rather than implementing the complete interface
+ * itself.</p>
+ *
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret
+ */
+public interface ErrorHandler {
+
+
+ /**
+ * Receive notification of a warning.
+ *
+ * <p>CSS parsers will use this method to report conditions that
+ * are not errors or fatal errors as defined by the XML 1.0
+ * recommendation. The default behaviour is to take no action.</p>
+ *
+ * <p>The CSS parser must continue to provide normal parsing events
+ * after invoking this method: it should still be possible for the
+ * application to process the document through to the end.</p>
+ *
+ * @param exception The warning information encapsulated in a
+ * CSS parse exception.
+ * @exception CSSException Any CSS exception, possibly
+ * wrapping another exception.
+ * @see CSSParseException
+ */
+ public void warning(CSSParseException exception) throws CSSException;
+
+ /**
+ * Receive notification of a recoverable error.
+ *
+ * <p>This corresponds to the definition of "error" in section 1.2
+ * of the W3C XML 1.0 Recommendation. For example, a validating
+ * parser would use this callback to report the violation of a
+ * validity constraint. The default behaviour is to take no
+ * action.</p>
+ *
+ * <p>The CSS parser must continue to provide normal parsing events
+ * after invoking this method: it should still be possible for the
+ * application to process the document through to the end. If the
+ * application cannot do so, then the parser should report a fatal
+ * error even if the XML 1.0 recommendation does not require it to
+ * do so.</p>
+ *
+ * @param exception The error information encapsulated in a
+ * CSS parse exception.
+ * @exception CSSException Any CSS exception, possibly
+ * wrapping another exception.
+ * @see CSSParseException
+ */
+ public void error(CSSParseException exception) throws CSSException;
+
+ /**
+ * Receive notification of a non-recoverable error.
+ *
+ * <p>This corresponds to the definition of "fatal error" in
+ * section 1.2 of the W3C XML 1.0 Recommendation. For example, a
+ * parser would use this callback to report the violation of a
+ * well-formedness constraint.</p>
+ *
+ * <p>The application must assume that the document is unusable
+ * after the parser has invoked this method, and should continue
+ * (if at all) only for the sake of collecting addition error
+ * messages: in fact, CSS parsers are free to stop reporting any
+ * other events once this method has been invoked.</p>
+ *
+ * @param exception The error information encapsulated in a
+ * CSS parse exception.
+ * @exception CSSException Any CSS exception, possibly
+ * wrapping another exception.
+ * @see CSSParseException
+ */
+ public void fatalError(CSSParseException exception) throws CSSException;
+
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/InputSource.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/InputSource.java
new file mode 100644
index 0000000..aa5148e
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/InputSource.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 1999 World Wide Web Consortium
+ * (Massachusetts Institute of Technology, Institut National de Recherche
+ * en Informatique et en Automatique, Keio University).
+ * All Rights Reserved. http://www.w3.org/Consortium/Legal/
+ *
+ * The original version of this interface comes from SAX :
+ * http://www.megginson.com/SAX/
+ *
+ * $Id: InputSource.java,v 1.1 2009/12/06 10:40:08 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+import java.io.InputStream;
+import java.io.Reader;
+
+/**
+ * A single input source for a CSS source.
+ *
+ * <p>This class allows a CSS application to encapsulate information about an
+ * input source in a single object, which may include a URI, a byte stream
+ * (possibly with a specified encoding), and/or a character stream.</p>
+ *
+ * <p>The CSS parser will use the InputSource object to determine how
+ * to read CSS input. If there is a character stream available, the
+ * parser will read that stream directly; if not, the parser will use
+ * a byte stream, if available; if neither a character stream nor a
+ * byte stream is available, the parser will attempt to open a URI
+ * connection to the resource identified by the URI.</p>
+ *
+ * <p>An InputSource object belongs to the application: the CSS parser
+ * shall never modify it in any way (it may modify a copy if
+ * necessary).</p>
+ *
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret
+ */
+public class InputSource {
+
+ private String uri;
+ private InputStream byteStream;
+ private String encoding;
+ private Reader characterStream;
+ private String title;
+ private String media;
+
+ /**
+ * Zero-argument default constructor.
+ *
+ * @see #setURI
+ * @see #setByteStream
+ * @see #setCharacterStream
+ * @see #setEncoding
+ */
+ public InputSource() {
+ }
+
+ /**
+ * Create a new input source with a URI.
+ *
+ * <p>The URI must be full resolved.</p>
+ *
+ * @param uri The URI.
+ * @see #setURI
+ * @see #setByteStream
+ * @see #setEncoding
+ * @see #setCharacterStream
+ */
+ public InputSource(String uri) {
+ setURI(uri);
+ }
+
+ /**
+ * Create a new input source with a character stream.
+ *
+ * <p>Application writers may use setURI() to provide a base
+ * for resolving relative URIs, and setPublicId to include a
+ * public identifier.</p>
+ *
+ * <p>The character stream shall not include a byte order mark.</p>
+ *
+ * @see #setURI
+ * @see #setByteStream
+ * @see #setCharacterStream
+ */
+ public InputSource(Reader characterStream) {
+ setCharacterStream(characterStream);
+ }
+
+ /**
+ * Set the URI for this input source.
+ *
+ * <p>The URI is optional if there is a byte stream or a character stream,
+ * but it is still useful to provide one, since the application can use it
+ * to resolve relative URIs and can include it in error messages and
+ * warnings (the parser will attempt to open a connection to the URI only
+ * if there is no byte stream or character stream specified).</p>
+ *
+ * <p>If the application knows the character encoding of the
+ * object pointed to by the URI, it can register
+ * the encoding using the setEncoding method.</p>
+ *
+ * <p>The URI must be fully resolved.</p>
+ *
+ * @param uri The URI as a string.
+ * @see #setEncoding
+ * @see #getURI
+ * @see Locator#getURI
+ * @see CSSParseException#getURI
+ */
+ public void setURI(String uri) {
+ this.uri = uri;
+ }
+
+ /**
+ * Get the URI for this input source.
+ *
+ * <p>The getEncoding method will return the character encoding
+ * of the object pointed to, or null if unknown.</p>
+ *
+ * <p>The URI will be fully resolved.</p>
+ *
+ * @return The URI.
+ * @see #setURI
+ * @see #getEncoding
+ */
+ public String getURI() {
+ return uri;
+ }
+
+ /**
+ * Set the byte stream for this input source.
+ *
+ * <p>The SAX parser will ignore this if there is also a character
+ * stream specified, but it will use a byte stream in preference
+ * to opening a URI connection itself.</p>
+ *
+ * <p>If the application knows the character encoding of the
+ * byte stream, it should set it with the setEncoding method.</p>
+ *
+ * @param byteStream A byte stream containing an CSS document or
+ * other entity.
+ * @see #setEncoding
+ * @see #getByteStream
+ * @see #getEncoding
+ */
+ public void setByteStream(InputStream byteStream) {
+ this.byteStream = byteStream;
+ }
+
+ /**
+ * Get the byte stream for this input source.
+ *
+ * <p>The getEncoding method will return the character
+ * encoding for this byte stream, or null if unknown.</p>
+ *
+ * @return The byte stream, or null if none was supplied.
+ * @see #getEncoding
+ * @see #setByteStream
+ */
+ public InputStream getByteStream() {
+ return byteStream;
+ }
+
+ /**
+ * Set the character encoding, if known.
+ *
+ * <p>The encoding must be a string acceptable for an
+ * CHARSET encoding declaration (see section 4.4 of the CSS
+ * recommendation Level 2).</p>
+ *
+ * <p>This method has no effect when the application provides a
+ * character stream.</p>
+ *
+ * @param encoding A string describing the character encoding.
+ * @see #setURI
+ * @see #setByteStream
+ * @see #getEncoding
+ */
+ public void setEncoding(String encoding) {
+ this.encoding = encoding;
+ }
+
+ /**
+ * Get the character encoding for a byte stream or URI.
+ *
+ * @return The encoding, or null if none was supplied.
+ * @see #setByteStream
+ * @see #getURI
+ * @see #getByteStream
+ */
+ public String getEncoding() {
+ return encoding;
+ }
+
+ /**
+ * Set the character stream for this input source.
+ *
+ * <p>If there is a character stream specified, the SAX parser
+ * will ignore any byte stream and will not attempt to open
+ * a URI connection to the URI.</p>
+ *
+ * @param characterStream The character stream containing the
+ * CSS document or other entity.
+ * @see #getCharacterStream
+ */
+ public void setCharacterStream(Reader characterStream) {
+ this.characterStream = characterStream;
+ }
+
+ /**
+ * Get the character stream for this input source.
+ *
+ * @return The character stream, or null if none was supplied.
+ * @see #setCharacterStream
+ */
+ public Reader getCharacterStream() {
+ return characterStream;
+ }
+
+ /**
+ * Set the title for this input source.
+ * @param title The advisory title. See the title attribute definition
+ * for the <a href="http://www.w3.org/TR/REC-html40/struct/links.html#edef-LINK">LINK</A>
+ * element in HTML 4.0, and the title pseudo-attribute for the XML
+ * style sheet processing instruction.
+ */
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ /**
+ * Returns the title for this input source.
+ */
+ public String getTitle() {
+ return title;
+ }
+
+ /**
+ * Set the media for this input source.
+ * @param media A comma separated list with all media.
+ */
+ public void setMedia(String media) {
+ this.media = media;
+ }
+
+ /**
+ * Returns the media associated to the input source or <code>null</code>
+ * if media are currently unknown.
+ * @return the media associated to this input source.
+ */
+ public String getMedia() {
+ if (media == null) {
+ return "all";
+ }
+ return media;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/LangCondition.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/LangCondition.java
new file mode 100644
index 0000000..0a45206
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/LangCondition.java
@@ -0,0 +1,21 @@
+/*
+ * (c) COPYRIGHT 1999 World Wide Web Consortium
+ * (Massachusetts Institute of Technology, Institut National de Recherche
+ * en Informatique et en Automatique, Keio University).
+ * All Rights Reserved. http://www.w3.org/Consortium/Legal/
+ *
+ * $Id: LangCondition.java,v 1.1 2009/12/06 10:40:08 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+/**
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret
+ * @see Condition#SAC_LANG_CONDITION
+ */
+public interface LangCondition extends Condition {
+ /**
+ * Returns the language
+ */
+ public String getLang();
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/LexicalUnit.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/LexicalUnit.java
new file mode 100644
index 0000000..28f8193
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/LexicalUnit.java
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 1999 World Wide Web Consortium
+ * (Massachusetts Institute of Technology, Institut National de Recherche
+ * en Informatique et en Automatique, Keio University).
+ * All Rights Reserved. http://www.w3.org/Consortium/Legal/
+ *
+ * $Id: LexicalUnit.java,v 1.1 2009/12/06 10:40:08 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+/**
+ * This is a lexical unit for CSS values.
+ * <p><b>Remarks</b>: Not all the following lexical units are supported (or
+ * will be supported) by CSS.
+ * <p>All examples are CSS2 compliant.
+ *
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret
+ */
+public interface LexicalUnit {
+
+ /**
+ * ,
+ */
+ public static final short SAC_OPERATOR_COMMA = 0;
+ /**
+ * +
+ */
+ public static final short SAC_OPERATOR_PLUS = 1;
+ /**
+ * -
+ */
+ public static final short SAC_OPERATOR_MINUS = 2;
+ /**
+ * *
+ */
+ public static final short SAC_OPERATOR_MULTIPLY = 3;
+ /**
+ * /
+ */
+ public static final short SAC_OPERATOR_SLASH = 4;
+ /**
+ * %
+ */
+ public static final short SAC_OPERATOR_MOD = 5;
+ /**
+ * ^
+ */
+ public static final short SAC_OPERATOR_EXP = 6;
+ /**
+ * <
+ */
+ public static final short SAC_OPERATOR_LT = 7;
+ /**
+ * >
+ */
+ public static final short SAC_OPERATOR_GT = 8;
+ /**
+ * <=
+ */
+ public static final short SAC_OPERATOR_LE = 9;
+ /**
+ * >=
+ */
+ public static final short SAC_OPERATOR_GE = 10;
+ /**
+ * ~
+ */
+ public static final short SAC_OPERATOR_TILDE = 11;
+
+ /**
+ * identifier <code>inherit</code>.
+ */
+ public static final short SAC_INHERIT = 12;
+ /**
+ * Integers.
+ * @see #getIntegerValue
+ */
+ public static final short SAC_INTEGER = 13;
+ /**
+ * reals.
+ * @see #getFloatValue
+ * @see #getDimensionUnitText
+ */
+ public static final short SAC_REAL = 14;
+ /**
+ * Relative length<code>em</code>.
+ * @see #getFloatValue
+ * @see #getDimensionUnitText
+ */
+ public static final short SAC_EM = 15;
+ /**
+ * Relative length<code>ex</code>.
+ * @see #getFloatValue
+ * @see #getDimensionUnitText
+ */
+ public static final short SAC_EX = 16;
+ /**
+ * Relative length <code>px</code>.
+ * @see #getFloatValue
+ * @see #getDimensionUnitText
+ */
+ public static final short SAC_PIXEL = 17;
+ /**
+ * Absolute length <code>in</code>.
+ * @see #getFloatValue
+ * @see #getDimensionUnitText
+ */
+ public static final short SAC_INCH = 18;
+ /**
+ * Absolute length <code>cm</code>.
+ * @see #getFloatValue
+ * @see #getDimensionUnitText
+ */
+ public static final short SAC_CENTIMETER = 19;
+ /**
+ * Absolute length <code>mm</code>.
+ * @see #getFloatValue
+ * @see #getDimensionUnitText
+ */
+ public static final short SAC_MILLIMETER = 20;
+ /**
+ * Absolute length <code>pt</code>.
+ * @see #getFloatValue
+ * @see #getDimensionUnitText
+ */
+ public static final short SAC_POINT = 21;
+ /**
+ * Absolute length <code>pc</code>.
+ * @see #getFloatValue
+ * @see #getDimensionUnitText
+ */
+ public static final short SAC_PICA = 22;
+ /**
+ * Percentage.
+ * @see #getFloatValue
+ * @see #getDimensionUnitText
+ */
+ public static final short SAC_PERCENTAGE = 23;
+ /**
+ * URI: <code>uri(...)</code>.
+ * @see #getStringValue
+ */
+ public static final short SAC_URI = 24;
+ /**
+ * function <code>counter</code>.
+ * @see #getFunctionName
+ * @see #getParameters
+ */
+ public static final short SAC_COUNTER_FUNCTION = 25;
+ /**
+ * function <code>counters</code>.
+ * @see #getFunctionName
+ * @see #getParameters
+ */
+ public static final short SAC_COUNTERS_FUNCTION = 26;
+ /**
+ * RGB Colors.
+ * <code>rgb(0, 0, 0)</code> and <code>#000</code>
+ * @see #getFunctionName
+ * @see #getParameters
+ */
+ public static final short SAC_RGBCOLOR = 27;
+ /**
+ * Angle <code>deg</code>.
+ * @see #getFloatValue
+ * @see #getDimensionUnitText
+ */
+ public static final short SAC_DEGREE = 28;
+ /**
+ * Angle <code>grad</code>.
+ * @see #getFloatValue
+ * @see #getDimensionUnitText
+ */
+ public static final short SAC_GRADIAN = 29;
+ /**
+ * Angle <code>rad</code>.
+ * @see #getFloatValue
+ * @see #getDimensionUnitText
+ */
+ public static final short SAC_RADIAN = 30;
+ /**
+ * Time <code>ms</code>.
+ * @see #getFloatValue
+ * @see #getDimensionUnitText
+ */
+ public static final short SAC_MILLISECOND = 31;
+ /**
+ * Time <code>s</code>.
+ * @see #getFloatValue
+ * @see #getDimensionUnitText
+ */
+ public static final short SAC_SECOND = 32;
+ /**
+ * Frequency <code>Hz</code>.
+ * @see #getFloatValue
+ * @see #getDimensionUnitText
+ */
+ public static final short SAC_HERTZ = 33;
+ /**
+ * Frequency <code>kHz</code>.
+ * @see #getFloatValue
+ * @see #getDimensionUnitText
+ */
+ public static final short SAC_KILOHERTZ = 34;
+
+ /**
+ * any identifier except <code>inherit</code>.
+ * @see #getStringValue
+ */
+ public static final short SAC_IDENT = 35;
+ /**
+ * A string.
+ * @see #getStringValue
+ */
+ public static final short SAC_STRING_VALUE = 36;
+ /**
+ * Attribute: <code>attr(...)</code>.
+ * @see #getStringValue
+ */
+ public static final short SAC_ATTR = 37;
+ /**
+ * function <code>rect</code>.
+ * @see #getFunctionName
+ * @see #getParameters
+ */
+ public static final short SAC_RECT_FUNCTION = 38;
+ /**
+ * A unicode range. @@TO BE DEFINED
+ */
+ public static final short SAC_UNICODERANGE = 39;
+
+ /**
+ * sub expressions
+ * <code>(a)</code> <code>(a + b)</code> <code>(normal/none)</code>
+ * @see #getSubValues
+ */
+ public static final short SAC_SUB_EXPRESSION = 40;
+
+ /**
+ * unknown function.
+ * @see #getFunctionName
+ * @see #getParameters
+ */
+ public static final short SAC_FUNCTION = 41;
+ /**
+ * unknown dimension.
+ * @see #getFloatValue
+ * @see #getDimensionUnitText
+ */
+ public static final short SAC_DIMENSION = 42;
+
+ /**
+ * An integer indicating the type of <code>LexicalUnit</code>.
+ */
+ public short getLexicalUnitType();
+
+ /**
+ * Returns the next value or <code>null</code> if any.
+ */
+ public LexicalUnit getNextLexicalUnit();
+
+ /**
+ * Returns the previous value or <code>null</code> if any.
+ */
+ public LexicalUnit getPreviousLexicalUnit();
+
+ /**
+ * Returns the integer value.
+ * @see #SAC_INTEGER
+ */
+ public int getIntegerValue();
+
+
+ /**
+ * Returns the float value.
+ * <p>If the type of <code>LexicalUnit</code> is one of SAC_DEGREE,
+ * SAC_GRADIAN, SAC_RADIAN, SAC_MILLISECOND, SAC_SECOND, SAC_HERTZ
+ * or SAC_KILOHERTZ, the value can never be negative.</p>
+ *
+ * @see #SAC_REAL
+ * @see #SAC_DIMENSION
+ * @see #SAC_EM
+ * @see #SAC_EX
+ * @see #SAC_PIXEL
+ * @see #SAC_INCH
+ * @see #SAC_CENTIMETER
+ * @see #SAC_MILLIMETER
+ * @see #SAC_POINT
+ * @see #SAC_PICA
+ * @see #SAC_PERCENTAGE
+ * @see #SAC_DEGREE
+ * @see #SAC_GRADIAN
+ * @see #SAC_RADIAN
+ * @see #SAC_MILLISECOND
+ * @see #SAC_SECOND
+ * @see #SAC_HERTZ
+ * @see #SAC_KILOHERTZ
+ */
+ public float getFloatValue();
+
+ /**
+ * Returns the string representation of the unit.
+ * <p>if this lexical unit represents a float, the dimension is an empty
+ * string.</p>
+ * @see #SAC_REAL
+ * @see #SAC_DIMENSION
+ * @see #SAC_EM
+ * @see #SAC_EX
+ * @see #SAC_PIXEL
+ * @see #SAC_INCH
+ * @see #SAC_CENTIMETER
+ * @see #SAC_MILLIMETER
+ * @see #SAC_POINT
+ * @see #SAC_PICA
+ * @see #SAC_PERCENTAGE
+ * @see #SAC_DEGREE
+ * @see #SAC_GRADIAN
+ * @see #SAC_RADIAN
+ * @see #SAC_MILLISECOND
+ * @see #SAC_SECOND
+ * @see #SAC_HERTZ
+ * @see #SAC_KILOHERTZ
+ */
+ public String getDimensionUnitText();
+
+ /**
+ * Returns the name of the function.
+ * @see #SAC_COUNTER_FUNCTION
+ * @see #SAC_COUNTERS_FUNCTION
+ * @see #SAC_RECT_FUNCTION
+ * @see #SAC_FUNCTION
+ * @see #SAC_RGBCOLOR
+ */
+ public String getFunctionName();
+
+ /**
+ * The function parameters including operators (like the comma).
+ * <code>#000</code> is converted to <code>rgb(0, 0, 0)</code>
+ * can return <code>null</code> if <code>SAC_FUNCTION</code>.
+ * @see #SAC_COUNTER_FUNCTION
+ * @see #SAC_COUNTERS_FUNCTION
+ * @see #SAC_RECT_FUNCTION
+ * @see #SAC_FUNCTION
+ * @see #SAC_RGBCOLOR
+ */
+ public LexicalUnit getParameters();
+
+ /**
+ * Returns the string value.
+ * <p>If the type is <code>SAC_URI</code>, the return value doesn't contain
+ * <code>uri(....)</code> or quotes.
+ * <p>If the type is <code>SAC_ATTR</code>, the return value doesn't contain
+ * <code>attr(....)</code>.
+ *
+ * @see #SAC_URI
+ * @see #SAC_ATTR
+ * @see #SAC_IDENT
+ * @see #SAC_STRING_VALUE
+ * @see #SAC_UNICODERANGE @@TO BE DEFINED
+ */
+ public String getStringValue();
+
+ /**
+ * Returns a list of values inside the sub expression.
+ * @see #SAC_SUB_EXPRESSION
+ */
+ public LexicalUnit getSubValues();
+
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/Locator.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/Locator.java
new file mode 100644
index 0000000..15b0bed
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/Locator.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 1999 World Wide Web Consortium
+ * (Massachusetts Institute of Technology, Institut National de Recherche
+ * en Informatique et en Automatique, Keio University).
+ * All Rights Reserved. http://www.w3.org/Consortium/Legal/
+ *
+ * The original version of this interface comes from SAX :
+ * http://www.megginson.com/SAX/
+ *
+ * $Id: Locator.java,v 1.1 2009/12/06 10:40:08 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+/**
+ * Interface for associating a CSS event with a document location.
+ *
+ * <p>If a SAX parser provides location information to the SAX
+ * application, it does so by implementing this interface and then
+ * passing an instance to the application using the document
+ * handler's setDocumentLocator method. The application can use the
+ * object to obtain the location of any other document handler event
+ * in the CSS source document.</p>
+ *
+ * <p>Note that the results returned by the object will be valid only
+ * during the scope of each document handler method: the application
+ * will receive unpredictable results if it attempts to use the
+ * locator at any other time.</p>
+ *
+ * <p>CSS parsers are not required to supply a locator, but they are
+ * very strong encouraged to do so. If the parser supplies a
+ * locator, it must do so before reporting any other document events.
+ * If no locator has been set by the time the application receives
+ * the startDocument event, the application should assume that a
+ * locator is not available.</p>
+ *
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret
+ */
+public interface Locator {
+
+ /**
+ * Return the URI for the current document event.
+ *
+ * <p>The parser must resolve the URI fully before passing it to the
+ * application.</p>
+ *
+ * @return A string containing the URI, or null
+ * if none is available.
+ */
+ public String getURI();
+
+ /**
+ * Return the line number where the current document event ends.
+ * Note that this is the line position of the first character
+ * after the text associated with the document event.
+ * @return The line number, or -1 if none is available.
+ * @see #getColumnNumber
+ */
+ public int getLineNumber();
+
+ /**
+ * Return the column number where the current document event ends.
+ * Note that this is the column number of the first
+ * character after the text associated with the document
+ * event. The first column in a line is position 1.
+ * @return The column number, or -1 if none is available.
+ * @see #getLineNumber
+ */
+ public int getColumnNumber();
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/NegativeCondition.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/NegativeCondition.java
new file mode 100644
index 0000000..c4c3e50
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/NegativeCondition.java
@@ -0,0 +1,22 @@
+/*
+ * (c) COPYRIGHT 1999 World Wide Web Consortium
+ * (Massachusetts Institute of Technology, Institut National de Recherche
+ * en Informatique et en Automatique, Keio University).
+ * All Rights Reserved. http://www.w3.org/Consortium/Legal/
+ *
+ * $Id: NegativeCondition.java,v 1.1 2009/12/06 10:40:08 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+/**
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret
+ * @see Condition#SAC_NEGATIVE_CONDITION
+ */
+public interface NegativeCondition extends Condition {
+
+ /**
+ * Returns the condition.
+ */
+ public Condition getCondition();
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/NegativeSelector.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/NegativeSelector.java
new file mode 100644
index 0000000..742b059
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/NegativeSelector.java
@@ -0,0 +1,22 @@
+/*
+ * (c) COPYRIGHT 1999 World Wide Web Consortium
+ * (Massachusetts Institute of Technology, Institut National de Recherche
+ * en Informatique et en Automatique, Keio University).
+ * All Rights Reserved. http://www.w3.org/Consortium/Legal/
+ *
+ * $Id: NegativeSelector.java,v 1.1 2009/12/06 10:40:08 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+/**
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret
+ * @see Selector#SAC_NEGATIVE_SELECTOR
+ */
+public interface NegativeSelector extends SimpleSelector {
+
+ /**
+ * Returns the simple selector.
+ */
+ public SimpleSelector getSimpleSelector();
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/Parser.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/Parser.java
new file mode 100644
index 0000000..c3dbec1
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/Parser.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 1999 World Wide Web Consortium
+ * (Massachusetts Institute of Technology, Institut National de Recherche
+ * en Informatique et en Automatique, Keio University).
+ * All Rights Reserved. http://www.w3.org/Consortium/Legal/
+ *
+ * The original version of this interface comes from SAX :
+ * http://www.megginson.com/SAX/
+ *
+ * $Id: Parser.java,v 1.1 2009/12/06 10:40:08 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+import java.io.IOException;
+import java.util.Locale;
+
+/**
+ * Basic interface for CSS (Simple API for CSS) parsers.
+ *
+ * <p>All CSS parsers must implement this basic interface: it allows
+ * applications to register handlers for different types of events
+ * and to initiate a parse from a URI, or a character stream.</p>
+ *
+ * <p>All CSS parsers must also implement a zero-argument constructor
+ * (though other constructors are also allowed).</p>
+ *
+ * <p>CSS parsers are reusable but not re-entrant: the application
+ * may reuse a parser object (possibly with a different input source)
+ * once the first parse has completed successfully, but it may not
+ * invoke the parse() methods recursively within a parse.</p>
+ *
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret
+ * @see DocumentHandler
+ * @see ErrorHandler
+ * @see InputSource
+ */
+public interface Parser {
+
+ /**
+ * Allow an application to request a locale for errors and warnings.
+ *
+ * <p>CSS parsers are not required to provide localisation for errors
+ * and warnings; if they cannot support the requested locale,
+ * however, they must throw a CSS exception. Applications may
+ * not request a locale change in the middle of a parse.</p>
+ *
+ * @param locale A Java Locale object.
+ * @exception CSSException Throws an exception
+ * (using the previous or default locale) if the
+ * requested locale is not supported.
+ * @see CSSException
+ * @see CSSParseException
+ */
+ public void setLocale(Locale locale) throws CSSException;
+
+ /**
+ * Allow an application to register a document event handler.
+ *
+ * <p>If the application does not register a document handler, all
+ * document events reported by the CSS parser will be silently
+ * ignored (this is the default behaviour implemented by
+ * HandlerBase).</p>
+ *
+ * <p>Applications may register a new or different handler in the
+ * middle of a parse, and the CSS parser must begin using the new
+ * handler immediately.</p>
+ *
+ * @param handler The document handler.
+ * @see DocumentHandler
+ */
+ public void setDocumentHandler(DocumentHandler handler);
+
+ public void setSelectorFactory(SelectorFactory selectorFactory);
+ public void setConditionFactory(ConditionFactory conditionFactory);
+
+ /**
+ * Allow an application to register an error event handler.
+ *
+ * <p>If the application does not register an error event handler,
+ * all error events reported by the CSS parser will be silently
+ * ignored, except for fatalError, which will throw a CSSException
+ * (this is the default behaviour implemented by HandlerBase).</p>
+ *
+ * <p>Applications may register a new or different handler in the
+ * middle of a parse, and the CSS parser must begin using the new
+ * handler immediately.</p>
+ *
+ * @param handler The error handler.
+ * @see ErrorHandler
+ * @see CSSException
+ */
+ public void setErrorHandler(ErrorHandler handler);
+
+ /**
+ * Parse a CSS document.
+ *
+ * <p>The application can use this method to instruct the CSS parser
+ * to begin parsing an CSS document from any valid input
+ * source (a character stream, a byte stream, or a URI).</p>
+ *
+ * <p>Applications may not invoke this method while a parse is in
+ * progress (they should create a new Parser instead for each
+ * additional CSS document). Once a parse is complete, an
+ * application may reuse the same Parser object, possibly with a
+ * different input source.</p>
+ *
+ * @param source The input source for the top-level of the
+ * CSS document.
+ * @exception CSSException Any CSS exception, possibly
+ * wrapping another exception.
+ * @exception java.io.IOException An IO exception from the parser,
+ * possibly from a byte stream or character stream
+ * supplied by the application.
+ * @see InputSource
+ * @see #parseStyleSheet(java.lang.String)
+ * @see #setDocumentHandler
+ * @see #setErrorHandler
+ */
+ public void parseStyleSheet(InputSource source)
+ throws CSSException, IOException;
+
+
+ /**
+ * Parse a CSS document from a URI.
+ *
+ * <p>This method is a shortcut for the common case of reading a document
+ * from a URI. It is the exact equivalent of the following:</p>
+ *
+ * <pre>
+ * parse(new InputSource(uri));
+ * </pre>
+ *
+ * <p>The URI must be fully resolved by the application before it is passed
+ * to the parser.</p>
+ *
+ * @param uri The URI.
+ * @exception CSSException Any CSS exception, possibly
+ * wrapping another exception.
+ * @exception java.io.IOException An IO exception from the parser,
+ * possibly from a byte stream or character stream
+ * supplied by the application.
+ * @see #parseStyleSheet(InputSource)
+ */
+ public void parseStyleSheet(String uri) throws CSSException, IOException;
+
+ /**
+ * Parse a CSS style declaration (without '{' and '}').
+ *
+ * @param source The source of the style sheet.
+ * @exception CSSException Any CSS exception, possibly
+ * wrapping another exception.
+ * @exception java.io.IOException An IO exception from the parser,
+ * possibly from a byte stream or character stream
+ * supplied by the application.
+ */
+ public void parseStyleDeclaration(InputSource source)
+ throws CSSException, IOException;
+
+
+ /**
+ * Parse a CSS rule.
+ *
+ * @exception CSSException Any CSS exception, possibly
+ * wrapping another exception.
+ * @exception java.io.IOException An IO exception from the parser,
+ * possibly from a byte stream or character stream
+ * supplied by the application.
+ */
+ public void parseRule(InputSource source) throws CSSException, IOException;
+
+ /**
+ * Returns a string about which CSS language is supported by this
+ * parser. For CSS Level 1, it returns "CSS1", for CSS Level 2, it returns
+ * "CSS2". For CSS Level 3, it returns "CSS3", etc. Note that a "CSSx"
+ * parser can return lexical unit other than those allowed by CSS Level x
+ * but this usage is not recommended.
+ */
+ public String getParserVersion();
+
+ /**
+ * Parse a comma separated list of selectors.
+ *
+ *
+ * @exception CSSException Any CSS exception, possibly
+ * wrapping another exception.
+ * @exception java.io.IOException An IO exception from the parser,
+ * possibly from a byte stream or character stream
+ * supplied by the application.
+ */
+ public SelectorList parseSelectors(InputSource source)
+ throws CSSException, IOException;
+
+
+ /**
+ * Parse a CSS property value.
+ *
+ *
+ * @exception CSSException Any CSS exception, possibly
+ * wrapping another exception.
+ * @exception java.io.IOException An IO exception from the parser,
+ * possibly from a byte stream or character stream
+ * supplied by the application.
+ */
+ public LexicalUnit parsePropertyValue(InputSource source)
+ throws CSSException, IOException;
+
+
+ /**
+ * Parse a CSS priority value (e.g. "!important").
+ *
+ *
+ * @exception CSSException Any CSS exception, possibly
+ * wrapping another exception.
+ * @exception java.io.IOException An IO exception from the parser,
+ * possibly from a byte stream or character stream
+ * supplied by the application.
+ */
+ public boolean parsePriority(InputSource source)
+ throws CSSException, IOException;
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/PositionalCondition.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/PositionalCondition.java
new file mode 100644
index 0000000..f8dd8c2
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/PositionalCondition.java
@@ -0,0 +1,36 @@
+/*
+ * (c) COPYRIGHT 1999 World Wide Web Consortium
+ * (Massachusetts Institute of Technology, Institut National de Recherche
+ * en Informatique et en Automatique, Keio University).
+ * All Rights Reserved. http://www.w3.org/Consortium/Legal/
+ *
+ * $Id: PositionalCondition.java,v 1.1 2009/12/06 10:40:07 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+/**
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret
+ * @see Condition#SAC_POSITIONAL_CONDITION
+ */
+public interface PositionalCondition extends Condition {
+
+ /**
+ * Returns the position in the tree.
+ * <p>A negative value means from the end of the child node list.
+ * <p>The child node list begins at 0.
+ */
+ public int getPosition();
+
+ /**
+ * <code>true</code> if the child node list only shows nodes of the same
+ * type of the selector (only elements, only PIS, ...)
+ */
+ public boolean getTypeNode();
+
+ /**
+ * <code>true</code> if the node should have the same node type (for
+ * element, same namespaceURI and same localName).
+ */
+ public boolean getType();
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/ProcessingInstructionSelector.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/ProcessingInstructionSelector.java
new file mode 100644
index 0000000..1604d0c
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/ProcessingInstructionSelector.java
@@ -0,0 +1,31 @@
+/*
+ * (c) COPYRIGHT 1999 World Wide Web Consortium
+ * (Massachusetts Institute of Technology, Institut National de Recherche
+ * en Informatique et en Automatique, Keio University).
+ * All Rights Reserved. http://www.w3.org/Consortium/Legal/
+ *
+ * $Id: ProcessingInstructionSelector.java,v 1.1 2009/12/06 10:40:07 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+/**
+ * This simple matches a
+ * <a href="http://www.w3.org/TR/REC-xml#sec-pi">processing instruction</a>.
+ *
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret
+ * @see Selector#SAC_PROCESSING_INSTRUCTION_NODE_SELECTOR
+ */
+public interface ProcessingInstructionSelector extends SimpleSelector {
+
+ /**
+ * Returns the <a href="http://www.w3.org/TR/REC-xml#NT-PITarget">target</a>
+ * of the processing instruction.
+ */
+ public String getTarget();
+
+ /**
+ * Returns the character data.
+ */
+ public String getData();
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/SACMediaList.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/SACMediaList.java
new file mode 100644
index 0000000..72db2f7
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/SACMediaList.java
@@ -0,0 +1,27 @@
+/*
+ * (c) COPYRIGHT 1999 World Wide Web Consortium
+ * (Massachusetts Institute of Technology, Institut National de Recherche
+ * en Informatique et en Automatique, Keio University).
+ * All Rights Reserved. http://www.w3.org/Consortium/Legal/
+ *
+ * $Id: SACMediaList.java,v 1.1 2009/12/06 10:40:08 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+/**
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret
+ */
+public interface SACMediaList {
+
+ /**
+ * Returns the length of this media list
+ */
+ public int getLength();
+
+ /**
+ * Returns the medium at the specified index, or <code>null</code> if this
+ * is not a valid index.
+ */
+ public String item(int index);
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/Selector.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/Selector.java
new file mode 100644
index 0000000..5ca82d5
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/Selector.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 1999 World Wide Web Consortium,
+ * (Massachusetts Institute of Technology, Institut National de
+ * Recherche en Informatique et en Automatique, Keio University). All
+ * Rights Reserved. This program is distributed under the W3C's Software
+ * Intellectual Property License. This program is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
+ *
+ * $Id: Selector.java,v 1.1 2009/12/06 10:40:08 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+/**
+ * This interface defines a selector.
+ * <p><b>Remarks</b>: Not all the following selectors are supported (or will be
+ * supported) by CSS.
+ * <p>All examples are CSS2 compliant.
+ *
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret
+ */
+public interface Selector {
+
+ /* simple selectors */
+
+ /**
+ * This is a conditional selector.
+ * example:
+ * <pre class="example">
+ * simple[role="private"]
+ * .part1
+ * H1#myId
+ * P:lang(fr).p1
+ * </pre>
+ *
+ * @see ConditionalSelector
+ */
+ public static final short SAC_CONDITIONAL_SELECTOR = 0;
+
+ /**
+ * This selector matches any node.
+ * @see SimpleSelector
+ */
+ public static final short SAC_ANY_NODE_SELECTOR = 1;
+
+ /**
+ * This selector matches the root node.
+ * @see SimpleSelector
+ */
+ public static final short SAC_ROOT_NODE_SELECTOR = 2;
+
+ /**
+ * This selector matches only node that are different from a specified one.
+ * @see NegativeSelector
+ */
+ public static final short SAC_NEGATIVE_SELECTOR = 3;
+
+ /**
+ * This selector matches only element node.
+ * example:
+ * <pre class="example">
+ * H1
+ * animate
+ * </pre>
+ * @see ElementSelector
+ */
+ public static final short SAC_ELEMENT_NODE_SELECTOR = 4;
+
+ /**
+ * This selector matches only text node.
+ * @see CharacterDataSelector
+ */
+ public static final short SAC_TEXT_NODE_SELECTOR = 5;
+
+ /**
+ * This selector matches only cdata node.
+ * @see CharacterDataSelector
+ */
+ public static final short SAC_CDATA_SECTION_NODE_SELECTOR = 6;
+
+ /**
+ * This selector matches only processing instruction node.
+ * @see ProcessingInstructionSelector
+ */
+ public static final short SAC_PROCESSING_INSTRUCTION_NODE_SELECTOR = 7;
+
+ /**
+ * This selector matches only comment node.
+ * @see CharacterDataSelector
+ */
+ public static final short SAC_COMMENT_NODE_SELECTOR = 8;
+ /**
+ * This selector matches the 'first line' pseudo element.
+ * example:
+ * <pre class="example">
+ * :first-line
+ * </pre>
+ * @see ElementSelector
+ */
+ public static final short SAC_PSEUDO_ELEMENT_SELECTOR = 9;
+
+ /* combinator selectors */
+
+ /**
+ * This selector matches an arbitrary descendant of some ancestor element.
+ * example:
+ * <pre class="example">
+ * E F
+ * </pre>
+ * @see DescendantSelector
+ */
+ public static final short SAC_DESCENDANT_SELECTOR = 10;
+
+ /**
+ * This selector matches a childhood relationship between two elements.
+ * example:
+ * <pre class="example">
+ * E > F
+ * </pre>
+ * @see DescendantSelector
+ */
+ public static final short SAC_CHILD_SELECTOR = 11;
+ /**
+ * This selector matches two selectors who shared the same parent in the
+ * document tree and the element represented by the first sequence
+ * immediately precedes the element represented by the second one.
+ * example:
+ * <pre class="example">
+ * E + F
+ * </pre>
+ * @see SiblingSelector
+ */
+ public static final short SAC_DIRECT_ADJACENT_SELECTOR = 12;
+
+ /**
+ * An integer indicating the type of <code>Selector</code>
+ */
+ public short getSelectorType();
+
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/SelectorFactory.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/SelectorFactory.java
new file mode 100644
index 0000000..fa2e713
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/SelectorFactory.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 1999 World Wide Web Consortium,
+ * (Massachusetts Institute of Technology, Institut National de
+ * Recherche en Informatique et en Automatique, Keio University). All
+ * Rights Reserved. This program is distributed under the W3C's Software
+ * Intellectual Property License. This program is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
+ *
+ * $Id: SelectorFactory.java,v 1.1 2009/12/06 10:40:08 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+/**
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret
+ * @see org.w3c.css.sac.Selector
+ */
+public interface SelectorFactory {
+
+ /**
+ * Creates a conditional selector.
+ *
+ * @param selector a selector.
+ * @param condition a condition
+ * @return the conditional selector.
+ * @exception CSSException If this selector is not supported.
+ */
+ ConditionalSelector createConditionalSelector(SimpleSelector selector,
+ Condition condition)
+ throws CSSException;
+
+ /**
+ * Creates an any node selector.
+ *
+ * @return the any node selector.
+ * @exception CSSException If this selector is not supported.
+ */
+ SimpleSelector createAnyNodeSelector() throws CSSException;
+
+ /**
+ * Creates an root node selector.
+ *
+ * @return the root node selector.
+ * @exception CSSException If this selector is not supported.
+ */
+ SimpleSelector createRootNodeSelector() throws CSSException;
+
+ /**
+ * Creates an negative selector.
+ *
+ * @param selector a selector.
+ * @return the negative selector.
+ * @exception CSSException If this selector is not supported.
+ */
+ NegativeSelector createNegativeSelector(SimpleSelector selector)
+ throws CSSException;
+
+ /**
+ * Creates an element selector.
+ *
+ * @param namespaceURI the <a href="http://www.w3.org/TR/REC-xml-names/#dt-NSName">namespace
+ * URI</a> of the element selector.
+ * @param tagName the <a href="http://www.w3.org/TR/REC-xml-names/#NT-LocalPart">local
+ * part</a> of the element name. <code>NULL</code> if this element
+ * selector can match any element.</p>
+ * @return the element selector
+ * @exception CSSException If this selector is not supported.
+ */
+ ElementSelector createElementSelector(String namespaceURI, String tagName)
+ throws CSSException;
+
+ /**
+ * Creates a text node selector.
+ *
+ * @param data the data
+ * @return the text node selector
+ * @exception CSSException If this selector is not supported.
+ */
+ CharacterDataSelector createTextNodeSelector(String data)
+ throws CSSException;
+
+ /**
+ * Creates a cdata section node selector.
+ *
+ * @param data the data
+ * @return the cdata section node selector
+ * @exception CSSException If this selector is not supported.
+ */
+ CharacterDataSelector createCDataSectionSelector(String data)
+ throws CSSException;
+
+ /**
+ * Creates a processing instruction node selector.
+ *
+ * @param target the target
+ * @param data the data
+ * @return the processing instruction node selector
+ * @exception CSSException If this selector is not supported.
+ */
+ ProcessingInstructionSelector
+ createProcessingInstructionSelector(String target,
+ String data)
+ throws CSSException;
+
+ /**
+ * Creates a comment node selector.
+ *
+ * @param data the data
+ * @return the comment node selector
+ * @exception CSSException If this selector is not supported.
+ */
+ CharacterDataSelector createCommentSelector(String data)
+ throws CSSException;
+
+ /**
+ * Creates a pseudo element selector.
+ *
+ * @param pseudoName the pseudo element name. <code>NULL</code> if this
+ * element selector can match any pseudo element.</p>
+ * @return the element selector
+ * @exception CSSException If this selector is not supported.
+ */
+ ElementSelector createPseudoElementSelector(String namespaceURI,
+ String pseudoName)
+ throws CSSException;
+
+ /**
+ * Creates a descendant selector.
+ *
+ * @param parent the parent selector
+ * @param descendant the descendant selector
+ * @return the combinator selector.
+ * @exception CSSException If this selector is not supported.
+ */
+ DescendantSelector createDescendantSelector(Selector parent,
+ SimpleSelector descendant)
+ throws CSSException;
+
+ /**
+ * Creates a child selector.
+ *
+ * @param parent the parent selector
+ * @param child the child selector
+ * @return the combinator selector.
+ * @exception CSSException If this selector is not supported.
+ */
+ DescendantSelector createChildSelector(Selector parent,
+ SimpleSelector child)
+ throws CSSException;
+
+ /**
+ * Creates a sibling selector.
+ *
+ * @param nodeType the type of nodes in the siblings list.
+ * @param child the child selector
+ * @param directAdjacent the direct adjacent selector
+ * @return the sibling selector with nodeType
+ * equals to org.w3c.dom.Node.ELEMENT_NODE
+ * @exception CSSException If this selector is not supported.
+ */
+ SiblingSelector createDirectAdjacentSelector(short nodeType,
+ Selector child,
+ SimpleSelector directAdjacent)
+ throws CSSException;
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/SelectorList.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/SelectorList.java
new file mode 100644
index 0000000..bccffc0
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/SelectorList.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 1999 World Wide Web Consortium
+ * (Massachusetts Institute of Technology, Institut National de Recherche
+ * en Informatique et en Automatique, Keio University).
+ * All Rights Reserved. http://www.w3.org/Consortium/Legal/
+ *
+ * $Id: SelectorList.java,v 1.1 2009/12/06 10:40:07 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+/**
+ * The SelectorList interface provides the abstraction of an ordered collection
+ * of selectors, without defining or constraining how this collection is
+ * implemented.
+ *
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret
+ */
+public interface SelectorList {
+
+ /**
+ * Returns the length of this selector list
+ */
+ public int getLength();
+
+ /**
+ * Returns the selector at the specified index, or <code>null</code> if this
+ * is not a valid index.
+ */
+ public Selector item(int index);
+}
+
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/SiblingSelector.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/SiblingSelector.java
new file mode 100644
index 0000000..db4c955
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/SiblingSelector.java
@@ -0,0 +1,36 @@
+/*
+ * (c) COPYRIGHT 1999 World Wide Web Consortium
+ * (Massachusetts Institute of Technology, Institut National de Recherche
+ * en Informatique et en Automatique, Keio University).
+ * All Rights Reserved. http://www.w3.org/Consortium/Legal/
+ *
+ * $Id: SiblingSelector.java,v 1.1 2009/12/06 10:40:08 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+/**
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret
+ * @see Selector#SAC_DIRECT_ADJACENT_SELECTOR
+ */
+public interface SiblingSelector extends Selector {
+
+ public static final short ANY_NODE = 201;
+
+ /**
+ * The node type to considered in the siblings list.
+ * All DOM node types are supported. In order to support the "any" node
+ * type, the code ANY_NODE is added to the DOM node types.
+ */
+ public short getNodeType();
+
+ /**
+ * Returns the first selector.
+ */
+ public Selector getSelector();
+
+ /*
+ * Returns the second selector.
+ */
+ public SimpleSelector getSiblingSelector();
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/SimpleSelector.java b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/SimpleSelector.java
new file mode 100644
index 0000000..227caf3
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/css/org/w3c/css/sac/SimpleSelector.java
@@ -0,0 +1,21 @@
+/*
+ * (c) COPYRIGHT 1999 World Wide Web Consortium
+ * (Massachusetts Institute of Technology, Institut National de Recherche
+ * en Informatique et en Automatique, Keio University).
+ * All Rights Reserved. http://www.w3.org/Consortium/Legal/
+ *
+ * $Id: SimpleSelector.java,v 1.1 2009/12/06 10:40:07 rsternber Exp $
+ */
+package org.w3c.css.sac;
+
+/**
+ * This interface is only for constraints on selectors.
+ *
+ * <p>A <code>ConditionalSelector</code> can only accept a simple selector or a
+ * negative selector.</p>
+ *
+ * @version $Revision: 1.1 $
+ * @author Philippe Le Hegaret */
+public interface SimpleSelector extends Selector {
+ // empty
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/icons/delete_obj.gif b/bundles/org.eclipse.rap.themeeditor/icons/delete_obj.gif
new file mode 100644
index 0000000..b6922ac
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/icons/delete_obj.gif
Binary files differ
diff --git a/bundles/org.eclipse.rap.themeeditor/icons/error_obj.gif b/bundles/org.eclipse.rap.themeeditor/icons/error_obj.gif
new file mode 100644
index 0000000..0bc6068
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/icons/error_obj.gif
Binary files differ
diff --git a/bundles/org.eclipse.rap.themeeditor/icons/field_private_obj.gif b/bundles/org.eclipse.rap.themeeditor/icons/field_private_obj.gif
new file mode 100644
index 0000000..1fe064e
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/icons/field_private_obj.gif
Binary files differ
diff --git a/bundles/org.eclipse.rap.themeeditor/icons/file_obj.gif b/bundles/org.eclipse.rap.themeeditor/icons/file_obj.gif
new file mode 100644
index 0000000..061161a
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/icons/file_obj.gif
Binary files differ
diff --git a/bundles/org.eclipse.rap.themeeditor/icons/font.gif b/bundles/org.eclipse.rap.themeeditor/icons/font.gif
new file mode 100644
index 0000000..8d187db
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/icons/font.gif
Binary files differ
diff --git a/bundles/org.eclipse.rap.themeeditor/icons/help.gif b/bundles/org.eclipse.rap.themeeditor/icons/help.gif
new file mode 100644
index 0000000..9d70301
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/icons/help.gif
Binary files differ
diff --git a/bundles/org.eclipse.rap.themeeditor/icons/image_obj.gif b/bundles/org.eclipse.rap.themeeditor/icons/image_obj.gif
new file mode 100644
index 0000000..830be0e
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/icons/image_obj.gif
Binary files differ
diff --git a/bundles/org.eclipse.rap.themeeditor/icons/no-image.gif b/bundles/org.eclipse.rap.themeeditor/icons/no-image.gif
new file mode 100644
index 0000000..18c5200
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/icons/no-image.gif
Binary files differ
diff --git a/bundles/org.eclipse.rap.themeeditor/icons/pageedit.gif b/bundles/org.eclipse.rap.themeeditor/icons/pageedit.gif
new file mode 100644
index 0000000..9f84990
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/icons/pageedit.gif
Binary files differ
diff --git a/bundles/org.eclipse.rap.themeeditor/icons/public_co.gif b/bundles/org.eclipse.rap.themeeditor/icons/public_co.gif
new file mode 100644
index 0000000..a9af5d5
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/icons/public_co.gif
Binary files differ
diff --git a/bundles/org.eclipse.rap.themeeditor/icons/swt_launcher.gif b/bundles/org.eclipse.rap.themeeditor/icons/swt_launcher.gif
new file mode 100644
index 0000000..3c4c7c8
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/icons/swt_launcher.gif
Binary files differ
diff --git a/bundles/org.eclipse.rap.themeeditor/icons/transparent-banner.gif b/bundles/org.eclipse.rap.themeeditor/icons/transparent-banner.gif
new file mode 100644
index 0000000..c8f0c29
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/icons/transparent-banner.gif
Binary files differ
diff --git a/bundles/org.eclipse.rap.themeeditor/icons/transparent-large.gif b/bundles/org.eclipse.rap.themeeditor/icons/transparent-large.gif
new file mode 100644
index 0000000..4d59c33
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/icons/transparent-large.gif
Binary files differ
diff --git a/bundles/org.eclipse.rap.themeeditor/icons/transparent-small.gif b/bundles/org.eclipse.rap.themeeditor/icons/transparent-small.gif
new file mode 100644
index 0000000..188d532
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/icons/transparent-small.gif
Binary files differ
diff --git a/bundles/org.eclipse.rap.themeeditor/icons/warning_obj.gif b/bundles/org.eclipse.rap.themeeditor/icons/warning_obj.gif
new file mode 100644
index 0000000..2b2e50f
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/icons/warning_obj.gif
Binary files differ
diff --git a/bundles/org.eclipse.rap.themeeditor/plugin.xml b/bundles/org.eclipse.rap.themeeditor/plugin.xml
new file mode 100644
index 0000000..e10d156
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/plugin.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+
+ <extension
+ point="org.eclipse.ui.editors">
+ <editor
+ class="org.eclipse.rap.themeeditor.editor.source.CSSSourceEditor"
+ filenames="theme.css"
+ icon="icons/file_obj.gif"
+ id="org.eclipse.rap.themeeditor.editor.ThemeEditor"
+ name="RAP Theme Editor">
+ </editor>
+ </extension>
+
+ <extension
+ point="org.eclipse.core.filebuffers.documentSetup">
+ <participant
+ class="org.eclipse.rap.themeeditor.editor.source.CSSDocumentSetupParticipant"
+ extensions="css">
+ </participant>
+ </extension>
+</plugin>
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/ColorRegistry.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/ColorRegistry.java
new file mode 100644
index 0000000..8fc6da3
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/ColorRegistry.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * Manager for holding instance of SWT Color object, and has the responsibility
+ * to dispose them when method dispose() is called.
+ */
+public class ColorRegistry {
+
+ private Display display;
+ private Map colorMap;
+
+ public ColorRegistry( final Display display ) {
+ colorMap = new HashMap();
+ this.display = display;
+ }
+
+ public Color getColor( final RGB rgb ) {
+ Color result = ( Color )colorMap.get( rgb );
+ if( result == null ) {
+ result = new Color( display, rgb );
+ colorMap.put( rgb, result );
+ }
+ return result;
+ }
+
+ public void dispose() {
+ Iterator iterator = colorMap.values().iterator();
+ while( iterator.hasNext() ) {
+ Color color = ( Color )iterator.next();
+ color.dispose();
+ }
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/SupportedKeywords.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/SupportedKeywords.java
new file mode 100644
index 0000000..2a7468d
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/SupportedKeywords.java
@@ -0,0 +1,208 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * All keywords that are supported by RAP, including selectors, styles, states
+ * and properties. Used for content assists and problem markers in source tab.
+ */
+public class SupportedKeywords {
+
+ public static final int UNDEFINED = 0;
+ public static final int SELECTOR_TYPE = 1;
+ public static final int PROPERTY_TYPE = 2;
+ public static final int STYLE_TYPE = 3;
+ public static final int STATE_TYPE = 4;
+ public static final String[] SELECTORS = {
+ "Button",
+ "Combo",
+ "CoolBar",
+ "CoolItem",
+ "CTabFolder",
+ "CTabItem",
+ "Group",
+ "Group-Frame",
+ "Group-Label",
+ "Label",
+ "Link",
+ "Link-Hyperlink",
+ "List",
+ "List-Item",
+ "Menu",
+ "MenuItem",
+ "ProgressBar",
+ "ProgressBar-Indicator",
+ "Shell",
+ "Shell-Titlebar",
+ "Shell-MinButton",
+ "Shell-MaxButton",
+ "Shell-CloseButton",
+ "Spinner",
+ "TabFolder",
+ "TabItem",
+ "Table",
+ "TableItem",
+ "TableColumn",
+ "TableColumn-SortIndicator",
+ "Table-GridLine",
+ "Table-Checkbox",
+ "Text",
+ "ToolBar",
+ "ToolItem",
+ "ToolTip",
+ "Tree",
+ "TreeItem",
+ "TreeColumn",
+ "TreeColumn-SortIndicator",
+ "*"
+ };
+ public static final String[] STYLES = {
+ "PUSH", "TOGGLE", "CHECK", "RADIO", "BORDER", "FLAT", "SINGLE", "MULTI"
+ };
+ public static final String[] STATES = {
+ "hover",
+ "pressed",
+ "up",
+ "down",
+ "disabled",
+ "selected",
+ "inactive",
+ "maximized",
+ "minimized"
+ };
+ public static final String[] PROPERTIES = {
+ "background-color",
+ "background-gradient-color",
+ "background-image",
+ "border",
+ "color",
+ "font",
+ "height",
+ "padding",
+ "margin",
+ "spacing",
+ "width",
+ "rwt-darkshadow-color",
+ "rwt-highlight-color",
+ "rwt-lightshadow-color",
+ "rwt-selectionmarker-color",
+ "rwt-shadow-color",
+ "rwt-thinborder-color"
+ };
+ public static final String[] COLOR_PROPERTIES = {
+ "background-color",
+ "background-gradient-color",
+ "border",
+ "color",
+ "rwt-darkshadow-color",
+ "rwt-highlight-color",
+ "rwt-lightshadow-color",
+ "rwt-selectionmarker-color",
+ "rwt-shadow-color",
+ "rwt-thinborder-color"
+ };
+ private static final String STARTS_WITH = "rwt";
+ private static final String ENDS_WITH = "color";
+
+ public static boolean isPropertySupported( final String name ) {
+ boolean result = false;
+ if( name.startsWith( STARTS_WITH ) && name.endsWith( ENDS_WITH ) ) {
+ result = true;
+ } else {
+ for( int i = 0; i < PROPERTIES.length; i++ ) {
+ if( name.equals( PROPERTIES[ i ] ) ) {
+ result = true;
+ }
+ }
+ }
+ return result;
+ }
+
+ public static boolean isSelectorSupported( final String selector ) {
+ boolean result = false;
+ if( selector == null ) {
+ result = true;
+ } else {
+ for( int i = 0; i < SELECTORS.length; i++ ) {
+ if( selector.equals( SELECTORS[ i ] ) ) {
+ result = true;
+ }
+ }
+ }
+ return result;
+ }
+
+ public static boolean isStyleSupported( final String style ) {
+ boolean result = false;
+ if( style == null ) {
+ result = true;
+ } else {
+ for( int i = 0; i < STYLES.length; i++ ) {
+ if( style.equals( STYLES[ i ] ) ) {
+ result = true;
+ }
+ }
+ }
+ return result;
+ }
+
+ public static boolean isStateSupported( final String state ) {
+ boolean result = false;
+ if( state == null ) {
+ result = true;
+ } else {
+ for( int i = 0; i < STATES.length; i++ ) {
+ if( state.equals( STATES[ i ] ) ) {
+ result = true;
+ }
+ }
+ }
+ return result;
+ }
+
+ public static String[] getKeywordsStartWith( final String start,
+ final int type )
+ {
+ String[] result = null;
+ String[] keywords = null;
+ switch( type ) {
+ case SELECTOR_TYPE:
+ keywords = SELECTORS;
+ break;
+ case PROPERTY_TYPE:
+ keywords = PROPERTIES;
+ break;
+ case STYLE_TYPE:
+ keywords = STYLES;
+ break;
+ case STATE_TYPE:
+ keywords = STATES;
+ break;
+ }
+ if( keywords != null && start != null ) {
+ List resultList = new ArrayList();
+ for( int i = 0; i < keywords.length; i++ ) {
+ String item = keywords[ i ];
+ if( item.toLowerCase().startsWith( start.toLowerCase() ) ) {
+ resultList.add( item );
+ }
+ }
+ result = new String[ resultList.size() ];
+ result = ( String[] )resultList.toArray( result );
+ Arrays.sort( result );
+ }
+ return result;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/ThemeEditorPlugin.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/ThemeEditorPlugin.java
new file mode 100644
index 0000000..9ff7443
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/ThemeEditorPlugin.java
@@ -0,0 +1,68 @@
+package org.eclipse.rap.themeeditor;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+public class ThemeEditorPlugin extends AbstractUIPlugin {
+
+ public static final String IMG_WARNING = "warning_obj.gif";
+ public static final String IMG_ERROR = "error_obj.gif";
+ public static final String IMG_FIELD_PRIVATE = "field_private_obj.gif";
+ public static final String IMG_PUBLIC = "public_co.gif";
+
+ public static final String PLUGIN_ID = "org.eclipse.rap.themeeditor.csseditor"; //$NON-NLS-1$
+
+ private static ThemeEditorPlugin sharedInstance;
+
+ private ColorRegistry colorRegistry;
+
+ public void start( BundleContext context ) throws Exception {
+ super.start( context );
+ sharedInstance = this;
+ }
+
+ public void stop( BundleContext context ) throws Exception {
+ sharedInstance = null;
+ super.stop( context );
+ }
+
+ public static ThemeEditorPlugin getDefault() {
+ return sharedInstance;
+ }
+
+ public ColorRegistry getColorRegistry() {
+ if( colorRegistry == null ) {
+ colorRegistry = new ColorRegistry( Display.getDefault() );
+ }
+ return colorRegistry;
+ }
+
+ public Image getImage( String key ) {
+ return getImageRegistry().get( key );
+ }
+
+
+ public static ImageDescriptor getImageDescriptor( final String path ) {
+ return imageDescriptorFromPlugin( PLUGIN_ID, path );
+ }
+
+ protected void initializeImageRegistry( final ImageRegistry registry ) {
+ registerImage( registry, IMG_WARNING, IMG_WARNING );
+ registerImage( registry, IMG_ERROR, IMG_ERROR );
+ registerImage( registry, IMG_FIELD_PRIVATE, IMG_FIELD_PRIVATE );
+ registerImage( registry, IMG_PUBLIC, IMG_PUBLIC );
+ }
+
+ private void registerImage( final ImageRegistry registry,
+ final String key,
+ final String fileName )
+ {
+ String path = "icons/" + fileName;
+ ImageDescriptor descriptor = getImageDescriptor( path );
+ registry.put( key, descriptor );
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/CSSContentOutlinePage.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/CSSContentOutlinePage.java
new file mode 100644
index 0000000..eab813d
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/CSSContentOutlinePage.java
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor.editor;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.rap.themeeditor.editor.rule.DefaultContentProvider;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.ui.texteditor.IDocumentProvider;
+import org.eclipse.ui.texteditor.ITextEditor;
+import org.eclipse.ui.views.contentoutline.ContentOutlinePage;
+
+/**
+ * Implementation of an Outline page showing StyleRules as items if the
+ * Rules-Tab is activated, or showing OutlineRegions as items if the Source-Tab
+ * is activated.
+ */
+public class CSSContentOutlinePage extends ContentOutlinePage {
+
+ protected Object[] input;
+ protected IDocumentProvider documentProvider;
+ protected ITextEditor textEditor;
+ private boolean isSetSelectionEnabled = true;
+ private int tabIndex = -1;
+ private Map listenerMap;
+
+ public CSSContentOutlinePage() {
+ super();
+ listenerMap = new HashMap();
+ }
+
+ public void createControl( final Composite parent ) {
+ super.createControl( parent );
+ TreeViewer viewer = getTreeViewer();
+ viewer.setContentProvider( new DefaultContentProvider() );
+ viewer.setLabelProvider( new ContentOutlineLabelProvider() );
+ viewer.addSelectionChangedListener( this );
+ if( input != null )
+ viewer.setInput( input );
+ }
+
+ /**
+ * Handles the SelectionChangedEvent if the Outline selection has been changed
+ * by the user, and so it calls a possibly registered listener.
+ */
+ public void selectionChanged( final SelectionChangedEvent event ) {
+ isSetSelectionEnabled = false;
+ super.selectionChanged( event );
+ int newIndex = -1;
+ Object item = null;
+ ISelection selection = event.getSelection();
+ if( !selection.isEmpty() ) {
+ item = ( ( IStructuredSelection )selection ).getFirstElement();
+ }
+ if( getTreeViewer().getTree().getSelectionCount() == 1 ) {
+ TreeItem treeItem = getTreeViewer().getTree().getSelection()[ 0 ];
+ newIndex = getTreeViewer().getTree().indexOf( treeItem );
+ }
+ IOutlineSelectionChangedListener listener = ( IOutlineSelectionChangedListener )listenerMap.get( new Integer( tabIndex ) );
+ if( listener != null ) {
+ listener.outlineSelectionChanged( newIndex, item );
+ }
+ isSetSelectionEnabled = true;
+ }
+
+ /**
+ * Forces a SelectionChangedEvent, and so it calls a possibly registered
+ * listener.
+ */
+ public void forceSelectionChanged( final int newIndex ) {
+ if( getTreeViewer() != null ) {
+ isSetSelectionEnabled = false;
+ Object item = null;
+ ISelection selection = getTreeViewer().getSelection();
+ if( !selection.isEmpty() ) {
+ item = ( ( IStructuredSelection )selection ).getFirstElement();
+ }
+ IOutlineSelectionChangedListener listener = ( IOutlineSelectionChangedListener )listenerMap.get( new Integer( tabIndex ) );
+ if( listener != null ) {
+ listener.outlineSelectionChanged( newIndex, item );
+ }
+ isSetSelectionEnabled = true;
+ }
+ }
+
+ /**
+ * Sets a new input array for the Outline.
+ */
+ public void setInput( final Object[] input, final int tabIndex ) {
+ this.input = input;
+ this.tabIndex = tabIndex;
+ update();
+ }
+
+ /**
+ * Updates the Outline. Called after the Outline input has changed.
+ */
+ private void update() {
+ TreeViewer viewer = getTreeViewer();
+ if( viewer != null ) {
+ Control control = viewer.getControl();
+ if( control != null && !control.isDisposed() ) {
+ control.setRedraw( false );
+ viewer.setInput( input );
+ viewer.expandAll();
+ control.setRedraw( true );
+ }
+ }
+ }
+
+ /**
+ * Sets the selected item in the Outline programmatically to the given index.
+ */
+ public void setSelection( final int index ) {
+ if( isSetSelectionEnabled && getTreeViewer() != null ) {
+ Tree tree = getTreeViewer().getTree();
+ if( index >= 0 && index < tree.getItemCount() ) {
+ tree.setSelection( tree.getItem( index ) );
+ tree.showSelection();
+ } else {
+ tree.deselectAll();
+ }
+ }
+ }
+
+ /**
+ * Sets a listener that will be notified of the selected item in the Outline
+ * changes.
+ */
+ public void setSelectionChangedListener( final IOutlineSelectionChangedListener listener,
+ final int tabIndex )
+ {
+ listenerMap.put( new Integer( tabIndex ), listener );
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/ContentOutlineLabelProvider.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/ContentOutlineLabelProvider.java
new file mode 100644
index 0000000..e2f8de9
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/ContentOutlineLabelProvider.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor.editor;
+
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.rap.themeeditor.ThemeEditorPlugin;
+import org.eclipse.rwt.internal.theme.css.StyleRule;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * JFace LabelProvider for elements displayed in Outline view.
+ */
+public class ContentOutlineLabelProvider extends LabelProvider {
+
+ public String getText( final Object element ) {
+ String result;
+ if( element instanceof StyleRule ) {
+ result = ( ( StyleRule )element ).getName();
+ } else {
+ result = element == null
+ ? ""
+ : element.toString();
+ }
+ return result;
+ }
+
+ public Image getImage( final Object element ) {
+ return ThemeEditorPlugin.getDefault()
+ .getImage( ThemeEditorPlugin.IMG_PUBLIC );
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/IOutlineSelectionChangedListener.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/IOutlineSelectionChangedListener.java
new file mode 100644
index 0000000..8087805
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/IOutlineSelectionChangedListener.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor.editor;
+
+/**
+ * Listener interface for GUI parts that want to be notified if the Outline
+ * selection has been changed.
+ */
+public interface IOutlineSelectionChangedListener {
+
+ public void outlineSelectionChanged( final int newIndex, final Object item );
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/rule/DefaultContentProvider.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/rule/DefaultContentProvider.java
new file mode 100644
index 0000000..b2aa13c
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/rule/DefaultContentProvider.java
@@ -0,0 +1,39 @@
+package org.eclipse.rap.themeeditor.editor.rule;
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+
+
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+
+/**
+ * A basic JFace ContentProvider with no parent element and no children
+ * elements.
+ */
+public class DefaultContentProvider extends ArrayContentProvider
+ implements ITreeContentProvider
+{
+
+ public DefaultContentProvider() {
+ }
+
+ public Object[] getChildren( final Object parentElement ) {
+ return new Object[ 0 ];
+ }
+
+ public Object getParent( final Object element ) {
+ return null;
+ }
+
+ public boolean hasChildren( final Object element ) {
+ return false;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/CSSCompletionProcessor.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/CSSCompletionProcessor.java
new file mode 100644
index 0000000..01b215c
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/CSSCompletionProcessor.java
@@ -0,0 +1,209 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor.editor.source;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.contentassist.CompletionProposal;
+import org.eclipse.jface.text.contentassist.ContextInformation;
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
+import org.eclipse.jface.text.contentassist.IContextInformation;
+import org.eclipse.jface.text.contentassist.IContextInformationValidator;
+import org.eclipse.rap.themeeditor.SupportedKeywords;
+import org.eclipse.rap.themeeditor.ThemeEditorPlugin;
+import org.eclipse.rap.themeeditor.editor.source.region.IRegionExt;
+import org.eclipse.rwt.internal.theme.ThemeDefElementWrapper;
+import org.eclipse.rwt.internal.theme.ThemeDefProperty;
+import org.eclipse.rwt.internal.theme.ThemeDefinitionProvider;
+
+public class CSSCompletionProcessor implements IContentAssistProcessor {
+
+ private CSSTokenScanner tokenScanner;
+
+ public CSSCompletionProcessor( final CSSTokenScanner tokenScanner ) {
+ this.tokenScanner = tokenScanner;
+ }
+
+ public ICompletionProposal[] computeCompletionProposals( final ITextViewer viewer,
+ final int offset )
+ {
+ IRegionExt regionExt = tokenScanner.getRegionExt( offset );
+ String currentContent = regionExt.getContent();
+ if( offset >= regionExt.getOffset()
+ && offset <= ( regionExt.getOffset() + regionExt.getLength() )
+ && ( offset - regionExt.getOffset() ) <= currentContent.length() )
+ {
+ currentContent = currentContent.substring( 0, offset
+ - regionExt.getOffset() );
+ } else {
+ return null;
+ }
+ String[] proposalStrings = SupportedKeywords.getKeywordsStartWith( currentContent.trim(),
+ regionExt.getKeywordType() );
+ if( proposalStrings == null ) {
+ return null;
+ }
+ proposalStrings = filterProposalStrings( proposalStrings, regionExt );
+ if( proposalStrings.length == 0 ) {
+ return null;
+ }
+ // just a hack to perform trimStart only, as whitespace at end must remain
+ currentContent = currentContent + '#';
+ int beginIndex = currentContent.trim().length() - 1;
+ ICompletionProposal[] result = new ICompletionProposal[ proposalStrings.length ];
+ for( int i = 0; i < proposalStrings.length; i++ ) {
+ String additionalInfo = ThemeDefinitionProvider.getDescription( regionExt,
+ proposalStrings[ i ] );
+ IContextInformation info = new ContextInformation( proposalStrings[ i ],
+ proposalStrings[ i ] );
+ result[ i ] = new CompletionProposal( proposalStrings[ i ],
+ offset - beginIndex,
+ beginIndex,
+ proposalStrings[ i ].length(),
+ ThemeEditorPlugin.getDefault()
+ .getImage( ThemeEditorPlugin.IMG_FIELD_PRIVATE ),
+ proposalStrings[ i ],
+ info,
+ additionalInfo );
+ }
+ return result;
+ }
+
+ public IContextInformation[] computeContextInformation( final ITextViewer viewer,
+ final int offset )
+ {
+ return null;
+ }
+
+ public char[] getCompletionProposalAutoActivationCharacters() {
+ return new char[]{
+ '.', ':', '['
+ };
+ }
+
+ public char[] getContextInformationAutoActivationCharacters() {
+ return null;
+ }
+
+ public IContextInformationValidator getContextInformationValidator() {
+ return null;
+ }
+
+ public String getErrorMessage() {
+ return null;
+ }
+
+ private String[] filterProposalStrings( final String[] proposalStrings,
+ final IRegionExt regionExt )
+ {
+ String[] result;
+ switch( regionExt.getKeywordType() ) {
+ case SupportedKeywords.STYLE_TYPE:
+ result = filterProposalStyles( proposalStrings, regionExt );
+ break;
+ case SupportedKeywords.STATE_TYPE:
+ result = filterProposalStates( proposalStrings, regionExt );
+ break;
+ case SupportedKeywords.PROPERTY_TYPE:
+ result = filterProposalProperties( proposalStrings, regionExt );
+ break;
+ default:
+ result = proposalStrings;
+ break;
+ }
+ return result;
+ }
+
+ private String[] filterProposalStyles( final String[] proposalStrings,
+ final IRegionExt regionExt )
+ {
+ String[] result = new String[ 0 ];
+ if( regionExt.getTokenType() == CSSTokenProvider.STYLE_TOKEN ) {
+ ThemeDefElementWrapper wrapper = ThemeDefinitionProvider.getElementWrapper( regionExt );
+ if( wrapper != null ) {
+ List resultList = new ArrayList();
+ for( int i = 0; i < proposalStrings.length; i++ ) {
+ String text = proposalStrings[ i ];
+ if( wrapper.element.styleMap.containsKey( text ) ) {
+ resultList.add( text );
+ }
+ }
+ result = new String[ resultList.size() ];
+ result = ( String[] )resultList.toArray( result );
+ }
+ }
+ return result;
+ }
+
+ private String[] filterProposalStates( final String[] proposalStrings,
+ final IRegionExt regionExt )
+ {
+ String[] result = new String[ 0 ];
+ if( regionExt.getTokenType() == CSSTokenProvider.STATE_TOKEN ) {
+ ThemeDefElementWrapper wrapper = ThemeDefinitionProvider.getElementWrapper( regionExt );
+ if( wrapper != null ) {
+ List resultList = new ArrayList();
+ for( int i = 0; i < proposalStrings.length; i++ ) {
+ String text = proposalStrings[ i ];
+ if( wrapper.element.stateMap.containsKey( text ) ) {
+ resultList.add( text );
+ }
+ }
+ result = new String[ resultList.size() ];
+ result = ( String[] )resultList.toArray( result );
+ }
+ }
+ return result;
+ }
+
+ private String[] filterProposalProperties( final String[] proposalStrings,
+ final IRegionExt regionExt )
+ {
+ String[] result = new String[ 0 ];
+ if( regionExt.getTokenType() == CSSTokenProvider.PROPERTY_TOKEN ) {
+ OutlineRegion[] regions = tokenScanner.getOutlineRegionsArray();
+ OutlineRegion outlineRegion = null;
+ for( int i = 0; i < regions.length; i++ ) {
+ OutlineRegion next = regions[ i ];
+ if( next.getOffset() <= regionExt.getOffset() ) {
+ outlineRegion = next;
+ }
+ }
+ if( outlineRegion != null ) {
+ List resultList = new ArrayList();
+ for( int i = 0; i < outlineRegion.getElements().length; i++ ) {
+ ThemeDefElementWrapper wrapper = ThemeDefinitionProvider.getElementWrapper( outlineRegion.getElements()[ i ] );
+ if( wrapper != null ) {
+ for( int j = 0; j < proposalStrings.length; j++ ) {
+ String text = proposalStrings[ j ];
+ for( int k = 0; k < wrapper.element.properties.length; k++ ) {
+ ThemeDefProperty property = wrapper.element.properties[ k ];
+ if( property.name.equals( text ) ) {
+ if( !resultList.contains( text ) ) {
+ resultList.add( text );
+ }
+ }
+ }
+ }
+ }
+ }
+ result = new String[ resultList.size() ];
+ result = ( String[] )resultList.toArray( result );
+ Arrays.sort( result );
+ }
+ }
+ return result;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/CSSDamagerRepairer.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/CSSDamagerRepairer.java
new file mode 100644
index 0000000..7690455
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/CSSDamagerRepairer.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor.editor.source;
+
+import org.eclipse.jface.text.ITypedRegion;
+import org.eclipse.jface.text.TextPresentation;
+import org.eclipse.jface.text.TypedRegion;
+import org.eclipse.jface.text.rules.DefaultDamagerRepairer;
+import org.eclipse.jface.text.rules.ITokenScanner;
+
+public class CSSDamagerRepairer extends DefaultDamagerRepairer {
+
+ public CSSDamagerRepairer( final ITokenScanner scanner ) {
+ super( scanner );
+ }
+
+ public void createPresentation( final TextPresentation presentation,
+ final ITypedRegion region )
+ {
+ ITypedRegion newRegion = new TypedRegion( 0, fDocument.getLength(), null );
+ super.createPresentation( presentation, newRegion );
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/CSSDocumentSetupParticipant.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/CSSDocumentSetupParticipant.java
new file mode 100644
index 0000000..650d7ca
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/CSSDocumentSetupParticipant.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor.editor.source;
+
+import org.eclipse.core.filebuffers.IDocumentSetupParticipant;
+
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IDocumentExtension3;
+import org.eclipse.jface.text.IDocumentPartitioner;
+import org.eclipse.jface.text.rules.FastPartitioner;
+import org.eclipse.jface.text.rules.RuleBasedPartitionScanner;
+
+public class CSSDocumentSetupParticipant implements IDocumentSetupParticipant {
+
+ public CSSDocumentSetupParticipant() {
+ }
+
+ public void setup( final IDocument document ) {
+ if( document instanceof IDocumentExtension3 ) {
+ IDocumentExtension3 extension3 = ( IDocumentExtension3 )document;
+ IDocumentPartitioner partitioner = new FastPartitioner( new RuleBasedPartitionScanner(),
+ new String[]{} );
+ extension3.setDocumentPartitioner( CSSSourceViewerConfiguration.CSS_PARTITIONING,
+ partitioner );
+ partitioner.connect( document );
+ }
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/CSSSourceEditor.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/CSSSourceEditor.java
new file mode 100644
index 0000000..920f0a7
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/CSSSourceEditor.java
@@ -0,0 +1,187 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor.editor.source;
+
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.ResourceBundle;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.DocumentEvent;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IDocumentListener;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.text.source.IVerticalRuler;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.rap.themeeditor.editor.IOutlineSelectionChangedListener;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.editors.text.TextEditor;
+import org.eclipse.ui.texteditor.ContentAssistAction;
+import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
+
+/**
+ * The general editor in the Source Tab. Providing content assists, syntax
+ * coloring and Outline contribution.
+ */
+public class CSSSourceEditor extends TextEditor
+ implements IOutlineSelectionChangedListener
+{
+
+ private CSSTokenScanner tokenScanner;
+
+ public CSSSourceEditor() {
+ super();
+// getCSSTokenScanner().setTokenChangedListener( editor );
+// outline.setSelectionChangedListener( this, ThemeEditor.SOURCE_TAB );
+ }
+
+ protected void initializeEditor() {
+ super.initializeEditor();
+ setSourceViewerConfiguration( new CSSSourceViewerConfiguration( getCSSTokenScanner() ) );
+ }
+
+ public void createPartControl( Composite parent ) {
+ super.createPartControl( parent );
+ final IDocument doc = getDocument();
+ // add listener and call setRange manually, because it isnt't called
+ // automatically from jface if backspace key is performed
+ doc.addDocumentListener( new IDocumentListener() {
+
+ public void documentAboutToBeChanged( DocumentEvent event ) {
+ ;
+ }
+
+ public void documentChanged( DocumentEvent event ) {
+ getCSSTokenScanner().setRange( doc, 0, doc.getLength() );
+ }
+ } );
+ }
+
+ protected ISourceViewer createSourceViewer( final Composite parent,
+ final IVerticalRuler ruler,
+ final int styles )
+ {
+ return super.createSourceViewer( parent, ruler, styles );
+ }
+
+ public Object[] getSelectorTokens() {
+ return getCSSTokenScanner().getOutlineRegionsArray();
+ }
+
+ /**
+ * Returns the index of a rule in the StyleSheet at a given offset position
+ * within the document.
+ */
+ private int getRuleNumber( final int offset ) {
+ int result = -1;
+ Iterator it = getCSSTokenScanner().getOutlineRegionsList().iterator();
+ while( it.hasNext() ) {
+ IRegion regionExt = ( IRegion )it.next();
+ if( regionExt.getOffset() <= offset ) {
+ result++;
+ }
+ }
+ if( result < 0 ) {
+ result = 0;
+ }
+ return result;
+ }
+
+ protected void handleCursorPositionChanged() {
+ super.handleCursorPositionChanged();
+ ISelection selection = getSelectionProvider().getSelection();
+ if( selection instanceof ITextSelection ) {
+ int offset = ( ( ITextSelection )selection ).getOffset();
+ int index = getRuleNumber( offset );
+// editor.updateOutlineSelection( index );
+ }
+ }
+
+ public void doCursorPositionChanged() {
+ handleCursorPositionChanged();
+ }
+
+ private CSSTokenScanner getCSSTokenScanner() {
+ if( tokenScanner == null ) {
+ tokenScanner = new CSSTokenScanner( this );
+ }
+ return tokenScanner;
+ }
+
+ public void dispose() {
+ tokenScanner.setTokenChangedListener( null );
+ super.dispose();
+ }
+
+ protected void createActions() {
+ super.createActions();
+ IAction action = new ContentAssistAction( getResourceBundle(),
+ "ContentAssistProposal.",
+ this );
+ action.setActionDefinitionId( ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS );
+ final String actionId = "RAP_THEME_EDITOR_CONTENT_ASSIST_PROPOSALS";
+ setAction( actionId, action );
+ markAsStateDependentAction( actionId, true );
+ }
+
+ /**
+ * Notification from the Outline when the user changed its selection.
+ */
+ public void outlineSelectionChanged( int newIndex, Object item ) {
+ if( item == null ) {
+ resetHighlightRange();
+ } else {
+ if( item instanceof OutlineRegion ) {
+ OutlineRegion region = ( OutlineRegion )item;
+ int start = region.getOffset();
+ int length = region.getLength();
+ try {
+ String regionText = getDocument().get( start, length );
+ int i = 0;
+ while( i < regionText.length()
+ && Character.isWhitespace( regionText.charAt( i ) ) )
+ {
+ i++;
+ }
+ setHighlightRange( start + i, length - i, true );
+ } catch( IllegalArgumentException exception ) {
+ resetHighlightRange();
+ } catch( BadLocationException exception ) {
+ resetHighlightRange();
+ }
+ } else {
+ resetHighlightRange();
+ }
+ }
+ }
+
+ public IDocument getDocument() {
+ return getDocumentProvider().getDocument( getEditorInput() );
+ }
+
+ private ResourceBundle getResourceBundle() {
+ return new ResourceBundle() {
+
+ protected Object handleGetObject( String key ) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Enumeration getKeys() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+ };
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/CSSSourceViewerConfiguration.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/CSSSourceViewerConfiguration.java
new file mode 100644
index 0000000..10ef026
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/CSSSourceViewerConfiguration.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor.editor.source;
+
+import org.eclipse.jface.text.DefaultInformationControl;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IInformationControl;
+import org.eclipse.jface.text.IInformationControlCreator;
+import org.eclipse.jface.text.ITextHover;
+import org.eclipse.jface.text.contentassist.ContentAssistant;
+import org.eclipse.jface.text.contentassist.IContentAssistant;
+import org.eclipse.jface.text.presentation.IPresentationReconciler;
+import org.eclipse.jface.text.presentation.PresentationReconciler;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.editors.text.TextSourceViewerConfiguration;
+
+public class CSSSourceViewerConfiguration extends TextSourceViewerConfiguration
+{
+
+ public final static String CSS_PARTITIONING = "__css_partitioning";
+ private CSSTokenScanner tokenScanner;
+
+ public CSSSourceViewerConfiguration( final CSSTokenScanner tokenScanner ) {
+ super();
+ this.tokenScanner = tokenScanner;
+ }
+
+ public String getConfiguredDocumentPartitioning( final ISourceViewer sourceViewer )
+ {
+ return CSS_PARTITIONING;
+ }
+
+ public String[] getConfiguredContentTypes( final ISourceViewer sourceViewer )
+ {
+ return new String[]{
+ IDocument.DEFAULT_CONTENT_TYPE
+ };
+ }
+
+ public IPresentationReconciler getPresentationReconciler( final ISourceViewer sourceViewer )
+ {
+ PresentationReconciler result = new PresentationReconciler();
+ result.setDocumentPartitioning( getConfiguredDocumentPartitioning( sourceViewer ) );
+ CSSDamagerRepairer repairer = new CSSDamagerRepairer( tokenScanner );
+ result.setDamager( repairer, IDocument.DEFAULT_CONTENT_TYPE );
+ result.setRepairer( repairer, IDocument.DEFAULT_CONTENT_TYPE );
+ return result;
+ }
+
+ public ITextHover getTextHover( final ISourceViewer sourceViewer,
+ final String contentType )
+ {
+ return new CSSTextHover( tokenScanner );
+ }
+
+ public IContentAssistant getContentAssistant( final ISourceViewer sourceViewer )
+ {
+ ContentAssistant assistant = new ContentAssistant();
+ assistant.setContentAssistProcessor( new CSSCompletionProcessor( tokenScanner ),
+ IDocument.DEFAULT_CONTENT_TYPE );
+// assistant.setContentAssistProcessor( new JavaDocCompletionProcessor(),
+// JavaPartitionScanner.JAVA_DOC );
+ assistant.enableAutoActivation( true );
+ assistant.setAutoActivationDelay( 500 );
+ assistant.setProposalPopupOrientation( IContentAssistant.PROPOSAL_OVERLAY );
+ assistant.setContextInformationPopupOrientation( IContentAssistant.CONTEXT_INFO_ABOVE );
+// assistant.setContextInformationPopupBackground(JavaEditorEnvironment.getJavaColorProvider().getColor(new RGB(150, 150, 0)));
+ assistant.setInformationControlCreator( new IInformationControlCreator() {
+
+ public IInformationControl createInformationControl( Shell parent ) {
+ return new DefaultInformationControl( parent );
+ }
+
+ });
+ return assistant;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/CSSTextHover.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/CSSTextHover.java
new file mode 100644
index 0000000..4a4c777
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/CSSTextHover.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor.editor.source;
+
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextHover;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.Region;
+import org.eclipse.rap.themeeditor.editor.source.region.IRegionExt;
+import org.eclipse.swt.graphics.Point;
+
+public class CSSTextHover implements ITextHover {
+
+ private CSSTokenScanner tokenScanner;
+
+ public CSSTextHover( final CSSTokenScanner tokenScanner ) {
+ this.tokenScanner = tokenScanner;
+ }
+
+ public String getHoverInfo( final ITextViewer textViewer,
+ final IRegion hoverRegion )
+ {
+ String result = "";
+ if( hoverRegion != null ) {
+ int offset = hoverRegion.getOffset();
+ IRegionExt regionExt = tokenScanner.getRegionExt( offset );
+ // TODO [rst] Implement pluggable descriptions to avoid tight coupling
+// result = ThemeDefinitionProvider.getDescription( regionExt,
+// regionExt.getContent()
+// .trim() );
+ }
+ return result;
+ }
+
+ public IRegion getHoverRegion( final ITextViewer textViewer, final int offset )
+ {
+ IRegion result;
+ Point selection = textViewer.getSelectedRange();
+ if( selection.x <= offset && offset < selection.x + selection.y ) {
+ result = new Region( selection.x, selection.y );
+ } else {
+ result = new Region( offset, 0 );
+ }
+ return result;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/CSSTokenProvider.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/CSSTokenProvider.java
new file mode 100644
index 0000000..96d1270
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/CSSTokenProvider.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor.editor.source;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.jface.text.TextAttribute;
+import org.eclipse.jface.text.rules.IToken;
+import org.eclipse.jface.text.rules.Token;
+import org.eclipse.rap.themeeditor.ThemeEditorPlugin;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.RGB;
+
+/**
+ * Holds information about the appearance (color and style) of all token types.
+ * This will be used for syntax coloring in source editor.
+ */
+public class CSSTokenProvider {
+
+ public static final int PROPERTY_TOKEN = 1;
+ public static final int SELECTOR_TOKEN = 2;
+ public static final int STYLE_TOKEN = 3;
+ public static final int STATE_TOKEN = 4;
+ public static final int VARIANT_TOKEN = 5;
+ public static final int STRING_TOKEN = 6;
+ public static final int COMMENT_TOKEN = 7;
+ public static final int DEFAULT_TOKEN = 8;
+ private Map tokenMap;
+
+ public CSSTokenProvider() {
+ tokenMap = new HashMap();
+ tokenMap.put( new Integer( PROPERTY_TOKEN ),
+ new CSSTokenStyle( new RGB( 127, 0, 85 ), SWT.BOLD ) );
+ tokenMap.put( new Integer( SELECTOR_TOKEN ),
+ new CSSTokenStyle( new RGB( 0, 0, 0 ), SWT.BOLD ) );
+ tokenMap.put( new Integer( STYLE_TOKEN ),
+ new CSSTokenStyle( new RGB( 42, 0, 255 ), SWT.NORMAL ) );
+ tokenMap.put( new Integer( STATE_TOKEN ),
+ new CSSTokenStyle( new RGB( 42, 0, 255 ), SWT.ITALIC ) );
+ tokenMap.put( new Integer( VARIANT_TOKEN ),
+ new CSSTokenStyle( new RGB( 255, 0, 0 ), SWT.NORMAL ) );
+ tokenMap.put( new Integer( STRING_TOKEN ),
+ new CSSTokenStyle( new RGB( 42, 0, 255 ), SWT.NORMAL ) );
+ tokenMap.put( new Integer( COMMENT_TOKEN ),
+ new CSSTokenStyle( new RGB( 63, 127, 95 ), SWT.NORMAL ) );
+ tokenMap.put( new Integer( DEFAULT_TOKEN ),
+ new CSSTokenStyle( new RGB( 0, 0, 0 ), SWT.NORMAL ) );
+ }
+
+ /**
+ * Returns a new token that can be used to style a found region appropriately
+ * to its type.
+ */
+ public IToken createToken( final int type ) {
+ CSSTokenStyle tokenStyle = ( CSSTokenStyle )tokenMap.get( new Integer( type ) );
+ if( tokenStyle == null ) {
+ tokenStyle = ( CSSTokenStyle )tokenMap.get( new Integer( DEFAULT_TOKEN ) );
+ }
+ return new Token( new TextAttribute( ThemeEditorPlugin.getDefault()
+ .getColorRegistry()
+ .getColor( tokenStyle.rgb ), null, tokenStyle.style ) );
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/CSSTokenScanner.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/CSSTokenScanner.java
new file mode 100644
index 0000000..7bb294f
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/CSSTokenScanner.java
@@ -0,0 +1,214 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor.editor.source;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.rules.IToken;
+import org.eclipse.jface.text.rules.ITokenScanner;
+import org.eclipse.jface.text.rules.Token;
+import org.eclipse.rap.themeeditor.editor.source.region.IHasParentRegion;
+import org.eclipse.rap.themeeditor.editor.source.region.IRegionExt;
+import org.eclipse.rap.themeeditor.editor.source.region.SelectorRegion;
+
+/**
+ * Scans a document and splits its content into tokens, which are implementors
+ * of IRegionExt.
+ */
+public class CSSTokenScanner implements ITokenScanner {
+
+ private CSSTokenProvider provider;
+ private CSSSourceEditor editor;
+ private List outlineRegions;
+ private List tokenList;
+ private IRegionExt lastState;
+ private int currentListPosition;
+ private int lastListPosition;
+ private ITokenChangedListener listener = null;
+ private String oldContent;
+ private int oldListPosition;
+ private SelectorRegion lastSelector;
+
+ public CSSTokenScanner( final CSSSourceEditor editor ) {
+ this.editor = editor;
+ provider = new CSSTokenProvider();
+ tokenList = new ArrayList();
+ outlineRegions = new ArrayList();
+ }
+
+ public int getTokenLength() {
+ return lastState.getLength();
+ }
+
+ public int getTokenOffset() {
+ return lastState.getOffset();
+ }
+
+ public IToken nextToken() {
+ currentListPosition++;
+ if( currentListPosition >= tokenList.size()
+ || ( currentListPosition > lastListPosition ) )
+ {
+ return Token.EOF;
+ }
+ lastState = ( IRegionExt )tokenList.get( currentListPosition );
+ IToken result = provider.createToken( lastState.getTokenType() );
+ return result;
+ }
+
+ public void setRange( final IDocument document,
+ final int offset,
+ final int length )
+ {
+ if( document.get().equals( oldContent ) ) {
+ currentListPosition = oldListPosition;
+ } else {
+ oldContent = document.get();
+ tokenList.clear();
+ currentListPosition = -1;
+ lastListPosition = -1;
+ IRegionExt currentState = new SelectorRegion( -1 );
+ lastSelector = ( SelectorRegion )currentState;
+ for( int i = 0; i < document.getLength(); i++ ) {
+ try {
+ char character = document.getChar( i );
+ IRegionExt newState = currentState.getNextState( character );
+ if( newState != currentState ) {
+ tokenList.add( currentState );
+ if( currentState instanceof SelectorRegion ) {
+ SelectorRegion sr = ( SelectorRegion )currentState;
+ if( sr.getContent().trim().length() > 0 ) {
+ lastSelector = ( SelectorRegion )currentState;
+ }
+ } else if( currentState instanceof IHasParentRegion ) {
+ ( ( IHasParentRegion )currentState ).setParentRegion( lastSelector );
+ }
+ if( ( currentState.getOffset() + currentState.getLength() ) < offset )
+ {
+ currentListPosition++;
+ }
+ if( currentState.getOffset() < ( offset + length ) ) {
+ lastListPosition++;
+ }
+ currentState = newState;
+ }
+ } catch( BadLocationException e ) {
+ e.printStackTrace();
+ }
+ }
+ tokenList.add( currentState );
+ if( currentState instanceof SelectorRegion ) {
+ lastSelector = ( SelectorRegion )currentState;
+ } else if( currentState instanceof IHasParentRegion ) {
+ ( ( IHasParentRegion )currentState ).setParentRegion( lastSelector );
+ }
+ if( ( currentState.getOffset() + currentState.getLength() ) < offset ) {
+ currentListPosition++;
+ }
+ if( currentState.getOffset() < ( offset + length ) ) {
+ lastListPosition++;
+ }
+ oldListPosition = currentListPosition;
+ // notify token changed listener if one is registered
+ if( listener != null ) {
+ listener.tokensChanged();
+ }
+ }
+ }
+
+ /**
+ * Returns the token at a given offset position in the document.
+ */
+ public IRegionExt getRegionExt( final int offset ) {
+ IRegionExt result = null;
+ Iterator it = tokenList.iterator();
+ while( it.hasNext() ) {
+ IRegionExt regionExt = ( IRegionExt )it.next();
+ if( regionExt.getOffset() <= offset ) {
+ result = regionExt;
+ }
+ }
+ return result;
+ }
+
+ public List getTokenList() {
+ return tokenList;
+ }
+
+ public void setTokenChangedListener( final ITokenChangedListener listener ) {
+ this.listener = listener;
+ }
+
+ /**
+ * Returns the array of Outline regions that are directly used as the input
+ * items for the Outline.
+ */
+ public synchronized OutlineRegion[] getOutlineRegionsArray() {
+ outlineRegions.clear();
+ boolean bufferEnabled = false;
+ int offset = 0;
+ List outlineElements = new ArrayList();
+ Iterator it = getTokenList().iterator();
+ while( it.hasNext() ) {
+ IRegionExt regionExt = ( IRegionExt )it.next();
+ if( regionExt.getTokenType() == CSSTokenProvider.SELECTOR_TOKEN ) {
+ outlineElements.add( regionExt );
+ }
+ if( regionExt.getTokenType() == CSSTokenProvider.SELECTOR_TOKEN
+ && !bufferEnabled )
+ {
+ String temp = "";
+ try {
+ temp = editor.getDocument().get( regionExt.getOffset(),
+ regionExt.getLength() ).trim();
+ } catch( BadLocationException e ) {
+ temp = "";
+ }
+ if( temp.length() > 0 ) {
+ offset = regionExt.getOffset();
+ bufferEnabled = true;
+ }
+ } else if( regionExt.getTokenType() == CSSTokenProvider.PROPERTY_TOKEN
+ && bufferEnabled )
+ {
+ bufferEnabled = false;
+ int length = regionExt.getOffset() - offset - 1;
+ String content = "";
+ try {
+ content = editor.getDocument().get( offset, length ).trim();
+ } catch( BadLocationException e ) {
+ e.printStackTrace();
+ }
+ if( content.length() > 0 ) {
+ // ignore comments and white spaces
+ content = content.replaceAll( "/\\*.*\\*/", " " );
+ content = content.replaceAll( "\\s+", " " );
+ OutlineRegion outlineRegion = new OutlineRegion( offset,
+ length,
+ content,
+ outlineElements );
+ outlineRegions.add( outlineRegion );
+ outlineElements = new ArrayList();
+ }
+ }
+ }
+ OutlineRegion[] result = new OutlineRegion[ outlineRegions.size() ];
+ return ( org.eclipse.rap.themeeditor.editor.source.OutlineRegion[] )outlineRegions.toArray( result );
+ }
+
+ public List getOutlineRegionsList() {
+ return outlineRegions;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/CSSTokenStyle.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/CSSTokenStyle.java
new file mode 100644
index 0000000..1c06e10
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/CSSTokenStyle.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor.editor.source;
+
+import org.eclipse.swt.graphics.RGB;
+
+public class CSSTokenStyle {
+
+ public RGB rgb;
+ public int style;
+
+ public CSSTokenStyle( final RGB rgb, final int style ) {
+ this.rgb = rgb;
+ this.style = style;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/DocumentUpdateTimer.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/DocumentUpdateTimer.java
new file mode 100644
index 0000000..443316d
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/DocumentUpdateTimer.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor.editor.source;
+
+/**
+ * Timer that is used to buffer all occurring document change events. A document
+ * change event is only forwarded to the editor after a certain delay after the
+ * last occurring event. This will save the editor from updating Outline on
+ * every received key event.
+ */
+public class DocumentUpdateTimer implements Runnable {
+
+ private Thread thread;
+ private Object mutex = new Object();
+ private boolean isReset = false;
+ private boolean isStopped = false;
+ private IDocumentUpdateListener listener;
+ private int updateDelay = 1000;
+
+ public DocumentUpdateTimer( IDocumentUpdateListener listener ) {
+ this.listener = listener;
+ }
+
+ protected void start() {
+ thread = new Thread( this, "DocumentUpdateTimer.update_delay" );
+ thread.start();
+ }
+
+ public void run() {
+ isStopped = false;
+ try {
+ while( true ) {
+ synchronized( mutex ) {
+ if( updateDelay != 0 ) {
+ mutex.wait( updateDelay );
+ }
+ if( isReset ) {
+ isReset = false;
+ continue;
+ }
+ }
+ if( listener != null && !isStopped ) {
+ listener.updateDocument();
+ }
+ break;
+ }
+ } catch( InterruptedException exception ) {
+ exception.printStackTrace();
+ }
+ thread = null;
+ }
+
+ protected void reset() {
+ synchronized( mutex ) {
+ isReset = true;
+ mutex.notifyAll();
+ }
+ }
+
+ public void stop() {
+ synchronized( mutex ) {
+ // Thread threadToStop = thread;
+ // if( threadToStop != null && threadToStop.isAlive() ) {
+ // threadToStop.interrupt();
+ // }
+ isStopped = true;
+ }
+ }
+
+ public void documentChanged() {
+ if( thread != null && thread.isAlive() ) {
+ reset();
+ } else {
+ start();
+ }
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/IDocumentUpdateListener.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/IDocumentUpdateListener.java
new file mode 100644
index 0000000..c364790
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/IDocumentUpdateListener.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor.editor.source;
+
+/**
+ * Listener that is notified when the time has elapsed after a document change
+ * event. So now the document change becomes visible to the editor.
+ */
+public interface IDocumentUpdateListener {
+
+ public void updateDocument();
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/ITokenChangedListener.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/ITokenChangedListener.java
new file mode 100644
index 0000000..a337a91
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/ITokenChangedListener.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor.editor.source;
+
+/**
+ * Listener interface that is called whenever the token scanner was requested to
+ * split the document again into tokens.
+ */
+public interface ITokenChangedListener {
+
+ public void tokensChanged();
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/OutlineRegion.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/OutlineRegion.java
new file mode 100644
index 0000000..fedbec2
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/OutlineRegion.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor.editor.source;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.rap.themeeditor.editor.source.region.SelectorRegion;
+
+/**
+ * Special type of region for Outline items. It's basically the region in the
+ * text containing the whole selector list of a rule.
+ */
+public class OutlineRegion implements IRegion {
+
+ private int offset;
+ private int length;
+ private String content;
+ private List elements;
+
+ public OutlineRegion( final int offset,
+ final int length,
+ final String content,
+ final List elements )
+ {
+ this.offset = offset;
+ this.length = length;
+ this.content = content;
+ this.elements = elements;
+ }
+
+ public int getLength() {
+ return length;
+ }
+
+ public int getOffset() {
+ return offset;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public String toString() {
+ return content == null
+ ? ""
+ : content;
+ }
+
+ /**
+ * Returns the array of selectors this outline region consists of. Namely the
+ * selector list of a rule.
+ */
+ public SelectorRegion[] getElements() {
+ List resultList = new ArrayList();
+ Iterator it = elements.iterator();
+ while( it.hasNext() ) {
+ Object object = it.next();
+ if( object instanceof SelectorRegion ) {
+ resultList.add( ( SelectorRegion )object );
+ }
+ }
+ SelectorRegion[] result = new SelectorRegion[ resultList.size() ];
+ return ( SelectorRegion[] )resultList.toArray( result );
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/AbstractRegion.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/AbstractRegion.java
new file mode 100644
index 0000000..9cb9797
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/AbstractRegion.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor.editor.source.region;
+
+/**
+ * Super class of all supported region types.
+ */
+public abstract class AbstractRegion implements IRegionExt {
+
+ protected int offset;
+ protected int length;
+ protected char lastCharacter;
+
+ public AbstractRegion( final int offset ) {
+ this.offset = offset + 1;
+ this.length = 0;
+ }
+
+ public int getOffset() {
+ return offset;
+ }
+
+ public int getLength() {
+ return length - 1;
+ }
+
+ public String getContent() {
+ return "";
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/CommentRegion.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/CommentRegion.java
new file mode 100644
index 0000000..560c1a1
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/CommentRegion.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor.editor.source.region;
+
+import org.eclipse.rap.themeeditor.SupportedKeywords;
+import org.eclipse.rap.themeeditor.editor.source.CSSTokenProvider;
+
+/**
+ * A region in the text file representing a comment section.
+ */
+public class CommentRegion extends AbstractRegion {
+
+ private IRegionExt lastState;
+
+ public CommentRegion( final int offset, final IRegionExt lastState ) {
+ super( offset - 1 );
+ length = 1;
+ this.lastState = lastState;
+ }
+
+ public IRegionExt getNextState( final char character ) {
+ IRegionExt result = this;
+ if( character == '/' && lastCharacter == '*' ) {
+ length++;
+ result = lastState.getCopy( offset + length );
+ length++;
+ }
+ lastCharacter = character;
+ length++;
+ return result;
+ }
+
+ public int getTokenType() {
+ return CSSTokenProvider.COMMENT_TOKEN;
+ }
+
+ /* never called */
+ public IRegionExt getCopy( final int offset ) {
+ return null;
+ }
+
+ public int getKeywordType() {
+ return SupportedKeywords.UNDEFINED;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/IHasParentRegion.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/IHasParentRegion.java
new file mode 100644
index 0000000..4bea107
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/IHasParentRegion.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor.editor.source.region;
+
+/**
+ * Interface implemented by Region Classes that provide access to a parent
+ * region. This parent region is basically the selector, which a style, state or
+ * variant belongs to.
+ */
+public interface IHasParentRegion {
+
+ public void setParentRegion( final SelectorRegion region );
+
+ public SelectorRegion getParentRegion();
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/IRegionExt.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/IRegionExt.java
new file mode 100644
index 0000000..9c06ed7
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/IRegionExt.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor.editor.source.region;
+
+import org.eclipse.jface.text.IRegion;
+
+/**
+ * An IRegionExt is a logic unit within the theme file, so that the editor can
+ * provide syntax color or content assists based on the structure of the regions
+ * of the theme file.
+ */
+public interface IRegionExt extends IRegion {
+
+ /**
+ * Returns the type of a region. Each region implementation has its own type.
+ */
+ public int getTokenType();
+
+ /**
+ * Returns the keyword type. These are the ones supported by RAP. So this type
+ * can be Selector, Property, Style, State, or default otherwise.
+ */
+ public int getKeywordType();
+
+ /**
+ * Returns the next state, namely the next instance of a region. Therefore an
+ * implementation has to evaluate the given character and decide if it shall
+ * switch the state (so instantiate an new region and return it) or if keeps
+ * the current state (so just return itself).
+ */
+ public IRegionExt getNextState( final char character );
+
+ /**
+ * Returns a new instance of a region that has got the same type as the
+ * current one. Used to continue with the same region type as before after a
+ * comment region has finished.
+ */
+ public IRegionExt getCopy( final int offset );
+
+ /**
+ * Returns a String containing all characters that were given to evaluate.
+ * This means the content is the part of text in the theme file from position
+ * offset until position offset+length.
+ */
+ public String getContent();
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/PropertyRegion.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/PropertyRegion.java
new file mode 100644
index 0000000..6ee7465
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/PropertyRegion.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor.editor.source.region;
+
+import org.eclipse.rap.themeeditor.SupportedKeywords;
+import org.eclipse.rap.themeeditor.editor.source.CSSTokenProvider;
+
+/**
+ * A region in the text file representing a property inside a rule.
+ */
+public class PropertyRegion extends AbstractRegion {
+
+ private StringBuffer buffer;
+
+ public PropertyRegion( final int offset ) {
+ super( offset );
+ buffer = new StringBuffer();
+ }
+
+ public IRegionExt getNextState( final char character ) {
+ IRegionExt result = this;
+ switch( character ) {
+ case ':':
+ result = new ValueRegion( offset + length );
+ break;
+ case '}':
+ result = new SelectorRegion( offset + length );
+ break;
+ case '"':
+ result = new StringRegion( offset + length, character, this );
+ break;
+ case '\'':
+ result = new StringRegion( offset + length, character, this );
+ break;
+ case '*':
+ if( lastCharacter == '/' ) {
+ result = new CommentRegion( offset + length - 1, this );
+ length--;
+ buffer.setCharAt( buffer.length() - 1, ' ' );
+ } else {
+ buffer.append( character );
+ }
+ break;
+ default:
+ buffer.append( character );
+ break;
+ }
+ lastCharacter = character;
+ length++;
+ return result;
+ }
+
+ public int getTokenType() {
+ return CSSTokenProvider.PROPERTY_TOKEN;
+ }
+
+ public IRegionExt getCopy( final int offset ) {
+ return new PropertyRegion( offset );
+ }
+
+ public int getKeywordType() {
+ return SupportedKeywords.PROPERTY_TYPE;
+ }
+
+ public String getContent() {
+ return buffer.toString();
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/SelectorRegion.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/SelectorRegion.java
new file mode 100644
index 0000000..7dc3f4b
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/SelectorRegion.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor.editor.source.region;
+
+import org.eclipse.rap.themeeditor.SupportedKeywords;
+import org.eclipse.rap.themeeditor.editor.source.CSSTokenProvider;
+
+/**
+ * A region in the text file representing a selector.
+ */
+public class SelectorRegion extends AbstractRegion {
+
+ private StringBuffer buffer;
+
+ public SelectorRegion( final int offset ) {
+ super( offset );
+ buffer = new StringBuffer();
+ }
+
+ public IRegionExt getNextState( final char character ) {
+ IRegionExt result = this;
+ switch( character ) {
+ case ',':
+ case ';':
+ case ' ':
+ result = new SelectorRegion( offset + length );
+ length++;
+ break;
+ case '[':
+ result = new StyleRegion( offset + length );
+ break;
+ case ':':
+ result = new StateRegion( offset + length );
+ break;
+ case '.':
+ result = new VariantRegion( offset + length );
+ break;
+ case '{':
+ result = new PropertyRegion( offset + length );
+ break;
+ case '"':
+ result = new StringRegion( offset + length, character, this );
+ break;
+ case '\'':
+ result = new StringRegion( offset + length, character, this );
+ break;
+ case '*':
+ if( lastCharacter == '/' ) {
+ result = new CommentRegion( offset + length - 1, this );
+ length--;
+ buffer.setCharAt( buffer.length() - 1, ' ' );
+ } else {
+ buffer.append( character );
+ }
+ break;
+ default:
+ buffer.append( character );
+ break;
+ }
+ lastCharacter = character;
+ length++;
+ return result;
+ }
+
+ public int getTokenType() {
+ return CSSTokenProvider.SELECTOR_TOKEN;
+ }
+
+ public IRegionExt getCopy( final int offset ) {
+ return new SelectorRegion( offset );
+ }
+
+ public int getKeywordType() {
+ return SupportedKeywords.SELECTOR_TYPE;
+ }
+
+ public String getContent() {
+ return buffer.toString();
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/StateRegion.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/StateRegion.java
new file mode 100644
index 0000000..3e9c96f
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/StateRegion.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor.editor.source.region;
+
+import org.eclipse.rap.themeeditor.SupportedKeywords;
+import org.eclipse.rap.themeeditor.editor.source.CSSTokenProvider;
+
+/**
+ * A region in the text file representing a state belonging to a selector.
+ */
+public class StateRegion extends AbstractRegion implements IHasParentRegion {
+
+ private StringBuffer buffer;
+ private SelectorRegion parent;
+
+ public StateRegion( final int offset ) {
+ super( offset );
+ buffer = new StringBuffer();
+ }
+
+ public IRegionExt getNextState( final char character ) {
+ IRegionExt result = this;
+ switch( character ) {
+ case '[':
+ result = new StyleRegion( offset + length );
+ break;
+ case ';':
+ result = new SelectorRegion( offset + length );
+ break;
+ case ',':
+ result = new SelectorRegion( offset + length );
+ break;
+ case '.':
+ result = new VariantRegion( offset + length );
+ break;
+ case ':':
+ result = new StateRegion( offset + length );
+ length++;
+ break;
+ case '{':
+ result = new PropertyRegion( offset + length );
+ break;
+ case '"':
+ result = new StringRegion( offset + length, character, this );
+ break;
+ case '\'':
+ result = new StringRegion( offset + length, character, this );
+ break;
+ case '*':
+ if( lastCharacter == '/' ) {
+ result = new CommentRegion( offset + length - 1, this );
+ length--;
+ buffer.setCharAt( buffer.length() - 1, ' ' );
+ } else {
+ buffer.append( character );
+ }
+ break;
+ default:
+ buffer.append( character );
+ break;
+ }
+ if( Character.isWhitespace( character ) ) {
+ result = new SelectorRegion( offset + length );
+ }
+ lastCharacter = character;
+ length++;
+ return result;
+ }
+
+ public int getTokenType() {
+ return CSSTokenProvider.STATE_TOKEN;
+ }
+
+ public IRegionExt getCopy( final int offset ) {
+ return new StateRegion( offset );
+ }
+
+ public int getKeywordType() {
+ return SupportedKeywords.STATE_TYPE;
+ }
+
+ public String getContent() {
+ return buffer.toString();
+ }
+
+ public SelectorRegion getParentRegion() {
+ return parent;
+ }
+
+ public void setParentRegion( final SelectorRegion region ) {
+ parent = region;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/StringRegion.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/StringRegion.java
new file mode 100644
index 0000000..8e1f752
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/StringRegion.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor.editor.source.region;
+
+import org.eclipse.rap.themeeditor.SupportedKeywords;
+import org.eclipse.rap.themeeditor.editor.source.CSSTokenProvider;
+
+/**
+ * A region in the text file representing a string value.
+ */
+public class StringRegion extends AbstractRegion {
+
+ private char quoteCharacter;
+ private IRegionExt lastState;
+
+ public StringRegion( final int offset,
+ final char quoteCharacter,
+ final IRegionExt lastState )
+ {
+ super( offset );
+ this.quoteCharacter = quoteCharacter;
+ this.lastState = lastState;
+ }
+
+ public IRegionExt getNextState( final char character ) {
+ IRegionExt result = this;
+ if( quoteCharacter == character ) {
+ result = lastState.getCopy( offset + length );
+ }
+ lastCharacter = character;
+ length++;
+ return result;
+ }
+
+ public int getTokenType() {
+ return CSSTokenProvider.STRING_TOKEN;
+ }
+
+ /* never called */
+ public IRegionExt getCopy( final int offset ) {
+ return null;
+ }
+
+ public int getKeywordType() {
+ return SupportedKeywords.UNDEFINED;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/StyleRegion.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/StyleRegion.java
new file mode 100644
index 0000000..1766ea5
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/StyleRegion.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor.editor.source.region;
+
+import org.eclipse.rap.themeeditor.SupportedKeywords;
+import org.eclipse.rap.themeeditor.editor.source.CSSTokenProvider;
+
+/**
+ * A region in the text file representing a style belonging to a selector.
+ */
+public class StyleRegion extends AbstractRegion implements IHasParentRegion {
+
+ private StringBuffer buffer;
+ private SelectorRegion parent;
+
+ public StyleRegion( final int offset ) {
+ super( offset );
+ buffer = new StringBuffer();
+ }
+
+ public IRegionExt getNextState( final char character ) {
+ IRegionExt result = this;
+ switch( character ) {
+ case ';':
+ result = new SelectorRegion( offset + length );
+ break;
+ case ',':
+ result = new SelectorRegion( offset + length );
+ break;
+ case ']':
+ result = new SelectorRegion( offset + length );
+ break;
+ case '.':
+ result = new VariantRegion( offset + length );
+ break;
+ case ':':
+ result = new StateRegion( offset + length );
+ break;
+ case '{':
+ result = new PropertyRegion( offset + length );
+ break;
+ case '"':
+ result = new StringRegion( offset + length, character, this );
+ break;
+ case '\'':
+ result = new StringRegion( offset + length, character, this );
+ break;
+ case '*':
+ if( lastCharacter == '/' ) {
+ result = new CommentRegion( offset + length - 1, this );
+ length--;
+ buffer.setCharAt( buffer.length() - 1, ' ' );
+ } else {
+ buffer.append( character );
+ }
+ break;
+ default:
+ buffer.append( character );
+ break;
+ }
+ if( Character.isWhitespace( character ) ) {
+ result = new SelectorRegion( offset + length );
+ }
+ lastCharacter = character;
+ length++;
+ return result;
+ }
+
+ public int getTokenType() {
+ return CSSTokenProvider.STYLE_TOKEN;
+ }
+
+ public IRegionExt getCopy( final int offset ) {
+ return new StyleRegion( offset );
+ }
+
+ public int getKeywordType() {
+ return SupportedKeywords.STYLE_TYPE;
+ }
+
+ public String getContent() {
+ return buffer.toString();
+ }
+
+ public SelectorRegion getParentRegion() {
+ return parent;
+ }
+
+ public void setParentRegion( final SelectorRegion region ) {
+ parent = region;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/ValueRegion.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/ValueRegion.java
new file mode 100644
index 0000000..0b860ab
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/ValueRegion.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor.editor.source.region;
+
+import org.eclipse.rap.themeeditor.SupportedKeywords;
+import org.eclipse.rap.themeeditor.editor.source.CSSTokenProvider;
+
+/**
+ * A region in the text file representing the value after a property.
+ */
+public class ValueRegion extends AbstractRegion {
+
+ public ValueRegion( final int offset ) {
+ super( offset );
+ }
+
+ public IRegionExt getNextState( final char character ) {
+ IRegionExt result = this;
+ switch( character ) {
+ case ';':
+ result = new PropertyRegion( offset + length );
+ break;
+ case '}':
+ result = new SelectorRegion( offset + length );
+ break;
+ case '"':
+ result = new StringRegion( offset + length, character, this );
+ break;
+ case '\'':
+ result = new StringRegion( offset + length, character, this );
+ break;
+ case '*':
+ if( lastCharacter == '/' ) {
+ result = new CommentRegion( offset + length - 1, this );
+ length--;
+ }
+ break;
+ default:
+ break;
+ }
+ lastCharacter = character;
+ length++;
+ return result;
+ }
+
+ public int getTokenType() {
+ return CSSTokenProvider.DEFAULT_TOKEN;
+ }
+
+ public IRegionExt getCopy( final int offset ) {
+ return new ValueRegion( offset );
+ }
+
+ public int getKeywordType() {
+ return SupportedKeywords.UNDEFINED;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/VariantRegion.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/VariantRegion.java
new file mode 100644
index 0000000..fd62857
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rap/themeeditor/editor/source/region/VariantRegion.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rap.themeeditor.editor.source.region;
+
+import org.eclipse.rap.themeeditor.SupportedKeywords;
+import org.eclipse.rap.themeeditor.editor.source.CSSTokenProvider;
+
+/**
+ * A region in the text file representing a variant belonging to a selector.
+ */
+public class VariantRegion extends AbstractRegion {
+
+ public VariantRegion( final int offset ) {
+ super( offset );
+ }
+
+ public IRegionExt getNextState( final char character ) {
+ IRegionExt result = this;
+ switch( character ) {
+ case '[':
+ result = new StyleRegion( offset + length );
+ break;
+ case ';':
+ result = new SelectorRegion( offset + length );
+ break;
+ case ',':
+ result = new SelectorRegion( offset + length );
+ break;
+ case ':':
+ result = new StateRegion( offset + length );
+ break;
+ case '.':
+ result = new VariantRegion( offset + length );
+ length++;
+ break;
+ case '{':
+ result = new PropertyRegion( offset + length );
+ break;
+ case '"':
+ result = new StringRegion( offset + length, character, this );
+ break;
+ case '\'':
+ result = new StringRegion( offset + length, character, this );
+ break;
+ case '*':
+ if( lastCharacter == '/' ) {
+ result = new CommentRegion( offset + length - 1, this );
+ length--;
+ }
+ break;
+ default:
+ break;
+ }
+ if( Character.isWhitespace( character ) ) {
+ result = new SelectorRegion( offset + length );
+ }
+ lastCharacter = character;
+ length++;
+ return result;
+ }
+
+ public int getTokenType() {
+ return CSSTokenProvider.VARIANT_TOKEN;
+ }
+
+ public IRegionExt getCopy( int offset ) {
+ return new VariantRegion( offset );
+ }
+
+ public int getKeywordType() {
+ return SupportedKeywords.UNDEFINED;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/NewThemeDefinitionReader.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/NewThemeDefinitionReader.java
new file mode 100644
index 0000000..aaacead
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/NewThemeDefinitionReader.java
@@ -0,0 +1,217 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.rwt.internal.theme;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.parsers.*;
+
+import org.w3c.dom.*;
+import org.xml.sax.*;
+
+/**
+ * Reader for theme definition files. These are the "*.theme.xml" files that
+ * define themeable properties of a certain widget.
+ */
+public class NewThemeDefinitionReader {
+
+ private static final String[] EMPTY_STRING_ARRAY = new String[ 0 ];
+ public static interface ThemeDefHandler {
+
+ public abstract void readThemeProperty( ThemeProperty def );
+ }
+ private static final String NODE_ROOT = "theme";
+ private static final String ATTR_NAME = "name";
+ private static final String ATTR_DESCRIPTION = "description";
+ private static final String THEME_DEF_SCHEMA = "themedef.xsd";
+ private static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
+ private static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
+ private final InputStream inputStream;
+ private final String fileName;
+
+ /**
+ * An instance of this class reads theme definitions from an XML resource.
+ *
+ * @param inputStream input stream from a theme definition XML
+ */
+ public NewThemeDefinitionReader( final InputStream inputStream,
+ final String fileName )
+ {
+ this.fileName = fileName;
+ if( inputStream == null ) {
+ throw new NullPointerException( "null argument" );
+ }
+ this.inputStream = inputStream;
+ }
+
+ public ThemeDefElement[] read() throws SAXException, IOException {
+ Document document;
+ document = parseThemeDefinition( inputStream );
+ Node root = document.getElementsByTagName( NODE_ROOT ).item( 0 );
+ NodeList childNodes = root.getChildNodes();
+ List elementList = new ArrayList();
+ for( int i = 0; i < childNodes.getLength(); i++ ) {
+ Node node = childNodes.item( i );
+ if( node.getNodeType() == Node.ELEMENT_NODE ) {
+ if( "element".equals( node.getNodeName() ) ) {
+ ThemeDefElement element = readThemeDefElement( node );
+ elementList.add( element );
+ }
+ }
+ }
+ ThemeDefElement[] result = new ThemeDefElement[ elementList.size() ];
+ elementList.toArray( result );
+ return result;
+ }
+
+ private ThemeDefElement readThemeDefElement( final Node node ) {
+ String name = getAttributeValue( node, ATTR_NAME );
+ String description = getAttributeValue( node, ATTR_DESCRIPTION );
+ NodeList childNodes = node.getChildNodes();
+ List propertyList = new ArrayList();
+ Map styleMap = new HashMap();
+ Map stateMap = new HashMap();
+ for( int i = 0; i < childNodes.getLength(); i++ ) {
+ Node childNode = childNodes.item( i );
+ if( childNode.getNodeType() == Node.ELEMENT_NODE ) {
+ if( "property".equals( childNode.getNodeName() ) ) {
+ ThemeDefProperty property = readThemeDefProperty( childNode );
+ propertyList.add( property );
+ } else if( "style".equals( childNode.getNodeName() ) ) {
+ styleMap.put( getAttributeValue( childNode, ATTR_NAME ),
+ getAttributeValue( childNode, ATTR_DESCRIPTION ) );
+ } else if( "state".equals( childNode.getNodeName() ) ) {
+ stateMap.put( getAttributeValue( childNode, ATTR_NAME ),
+ getAttributeValue( childNode, ATTR_DESCRIPTION ) );
+ }
+ }
+ }
+ ThemeDefProperty[] properties = new ThemeDefProperty[ propertyList.size() ];
+ propertyList.toArray( properties );
+ return new ThemeDefElement( name,
+ description,
+ properties,
+ styleMap,
+ stateMap );
+ }
+
+ private ThemeDefProperty readThemeDefProperty( final Node node ) {
+ String name = getAttributeValue( node, ATTR_NAME );
+ String description = getAttributeValue( node, ATTR_DESCRIPTION );
+ String stylesStr = getAttributeValue( node, "styles" );
+ String[] styles;
+ if( stylesStr != null ) {
+ styles = stylesStr.split( "\\s+" );
+ } else {
+ styles = EMPTY_STRING_ARRAY;
+ }
+ String statesStr = getAttributeValue( node, "states" );
+ String[] states = null;
+ if( statesStr != null ) {
+ states = statesStr.split( "\\s+" );
+ } else {
+ states = EMPTY_STRING_ARRAY;
+ }
+ return new ThemeDefProperty( name, description, styles, states );
+ }
+
+ private static String getAttributeValue( final Node node, final String name )
+ {
+ String result = null;
+ NamedNodeMap attributes = node.getAttributes();
+ if( attributes != null ) {
+ Node namedItem = attributes.getNamedItem( name );
+ if( namedItem != null ) {
+ result = namedItem.getNodeValue();
+ }
+ }
+ return result;
+ }
+
+ private Document parseThemeDefinition( final InputStream is )
+ throws SAXException, IOException
+ {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware( true );
+ ClassLoader loader = NewThemeDefinitionReader.class.getClassLoader();
+ final URL schema = loader.getResource( THEME_DEF_SCHEMA );
+ factory.setValidating( schema != null );
+ try {
+ factory.setAttribute( JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA );
+ } catch( final IllegalArgumentException iae ) {
+ // XML-Processing does not support JAXP 1.2 or greater
+ factory.setNamespaceAware( false );
+ factory.setValidating( false );
+ }
+ DocumentBuilder builder;
+ try {
+ builder = factory.newDocumentBuilder();
+ } catch( final ParserConfigurationException e ) {
+ String message = "Failed to initialize parser for theme definition files";
+ throw new RuntimeException( message, e );
+ }
+ // builder.setEntityResolver( new EntityResolver() {
+ // public InputSource resolveEntity( final String publicID,
+ // final String systemID )
+ // throws IOException, SAXException
+ // {
+ // InputSource result = null;
+ // if( schema != null && systemID.endsWith( THEME_DEF_SCHEMA ) ) {
+ // URLConnection connection = schema.openConnection();
+ // connection.setUseCaches( false );
+ // result = new InputSource( connection.getInputStream() );
+ // }
+ // return result;
+ // }
+ // } );
+ builder.setErrorHandler( new ThemeDefinitionErrorHandler() );
+ return builder.parse( is );
+ }
+ // TODO: Logging instead of sysout
+ private class ThemeDefinitionErrorHandler implements ErrorHandler {
+
+ public void error( final SAXParseException spe ) throws SAXException {
+ System.err.println( "Error parsing theme definition "
+ + getPosition( spe )
+ + ":" );
+ System.err.println( spe.getMessage() );
+ }
+
+ public void fatalError( final SAXParseException spe ) throws SAXException {
+ System.err.println( "Fatal error parsing theme definition "
+ + getPosition( spe )
+ + ":" );
+ System.err.println( spe.getMessage() );
+ }
+
+ public void warning( final SAXParseException spe ) throws SAXException {
+ System.err.println( "Warning parsing theme definition "
+ + getPosition( spe )
+ + ":" );
+ System.err.println( spe.getMessage() );
+ }
+
+ private String getPosition( final SAXParseException spe ) {
+ return "in file '"
+ + fileName
+ + "' at line "
+ + spe.getLineNumber()
+ + ", col "
+ + spe.getColumnNumber();
+ }
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/QxBoolean.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/QxBoolean.java
new file mode 100644
index 0000000..efe9527
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/QxBoolean.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme;
+
+import java.text.MessageFormat;
+
+
+public class QxBoolean implements QxType {
+
+ public static final QxBoolean TRUE = new QxBoolean( true );
+
+ public static final QxBoolean FALSE = new QxBoolean( false );
+
+ private static final String[] VALID_TRUE_STRINGS = new String[] {
+ "true", "yes", "on"
+ };
+
+ private static final String[] VALID_FALSE_STRINGS = new String[] {
+ "false", "no", "off"
+ };
+
+ public final boolean value;
+
+ private QxBoolean( final boolean value ) {
+ this.value = value;
+ }
+
+ public static QxBoolean valueOf( final String input ) {
+ return evalInput( input ) ? TRUE : FALSE;
+ }
+
+ public String toDefaultString() {
+ return value ? VALID_TRUE_STRINGS[ 0 ] : VALID_FALSE_STRINGS[ 0 ];
+ }
+
+ public String toString () {
+ return "QxBoolean{ "
+ + String.valueOf( value )
+ + " }";
+ }
+
+ private static boolean evalInput( final String input ) {
+ boolean result = false;
+ if( input == null ) {
+ throw new NullPointerException( "null argument" );
+ }
+ boolean found = false;
+ for( int i = 0; i < VALID_TRUE_STRINGS.length && !found; i++ ) {
+ if( VALID_TRUE_STRINGS[ i ].equals( input ) ) {
+ result = true;
+ found = true;
+ }
+ }
+ for( int i = 0; i < VALID_FALSE_STRINGS.length && !found; i++ ) {
+ if( VALID_FALSE_STRINGS[ i ].equals( input ) ) {
+ found = true;
+ }
+ }
+ if( !found ) {
+ String mesg = "Illegal boolean value: ''{0}''";
+ Object[] arguments = new Object[] { input };
+ String message = MessageFormat.format( mesg, arguments );
+ throw new IllegalArgumentException( message );
+ }
+ return result;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/QxBorder.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/QxBorder.java
new file mode 100644
index 0000000..c4d6d53
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/QxBorder.java
@@ -0,0 +1,268 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme;
+
+public class QxBorder implements QxType {
+
+ public static final QxBorder NONE = new QxBorder( 0, null, null );
+
+ public static final String[] VALID_STYLES = new String[] {
+ "none",
+ "hidden",
+ "dotted",
+ "dashed",
+ "solid",
+ "double",
+ "groove",
+ "ridge",
+ "inset",
+ "outset"
+ };
+
+ // TODO [rst] Implement properties for left, right, etc.
+
+ private static final String DARKSHADOW_LIGHTSHADOW
+ = getBorderColors( "widget.darkshadow", "widget.lightshadow" );
+
+ private static final String LIGHTSHADOW_DARKSHADOW
+ = getBorderColors( "widget.lightshadow", "widget.darkshadow" );
+
+ private static final String SHADOW_HIGHLIGHT
+ = getBorderColors( "widget.shadow", "widget.highlight" );
+
+ private static final String HIGHLIGHT_SHADOW
+ = getBorderColors( "widget.highlight", "widget.shadow" );
+
+ public final int width;
+
+ public final String style;
+
+ // TODO [rst] Color is either a valid color string or a named color from the
+ // color theme. Check for valid colors.
+ public final String color;
+
+ private QxBorder( final int width, final String style, final String color ) {
+ this.width = width;
+ this.style = style;
+ this.color = color;
+ }
+
+ public static QxBorder create( final int width,
+ final String style,
+ final String color )
+ {
+ QxBorder result;
+ if( width == 0 || "none".equals( style ) || "hidden".equals( style ) ) {
+ result = NONE;
+ } else {
+ result = new QxBorder( width, style == null ? "solid" : style, color );
+ }
+ return result;
+ }
+
+ public static QxBorder valueOf( final String input ) {
+ if( input == null ) {
+ throw new NullPointerException( "null argument" );
+ }
+ String[] parts = input.split( "\\s+" );
+ if( input.trim().length() == 0 ) {
+ throw new IllegalArgumentException( "Empty border definition" );
+ }
+ if( parts.length > 3 ) {
+ throw new IllegalArgumentException( "Illegal number of arguments for border" );
+ }
+ int width = -1;
+ String style = null;
+ String color = null;
+ for( int i = 0; i < parts.length; i++ ) {
+ String part = parts[ i ];
+ boolean consumed = "".equals( part );
+ // parse width
+ if( !consumed && width == -1 ) {
+ Integer parsedWidth = QxDimension.parseLength( part );
+ if( parsedWidth != null ) {
+ if( parsedWidth.intValue() < 0 ) {
+ throw new IllegalArgumentException( "Negative width: " + part );
+ }
+ width = parsedWidth.intValue();
+ consumed = true;
+ }
+ }
+ // parse style
+ if( !consumed && style == null ) {
+ String parsedStyle = parseStyle( part );
+ if( parsedStyle != null ) {
+ style = parsedStyle;
+ consumed = true;
+ }
+ }
+ // parse color
+ if( !consumed && color == null ) {
+ color = part;
+ consumed = true;
+ }
+ if( !consumed ) {
+ throw new IllegalArgumentException( "Illegal parameter for color: "
+ + part );
+ }
+ }
+ if( width == -1 ) {
+ width = 1;
+ }
+ return QxBorder.create( width, style, color );
+ }
+
+ public String getQxStyle() {
+ String result = style;
+ if( color == null ) {
+ if( ( "outset".equals( style ) || "inset".equals( style ) )
+ && ( width == 1 || width == 2 ) )
+ {
+ result = "solid";
+ } else if( ( "ridge".equals( style ) || "groove".equals( style ) )
+ && width == 2 )
+ {
+ result = "solid";
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the colors to pass to qx for use default widget colors for 3d
+ * borders. When a 3d border style is used and no color has been set, this
+ * method returns an array of the default widget colors for the style.
+ */
+ public String getQxColors() {
+ String result = null;
+ if( color == null && width == 2 ) {
+ if( "outset".equals( style ) ) {
+ result = LIGHTSHADOW_DARKSHADOW;
+ } else if( "inset".equals( style ) ) {
+ result = SHADOW_HIGHLIGHT;
+ } else if( "ridge".equals( style ) ) {
+ result = HIGHLIGHT_SHADOW;
+ } else if( "groove".equals( style ) ) {
+ result = SHADOW_HIGHLIGHT;
+ }
+ } else if( color == null && width == 1 ) {
+ if( "outset".equals( style ) ) {
+ result = HIGHLIGHT_SHADOW;
+ } else if( "inset".equals( style ) ) {
+ result = SHADOW_HIGHLIGHT;
+ }
+ }
+ if( result == null ) {
+ result = color == null ? null : "\"" + color + "\"";
+ }
+ return result;
+ }
+
+ /**
+ * Returns the inner colors to pass to qx for use default widget colors for 3d
+ * borders. When a 3d border style is used and no color has been set, this
+ * method returns an array of the default widget colors for the style.
+ */
+ public String getQxInnerColors() {
+ String result = null;
+ if( color == null && width == 2 ) {
+ if( "outset".equals( style ) ) {
+ result = HIGHLIGHT_SHADOW;
+ } else if( "inset".equals( style ) ) {
+ result = DARKSHADOW_LIGHTSHADOW;
+ } else if( "ridge".equals( style ) ) {
+ result = SHADOW_HIGHLIGHT;
+ } else if( "groove".equals( style ) ) {
+ result = HIGHLIGHT_SHADOW;
+ }
+ }
+ return result;
+ }
+
+ public String toDefaultString() {
+ StringBuffer result = new StringBuffer();
+ if( width == 0 ) {
+ result.append( "none" );
+ } else {
+ result.append( width + "px" );
+ result.append( " " );
+ result.append( style );
+ if( color != null ) {
+ result.append( " " );
+ result.append( color );
+ }
+ }
+ return result.toString();
+ }
+
+ public boolean equals( final Object object ) {
+ // TODO [rst] Adapt this method as soon as properties for left, right, etc. exist
+ boolean result = false;
+ if( object == this ) {
+ result = true;
+ } else if( object instanceof QxBorder ) {
+ QxBorder other = ( QxBorder )object;
+ result = other.width == this.width
+ && ( style == null
+ ? other.style == null
+ : style.equals( other.style ) )
+ && ( color == null
+ ? other.color == null
+ : color.equals( other.color ) );
+ }
+ return result;
+ }
+
+ public int hashCode() {
+ // TODO [rst] Adapt this method as soon as properties for left, right, etc.
+ // exist
+ int result = 23;
+ result += 37 * result + width;
+ if( style != null ) {
+ result += 37 * result + style.hashCode();
+ }
+ if( color != null ) {
+ result += 37 * result + color.hashCode();
+ }
+ return result;
+ }
+
+ public String toString() {
+ // TODO [rst] Adapt this method as soon as properties for left, right, etc.
+ // exist
+ return "QxBorder{ " + width + ", " + style + ", " + color + " }";
+ }
+
+ private static String getBorderColors( final String color1, final String color2 ) {
+ StringBuffer result = new StringBuffer();
+ result.append( "[ \"");
+ result.append( color1 );
+ result.append( "\", \"");
+ result.append( color2 );
+ result.append( "\", \"");
+ result.append( color2 );
+ result.append( "\", \"");
+ result.append( color1 );
+ result.append( "\" ]");
+ return result.toString();
+ }
+
+ private static String parseStyle( final String part ) {
+ String result = null;
+ for( int j = 0; j < VALID_STYLES.length && result == null; j++ ) {
+ if( VALID_STYLES[ j ].equalsIgnoreCase( part ) ) {
+ result = VALID_STYLES[ j ];
+ }
+ }
+ return result;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/QxBoxDimensions.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/QxBoxDimensions.java
new file mode 100644
index 0000000..dbc38d9
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/QxBoxDimensions.java
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme;
+
+import org.eclipse.swt.graphics.Rectangle;
+
+public class QxBoxDimensions implements QxType {
+
+ public static final QxBoxDimensions ZERO = new QxBoxDimensions( 0, 0, 0, 0 );
+
+ public final int top;
+
+ public final int right;
+
+ public final int bottom;
+
+ public final int left;
+
+ private QxBoxDimensions( final int top,
+ final int right,
+ final int bottom,
+ final int left )
+ {
+ this.top = top;
+ this.right = right;
+ this.bottom = bottom;
+ this.left = left;
+ }
+
+ public static QxBoxDimensions create( final int top,
+ final int right,
+ final int bottom,
+ final int left )
+ {
+ QxBoxDimensions result;
+ if( top == 0 && right == 0 && bottom == 0 && left == 0 ) {
+ result = ZERO;
+ } else {
+ result = new QxBoxDimensions( top, right, bottom, left );
+ }
+ return result;
+ }
+
+ public static QxBoxDimensions valueOf( final String input ) {
+ if( input == null ) {
+ throw new NullPointerException( "null argument" );
+ }
+ String[] parts = input.split( "\\s+" );
+ if( parts.length == 0 || parts.length > 4 ) {
+ String msg = "Illegal number of arguments for box dimensions";
+ throw new IllegalArgumentException( msg );
+ }
+ int top, right, left, bottom;
+ top = right = bottom = left = parsePxValue( parts[ 0 ] );
+ if( parts.length >= 2 ) {
+ right = left = parsePxValue( parts[ 1 ] );
+ }
+ if( parts.length >= 3 ) {
+ bottom = parsePxValue( parts[ 2 ] );
+ }
+ if( parts.length == 4 ) {
+ left = parsePxValue( parts[ 3 ] );
+ }
+ return create( top, right, bottom, left );
+ }
+
+ /**
+ * Returns <code>left + right</code> for convenience.
+ */
+ public int getWidth() {
+ return left + right;
+ }
+
+ /**
+ * Returns <code>top + bottom</code> for convenience.
+ */
+ public int getHeight() {
+ return top + bottom;
+ }
+
+ public String toJsArray() {
+ return "[ " + top + ", " + right + ", " + bottom + ", " + left + " ]";
+ }
+
+ public String toDefaultString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append( top + "px" );
+ if( right != top || bottom != top || left != top ) {
+ buffer.append( " " + right + "px" );
+ }
+ if( bottom != top || left != right ) {
+ buffer.append( " " + bottom + "px" );
+ }
+ if( left != right ) {
+ buffer.append( " " + left + "px" );
+ }
+ return buffer.toString();
+ }
+
+ public boolean equals( final Object object ) {
+ boolean result = false;
+ if( object == this ) {
+ result = true;
+ } else if( object instanceof QxBoxDimensions ) {
+ QxBoxDimensions other = (QxBoxDimensions)object;
+ result = ( other.top == this.top )
+ && ( other.right == this.right )
+ && ( other.bottom == this.bottom )
+ && ( other.left == this.left );
+ }
+ return result;
+}
+
+ public int hashCode () {
+ int result = 911;
+ result += 23 * result + top;
+ result += 23 * result + right;
+ result += 23 * result + bottom;
+ result += 23 * result + left;
+ return result;
+ }
+
+ public String toString () {
+ return "QxBoxDimensions{ "
+ + top
+ + ", "
+ + right
+ + ", "
+ + bottom
+ + ", "
+ + left
+ + " }";
+ }
+
+ private static int parsePxValue( final String part ) {
+ Integer result = QxDimension.parseLength( part );
+ if( result == null ) {
+ throw new IllegalArgumentException( "Illegal parameter: " + part );
+ }
+ return result.intValue();
+ }
+
+ public static Rectangle createRectangle( final QxBoxDimensions boxdim ) {
+ return new Rectangle( boxdim.left,
+ boxdim.top,
+ boxdim.left + boxdim.right,
+ boxdim.top + boxdim.bottom );
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/QxColor.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/QxColor.java
new file mode 100644
index 0000000..2866522
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/QxColor.java
@@ -0,0 +1,188 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme;
+
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.Map;
+
+public class QxColor implements QxType {
+
+ private static final String TRANSPARENT_STR = "transparent";
+
+ private static final Map NAMED_COLORS = new HashMap();
+
+ public static final QxColor BLACK = new QxColor( 0, 0, 0 );
+
+ public static final QxColor WHITE = new QxColor( 255, 255, 255 );
+
+ public static final QxColor TRANSPARENT = new QxColor();
+
+ public final int red;
+
+ public final int green;
+
+ public final int blue;
+
+ public final boolean transparent;
+
+ static {
+ // register 16 standard HTML colors
+ NAMED_COLORS.put( "black", new int[] { 0, 0, 0 } );
+ NAMED_COLORS.put( "gray", new int[] { 128, 128, 128 } );
+ NAMED_COLORS.put( "silver", new int[] { 192, 192, 192 } );
+ NAMED_COLORS.put( "white", new int[] { 255, 255, 255 } );
+ NAMED_COLORS.put( "maroon", new int[] { 128, 0, 0 } );
+ NAMED_COLORS.put( "red", new int[] { 255, 0, 0 } );
+ NAMED_COLORS.put( "purple", new int[] { 128, 0, 128 } );
+ NAMED_COLORS.put( "fuchsia", new int[] { 255, 0, 255 } );
+ NAMED_COLORS.put( "green", new int[] { 0, 128, 0 } );
+ NAMED_COLORS.put( "lime", new int[] { 0, 255, 0 } );
+ NAMED_COLORS.put( "navy", new int[] { 0, 0, 128 } );
+ NAMED_COLORS.put( "blue", new int[] { 0, 0, 255 } );
+ NAMED_COLORS.put( "olive", new int[] { 128, 128, 0 } );
+ NAMED_COLORS.put( "yellow", new int[] { 255, 255, 0 } );
+ NAMED_COLORS.put( "teal", new int[] { 0, 128, 128 } );
+ NAMED_COLORS.put( "aqua", new int[] { 0, 255, 255 } );
+ }
+
+ private QxColor() {
+ this.red = 0;
+ this.green = 0;
+ this.blue = 0;
+ this.transparent = true;
+ }
+
+ private QxColor( final int red, final int green, final int blue ) {
+ this.red = red;
+ this.green = green;
+ this.blue = blue;
+ this.transparent = false;
+ }
+
+ public static QxColor create( final int red, final int green, final int blue )
+ {
+ QxColor result;
+ if( red == 0 && green == 0 && blue == 0 ) {
+ result = BLACK;
+ } else if( red == 255 && green == 255 && blue == 255 ) {
+ result = WHITE;
+ } else {
+ result = new QxColor( red, green, blue );
+ }
+ return result;
+ }
+
+ public static QxColor valueOf( final String input ) {
+ QxColor result;
+ if( input == null ) {
+ throw new NullPointerException( "null argument" );
+ }
+ if( TRANSPARENT_STR.equals( input ) ) {
+ result = TRANSPARENT;
+ } else {
+ int red, green, blue;
+ if( input.startsWith( "#" ) ) {
+ try {
+ if( input.length() == 7 ) {
+ red = Integer.parseInt( input.substring( 1, 3 ), 16 );
+ green = Integer.parseInt( input.substring( 3, 5 ), 16 );
+ blue = Integer.parseInt( input.substring( 5, 7 ), 16 );
+ } else if( input.length() == 4 ) {
+ red = Integer.parseInt( input.substring( 1, 2 ), 16 ) * 17;
+ green = Integer.parseInt( input.substring( 2, 3 ), 16 ) * 17;
+ blue = Integer.parseInt( input.substring( 3, 4 ), 16 ) * 17;
+ } else {
+ String pattern = "Illegal number of characters in color definition ''{0}''";
+ Object[] arguments = new Object[] { input };
+ String message = MessageFormat.format( pattern, arguments );
+ throw new IllegalArgumentException( message );
+ }
+ } catch( final NumberFormatException e ) {
+ String pattern = "Illegal number format in color definition ''{0}''";
+ Object[] arguments = new Object[] { input };
+ String message = MessageFormat.format( pattern, arguments );
+ throw new IllegalArgumentException( message );
+ }
+ } else if( NAMED_COLORS.containsKey( input.toLowerCase() ) ) {
+ int[] values = ( int[] )NAMED_COLORS.get( input.toLowerCase() );
+ red = values[ 0 ];
+ green = values[ 1 ];
+ blue = values[ 2 ];
+ } else {
+ String[] parts = input.split( "\\s*,\\s*" );
+ if( parts.length == 3 ) {
+ try {
+ red = Integer.parseInt( parts[ 0 ] );
+ green = Integer.parseInt( parts[ 1 ] );
+ blue = Integer.parseInt( parts[ 2 ] );
+ } catch( final NumberFormatException e ) {
+ String pattern = "Illegal number format in color definition ''{0}''";
+ Object[] arguments = new Object[] { input };
+ String message = MessageFormat.format( pattern, arguments );
+ throw new IllegalArgumentException( message );
+ }
+ } else {
+ String pattern = "Invalid color name ''{0}''";
+ Object[] arguments = new Object[] { input };
+ String message = MessageFormat.format( pattern, arguments );
+ throw new IllegalArgumentException( message );
+ }
+ }
+ result = create( red, green, blue );
+ }
+ return result;
+ }
+
+ public String toDefaultString() {
+ return transparent ? TRANSPARENT_STR : toHtmlString( red, green, blue );
+ }
+
+ public boolean equals( final Object obj ) {
+ boolean result = false;
+ if( obj == this ) {
+ result = true;
+ } else if( obj instanceof QxColor ) {
+ QxColor other = ( QxColor )obj;
+ result = other.red == red
+ && other.green == green
+ && other.blue == blue;
+ }
+ return result;
+ }
+
+ public int hashCode() {
+ return transparent ? -1 : red + green * 256 + blue * 65536;
+ }
+
+ public String toString() {
+ String colors = red + ", " + green + ", " + blue;
+ return "QxColor{ " + ( transparent ? TRANSPARENT_STR : colors ) + " }";
+ }
+
+ public static String toHtmlString( final int red,
+ final int green,
+ final int blue )
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append( "#" );
+ sb.append( getHexStr( red ) );
+ sb.append( getHexStr( green ) );
+ sb.append( getHexStr( blue ) );
+ return sb.toString();
+ }
+
+ private static String getHexStr( final int value ) {
+ String hex = Integer.toHexString( value );
+ return hex.length() == 1 ? "0" + hex : hex;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/QxDimension.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/QxDimension.java
new file mode 100644
index 0000000..58283bd
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/QxDimension.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class QxDimension implements QxType {
+
+ public static final QxDimension ZERO = new QxDimension( 0 );
+
+ private static final Pattern LENGTH_PATTERN
+ = Pattern.compile( "((\\+|-)?\\d+)(em|ex|px|pt|pc|in|cm|mm|%)?" );
+
+ public final int value;
+
+ private QxDimension( final int value ) {
+ this.value = value;
+ }
+
+ public static QxDimension create( final int value ) {
+ QxDimension result;
+ if( value == 0 ) {
+ result = ZERO;
+ } else {
+ result = new QxDimension( value );
+ }
+ return result;
+ }
+
+ public static QxDimension valueOf( final String input ) {
+ if( input == null ) {
+ throw new NullPointerException( "null argument" );
+ }
+ Integer parsed = parseLength( input );
+ if( parsed == null ) {
+ throw new IllegalArgumentException( "Illegal dimension parameter: " + input );
+ }
+ return create( parsed.intValue() );
+ }
+
+ public String toDefaultString() {
+ return value + "px";
+ }
+
+ public boolean equals( final Object object ) {
+ boolean result = false;
+ if( object == this ) {
+ result = true;
+ } else if( object instanceof QxDimension ) {
+ QxDimension other = (QxDimension)object;
+ result = ( other.value == this.value );
+ }
+ return result;
+ }
+
+ public int hashCode () {
+ return value * 47;
+ }
+
+ public String toString () {
+ return "QxDimension{ "
+ + value
+ + " }";
+ }
+
+ /**
+ * Tries to interpret a string as length parameter.
+ *
+ * @return the parsed length as integer, or <code>null</code> if the string
+ * could not be parsed.
+ * @throws IllegalArgumentException if the string is valid CSS length
+ * parameter that is a percentage value or has an unsupported
+ * unit.
+ */
+ static Integer parseLength( final String input ) {
+ // TODO [rst] Also catch values with fractional digits
+ Integer result = null;
+ Matcher matcher = LENGTH_PATTERN.matcher( input );
+ if( matcher.matches() ) {
+ result = Integer.valueOf( matcher.group( 1 ) );
+ String unit = matcher.group( 3 );
+ if( unit != null && "%".equals( unit ) ) {
+ throw new IllegalArgumentException( "Percentages not supported: " + input );
+ }
+ if( unit != null && !"px".equals( unit ) ) {
+ throw new IllegalArgumentException( "Unit not supported: " + input );
+ }
+ }
+ return result;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/QxFont.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/QxFont.java
new file mode 100644
index 0000000..9a410f2
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/QxFont.java
@@ -0,0 +1,169 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme;
+
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class QxFont implements QxType {
+
+ private static final Pattern FONT_DEF_PATTERN
+ = Pattern.compile( "(\".+?\"|'.+?'|\\S[^\\s,]+)(\\s*,)?" );
+
+ public final String[] family;
+
+ public final int size;
+
+ public final boolean bold;
+
+ public final boolean italic;
+
+ private String familyAsString;
+
+ private QxFont( final String[] family,
+ final int size,
+ final boolean bold,
+ final boolean italic )
+ {
+ this.family = family;
+ this.size = size;
+ this.bold = bold;
+ this.italic = italic;
+ }
+
+ public static QxFont create( final String[] families,
+ final int size,
+ final boolean bold,
+ final boolean italic )
+ {
+ if( size < 0 ) {
+ throw new IllegalArgumentException( "Negative width: " + size );
+ }
+ return new QxFont( families, size, bold, italic );
+ }
+
+ public static QxFont valueOf( final String input ) {
+ if( input == null ) {
+ throw new NullPointerException( "null argument" );
+ }
+ if( input.trim().length() == 0 ) {
+ throw new IllegalArgumentException( "Empty font definition" );
+ }
+ List family = new ArrayList();
+ int size = 0;
+ boolean bold = false;
+ boolean italic = false;
+
+ Matcher matcher = FONT_DEF_PATTERN.matcher( input );
+ while( matcher.find() ) {
+ String part = matcher.group( 1 );
+ char c = part.charAt( 0 );
+ if( c == '"' || c == '\'' ) {
+ part = part.substring( 1, part.length() - 1 );
+ }
+// boolean hasComma = matcher.group( 2 ) != null;
+ if( "bold".equalsIgnoreCase( part ) ) {
+ bold = true;
+ } else if( "italic".equalsIgnoreCase( part ) ) {
+ italic = true;
+ } else {
+ Integer parsedSize = QxDimension.parseLength( part );
+ if( parsedSize != null ) {
+ size = parsedSize.intValue();
+ } else {
+ // TODO [rst] Check commas
+ family.add( part );
+ }
+ }
+ }
+ // TODO [rst] Check for illegal input and throw exception
+ String[] familyArr = ( String[] )family.toArray( new String[ family.size() ] );
+ return new QxFont( familyArr, size, bold, italic ) ;
+ }
+
+ public String getFamilyAsString() {
+ if( familyAsString == null ) {
+ StringBuffer buffer = new StringBuffer();
+ for( int i = 0; i < family.length; i++ ) {
+ if( i > 0 ) {
+ buffer.append( ", " );
+ }
+ boolean hasSpace = family[ i ].indexOf( ' ' ) != -1;
+ if( hasSpace ) {
+ buffer.append( "\"" );
+ }
+ buffer.append( family[ i ] );
+ if( hasSpace ) {
+ buffer.append( "\"" );
+ }
+ }
+ familyAsString = buffer.toString();
+ }
+ return familyAsString;
+ }
+
+ public String toDefaultString() {
+ StringBuffer result = new StringBuffer();
+ if( bold ) {
+ result.append( "bold " );
+ }
+ if( italic ) {
+ result.append( "italic " );
+ }
+ result.append( size );
+ result.append( "px " );
+ result.append( getFamilyAsString() );
+ return result.toString();
+ }
+
+ public boolean equals( final Object obj ) {
+ boolean result = false;
+ if( obj == this ) {
+ result = true;
+ } else if( obj instanceof QxFont ) {
+ QxFont other = ( QxFont )obj;
+ result = Arrays.equals( other.family, family )
+ && other.size == size
+ && other.bold == bold
+ && other.italic == italic;
+ }
+ return result;
+ }
+
+ public int hashCode() {
+ int result = 23;
+ for( int i = 0; i < family.length; i++ ) {
+ result += 37 * result + family[ i ].hashCode();
+ }
+ result += 37 * result + size;
+ result += bold ? 0 : 37 * result + 41;
+ result += italic ? 0 : 37 * result + 43;
+ return result;
+ }
+
+ public String toString() {
+ StringBuffer result = new StringBuffer();
+ result.append( "QxFont{ " );
+ if( bold ) {
+ result.append( "bold " );
+ }
+ if( italic ) {
+ result.append( "italic " );
+ }
+ result.append( size );
+ result.append( "px " );
+ result.append( getFamilyAsString() );
+ result.append( " }" );
+ return result.toString();
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/QxImage.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/QxImage.java
new file mode 100644
index 0000000..ed11700
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/QxImage.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme;
+
+public final class QxImage implements QxType {
+
+ private static final String NONE_INPUT = "none";
+
+ public static final QxImage NONE = new QxImage( true, null, null );
+
+ public final boolean none;
+
+ public final String path;
+
+ public final ResourceLoader loader;
+
+ /**
+ * Creates a new image from the given value.
+ *
+ * @param path the definition string to create the image from. Either
+ * <code>none</code> or a path to an image
+ * @param loader a resource loader which is able to load the image from the
+ * given path
+ */
+ private QxImage( final boolean none,
+ final String path,
+ final ResourceLoader loader )
+ {
+ this.none = none;
+ this.path = path;
+ this.loader = loader;
+ }
+
+ public static QxImage valueOf( final String input, final ResourceLoader loader )
+ {
+ QxImage result;
+ if( NONE_INPUT.equals( input ) ) {
+ result = NONE;
+ } else {
+ if( input == null || loader == null ) {
+ throw new NullPointerException( "null argument" );
+ }
+ if( input.length() == 0 ) {
+ throw new IllegalArgumentException( "Empty image path" );
+ }
+ result = new QxImage( false, input, loader );
+ }
+ return result;
+ }
+
+ public String toDefaultString() {
+ // returns an empty string, because the default resource path is only valid
+ // for the bundle that specified it
+ return none ? NONE_INPUT : "";
+ }
+
+ public boolean equals( final Object object ) {
+ boolean result = false;
+ if( object == this ) {
+ result = true;
+ } else if( object instanceof QxImage ) {
+ QxImage other = ( QxImage )object;
+ result = path != null
+ && path.equals( other.path )
+ && loader != null
+ && loader.equals( other.loader );
+ }
+ return result;
+ }
+
+ public int hashCode() {
+ return path.hashCode();
+ }
+
+ public String toString() {
+ return "QxImage{ "
+ + ( none ? NONE_INPUT : path )
+ + " }";
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/QxTheme.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/QxTheme.java
new file mode 100644
index 0000000..b8f9c8b
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/QxTheme.java
@@ -0,0 +1,319 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme;
+
+
+/**
+ * Instances of this class represent a qooxdoo theme of a certain type. Used to
+ * assemble the Javascript code for qooxdoo themes.
+ */
+public class QxTheme {
+
+ private final String id;
+
+ private final String title;
+
+ private final int type;
+
+ private final String base;
+
+ private final StringBuffer code;
+
+ private boolean headWritten;
+
+ private boolean tailWritten;
+
+ private boolean valueWritten;
+
+ /** Type for qooxdoo meta themes */
+ public static final int META = 1;
+
+ /** Type for qooxdoo font themes */
+ public static final int FONT = 2;
+
+ /** Type for qooxdoo color themes */
+ public static final int COLOR = 3;
+
+ /** Type for qooxdoo border themes */
+ public static final int BORDER = 4;
+
+ /** Type for qooxdoo icon themes */
+ public static final int ICON = 5;
+
+ /** Type for qooxdoo widget themes */
+ public static final int WIDGET = 6;
+
+ /** Type for qooxdoo apearance themes */
+ public static final int APPEARANCE = 7;
+
+ /**
+ * Creates a new qooxdoo theme with the given, id, name, and type.
+ *
+ * @param id the fully qualified qx class name for the theme
+ * @param title the name of the theme
+ * @param type the type of the theme
+ */
+ public QxTheme( final String id, final String title, final int type ) {
+ this( id, title, type, null );
+ }
+
+ /**
+ * Creates a new qooxdoo theme with the given, id, name, type, and base class.
+ *
+ * @param id the fully qualified qx class name for the theme
+ * @param title the name of the theme
+ * @param type the type of the theme
+ * @param base the fully qualified name of the qx theme to extend
+ */
+ public QxTheme( final String id,
+ final String title,
+ final int type,
+ final String base )
+ {
+ this.id = id;
+ this.title = title;
+ this.type = checkType( type );
+ this.base = base;
+ this.code = new StringBuffer();
+ headWritten = false;
+ tailWritten = false;
+ valueWritten = false;
+ }
+
+ /**
+ * Appends a number of key-value pairs to the generated theme. The given
+ * Javascript code is appended as is, without any checks being performed.
+ *
+ * @param values Javascript code that adds the additional values
+ */
+ public void appendValues( final String values ) {
+ beforeWriteValue();
+ code.append( values );
+ afterWriteValue();
+ }
+
+ /**
+ * Appends a key-value pair to the generated font theme. Only applicable for
+ * instances with type FONT.
+ *
+ * @param key the key to append
+ * @param font the value for the key
+ */
+ public void appendFont( final String key, final QxFont font ) {
+ beforeWriteValue();
+ code.append( " \"" + key + "\" : { " );
+ code.append( "family: [" );
+ for( int i = 0; i < font.family.length; i++ ) {
+ if( i > 0 ) {
+ code.append( " ," );
+ }
+ code.append( "\"" );
+ code.append( font.family[ i ] );
+ code.append( "\"" );
+ }
+ code.append( "]" );
+ code.append( ", size: " );
+ code.append( font.size );
+ if( font.bold ) {
+ code.append( ", bold: true" );
+ }
+ if( font.italic ) {
+ code.append( ", italic: true" );
+ }
+ code.append( " }" );
+ afterWriteValue();
+ }
+
+ /**
+ * Appends a key-value pair to the generated color theme. Only applicable for
+ * instances with type COLOR.
+ *
+ * @param key the key to append
+ * @param color the value for the key
+ */
+ public void appendColor( final String key, final QxColor color ) {
+ beforeWriteValue();
+ code.append( " \"" + key + "\" : " );
+ code.append( "[ " );
+ code.append( color.red );
+ code.append( ", " );
+ code.append( color.green );
+ code.append( ", " );
+ code.append( color.blue );
+ code.append( " ]" );
+ afterWriteValue();
+ }
+
+ /**
+ * Appends a key-value pair to the generated border theme. Only applicable for
+ * instances with type BORDER.
+ *
+ * @param key the key to append
+ * @param border the value for the key
+ */
+ public void appendBorder( final String key, final QxBorder border ) {
+ beforeWriteValue();
+ code.append( " \"" + key + "\" : " );
+ // none
+ code.append( "{ width : " );
+ code.append( border.width );
+ String style = border.getQxStyle();
+ if( style != null && !"solid".equals( style ) ) {
+ code.append( ", style : \"" );
+ code.append( style );
+ code.append( "\"" );
+ }
+ String colors = border.getQxColors();
+ if( colors != null ) {
+ code.append( ", color : " );
+ code.append( colors );
+ }
+ String innerColor = border.getQxInnerColors();
+ if( innerColor != null ) {
+ code.append( ", innerColor : " );
+ code.append( innerColor );
+ }
+ code.append( " }" );
+ afterWriteValue();
+ }
+
+ /**
+ * Appends the single uri entry to the generated widget or icon theme. Only
+ * applicable for instances with type WIDGET or ICON.
+ *
+ * @param pathPrefix the prefix to map "widget/" or "icon/" to
+ */
+ public void appendUri( final String pathPrefix ) {
+ beforeWriteValue();
+ code.append( " \"uri\" : \"" );
+ code.append( pathPrefix );
+ code.append( "\"" );
+ afterWriteValue();
+ }
+
+ /**
+ * Appends a key-value pair to the generated theme. Only applicable for
+ * META theme writers.
+ *
+ * @param key the key to append
+ * @param theme the value for the key
+ */
+ public void appendTheme( final String key, final String theme ) {
+ beforeWriteValue();
+ code.append( " \"" + key + "\" : " );
+ code.append( theme );
+ afterWriteValue();
+ }
+
+ /**
+ * Returns the Javascript code that represents this theme. Once this method
+ * has been called, no values can be appended anymore.
+ *
+ * @return the generated theme code.
+ */
+ public String getJsCode() {
+ if( !headWritten ) {
+ writeHead();
+ }
+ if( !tailWritten ) {
+ writeTail();
+ }
+ return code.toString();
+ }
+
+ private void beforeWriteValue() {
+ if( !headWritten ) {
+ writeHead();
+ }
+ if( tailWritten ) {
+ throw new IllegalStateException( "Tail already written" );
+ }
+ if( valueWritten ) {
+ code.append( ",\n" );
+ }
+ }
+
+ private void afterWriteValue() {
+ valueWritten = true;
+ }
+
+ private void writeHead() {
+ code.append( "/* RAP theme file generated by QxTheme. */\n" );
+ code.append( "qx.Theme.define( \"" + id + getNameSuffix() + "\",\n" );
+ code.append( "{\n" );
+ code.append( " title : \"" + title + "\",\n" );
+ if( base != null ) {
+ code.append( " extend : " + base + ",\n" );
+ }
+ code.append( " " + getThemeKey() + " : {\n" );
+ headWritten = true;
+ }
+
+ private void writeTail() {
+ code.append( "\n" );
+ code.append( " }\n" );
+ code.append( "} );\n" );
+ tailWritten = true;
+ }
+
+ private int checkType( final int type ) {
+ if( type != META
+ && type != FONT
+ && type != COLOR
+ && type != BORDER
+ && type != ICON
+ && type != WIDGET
+ && type != APPEARANCE )
+ {
+ throw new IllegalArgumentException( "illegal type" );
+ }
+ return type;
+ }
+
+ private String getNameSuffix() {
+ String result = "";
+ if( type == FONT ) {
+ result = "Fonts";
+ } else if( type == COLOR ) {
+ result = "Colors";
+ } else if( type == BORDER ) {
+ result = "Borders";
+ } else if( type == ICON ) {
+ result = "Icons";
+ } else if( type == WIDGET ) {
+ result = "Widgets";
+ } else if( type == APPEARANCE ) {
+ result = "Appearances";
+ }
+ return result;
+ }
+
+ private String getThemeKey() {
+ String result = null;
+ if( type == META ) {
+ result = "meta";
+ } else if( type == FONT ) {
+ result = "fonts";
+ } else if( type == COLOR ) {
+ result = "colors";
+ } else if( type == BORDER ) {
+ result = "borders";
+ } else if( type == ICON ) {
+ result = "icons";
+ } else if( type == WIDGET ) {
+ result = "widgets";
+ } else if( type == APPEARANCE ) {
+ result = "appearances";
+ }
+ return result;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/QxType.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/QxType.java
new file mode 100644
index 0000000..641a4fd
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/QxType.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme;
+
+public interface QxType {
+
+ /**
+ * Returns a default representation of the value, that can also be applied to
+ * the constructor. The returned value is also a valid notation for RAP theme
+ * files.
+ */
+ public abstract String toDefaultString();
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/ResourceLoader.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/ResourceLoader.java
new file mode 100644
index 0000000..9c210e4
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/ResourceLoader.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public interface ResourceLoader {
+
+ InputStream getResourceAsStream( String resourceName ) throws IOException;
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/ThemeDefElement.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/ThemeDefElement.java
new file mode 100644
index 0000000..f4db40f
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/ThemeDefElement.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme;
+
+import java.util.Map;
+
+public class ThemeDefElement {
+
+ public final String name;
+ public final String description;
+ public final ThemeDefProperty[] properties;
+ public final Map styleMap;
+ public final Map stateMap;
+
+ public ThemeDefElement( final String name,
+ final String description,
+ final ThemeDefProperty[] properties,
+ final Map styleMap,
+ final Map stateMap )
+ {
+ this.name = name;
+ this.description = description;
+ this.properties = properties;
+ this.styleMap = styleMap;
+ this.stateMap = stateMap;
+ }
+
+
+
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/ThemeDefElementWrapper.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/ThemeDefElementWrapper.java
new file mode 100644
index 0000000..19a9344
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/ThemeDefElementWrapper.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rwt.internal.theme;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class ThemeDefElementWrapper {
+
+ public final ThemeDefElement element;
+ public final ThemeDefElementWrapper parent;
+ private List children;
+
+ public ThemeDefElementWrapper( final ThemeDefElement element,
+ final ThemeDefElementWrapper parent )
+ {
+ this.element = element;
+ this.parent = parent;
+ children = new ArrayList();
+ }
+
+ public void addChildElement( final ThemeDefElementWrapper childElement ) {
+ children.add( childElement );
+ }
+
+ public Object[] getChildren() {
+ return children.toArray();
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/ThemeDefProperty.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/ThemeDefProperty.java
new file mode 100644
index 0000000..3be0846
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/ThemeDefProperty.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme;
+
+public class ThemeDefProperty {
+
+ public final String name;
+ public final String description;
+ public final String[] styles;
+ public final String[] states;
+
+ public ThemeDefProperty( final String name,
+ final String description,
+ final String[] styles,
+ final String[] states )
+ {
+ this.name = name;
+ this.description = description;
+ this.styles = styles;
+ this.states = states;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/ThemeDefinitionProvider.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/ThemeDefinitionProvider.java
new file mode 100644
index 0000000..1c96b49
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/ThemeDefinitionProvider.java
@@ -0,0 +1,246 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rwt.internal.theme;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.rap.themeeditor.editor.source.CSSTokenProvider;
+import org.eclipse.rap.themeeditor.editor.source.region.IRegionExt;
+import org.eclipse.rap.themeeditor.editor.source.region.SelectorRegion;
+import org.eclipse.rap.themeeditor.editor.source.region.StateRegion;
+import org.eclipse.rap.themeeditor.editor.source.region.StyleRegion;
+import org.xml.sax.SAXException;
+
+public class ThemeDefinitionProvider {
+
+ private static final String[] THEME_FILES = {
+ "org/eclipse/swt/internal/widgets/widgetkit/Widget.theme.xml",
+ "org/eclipse/swt/internal/widgets/buttonkit/Button.theme.xml",
+ "org/eclipse/swt/internal/widgets/combokit/Combo.theme.xml",
+ "org/eclipse/swt/internal/widgets/coolbarkit/CoolBar.theme.xml",
+ "org/eclipse/swt/internal/custom/ctabfolderkit/CTabFolder.theme.xml",
+ "org/eclipse/swt/internal/widgets/groupkit/Group.theme.xml",
+ "org/eclipse/swt/internal/widgets/labelkit/Label.theme.xml",
+ "org/eclipse/swt/internal/widgets/linkkit/Link.theme.xml",
+ "org/eclipse/swt/internal/widgets/listkit/List.theme.xml",
+ "org/eclipse/swt/internal/widgets/menukit/Menu.theme.xml",
+ "org/eclipse/swt/internal/widgets/progressbarkit/ProgressBar.theme.xml",
+ "org/eclipse/swt/internal/widgets/shellkit/Shell.theme.xml",
+ "org/eclipse/swt/internal/widgets/spinnerkit/Spinner.theme.xml",
+ "org/eclipse/swt/internal/widgets/tabfolderkit/TabFolder.theme.xml",
+ "org/eclipse/swt/internal/widgets/tablekit/Table.theme.xml",
+ "org/eclipse/swt/internal/widgets/textkit/Text.theme.xml",
+ "org/eclipse/swt/internal/widgets/toolbarkit/ToolBar.theme.xml",
+ "org/eclipse/swt/internal/widgets/treekit/Tree.theme.xml"
+ };
+ private ThemeDefElementWrapper[] content;
+ private Map widgetMap;
+ private static ThemeDefinitionProvider provider = new ThemeDefinitionProvider();
+
+ private ThemeDefinitionProvider() {
+ widgetMap = new HashMap();
+ content = new ThemeDefElementWrapper[ THEME_FILES.length ];
+ for( int i = 0; i < THEME_FILES.length; i++ ) {
+ ThemeDefElementWrapper wrapper = readFile( THEME_FILES[ i ] );
+ content[ i ] = wrapper;
+ widgetMap.put( wrapper.element.name, wrapper );
+ for( int j = 0; j < wrapper.getChildren().length; j++ ) {
+ ThemeDefElementWrapper child = ( ThemeDefElementWrapper )wrapper.getChildren()[ j ];
+ widgetMap.put( child.element.name, child );
+ }
+ }
+ }
+
+ public static ThemeDefElementWrapper[] getContent() {
+ return provider.content;
+ }
+
+ public static String getDescription( final IRegionExt regionExt,
+ final String content )
+ {
+ String result = "";
+ if( regionExt != null && content != null ) {
+ ThemeDefElementWrapper wrapper = getElementWrapper( regionExt );
+ if( wrapper == null ) {
+ wrapper = ( ThemeDefElementWrapper )provider.widgetMap.get( content );
+ }
+ if( wrapper != null ) {
+ String text;
+ switch( regionExt.getTokenType() ) {
+ case CSSTokenProvider.SELECTOR_TOKEN:
+ result = wrapper.element.description;
+ break;
+ case CSSTokenProvider.STATE_TOKEN:
+ text = ( String )wrapper.element.stateMap.get( content );
+ if( text != null ) {
+ result = text;
+ } else {
+ result = "This state is not supported for "
+ + wrapper.element.name
+ + " widgets.";
+ }
+ break;
+ case CSSTokenProvider.STYLE_TOKEN:
+ text = ( String )wrapper.element.styleMap.get( content );
+ if( text != null ) {
+ result = text;
+ } else {
+ result = "This style is not supported for "
+ + wrapper.element.name
+ + " widgets.";
+ }
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ public static String getPropertyDescription( final String widgetName,
+ final String propertyName )
+ {
+ String result = null;
+ ThemeDefElementWrapper wrapper = ( ThemeDefElementWrapper )provider.widgetMap.get( widgetName );
+ if( wrapper != null ) {
+ for( int i = 0; i < wrapper.element.properties.length; i++ ) {
+ ThemeDefProperty property = wrapper.element.properties[ i ];
+ if( property.name.equals( propertyName ) ) {
+ result = property.description;
+ }
+ }
+ }
+ return result;
+ }
+
+ public static ThemeDefElementWrapper getElementWrapper( final IRegionExt regionExt )
+ {
+ ThemeDefElementWrapper result = null;
+ if( regionExt != null ) {
+ SelectorRegion parent;
+ switch( regionExt.getTokenType() ) {
+ case CSSTokenProvider.SELECTOR_TOKEN:
+ result = ( ThemeDefElementWrapper )provider.widgetMap.get( regionExt.getContent()
+ .trim() );
+ break;
+ case CSSTokenProvider.STATE_TOKEN:
+ parent = ( ( StateRegion )regionExt ).getParentRegion();
+ result = ( ThemeDefElementWrapper )provider.widgetMap.get( parent.getContent()
+ .trim() );
+ break;
+ case CSSTokenProvider.STYLE_TOKEN:
+ parent = ( ( StyleRegion )regionExt ).getParentRegion();
+ result = ( ThemeDefElementWrapper )provider.widgetMap.get( parent.getContent()
+ .trim() );
+ break;
+ }
+ }
+ return result;
+ }
+
+ private ThemeDefElementWrapper readFile( final String filename ) {
+ ClassLoader loader = this.getClass().getClassLoader();
+ InputStream is = loader.getResourceAsStream( filename );
+ NewThemeDefinitionReader reader = new NewThemeDefinitionReader( is, "test" );
+ ThemeDefElement[] elements = null;
+ try {
+ elements = reader.read();
+ is.close();
+ } catch( SAXException e ) {
+ e.printStackTrace();
+ } catch( IOException e ) {
+ e.printStackTrace();
+ }
+ ThemeDefElementWrapper result = new ThemeDefElementWrapper( elements[ 0 ],
+ null );
+ for( int i = 1; i < elements.length; i++ ) {
+ result.addChildElement( new ThemeDefElementWrapper( elements[ i ], result ) );
+ }
+ return result;
+ }
+
+ // TODO [mschaeff] do this only once and store in map
+ public static boolean isStyleSupported( final String selector,
+ final String styleName )
+ {
+ ThemeDefElementWrapper[] wrappers = getContent();
+ for( int i = 0; i < wrappers.length; i++ ) {
+ ThemeDefElementWrapper wrapper = wrappers[ i ];
+ if( wrapper.element.name.equals( selector ) ) {
+ for( int j = 0; j < wrapper.element.properties.length; j++ ) {
+ String[] styles = wrapper.element.properties[ j ].styles;
+ for( int k = 0; k < styles.length; k++ ) {
+ if( styles[ k ].equals( styleName ) ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ } else {
+ // check child elements
+ for( int m = 0; m < wrapper.getChildren().length; m++ ) {
+ ThemeDefElementWrapper child = ( ThemeDefElementWrapper )wrapper.getChildren()[ m ];
+ if( child.element.name.equals( selector ) ) {
+ for( int j = 0; j < child.element.properties.length; j++ ) {
+ String[] styles = child.element.properties[ j ].styles;
+ for( int k = 0; k < styles.length; k++ ) {
+ if( styles[ k ].equals( styleName ) ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ // TODO [mschaeff] do this only once and store in map
+ // TODO [mschaeff] only supports direct child elements on level 1
+ public static boolean isStateSupported( String selector, String stateName ) {
+ ThemeDefElementWrapper[] wrappers = getContent();
+ for( int i = 0; i < wrappers.length; i++ ) {
+ ThemeDefElementWrapper wrapper = wrappers[ i ];
+ if( wrapper.element.name.equals( selector ) ) {
+ for( int j = 0; j < wrapper.element.properties.length; j++ ) {
+ String[] states = wrapper.element.properties[ j ].states;
+ for( int k = 0; k < states.length; k++ ) {
+ if( states[ k ].equals( stateName ) ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ } else {
+ // check child elements
+ for( int m = 0; m < wrapper.getChildren().length; m++ ) {
+ ThemeDefElementWrapper child = ( ThemeDefElementWrapper )wrapper.getChildren()[ m ];
+ if( child.element.name.equals( selector ) ) {
+ for( int j = 0; j < child.element.properties.length; j++ ) {
+ String[] states = child.element.properties[ j ].states;
+ for( int k = 0; k < states.length; k++ ) {
+ if( states[ k ].equals( stateName ) ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/ThemeDefinitionReader.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/ThemeDefinitionReader.java
new file mode 100644
index 0000000..0bcfc3f
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/ThemeDefinitionReader.java
@@ -0,0 +1,269 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import javax.xml.parsers.*;
+
+import org.w3c.dom.*;
+import org.xml.sax.*;
+
+
+/**
+ * Reader for theme definition files. These are the "*.theme.xml" files
+ * that define themeable properties of a certain widget.
+ */
+public class ThemeDefinitionReader {
+
+ public static interface ThemeDefHandler {
+ public abstract void readThemeProperty( ThemeProperty def );
+ }
+
+ private static final String NODE_ROOT = "theme";
+
+ private static final String ATTR_NAME = "name";
+
+ private static final String ATTR_DESCRIPTION = "description";
+
+ private static final String ATTR_DEFAULT = "default";
+
+ private static final String ATTR_INHERIT = "inherit";
+
+ private static final String ATTR_TARGET_PATH = "targetPath";
+
+ private static final String ATTR_TRANSPARENT_ALLOWED = "transparentAllowed";
+
+ private static final String ATTR_CSS_ELEMENTS = "css-elements";
+
+ private static final String ATTR_CSS_PROPERTY = "css-property";
+
+ private static final String ATTR_CSS_SELECTORS = "css-selectors";
+
+ private static final String TYPE_BOOLEAN = "boolean";
+
+ private static final String TYPE_BORDER = "border";
+
+ private static final String TYPE_DIMENSION = "dimension";
+
+ private static final String TYPE_BOXDIMENSION = "boxdim";
+
+ private static final String TYPE_COLOR = "color";
+
+ private static final String TYPE_FONT = "font";
+
+ private static final String TYPE_IMAGE = "image";
+
+ private static final String THEME_DEF_SCHEMA = "themedef.xsd";
+
+ private static final String JAXP_SCHEMA_LANGUAGE
+ = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
+
+ private static final String W3C_XML_SCHEMA
+ = "http://www.w3.org/2001/XMLSchema";
+
+ private final InputStream inputStream;
+
+ private final ResourceLoader loader;
+
+ private final String fileName;
+
+ /**
+ * An instance of this class reads theme definitions from an XML resource.
+ *
+ * @param inputStream input stream from a theme definition XML
+ */
+ public ThemeDefinitionReader( final InputStream inputStream,
+ final String fileName,
+ final ResourceLoader loader )
+ {
+ this.fileName = fileName;
+ if( inputStream == null ) {
+ throw new NullPointerException( "null argument" );
+ }
+ this.inputStream = inputStream;
+ this.loader = loader;
+ }
+
+ /**
+ * Reads a theme definition from the specified stream. The stream is kept open
+ * after reading.
+ *
+ * @param callback an implementation of the ThemeDefHandler interface that
+ * handles parsing events
+ * @throws IOException if a I/O error occurs
+ * @throws SAXException if a parse error occurs
+ */
+ public void read( final ThemeDefHandler callback )
+ throws SAXException, IOException
+ {
+ Document document;
+ document = parseThemeDefinition( inputStream );
+ Node root = document.getElementsByTagName( NODE_ROOT ).item( 0 );
+ NodeList childNodes = root.getChildNodes();
+ for( int i = 0; i < childNodes.getLength(); i++ ) {
+ Node node = childNodes.item( i );
+ if( node.getNodeType() == Node.ELEMENT_NODE ) {
+ ThemeProperty property = readElement( node );
+ if( property != null ) {
+ callback.readThemeProperty( property );
+ }
+ }
+ }
+ }
+
+ private ThemeProperty readElement( final Node node ) {
+ String type = node.getNodeName();
+ String name = getAttributeValue( node, ATTR_NAME );
+ String description = getAttributeValue( node, ATTR_DESCRIPTION );
+ String inherit = getAttributeValue( node, ATTR_INHERIT );
+ String defaultStr = getAttributeValue( node, ATTR_DEFAULT );
+ String cssElements = getAttributeValue( node, ATTR_CSS_ELEMENTS );
+ if( cssElements == null ) {
+ cssElements = getAttributeValue( node.getParentNode(), ATTR_CSS_ELEMENTS );
+ }
+ String cssProperty = getAttributeValue( node, ATTR_CSS_PROPERTY );
+ String cssSelectors = getAttributeValue( node, ATTR_CSS_SELECTORS );
+ QxType value;
+ String targetPath = null;
+ boolean transparentAllowed = false;
+ ThemeProperty result = null;
+ if( "property".equals( type ) || "element".equals( type ) ) {
+ // new syntax, ignore for now
+ } else {
+ if( TYPE_FONT.equals( type ) ) {
+ value = QxFont.valueOf( defaultStr );
+ } else if( TYPE_COLOR.equals( type ) ) {
+ String transpValue = getAttributeValue( node, ATTR_TRANSPARENT_ALLOWED );
+ transparentAllowed = Boolean.valueOf( transpValue ).booleanValue();
+ value = QxColor.valueOf( defaultStr );
+ } else if( TYPE_BOOLEAN.equals( type ) ) {
+ value = QxBoolean.valueOf( defaultStr );
+ } else if( TYPE_BORDER.equals( type ) ) {
+ value = QxBorder.valueOf( defaultStr );
+ } else if( TYPE_BOXDIMENSION.equals( type ) ) {
+ value = QxBoxDimensions.valueOf( defaultStr );
+ } else if( TYPE_DIMENSION.equals( type ) ) {
+ value = QxDimension.valueOf( defaultStr );
+ } else if( TYPE_IMAGE.equals( type ) ) {
+ targetPath = getAttributeValue( node, ATTR_TARGET_PATH );
+ value = QxImage.valueOf( defaultStr, loader );
+ } else {
+ // TODO [rst] Remove when XML validation is active
+ throw new IllegalArgumentException( "Illegal type: " + type );
+ }
+ result = new ThemeProperty( name, inherit, value, description );
+ result.targetPath = targetPath;
+ result.transparentAllowed = transparentAllowed;
+ if( cssElements != null && cssProperty != null ) {
+ result.cssElements = cssElements.split( "\\s+" );
+ result.cssProperty = cssProperty;
+ if( cssSelectors != null ) {
+ result.cssSelectors = cssSelectors.split( "\\s+" );
+ }
+ }
+ }
+ return result;
+ }
+
+ private static String getAttributeValue( final Node node, final String name )
+ {
+ String result = null;
+ NamedNodeMap attributes = node.getAttributes();
+ if( attributes != null ) {
+ Node namedItem = attributes.getNamedItem( name );
+ if( namedItem != null ) {
+ result = namedItem.getNodeValue();
+ }
+ }
+ return result;
+ }
+
+ private Document parseThemeDefinition( final InputStream is )
+ throws SAXException, IOException
+ {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware( true );
+ ClassLoader loader = ThemeDefinitionReader.class.getClassLoader();
+ final URL schema = loader.getResource( THEME_DEF_SCHEMA );
+ factory.setValidating( schema != null );
+ try {
+ factory.setAttribute( JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA );
+ } catch( final IllegalArgumentException iae ) {
+ // XML-Processing does not support JAXP 1.2 or greater
+ factory.setNamespaceAware( false );
+ factory.setValidating( false );
+ }
+ DocumentBuilder builder;
+ try {
+ builder = factory.newDocumentBuilder();
+ } catch( final ParserConfigurationException e ) {
+ String message = "Failed to initialize parser for theme definition files";
+ throw new RuntimeException( message, e );
+ }
+// builder.setEntityResolver( new EntityResolver() {
+// public InputSource resolveEntity( final String publicID,
+// final String systemID )
+// throws IOException, SAXException
+// {
+// InputSource result = null;
+// if( schema != null && systemID.endsWith( THEME_DEF_SCHEMA ) ) {
+// URLConnection connection = schema.openConnection();
+// connection.setUseCaches( false );
+// result = new InputSource( connection.getInputStream() );
+// }
+// return result;
+// }
+// } );
+ builder.setErrorHandler( new ThemeDefinitionErrorHandler() );
+ return builder.parse( is );
+ }
+
+ // TODO: Logging instead of sysout
+ private class ThemeDefinitionErrorHandler implements ErrorHandler {
+ public void error( final SAXParseException spe ) throws SAXException {
+ System.err.println( "Error parsing theme definition "
+ + getPosition( spe )
+ + ":" );
+ System.err.println( spe.getMessage() );
+ }
+
+ public void fatalError( final SAXParseException spe )
+ throws SAXException
+ {
+ System.err.println( "Fatal error parsing theme definition "
+ + getPosition( spe )
+ + ":" );
+ System.err.println( spe.getMessage() );
+ }
+
+ public void warning( final SAXParseException spe )
+ throws SAXException
+ {
+ System.err.println( "Warning parsing theme definition "
+ + getPosition( spe )
+ + ":" );
+ System.err.println( spe.getMessage() );
+ }
+
+ private String getPosition( final SAXParseException spe ) {
+ return "in file '"
+ + fileName
+ + "' at line "
+ + spe.getLineNumber()
+ + ", col "
+ + spe.getColumnNumber();
+ }
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/ThemeProperty.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/ThemeProperty.java
new file mode 100644
index 0000000..3768ae3
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/ThemeProperty.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme;
+
+
+/**
+ * Holds all data read from a single property of a theme definition
+ * (*.theme.xml) file.
+ */
+// TODO [rst] Make immutable?
+// TODO [rst] implements equals and hashcode
+public class ThemeProperty {
+
+ private static final String[] EMPTY = new String[ 0 ];
+
+ public final String name;
+
+ public final String inherit;
+
+ public final QxType defValue;
+
+ public final String description;
+
+ public String targetPath;
+
+ public boolean transparentAllowed;
+
+ public String cssProperty;
+
+ public String[] cssElements;
+
+ public String[] cssSelectors;
+
+ public ThemeProperty( final String name,
+ final String inherit,
+ final QxType defValue,
+ final String description )
+ {
+ this.name = name;
+ this.inherit = inherit;
+ this.defValue = defValue;
+ this.description = description;
+ this.cssElements = EMPTY;
+ this.cssSelectors = EMPTY;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/AndConditionImpl.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/AndConditionImpl.java
new file mode 100644
index 0000000..9cf49a7
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/AndConditionImpl.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme.css;
+
+import org.w3c.css.sac.CombinatorCondition;
+import org.w3c.css.sac.Condition;
+
+
+public class AndConditionImpl
+ implements CombinatorCondition, ConditionExt
+{
+
+ private final Condition first;
+
+ private final Condition second;
+
+ public AndConditionImpl( final Condition first, final Condition second ) {
+ this.first = first;
+ this.second = second;
+ }
+
+ public Condition getFirstCondition() {
+ return first;
+ }
+
+ public Condition getSecondCondition() {
+ return second;
+ }
+
+ public short getConditionType() {
+ return SAC_AND_CONDITION;
+ }
+
+ public boolean matches( final Element element ) {
+ ElementMatcher firstMatcher = ( ElementMatcher )first;
+ ElementMatcher secondMatcher = ( ElementMatcher )second;
+ return firstMatcher.matches( element ) && secondMatcher.matches( element );
+ }
+
+ public int getSpecificity() {
+ Specific specificFirst = ( Specific )first;
+ Specific specificSecond = ( Specific )second;
+ return specificFirst.getSpecificity() + specificSecond.getSpecificity();
+ }
+
+ public String[] getClasses() {
+ String[] classes1 = ( ( ConditionExt )first ).getClasses();
+ String[] classes2 = ( ( ConditionExt )second ).getClasses();
+ String[] result = null;
+ if( classes1 == null ) {
+ result = classes2;
+ } else if( classes2 == null ) {
+ result = classes1;
+ } else {
+ result = new String[ classes1.length + classes2.length ];
+ System.arraycopy( classes1, 0, result, 0, classes1.length );
+ System.arraycopy( classes2, 0, result, classes1.length, classes2.length );
+ }
+ return result;
+ }
+
+ public String toString() {
+ return first.toString() + second.toString();
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/AttributeConditionImpl.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/AttributeConditionImpl.java
new file mode 100644
index 0000000..fba8050
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/AttributeConditionImpl.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme.css;
+
+import org.w3c.css.sac.AttributeCondition;
+
+
+public class AttributeConditionImpl implements AttributeCondition, ConditionExt
+{
+
+ private final String localName;
+ private final String value;
+ private final boolean specified;
+
+ public AttributeConditionImpl( final String localName,
+ final String value,
+ final boolean specified )
+ {
+ this.localName = localName;
+ this.value = value;
+ this.specified = specified;
+ }
+
+ public String getLocalName() {
+ return localName;
+ }
+
+ public String getNamespaceURI() {
+ return null;
+ }
+
+ public boolean getSpecified() {
+ return specified;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public short getConditionType() {
+ return SAC_ATTRIBUTE_CONDITION;
+ }
+
+ public boolean matches( final Element element ) {
+ boolean result = false;
+ if( localName != null ) {
+ String attr = element.getAttribute( localName );
+ if( value != null ) {
+ result = value.equals( attr );
+ } else if(attr != null ) {
+ result = !attr.equals( "" );
+ }
+ }
+ return result;
+ }
+
+ public int getSpecificity() {
+ return ATTR_SPEC;
+ }
+
+ public String[] getClasses() {
+ return null;
+ }
+
+ public String toString() {
+ String result;
+ if( value != null ) {
+ result = "[" + localName + "=\"" + value + "\"]";
+ } else {
+ result = "[" + localName + "]";
+ }
+ return result;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/ChildSelectorImpl.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/ChildSelectorImpl.java
new file mode 100644
index 0000000..0b60afd
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/ChildSelectorImpl.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme.css;
+
+import org.w3c.css.sac.*;
+
+
+public class ChildSelectorImpl implements DescendantSelector, SelectorExt {
+
+ private final Selector parent;
+ private final SimpleSelector child;
+
+ public ChildSelectorImpl( final Selector parent, final SimpleSelector child )
+ {
+ this.parent = parent;
+ this.child = child;
+ }
+
+ public Selector getAncestorSelector() {
+ return parent;
+ }
+
+ public SimpleSelector getSimpleSelector() {
+ return child;
+ }
+
+ public short getSelectorType() {
+ return SAC_CHILD_SELECTOR;
+ }
+
+ public String[] getClasses() {
+ return null;
+ }
+
+ public String getElementName() {
+ return ( ( SelectorExt )child ).getElementName();
+ }
+
+ public boolean matches( final Element element ) {
+ return ( ( ElementMatcher )child ).matches( element )
+ && ( ( ElementMatcher )parent ).matches( element.getParent() );
+ }
+
+ public int getSpecificity() {
+ return ( ( Specific )parent ).getSpecificity()
+ + ( ( Specific )child ).getSpecificity();
+ }
+
+ public String toString() {
+ return parent.toString() + " > " + child.toString();
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/ClassConditionImpl.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/ClassConditionImpl.java
new file mode 100644
index 0000000..a83578a
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/ClassConditionImpl.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme.css;
+
+import org.w3c.css.sac.AttributeCondition;
+
+
+public class ClassConditionImpl implements AttributeCondition, ConditionExt {
+
+ private final String value;
+
+ public ClassConditionImpl( final String value ) {
+ this.value = value;
+ }
+
+ public String getLocalName() {
+ return null;
+ }
+
+ public boolean getSpecified() {
+ return true;
+ }
+
+ public String getNamespaceURI() {
+ return null;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public short getConditionType() {
+ return SAC_CLASS_CONDITION;
+ }
+
+ public boolean matches( final Element e ) {
+ return e.hasClass( value );
+ }
+
+ public int getSpecificity() {
+ return ATTR_SPEC;
+ }
+
+ public String[] getClasses() {
+ return new String[] { value };
+ }
+
+ public String toString() {
+ return "." + value;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/ConditionExt.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/ConditionExt.java
new file mode 100644
index 0000000..cff9526
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/ConditionExt.java
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme.css;
+
+
+public interface ConditionExt extends ElementMatcher, Specific {
+
+ abstract String[] getClasses();
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/ConditionFactoryImpl.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/ConditionFactoryImpl.java
new file mode 100644
index 0000000..408cb62
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/ConditionFactoryImpl.java
@@ -0,0 +1,134 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme.css;
+
+import org.w3c.css.sac.*;
+
+/**
+ * ConditionFactory implementation for parsing RAP theme files. All returned
+ * conditions implement the interface {@link ConditionExt}.
+ */
+public class ConditionFactoryImpl implements ConditionFactory {
+
+ private final CssFileReader reader;
+
+ public ConditionFactoryImpl( final CssFileReader reader ) {
+ this.reader = reader;
+ }
+
+ public AttributeCondition createClassCondition( final String namespaceURI,
+ final String value )
+ throws CSSException
+ {
+ return new ClassConditionImpl( value );
+ }
+
+ public AttributeCondition createPseudoClassCondition( final String namespaceURI,
+ final String value )
+ throws CSSException
+ {
+ return new PseudoClassConditionImpl( value );
+ }
+
+ public AttributeCondition createAttributeCondition( final String localName,
+ final String namespaceURI,
+ final boolean specified,
+ final String value )
+ throws CSSException
+ {
+ return new AttributeConditionImpl( localName, value, specified );
+ }
+
+ public AttributeCondition createOneOfAttributeCondition( final String localName,
+ final String namespaceURI,
+ final boolean specified,
+ final String value )
+ throws CSSException
+ {
+ return new OneOfAttributeCondition( localName, value, specified );
+ }
+
+ public CombinatorCondition createAndCondition( final Condition first,
+ final Condition second )
+ throws CSSException
+ {
+ return new AndConditionImpl( first, second );
+ }
+
+ // ==========================================================================
+ // Not supported by RAP
+
+ public LangCondition createLangCondition( final String lang )
+ throws CSSException
+ {
+ String mesg = "Lang conditions not supported by RAP - ignored";
+ reader.addProblem( new CSSException( mesg ) );
+ return new NullLangCondition();
+ }
+
+ public AttributeCondition createIdCondition( final String value )
+ throws CSSException
+ {
+ String mesg = "Id conditions not supported by RAP - ignored";
+ reader.addProblem( new CSSException( mesg ) );
+ return new NullAttributeCondition();
+ }
+
+ public AttributeCondition createBeginHyphenAttributeCondition( final String localName,
+ final String namespaceURI,
+ final boolean specified,
+ final String value )
+ throws CSSException
+ {
+ String mesg = "Begin hyphen attribute conditions not supported by RAP - ignored";
+ reader.addProblem( new CSSException( mesg ) );
+ return new NullAttributeCondition();
+ }
+
+ // ==========================================================================
+ // Not supported by CSS 2
+
+ public CombinatorCondition createOrCondition( final Condition first,
+ final Condition second )
+ throws CSSException
+ {
+ throw new CSSException( "Or conditions not supported by CSS2" );
+ }
+
+ public NegativeCondition createNegativeCondition( final Condition condition )
+ throws CSSException
+ {
+ throw new CSSException( "Negative conditions not supported by CSS2" );
+ }
+
+ public PositionalCondition createPositionalCondition( final int position,
+ final boolean typeNode,
+ final boolean type )
+ throws CSSException
+ {
+ throw new CSSException( "Positional conditions not supported by CSS2" );
+ }
+
+ public Condition createOnlyChildCondition() throws CSSException {
+ throw new CSSException( "Only-one-child conditions not supported by CSS2" );
+ }
+
+ public Condition createOnlyTypeCondition() throws CSSException {
+ throw new CSSException( "Only-one-type conditions not supported by CSS2" );
+ }
+
+ public ContentCondition createContentCondition( final String data )
+ throws CSSException
+ {
+ throw new CSSException( "Content conditions not supported by CSS2" );
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/ConditionalSelectorImpl.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/ConditionalSelectorImpl.java
new file mode 100644
index 0000000..e04db51
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/ConditionalSelectorImpl.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme.css;
+
+import org.w3c.css.sac.*;
+
+
+public class ConditionalSelectorImpl
+ implements ConditionalSelector, SelectorExt
+{
+
+ private final SimpleSelector selector;
+ private final Condition condition;
+
+ public ConditionalSelectorImpl( final SimpleSelector selector,
+ final Condition condition )
+ {
+ this.selector = selector;
+ this.condition = condition;
+ }
+
+ public Condition getCondition() {
+ return condition;
+ }
+
+ public SimpleSelector getSimpleSelector() {
+ return selector;
+ }
+
+ public short getSelectorType() {
+ return SAC_CONDITIONAL_SELECTOR;
+ }
+
+ public boolean matches( final Element element ) {
+ ElementMatcher conditionMatcher = ( ElementMatcher )condition;
+ ElementMatcher selectorMatcher = ( ElementMatcher )selector;
+ return selectorMatcher.matches( element )
+ && conditionMatcher.matches( element );
+ }
+
+ public int getSpecificity() {
+ Specific specificSelector = (Specific)selector;
+ Specific specificCondition = (Specific)condition;
+ return specificSelector.getSpecificity()
+ + specificCondition.getSpecificity();
+ }
+
+ public String getElementName() {
+ return ( ( SelectorExt )selector ).getElementName();
+ }
+
+ public String[] getClasses() {
+ return ( ( ConditionExt )condition ).getClasses();
+ }
+
+ public String toString() {
+ return selector.toString() + condition.toString();
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/CssFileReader.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/CssFileReader.java
new file mode 100644
index 0000000..3dd9e5b
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/CssFileReader.java
@@ -0,0 +1,174 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme.css;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.w3c.css.sac.*;
+
+
+public class CssFileReader {
+
+ private static final String CSS_ENCODING = "UTF-8";
+
+ private List problems;
+
+ private Parser parser;
+
+ /* BEGIN Modification for Theme Editor */
+ private List errors;
+ private List warnings;
+ private String uri;
+ /* END Modification for Theme Editor */
+
+ public CssFileReader() {
+ try {
+ parser = new org.apache.batik.css.parser.Parser();
+ } catch( Exception e ) {
+ throw new RuntimeException( "Failed to instantiate CSS parser", e );
+ }
+ problems = new ArrayList();
+ /* BEGIN Modification for Theme Editor */
+ errors = new ArrayList();
+ warnings = new ArrayList();
+ /* END Modification for Theme Editor */
+ }
+
+ public StyleSheet parse( final InputStream inputStream, final String uri )
+ throws CSSException, IOException
+ {
+ /* BEGIN Modification for Theme Editor */
+ this.uri = uri;
+ /* END Modification for Theme Editor */
+ InputSource source = new InputSource();
+ source.setByteStream( inputStream );
+ source.setEncoding( CSS_ENCODING );
+ source.setURI( uri );
+ parser.setConditionFactory( new ConditionFactoryImpl( this ) );
+ parser.setSelectorFactory( new SelectorFactoryImpl( this ) );
+ DocumentHandlerImpl documentHandler = new DocumentHandlerImpl( this );
+ parser.setDocumentHandler( documentHandler );
+ parser.setErrorHandler( new ErrorHandlerImpl( this ) );
+ parser.parseStyleSheet( source );
+ StyleRule[] styleRules = documentHandler.getStyleRules();
+ StyleSheet result = new StyleSheet( styleRules );
+ /* BEGIN Modification for Theme Editor */
+ result.setHeaderComment( documentHandler.getHeaderComment() );
+ /* END Modification for Theme Editor */
+ return result;
+ }
+
+ public CSSException[] getProblems() {
+ CSSException[] result = new CSSException[ problems.size() ];
+ problems.toArray( result );
+ return result;
+ }
+
+ void addProblem( final CSSException exception ) {
+// TODO [rst] Logging instead of sysout
+ System.err.println( exception );
+ problems.add( exception );
+ /* BEGIN Modification for Theme Editor */
+ if( exception instanceof CSSParseException ) {
+ addWarning( ( CSSParseException )exception );
+ } else if( parser instanceof org.apache.batik.css.parser.Parser ) {
+ CSSParseException parseException = new CSSParseException( exception.getMessage(),
+ uri,
+ getCurrentLine(),
+ 0 );
+ addWarning( parseException );
+ }
+ /* END Modification for Theme Editor */
+ }
+
+ public CSSParseException[] getErrors() {
+ CSSParseException[] result = new CSSParseException[ errors.size() ];
+ errors.toArray( result );
+ return result;
+ }
+
+ public CSSParseException[] getWarnings() {
+ CSSParseException[] result = new CSSParseException[ warnings.size() ];
+ warnings.toArray( result );
+ return result;
+ }
+
+ private void addError( final CSSParseException exception ) {
+ errors.add( exception );
+ }
+
+ private void addWarning( final CSSParseException exception ) {
+ warnings.add( exception );
+ }
+
+ public int getCurrentLine() {
+ int result = -1;
+ if( parser instanceof org.apache.batik.css.parser.Parser ) {
+ //result = ( ( org.apache.batik.css.parser.Parser )parser ).getLine();
+ }
+ return result;
+ }
+ /* END Modification for Theme Editor */
+
+
+ private static String createProblemDescription( final String type,
+ final CSSParseException exception )
+ {
+ String pattern = "{0}: {1} in {2} at pos [{3}:{4}]";
+ Object[] arguments = new Object[] {
+ type,
+ exception.getMessage(),
+ exception.getURI(),
+ String.valueOf( exception.getLineNumber() ),
+ String.valueOf( exception.getColumnNumber() )
+ };
+ return MessageFormat.format( pattern, arguments );
+ }
+
+ private static class ErrorHandlerImpl implements ErrorHandler {
+
+// private final List problems;
+ private final CssFileReader reader;
+
+ public ErrorHandlerImpl( final CssFileReader reader ) {
+// this.problems = reader.problems;
+ this.reader = reader;
+ }
+
+ // TODO [rst] decent logging instead of sysout
+ public void warning( final CSSParseException exception ) throws CSSException {
+// String problem = createProblemDescription( "WARNING: ", exception );
+// System.err.println( problem );
+// problems.add( exception );
+ reader.addWarning( exception );
+ }
+
+ public void error( final CSSParseException exception ) throws CSSException {
+// String problem = createProblemDescription( "ERROR: ", exception );
+// System.err.println( problem );
+// problems.add( exception );
+ reader.addError( exception );
+ }
+
+ public void fatalError( final CSSParseException exception ) throws CSSException {
+// String problem = createProblemDescription( "FATAL ERROR: ", exception );
+// System.err.println( problem );
+// problems.add( exception );
+ reader.addError( exception );
+ throw exception;
+ }
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/CssFileWriter.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/CssFileWriter.java
new file mode 100644
index 0000000..1aeafaa
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/CssFileWriter.java
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rwt.internal.theme.css;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.List;
+
+public class CssFileWriter {
+
+ private BufferedWriter out;
+
+ public CssFileWriter() {
+ }
+
+ public void write( StyleSheet styleSheet, String filename ) {
+ ClassLoader classLoader = CssFileWriter.class.getClassLoader();
+ URL url = classLoader.getResource( filename );
+ try {
+ File file = new File( new URI( url.toString() ) );
+ out = new BufferedWriter( new FileWriter( file ) );
+ writeRules( styleSheet );
+ out.flush();
+ out.close();
+ } catch( URISyntaxException e ) {
+ e.printStackTrace();
+ } catch( IOException e ) {
+ e.printStackTrace();
+ }
+ }
+
+ public String getAsString( StyleSheet styleSheet ) {
+ String result;
+ if( styleSheet == null ) {
+ result = "";
+ } else {
+ StringWriter stringWriter = new StringWriter();
+ try {
+ out = new BufferedWriter( stringWriter );
+ writeRules( styleSheet );
+ out.flush();
+ out.close();
+ } catch( IOException e ) {
+ e.printStackTrace();
+ }
+ result = stringWriter.toString();
+ }
+ return result;
+ }
+
+ private void writeRules( StyleSheet styleSheet ) throws IOException {
+ // write header comment first
+ String headerComment = styleSheet.getHeaderComment();
+ if( headerComment != null ) {
+ out.write( "/*" + headerComment + "*/" );
+ out.newLine();
+ }
+ // write each rule with comments
+ StyleRule[] rules = styleSheet.getStyleRules();
+ for( int i = 0; i < rules.length; i++ ) {
+ StyleRule rule = rules[ i ];
+ List comments = rule.getComments();
+ for( int j = 0; j < comments.size(); j++ ) {
+ String comment = ( String )comments.get( j );
+ out.write( "/*" + comment + "*/" );
+ out.newLine();
+ }
+ StylePropertyMap properties = rule.getProperties();
+ out.write( rule.getSelectorText() );
+ out.write( " {" );
+ out.newLine();
+ String[] keys = properties.getKeys();
+ for( int j = 0; j < keys.length; j++ ) {
+ String cssProperty = keys[ j ];
+
+ String property = properties.getPropertyString( cssProperty );
+ if ( property != null ) {
+ out.write( " " + cssProperty + ": " + property + ";" );
+ out.newLine();
+ }
+
+ /*
+ LexicalUnit property = properties.getProperty( cssProperty );
+ if( property != null ) {
+ out.write( getPropertyAsString( cssProperty ) );
+ IPropertyWrapper wrapper = PropertyWrapperFactory.createPropertyWrapper( cssProperty,
+ property,
+ rule );
+ if( wrapper != null ) {
+ out.write( wrapper.getDefaultString() );
+ } else {
+ // handle unsupported properties
+ if( property.getLexicalUnitType() == LexicalUnit.SAC_IDENT ) {
+ out.write( property.getStringValue() );
+ } else {
+ out.write( "0" );
+ }
+ }
+ out.write( ";" );
+ out.newLine();
+ }
+ */
+
+
+ }
+ out.write( "}" );
+ out.newLine();
+ out.newLine();
+ }
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/DocumentHandlerExt.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/DocumentHandlerExt.java
new file mode 100644
index 0000000..5cc2225
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/DocumentHandlerExt.java
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Mathias Schaeffner and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathias Schaeffner - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.rwt.internal.theme.css;
+
+public interface DocumentHandlerExt {
+
+ public void propertyString( final String name, final String value );
+
+ public void propertyLine( final String name, final int line );
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/DocumentHandlerImpl.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/DocumentHandlerImpl.java
new file mode 100644
index 0000000..fa6d12e
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/DocumentHandlerImpl.java
@@ -0,0 +1,255 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme.css;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.w3c.css.sac.*;
+
+
+public class DocumentHandlerImpl implements DocumentHandler, DocumentHandlerExt {
+
+ private String uri;
+ private final List rules;
+ private final CssFileReader reader;
+ private StylePropertyMap currentStyleProperties = null;
+
+ /* BEGIN Modification for Theme Editor */
+ private int ruleLineNumber = -1;
+ private List comments = new ArrayList();
+ private boolean firstSelectorStarted = false;
+ private boolean insideRule = false;
+ private String headerComment;
+
+ public String getHeaderComment() {
+ return headerComment;
+ }
+ /* END Modification for Theme Editor */
+
+ public DocumentHandlerImpl( final CssFileReader reader ) {
+ this.reader = reader;
+ this.rules = new ArrayList();
+ }
+
+ public void startDocument( final InputSource source ) throws CSSException {
+ uri = source.getURI();
+ log( "=== startDocument " + uri + "===" );
+ }
+
+ public void endDocument( final InputSource source ) throws CSSException {
+ log( "___ endDocument ___" );
+ }
+
+ public void startSelector( final SelectorList patterns ) throws CSSException {
+ log( "startSelector " + toString( patterns ) );
+ currentStyleProperties = new StylePropertyMap();
+ /* BEGIN Modification for Theme Editor */
+ ruleLineNumber = reader.getCurrentLine() - 1;
+ firstSelectorStarted = true;
+ insideRule = true;
+ /* END Modification for Theme Editor */
+ }
+
+ public void endSelector( final SelectorList patterns ) throws CSSException {
+ log( "endSelector " + toString( patterns ) );
+ /* BEGIN Modification for Theme Editor */
+ StyleRule newRule = new StyleRule( patterns, currentStyleProperties );
+ newRule.setComments( comments );
+ newRule.setLineNumber( ruleLineNumber );
+ rules.add( newRule );
+ comments = new ArrayList();
+ insideRule = false;
+ /* END Modification for Theme Editor */
+ currentStyleProperties = null;
+ }
+
+ public void property( final String name,
+ final LexicalUnit value,
+ final boolean important ) throws CSSException
+ {
+ log( " property "
+ + name
+ + " := "
+ + toString( value )
+ + ( important
+ ? ", important"
+ : "" ) );
+ if( currentStyleProperties != null ) {
+ currentStyleProperties.setProperty( name, value );
+ }
+ }
+
+ /* BEGIN Modification for Theme Editor */
+ public void propertyString( final String name, final String value ) {
+ if( currentStyleProperties != null ) {
+ currentStyleProperties.setPropertyString( name, value );
+ }
+ }
+
+ public void propertyLine( final String name, final int line ) {
+ if( currentStyleProperties != null ) {
+ currentStyleProperties.setLineNumber( name, line );
+ }
+ }
+ /* END Modification for Theme Editor */
+
+ // -- ignored, but used for Theme Editor --
+ public void comment( final String text ) throws CSSException {
+ log( " /*" + text + "*/" );
+ if ( !insideRule ) {
+ if ( !firstSelectorStarted && headerComment == null ) {
+ headerComment = text;
+ } else {
+ comments.add( text );
+ }
+ }
+ }
+
+ // -- unsupported --
+ public void importStyle( final String uri,
+ final SACMediaList media,
+ final String defaultNamespaceURI )
+ throws CSSException
+ {
+ log( "importStyle " + uri + ", " + media + ", " + defaultNamespaceURI );
+ reader.addProblem( new CSSException( "import rules not supported - ignored" ) );
+ }
+
+ public void namespaceDeclaration( final String prefix, final String uri )
+ throws CSSException
+ {
+ log( "namespaceDeclaration " + prefix + ", " + uri );
+ reader.addProblem( new CSSException( "unsupported namespace declaration '"
+ + prefix
+ + ":"
+ + uri
+ + "' - ignored" ) );
+ }
+
+ public void ignorableAtRule( final String atRule ) throws CSSException {
+ log( "ignorableAtRule " + atRule );
+ reader.addProblem( new CSSException( "unsupported at rule '"
+ + atRule
+ + "' - ignored" ) );
+ }
+
+ public void startPage( final String name, final String pseudo_page )
+ throws CSSException
+ {
+ log( "startPage " + name + ", " + pseudo_page );
+ reader.addProblem( new CSSException( "page rules not supported - ignored" ) );
+ }
+
+ public void endPage( final String name, final String pseudo_page )
+ throws CSSException
+ {
+ log( "endPage " + name + ", " + pseudo_page );
+ }
+
+ public void startMedia( final SACMediaList media ) throws CSSException {
+ log( "startMedia " + media );
+ reader.addProblem( new CSSException( "media rules not supported - ignored" ) );
+ }
+
+ public void endMedia( final SACMediaList media ) throws CSSException {
+ log( "endMedia " + media );
+ }
+
+ public void startFontFace() throws CSSException {
+ log( "startFontFace" );
+ reader.addProblem( new CSSException( "font face rules not supported - ignored" ) );
+ }
+
+ public void endFontFace() throws CSSException {
+ log( "end FontFace" );
+ }
+
+ public StyleRule[] getStyleRules() {
+ StyleRule[] result = new StyleRule[ rules.size() ];
+ rules.toArray( result );
+ return result;
+ }
+
+ private void log( final String message ) {
+// System.out.println( message );
+ }
+
+ private static String toString( final SelectorList patterns ) {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append( "[" );
+ int length = patterns.getLength();
+ for( int i = 0; i < length; i++ ) {
+ buffer.append( " " );
+ Selector selector = patterns.item( i );
+ buffer.append( selector.toString() );
+ }
+ buffer.append( " ]" );
+ return buffer.toString();
+ }
+
+ private static String toString( final LexicalUnit value ) {
+ StringBuffer buffer = new StringBuffer();
+ short type = value.getLexicalUnitType();
+ if( type == LexicalUnit.SAC_ATTR ) {
+ buffer.append( "ATTR " + value.getStringValue() );
+ } else if( type == LexicalUnit.SAC_CENTIMETER
+ || type == LexicalUnit.SAC_DEGREE
+ || type == LexicalUnit.SAC_EM
+ || type == LexicalUnit.SAC_EX
+ || type == LexicalUnit.SAC_GRADIAN
+ || type == LexicalUnit.SAC_HERTZ
+ || type == LexicalUnit.SAC_INCH
+ || type == LexicalUnit.SAC_KILOHERTZ
+ || type == LexicalUnit.SAC_MILLIMETER
+ || type == LexicalUnit.SAC_MILLISECOND
+ || type == LexicalUnit.SAC_PERCENTAGE
+ || type == LexicalUnit.SAC_PICA
+ || type == LexicalUnit.SAC_POINT
+ || type == LexicalUnit.SAC_PIXEL
+ || type == LexicalUnit.SAC_RADIAN
+ || type == LexicalUnit.SAC_SECOND
+ || type == LexicalUnit.SAC_DIMENSION )
+ {
+ buffer.append( "DIM "
+ + value.getFloatValue()
+ + value.getDimensionUnitText() );
+ } else if( type == LexicalUnit.SAC_RGBCOLOR ) {
+ LexicalUnit parameters = value.getParameters();
+ buffer.append( "RGBCOLOR " + toString( parameters ) );
+ } else if( type == LexicalUnit.SAC_STRING_VALUE ) {
+ buffer.append( "STRING " + value.getStringValue() );
+ } else if( type == LexicalUnit.SAC_IDENT ) {
+ buffer.append( "IDENT " + value.getStringValue() );
+ } else if( type == LexicalUnit.SAC_PIXEL ) {
+ buffer.append( "PIXEL " + value.getFloatValue() );
+ } else if( type == LexicalUnit.SAC_INTEGER ) {
+ buffer.append( "INT " + value.getIntegerValue() );
+ } else if( type == LexicalUnit.SAC_OPERATOR_COMMA ) {
+ buffer.append( "COMMA" );
+ } else if( type == LexicalUnit.SAC_ATTR ) {
+ buffer.append( "ATTR " + value.getStringValue() );
+ } else if( type == LexicalUnit.SAC_FUNCTION ) {
+ buffer.append( "UNKNOWN FUNCTION " + value.getFunctionName() );
+ } else if( type == LexicalUnit.SAC_DIMENSION ) {
+ buffer.append( "UNKNOWN DIMENSION " + value );
+ } else {
+ buffer.append( "unsupported unit " + value.getLexicalUnitType() );
+ }
+ LexicalUnit next = value.getNextLexicalUnit();
+ if( next != null ) {
+ buffer.append( ", " );
+ buffer.append( toString( next ) );
+ }
+ return buffer.toString();
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/Element.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/Element.java
new file mode 100644
index 0000000..c0f5247
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/Element.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme.css;
+
+
+public interface Element {
+
+ abstract boolean hasName( String name );
+
+ abstract boolean hasClass( String name );
+
+ abstract boolean hasPseudoClass( String name );
+
+ abstract boolean hasAttribute( String name );
+
+ abstract String getAttribute( String name );
+
+ abstract Element getParent();
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/ElementMatcher.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/ElementMatcher.java
new file mode 100644
index 0000000..308d79a
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/ElementMatcher.java
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme.css;
+
+
+public interface ElementMatcher {
+
+ abstract boolean matches( Element element );
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/ElementSelectorImpl.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/ElementSelectorImpl.java
new file mode 100644
index 0000000..1fc3025
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/ElementSelectorImpl.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme.css;
+
+import org.w3c.css.sac.ElementSelector;
+
+
+public class ElementSelectorImpl implements ElementSelector, SelectorExt {
+
+ private final String tagName;
+
+ public ElementSelectorImpl( final String tagName ) {
+ this.tagName = tagName;
+ }
+
+ public String getLocalName() {
+ return tagName;
+ }
+
+ public String getNamespaceURI() {
+ return null;
+ }
+
+ public short getSelectorType() {
+ return SAC_ELEMENT_NODE_SELECTOR;
+ }
+
+ public boolean matches( final Element element ) {
+ boolean result = false;
+ if( element != null ) {
+ result = tagName == null || element.hasName( tagName );
+ }
+ return result;
+ }
+
+ public int getSpecificity() {
+ return tagName != null ? ELEMENT_SPEC : 0;
+ }
+
+ public String getElementName() {
+ return tagName;
+ }
+
+ public String[] getClasses() {
+ return null;
+ }
+
+ public String toString() {
+ return tagName != null ? tagName : "*";
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/EmptyChildSelectorImpl.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/EmptyChildSelectorImpl.java
new file mode 100644
index 0000000..e99c9c9
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/EmptyChildSelectorImpl.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.rwt.internal.theme.css;
+
+import org.w3c.css.sac.*;
+
+public class EmptyChildSelectorImpl implements DescendantSelector, SelectorExt {
+
+ private final Selector parent;
+ private final SimpleSelector child;
+
+ public EmptyChildSelectorImpl( final Selector parent,
+ final SimpleSelector child )
+ {
+ this.parent = parent;
+ this.child = child;
+ }
+
+ public Selector getAncestorSelector() {
+ return parent;
+ }
+
+ public SimpleSelector getSimpleSelector() {
+ return child;
+ }
+
+ public short getSelectorType() {
+ return SAC_CHILD_SELECTOR;
+ }
+
+ public String[] getClasses() {
+ return null;
+ }
+
+ public String getElementName() {
+ return ( ( SelectorExt )child ).getElementName();
+ }
+
+ public boolean matches( final Element element ) {
+ return false;
+ }
+
+ public int getSpecificity() {
+ return 0;
+ }
+
+ public String toString() {
+ return parent.toString() + " > " + child.toString();
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/EmptyDescendantSelectorImpl.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/EmptyDescendantSelectorImpl.java
new file mode 100644
index 0000000..d00d461
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/EmptyDescendantSelectorImpl.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.rwt.internal.theme.css;
+
+import org.w3c.css.sac.*;
+
+public class EmptyDescendantSelectorImpl
+ implements DescendantSelector, SelectorExt
+{
+
+ private final Selector parent;
+ private final SimpleSelector child;
+
+ public EmptyDescendantSelectorImpl( final Selector parent,
+ final SimpleSelector child )
+ {
+ this.parent = parent;
+ this.child = child;
+ }
+
+ public Selector getAncestorSelector() {
+ return parent;
+ }
+
+ public SimpleSelector getSimpleSelector() {
+ return child;
+ }
+
+ public short getSelectorType() {
+ return SAC_DESCENDANT_SELECTOR;
+ }
+
+ public String[] getClasses() {
+ return null;
+ }
+
+ public String getElementName() {
+ return ( ( SelectorExt )child ).getElementName();
+ }
+
+ public boolean matches( final Element element ) {
+ return false;
+ }
+
+ public int getSpecificity() {
+ return 0;
+ }
+
+ public String toString() {
+ return parent.toString() + " " + child.toString();
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/EmptyElementSelectorImpl.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/EmptyElementSelectorImpl.java
new file mode 100644
index 0000000..574df71
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/EmptyElementSelectorImpl.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.rwt.internal.theme.css;
+
+import org.w3c.css.sac.ElementSelector;
+
+public class EmptyElementSelectorImpl implements ElementSelector, SelectorExt {
+
+ private final String tagName;
+
+ public EmptyElementSelectorImpl( final String tagName ) {
+ this.tagName = tagName;
+ }
+
+ public String getLocalName() {
+ return null;
+ }
+
+ public String getNamespaceURI() {
+ return null;
+ }
+
+ public short getSelectorType() {
+ return SAC_ELEMENT_NODE_SELECTOR;
+ }
+
+ public boolean matches( final Element element ) {
+ return false;
+ }
+
+ public int getSpecificity() {
+ return 0;
+ }
+
+ public String getElementName() {
+ return null;
+ }
+
+ public String[] getClasses() {
+ return null;
+ }
+
+ public String toString() {
+ return tagName != null
+ ? tagName
+ : "*";
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/EmptySiblingSelectorImpl.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/EmptySiblingSelectorImpl.java
new file mode 100644
index 0000000..99e6bea
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/EmptySiblingSelectorImpl.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.rwt.internal.theme.css;
+
+import org.w3c.css.sac.*;
+
+public class EmptySiblingSelectorImpl implements SiblingSelector, SelectorExt {
+
+ private final SimpleSelector directAdjacent;
+ private final Selector child;
+ private short nodeType;
+
+ public EmptySiblingSelectorImpl( final short nodeType,
+ final Selector child,
+ final SimpleSelector directAdjacent )
+ {
+ this.directAdjacent = directAdjacent;
+ this.child = child;
+ this.nodeType = nodeType;
+ }
+
+ public Selector getSelector() {
+ return child;
+ }
+
+ public SimpleSelector getSiblingSelector() {
+ return directAdjacent;
+ }
+
+ public short getSelectorType() {
+ return SAC_DIRECT_ADJACENT_SELECTOR;
+ }
+
+ public String[] getClasses() {
+ return null;
+ }
+
+ public String getElementName() {
+ return ( ( SelectorExt )child ).getElementName();
+ }
+
+ public boolean matches( final Element element ) {
+ return false;
+ }
+
+ public int getSpecificity() {
+ return 0;
+ }
+
+ public String toString() {
+ return child.toString() + " + " + directAdjacent.toString();
+ }
+
+ public short getNodeType() {
+ return nodeType;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/NullAttributeCondition.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/NullAttributeCondition.java
new file mode 100644
index 0000000..9ebfc58
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/NullAttributeCondition.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme.css;
+
+import org.w3c.css.sac.AttributeCondition;
+
+
+public class NullAttributeCondition implements AttributeCondition, ConditionExt
+{
+
+ public String getLocalName() {
+ return null;
+ }
+
+ public String getNamespaceURI() {
+ return null;
+ }
+
+ public boolean getSpecified() {
+ return false;
+ }
+
+ public String getValue() {
+ return null;
+ }
+
+ public short getConditionType() {
+ return SAC_ATTRIBUTE_CONDITION;
+ }
+
+ public boolean matches( final Element element ) {
+ return false;
+ }
+
+ public String[] getClasses() {
+ return null;
+ }
+
+ public int getSpecificity() {
+ return 0;
+ }
+
+ public String toString() {
+ return "null condition";
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/NullDescendantSelector.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/NullDescendantSelector.java
new file mode 100644
index 0000000..0a1b66f
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/NullDescendantSelector.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme.css;
+
+import org.w3c.css.sac.*;
+
+
+public class NullDescendantSelector implements DescendantSelector, SelectorExt {
+
+ public Selector getAncestorSelector() {
+ return null;
+ }
+
+ public SimpleSelector getSimpleSelector() {
+ return null;
+ }
+
+ public short getSelectorType() {
+ return SAC_DESCENDANT_SELECTOR;
+ }
+
+ public boolean matches( final Element element ) {
+ return false;
+ }
+
+ public String getElementName() {
+ return null;
+ }
+
+ public String[] getClasses() {
+ return null;
+ }
+
+ public int getSpecificity() {
+ return 0;
+ }
+
+ public String toString() {
+ return "null selector";
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/NullElementSelector.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/NullElementSelector.java
new file mode 100644
index 0000000..c4dc0da
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/NullElementSelector.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme.css;
+
+import org.w3c.css.sac.ElementSelector;
+
+
+public class NullElementSelector implements ElementSelector, SelectorExt {
+
+ public String getLocalName() {
+ return null;
+ }
+
+ public String getNamespaceURI() {
+ return null;
+ }
+
+ public short getSelectorType() {
+ return SAC_ELEMENT_NODE_SELECTOR;
+ }
+
+ public boolean matches( final Element element ) {
+ return false;
+ }
+
+ public String getElementName() {
+ return null;
+ }
+
+ public String[] getClasses() {
+ return null;
+ }
+
+ public int getSpecificity() {
+ return 0;
+ }
+
+ public String toString() {
+ return "null selector";
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/NullLangCondition.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/NullLangCondition.java
new file mode 100644
index 0000000..ee5322d
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/NullLangCondition.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme.css;
+
+import org.w3c.css.sac.LangCondition;
+
+
+public class NullLangCondition implements LangCondition, ConditionExt {
+
+ public String getLang() {
+ return null;
+ }
+
+ public short getConditionType() {
+ return SAC_LANG_CONDITION;
+ }
+
+ public boolean matches( final Element element ) {
+ return false;
+ }
+
+ public String[] getClasses() {
+ return null;
+ }
+
+ public int getSpecificity() {
+ return 0;
+ }
+
+ public String toString() {
+ return "null condition";
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/NullSiblingSelector.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/NullSiblingSelector.java
new file mode 100644
index 0000000..05f939e
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/NullSiblingSelector.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme.css;
+
+import org.w3c.css.sac.*;
+
+
+public class NullSiblingSelector implements SiblingSelector, SelectorExt {
+
+ public Selector getSelector() {
+ return null;
+ }
+
+ public SimpleSelector getSiblingSelector() {
+ return null;
+ }
+
+ public short getSelectorType() {
+ return SAC_DIRECT_ADJACENT_SELECTOR;
+ }
+
+ public short getNodeType() {
+ return ANY_NODE;
+ }
+
+ public boolean matches( final Element element ) {
+ return false;
+ }
+
+ public String getElementName() {
+ return null;
+ }
+
+ public String[] getClasses() {
+ return null;
+ }
+
+ public int getSpecificity() {
+ return 0;
+ }
+
+ public String toString() {
+ return "null selector";
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/OneOfAttributeCondition.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/OneOfAttributeCondition.java
new file mode 100644
index 0000000..3565bcc
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/OneOfAttributeCondition.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme.css;
+
+import org.w3c.css.sac.AttributeCondition;
+
+
+public class OneOfAttributeCondition implements AttributeCondition, ConditionExt
+{
+
+ private final String localName;
+ private final String value;
+ private final boolean specified;
+
+ public OneOfAttributeCondition( final String localName,
+ final String value,
+ final boolean specified )
+ {
+ this.localName = localName;
+ this.value = value;
+ this.specified = specified;
+ }
+
+ public String getLocalName() {
+ return localName;
+ }
+
+ public String getNamespaceURI() {
+ return null;
+ }
+
+ public boolean getSpecified() {
+ return specified;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public short getConditionType() {
+ return SAC_ONE_OF_ATTRIBUTE_CONDITION;
+ }
+
+ public boolean matches( final Element element ) {
+ boolean result = false;
+ if( localName != null && value != null ) {
+ String attr = element.getAttribute( localName );
+ // TODO improve this
+ if( attr != null ) {
+ String[] parts = attr.split( "\\s+" );
+ for( int i = 0; i < parts.length && !result; i++ ) {
+ result |= parts[ i ].equals( value );
+ }
+ }
+ }
+ return result;
+ }
+
+ public int getSpecificity() {
+ return ATTR_SPEC;
+ }
+
+ public String[] getClasses() {
+ return null;
+ }
+
+ public String toString() {
+ return "[" + getLocalName() + "~=\"" + getValue() + "\"]";
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/ParserUtil.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/ParserUtil.java
new file mode 100644
index 0000000..8fb7fe7
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/ParserUtil.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.rwt.internal.theme.css;
+
+import org.w3c.css.sac.DocumentHandler;
+
+public class ParserUtil {
+
+ public static void handlePropertyString( final DocumentHandler documentHandler,
+ final String propertyName,
+ final String propertyString,
+ final int propertyLine )
+ {
+ if( propertyString != null ) {
+ String trimmedString = propertyString.trim();
+ if( documentHandler instanceof DocumentHandlerExt ) {
+ int length = trimmedString.length();
+ if( trimmedString.charAt( length - 1 ) == ';' ) {
+ trimmedString = trimmedString.substring( 0, length - 1 );
+ }
+ ( ( DocumentHandlerExt )documentHandler ).propertyString( propertyName,
+ trimmedString );
+ ( ( DocumentHandlerExt )documentHandler ).propertyLine( propertyName,
+ propertyLine );
+ }
+ }
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/PropertyResolver.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/PropertyResolver.java
new file mode 100644
index 0000000..a4f2c06
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/PropertyResolver.java
@@ -0,0 +1,472 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme.css;
+
+import java.util.*;
+
+import org.eclipse.rwt.internal.theme.*;
+
+import org.w3c.css.sac.LexicalUnit;
+
+
+public class PropertyResolver {
+
+ private static final String BOLD = "bold";
+
+ private static final String ITALIC = "italic";
+
+ private static final String NORMAL = "normal";
+
+ private static final String NONE = "none";
+
+ private static final String HIDDEN = "hidden";
+
+ private static final String DOTTED = "dotted";
+
+ private static final String DASHED = "dashed";
+
+ private static final String SOLID = "solid";
+
+ private static final String DOUBLE = "double";
+
+ private static final String GROOVE = "groove";
+
+ private static final String RIDGE = "ridge";
+
+ private static final String INSET = "inset";
+
+ private static final String OUTSET = "outset";
+
+ /** A thin border. */
+ private static final String THIN = "thin";
+
+ /** A medium border. */
+ private static final String MEDIUM = "medium";
+
+ /** A thick border. */
+ private static final String THICK = "thick";
+
+ private static final String TRANSPARENT = "transparent";
+
+ private static final Map NAMED_COLORS = new HashMap();
+
+ private static final List BORDER_STYLES = new ArrayList();
+
+ /** Width value for "thin" identifier. */
+ public static final int THIN_VALUE = 1;
+
+ /** Width value for "medium" identifier. */
+ public static final int MEDIUM_VALUE = 3;
+
+ /** Width value for "thick" identifier. */
+ public static final int THICK_VALUE = 5;
+
+ static {
+ // register 16 standard HTML colors
+ NAMED_COLORS.put( "black", new int[] { 0, 0, 0 } );
+ NAMED_COLORS.put( "gray", new int[] { 128, 128, 128 } );
+ NAMED_COLORS.put( "silver", new int[] { 192, 192, 192 } );
+ NAMED_COLORS.put( "white", new int[] { 255, 255, 255 } );
+ NAMED_COLORS.put( "maroon", new int[] { 128, 0, 0 } );
+ NAMED_COLORS.put( "red", new int[] { 255, 0, 0 } );
+ NAMED_COLORS.put( "purple", new int[] { 128, 0, 128 } );
+ NAMED_COLORS.put( "fuchsia", new int[] { 255, 0, 255 } );
+ NAMED_COLORS.put( "green", new int[] { 0, 128, 0 } );
+ NAMED_COLORS.put( "lime", new int[] { 0, 255, 0 } );
+ NAMED_COLORS.put( "navy", new int[] { 0, 0, 128 } );
+ NAMED_COLORS.put( "blue", new int[] { 0, 0, 255 } );
+ NAMED_COLORS.put( "olive", new int[] { 128, 128, 0 } );
+ NAMED_COLORS.put( "yellow", new int[] { 255, 255, 0 } );
+ NAMED_COLORS.put( "teal", new int[] { 0, 128, 128 } );
+ NAMED_COLORS.put( "aqua", new int[] { 0, 255, 255 } );
+ // register border styles
+ BORDER_STYLES.add( NONE ); // No border; the computed border width is zero.
+ BORDER_STYLES.add( HIDDEN ); // Same as 'none', except in terms of border conflict resolution for table elements.
+ BORDER_STYLES.add( DOTTED ); // The border is a series of dots.
+ BORDER_STYLES.add( DASHED ); // The border is a series of short line segments.
+ BORDER_STYLES.add( SOLID ); // The border is a single line segment.
+ BORDER_STYLES.add( DOUBLE ); // The border is two solid lines. The sum of the two lines and the space between them equals the value of 'border-width'.
+ BORDER_STYLES.add( GROOVE ); // The border looks as though it were carved into the canvas.
+ BORDER_STYLES.add( RIDGE ); // The opposite of 'groove': the border looks as though it were coming out of the canvas.
+ BORDER_STYLES.add( INSET ); // The border makes the box look as though it were embedded in the canvas.
+ BORDER_STYLES.add( OUTSET ); // The opposite of 'inset': the border makes the box look as though it were coming out of the canvas.
+ }
+
+ public static QxColor readColor( final LexicalUnit input ) {
+ QxColor result = null;
+ short type = input.getLexicalUnitType();
+ if( type == LexicalUnit.SAC_RGBCOLOR ) {
+ LexicalUnit redParam = input.getParameters();
+ LexicalUnit greenParam = redParam.getNextLexicalUnit().getNextLexicalUnit();
+ LexicalUnit blueParam = greenParam.getNextLexicalUnit().getNextLexicalUnit();
+ short valueType = redParam.getLexicalUnitType();
+ if( greenParam.getLexicalUnitType() == valueType
+ || blueParam.getLexicalUnitType() == valueType )
+ {
+ if( valueType == LexicalUnit.SAC_INTEGER ) {
+ int red = normalizeRGBValue( redParam.getIntegerValue() );
+ int green = normalizeRGBValue( greenParam.getIntegerValue() );
+ int blue = normalizeRGBValue( blueParam.getIntegerValue() );
+ result = QxColor.create( red, green, blue );
+ } else if( valueType == LexicalUnit.SAC_PERCENTAGE ) {
+ float redPercent = normalizePercentValue( redParam.getFloatValue() );
+ float greenPercent = normalizePercentValue( greenParam.getFloatValue() );
+ float bluePercent = normalizePercentValue( blueParam.getFloatValue() );
+ int red = ( int )( 255 * redPercent / 100 );
+ int green = ( int )( 255 * greenPercent / 100 );
+ int blue = ( int )( 255 * bluePercent / 100 );
+ result = QxColor.create( red, green, blue );
+ }
+ }
+ } else if( type == LexicalUnit.SAC_IDENT ) {
+ String string = input.getStringValue();
+ if( TRANSPARENT.equals( string ) ) {
+ result = QxColor.TRANSPARENT;
+ } else if( NAMED_COLORS.containsKey( string.toLowerCase() ) ) {
+ int[] values = ( int[] )NAMED_COLORS.get( string.toLowerCase() );
+ result = QxColor.create( values[ 0 ], values[ 1 ], values[ 2 ] );
+ }
+ }
+ return result;
+ }
+
+ public static QxDimension readDimension( final LexicalUnit unit ) {
+ QxDimension result = null;
+ Integer length = readSingleLengthUnit( unit );
+ if( length != null ) {
+ result = QxDimension.create( length.intValue() );
+ }
+ return result;
+ }
+
+ public static QxBoxDimensions readBoxDimensions( final LexicalUnit unit ) {
+ QxBoxDimensions result = null;
+ Integer value1 = readSingleLengthUnit( unit );
+ if( value1 != null ) {
+ int top, right, left, bottom;
+ top = right = bottom = left = value1.intValue();
+ LexicalUnit nextUnit = unit.getNextLexicalUnit();
+ boolean ok = true;
+ int pos = 1;
+ while( nextUnit != null && ok ) {
+ pos++;
+ Integer nextValue = readSingleLengthUnit( nextUnit );
+ ok &= nextValue != null && pos <= 4;
+ if( ok ) {
+ if( pos == 2 ) {
+ right = left = nextValue.intValue();
+ } else if( pos == 3 ) {
+ bottom = nextValue.intValue();
+ } else if( pos == 4 ) {
+ left = nextValue.intValue();
+ }
+ }
+ nextUnit = nextUnit.getNextLexicalUnit();
+ }
+ ok &= nextUnit == null;
+ if( ok ) {
+ result = QxBoxDimensions.create( top, right, bottom, left );
+ }
+ }
+ return result;
+ }
+
+ public static String readBorderStyle( final LexicalUnit unit ) {
+ String result = null;
+ short type = unit.getLexicalUnitType();
+ if( type == LexicalUnit.SAC_IDENT ) {
+ String string = unit.getStringValue();
+ if( BORDER_STYLES.contains( string ) ) {
+ result = string;
+ }
+ }
+ return result;
+ }
+
+ public static int readBorderWidth( final LexicalUnit unit ) {
+ int result = -1;
+ short type = unit.getLexicalUnitType();
+ if( type == LexicalUnit.SAC_IDENT ) {
+ String string = unit.getStringValue();
+ if( THIN.equals( string ) ) {
+ result = THIN_VALUE;
+ } else if( MEDIUM.equals( string ) ) {
+ result = MEDIUM_VALUE;
+ } else if( THICK.equals( string ) ) {
+ result = THICK_VALUE;
+ }
+ } else if( type == LexicalUnit.SAC_PIXEL ) {
+ float value = unit.getFloatValue();
+ if( value >= 0f ) {
+ result = Math.round( value );
+ }
+ }
+ return result;
+ }
+
+ public static QxBorder readBorder( final LexicalUnit unit ) {
+ QxBorder result = null;
+ QxColor color = null;
+ String style = null;
+ int width = -1;
+ LexicalUnit nextUnit = unit;
+ boolean consumed = false;
+ while( nextUnit != null ) {
+ consumed = false;
+ if( !consumed && width == -1 ) {
+ width = readBorderWidth( nextUnit );
+ consumed |= width != -1;
+ }
+ if( !consumed && style == null ) {
+ style = readBorderStyle( nextUnit );
+ consumed |= style != null;
+ }
+ if( !consumed && color == null ) {
+ color = readColor( nextUnit );
+ consumed |= color != null;
+ }
+ nextUnit = consumed ? nextUnit.getNextLexicalUnit() : null;
+ }
+ if( consumed ) {
+ // TODO [rst] create should take a QxColor
+ result = QxBorder.create( width == -1 ? 0 : width,
+ style,
+ color != null ? color.toDefaultString() : null );
+ }
+ return result;
+ }
+
+ public static String readFontStyle( final LexicalUnit unit ) {
+ String result = null;
+ short type = unit.getLexicalUnitType();
+ if( type == LexicalUnit.SAC_IDENT ) {
+ String value = unit.getStringValue();
+ if( NORMAL.equals( value ) ) {
+ result = value;
+ } else if( ITALIC.equals( value ) ) {
+ result = value;
+ }
+ }
+ return result;
+ }
+
+ public static String readFontWeight( final LexicalUnit unit ) {
+ String result = null;
+ short type = unit.getLexicalUnitType();
+ if( type == LexicalUnit.SAC_IDENT ) {
+ String value = unit.getStringValue();
+ if( NORMAL.equals( value ) ) {
+ result = value;
+ } else if( BOLD.equals( value ) ) {
+ result = value;
+ }
+ }
+ return result;
+ }
+
+ public static int readFontSize( final LexicalUnit unit ) {
+ int result = -1;
+ Integer length = readSingleLengthUnit( unit );
+ if( length != null ) {
+ int value = length.intValue();
+ if( value >= 0 ) {
+ result = value;
+ }
+ }
+ return result;
+ }
+
+ public static String[] readFontFamily( final LexicalUnit unit ) {
+ List list = new ArrayList();
+ LexicalUnit nextUnit = unit;
+ boolean ok = true;
+ String buffer = "";
+ while( nextUnit != null && ok ) {
+ short type = nextUnit.getLexicalUnitType();
+ if( type == LexicalUnit.SAC_STRING_VALUE
+ || type == LexicalUnit.SAC_IDENT )
+ {
+ if( buffer.length() > 0 ) {
+ buffer += " ";
+ }
+ buffer += nextUnit.getStringValue();
+ } else if( type == LexicalUnit.SAC_OPERATOR_COMMA ) {
+ if( buffer.length() > 0 ) {
+ list.add( buffer );
+ } else {
+ ok = false;
+ }
+ buffer = "";
+ }
+ nextUnit = nextUnit.getNextLexicalUnit();
+ }
+ String[] result = null;
+ if( buffer.length() > 0 ) {
+ list.add( buffer );
+ result = new String[ list.size() ];
+ list.toArray( result );
+ }
+ return result;
+ }
+
+ // The format of a URI value is 'url(' followed by optional whitespace
+ // followed by an optional single quote (') or double quote (") character
+ // followed by the URI itself, followed by an optional single quote (') or
+ // double quote (") character followed by optional whitespace followed by ')'.
+ // The two quote characters must be the same.
+
+ public static QxFont readFont( final LexicalUnit unit ) {
+ QxFont result = null;
+ String[] family = null;
+ String style = null;
+ String weight = null;
+ int size = -1;
+ boolean consumed = false;
+ boolean consumedSize = false;
+ boolean consumedFamily = false;
+ LexicalUnit nextUnit = unit;
+ while( nextUnit != null && !consumedFamily ) {
+ consumed = false;
+ if( !consumed && !consumedSize && style == null ) {
+ style = readFontStyle( nextUnit );
+ consumed |= style != null;
+ }
+ if( !consumed && !consumedSize && weight == null ) {
+ weight = readFontWeight( nextUnit );
+ consumed |= weight != null;
+ }
+ if( !consumed && !consumedFamily && size == -1 ) {
+ size = readFontSize( nextUnit );
+ consumedSize = size != -1;
+ consumed |= consumedSize;
+ }
+ if( !consumed && consumedSize && family == null ) {
+ family = readFontFamily( nextUnit );
+ consumedFamily = family != null;
+ consumed |= consumedFamily;
+ }
+ nextUnit = consumed ? nextUnit.getNextLexicalUnit() : null;
+ }
+ if( consumed && consumedSize && consumedFamily ) {
+ boolean bold = BOLD.equals( weight );
+ boolean italic = ITALIC.equals( style );
+ result = QxFont.create( family, size, bold, italic );
+ }
+ return result;
+ }
+
+ public static String readUrl( final LexicalUnit unit ) {
+ String result = null;
+ short type = unit.getLexicalUnitType();
+ if( type == LexicalUnit.SAC_URI ) {
+ result = unit.getStringValue();
+ }
+ return result;
+ }
+
+ public static QxImage readBackgroundImage( final LexicalUnit unit,
+ final ResourceLoader loader ) {
+ QxImage result = null;
+ short type = unit.getLexicalUnitType();
+ if( type == LexicalUnit.SAC_URI ) {
+ String value = unit.getStringValue();
+ result = QxImage.valueOf( value, loader );
+ } else if( type == LexicalUnit.SAC_IDENT ) {
+ String value = unit.getStringValue();
+ if( NONE.equals( value ) ) {
+ result = QxImage.NONE;
+ }
+ }
+ return result;
+ }
+
+ private static Integer readSingleLengthUnit( final LexicalUnit unit ) {
+ Integer result = null;
+ short type = unit.getLexicalUnitType();
+ if( type == LexicalUnit.SAC_PIXEL ) {
+ result = new Integer( ( int )unit.getFloatValue() );
+ }
+ return result;
+ }
+
+ private static int normalizeRGBValue( final int input ) {
+ int result = input;
+ if( input < 0 ) {
+ result = 0;
+ } else if( input > 255 ) {
+ result = 255;
+ }
+ return result;
+ }
+
+ private static float normalizePercentValue( final float input ) {
+ float result = input;
+ if( input < 0f ) {
+ result = 0f;
+ } else if( input > 100f ) {
+ result = 100f;
+ }
+ return result;
+ }
+
+ /*
+ * BEGIN Modification for Theme Editor
+ * Returns an QxType out of a LexicalUnit.
+ */
+ public static QxType getQxType( final String cssProperty,
+ final LexicalUnit unit )
+ {
+ QxType result = null;
+ if( unit != null ) {
+// IPropertyWrapper wrapper = PropertyWrapperFactory.createPropertyWrapper( cssProperty,
+// unit,
+// null );
+// if ( wrapper != null ) {
+// result = wrapper.getQxType();
+// }
+ }
+ return result;
+ }
+
+ /*
+ * Returns the color value of a border unit.
+ */
+ public static QxColor readBorderColor( final LexicalUnit unit ) {
+ QxColor result = null;
+ String style = null;
+ int width = -1;
+ LexicalUnit nextUnit = unit;
+ boolean consumed = false;
+ while( nextUnit != null ) {
+ consumed = false;
+ if( !consumed && width == -1 ) {
+ width = readBorderWidth( nextUnit );
+ consumed |= width != -1;
+ }
+ if( !consumed && style == null ) {
+ style = readBorderStyle( nextUnit );
+ consumed |= style != null;
+ }
+ if( !consumed && result == null ) {
+ result = readColor( nextUnit );
+ consumed |= result != null;
+ }
+ nextUnit = consumed
+ ? nextUnit.getNextLexicalUnit()
+ : null;
+ }
+ return result;
+ }
+ /*
+ * END Modification for Theme Editor
+ */
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/PseudoClassConditionImpl.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/PseudoClassConditionImpl.java
new file mode 100644
index 0000000..86a4fe7
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/PseudoClassConditionImpl.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme.css;
+
+import org.w3c.css.sac.AttributeCondition;
+
+
+public class PseudoClassConditionImpl
+ implements AttributeCondition, ConditionExt
+{
+
+ private final String value;
+
+ public PseudoClassConditionImpl( final String value ) {
+ this.value = value;
+ }
+
+ public String getLocalName() {
+ return null;
+ }
+
+ public String getNamespaceURI() {
+ return null;
+ }
+
+ public boolean getSpecified() {
+ return false;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public short getConditionType() {
+ return SAC_PSEUDO_CLASS_CONDITION;
+ }
+
+ public boolean matches( final Element element ) {
+ return element.hasPseudoClass( value );
+ }
+
+ public int getSpecificity() {
+ return ATTR_SPEC;
+ }
+
+ public String[] getClasses() {
+ return null;
+ }
+
+ public String toString() {
+ return ":" + value;
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/SelectorExt.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/SelectorExt.java
new file mode 100644
index 0000000..8506a43
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/SelectorExt.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme.css;
+
+
+public interface SelectorExt extends ElementMatcher, Specific {
+
+ abstract String getElementName();
+
+ abstract String[] getClasses();
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/SelectorFactoryImpl.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/SelectorFactoryImpl.java
new file mode 100644
index 0000000..6e28530
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/SelectorFactoryImpl.java
@@ -0,0 +1,132 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme.css;
+
+import org.w3c.css.sac.*;
+
+/**
+ * SelectorFacory implementation for parsing RAP theme files. All returned
+ * selectors implement the interface {@link SelectorExt}.
+ */
+public class SelectorFactoryImpl implements SelectorFactory {
+
+ private final CssFileReader reader;
+
+ public SelectorFactoryImpl( final CssFileReader reader ) {
+ this.reader = reader;
+ }
+
+ public ElementSelector createElementSelector( final String namespaceURI,
+ final String tagName )
+ throws CSSException
+ {
+ return new ElementSelectorImpl( tagName );
+ }
+
+ public ConditionalSelector createConditionalSelector( final SimpleSelector selector,
+ final Condition condition )
+ throws CSSException
+ {
+ return new ConditionalSelectorImpl( selector, condition );
+ }
+
+ // ==========================================================================
+ // Not supported by RAP, but used by Theme Editor
+
+ public DescendantSelector createChildSelector( final Selector parent,
+ final SimpleSelector child )
+ throws CSSException
+ {
+// return new ChildSelectorImpl( parent, child );
+ String mesg = "Child selectors not supported by RAP - ignored";
+ reader.addProblem( new CSSException( mesg ) );
+ /* BEGIN Modification for Theme Editor */
+ return new EmptyChildSelectorImpl( parent, child );
+ /* END Modification for Theme Editor */
+ }
+
+ public ElementSelector createPseudoElementSelector( final String namespaceURI,
+ final String pseudoName )
+ throws CSSException
+ {
+ String mesg = "Pseudo element selectors not supported by RAP - ignored";
+ reader.addProblem( new CSSException( mesg ) );
+ /* BEGIN Modification for Theme Editor */
+ return new EmptyElementSelectorImpl( pseudoName );
+ /* END Modification for Theme Editor */
+ }
+
+ public DescendantSelector createDescendantSelector( final Selector parent,
+ final SimpleSelector descendant )
+ throws CSSException
+ {
+ String mesg = "Descendant selectors not supported by RAP - ignored";
+ reader.addProblem( new CSSException( mesg ) );
+ /* BEGIN Modification for Theme Editor */
+ return new EmptyDescendantSelectorImpl( parent, descendant );
+ /* END Modification for Theme Editor */
+ }
+
+ public SiblingSelector createDirectAdjacentSelector( final short nodeType,
+ final Selector child,
+ final SimpleSelector directAdjacent )
+ throws CSSException
+ {
+ String mesg = "Sibling selectors not supported by RAP - ignored";
+ reader.addProblem( new CSSException( mesg ) );
+ /* BEGIN Modification for Theme Editor */
+ return new EmptySiblingSelectorImpl( nodeType, child, directAdjacent );
+ /* END Modification for Theme Editor */
+ }
+
+ // ==========================================================================
+ // Not implemented in CSS 2
+
+ public SimpleSelector createRootNodeSelector() throws CSSException {
+ throw new CSSException( "Root node selectors not supported by CSS2" );
+ }
+
+ public CharacterDataSelector createTextNodeSelector( final String data )
+ throws CSSException
+ {
+ throw new CSSException( "Text node selectors not supported by CSS2" );
+ }
+
+ public CharacterDataSelector createCDataSectionSelector( final String data )
+ throws CSSException
+ {
+ throw new CSSException( "CData section selectors not supported by CSS2" );
+ }
+
+ public ProcessingInstructionSelector createProcessingInstructionSelector( final String target,
+ final String data )
+ throws CSSException
+ {
+ throw new CSSException( "Processing instruction selectors not supported by CSS2" );
+ }
+
+ public CharacterDataSelector createCommentSelector( final String data )
+ throws CSSException
+ {
+ throw new CSSException( "Comment selectors not supported by CSS2" );
+ }
+
+ public SimpleSelector createAnyNodeSelector() throws CSSException {
+ throw new CSSException( "Any-node selectors not supported by CSS2" );
+ }
+
+ public NegativeSelector createNegativeSelector( final SimpleSelector selector )
+ throws CSSException
+ {
+ throw new CSSException( "Negative selectors not supported by CSS2" );
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/Specific.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/Specific.java
new file mode 100644
index 0000000..e4f4998
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/Specific.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme.css;
+
+/**
+ * See {@link http://www.w3.org/TR/CSS21/cascade.html#specificity}
+ */
+public interface Specific {
+
+ /**
+ * Factor for b variable in specificity algorithm, see <a
+ * href="http://www.w3.org/TR/CSS21/cascade.html#specificity">http://www.w3.org/TR/CSS21/cascade.html#specificity</a>.
+ */
+ public static int ID_SPEC = 16 << 1;
+
+ /**
+ * Factor for c variable in specificity algorithm, see <a
+ * href="http://www.w3.org/TR/CSS21/cascade.html#specificity">http://www.w3.org/TR/CSS21/cascade.html#specificity</a>.
+ */
+ public static int ATTR_SPEC = 8 << 1;
+
+ /**
+ * Factor for d variable in specificity algorithm, see <a
+ * href="http://www.w3.org/TR/CSS21/cascade.html#specificity">http://www.w3.org/TR/CSS21/cascade.html#specificity</a>.
+ */
+ public static int ELEMENT_SPEC = 1;
+
+ abstract int getSpecificity();
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/StylableElement.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/StylableElement.java
new file mode 100644
index 0000000..c7409c3
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/StylableElement.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme.css;
+
+import java.util.*;
+
+
+public class StylableElement implements Element {
+
+ private Map attributes = new HashMap();
+
+ private List classes = new ArrayList();
+
+ private List pseudoClasses = new ArrayList();
+
+ private String name;
+
+ private Element parent;
+
+ public StylableElement( final String name ) {
+ this( null, name );
+ }
+
+ public StylableElement( final Element parent, final String name ) {
+ this.name = name;
+ this.parent = parent;
+ }
+
+ public boolean hasName( final String value ) {
+ return name == null || name.equals( value );
+ }
+
+ public Element getParent() {
+ return parent;
+ }
+
+ public boolean hasClass( final String value ) {
+ return value != null && classes.contains( value );
+ }
+
+ public boolean hasPseudoClass( final String value ) {
+ return value != null && pseudoClasses.contains( value );
+ }
+
+ public boolean hasAttribute( final String name ) {
+ String value = ( String )attributes.get( name );
+ return value != null && value.length() > 0;
+ }
+
+ public String getAttribute( final String name ) {
+ return ( String )attributes.get( name );
+ }
+
+ public void setClass( final String className ) {
+ if( className != null ) {
+ classes.add( className );
+ }
+ }
+
+ public void resetClass( final String className ) {
+ if( className != null && classes.contains( className ) ) {
+ classes.remove( className );
+ }
+ }
+
+ public void setPseudoClass( final String pseudoName ) {
+ if( pseudoName != null ) {
+ pseudoClasses.add( pseudoName );
+ }
+ }
+
+ public void resetPseudoClass( final String pseudoName ) {
+ if( pseudoName != null && pseudoClasses.contains( pseudoName ) ) {
+ pseudoClasses.remove( pseudoName );
+ }
+ }
+
+ public void setAttribute( final String name, final String value ) {
+ if( name != null ) {
+ if( value != null ) {
+ attributes.put( name, value );
+ } else {
+ attributes.remove( name );
+ }
+ }
+ }
+
+ public void setAttribute( final String name ) {
+ setAttribute( name, "true" );
+ }
+
+ public void resetAttribute( final String name ) {
+ setAttribute( name, null );
+ }
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/StylePropertyMap.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/StylePropertyMap.java
new file mode 100644
index 0000000..d9f9e06
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/StylePropertyMap.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.rwt.internal.theme.css;
+
+import java.util.*;
+
+import org.eclipse.rwt.internal.theme.QxType;
+import org.w3c.css.sac.LexicalUnit;
+
+public class StylePropertyMap {
+
+ private final Map properties = new HashMap();
+
+ /* BEGIN Modification for Theme Editor */
+ private final Map lineNumbers = new HashMap();
+ private final Map propertyStrings = new HashMap();
+ /* END Modification for Theme Editor */
+
+ public LexicalUnit getProperty( final String key ) {
+ return ( LexicalUnit )properties.get( key );
+ }
+
+ public void setProperty( final String key, final LexicalUnit value ) {
+ if( key == null || value == null ) {
+ throw new NullPointerException( "null argument" );
+ }
+ properties.put( key, value );
+ /* BEGIN Modification for Theme Editor */
+ QxType qxType = PropertyResolver.getQxType( key, value );
+ if( qxType != null ) {
+ setPropertyString( key, qxType.toDefaultString() );
+ }
+ /* END Modification for Theme Editor */
+ }
+
+ public String[] getKeys() {
+ Set keySet = properties.keySet();
+ String[] result = new String[ keySet.size() ];
+ keySet.toArray( result );
+ return result;
+ }
+
+ public void merge( final StylePropertyMap styles ) {
+ String[] keys = styles.getKeys();
+ for( int i = 0; i < keys.length; i++ ) {
+ String key = keys[ i ];
+ properties.put( key, styles.getProperty( key ) );
+ propertyStrings.put( key, styles.getPropertyString( key ) );
+ }
+ }
+
+ /*
+ * BEGIN Modification for Theme Editor
+ */
+ public void removeProperty( final String key ) {
+ if( key != null ) {
+ properties.remove( key );
+ propertyStrings.remove( key );
+ }
+ }
+
+ public int size() {
+ return properties.size();
+ }
+
+ public int getLineNumber( final String key ) {
+ int result = -1;
+ Integer value = ( Integer )lineNumbers.get( key );
+ if( value != null ) {
+ result = value.intValue();
+ }
+ return result;
+ }
+
+ public void setLineNumber( final String key, final int lineNumber ) {
+ if( key != null ) {
+ lineNumbers.put( key, new Integer( lineNumber ) );
+ }
+ }
+
+ public String getPropertyString( final String key ) {
+ return ( String )propertyStrings.get( key );
+ }
+
+ public void setPropertyString( final String key, final String value ) {
+ if( key == null || value == null ) {
+ throw new NullPointerException( "null argument" );
+ }
+ if ( properties.containsKey( key ) ) {
+ propertyStrings.put( key, value );
+ }
+ }
+ /*
+ * END Modification for Theme Editor
+ */
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/StyleRule.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/StyleRule.java
new file mode 100644
index 0000000..6c0eb7b
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/StyleRule.java
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme.css;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.w3c.css.sac.Selector;
+import org.w3c.css.sac.SelectorList;
+
+
+public class StyleRule implements ElementMatcher {
+
+ private final SelectorList selectors;
+
+ private final StylePropertyMap properties;
+
+ /* BEGIN Modification for Theme Editor */
+ private List comments;
+ private int namePosition;
+ private String name;
+ private int lineNumber = -1;
+ /* END Modification for Theme Editor */
+
+ public StyleRule( final SelectorList selectors,
+ final StylePropertyMap properties )
+ {
+ this.selectors = selectors;
+ this.properties = properties;
+ /* BEGIN Modification for Theme Editor */
+ comments = new ArrayList();
+ /* END Modification for Theme Editor */
+ }
+
+ public SelectorList getSelectors() {
+ return selectors;
+ }
+
+ public StylePropertyMap getProperties() {
+ return properties;
+ }
+
+ public Selector getMatchingSelector( final Element element ) {
+ Selector result = null;
+ int maxSpecificity = -1;
+ int length = selectors.getLength();
+ for( int i = 0; i < length; i++ ) {
+ Selector selector = selectors.item( i );
+ ElementMatcher matcher = ( ElementMatcher )selector;
+ if( matcher.matches( element ) ) {
+ int specificity = ( ( Specific )selector ).getSpecificity();
+ if( specificity > maxSpecificity ) {
+ result = selector;
+ maxSpecificity = specificity;
+ }
+ }
+ }
+ return result;
+ }
+
+ public boolean matches( final Element element ) {
+ return getMatchingSelector( element ) != null;
+ }
+
+ public String getSelectorText() {
+ StringBuffer buffer = new StringBuffer();
+ int length = selectors.getLength();
+ for( int i = 0; i < length; i++ ) {
+ Selector selector = selectors.item( i );
+ if( i > 0 ) {
+ buffer.append( ", " );
+ }
+ buffer.append( selector.toString() );
+ }
+ return buffer.toString();
+ }
+
+ /*
+ * BEGIN Modification for Theme Editor
+ */
+ public List getComments() {
+ return comments;
+ }
+
+ public void setComments( final List comments ) {
+ if ( comments != null ) {
+ this.comments = comments;
+ parseComments();
+ }
+ }
+
+ private void parseComments() {
+ for( int i = 0; i < comments.size(); i++ ) {
+ String comment = ( ( String )comments.get( i ) ).trim();
+ if( comment.startsWith( "@name " ) ) {
+ name = comment.substring( 6 );
+ namePosition = i;
+ }
+ }
+ }
+
+ public String getName() {
+ if( name == null ) {
+ return getSelectorText();
+ } else {
+ return name;
+ }
+ }
+
+ public void setName( final String name ) {
+ if( this.name == null ) {
+ comments.add( " @name " + name + " " );
+ namePosition = comments.size() - 1;
+ } else {
+ comments.set( namePosition, " @name " + name + " " );
+ }
+ this.name = name;
+ }
+
+ public int getLineNumber() {
+ return lineNumber;
+ }
+
+ public void setLineNumber( int lineNumber ) {
+ this.lineNumber = lineNumber;
+ }
+ /*
+ * END Modification for Theme Editor
+ */
+}
diff --git a/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/StyleSheet.java b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/StyleSheet.java
new file mode 100644
index 0000000..b5b9b77
--- /dev/null
+++ b/bundles/org.eclipse.rap.themeeditor/src/org/eclipse/rwt/internal/theme/css/StyleSheet.java
@@ -0,0 +1,295 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rwt.internal.theme.css;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.eclipse.rwt.internal.theme.QxBorder;
+import org.eclipse.rwt.internal.theme.QxBoxDimensions;
+import org.eclipse.rwt.internal.theme.QxColor;
+import org.eclipse.rwt.internal.theme.QxDimension;
+import org.eclipse.rwt.internal.theme.QxFont;
+import org.eclipse.rwt.internal.theme.QxImage;
+import org.eclipse.rwt.internal.theme.QxType;
+import org.eclipse.rwt.internal.theme.ResourceLoader;
+import org.w3c.css.sac.LexicalUnit;
+import org.w3c.css.sac.Selector;
+import org.w3c.css.sac.SelectorList;
+
+
+public class StyleSheet {
+
+
+ private static final MatchedStyleRuleComparator COMPARATOR
+ = new MatchedStyleRuleComparator();
+
+ private final StyleRule[] styleRules;
+
+ private String[] variants;
+
+ private String headerComment;
+
+ public StyleSheet( final StyleRule[] styleRules ) {
+ this.styleRules = styleRules;
+ findClasses();
+ }
+
+ public StyleRule[] getStyleRules() {
+ return styleRules;
+ }
+
+ public StyleRule[] getMatchingStyleRules( final Element element ) {
+ List buffer = new ArrayList();
+ for( int i = 0; i < styleRules.length; i++ ) {
+ StyleRule rule = styleRules[ i ];
+ Selector selector = rule.getMatchingSelector( element );
+ if( selector != null ) {
+ int specificity = ( ( Specific )selector ).getSpecificity();
+ buffer.add( new MatchedStyleRule( rule, specificity, i ) );
+ }
+ }
+ Collections.sort( buffer, COMPARATOR );
+ StyleRule[] result = new StyleRule[ buffer.size() ];
+ for( int i = 0; i < result.length; i++ ) {
+ result[ i ] = ( ( MatchedStyleRule )buffer.get( i ) ).rule;
+ }
+ return result;
+ }
+
+ public QxType getValue( final String cssProperty,
+ final StylableElement element,
+ final ResourceLoader loader )
+ {
+ QxType result = null;
+ StyleRule[] rules = getMatchingStyleRules( element );
+ for( int i = 0; i < rules.length; i++ ) {
+ StyleRule rule = rules[ i ];
+ StylePropertyMap properties = rule.getProperties();
+ LexicalUnit property = properties.getProperty( cssProperty );
+ if( property != null ) {
+ if( "color".equals( cssProperty ) ) {
+ result = readColor( properties );
+ } else if( "background-color".equals( cssProperty ) ) {
+ result = readBackgroundColor( properties );
+ } else if( "background-image".equals( cssProperty ) ) {
+ result = readBackgroundImage( properties, loader );
+ } else if( "border".equals( cssProperty ) ) {
+ result = readBorder( properties );
+ } else if( "padding".equals( cssProperty ) ) {
+ result = readPadding( properties );
+ } else if( "margin".equals( cssProperty ) ) {
+ result = readMargin( properties );
+ } else if( "spacing".equals( cssProperty ) ) {
+ result = readSpacing( properties );
+ } else if( "height".equals( cssProperty ) ) {
+ result = readHeight( properties );
+ } else if( "width".equals( cssProperty ) ) {
+ result = readWidth( properties );
+ } else if( "font".equals( cssProperty ) ) {
+ result = readFont( properties );
+ } else if( cssProperty.startsWith( "rwt" )
+ && cssProperty.endsWith( "color" ) )
+ {
+ result = readColor( properties, cssProperty );
+ } else if( "background-gradient-color".equals( cssProperty ) ) {
+ result = readBackgroundColor( properties, cssProperty );
+ } else {
+// TODO [rst] Logging instead of sysout
+ System.err.println( "unsupported css property: " + cssProperty );
+ }
+ }
+ }
+ return result;
+ }
+
+ public String[] getVariants( final String elementName ) {
+ return variants;
+ }
+
+ private void findClasses() {
+ List list = new ArrayList();
+ for( int i = 0; i < styleRules.length; i++ ) {
+ StyleRule rule = styleRules[ i ];
+ SelectorList selectors = rule.getSelectors();
+ int length = selectors.getLength();
+ for( int j = 0; j < length; j++ ) {
+ SelectorExt selector = ( SelectorExt )selectors.item( j );
+ String[] classes = selector.getClasses();
+ if( classes != null ) {
+ for( int k = 0; k < classes.length; k++ ) {
+ String variant = classes[ k ];
+ if( !list.contains( variant ) ) {
+ list.add( variant );
+// System.out.println( "found variant: " + variant );
+ }
+ }
+ }
+ }
+ }
+ variants = new String[ list.size() ];
+ list.toArray( variants );
+ }
+
+ private static QxColor readColor( final StylePropertyMap properties ) {
+ return readColor( properties, "color" );
+ }
+
+ private static QxColor readColor( final StylePropertyMap properties,
+ final String property )
+ {
+ LexicalUnit unit = properties.getProperty( property );
+ QxColor result = PropertyResolver.readColor( unit );
+ return result != QxColor.TRANSPARENT ? result : null;
+ }
+
+ private static QxColor readBackgroundColor( final StylePropertyMap properties )
+ {
+ return readBackgroundColor( properties, "background-color" );
+ }
+
+ private static QxColor readBackgroundColor( final StylePropertyMap properties,
+ final String property )
+ {
+ LexicalUnit unit = properties.getProperty( property );
+ return PropertyResolver.readColor( unit );
+ }
+
+ private QxFont readFont( final StylePropertyMap properties ) {
+ LexicalUnit property = properties.getProperty( "font" );
+ return PropertyResolver.readFont( property );
+ }
+
+ private QxImage readBackgroundImage( final StylePropertyMap properties,
+ final ResourceLoader loader ) {
+ LexicalUnit property = properties.getProperty( "background-image" );
+ return PropertyResolver.readBackgroundImage( property, loader );
+ }
+
+ private QxBorder readBorder( final StylePropertyMap properties ) {
+ LexicalUnit property = properties.getProperty( "border" );
+ return PropertyResolver.readBorder( property );
+ }
+
+ private QxBoxDimensions readPadding( final StylePropertyMap properties ) {
+ LexicalUnit property = properties.getProperty( "padding" );
+ return PropertyResolver.readBoxDimensions( property );
+ }
+
+ private QxBoxDimensions readMargin( final StylePropertyMap properties ) {
+ LexicalUnit property = properties.getProperty( "margin" );
+ return PropertyResolver.readBoxDimensions( property );
+ }
+
+ private QxDimension readSpacing( final StylePropertyMap properties ) {
+ LexicalUnit property = properties.getProperty( "spacing" );
+ return PropertyResolver.readDimension( property );
+ }
+
+ private QxDimension readHeight( final StylePropertyMap properties ) {
+ LexicalUnit property = properties.getProperty( "height" );
+ return PropertyResolver.readDimension( property );
+ }
+
+ private QxDimension readWidth( final StylePropertyMap properties ) {
+ LexicalUnit property = properties.getProperty( "width" );
+ return PropertyResolver.readDimension( property );
+ }
+
+ static class MatchedStyleRuleComparator implements Comparator {
+
+ public int compare( final Object object1, final Object object2 ) {
+ MatchedStyleRule rule1 = ( MatchedStyleRule )object1;
+ MatchedStyleRule rule2 = ( MatchedStyleRule )object2;
+ int result = 0;
+ if( rule1.specificity > rule2.specificity ) {
+ result = 1;
+ } else if( rule1.specificity < rule2.specificity ) {
+ result = -1;
+ } else if( rule1.position > rule2.position ) {
+ result = 1;
+ } else if( rule1.position < rule2.position ) {
+ result = -1;
+ }
+ return result;
+ }
+ }
+
+ static class MatchedStyleRule {
+
+ public final StyleRule rule;
+
+ public final int specificity;
+
+ public final int position;
+
+ public MatchedStyleRule( final StyleRule rule,
+ final int specificity,
+ final int position )
+ {
+ this.rule = rule;
+ this.specificity = specificity;
+ this.position = position;
+ }
+ }
+
+ /*
+ * BEGIN Modification for Theme Editor
+ */
+ public void setHeaderComment( final String headerComment ) {
+ this.headerComment = headerComment;
+ }
+
+ public String getHeaderComment() {
+ return headerComment;
+ }
+
+ public int getStyleRulePoition( StyleRule rule ) {
+ int result = -1;
+ for( int i = 0; i < styleRules.length; i++ ) {
+ if( styleRules[ i ] == rule ) {
+ result = i;
+ }
+ }
+ return result;
+ }
+
+// public IPropertyWrapper getValueWrapper( final String cssProperty,
+// final StylableElement element )
+// {
+// IPropertyWrapper result = null;
+// StyleRule[] rules = getMatchingStyleRules( element );
+// for( int i = 0; i < rules.length; i++ ) {
+// StyleRule rule = rules[ i ];
+// StylePropertyMap properties = rule.getProperties();
+// LexicalUnit property = properties.getProperty( cssProperty );
+// if( property != null ) {
+// result = PropertyWrapperFactory.createPropertyWrapper( cssProperty,
+// property,
+// rule );
+// }
+// }
+// if ( result == null ) {
+// result = PropertyWrapperFactory.createPropertyWrapper( cssProperty );
+// }
+// return result;
+// }
+
+ public String[] getVariants() {
+ return variants;
+ }
+ /*
+ * END Modification for Theme Editor
+ */
+}