Merge branch 'master' into master_juno
diff --git a/org.eclipse.vex.core.tests/plugin.xml b/org.eclipse.vex.core.tests/plugin.xml
index a23c416..17a8faa 100644
--- a/org.eclipse.vex.core.tests/plugin.xml
+++ b/org.eclipse.vex.core.tests/plugin.xml
@@ -13,10 +13,18 @@
name="http://www.eclipse.org/vex/test/content"
uri="testResources/content.xsd">
</uri>
+ <system
+ systemId="http://www.eclipse.org/vex/test/content.xsd"
+ uri="testResources/content.xsd">
+ </system>
<public
publicId="-//Eclipse Foundation//DTD Vex Test//EN"
uri="testResources/test1.dtd">
</public>
+ <uri
+ name="urn:org:eclipse:vex:styles:test:test.css"
+ uri="testResources/test.css">
+ </uri>
</catalogContribution>
</extension>
diff --git a/org.eclipse.vex.core.tests/pom.xml b/org.eclipse.vex.core.tests/pom.xml
index 4dfaf79..6ddf768 100644
--- a/org.eclipse.vex.core.tests/pom.xml
+++ b/org.eclipse.vex.core.tests/pom.xml
@@ -19,11 +19,6 @@
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-surefire-plugin</artifactId>
<version>${tycho-version}</version>
- <configuration>
- <useUIHarness>true</useUIHarness>
- <testSuite>org.eclipse.vex.core.tests</testSuite>
- <testClass>org.eclipse.vex.core.tests.VEXCoreTestSuite</testClass>
- </configuration>
</plugin>
</plugins>
</build>
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/css/BatikBehaviorTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/css/BatikBehaviorTest.java
index 28c737c..7405245 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/css/BatikBehaviorTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/css/BatikBehaviorTest.java
@@ -1,82 +1,84 @@
-/*******************************************************************************
- * Copyright (c) 2011, 2013 Florian Thienel 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:
- * Florian Thienel - initial API and implementation
- * Carsten Hiesserich - additional tests
- *******************************************************************************/
-package org.eclipse.vex.core.internal.css;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.util.List;
-
-import org.eclipse.vex.core.internal.dom.Element;
-import org.eclipse.vex.core.provisional.dom.IElement;
-import org.junit.Test;
-
-/**
- * @author Florian Thienel
- */
-public class BatikBehaviorTest {
-
- @Test
- public void pseudoElements() throws Exception {
- final StyleSheetReader reader = new StyleSheetReader();
- final StyleSheet styleSheet = reader.read("plan:before { display: block; font-size: 123px; }");
- final List<Rule> rules = styleSheet.getRules();
- assertEquals(1, rules.size());
- final Rule rule = rules.get(0);
- final Element element = new Element("plan");
- // The rule should match the parent of the pseudo element. See StyleSheet#getApplicableDeclarations
- assertTrue(rule.matches(element));
- final IElement before = styleSheet.getPseudoElement(element, "before", false);
- final Styles beforeStyles = styleSheet.getStyles(before);
- assertEquals("block", beforeStyles.get("display"));
- assertEquals(123.0f, beforeStyles.getFontSize(), 0.0f);
- }
-
- @Test
- public void pseudoElements_shouldInheritFromParent() throws Exception {
- final StyleSheetReader reader = new StyleSheetReader();
- final StyleSheet styleSheet = reader.read("plan {font-size: 123px;} plan:before { content: 'test' }");
- final Element element = new Element("plan");
- final IElement before = styleSheet.getPseudoElement(element, "before", false);
- final Styles beforeStyles = styleSheet.getStyles(before);
- assertEquals("test", beforeStyles.getContent(element).get(0));
- assertEquals(123.0f, beforeStyles.getFontSize(), 0.0f);
- }
-
- @Test
- public void testNamespace() throws Exception {
- final StyleSheetReader reader = new StyleSheetReader();
- final StyleSheet styleSheet = reader.read("vex|plan {font-size: 123px;} vex|plan:before { content: 'test' }");
- final Element element = new Element("vex|plan");
- final Styles styles = styleSheet.getStyles(element);
- assertEquals(123.0f, styles.getFontSize(), 0.0f);
- final IElement before = styleSheet.getPseudoElement(element, "before", false);
- final Styles beforeStyles = styleSheet.getStyles(before);
- assertEquals("test", beforeStyles.getContent(element).get(0));
- assertEquals(123.0f, beforeStyles.getFontSize(), 0.0f);
- }
-
- @Test
- public void testNamespaceWithChildSelector() throws Exception {
- final StyleSheetReader reader = new StyleSheetReader();
- final StyleSheet styleSheet = reader.read("vex|parent {font-size: 123px;} vex|parent > child { content: 'child' } child {content: 'nochild'}");
- final Element element = new Element("vex|parent");
- final Element child = new Element("child");
- final Element nochild = new Element("child");
- child.setParent(element);
- final Styles styles = styleSheet.getStyles(child);
- assertEquals(1, styles.getContent(element).size());
- assertEquals("child", styles.getContent(element).get(0));
- final Styles nochildStyles = styleSheet.getStyles(nochild);
- assertEquals("nochild", nochildStyles.getContent(element).get(0));
- }
-}
+/*******************************************************************************
+ * Copyright (c) 2011, 2013 Florian Thienel 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:
+ * Florian Thienel - initial API and implementation
+ * Carsten Hiesserich - additional tests
+ *******************************************************************************/
+package org.eclipse.vex.core.internal.css;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.eclipse.core.runtime.QualifiedName;
+import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Namespace;
+import org.eclipse.vex.core.provisional.dom.IElement;
+import org.junit.Test;
+
+/**
+ * @author Florian Thienel
+ */
+public class BatikBehaviorTest {
+
+ @Test
+ public void pseudoElements() throws Exception {
+ final StyleSheetReader reader = new StyleSheetReader();
+ final StyleSheet styleSheet = reader.read("plan:before { display: block; font-size: 123px; }");
+ final List<Rule> rules = styleSheet.getRules();
+ assertEquals(1, rules.size());
+ final Rule rule = rules.get(0);
+ final Element element = new Element("plan");
+ // The rule should match the parent of the pseudo element. See StyleSheet#getApplicableDeclarations
+ assertTrue(rule.matches(element));
+ final IElement before = styleSheet.getPseudoElement(element, "before", false);
+ final Styles beforeStyles = styleSheet.getStyles(before);
+ assertEquals("block", beforeStyles.get("display"));
+ assertEquals(123.0f, beforeStyles.getFontSize(), 0.0f);
+ }
+
+ @Test
+ public void pseudoElements_shouldInheritFromParent() throws Exception {
+ final StyleSheetReader reader = new StyleSheetReader();
+ final StyleSheet styleSheet = reader.read("plan {font-size: 123px;} plan:before { content: 'test' }");
+ final Element element = new Element("plan");
+ final IElement before = styleSheet.getPseudoElement(element, "before", false);
+ final Styles beforeStyles = styleSheet.getStyles(before);
+ assertEquals("test", beforeStyles.getContent(element).get(0));
+ assertEquals(123.0f, beforeStyles.getFontSize(), 0.0f);
+ }
+
+ @Test
+ public void testNamespace() throws Exception {
+ final StyleSheetReader reader = new StyleSheetReader();
+ final StyleSheet styleSheet = reader.read("vex|plan {font-size: 123px;} vex|plan:before { content: 'test' }");
+ final Element element = new Element(new QualifiedName(Namespace.VEX_NAMESPACE_URI, "plan"));
+ final Styles styles = styleSheet.getStyles(element);
+ assertEquals(123.0f, styles.getFontSize(), 0.0f);
+ final IElement before = styleSheet.getPseudoElement(element, "before", false);
+ final Styles beforeStyles = styleSheet.getStyles(before);
+ assertEquals("test", beforeStyles.getContent(element).get(0));
+ assertEquals(123.0f, beforeStyles.getFontSize(), 0.0f);
+ }
+
+ @Test
+ public void testNamespaceWithChildSelector() throws Exception {
+ final StyleSheetReader reader = new StyleSheetReader();
+ final StyleSheet styleSheet = reader.read("vex|parent {font-size: 123px;} vex|parent > child { content: 'child' } child {content: 'nochild'}");
+ final Element element = new Element(new QualifiedName(Namespace.VEX_NAMESPACE_URI, "parent"));
+ final Element child = new Element("child");
+ final Element nochild = new Element("child");
+ child.setParent(element);
+ final Styles styles = styleSheet.getStyles(child);
+ assertEquals(1, styles.getContent(element).size());
+ assertEquals("child", styles.getContent(element).get(0));
+ final Styles nochildStyles = styleSheet.getStyles(nochild);
+ assertEquals("nochild", nochildStyles.getContent(element).get(0));
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/css/CssTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/css/CssTest.java
index a0e2cc3..3389232 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/css/CssTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/css/CssTest.java
@@ -12,6 +12,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import java.net.URL;
@@ -582,4 +583,10 @@
element.setAttribute("attribute", "After");
assertEquals("After", styles.getContent(element).get(0));
}
+
+ @Test
+ public void testCatalogImport() throws Exception {
+ final StyleSheet ss = parseStyleSheetResource("testCatalog.css");
+ assertTrue(ss.getRules().size() > 0);
+ }
}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/css/testCatalog.css b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/css/testCatalog.css
new file mode 100644
index 0000000..d9fc687
--- /dev/null
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/css/testCatalog.css
@@ -0,0 +1,2 @@
+/* Stylesheet for unit testing */
+@import url(urn:org:eclipse:vex:styles:test:test.css)
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/AttributeTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/AttributeTest.java
new file mode 100644
index 0000000..bbfe332
--- /dev/null
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/AttributeTest.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Carsten Hiesserich 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:
+ * Carsten Hiesserich - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.vex.core.internal.dom;
+
+import static org.junit.Assert.assertEquals;
+
+import org.eclipse.core.runtime.QualifiedName;
+import org.eclipse.vex.core.provisional.dom.IDocument;
+import org.eclipse.vex.core.provisional.dom.IElement;
+import org.junit.Test;
+
+public class AttributeTest {
+
+ @Test
+ public void testWithoutNamespace() throws Exception {
+ final IDocument doc = new Document(new QualifiedName(null, "a"));
+ final IElement a = doc.getRootElement();
+ final IElement ns = doc.insertElement(2, new QualifiedName("http://namespace/uri", "b"));
+
+ a.setAttribute("attr1", "attr1Val");
+ assertEquals("Expected attribute count", 1, a.getAttributes().size());
+ assertEquals("attr1Val", a.getAttribute("attr1").getValue());
+ assertEquals("attr1Val", a.getAttributeValue("attr1"));
+ a.removeAttribute("attr1");
+ assertEquals("Expected attribute count", 0, a.getAttributes().size());
+
+ ns.setAttribute("attr2", "attr2Val");
+ assertEquals("Expected attribute count", 1, ns.getAttributes().size());
+ assertEquals("attr2Val", ns.getAttribute("attr2").getValue());
+ assertEquals("attr2Val", ns.getAttributeValue("attr2"));
+ ns.removeAttribute("attr2");
+ assertEquals("Expected attribute count", 0, ns.getAttributes().size());
+ }
+
+ @Test
+ public void testWithNamespace() throws Exception {
+ final IDocument doc = new Document(new QualifiedName(null, "a"));
+ final IElement a = doc.getRootElement();
+ final IElement ns = doc.insertElement(2, new QualifiedName("http://namespace/uri", "b"));
+
+ a.setAttribute(new QualifiedName("http://namespace/attr", "attr1"), "attr1Val");
+ assertEquals("Expected attribute count", 1, a.getAttributes().size());
+ assertEquals("attr1Val", a.getAttribute(new QualifiedName("http://namespace/attr", "attr1")).getValue());
+ assertEquals("attr1Val", a.getAttributeValue(new QualifiedName("http://namespace/attr", "attr1")));
+ a.removeAttribute(new QualifiedName("http://namespace/attr", "attr1"));
+ assertEquals("Expected attribute count", 0, a.getAttributes().size());
+
+ ns.setAttribute(new QualifiedName("http://namespace/attr", "attr2"), "attr2Val");
+ assertEquals("Expected attribute count", 1, ns.getAttributes().size());
+ assertEquals("attr2Val", ns.getAttribute(new QualifiedName("http://namespace/attr", "attr2")).getValue());
+ assertEquals("attr2Val", ns.getAttributeValue(new QualifiedName("http://namespace/attr", "attr2")));
+ ns.removeAttribute(new QualifiedName("http://namespace/attr", "attr2"));
+ assertEquals("Expected attribute count", 0, ns.getAttributes().size());
+ }
+}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/BlockElementBoxTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/BlockElementBoxTest.java
index 195b73a..26a09ff 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/BlockElementBoxTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/BlockElementBoxTest.java
@@ -63,6 +63,7 @@
final RootBox parentBox = new RootBox(context, doc, 500);
final BlockElementBox box = new BlockElementBox(context, parentBox, doc.getRootElement());
+ box.setWidth(parentBox.getWidth());
final List<Box> childrenList = box.createChildren(context);
final Box[] children = childrenList.toArray(new Box[childrenList.size()]);
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/L1DeletionTests.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/L1DeletionTest.java
similarity index 98%
rename from org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/L1DeletionTests.java
rename to org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/L1DeletionTest.java
index 9d6dcba..c2d0282 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/L1DeletionTests.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/L1DeletionTest.java
@@ -21,7 +21,7 @@
import org.junit.Before;
import org.junit.Test;
-public class L1DeletionTests {
+public class L1DeletionTest {
private IDocument document;
private IElement child;
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/NamespaceTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/NamespaceTest.java
index 2c7e02b..e88bff0 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/NamespaceTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/NamespaceTest.java
@@ -4,7 +4,7 @@
* 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:
* Florian Thienel - initial API and implementation
* Carsten Hiesserich - test for handling of attribute namespaces in FindUndeclaredNamespacesVisitor
@@ -226,7 +226,7 @@
element.setAttribute(new QualifiedName("http://namespace/uri/2", "attribute3"), "value3");
assertEquals("attribute1", element.getAttribute("attribute1").getPrefixedName());
- assertEquals("attribute2", element.getAttribute(new QualifiedName("http://namespace/uri/1", "attribute2")).getPrefixedName());
+ assertEquals("ns1:attribute2", element.getAttribute(new QualifiedName("http://namespace/uri/1", "attribute2")).getPrefixedName());
assertEquals("ns2:attribute3", element.getAttribute(new QualifiedName("http://namespace/uri/2", "attribute3")).getPrefixedName());
}
@@ -280,25 +280,26 @@
final IDocument document = readDocumentFromString("<ns1:a xmlns=\"http://namespace/default\" xmlns:ns1=\"http://namespace/uri/1\" attr1=\"value1\">"
+ "<ns2:b xmlns:ns2=\"http://namespace/uri/2\" ns1:attr2=\"value2\" ns2:attr3=\"value3\" attr4=\"value4\" />" + "<c ns1:attr5=\"value5\" attr6=\"value6\" />" + "</ns1:a>");
final IElement rootElement = document.getRootElement();
- assertTrue(rootElement.getAttributeNames().contains(new QualifiedName("http://namespace/uri/1", "attr1")));
+ assertFalse(rootElement.getAttributeNames().contains(new QualifiedName("http://namespace/uri/1", "attr1")));
assertFalse(rootElement.getAttributeNames().contains(new QualifiedName("http://namespace/default", "attr1")));
assertFalse(rootElement.getAttributeNames().contains(new QualifiedName("", "attr1")));
- assertFalse(rootElement.getAttributeNames().contains(new QualifiedName(null, "attr1")));
+ assertTrue(rootElement.getAttributeNames().contains(new QualifiedName(null, "attr1")));
final IElement firstNestedElement = rootElement.childElements().first();
assertTrue(firstNestedElement.getAttributeNames().contains(new QualifiedName("http://namespace/uri/1", "attr2")));
assertTrue(firstNestedElement.getAttributeNames().contains(new QualifiedName("http://namespace/uri/2", "attr3")));
- assertTrue(firstNestedElement.getAttributeNames().contains(new QualifiedName("http://namespace/uri/2", "attr4")));
+ assertTrue(firstNestedElement.getAttributeNames().contains(new QualifiedName(null, "attr4")));
final IElement secondNestedElement = rootElement.childElements().get(1);
assertTrue(secondNestedElement.getAttributeNames().contains(new QualifiedName("http://namespace/uri/1", "attr5")));
- assertTrue(secondNestedElement.getAttributeNames().contains(new QualifiedName("http://namespace/default", "attr6")));
+ assertTrue(secondNestedElement.getAttributeNames().contains(new QualifiedName(null, "attr6")));
}
@Test
public void readWriteCycle() throws Exception {
+ // Caution: Vex sorts attributes on writing, so the order of attributes may change
final String inputContent = "<?xml version='1.0' encoding='UTF-8'?> <ns1:a xmlns=\"http://namespace/default\" xmlns:ns1=\"http://namespace/uri/1\" attr1=\"value1\"> "
- + "<ns2:b xmlns:ns2=\"http://namespace/uri/2\" ns1:attr2=\"value2\" attr3=\"value3\"/> " + "<c attr4=\"value4\" ns1:attr5=\"value5\"/>" + "</ns1:a> ";
+ + "<ns2:b xmlns:ns2=\"http://namespace/uri/2\" ns1:attr2=\"value2\" ns2:attr3=\"value3\"/> " + "<c attr4=\"value4\" ns1:attr5=\"value5\"/>" + "</ns1:a> ";
final IDocument document = readDocumentFromString(inputContent);
final DocumentWriter documentWriter = new DocumentWriter();
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/ParentTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/ParentTest.java
index 678b831..c894112 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/ParentTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/ParentTest.java
@@ -4,7 +4,7 @@
* 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:
* Florian Thienel - initial API and implementation
* Carsten Hiesserich - extended insert / remove tests for nodes with text (bug 408731)
@@ -453,6 +453,48 @@
}
@Test
+ public void shouldReturnChildAtOffset() throws Exception {
+ content.insertText(parent.getEndOffset(), "Hello ");
+ final TestChild child1 = addTestChild();
+ content.insertText(child1.getEndOffset(), "Child1");
+
+ assertSame(child1, parent.getChildAt(9));
+ }
+
+ @Test
+ public void shouldReturnTextAtOffsetBetweenChildren() throws Exception {
+ content.insertText(parent.getEndOffset(), "Hello ");
+ final TestChild child1 = addTestChild();
+ content.insertText(child1.getEndOffset(), "Child1");
+ content.insertText(parent.getEndOffset(), " Gap ");
+ final TestChild child2 = addTestChild();
+ content.insertText(child2.getEndOffset(), "Child2");
+ content.insertText(parent.getEndOffset(), " World");
+
+ final INode text = parent.children().get(2);
+
+ assertTextNodeEquals(" Gap ", text.getStartOffset(), text.getEndOffset(), parent.getChildAt(text.getStartOffset() + 1));
+ }
+
+ @Test
+ public void shouldReturnTextAtOffsetBeforeFirstChild() throws Exception {
+ setUpChildNodes();
+
+ final INode text = parent.children().get(0);
+
+ assertTextNodeEquals("Hello ", text.getStartOffset(), text.getEndOffset(), parent.getChildAt(text.getStartOffset() + 1));
+ }
+
+ @Test
+ public void shouldReturnTextAtOffsetAfterLastChild() throws Exception {
+ setUpChildNodes();
+
+ final INode text = parent.children().get(3);
+
+ assertTextNodeEquals(" World", text.getStartOffset(), text.getEndOffset(), parent.getChildAt(text.getStartOffset() + 1));
+ }
+
+ @Test
public void shouldReturnTextWithinBoundaries() throws Exception {
content.insertText(parent.getEndOffset(), "Hello World");
final INode text = parent.children().first();
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/io/DocumentContentModelTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/io/DocumentContentModelTest.java
index e643210..52e3aa7 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/io/DocumentContentModelTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/io/DocumentContentModelTest.java
@@ -16,8 +16,6 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import java.net.URL;
-
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.vex.core.internal.dom.Element;
import org.eclipse.vex.core.provisional.dom.DocumentContentModel;
@@ -99,17 +97,24 @@
}
@Test
- public void resolveSchemaIdentifier() throws Exception {
- final URL resolvedUrl = model.resolveSchemaIdentifier(TestResources.TEST_DTD);
+ public void resolveSchemaBySchemaLocation() throws Exception {
+ final String resolvedUrl = model.resolveResourceURI(null, "http://www.eclipse.org/vex/test/content.xsd");
assertNotNull(resolvedUrl);
- assertTrue(resolvedUrl.toString().contains(VEXCoreTestPlugin.PLUGIN_ID));
+ assertTrue(resolvedUrl.contains(VEXCoreTestPlugin.PLUGIN_ID) && resolvedUrl.endsWith("testResources/content.xsd"));
+ }
+
+ @Test
+ public void resolveSchemaByNamespace() throws Exception {
+ final String resolvedUrl = model.resolveResourceURI(null, "http://www.eclipse.org/vex/test/content");
+ assertNotNull(resolvedUrl);
+ assertTrue(resolvedUrl.contains(VEXCoreTestPlugin.PLUGIN_ID) && resolvedUrl.endsWith("testResources/content.xsd"));
}
@Test
public void onlySystemId() throws Exception {
model.initialize(null, null, TestResources.get("test1.dtd").toString(), null);
assertTrue(model.isDtdAssigned());
- assertNotNull(model.getDTD());
+ assertNotNull(model.getContentModelDocument());
}
@Test
@@ -117,8 +122,26 @@
final String baseUri = TestResources.get("test.css").toString();
model.initialize(baseUri, null, "test1.dtd", null);
assertTrue(model.isDtdAssigned());
- final CMDocument dtd = model.getDTD();
+ final CMDocument dtd = model.getContentModelDocument();
assertNotNull(dtd);
assertEquals(11, dtd.getElements().getLength());
}
+
+ @Test
+ public void onlyNamespace() throws Exception {
+ model.initialize(null, null, null, new Element(new QualifiedName("http://www.eclipse.org/vex/test/content", "rootElement")));
+ assertFalse(model.isDtdAssigned());
+ final CMDocument schema = model.getContentModelDocument();
+ assertNotNull(schema);
+ assertEquals(1, schema.getElements().getLength());
+ }
+
+ @Test
+ public void testExplicitNamespace() throws Exception {
+ model.setSchemaId(null, "http://www.eclipse.org/vex/test/content");
+ assertFalse(model.isDtdAssigned());
+ final CMDocument schema = model.getContentModelDocument();
+ assertNotNull(schema);
+ assertEquals(1, schema.getElements().getLength());
+ }
}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/io/DocumentReaderTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/io/DocumentReaderTest.java
index dab2031..ca6aa00 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/io/DocumentReaderTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/io/DocumentReaderTest.java
@@ -21,11 +21,14 @@
import java.io.IOException;
import java.net.URL;
import java.util.Iterator;
+import java.util.List;
+import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.vex.core.IFilter;
import org.eclipse.vex.core.internal.dom.DummyValidator;
import org.eclipse.vex.core.provisional.dom.BaseNodeVisitorWithResult;
import org.eclipse.vex.core.provisional.dom.DocumentContentModel;
+import org.eclipse.vex.core.provisional.dom.IAttribute;
import org.eclipse.vex.core.provisional.dom.IAxis;
import org.eclipse.vex.core.provisional.dom.IComment;
import org.eclipse.vex.core.provisional.dom.IDocument;
@@ -234,4 +237,20 @@
assertEquals("whitespace text nodes", 0, nodesWithEmptyTextNodes.count());
}
+
+ @Test
+ public void readDocumentWithAttributes() throws Exception {
+ final DocumentReader reader = new DocumentReader();
+ final IDocument document = reader.read(TestResources.get("document.xml"));
+ final List<? extends IElement> elements = document.getRootElement().childElements().asList();
+ final IElement chapter = elements.get(1);
+ assertEquals("chapter", chapter.getLocalName());
+ assertEquals("Expected attributes in chapter element", 2, chapter.getAttributes().size());
+ final IAttribute attr1 = chapter.getAttribute(new QualifiedName(null, "attribute"));
+ assertNotNull("Attribute without namespace not found", attr1);
+ assertEquals("Value of attribute without namespace", "ns-null", attr1.getValue());
+ final IAttribute attr2 = chapter.getAttribute(new QualifiedName("http://www.eclipse.org/vex/test/content", "attribute"));
+ assertNotNull("Attribute with namespace not found", attr2);
+ assertEquals("Value of attribute without namespace", "ns-content", attr2.getValue());
+ }
}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/FormattingPortionIteratorTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/FormattingPortionIteratorTest.java
new file mode 100644
index 0000000..52cf070
--- /dev/null
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/FormattingPortionIteratorTest.java
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Florian Thienel 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:
+ * Florian Thienel - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.vex.core.internal.layout;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
+import org.eclipse.core.runtime.QualifiedName;
+import org.eclipse.vex.core.internal.css.IWhitespacePolicy;
+import org.eclipse.vex.core.internal.dom.Document;
+import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.provisional.dom.ContentRange;
+import org.eclipse.vex.core.provisional.dom.IElement;
+import org.eclipse.vex.core.provisional.dom.INode;
+import org.eclipse.vex.core.provisional.dom.IParent;
+import org.junit.Test;
+
+/**
+ * @author Florian Thienel
+ */
+public class FormattingPortionIteratorTest {
+
+ private Document document;
+ private IParent parent;
+ private Element blockElement;
+
+ @Test
+ public void givenRangeWithBlockElement_whenBlockElementStartsAtRangeStart_shouldReturnBlockElement() throws Exception {
+ givenRangeWithBlockElement();
+
+ final FormattingPortionIterator iterator = createIterator(blockElement.getStartOffset(), parent.getEndOffset());
+
+ assertSame(blockElement, iterator.next());
+ }
+
+ @Test
+ public void givenRangeWithBlockElement_whenBlockElementStartsAfterRangeStart_shouldReturnRangeBeforeBlockElement() throws Exception {
+ givenRangeWithBlockElement();
+
+ final FormattingPortionIterator iterator = createIterator(blockElement.getStartOffset() - 2, parent.getEndOffset());
+
+ assertEquals(new ContentRange(blockElement.getStartOffset() - 2, blockElement.getStartOffset()), iterator.next());
+ }
+
+ @Test
+ public void givenRangeWithBlockElement_whenContentExistsAfterBlockElement_shouldReturnRangeAfterBlockElement() throws Exception {
+ givenRangeWithBlockElement();
+
+ final FormattingPortionIterator iterator = createIterator(blockElement.getStartOffset(), parent.getEndOffset());
+
+ iterator.next();
+ assertEquals(new ContentRange(blockElement.getEndOffset() + 1, parent.getEndOffset()), iterator.next());
+ }
+
+ @Test
+ public void givenRangeWithBlockElement_whenNoMoreContentExists_shouldReturnNull() throws Exception {
+ givenRangeWithBlockElement();
+
+ final FormattingPortionIterator iterator = createIterator(blockElement.getEndOffset(), parent.getEndOffset());
+
+ iterator.next();
+ assertNull(iterator.next());
+ }
+
+ @Test
+ public void givenRangeWithBlockElement_whenContentRangeIsPushed_shouldReturnContentRange() throws Exception {
+ givenRangeWithBlockElement();
+
+ final FormattingPortionIterator iterator = createIterator(parent.getStartOffset(), parent.getEndOffset());
+
+ final ContentRange contentRange = (ContentRange) iterator.next();
+ iterator.push(contentRange);
+
+ assertSame(contentRange, iterator.next());
+ }
+
+ @Test
+ public void givenRangeWithBlockElement_whenBlockElementIsPushed_shouldReturnBlockElement() throws Exception {
+ givenRangeWithBlockElement();
+
+ final FormattingPortionIterator iterator = createIterator(blockElement.getStartOffset(), parent.getEndOffset());
+
+ final IElement element = (IElement) iterator.next();
+ iterator.push(element);
+
+ assertSame(element, iterator.next());
+ }
+
+ @Test
+ public void givenRangeWithBlockElement_whenEndingWithinBlockElement_shouldNotReturnBlockElement() throws Exception {
+ givenRangeWithBlockElement();
+
+ final FormattingPortionIterator iterator = createIterator(parent.getStartOffset(), blockElement.getStartOffset() + 2);
+
+ iterator.next();
+ assertNull(iterator.next());
+ }
+
+ @Test
+ public void givenRangeWithSeveralBlockElements_shouldReturnAllBlockElementsAndRanges() throws Exception {
+ givenRangeWithBlockElements(10);
+
+ final FormattingPortionIterator iterator = createIterator(parent.getStartOffset(), parent.getEndOffset());
+
+ int count = 0;
+ while (iterator.next() != null) {
+ count++;
+ }
+ assertEquals(12, count);
+ }
+
+ private void givenRangeWithBlockElement() {
+ givenRangeWithBlockElements(1);
+ }
+
+ private void givenRangeWithBlockElements(final int count) {
+ document = new Document(new QualifiedName(null, "parent"));
+ parent = document.getRootElement();
+ document.insertText(parent.getEndOffset(), "Hello");
+ for (int i = 0; i < count; i++) {
+ blockElement = document.insertElement(parent.getEndOffset(), new QualifiedName(null, "element"));
+ document.insertText(blockElement.getEndOffset(), "Block " + i);
+ }
+ document.insertText(parent.getEndOffset(), "World");
+ }
+
+ private FormattingPortionIterator createIterator(final int startOffset, final int endOffset) {
+ return new FormattingPortionIterator(new IWhitespacePolicy() {
+ @Override
+ public boolean isBlock(final INode node) {
+ return node instanceof IElement;
+ }
+
+ @Override
+ public boolean isPre(final INode node) {
+ return false;
+ }
+ }, parent, startOffset, endOffset);
+ }
+}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/LayoutTestSuite.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/LayoutTest.java
similarity index 86%
rename from org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/LayoutTestSuite.java
rename to org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/LayoutTest.java
index 6d6f6be..25ea549 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/LayoutTestSuite.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/LayoutTest.java
@@ -30,7 +30,6 @@
import org.eclipse.vex.core.internal.css.IStyleSheetProvider;
import org.eclipse.vex.core.internal.css.StyleSheet;
import org.eclipse.vex.core.internal.css.StyleSheetReader;
-import org.eclipse.vex.core.internal.dom.DummyValidator;
import org.eclipse.vex.core.internal.io.DocumentReader;
import org.eclipse.vex.core.provisional.dom.BaseNodeVisitorWithResult;
import org.eclipse.vex.core.provisional.dom.ContentRange;
@@ -54,6 +53,8 @@
* <ul>
* <li>insertTextAction="someText" - Insert the given text at the end of the element.</li>
* <li>removeTextAction="5" - Remove given length text from the start of the element.</li>
+ * <li>removeElementAction="1" - Remove the element that defined this box.</li>
+ * <li>shouldBeRemoved="1" - This box is expected to be removed;
* <li>InvalidateAction="1" - Invalidates the element (only valid in BlockBox instances)</li>
* </ul>
* The expected layout state of an box may be checked with the attribute <code>layoutState="LAYOUT_XXX"</code> (
@@ -62,17 +63,18 @@
*
*/
@RunWith(AllTests.class)
-public class LayoutTestSuite extends TestCase {
+public class LayoutTest extends TestCase {
public String id;
public String documentContent;
public int layoutWidth = 100;
public boolean performActions = false;
+ public boolean invalidateParentBlock;
public BoxSpec result;
public String css;
public static Test suite() throws ParserConfigurationException, FactoryConfigurationError, IOException, SAXException {
- final TestSuite suite = new TestSuite(LayoutTestSuite.class.getName());
+ final TestSuite suite = new TestSuite(LayoutTest.class.getName());
suite.addTest(loadSuite("block-inline.xml"));
suite.addTest(loadSuite("before-after.xml"));
suite.addTest(loadSuite("linebreaks.xml"));
@@ -87,17 +89,17 @@
final TestCaseBuilder builder = new TestCaseBuilder();
xmlReader.setContentHandler(builder);
// xmlReader.setEntityResolver(builder);
- final URL url = LayoutTestSuite.class.getResource(filename);
+ final URL url = LayoutTest.class.getResource(filename);
xmlReader.parse(new InputSource(url.toString()));
final TestSuite suite = new TestSuite(filename);
- for (final LayoutTestSuite test : builder.testCases) {
+ for (final LayoutTest test : builder.testCases) {
suite.addTest(test);
}
return suite;
}
- public LayoutTestSuite() {
+ public LayoutTest() {
super("testLayout");
}
@@ -107,7 +109,7 @@
}
public void testLayout() throws Exception {
- final URL url = LayoutTestSuite.class.getResource(css);
+ final URL url = LayoutTest.class.getResource(css);
final StyleSheet styleSheet = new StyleSheetReader().read(url);
final FakeGraphics g = new FakeGraphics();
@@ -119,7 +121,7 @@
context.setWhitespacePolicy(new CssWhitespacePolicy(styleSheet));
final DocumentReader reader = new DocumentReader();
- reader.setValidator(new DummyValidator());
+ reader.setValidator(new LayoutTestValidator());
reader.setStyleSheetProvider(new IStyleSheetProvider() {
public StyleSheet getStyleSheet(final DocumentContentModel documentContentModel) {
return styleSheet;
@@ -127,6 +129,7 @@
});
reader.setWhitespacePolicyFactory(CssWhitespacePolicy.FACTORY);
final IDocument document = reader.read(documentContent);
+ document.setValidator(reader.getValidator());
context.setDocument(document);
final RootBox rootBox = new RootBox(context, document, layoutWidth);
@@ -143,7 +146,8 @@
}
}
- private static void performActions(final BoxSpec boxSpec, final Box box, final IDocument doc) {
+ private void performActions(final BoxSpec boxSpec, final Box box, final IDocument doc) {
+
if (boxSpec.insertTextAction != null) {
doc.insertText(box.getNode().getEndOffset(), boxSpec.insertTextAction);
}
@@ -158,12 +162,36 @@
doc.getContent().remove(new ContentRange(startOffset + 1, startOffset + boxSpec.removeTextAction));
}
+ if (boxSpec.removeElementAction) {
+ if (box.getNode() == null) {
+ fail(String.format("Error in test configuration. Can not remove element for box'%s'", boxSpec.toString()));
+ }
+ System.out.println("Removing element " + box.getNode());
+ final int startOffset = box.getNode().getStartOffset();
+ final int endOffset = box.getNode().getEndOffset();
+ doc.delete(new ContentRange(startOffset, endOffset));
+ invalidateParentBlock = true;
+ return;
+ }
+
if (boxSpec.invalidateAction && box instanceof BlockBox) {
((BlockBox) box).invalidate(true);
}
+ final List<BoxSpec> toRemove = new ArrayList<BoxSpec>();
for (int i = 0; i < boxSpec.children.size(); i++) {
- performActions(boxSpec.children.get(i), box.getChildren()[i], doc);
+ final BoxSpec childSpec = boxSpec.children.get(i);
+ performActions(childSpec, box.getChildren()[i], doc);
+ if (childSpec.removeElementAction || childSpec.shouldBeRemoved) {
+ toRemove.add(childSpec);
+ }
+ }
+
+ boxSpec.children.removeAll(toRemove);
+
+ if (invalidateParentBlock && box instanceof BlockBox && box.getNode() != null) {
+ ((BlockBox) box).invalidate(true);
+ invalidateParentBlock = false;
}
}
@@ -248,9 +276,9 @@
private static class TestCaseBuilder extends DefaultHandler {
- private List<LayoutTestSuite> testCases;
+ private List<LayoutTest> testCases;
private String css;
- private LayoutTestSuite testCase;
+ private LayoutTest testCase;
private BoxSpec boxSpec;
private Stack<BoxSpec> boxSpecs;
private boolean inDoc;
@@ -285,7 +313,7 @@
public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) throws SAXException {
if (qName.equals("testcases")) {
- testCases = new ArrayList<LayoutTestSuite>();
+ testCases = new ArrayList<LayoutTest>();
css = attributes.getValue("css");
if (css == null) {
css = "test.css";
@@ -293,7 +321,7 @@
testCase = null;
boxSpecs = new Stack<BoxSpec>();
} else if (qName.equals("test")) {
- testCase = new LayoutTestSuite();
+ testCase = new LayoutTest();
testCase.id = attributes.getValue("id");
testCase.css = css;
final String layoutWidth = attributes.getValue("layoutWidth");
@@ -319,7 +347,9 @@
} catch (final NumberFormatException e) {
boxSpec.removeTextAction = 0;
}
+ boxSpec.removeElementAction = attributes.getValue("removeElementAction") != null;
boxSpec.invalidateAction = attributes.getValue("invalidateAction") != null;
+ boxSpec.shouldBeRemoved = attributes.getValue("shouldBeRemoved") != null;
String layoutStateAttr = attributes.getValue("layoutState");
if (layoutStateAttr != null) {
layoutStateAttr = layoutStateAttr.trim().toLowerCase();
@@ -353,6 +383,8 @@
public byte layoutState = -1;
public String insertTextAction;
public int removeTextAction;
+ public boolean removeElementAction;
+ public boolean shouldBeRemoved;
public boolean invalidateAction = false;
}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/LayoutTestValidator.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/LayoutTestValidator.java
new file mode 100644
index 0000000..b760b7b
--- /dev/null
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/LayoutTestValidator.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Carsten Hiesserich 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:
+ * Carsten Hiesserich - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.vex.core.internal.layout;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.QualifiedName;
+import org.eclipse.vex.core.internal.dom.DummyValidator;
+
+/**
+ * A dummy validator tzo be used with layout tests
+ */
+public class LayoutTestValidator extends DummyValidator {
+
+ final static List<String> nodesForInsertion = new ArrayList<String>();
+ static {
+ nodesForInsertion.add("p");
+ };
+
+ @Override
+ public boolean isValidSequence(final QualifiedName element, final List<QualifiedName> sequence1, final List<QualifiedName> sequence2, final List<QualifiedName> sequence3, final boolean partial) {
+ // Allow insertions in <p> element
+ if (nodesForInsertion.contains(element.getLocalName())) {
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TestDocumentTextBox.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TestDocumentTextBox.java
index 659a01f..9efbe3d 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TestDocumentTextBox.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TestDocumentTextBox.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2008 John Krasnay and others.
+ * Copyright (c) 2004, 2013 John Krasnay 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
@@ -7,6 +7,7 @@
*
* Contributors:
* John Krasnay - initial API and implementation
+ * Carsten Hiesserich - adapted tests to optimized split methods
*******************************************************************************/
package org.eclipse.vex.core.internal.layout;
@@ -25,6 +26,7 @@
import org.eclipse.vex.core.provisional.dom.ContentRange;
import org.eclipse.vex.core.provisional.dom.IDocument;
import org.eclipse.vex.core.provisional.dom.IElement;
+import org.eclipse.vex.core.provisional.dom.INode;
import org.junit.Test;
/**
@@ -57,48 +59,62 @@
final Styles styles = context.getStyleSheet().getStyles(root);
- final int width = g.getCharWidth();
-
// 0 6 13 21
// / / / /
// baggy orange trousers
doc.insertText(2, "baggy orange trousers");
- final DocumentTextBox box = new DocumentTextBox(context, root, 2, 23);
- assertEquals(box.getText().length() * width, box.getWidth());
+ final DocumentTextBox box = new DocumentTextBox(context, root, root.getStartOffset() + 1, root.getEndOffset() - 1);
assertEquals(styles.getLineHeight(), box.getHeight());
- assertSplit(box, 22, false, "baggy orange ", "trousers");
- assertSplit(box, 21, false, "baggy orange ", "trousers");
- assertSplit(box, 20, false, "baggy orange ", "trousers");
- assertSplit(box, 13, false, "baggy orange ", "trousers");
- assertSplit(box, 12, false, "baggy ", "orange trousers");
- assertSplit(box, 6, false, "baggy ", "orange trousers");
- assertSplit(box, 5, false, null, "baggy orange trousers");
- assertSplit(box, 1, false, null, "baggy orange trousers");
- assertSplit(box, 0, false, null, "baggy orange trousers");
- assertSplit(box, -1, false, null, "baggy orange trousers");
- assertSplit(box, 22, true, "baggy orange ", "trousers");
- assertSplit(box, 21, true, "baggy orange ", "trousers");
- assertSplit(box, 20, true, "baggy orange ", "trousers");
- assertSplit(box, 13, true, "baggy orange ", "trousers");
- assertSplit(box, 12, true, "baggy ", "orange trousers");
- assertSplit(box, 6, true, "baggy ", "orange trousers");
- assertSplit(box, 5, true, "baggy ", "orange trousers");
- assertSplit(box, 4, true, "bagg", "y orange trousers");
- assertSplit(box, 3, true, "bag", "gy orange trousers");
- assertSplit(box, 2, true, "ba", "ggy orange trousers");
- assertSplit(box, 1, true, "b", "aggy orange trousers");
- assertSplit(box, 0, true, "b", "aggy orange trousers");
- assertSplit(box, -1, true, "b", "aggy orange trousers");
+ assertSplit(root, 22, false, "baggy orange ", "trousers");
+ assertSplit(root, 21, false, "baggy orange ", "trousers");
+ assertSplit(root, 20, false, "baggy orange ", "trousers");
+ assertSplit(root, 13, false, "baggy orange ", "trousers");
+ assertSplit(root, 12, false, "baggy ", "orange trousers");
+ assertSplit(root, 6, false, "baggy ", "orange trousers");
+ assertSplit(root, 5, false, null, "baggy orange trousers");
+ assertSplit(root, 1, false, null, "baggy orange trousers");
+ assertSplit(root, 0, false, null, "baggy orange trousers");
+ assertSplit(root, -1, false, null, "baggy orange trousers");
+
+ assertSplit(root, 22, true, "baggy orange ", "trousers");
+ assertSplit(root, 21, true, "baggy orange ", "trousers");
+ assertSplit(root, 20, true, "baggy orange ", "trousers");
+ assertSplit(root, 13, true, "baggy orange ", "trousers");
+ assertSplit(root, 12, true, "baggy ", "orange trousers");
+ assertSplit(root, 6, true, "baggy ", "orange trousers");
+ assertSplit(root, 5, true, "baggy ", "orange trousers");
+ assertSplit(root, 4, true, "bagg", "y orange trousers");
+ assertSplit(root, 3, true, "bag", "gy orange trousers");
+ assertSplit(root, 2, true, "ba", "ggy orange trousers");
+ assertSplit(root, 1, true, "b", "aggy orange trousers");
+ assertSplit(root, 0, true, "b", "aggy orange trousers");
+ assertSplit(root, -1, true, "b", "aggy orange trousers");
doc.delete(new ContentRange(3, 22));
}
- private void assertSplit(final DocumentTextBox box, final int splitPos, final boolean force, final String left, final String right) {
+ @Test
+ public void testMultipleSplit() throws Exception {
+ final IDocument doc = new Document(new QualifiedName(null, "root"));
+ doc.insertText(2, "12345 67890 ");
+ final IElement root = doc.getRootElement();
+ final DocumentTextBox box = new DocumentTextBox(context, root, root.getStartOffset() + 1, root.getEndOffset() - 1);
+ final InlineBox.Pair pair = box.split(context, 150, false);
+ assertEquals("12345 ", ((DocumentTextBox) pair.getLeft()).getText());
+ final InlineBox.Pair pair2 = pair.getRight().split(context, 100, false);
+ assertNull(pair2.getLeft());
+ assertEquals("67890 ", ((DocumentTextBox) pair2.getRight()).getText());
+ assertEquals("Last right box should have a width", 36, pair2.getRight().getWidth());
+ }
+
+ private void assertSplit(final INode node, final int splitPos, final boolean force, final String left, final String right) {
+
+ final DocumentTextBox box = new DocumentTextBox(context, node, node.getStartOffset() + 1, node.getEndOffset() - 1);
final Styles styles = context.getStyleSheet().getStyles(box.getNode());
-
+ final int textLength = box.getText().length();
final int width = g.getCharWidth();
final InlineBox.Pair pair = box.split(context, splitPos * width, force);
@@ -106,9 +122,9 @@
final DocumentTextBox leftBox = (DocumentTextBox) pair.getLeft();
final DocumentTextBox rightBox = (DocumentTextBox) pair.getRight();
- final int leftOffset = 2;
+ final int leftOffset = box.getNode().getStartOffset() + 1;
final int midOffset = leftOffset + (left == null ? 0 : left.length());
- final int rightOffset = leftOffset + box.getText().length();
+ final int rightOffset = leftOffset + textLength;
if (left == null) {
assertNull(leftBox);
@@ -126,10 +142,10 @@
} else {
assertNotNull(rightBox);
assertEquals(right, rightBox.getText());
- assertEquals(right.length() * width, rightBox.getWidth());
+ //assertEquals(right.length() * width, rightBox.getWidth());
assertEquals(styles.getLineHeight(), rightBox.getHeight());
assertEquals(midOffset, rightBox.getStartOffset());
- assertEquals(rightOffset, rightBox.getEndOffset());
+ assertEquals(rightOffset - 1, rightBox.getEndOffset());
}
}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TestStaticTextBox.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TestStaticTextBox.java
index 5215646..6e34941 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TestStaticTextBox.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TestStaticTextBox.java
@@ -23,6 +23,7 @@
import org.eclipse.vex.core.internal.css.StyleSheetReader;
import org.eclipse.vex.core.internal.css.Styles;
import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.provisional.dom.INode;
import org.junit.Before;
import org.junit.Test;
@@ -54,47 +55,58 @@
@Test
public void testSplit() throws Exception {
- final int width = g.getCharWidth();
- final StaticTextBox box = new StaticTextBox(context, root, "baggy orange trousers");
- assertEquals(box.getText().length() * width, box.getWidth());
+ final StaticTextBox box = new StaticTextBox(context, root, "test");
assertEquals(styles.getLineHeight(), box.getHeight());
- assertSplit(box, 22, false, "baggy orange ", "trousers");
- assertSplit(box, 21, false, "baggy orange ", "trousers");
- assertSplit(box, 20, false, "baggy orange ", "trousers");
- assertSplit(box, 13, false, "baggy orange ", "trousers");
- assertSplit(box, 12, false, "baggy ", "orange trousers");
- assertSplit(box, 6, false, "baggy ", "orange trousers");
- assertSplit(box, 5, false, null, "baggy orange trousers");
- assertSplit(box, 1, false, null, "baggy orange trousers");
- assertSplit(box, 0, false, null, "baggy orange trousers");
- assertSplit(box, -1, false, null, "baggy orange trousers");
- assertSplit(box, 22, true, "baggy orange ", "trousers");
- assertSplit(box, 21, true, "baggy orange ", "trousers");
- assertSplit(box, 20, true, "baggy orange ", "trousers");
- assertSplit(box, 13, true, "baggy orange ", "trousers");
- assertSplit(box, 12, true, "baggy ", "orange trousers");
- assertSplit(box, 6, true, "baggy ", "orange trousers");
- assertSplit(box, 5, true, "baggy ", "orange trousers");
- assertSplit(box, 4, true, "bagg", "y orange trousers");
- assertSplit(box, 3, true, "bag", "gy orange trousers");
- assertSplit(box, 2, true, "ba", "ggy orange trousers");
- assertSplit(box, 1, true, "b", "aggy orange trousers");
- assertSplit(box, 0, true, "b", "aggy orange trousers");
- assertSplit(box, -1, true, "b", "aggy orange trousers");
+ assertSplit(root, 22, false, "baggy orange ", "trousers");
+ assertSplit(root, 21, false, "baggy orange ", "trousers");
+ assertSplit(root, 20, false, "baggy orange ", "trousers");
+ assertSplit(root, 13, false, "baggy orange ", "trousers");
+ assertSplit(root, 12, false, "baggy ", "orange trousers");
+ assertSplit(root, 6, false, "baggy ", "orange trousers");
+ assertSplit(root, 5, false, null, "baggy orange trousers");
+ assertSplit(root, 1, false, null, "baggy orange trousers");
+ assertSplit(root, 0, false, null, "baggy orange trousers");
+ assertSplit(root, -1, false, null, "baggy orange trousers");
+
+ assertSplit(root, 22, true, "baggy orange ", "trousers");
+ assertSplit(root, 21, true, "baggy orange ", "trousers");
+ assertSplit(root, 20, true, "baggy orange ", "trousers");
+ assertSplit(root, 13, true, "baggy orange ", "trousers");
+ assertSplit(root, 12, true, "baggy ", "orange trousers");
+ assertSplit(root, 6, true, "baggy ", "orange trousers");
+ assertSplit(root, 5, true, "baggy ", "orange trousers");
+ assertSplit(root, 4, true, "bagg", "y orange trousers");
+ assertSplit(root, 3, true, "bag", "gy orange trousers");
+ assertSplit(root, 2, true, "ba", "ggy orange trousers");
+ assertSplit(root, 1, true, "b", "aggy orange trousers");
+ assertSplit(root, 0, true, "b", "aggy orange trousers");
+ assertSplit(root, -1, true, "b", "aggy orange trousers");
}
+ @Test
public void testSpaceSplit() throws Exception {
- final StaticTextBox box = new StaticTextBox(context, root, "red green");
- assertSplit(box, 11, false, "red ", "green");
- assertSplit(box, 10, false, "red ", "green");
- assertSplit(box, 9, false, "red ", "green");
- assertSplit(box, 5, false, "red ", "green");
-
+ assertSplit(root, 11, false, "red ", "green");
+ assertSplit(root, 10, false, "red ", "green");
+ assertSplit(root, 9, false, "red ", "green");
+ assertSplit(root, 5, false, "red ", "green");
}
- private void assertSplit(final StaticTextBox box, final int splitPos, final boolean force, final String left, final String right) {
+ @Test
+ public void testMultipleSplit() throws Exception {
+ final StaticTextBox box = new StaticTextBox(context, root, "12345 67890 ");
+ final InlineBox.Pair pair = box.split(context, 150, false);
+ assertEquals("12345 ", ((StaticTextBox) pair.getLeft()).getText());
+ final InlineBox.Pair pair2 = pair.getRight().split(context, 100, false);
+ assertNull(pair2.getLeft());
+ assertEquals("67890 ", ((StaticTextBox) pair2.getRight()).getText());
+ assertEquals("Last right box should have a width", 36, pair2.getRight().getWidth());
+ }
+
+ private void assertSplit(final INode node, final int splitPos, final boolean force, final String left, final String right) {
+
+ final StaticTextBox box = new StaticTextBox(context, node, left != null ? left + right : right);
final Styles styles = context.getStyleSheet().getStyles(box.getNode());
final int width = g.getCharWidth();
@@ -118,7 +130,6 @@
} else {
assertNotNull(rightBox);
assertEquals(right, rightBox.getText());
- assertEquals(right.length() * width, rightBox.getWidth());
assertEquals(styles.getLineHeight(), rightBox.getHeight());
}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/before-after.css b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/before-after.css
index 78e02cd..74b3077 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/before-after.css
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/before-after.css
@@ -21,6 +21,15 @@
}
+iib2 {
+ display: inline;
+}
+
+iib2:before {
+ display: inline;
+ content: 'BEFORE1 BEFORE2 ';
+}
+
iba {
display: inline;
}
@@ -78,3 +87,12 @@
content: 'BEFORE';
}
+bbb2 {
+ display: block;
+}
+
+bbb2:before {
+ display: block;
+ content: 'BEFORE1 BEFORE2 ';
+}
+
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/before-after.xml b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/before-after.xml
index 19670db..f48a7a6 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/before-after.xml
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/before-after.xml
@@ -114,6 +114,74 @@
</result>
</test>
+ <test id="Block with Split In Before" layoutWidth="42">
+ <doc><![CDATA[ <root><bbb2>wuzzle</bbb2></root> ]]></doc>
+ <result>
+ <box class="RootBox">
+ <box class="BlockElementBox">
+ <box class="BlockElementBox" element="root">
+
+ <box class="BlockElementBox" element="bbb2">
+
+ <box class="BlockPseudoElementBox">
+ <box class="ParagraphBox">
+ <box class="LineBox">
+ <box class="StaticTextBox" text="BEFORE1 " />
+ </box>
+ <box class="LineBox">
+ <box class="StaticTextBox" text="BEFORE2 " />
+ </box>
+ </box>
+ </box>
+
+ <box class="ParagraphBox">
+ <box class="LineBox">
+ <box class="DocumentTextBox" text="wuzzle" />
+ <box class="PlaceholderBox" />
+ </box>
+ </box>
+
+ </box>
+ </box>
+ </box>
+ </box>
+ </result>
+ </test>
+
+ <test id="Inline with Split In Before" layoutWidth="66">
+ <doc><![CDATA[ <root>abc<iib2>wuzzle</iib2></root> ]]></doc>
+ <result>
+ <box class="RootBox">
+ <box class="BlockElementBox">
+ <box class="BlockElementBox" element="root">
+ <box class="ParagraphBox">
+ <box class="LineBox">
+ <box class="DocumentTextBox" text="abc" />
+ <box class="PlaceholderBox" />
+ <box class="InlineElementBox" element="iib2">
+ <box class="StaticTextBox" text="BEFORE1 " />
+ </box>
+ </box>
+ <box class="LineBox">
+ <box class="InlineElementBox" element="iib2">
+ <box class="StaticTextBox" text="BEFORE2 " />
+ </box>
+ </box>
+ <box class="LineBox">
+ <box class="InlineElementBox" element="iib2">
+ <box class="DrawableBox" />
+ <box class="DocumentTextBox" text="wuzzle" />
+ <box class="PlaceholderBox" />
+ <box class="DrawableBox" />
+ </box>
+ <box class="PlaceholderBox" />
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ </result>
+ </test>
<!-- <test id="Inline with Block Before" layoutWidth="100"> <doc><![CDATA[
<root><ibb>wuzzle</ibb></root> ]]></doc> <result> <box class="RootBox"> <box
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/block-inline.css b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/block-inline.css
index ba32596..1b68fee 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/block-inline.css
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/block-inline.css
@@ -9,6 +9,11 @@
display: inline;
}
+nomarker {
+ display: inline;
+ _vex-inline-marker: none;
+}
+
p {
display: block;
}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/block-inline.xml b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/block-inline.xml
index d9aaccd..9d9b06d 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/block-inline.xml
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/block-inline.xml
@@ -258,7 +258,64 @@
</result>
</test>
+ <test id="Inline With Surrounding Text Split 3" layoutWidth="24">
+ <doc><![CDATA[ <root>hat <b>cat sat</b> bat</root> ]]></doc>
+ <result>
+ <box class="RootBox">
+ <box class="BlockElementBox">
+ <box class="BlockElementBox" element="root">
+ <box class="ParagraphBox">
+ <box class="LineBox">
+ <box class="DocumentTextBox" text="hat " />
+ </box>
+ <box class="LineBox">
+ <box class="PlaceholderBox" />
+ <box class="InlineElementBox">
+ <box class="DrawableBox" />
+ <box class="DocumentTextBox" text="cat " />
+ </box>
+ </box>
+ <box class="LineBox">
+ <box class="InlineElementBox">
+ <box class="DocumentTextBox" text="sat" />
+ <box class="PlaceholderBox" />
+ <box class="DrawableBox" />
+ </box>
+ <box class="DocumentTextBox" text=" " />
+ </box>
+ <box class="LineBox">
+ <box class="DocumentTextBox" text="bat" />
+ <box class="PlaceholderBox" />
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ </result>
+ </test>
+ <test id="Inline w/o marker" layoutWidth="100">
+ <doc><![CDATA[ <root><nomarker>cat sat</nomarker></root> ]]></doc>
+ <result>
+ <box class="RootBox">
+ <box class="BlockElementBox">
+ <box class="BlockElementBox" element="root">
+ <box class="ParagraphBox">
+ <box class="LineBox">
+ <box class="PlaceholderBox" />
+ <box class="InlineElementBox">
+ <box class="DocumentTextBox" text="cat " />
+ <box class="DocumentTextBox" text="sat" />
+ <box class="PlaceholderBox" />
+ </box>
+ <box class="PlaceholderBox" />
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ </result>
+ </test>
<test id="Block Child w/ Inline Before" layoutWidth="75">
<doc><![CDATA[ <root>Paris <p>Garters</p></root> ]]></doc>
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/validator/DTDValidatorTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/validator/DTDValidatorTest.java
index 76d60b1..df646ed 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/validator/DTDValidatorTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/validator/DTDValidatorTest.java
@@ -166,17 +166,6 @@
assertInvalidSequence("document", "preface", "index");
}
- @Test
- public void testValidateDocumentWithDTDAndNamespaces() throws Exception {
- final IDocument doc = new Document(new QualifiedName("http://namespace/uri/is/not/registered", "section"));
- doc.setValidator(validator);
- doc.insertElement(2, new QualifiedName(null, "title"));
- doc.insertText(3, "ab");
- doc.insertElement(6, new QualifiedName(null, "para"));
-
- validator.getAttributeDefinitions(doc.getRootElement());
- }
-
private void assertFullyValidSequence(final String element, final String... sequence) {
// fully includes partially
assertValidSequence(true, element, true, true, sequence);
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/tests/VEXCoreTestSuite.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/tests/VEXCoreTestSuite.java
deleted file mode 100644
index ccfe43d..0000000
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/tests/VEXCoreTestSuite.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2004, 2013 John Krasnay 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:
- * John Krasnay - initial API and implementation
- * Florian Thienel - bug 306639 - remove serializability from StyleSheet
- * and dependend classes
- * Carsten Hiesserich - bug 408501 - keep whitespace when copying fragments
- * into pre elements
- *******************************************************************************/
-package org.eclipse.vex.core.tests;
-
-import org.eclipse.vex.core.internal.core.AfterNIteratorTest;
-import org.eclipse.vex.core.internal.core.FilterIteratorTest;
-import org.eclipse.vex.core.internal.core.FirstNIteratorTest;
-import org.eclipse.vex.core.internal.core.XmlTest;
-import org.eclipse.vex.core.internal.css.BatikBehaviorTest;
-import org.eclipse.vex.core.internal.css.CssTest;
-import org.eclipse.vex.core.internal.css.CssWhitespacePolicyTest;
-import org.eclipse.vex.core.internal.css.PropertyTest;
-import org.eclipse.vex.core.internal.css.RuleTest;
-import org.eclipse.vex.core.internal.dom.AxisTest;
-import org.eclipse.vex.core.internal.dom.BasicNodeTest;
-import org.eclipse.vex.core.internal.dom.BlockElementBoxTest;
-import org.eclipse.vex.core.internal.dom.ContentRangeTest;
-import org.eclipse.vex.core.internal.dom.CopyVisitorTest;
-import org.eclipse.vex.core.internal.dom.DeepCopyTest;
-import org.eclipse.vex.core.internal.dom.DocumentEventTest;
-import org.eclipse.vex.core.internal.dom.DocumentFragmentTest;
-import org.eclipse.vex.core.internal.dom.DocumentTest;
-import org.eclipse.vex.core.internal.dom.GapContentTest;
-import org.eclipse.vex.core.internal.dom.L1CommentHandlingTest;
-import org.eclipse.vex.core.internal.dom.L1DeletionTests;
-import org.eclipse.vex.core.internal.dom.L1ElementHandlingTest;
-import org.eclipse.vex.core.internal.dom.L1FragmentHandlingTest;
-import org.eclipse.vex.core.internal.dom.L1ProcessingInstructionHandlingTest;
-import org.eclipse.vex.core.internal.dom.L1TextHandlingTest;
-import org.eclipse.vex.core.internal.dom.NamespaceTest;
-import org.eclipse.vex.core.internal.dom.ParentTest;
-import org.eclipse.vex.core.internal.io.DocumentContentModelTest;
-import org.eclipse.vex.core.internal.io.DocumentReaderTest;
-import org.eclipse.vex.core.internal.io.DocumentWriterTest;
-import org.eclipse.vex.core.internal.io.NamespaceStackTest;
-import org.eclipse.vex.core.internal.io.SpaceNormalizerTest;
-import org.eclipse.vex.core.internal.io.TextWrapperTest;
-import org.eclipse.vex.core.internal.io.XMLFragmentTest;
-import org.eclipse.vex.core.internal.layout.ImageBoxTest;
-import org.eclipse.vex.core.internal.layout.LayoutTestSuite;
-import org.eclipse.vex.core.internal.layout.TableLayoutTest;
-import org.eclipse.vex.core.internal.layout.TestBlockElementBox;
-import org.eclipse.vex.core.internal.layout.TestBlocksInInlines;
-import org.eclipse.vex.core.internal.layout.TestDocumentTextBox;
-import org.eclipse.vex.core.internal.layout.TestStaticTextBox;
-import org.eclipse.vex.core.internal.validator.DTDValidatorTest;
-import org.eclipse.vex.core.internal.validator.SchemaValidatorTest;
-import org.eclipse.vex.core.internal.widget.L2CommentEditingTest;
-import org.eclipse.vex.core.internal.widget.L2ProcessingInstructionEditingTest;
-import org.eclipse.vex.core.internal.widget.L2SelectionTest;
-import org.eclipse.vex.core.internal.widget.L2SimpleEditingTest;
-import org.eclipse.vex.core.internal.widget.L2StyleSheetTest;
-import org.eclipse.vex.core.internal.widget.L2XmlInsertionTest;
-import org.eclipse.vex.core.internal.widget.VexWidgetTest;
-import org.eclipse.vex.core.internal.widget.swt.DocumentFragmentTransferTest;
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
-
-@RunWith(Suite.class)
-@Suite.SuiteClasses({ FilterIteratorTest.class, FirstNIteratorTest.class, AfterNIteratorTest.class, AxisTest.class, NamespaceStackTest.class, NamespaceTest.class, DocumentReaderTest.class,
- DocumentContentModelTest.class, SchemaValidatorTest.class, CssTest.class, CssWhitespacePolicyTest.class, BatikBehaviorTest.class, ContentRangeTest.class, BasicNodeTest.class,
- ParentTest.class, DocumentTest.class, L1TextHandlingTest.class, L1CommentHandlingTest.class, L1ProcessingInstructionHandlingTest.class, L1ElementHandlingTest.class,
- L1FragmentHandlingTest.class, L1DeletionTests.class, DocumentFragmentTest.class, CopyVisitorTest.class, DeepCopyTest.class, PropertyTest.class, RuleTest.class, BlockElementBoxTest.class,
- ImageBoxTest.class, DocumentWriterTest.class, DTDValidatorTest.class, GapContentTest.class, SpaceNormalizerTest.class, TextWrapperTest.class, TestBlockElementBox.class,
- TestBlocksInInlines.class, TestDocumentTextBox.class, TestStaticTextBox.class, TableLayoutTest.class, LayoutTestSuite.class, ListenerListTest.class, DocumentFragmentTransferTest.class,
- XMLFragmentTest.class, VexWidgetTest.class, L2SimpleEditingTest.class, L2SelectionTest.class, L2CommentEditingTest.class, L2ProcessingInstructionEditingTest.class, L2XmlInsertionTest.class,
- DocumentEventTest.class, L2StyleSheetTest.class, XmlTest.class
-
-})
-public class VEXCoreTestSuite {
-}
diff --git a/org.eclipse.vex.core.tests/testResources/document.xml b/org.eclipse.vex.core.tests/testResources/document.xml
index 5eeb284..e7086a3 100644
--- a/org.eclipse.vex.core.tests/testResources/document.xml
+++ b/org.eclipse.vex.core.tests/testResources/document.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter xmlns="http://www.eclipse.org/vex/test/structure" xmlns:c="http://www.eclipse.org/vex/test/content">
<title>Title</title>
- <chapter>
+ <chapter attribute="ns-null" c:attribute="ns-content">
<title>1.1</title>
<c:p>The <c:i>first</c:i> <c:b>paragraph</c:b>.</c:p>
</chapter>
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/CSS.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/CSS.java
index beb8584..83f064c 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/CSS.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/CSS.java
@@ -133,6 +133,7 @@
// we can't use a dash '-vex' here, because of a bug in the batik css parser
// see https://issues.apache.org/bugzilla/show_bug.cgi?id=47800
public static final String OUTLINE_CONTENT = "_vex-outline-content";
+ public static final String INLINE_MARKER = "_vex-inline-marker";
// suffixes to BORDER_XXX
public static final String COLOR_SUFFIX = "-color";
@@ -235,8 +236,9 @@
public static final String XX_SMALL = "xx-small";
// Common element names
- public static final String XML_PROCESSING_INSTRUCTION = "vex|processing-instruction";
- public static final String XML_COMMENT = "vex|comment";
+ public static final String XML_PROCESSING_INSTRUCTION = "processing-instruction";
+ public static final String XML_COMMENT = "comment";
+ public static final String VEX_NAMESPACE_PREFIX = "vex";
// Pseudo elements
public static final String PSEUDO_TARGET = "target";
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/InlineMarkerProperty.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/InlineMarkerProperty.java
new file mode 100644
index 0000000..29275e7
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/InlineMarkerProperty.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Carsten Hiesserich 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:
+ * Carsten Hiesserich - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.vex.core.internal.css;
+
+import org.eclipse.vex.core.provisional.dom.INode;
+import org.w3c.css.sac.LexicalUnit;
+
+/**
+ * The -vex-inline-marker CSS property. This property decides the type of inline markers<br />
+ * The value <code>none</code> will hide the inline markers around the element.<br />
+ * The defualt is <code>normal</code> to display the default markers.
+ */
+public class InlineMarkerProperty extends AbstractProperty {
+
+ /**
+ * Class constructor.
+ */
+ public InlineMarkerProperty() {
+ super(CSS.INLINE_MARKER);
+ }
+
+ public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final INode node) {
+ if (isInlineMarker(lu)) {
+ return lu.getStringValue();
+ }
+
+ return CSS.NORMAL;
+ }
+
+ /**
+ * Returns true if the given lexical unit represents a valid _vex-inline-marker.
+ *
+ * @param lu
+ * LexicalUnit to check.
+ */
+ public static boolean isInlineMarker(final LexicalUnit lu) {
+ if (lu == null) {
+ return false;
+ } else if (lu.getLexicalUnitType() == LexicalUnit.SAC_IDENT) {
+ final String s = lu.getStringValue();
+ return s.equals(CSS.NORMAL) || s.equals(CSS.NONE);
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/Rule.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/Rule.java
index bc736e3..fdaaa9a 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/Rule.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/Rule.java
@@ -20,6 +20,7 @@
import java.util.List;
import java.util.StringTokenizer;
+import org.eclipse.vex.core.internal.dom.Namespace;
import org.eclipse.vex.core.provisional.dom.BaseNodeVisitorWithResult;
import org.eclipse.vex.core.provisional.dom.IComment;
import org.eclipse.vex.core.provisional.dom.IDocument;
@@ -156,6 +157,13 @@
case Selector.SAC_ELEMENT_NODE_SELECTOR:
final String elementName = getLocalNameOfElement(node);
final String selectorName = ((ElementSelector) selector).getLocalName();
+
+ // If the Selector has a namespace URI, it has to match the namespace URI of the node
+ final String selectorNamespaceURI = ((ElementSelector) selector).getNamespaceURI();
+ if (selectorNamespaceURI != null && !selectorNamespaceURI.equals(getNamespaceURIOfElement(node))) {
+ return false;
+ }
+
if (selectorName == null) {
// We land here if we have a wildcard selector (*) or
// a pseudocondition w/o an element name (:before)
@@ -244,6 +252,25 @@
});
}
+ private static String getNamespaceURIOfElement(final INode node) {
+ return node.accept(new BaseNodeVisitorWithResult<String>("") {
+ @Override
+ public String visit(final IElement element) {
+ return element.getQualifiedName().getQualifier();
+ }
+
+ @Override
+ public String visit(final IComment comment) {
+ return Namespace.VEX_NAMESPACE_URI;
+ }
+
+ @Override
+ public String visit(final IProcessingInstruction pi) {
+ return Namespace.VEX_NAMESPACE_URI;
+ }
+ });
+ }
+
/**
* Returns true if some ancestor of the given element matches the given selector.
*/
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/StyleSheet.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/StyleSheet.java
index 0a6707a..9aa8714 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/StyleSheet.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/StyleSheet.java
@@ -82,7 +82,7 @@
new BorderWidthProperty(CSS.BORDER_LEFT_WIDTH, CSS.BORDER_LEFT_STYLE, IProperty.Axis.HORIZONTAL),
new BorderWidthProperty(CSS.BORDER_RIGHT_WIDTH, CSS.BORDER_RIGHT_STYLE, IProperty.Axis.HORIZONTAL),
new BorderWidthProperty(CSS.BORDER_TOP_WIDTH, CSS.BORDER_TOP_STYLE, IProperty.Axis.VERTICAL), new BorderSpacingProperty(), new LengthProperty(CSS.HEIGHT, IProperty.Axis.VERTICAL),
- new LengthProperty(CSS.WIDTH, IProperty.Axis.HORIZONTAL), new BackgroundImageProperty(), new OutlineContentProperty() };
+ new LengthProperty(CSS.WIDTH, IProperty.Axis.HORIZONTAL), new BackgroundImageProperty(), new OutlineContentProperty(), new InlineMarkerProperty() };
/**
* The rules that comprise the stylesheet.
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/StyleSheetReader.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/StyleSheetReader.java
index bd72c57..dce4b62 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/StyleSheetReader.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/StyleSheetReader.java
@@ -44,7 +44,7 @@
private static final URIResolver URI_RESOLVER = URIResolverPlugin.createResolver();
public static Parser createParser() {
- return new org.apache.batik.css.parser.Parser() {
+ final Parser parser = new org.apache.batik.css.parser.Parser() {
/**
* The batik implementation uses hardcoded values. This Override allows custom PseudoElements.
@@ -106,6 +106,9 @@
}
};
+
+ parser.setSelectorFactory(new VexSelectorFactory());
+ return parser;
}
/**
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/Styles.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/Styles.java
index 1cc7da2..5f8e14d 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/Styles.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/Styles.java
@@ -229,6 +229,13 @@
}
/**
+ * Returns the value of the <code>_vex-inline-marker</code> property.
+ */
+ public String getInlineMarker() {
+ return (String) values.get(CSS.INLINE_MARKER);
+ }
+
+ /**
* Returns the value of the <code>lineHeight</code> property.
*/
public int getLineHeight() {
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/VexSelectorFactory.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/VexSelectorFactory.java
new file mode 100644
index 0000000..e092e7e
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/VexSelectorFactory.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Carsten Hiesserich 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:
+ * Carsten Hiesserich - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.vex.core.internal.css;
+
+import org.apache.batik.css.parser.DefaultElementSelector;
+import org.apache.batik.css.parser.DefaultSelectorFactory;
+import org.eclipse.vex.core.internal.dom.Namespace;
+import org.w3c.css.sac.CSSException;
+import org.w3c.css.sac.ElementSelector;
+
+/**
+ * Together with {@link org.eclipse.vex.core.internal.css.CssScanner CssScanner} this class provides a pseudo support
+ * for CSS namespaces.<br>
+ * There is no support for <code>@namespace</code> rules, the allowed namespaces and prefixes are hardcoded.
+ */
+public class VexSelectorFactory extends DefaultSelectorFactory {
+ /**
+ * <b>SAC</b>: Implements {@link org.w3c.css.sac.SelectorFactory#createElementSelector(String,String)}.
+ */
+ @Override
+ public ElementSelector createElementSelector(String namespaceURI, String tagName) throws CSSException {
+ final int seperatorIndex = tagName != null ? tagName.indexOf("|") : -1;
+ if (seperatorIndex > -1) {
+ final String namespacePrefix = tagName.substring(0, seperatorIndex);
+ if (namespacePrefix.equals(CSS.VEX_NAMESPACE_PREFIX)) {
+ namespaceURI = Namespace.VEX_NAMESPACE_URI;
+ tagName = tagName.substring(seperatorIndex + 1);
+ }
+ }
+ return new DefaultElementSelector(namespaceURI, tagName);
+ }
+}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/vex-core-styles.css b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/vex-core-styles.css
index 4e8119f..f3c7ca2 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/vex-core-styles.css
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/vex-core-styles.css
@@ -16,6 +16,7 @@
vex|processing-instruction {
display: inherit;
color: blue;
+ _vex-inline-marker: none;
}
vex|processing-instruction:before {
@@ -33,6 +34,7 @@
vex|comment {
display: inherit;
color: green;
+ _vex-inline-marker: none;
}
vex|comment:before {
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Attribute.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Attribute.java
index e07de80..508c81a 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Attribute.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Attribute.java
@@ -59,10 +59,6 @@
if (parent == null || attributeQualifier == null) {
return getLocalName();
}
- final String elementQualifier = parent.getQualifiedName().getQualifier();
- if (attributeQualifier.equals(elementQualifier)) {
- return getLocalName();
- }
final String prefix = parent.getNamespacePrefix(attributeQualifier);
return (prefix == null ? "" : prefix + ":") + getLocalName();
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Element.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Element.java
index cfa54de..1ddbc69 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Element.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Element.java
@@ -114,7 +114,7 @@
*/
public IAttribute getAttribute(final String localName) {
- return getAttribute(qualify(localName));
+ return getAttribute(new QualifiedName(null, localName));
}
public IAttribute getAttribute(final QualifiedName name) {
@@ -122,7 +122,7 @@
}
public String getAttributeValue(final String localName) {
- return getAttributeValue(qualify(localName));
+ return getAttributeValue(new QualifiedName(null, localName));
}
public String getAttributeValue(final QualifiedName name) {
@@ -142,7 +142,7 @@
}
public void removeAttribute(final String localName) throws DocumentValidationException {
- removeAttribute(qualify(localName));
+ removeAttribute(new QualifiedName(null, localName));
}
public void removeAttribute(final QualifiedName name) throws DocumentValidationException {
@@ -173,7 +173,7 @@
}
public void setAttribute(final String localName, final String value) throws DocumentValidationException {
- setAttribute(qualify(localName), value);
+ setAttribute(new QualifiedName(null, localName), value);
}
public void setAttribute(final QualifiedName name, final String value) throws DocumentValidationException {
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/GapContent.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/GapContent.java
index 159500e..fd1d179 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/GapContent.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/GapContent.java
@@ -9,9 +9,11 @@
* John Krasnay - initial API and implementation
* Igor Jacy Lino Campista - Java 5 warnings fixed (bug 311325)
* Florian Thienel - refactoring to full fledged DOM
+ * Carsten Hiesserich - some optimization in getText methods
*******************************************************************************/
package org.eclipse.vex.core.internal.dom;
+import java.util.Iterator;
import java.util.SortedSet;
import java.util.TreeSet;
@@ -37,7 +39,7 @@
private char[] content;
private int gapStart;
private int gapEnd;
- private TreeSet<GapContentPosition> positions = new TreeSet<GapContentPosition>();
+ private final TreeSet<GapContentPosition> positions = new TreeSet<GapContentPosition>();
/**
* Create a GapContent with the given initial capacity.
@@ -113,14 +115,9 @@
}
private void movePositions(final int startOffset, final int delta) {
- final TreeSet<GapContentPosition> newPositions = new TreeSet<GapContentPosition>();
- for (final GapContentPosition position : positions) {
- if (position.getOffset() >= startOffset) {
- position.setOffset(position.getOffset() + delta);
- }
- newPositions.add(position);
+ for (final GapContentPosition position : positions.tailSet(new GapContentPosition(startOffset))) {
+ position.setOffset(position.getOffset() + delta);
}
- positions = newPositions;
}
public void insertTagMarker(final int offset) {
@@ -155,18 +152,17 @@
moveGap(range.getEndOffset() + 1);
gapStart -= range.length();
- final TreeSet<GapContentPosition> newPositions = new TreeSet<GapContentPosition>();
- for (final GapContentPosition position : positions) {
- if (position.getOffset() > range.getEndOffset()) {
- position.setOffset(position.getOffset() - range.length());
- newPositions.add(position);
- } else if (position.getOffset() >= range.getStartOffset()) {
+ final SortedSet<GapContentPosition> tail = positions.tailSet(new GapContentPosition(range.getStartOffset()));
+ for (final Iterator<GapContentPosition> iterator = tail.iterator(); iterator.hasNext();) {
+ final GapContentPosition position = iterator.next();
+
+ if (position.getOffset() <= range.getEndOffset()) {
position.invalidate();
+ iterator.remove();
} else {
- newPositions.add(position);
+ position.setOffset(position.getOffset() - range.length());
}
}
- positions = newPositions;
}
public String getText() {
@@ -177,7 +173,8 @@
Assert.isTrue(getRange().contains(range));
final int delta = gapEnd - gapStart;
- final StringBuilder result = new StringBuilder();
+ // Use range length as initial capacity. This might be a bit too much, but that's better than having to resize the StringBuilder.
+ final StringBuilder result = new StringBuilder(range.length());
if (range.getEndOffset() < gapStart) {
appendPlainText(result, range);
} else if (range.getStartOffset() >= gapStart) {
@@ -190,7 +187,8 @@
}
private void appendPlainText(final StringBuilder stringBuilder, final ContentRange range) {
- for (int i = range.getStartOffset(); range.contains(i); i++) {
+ final int endOffset = range.getEndOffset();
+ for (int i = range.getStartOffset(); i <= endOffset; i++) {
final char c = content[i];
if (!isTagMarker(c)) {
stringBuilder.append(c);
@@ -206,16 +204,16 @@
Assert.isTrue(getRange().contains(range));
final int delta = gapEnd - gapStart;
- final StringBuilder result = new StringBuilder();
if (range.getEndOffset() < gapStart) {
- appendRawText(result, range);
+ return new String(content, range.getStartOffset(), range.length());
} else if (range.getStartOffset() >= gapStart) {
- appendRawText(result, range.moveBy(delta));
+ return new String(content, range.getStartOffset() + delta, range.length());
} else {
+ final StringBuilder result = new StringBuilder(range.length());
appendRawText(result, new ContentRange(range.getStartOffset(), gapStart - 1));
appendRawText(result, new ContentRange(gapEnd, range.getEndOffset() + delta));
+ return result.toString();
}
- return result.toString();
}
private void appendRawText(final StringBuilder stringBuilder, final ContentRange range) {
@@ -295,7 +293,7 @@
/*
* Implementation of the Position interface.
*/
- private static class GapContentPosition implements IPosition, Comparable<IPosition> {
+ private static class GapContentPosition implements IPosition {
private int offset;
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Node.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Node.java
index 4d3cc88..66a3355 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Node.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Node.java
@@ -16,6 +16,7 @@
import java.util.List;
import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.AssertionFailedException;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.vex.core.provisional.dom.BaseNodeVisitor;
import org.eclipse.vex.core.provisional.dom.ContentRange;
@@ -90,12 +91,16 @@
}
public int getStartOffset() {
- Assert.isTrue(isAssociated(), "Node must be associated to a ContentRange to have a start offset.");
+ if (!isAssociated()) {
+ throw new AssertionFailedException("Node must be associated to a ContentRange to have a start offset.");
+ }
return startPosition.getOffset();
}
public int getEndOffset() {
- Assert.isTrue(isAssociated(), "Node must be associated to a ContentRange to have an end offset.");
+ if (!isAssociated()) {
+ throw new AssertionFailedException("Node must be associated to a ContentRange to have a start offset.");
+ }
return endPosition.getOffset();
}
@@ -132,7 +137,9 @@
}
public String getText(final ContentRange range) {
- Assert.isTrue(isAssociated(), "Node must be associated to a Content region to have textual content.");
+ if (!isAssociated()) {
+ throw new AssertionFailedException("Node must be associated to a Content region to have textual content.");
+ }
return content.getText(range.intersection(getRange()));
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Parent.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Parent.java
index 8c1529c..bb19d77 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Parent.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Parent.java
@@ -4,7 +4,7 @@
* 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:
* Florian Thienel - initial API and implementation
* Carsten Hiesserich - fixed insertion of elements to nodes with text (bug 408731)
@@ -17,6 +17,7 @@
import java.util.List;
import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.AssertionFailedException;
import org.eclipse.vex.core.provisional.dom.ContentRange;
import org.eclipse.vex.core.provisional.dom.IAxis;
import org.eclipse.vex.core.provisional.dom.INode;
@@ -63,15 +64,31 @@
final ContentRange insertionRange = getRange().resizeBy(1, 0);
Assert.isTrue(insertionRange.contains(offset), MessageFormat.format("The offset must be within {0}.", insertionRange));
- // We have to return an index in the children List, so Axis withoutText must be used!
- int i = 0;
- for (final INode child : children().withoutText()) {
- if (offset <= child.getStartOffset()) {
- return i;
- }
- i++;
+ if (children.isEmpty()) {
+ return 0;
}
- return children.size();
+
+ int minIndex = -1;
+ int maxIndex = children.size();
+
+ while (minIndex <= maxIndex) {
+ final int pivotIndex = (maxIndex + minIndex) / 2;
+ final INode pivot = children.get(pivotIndex);
+
+ if (pivot.containsOffset(offset)) {
+ return pivotIndex;
+ } else if (maxIndex - minIndex == 1) {
+ return maxIndex;
+ }
+
+ if (pivot.getStartOffset() > offset) {
+ maxIndex = Math.min(pivotIndex, maxIndex);
+ } else if (pivot.getEndOffset() < offset) {
+ minIndex = Math.max(pivotIndex, minIndex);
+ }
+ }
+
+ throw new AssertionError("No child found at offset " + offset);
}
private void insertChildAtIndex(final int index, final Node child) {
@@ -87,17 +104,66 @@
* @return the node at the given offset
*/
public INode getChildAt(final int offset) {
- Assert.isTrue(containsOffset(offset), MessageFormat.format("Offset must be within {0}.", getRange()));
- for (final INode child : children()) {
- if (child.containsOffset(offset)) {
- if (child instanceof IParent) {
- return ((IParent) child).getChildAt(offset);
- } else {
- return child;
- }
+ if (!containsOffset(offset)) {
+ throw new AssertionFailedException(MessageFormat.format("Offset must be within {0}.", getRange()));
+ }
+
+ if (offset == getStartOffset() || offset == getEndOffset()) {
+ return this;
+ }
+
+ if (children.isEmpty()) {
+ return new Text(this, getContent(), getRange().resizeBy(1, -1));
+ }
+
+ int minIndex = -1;
+ int maxIndex = children.size();
+
+ while (minIndex <= maxIndex) {
+ final int pivotIndex = (maxIndex + minIndex) / 2;
+ final INode pivot = children.get(pivotIndex);
+
+ if (pivot.containsOffset(offset)) {
+ return getChildIn(pivot, offset);
+ } else if (maxIndex - minIndex == 1) {
+ return createTextBetween(minIndex, maxIndex);
+ }
+
+ if (pivot.getStartOffset() > offset) {
+ maxIndex = Math.min(pivotIndex, maxIndex);
+ } else if (pivot.getEndOffset() < offset) {
+ minIndex = Math.max(pivotIndex, minIndex);
}
}
- return this;
+
+ throw new AssertionError("No child found at offset " + offset);
+ }
+
+ private INode getChildIn(final INode child, final int offset) {
+ if (child instanceof IParent) {
+ return ((IParent) child).getChildAt(offset);
+ }
+ return child;
+ }
+
+ private Text createTextBetween(final int childIndex1, final int childIndex2) {
+ Assert.isTrue(childIndex1 < childIndex2);
+
+ final int startOffset;
+ if (childIndex1 < 0) {
+ startOffset = getStartOffset() + 1;
+ } else {
+ startOffset = children.get(childIndex1).getEndOffset() + 1;
+ }
+
+ final int endOffset;
+ if (childIndex2 >= children.size()) {
+ endOffset = getEndOffset() - 1;
+ } else {
+ endOffset = children.get(childIndex2).getStartOffset() - 1;
+ }
+
+ return new Text(this, getContent(), new ContentRange(startOffset, endOffset));
}
/**
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/io/DocumentBuilder.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/io/DocumentBuilder.java
index 056c86d..5cb845f 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/io/DocumentBuilder.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/io/DocumentBuilder.java
@@ -255,7 +255,8 @@
if ("".equals(attrs.getLocalName(i))) {
attributeName = new QualifiedName(null, attrs.getQName(i));
} else if ("".equals(attrs.getURI(i))) {
- attributeName = new QualifiedName(elementName.getQualifier(), attrs.getLocalName(i));
+ // Attributes do not inherit the elements namespace (http://www.w3.org/TR/REC-xml-names/#defaulting)
+ attributeName = new QualifiedName(null, attrs.getLocalName(i));
} else {
attributeName = new QualifiedName(attrs.getURI(i), attrs.getLocalName(i));
}
@@ -272,7 +273,7 @@
if (dtdPublicID != null && dtdSystemID != null || previousDocTypeID == null) {
// The content model is initialized only if the input document defines a DocType
// or if it has not been initialized already.
- // This way, a user selected is reapplied when the document is reloaded.
+ // This way, a user selected doctype is reapplied when the document is reloaded.
documentContentModel.initialize(baseUri, dtdPublicID, dtdSystemID, rootElement);
}
final StyleSheet styleSheet = styleSheetProvider.getStyleSheet(documentContentModel);
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/AbstractBlockBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/AbstractBlockBox.java
index 1eb7b4a..b896ddb 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/AbstractBlockBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/AbstractBlockBox.java
@@ -13,7 +13,6 @@
package org.eclipse.vex.core.internal.layout;
import java.util.ArrayList;
-import java.util.LinkedList;
import java.util.List;
import java.util.Set;
@@ -23,7 +22,6 @@
import org.eclipse.vex.core.internal.core.FontMetrics;
import org.eclipse.vex.core.internal.core.Graphics;
import org.eclipse.vex.core.internal.core.Insets;
-import org.eclipse.vex.core.internal.css.IWhitespacePolicy;
import org.eclipse.vex.core.internal.css.StyleSheet;
import org.eclipse.vex.core.internal.css.Styles;
import org.eclipse.vex.core.internal.widget.IBoxFilter;
@@ -706,15 +704,15 @@
final int relOffset = startOffset - node.getStartOffset();
pendingInlines.add(new PlaceholderBox(context, node, relOffset));
} else if (node instanceof IParent) {
- final BlockInlineIterator iter = new BlockInlineIterator(context, (IParent) node, startOffset, endOffset);
+ final FormattingPortionIterator iter = new FormattingPortionIterator(context.getWhitespacePolicy(), (IParent) node, startOffset, endOffset);
while (true) {
- Object next = iter.next();
- if (next == null) {
+ Object formattingPortion = iter.next();
+ if (formattingPortion == null) {
break;
}
- if (next instanceof ContentRange) {
- final ContentRange range = (ContentRange) next;
+ if (formattingPortion instanceof ContentRange) {
+ final ContentRange range = (ContentRange) formattingPortion;
final InlineElementBox.InlineBoxes inlineBoxes = InlineElementBox.createInlineBoxes(context, node, range);
pendingInlines.addAll(inlineBoxes.boxes);
pendingInlines.add(new PlaceholderBox(context, node, range.getEndOffset() - node.getStartOffset()));
@@ -724,25 +722,25 @@
pendingInlines.clear();
}
- if (isTableChild(context, next)) {
+ if (isTableChild(context, formattingPortion)) {
// Consume continguous table children and create an
// anonymous table.
- final int tableStartOffset = ((IElement) next).getStartOffset();
+ final int tableStartOffset = ((IElement) formattingPortion).getStartOffset();
int tableEndOffset = -1; // dummy to hide warning
- while (isTableChild(context, next)) {
- tableEndOffset = ((IElement) next).getEndOffset() + 1;
- next = iter.next();
+ while (isTableChild(context, formattingPortion)) {
+ tableEndOffset = ((IElement) formattingPortion).getEndOffset() + 1;
+ formattingPortion = iter.next();
}
// add anonymous table
blockBoxes.add(new TableBox(context, this, tableStartOffset, tableEndOffset));
- if (next == null) {
+ if (formattingPortion == null) {
break;
} else {
- iter.push(next);
+ iter.push(formattingPortion);
}
} else { // next is a block box element
- final INode blockNode = (INode) next;
+ final INode blockNode = (INode) formattingPortion;
blockBoxes.add(context.getBoxFactory().createBox(context, blockNode, this, width));
}
}
@@ -766,57 +764,6 @@
return blockBoxes;
}
- private static class BlockInlineIterator {
-
- private final LayoutContext context;
- private final IParent parent;
- private int startOffset;
- private final int endOffset;
- private final LinkedList<Object> pushStack = new LinkedList<Object>();
-
- public BlockInlineIterator(final LayoutContext context, final IParent parent, final int startOffset, final int endOffset) {
- this.context = context;
- this.parent = parent;
- this.startOffset = startOffset;
- this.endOffset = endOffset;
- }
-
- /**
- * Returns the next block element or inline range, or null if we're at the end.
- */
- public Object next() {
- if (!pushStack.isEmpty()) {
- return pushStack.removeLast();
- } else if (startOffset >= endOffset) {
- return null;
- } else {
- final INode blockNode = findNextBlockNode(context, parent, startOffset, endOffset);
- if (blockNode == null) {
- if (startOffset < endOffset) {
- final ContentRange result = new ContentRange(startOffset, endOffset);
- startOffset = endOffset;
- return result;
- } else {
- return null;
- }
- } else if (blockNode.getStartOffset() > startOffset) {
- pushStack.addLast(blockNode);
- final ContentRange result = new ContentRange(startOffset, blockNode.getStartOffset());
- startOffset = blockNode.getEndOffset() + 1;
- return result;
- } else {
- startOffset = blockNode.getEndOffset() + 1;
- return blockNode;
- }
- }
- }
-
- public void push(final Object pushed) {
- pushStack.addLast(pushed);
- }
-
- }
-
protected boolean hasChildren() {
return getChildren() != null && getChildren().length > 0;
}
@@ -893,62 +840,6 @@
// ========================================================= PRIVATE
/**
- * Searches for the next block-formatted child.
- *
- * @param context
- * LayoutContext to use.
- * @param parent
- * Element within which to search.
- * @param startOffset
- * The offset at which to start the search.
- * @param endOffset
- * The offset at which to end the search.
- */
- private static INode findNextBlockNode(final LayoutContext context, final IParent parent, final int startOffset, final int endOffset) {
- final IWhitespacePolicy policy = context.getWhitespacePolicy();
- for (final INode child : parent.children().in(new ContentRange(startOffset, endOffset)).withoutText()) {
- final INode nextBlockNode = child.accept(new BaseNodeVisitorWithResult<INode>() {
- @Override
- public INode visit(final IElement element) {
- // found?
- if (policy.isBlock(element)) {
- return element;
- }
-
- // recursion
- final INode fromChild = findNextBlockNode(context, element, startOffset, endOffset);
- if (fromChild != null) {
- return fromChild;
- }
-
- return null;
- }
-
- @Override
- public INode visit(final IComment comment) {
- if (policy.isBlock(comment)) {
- return comment;
- }
- return null;
- }
-
- @Override
- public INode visit(final IProcessingInstruction pi) {
- if (policy.isBlock(pi)) {
- return pi;
- }
- return null;
- }
- });
- if (nextBlockNode != null) {
- return nextBlockNode;
- }
- }
-
- return null;
- }
-
- /**
* Return the end position of an anonymous box. The default implementation returns null.
*/
private IPosition getEndPosition() {
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/AbstractBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/AbstractBox.java
index c4716e7..f854bcd 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/AbstractBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/AbstractBox.java
@@ -10,6 +10,7 @@
*******************************************************************************/
package org.eclipse.vex.core.internal.layout;
+import org.eclipse.core.runtime.Assert;
import org.eclipse.vex.core.internal.core.Caret;
import org.eclipse.vex.core.internal.core.Color;
import org.eclipse.vex.core.internal.core.ColorResource;
@@ -141,6 +142,7 @@
* @see org.eclipse.vex.core.internal.layout.Box#getWidth()
*/
public int getWidth() {
+ Assert.isTrue(width > -1); // Make sure width has been calculated
return width;
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/AbstractInlineBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/AbstractInlineBox.java
index 7d2e909..0265f9d 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/AbstractInlineBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/AbstractInlineBox.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2010 Florian Thienel and others.
+ * Copyright (c) 2010, 2013 Florian Thienel 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
@@ -7,6 +7,7 @@
*
* Contributors:
* Florian Thienel - initial API and implementation
+ * Carsten Hiesserich - added isSplitable() method
*******************************************************************************/
package org.eclipse.vex.core.internal.layout;
@@ -18,4 +19,13 @@
public void alignOnBaseline(final int baseline) {
setY(baseline - getBaseline());
}
+
+ public boolean isSplitable() {
+ return false;
+ }
+
+ public Pair split(final LayoutContext context, final int maxWidth, final boolean force) {
+ throw new UnsupportedOperationException("split method not supported");
+ }
+
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/CompositeInlineBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/CompositeInlineBox.java
index 63cb2c1..c0334a0 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/CompositeInlineBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/CompositeInlineBox.java
@@ -102,10 +102,16 @@
return new TextCaret(x, y, height);
}
+ @Override
+ public boolean isSplitable() {
+ return true;
+ }
+
/**
* @see org.eclipse.vex.core.internal.layout.InlineBox#split(org.eclipse.vex.core.internal.layout.LayoutContext,
* int, boolean)
*/
+ @Override
public Pair split(final LayoutContext context, final int maxWidth, final boolean force) {
// list of children that have yet to be added to the left side
@@ -120,26 +126,48 @@
int remaining = maxWidth;
boolean eol = false;
+ InlineBox currentBox = null;
- while (!rights.isEmpty() && remaining >= 0) {
- final InlineBox inline = (InlineBox) rights.removeFirst();
- final InlineBox.Pair pair = inline.split(context, remaining, force && lefts.isEmpty());
-
- if (pair.getLeft() != null) {
- lefts.addAll(pending);
- pending.clear();
- lefts.add(pair.getLeft());
- remaining -= pair.getLeft().getWidth();
+ while ((!rights.isEmpty() || currentBox != null) && remaining >= 0) {
+ final InlineBox inline;
+ if (currentBox != null) {
+ inline = currentBox;
+ currentBox = null;
+ } else {
+ inline = (InlineBox) rights.removeFirst();
}
- if (pair.getRight() != null) {
- pending.add(pair.getRight());
- remaining -= pair.getRight().getWidth();
- }
+ if (inline.isSplitable()) {
+ final InlineBox.Pair pair = inline.split(context, remaining, force && lefts.isEmpty());
- if (pair.getLeft() != null && pair.getLeft().isEOL()) {
- eol = true;
- break;
+ if (pair.getLeft() != null) {
+ lefts.addAll(pending);
+ pending.clear();
+ lefts.add(pair.getLeft());
+ remaining -= pair.getLeft().getWidth();
+ }
+
+ if (pair.getRight() != null) {
+ if (pair.getLeft() == null) {
+ // pair.left is null, so the right either fits completely or not at all
+ remaining = pair.getRemaining();
+ pending.add(pair.getRight());
+ } else if (remaining >= 0 && !pair.getLeft().isEOL()) {
+ // we have no valid right width, so try to further split the right element
+ currentBox = pair.getRight();
+ } else {
+ pending.add(pair.getRight());
+ }
+ }
+
+ if (pair.getLeft() != null && pair.getLeft().isEOL()) {
+ eol = true;
+ break;
+ }
+ } else {
+ // If the box is not splitable, it has a valid width
+ remaining -= inline.getWidth();
+ pending.add(inline);
}
}
@@ -152,7 +180,7 @@
final InlineBox[] leftKids = lefts.toArray(new InlineBox[lefts.size()]);
final InlineBox[] rightKids = rights.toArray(new InlineBox[rights.size()]);
- return this.split(context, leftKids, rightKids);
+ return this.split(context, leftKids, rightKids, remaining);
}
/**
@@ -164,9 +192,11 @@
* Child boxes to be given to the left box.
* @param rights
* Child boxes to be given to the right box.
+ * @param remaining
+ * The remaining width after the split.
* @return
*/
- protected abstract Pair split(LayoutContext context, InlineBox[] lefts, InlineBox[] rights);
+ public abstract Pair split(LayoutContext context, InlineBox[] lefts, InlineBox[] rights, int remaining);
/**
* @see org.eclipse.vex.core.internal.layout.Box#viewToModel(org.eclipse.vex.core.internal.layout.LayoutContext,
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/DocumentTextBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/DocumentTextBox.java
index bddd2a1..93890ca 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/DocumentTextBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/DocumentTextBox.java
@@ -1,18 +1,19 @@
/*******************************************************************************
- * Copyright (c) 2004, 2008 John Krasnay and others.
+ * Copyright (c) 2004, 2013 John Krasnay 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:
* John Krasnay - initial API and implementation
+ * Carsten Hiesserich - performance optimization for split methods
*******************************************************************************/
package org.eclipse.vex.core.internal.layout;
import java.text.MessageFormat;
-import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.AssertionFailedException;
import org.eclipse.vex.core.internal.core.ColorResource;
import org.eclipse.vex.core.internal.core.FontResource;
import org.eclipse.vex.core.internal.core.Graphics;
@@ -25,7 +26,7 @@
*/
public class DocumentTextBox extends TextBox {
- private final int startRelative;
+ private int startRelative;
private final int endRelative;
/**
@@ -42,14 +43,42 @@
*/
public DocumentTextBox(final LayoutContext context, final INode node, final int startOffset, final int endOffset) {
super(node);
- Assert.isTrue(startOffset <= endOffset, MessageFormat.format("DocumentTextBox for {2}: startOffset {0} > endOffset {1}", startOffset, endOffset, node));
+ if (startOffset > endOffset) {
+ // Do not use Assert.isTrue. This Contructor is called very often and the use of Assert.isTrue would evaluate the Message.format every time.
+ throw new AssertionFailedException(MessageFormat.format("assertion failed: DocumentTextBox for {2}: startOffset {0} > endOffset {1}", startOffset, endOffset, node)); //$NON-NLS-1$
+ }
- startRelative = startOffset - node.getStartOffset();
- endRelative = endOffset - node.getStartOffset();
- calculateSize(context);
+ final int nodeStart = node.getStartOffset();
+ startRelative = startOffset - nodeStart;
+ endRelative = endOffset - nodeStart;
- Assert.isTrue(getText().length() >= endOffset - startOffset,
- MessageFormat.format("DocumentTextBox for {2}: text shorter than range: {0} < {1}", getText().length(), endOffset - startOffset, node));
+ // The box constructed here will be splitted, so there's no need to calculate the width here.
+ calculateHeight(context);
+ setWidth(-1);
+
+ if (startOffset <= nodeStart || endOffset >= node.getEndOffset()) {
+ // Do not use Assert.isTrue. This Contructor is called very often and the use of Assert.isTrue would evaluate the Message.format every time.
+ throw new AssertionFailedException(MessageFormat.format("assertion failed: Range of DocumentTextBox for {0} exceeds content of parent node", node)); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Class constructor used by the splitAt method.
+ *
+ * @param other
+ * Instance of DocumentTextBox that should be splitted.
+ * @param endOffset
+ * The endOffset of the new box.
+ * @param width
+ * The calculated layout width of the new box.
+ */
+ private DocumentTextBox(final DocumentTextBox other, final int endOffset, final int width) {
+ super(other.getNode());
+ startRelative = other.startRelative;
+ endRelative = endOffset - getNode().getStartOffset();
+ setWidth(width);
+ setHeight(other.getHeight());
+ setBaseline(other.getBaseline());
}
/**
@@ -81,7 +110,14 @@
*/
@Override
public String getText() {
- return getNode().getText(new ContentRange(getStartOffset(), getEndOffset()));
+ // The content range of this box can not include tag markers, so we can use IContent#getRawText here. This
+ // method is dramatically faster than IContent#getText
+ return getNode().getContent().getRawText(new ContentRange(getStartOffset(), getEndOffset()));
+ }
+
+ @Override
+ public boolean isEOL() {
+ return getNode().getContent().charAt(getEndOffset()) == NEWLINE_CHAR;
}
/**
@@ -164,28 +200,36 @@
* @see org.eclipse.vex.core.internal.layout.TextBox#splitAt(int)
*/
@Override
- public Pair splitAt(final LayoutContext context, final int offset) {
+ protected Pair splitAt(final LayoutContext context, final int offset, final int leftWidth, final int maxWidth) {
if (offset < 0 || offset > endRelative - startRelative + 1) {
throw new IllegalStateException();
}
final int split = getStartOffset() + offset;
+ int remaining = maxWidth;
DocumentTextBox left;
if (offset == 0) {
left = null;
} else {
- left = new DocumentTextBox(context, getNode(), getStartOffset(), split - 1);
+ left = new DocumentTextBox(this, split - 1, leftWidth);
+ remaining -= leftWidth;
}
InlineBox right;
if (split > getEndOffset()) {
right = null;
} else {
- right = new DocumentTextBox(context, getNode(), split, getEndOffset());
+ // Instead of creating a new box, we reuse this one
+ startRelative = split - getNode().getStartOffset();
+ if (left == null) {
+ calculateSize(context);
+ remaining -= getWidth();
+ }
+ right = this;
}
- return new Pair(left, right);
+ return new Pair(left, right, remaining);
}
/**
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/DrawableBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/DrawableBox.java
index fa5558a..5ec9ae6 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/DrawableBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/DrawableBox.java
@@ -85,14 +85,6 @@
}
/**
- * @see org.eclipse.vex.core.internal.layout.InlineBox#split(org.eclipse.vex.core.internal.layout.LayoutContext,
- * int, boolean)
- */
- public Pair split(final LayoutContext context, final int maxWidth, final boolean force) {
- return new Pair(null, this);
- }
-
- /**
* Draw the drawable. The foreground color of the context's Graphics is set before calling the drawable's draw
* method.
*/
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/FormattingPortionIterator.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/FormattingPortionIterator.java
new file mode 100644
index 0000000..d2a228b
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/FormattingPortionIterator.java
@@ -0,0 +1,147 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Florian Thienel 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:
+ * Florian Thienel - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.vex.core.internal.layout;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import org.eclipse.vex.core.internal.css.IWhitespacePolicy;
+import org.eclipse.vex.core.provisional.dom.BaseNodeVisitorWithResult;
+import org.eclipse.vex.core.provisional.dom.ContentRange;
+import org.eclipse.vex.core.provisional.dom.IComment;
+import org.eclipse.vex.core.provisional.dom.IElement;
+import org.eclipse.vex.core.provisional.dom.INode;
+import org.eclipse.vex.core.provisional.dom.IParent;
+import org.eclipse.vex.core.provisional.dom.IProcessingInstruction;
+
+/**
+ * @author Florian Thienel
+ */
+public class FormattingPortionIterator {
+
+ private final IWhitespacePolicy policy;
+ private int startOffset;
+ private final int endOffset;
+ private final LinkedList<Iterator<? extends INode>> iteratorStack = new LinkedList<Iterator<? extends INode>>();
+ private final LinkedList<Object> pushStack = new LinkedList<Object>();
+
+ public FormattingPortionIterator(final IWhitespacePolicy policy, final IParent parent, final int startOffset, final int endOffset) {
+ this.policy = policy;
+ this.startOffset = startOffset;
+ this.endOffset = endOffset;
+ pushIteratorFor(parent);
+ }
+
+ /**
+ * Returns the next block element or inline range, or null if we're at the end.
+ */
+ public Object next() {
+ if (!pushStack.isEmpty()) {
+ return pushStack.removeLast();
+ } else if (startOffset >= endOffset) {
+ return null;
+ } else {
+ final INode blockNode = findNextBlockNode(policy);
+ if (blockNode == null) {
+ if (startOffset < endOffset) {
+ final ContentRange result = new ContentRange(startOffset, endOffset);
+ startOffset = endOffset;
+ return result;
+ } else {
+ return null;
+ }
+ } else if (blockNode.getStartOffset() > startOffset) {
+ pushStack.addLast(blockNode);
+ final ContentRange result = new ContentRange(startOffset, blockNode.getStartOffset());
+ startOffset = blockNode.getEndOffset() + 1;
+ return result;
+ } else {
+ startOffset = blockNode.getEndOffset() + 1;
+ return blockNode;
+ }
+ }
+ }
+
+ public void push(final Object pushed) {
+ pushStack.addLast(pushed);
+ }
+
+ private void pushIteratorFor(final IParent parent) {
+ pushIterator(parent.children().in(new ContentRange(startOffset, endOffset)).withoutText().iterator());
+ }
+
+ private void pushIterator(final Iterator<? extends INode> iterator) {
+ iteratorStack.addFirst(iterator);
+ }
+
+ private Iterator<? extends INode> peekIterator() {
+ return iteratorStack.getFirst();
+ }
+
+ private void popIterator() {
+ if (hasIterator()) {
+ iteratorStack.removeFirst();
+ }
+ }
+
+ private boolean hasIterator() {
+ return !iteratorStack.isEmpty();
+ }
+
+ private INode findNextBlockNode(final IWhitespacePolicy policy) {
+ for (final Iterator<? extends INode> iterator = peekIterator(); iterator.hasNext();) {
+ final INode nextBlockNode = iterator.next().accept(new BaseNodeVisitorWithResult<INode>() {
+ @Override
+ public INode visit(final IElement element) {
+ // found?
+ if (policy.isBlock(element)) {
+ return element;
+ }
+
+ // recursion
+ pushIteratorFor(element);
+ final INode fromChild = findNextBlockNode(policy);
+ if (fromChild != null) {
+ return fromChild;
+ }
+
+ return null;
+ }
+
+ @Override
+ public INode visit(final IComment comment) {
+ if (policy.isBlock(comment)) {
+ return comment;
+ }
+ return null;
+ }
+
+ @Override
+ public INode visit(final IProcessingInstruction pi) {
+ if (policy.isBlock(pi)) {
+ return pi;
+ }
+ return null;
+ }
+ });
+ if (nextBlockNode != null) {
+ return nextBlockNode;
+ }
+ }
+
+ popIterator();
+ if (hasIterator()) {
+ return findNextBlockNode(policy);
+ }
+
+ return null;
+ }
+}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/ImageBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/ImageBox.java
index 0636bd4..7c9dcfd 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/ImageBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/ImageBox.java
@@ -98,7 +98,4 @@
return false;
}
- public Pair split(final LayoutContext context, final int maxWidth, final boolean force) {
- return new Pair(null, this);
- }
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/InlineBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/InlineBox.java
index fea8dcd..4531578 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/InlineBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/InlineBox.java
@@ -1,12 +1,13 @@
/*******************************************************************************
- * Copyright (c) 2004, 2008 John Krasnay and others.
+ * Copyright (c) 2004, 2013 John Krasnay 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:
* John Krasnay - initial API and implementation
+ * Carsten Hiesserich - added remainingWidth to Pair
*******************************************************************************/
package org.eclipse.vex.core.internal.layout;
@@ -21,6 +22,7 @@
public class Pair {
private final InlineBox left;
private final InlineBox right;
+ private final int remainingWidth;
/**
* Class constructor.
@@ -29,10 +31,13 @@
* box to the left of the split
* @param right
* box to the right of the split
+ * @param remaining
+ * the remaining layout width after this split
*/
- public Pair(final InlineBox left, final InlineBox right) {
+ public Pair(final InlineBox left, final InlineBox right, final int remaining) {
this.left = left;
this.right = right;
+ remainingWidth = remaining;
}
/**
@@ -48,6 +53,13 @@
public InlineBox getRight() {
return right;
}
+
+ /**
+ * Return the remaining with after the split
+ */
+ public int getRemaining() {
+ return remainingWidth;
+ }
}
/**
@@ -66,6 +78,11 @@
public boolean isEOL();
/**
+ * @return <code>true</code> if this box can be splitted.
+ */
+ public boolean isSplitable();
+
+ /**
* Splits this inline box into two. If <code>force</code> is false, this method should find a natural split point
* (e.g. after a space) and return two boxes representing a split at that point. The width of the last box must not
* exceed <code>maxWidth</code>. If no such natural split exists, null should be returned as the left box and
@@ -89,6 +106,7 @@
* Maximum width of the left part of the box.
* @param force
* if true, force a suboptimal split
+ * @return A new {@link Pair} of inline boxes, or null if this box is not splitable
*/
public Pair split(LayoutContext context, int maxWidth, boolean force);
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/InlineElementBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/InlineElementBox.java
index d6ecd4a..61e1211 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/InlineElementBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/InlineElementBox.java
@@ -21,7 +21,6 @@
import org.eclipse.vex.core.internal.core.Graphics;
import org.eclipse.vex.core.internal.core.Rectangle;
import org.eclipse.vex.core.internal.css.CSS;
-import org.eclipse.vex.core.internal.css.StyleSheet;
import org.eclipse.vex.core.internal.css.Styles;
import org.eclipse.vex.core.provisional.dom.BaseNodeVisitor;
import org.eclipse.vex.core.provisional.dom.ContentRange;
@@ -37,14 +36,15 @@
public class InlineElementBox extends CompositeInlineBox {
private final INode node;
- private final InlineBox[] children;
+ private InlineBox[] children;
private InlineBox firstContentChild = null;
private InlineBox lastContentChild = null;
private int baseline;
private int halfLeading;
/**
- * Class constructor, called by the createInlineBoxes static factory method.
+ * Class constructor, called by the createInlineBoxes static factory method. The Box created here is only temporary,
+ * it will be replaced by the split method.
*
* @param context
* LayoutContext to use.
@@ -71,13 +71,17 @@
childList.add(new SpaceBox(space, 1));
}
+ final boolean showLeftMarker = styles.getInlineMarker().equals(CSS.NORMAL);
+
// :before content
final IElement beforeElement = context.getStyleSheet().getPseudoElement(node, CSS.PSEUDO_BEFORE, true);
if (beforeElement != null) {
- childList.addAll(LayoutUtils.createGeneratedInlines(context, beforeElement));
+ childList.addAll(LayoutUtils.createGeneratedInlines(context, beforeElement, showLeftMarker ? StaticTextBox.NO_MARKER : StaticTextBox.START_MARKER));
}
// left marker
- childList.add(createLeftMarker(node, styles));
+ if (showLeftMarker) {
+ childList.add(createLeftMarker(node, styles));
+ }
}
// background image
@@ -105,13 +109,17 @@
if (endOffset > node.getEndOffset()) {
childList.add(new PlaceholderBox(context, node, node.getEndOffset() - node.getStartOffset()));
+ final boolean showRightMarker = styles.getInlineMarker().equals(CSS.NORMAL);
+
// trailing marker
- childList.add(createRightMarker(node, styles));
+ if (showRightMarker) {
+ childList.add(createRightMarker(node, styles));
+ }
// :after content
final IElement afterElement = context.getStyleSheet().getPseudoElement(node, CSS.PSEUDO_AFTER, true);
if (afterElement != null) {
- childList.addAll(LayoutUtils.createGeneratedInlines(context, afterElement));
+ childList.addAll(LayoutUtils.createGeneratedInlines(context, afterElement, showRightMarker ? StaticTextBox.NO_MARKER : StaticTextBox.END_MARKER));
}
// space for the right margin/border/padding
@@ -123,7 +131,6 @@
}
children = childList.toArray(new InlineBox[childList.size()]);
- layout(context);
}
/**
@@ -210,7 +217,7 @@
}
@Override
- public Pair split(final LayoutContext context, final InlineBox[] lefts, final InlineBox[] rights) {
+ public Pair split(final LayoutContext context, final InlineBox[] lefts, final InlineBox[] rights, final int remaining) {
InlineElementBox left = null;
InlineElementBox right = null;
@@ -220,10 +227,23 @@
}
if (rights.length > 0) {
- right = new InlineElementBox(context, getNode(), rights);
+ // We reuse this element instead of creating a new one
+ children = rights;
+ for (final InlineBox child : children) {
+ if (child.hasContent()) {
+ // The lastContentChild is already set in this instance an did not change
+ firstContentChild = child;
+ break;
+ }
+ }
+ if (left == null && remaining >= 0) {
+ // There is no left box, and the right box fits without further splitting, so we have to calculate the size here
+ layout(context);
+ }
+ right = this;
}
- return new Pair(left, right);
+ return new Pair(left, right, remaining);
}
@Override
@@ -292,12 +312,16 @@
@Override
public void visit(final IComment comment) {
- createBoxWithBeforeAndAfterContent(comment);
+ addPlaceholderBox(result, new PlaceholderBox(context, node, comment.getStartOffset() - node.getStartOffset()));
+ final InlineBox child = new InlineElementBox(context, comment, range.getStartOffset(), range.getEndOffset());
+ addChildInlineBox(result, child);
};
@Override
public void visit(final IProcessingInstruction pi) {
- createBoxWithBeforeAndAfterContent(pi);
+ addPlaceholderBox(result, new PlaceholderBox(context, node, pi.getStartOffset() - node.getStartOffset()));
+ final InlineBox child = new InlineElementBox(context, pi, range.getStartOffset(), range.getEndOffset());
+ addChildInlineBox(result, child);
};
@Override
@@ -306,34 +330,21 @@
final InlineBox child = new DocumentTextBox(context, node, boxRange.getStartOffset(), boxRange.getEndOffset());
addChildInlineBox(result, child);
}
-
- private void createBoxWithBeforeAndAfterContent(final INode node) {
- addPlaceholderBox(result, new PlaceholderBox(context, node, node.getStartOffset() - node.getStartOffset()));
- final List<Box> boxes = new ArrayList<Box>();
- final StyleSheet styleSheet = context.getStyleSheet();
-
- // :before content
- final IElement before = styleSheet.getPseudoElement(node, CSS.PSEUDO_BEFORE, true);
- if (before != null) {
- boxes.addAll(LayoutUtils.createGeneratedInlines(context, before, StaticTextBox.START_MARKER));
- }
-
- if (node.getEndOffset() - node.getStartOffset() > 1) {
- boxes.add(new DocumentTextBox(context, node, node.getStartOffset() + 1, node.getEndOffset() - 1));
- }
- boxes.add(new PlaceholderBox(context, node, node.getEndOffset() - node.getStartOffset()));
-
- // :after content
- final IElement after = styleSheet.getPseudoElement(node, CSS.PSEUDO_AFTER, true);
- if (after != null) {
- boxes.addAll(LayoutUtils.createGeneratedInlines(context, after, StaticTextBox.END_MARKER));
- }
- final InlineBox child = new InlineElementBox(context, node, boxes.toArray(new InlineBox[boxes.size()]));
- addChildInlineBox(result, child);
- }
});
}
}
+
+ @Override
+ public void visit(final IComment comment) {
+ final InlineBox child = new DocumentTextBox(context, comment, comment.getStartOffset() + 1, comment.getEndOffset() - 1);
+ addChildInlineBox(result, child);
+ }
+
+ @Override
+ public void visit(final IProcessingInstruction pi) {
+ final InlineBox child = new DocumentTextBox(context, pi, pi.getStartOffset() + 1, pi.getEndOffset() - 1);
+ addChildInlineBox(result, child);
+ }
});
return result;
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/LineBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/LineBox.java
index 0fbef92..8b90944 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/LineBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/LineBox.java
@@ -18,7 +18,7 @@
public class LineBox extends CompositeInlineBox {
private final INode node;
- private final InlineBox[] children;
+ private InlineBox[] children;
private InlineBox firstContentChild = null;
private InlineBox lastContentChild = null;
private int baseline;
@@ -32,29 +32,26 @@
* InlineBoxes that make up this line.
*/
public LineBox(final LayoutContext context, final INode node, final InlineBox[] children) {
-
this.node = node;
this.children = children;
+ }
- int height = 0;
- int x = 0;
- baseline = 0;
- for (final InlineBox child : children) {
- child.setX(x);
- child.setY(0); // TODO: do proper vertical alignment
- baseline = Math.max(baseline, child.getBaseline());
- x += child.getWidth();
- height = Math.max(height, child.getHeight());
- if (child.hasContent()) {
- if (firstContentChild == null) {
- firstContentChild = child;
- }
- lastContentChild = child;
- }
- }
-
- setHeight(height);
- setWidth(x);
+ /**
+ * Class constructor used by the split method.
+ *
+ * @param other
+ * Instance of LineBox that should be splitted.
+ * @param context
+ * LayoutContext used for the layout.
+ * @param node
+ * Node to which this box applies.
+ * @param children
+ * Child boxes.
+ */
+ private LineBox(final LineBox other, final LayoutContext context, final InlineBox[] children) {
+ node = other.node;
+ this.children = children;
+ layout(context);
}
/**
@@ -106,20 +103,27 @@
* org.eclipse.vex.core.internal.layout.InlineBox[], org.eclipse.vex.core.internal.layout.InlineBox[])
*/
@Override
- public Pair split(final LayoutContext context, final InlineBox[] lefts, final InlineBox[] rights) {
+ public Pair split(final LayoutContext context, final InlineBox[] lefts, final InlineBox[] rights, final int remaining) {
LineBox left = null;
LineBox right = null;
if (lefts.length > 0) {
- left = new LineBox(context, getNode(), lefts);
+ left = new LineBox(this, context, lefts);
}
if (rights.length > 0) {
- right = new LineBox(context, getNode(), rights);
+ // We reuse this element instead of creating a new one
+ children = rights;
+
+ if (left == null && remaining >= 0) {
+ // There is no left box, and the right box fits without further splitting, so we have to calculate the size here
+ layout(context);
+ }
+ right = this;
}
- return new Pair(left, right);
+ return new Pair(left, right, remaining);
}
/**
@@ -137,4 +141,26 @@
// ========================================================== PRIVATE
+ private void layout(final LayoutContext context) {
+ int height = 0;
+ int x = 0;
+ baseline = 0;
+ for (final InlineBox child : children) {
+ child.setX(x);
+ child.setY(0); // TODO: do proper vertical alignment
+ baseline = Math.max(baseline, child.getBaseline());
+ x += child.getWidth();
+ height = Math.max(height, child.getHeight());
+ if (child.hasContent()) {
+ if (firstContentChild == null) {
+ firstContentChild = child;
+ }
+ lastContentChild = child;
+ }
+ }
+
+ setHeight(height);
+ setWidth(x);
+ }
+
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/ParagraphBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/ParagraphBox.java
index e66d698..eecb0d0 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/ParagraphBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/ParagraphBox.java
@@ -84,28 +84,25 @@
while (right != null) {
final InlineBox.Pair pair = right.split(context, width, true);
- //FIXME icampist this indicates some design problem, since later on, LineBoxes are expected
- //either we cast here to LineBox or we make an if later on.
lines.add(pair.getLeft());
right = pair.getRight();
}
final Styles styles = context.getStyleSheet().getStyles(node);
final String textAlign = styles.getTextAlign();
+ final boolean alignRight = textAlign.equals(CSS.RIGHT);
+ final boolean alignCenter = textAlign.equals(CSS.CENTER);
// y-offset of the next line
int y = 0;
int actualWidth = 0;
- //children for the ParagraphBox constructor that accepts only LineBoxes
- final List<LineBox> lineBoxesChildren = new ArrayList<LineBox>();
-
for (final Box lineBox : lines) {
int x;
- if (textAlign.equals(CSS.RIGHT)) {
+ if (alignRight) {
x = width - lineBox.getWidth();
- } else if (textAlign.equals(CSS.CENTER)) {
+ } else if (alignCenter) {
x = (width - lineBox.getWidth()) / 2;
} else {
x = 0;
@@ -116,36 +113,12 @@
y += lineBox.getHeight();
actualWidth = Math.max(actualWidth, lineBox.getWidth());
-
- //strange, but we need to check the case because it's not explicit anywhere
- if (lineBox instanceof LineBox) {
- lineBoxesChildren.add((LineBox) lineBox);
- }
}
- final ParagraphBox para = new ParagraphBox(lineBoxesChildren.toArray(new LineBox[lineBoxesChildren.size()]));
+ final ParagraphBox para = new ParagraphBox(lines.toArray(new LineBox[lines.size()]));
para.setWidth(actualWidth);
para.setHeight(y);
- // BlockElementBox uses a scaling factor to estimate box height based
- // on font size, layout width, and character count, as follows.
- //
- // estHeight = factor * fontSize * fontSize * charCount / width
- //
- // This bit reports the actual factor that would correctly estimate
- // the height of a BlockElementBox containing only this paragraph.
- //
- // factor = estHeight * width / (fontSize * fontSize * charCount)
- //
- /*
- * Box firstContentBox = null; for (int i = 0; i < inlines.length; i++) { Box box = inlines[i]; if
- * (box.hasContent()) { firstContentBox = box; break; } }
- *
- * if (firstContentBox != null) { float fontSize = styles.getFontSize(); int charCount =
- * lastContentBox.getEndOffset() - firstContentBox.getStartOffset(); float factor = para.getHeight()
- * para.getWidth() / (fontSize fontSize charCount); System.out.println("Actual factor is " + factor); }
- */
-
return para;
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/PlaceholderBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/PlaceholderBox.java
index 38afaac..0e7f54c 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/PlaceholderBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/PlaceholderBox.java
@@ -69,14 +69,6 @@
}
/**
- * @see org.eclipse.vex.core.internal.layout.InlineBox#split(org.eclipse.vex.core.internal.layout.LayoutContext,
- * int, boolean)
- */
- public Pair split(final LayoutContext context, final int maxWidth, final boolean force) {
- return new Pair(null, this);
- }
-
- /**
* @see org.eclipse.vex.core.internal.layout.Box#getCaret(org.eclipse.vex.core.internal.layout.LayoutContext, int)
*/
@Override
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/SpaceBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/SpaceBox.java
index 0f90c12..3ded483 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/SpaceBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/SpaceBox.java
@@ -40,14 +40,6 @@
}
/**
- * @see org.eclipse.vex.core.internal.layout.InlineBox#split(org.eclipse.vex.core.internal.layout.LayoutContext,
- * int, boolean)
- */
- public Pair split(final LayoutContext context, final int maxWidth, final boolean force) {
- return new Pair(null, this);
- }
-
- /**
* @see java.lang.Object#toString()
*/
@Override
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/StaticTextBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/StaticTextBox.java
index b86ed20..8654b51 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/StaticTextBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/StaticTextBox.java
@@ -10,6 +10,7 @@
*******************************************************************************/
package org.eclipse.vex.core.internal.layout;
+import org.eclipse.core.runtime.Assert;
import org.eclipse.vex.core.internal.core.ColorResource;
import org.eclipse.vex.core.internal.core.FontResource;
import org.eclipse.vex.core.internal.core.Graphics;
@@ -28,6 +29,8 @@
private final String text;
private final byte marker;
+ private int startRelative;
+ private final int endRelative;
/**
* Class constructor.
@@ -64,8 +67,35 @@
public StaticTextBox(final LayoutContext context, final INode node, final String text, final byte marker) {
super(node);
this.text = text;
+ startRelative = 0;
+ endRelative = text.length();
this.marker = marker;
- calculateSize(context);
+ calculateHeight(context);
+ setWidth(-1);
+ }
+
+ /**
+ * Class constructor used by the splitAt method.
+ *
+ * @param other
+ * Instance of DocumentTextBox that should be splitted.
+ * @param endOffset
+ * The endOffset of the text in the new box.
+ * @param width
+ * The calculated layout width of the new box.
+ */
+ private StaticTextBox(final StaticTextBox other, final int endOffset, final int width) {
+ super(other.getNode());
+ text = other.text; // Text is shared in all instances
+ startRelative = other.startRelative;
+ endRelative = startRelative + endOffset;
+ if (endRelative <= startRelative) {
+ Assert.isTrue(startRelative < endRelative, "StaticTextBox start is greater than end");
+ }
+ marker = other.marker;
+ setWidth(width);
+ setHeight(other.getHeight());
+ setBaseline(other.getBaseline());
}
/**
@@ -73,7 +103,12 @@
*/
@Override
public String getText() {
- return text;
+ return text.substring(startRelative, endRelative);
+ }
+
+ @Override
+ public boolean isEOL() {
+ return text.length() > 0 && text.charAt(endRelative - 1) == NEWLINE_CHAR;
}
/**
@@ -123,22 +158,31 @@
* @see org.eclipse.vex.core.internal.layout.TextBox#splitAt(int)
*/
@Override
- public Pair splitAt(final LayoutContext context, final int offset) {
+ protected Pair splitAt(final LayoutContext context, final int offset, final int leftWidth, final int maxWidth) {
+
+ int remaining = maxWidth;
StaticTextBox left;
if (offset == 0) {
left = null;
} else {
- left = new StaticTextBox(context, getNode(), getText().substring(0, offset), marker);
+ left = new StaticTextBox(this, offset, leftWidth);
+ remaining -= leftWidth;
}
StaticTextBox right;
- if (offset == getText().length()) {
+ if (offset + startRelative >= endRelative) {
right = null;
} else {
- right = new StaticTextBox(context, getNode(), getText().substring(offset), marker);
+ // Instead of creating a new box, we reuse this one
+ startRelative += offset;
+ if (left == null) {
+ calculateSize(context);
+ remaining -= getWidth();
+ }
+ right = this;
}
- return new Pair(left, right);
+ return new Pair(left, right, remaining);
}
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/TextBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/TextBox.java
index 0983682..f975164 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/TextBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/TextBox.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2008 John Krasnay and others.
+ * Copyright (c) 2004, 2013 John Krasnay 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
@@ -7,6 +7,7 @@
*
* Contributors:
* John Krasnay - initial API and implementation
+ * Carsten Hiesserich - performance optimization for split methods
*******************************************************************************/
package org.eclipse.vex.core.internal.layout;
@@ -46,7 +47,8 @@
* initialized.
*
* @param context
- * LayoutContext used to calculate size.
+ * LayoutContext used to calculate size. The correct font has to be set in the context's graphics before
+ * calling this method.
*/
protected void calculateSize(final LayoutContext context) {
String s = getText();
@@ -56,13 +58,41 @@
final Graphics g = context.getGraphics();
final Styles styles = context.getStyleSheet().getStyles(getNode());
+
+ final FontMetrics fm = g.getFontMetrics();
+ if (s.length() > 1000) {
+ // g.stringWidth() fails randomly with long strings on windows. Such a long text will be splitted anyway,
+ // so it is safe to return a very long fixed width here instead.
+ setWidth(99999);
+ } else {
+ setWidth(g.stringWidth(s));
+ }
+ setHeight(styles.getLineHeight());
+ final int halfLeading = (getHeight() - (fm.getAscent() + fm.getDescent())) / 2;
+ setBaseline(halfLeading + fm.getAscent());
+ }
+
+ /**
+ * Causes the box to recalculate its height and baseline. Subclasses should call this from their constructors after
+ * they are initialized.
+ *
+ * @param context
+ * LayoutContext used to calculate size.
+ */
+ protected void calculateHeight(final LayoutContext context) {
+ String s = getText();
+ if (s.endsWith(NEWLINE_STRING)) {
+ s = s.substring(0, s.length() - 1);
+ }
+
+ final Graphics g = context.getGraphics();
+ final Styles styles = context.getStyleSheet().getStyles(getNode());
final FontResource font = g.createFont(styles.getFont());
final FontResource oldFont = g.setFont(font);
final FontMetrics fm = g.getFontMetrics();
- setWidth(g.stringWidth(s));
setHeight(styles.getLineHeight());
final int halfLeading = (getHeight() - (fm.getAscent() + fm.getDescent())) / 2;
- baseline = halfLeading + fm.getAscent();
+ setBaseline(halfLeading + fm.getAscent());
g.setFont(oldFont);
font.dispose();
}
@@ -75,6 +105,13 @@
}
/**
+ * @see org.eclipse.vex.core.internal.layout.InlineBox#getBaseline()
+ */
+ public void setBaseline(final int baseline) {
+ this.baseline = baseline;
+ }
+
+ /**
* @see org.eclipse.vex.core.internal.layout.Box#getCaret(org.eclipse.vex.core.internal.layout.LayoutContext, int)
*/
@Override
@@ -115,11 +152,6 @@
return Character.isWhitespace(c);
}
- public boolean isEOL() {
- final String s = getText();
- return s.length() > 0 && s.charAt(s.length() - 1) == NEWLINE_CHAR;
- }
-
/**
* Paints a string as selected text.
*
@@ -202,31 +234,44 @@
g.drawLine(x, y, x + width, y);
}
+ @Override
+ public boolean isSplitable() {
+ return true;
+ }
+
/**
* @see org.eclipse.vex.core.internal.layout.InlineBox#split(org.eclipse.vex.core.internal.layout.LayoutContext,
* int, boolean)
*/
+ @Override
public Pair split(final LayoutContext context, final int maxWidth, final boolean force) {
- final char[] chars = getText().toCharArray();
+ final String text = getText();
+ final int length = text.length();
- if (chars.length == 0) {
+ if (text.length() == 0) {
throw new IllegalStateException();
}
final Graphics g = context.getGraphics();
final Styles styles = context.getStyleSheet().getStyles(node);
+
final FontResource font = g.createFont(styles.getFont());
final FontResource oldFont = g.setFont(font);
int split = 0;
int next = 1;
+ int width = 0;
+ int splitWidth = 0;
boolean eol = false; // end of line found
- while (next < chars.length) {
- if (isSplitChar(chars[next - 1])) {
- if (g.charsWidth(chars, 0, next) <= maxWidth) {
+ while (next < length) {
+ final char nextChar = text.charAt(next - 1);
+ if (isSplitChar(nextChar)) {
+ width += g.stringWidth(text.substring(split, next));
+ if (width <= maxWidth) {
split = next;
- if (chars[next - 1] == NEWLINE_CHAR) {
+ splitWidth = width;
+ if (nextChar == NEWLINE_CHAR) {
eol = true;
break;
}
@@ -240,40 +285,53 @@
if (force && split == 0) {
// find some kind of split
split = 1;
- while (split < chars.length) {
- if (g.charsWidth(chars, 0, split + 1) > maxWidth) {
+ splitWidth = width = g.stringWidth(text.substring(0, 1));
+ while (split < length) {
+ width += g.stringWidth(text.substring(split, split + 1));
+ if (width > maxWidth) {
break;
}
split++;
+ splitWidth = width;
}
-
}
// include any trailing spaces in the split
// this also grabs any leading spaces when split==0
+ final int spaceCharWidth = context.getGraphics().stringWidth(" ");
if (!eol) {
- while (split < chars.length - 1 && chars[split] == ' ') {
+ while (split < length && text.charAt(split) == ' ') {
split++;
+ splitWidth += spaceCharWidth;
}
}
+ final Pair splitPair = splitAt(context, split, splitWidth, maxWidth);
+
+ // The created font is used by the calculateSize() method, so we have to keep it till after the splitAt method call.
g.setFont(oldFont);
font.dispose();
- return splitAt(context, split);
+ return splitPair;
}
/**
* Return a pair of boxes representing a split at the given offset. If split is zero, then the returned left box
* should be null. If the split is equal to the length of the text, then the right box should be null.
- *
+ *
* @param context
- * LayoutContext used to calculate the sizes of the resulting boxes.
+ * LayoutContext used to calculate size. The correct font has to be set in the context's graphics before
+ * calling this method.
* @param offset
* location of the split, relative to the start of the text box.
+ * @param leftWidth
+ * Calculated width of the left box. The width has already been calculated by the calling class, so
+ * there's no need to calculated it again.
+ * @param maxWidth
+ * The maximal width of the current split. Used to calculate the remaining width of the returned Pair.
* @return
*/
- public abstract Pair splitAt(LayoutContext context, int offset);
+ protected abstract Pair splitAt(LayoutContext context, int offset, int leftWidth, int maxWidth);
/**
* @see java.lang.Object#toString()
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/VerticalRange.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/VerticalRange.java
index ca7aed1..c4f8cc1 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/VerticalRange.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/VerticalRange.java
@@ -13,7 +13,7 @@
import java.text.MessageFormat;
-import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.AssertionFailedException;
/**
* Represents a vertical range used in the layouting algorithm. Zero-length ranges (i.e. ranges where top == bottom) are
@@ -33,7 +33,9 @@
* bottom of the range, must be >= top
*/
public VerticalRange(final int top, final int bottom) {
- Assert.isTrue(top <= bottom, MessageFormat.format("top {0} must not be above bottom {1}", top, bottom));
+ if (top > bottom) {
+ throw new AssertionFailedException(MessageFormat.format("top {0} must not be above bottom {1}", top, bottom));
+ }
this.top = top;
this.bottom = bottom;
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/validator/WTPVEXValidator.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/validator/WTPVEXValidator.java
index 5153b9a..7e374dc 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/validator/WTPVEXValidator.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/validator/WTPVEXValidator.java
@@ -41,7 +41,6 @@
import org.eclipse.wst.xml.core.internal.contentmodel.CMNamedNodeMap;
import org.eclipse.wst.xml.core.internal.contentmodel.CMNode;
import org.eclipse.wst.xml.core.internal.contentmodel.CMNodeList;
-import org.eclipse.wst.xml.core.internal.contentmodel.ContentModelManager;
import org.eclipse.wst.xml.core.internal.contentmodel.internal.util.CMValidator;
import org.eclipse.wst.xml.core.internal.contentmodel.internal.util.CMValidator.ElementContentComparator;
import org.eclipse.wst.xml.core.internal.contentmodel.internal.util.CMValidator.ElementPathRecordingResult;
@@ -64,9 +63,7 @@
private final DocumentContentModel documentContentModel;
- private CMDocument dtd;
-
- private final Map<URL, CMDocument> contentModelCache = new HashMap<URL, CMDocument>();
+ private final Map<String, CMDocument> contentModelCache = new HashMap<String, CMDocument>();
private final CMValidator validator = new CMValidator();
@@ -90,48 +87,29 @@
return documentContentModel;
}
- private CMDocument getSchema(final String namespaceURI) {
- if (isDTDDefined()) {
- return getDTD();
- }
- if (namespaceURI == null) {
- /*
- * This can be the case if the document does neither contain a doctype declaration nor a default namespace
- * declaration.
- */
- return getSchema((URL) null);
- }
- final URL resolved = documentContentModel.resolveSchemaIdentifier(namespaceURI);
- return getSchema(resolved);
- }
-
- private CMDocument getSchema(final URL schemaUrl) {
- if (contentModelCache.containsKey(schemaUrl)) {
- return contentModelCache.get(schemaUrl);
+ private CMDocument getContentModelDoc(final String schemaURI) {
+ if (contentModelCache.containsKey(schemaURI)) {
+ return contentModelCache.get(schemaURI);
}
- final CMDocument contentModel;
- if (schemaUrl != null) {
- final ContentModelManager modelManager = ContentModelManager.getInstance();
- contentModel = modelManager.createCMDocument(schemaUrl.toString(), null);
+ CMDocument contentModel;
+
+ if (schemaURI == null) {
+ contentModel = documentContentModel.getContentModelDocument();
} else {
+ contentModel = documentContentModel.getContentModelDocument(schemaURI);
+ }
+
+ if (contentModel == null) {
+ // Schema could not be resolved - create a dummy instance
contentModel = new UnknownCMDocument(null);
}
- contentModelCache.put(schemaUrl, contentModel);
+
+ contentModelCache.put(schemaURI, contentModel);
+
return contentModel;
}
- private boolean isDTDDefined() {
- return documentContentModel.isDtdAssigned();
- }
-
- private CMDocument getDTD() {
- if (dtd == null && documentContentModel.isDtdAssigned()) {
- dtd = documentContentModel.getDTD();
- }
- return dtd;
- }
-
public AttributeDefinition getAttributeDefinition(final IAttribute attribute) {
final String attributeName = attribute.getLocalName();
final CMElementDeclaration cmElement = getElementDeclaration(attribute.getParent());
@@ -190,7 +168,7 @@
return null;
}
final String localName = element.getLocalName();
- final CMElementDeclaration declarationFromRoot = (CMElementDeclaration) getSchema(element.getQualifiedName().getQualifier()).getElements().getNamedItem(localName);
+ final CMElementDeclaration declarationFromRoot = (CMElementDeclaration) getContentModelDoc(element.getQualifiedName().getQualifier()).getElements().getNamedItem(localName);
if (declarationFromRoot != null) {
return declarationFromRoot;
}
@@ -346,7 +324,7 @@
private Set<CMElementDeclaration> getValidRootElements(final String namespaceURI) {
final HashSet<CMElementDeclaration> result = new HashSet<CMElementDeclaration>();
- final Iterator<?> iter = getSchema(namespaceURI).getElements().iterator();
+ final Iterator<?> iter = getContentModelDoc(namespaceURI).getElements().iterator();
while (iter.hasNext()) {
final CMElementDeclaration element = (CMElementDeclaration) iter.next();
result.add(element);
@@ -368,7 +346,13 @@
return true;
}
- final CMNode parent = getSchema(element.getQualifier()).getElements().getNamedItem(element.getLocalName());
+ final CMDocument document = getContentModelDoc(element.getQualifier());
+ if (document == null) {
+ System.out.println("Unable to resolve validation schema for " + element.getQualifier());
+ return true;
+ }
+ CMNode parent = null;
+ parent = document.getElements().getNamedItem(element.getLocalName());
if (!(parent instanceof CMElementDeclaration)) {
return true;
}
@@ -425,7 +409,7 @@
private Set<String> getRequiredNamespaces(final String namespaceUri, final Set<CMNode> visitedNodes) {
final HashSet<String> result = new HashSet<String>();
result.add(namespaceUri);
- final CMDocument mainSchema = getSchema(namespaceUri);
+ final CMDocument mainSchema = getContentModelDoc(namespaceUri);
for (final Iterator<?> iter = mainSchema.getElements().iterator(); iter.hasNext();) {
final CMElementDeclaration elementDeclaration = (CMElementDeclaration) iter.next();
result.addAll(getRequiredNamespaces(elementDeclaration, visitedNodes));
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/ContentRange.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/ContentRange.java
index 68b8f79..e576af7 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/ContentRange.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/ContentRange.java
@@ -12,7 +12,7 @@
import java.text.MessageFormat;
-import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.AssertionFailedException;
/**
* An immutable representation of a range within <code>IContent</code>.
@@ -35,7 +35,10 @@
* the end offset of this range
*/
public ContentRange(final int startOffset, final int endOffset) {
- Assert.isTrue(startOffset <= endOffset, MessageFormat.format("startOffset {0} must not be greater than endOffset {1}", startOffset, endOffset));
+ if (startOffset > endOffset) {
+ // Do not use Assert.isTrue. This Contructor is called very often and the use of Assert.isTrue would evaluate the Message.format every time.
+ throw new AssertionFailedException(MessageFormat.format("assertion failed: startOffset {0} must not be greater than endOffset {1}", startOffset, endOffset)); //$NON-NLS-1$
+ }
this.startOffset = startOffset;
this.endOffset = endOffset;
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/DocumentContentModel.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/DocumentContentModel.java
index e74650f..e8823aa 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/DocumentContentModel.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/DocumentContentModel.java
@@ -11,8 +11,6 @@
package org.eclipse.vex.core.provisional.dom;
import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
import java.text.MessageFormat;
import org.eclipse.wst.common.uriresolver.internal.provisional.URIResolver;
@@ -42,17 +40,45 @@
initialize(baseUri, publicId, systemId, rootElement);
}
+ /**
+ * Initialize the content model.
+ *
+ * @param baseUri
+ * The base uri of the loaded document
+ * @param publicId
+ * The PublicID of the DocumentTypeDefinition (DTD)
+ * @param systemId
+ * The SystemID of the DocumentTypeDefinition (DTD)
+ * @param rootElement
+ * If no DTD is defined (publicId and systemId are both null) the namespace of the root element is used
+ * to define the document type.
+ */
public void initialize(final String baseUri, final String publicId, final String systemId, final IElement rootElement) {
this.baseUri = baseUri;
this.publicId = publicId;
this.systemId = systemId;
- if (rootElement != null) {
+ if (publicId == null && systemId == null && rootElement != null) {
schemaId = rootElement.getQualifiedName().getQualifier();
} else {
schemaId = null;
}
}
+ /**
+ * Sets an explicit namespace.
+ *
+ * @param baseUri
+ * The base uri of the loaded document
+ * @param rootNamespace
+ * The default namespace to resolve the XML-Schema for validation.
+ */
+ public void setSchemaId(final String baseUri, final String rootNamespace) {
+ this.baseUri = baseUri;
+ publicId = null;
+ systemId = null;
+ schemaId = rootNamespace;
+ }
+
public String getMainDocumentTypeIdentifier() {
if (publicId != null) {
return publicId;
@@ -71,29 +97,76 @@
return systemId;
}
+ public String getSchemaId() {
+ return schemaId;
+ }
+
public boolean isDtdAssigned() {
return publicId != null || systemId != null;
}
- public CMDocument getDTD() {
- final URL resolvedPublicId = resolveSchemaIdentifier(publicId);
- if (resolvedPublicId != null) {
- return createCMDocument(resolvedPublicId);
+ /**
+ * Create and return the WTP CMDocument for the DTD or schema defined by this ContentModel.
+ *
+ * @return The resolved CMDocument.
+ */
+ public CMDocument getContentModelDocument() {
+ if (schemaId != null) {
+ return getContentModelDocument(schemaId);
}
- return createCMDocument(resolveSystemId(systemId));
+
+ String resolvedURI = null;
+ try {
+ resolvedURI = resolveResourceURI(publicId, systemId);
+ if (resolvedURI == null) {
+ return null;
+ }
+ return createCMDocument(resolvedURI);
+ } catch (final Exception e) {
+ throw new AssertionError(MessageFormat.format("Resolution of systemId ''{0}'' resulted in a exception:{1}. {2}", systemId, resolvedURI, e.getMessage()));
+ }
}
- private CMDocument createCMDocument(final URL resolvedDtdUrl) {
- if (resolvedDtdUrl == null) {
+ /**
+ * Create and return the WTP CMDocument for the XML-Schema at the given URI or namespace. The XML catalog is used to
+ * resolve the schema URI.
+ *
+ * @param schemaID
+ * The URI or the namespace of the XML-Schema.
+ * @return The resolved CMDocument.
+ */
+ public CMDocument getContentModelDocument(final String schemaId) {
+ String resolvedUri = null;
+ try {
+ resolvedUri = resolveResourceURI(null, schemaId);
+ if (resolvedUri == null) {
+ return null;
+ }
+ return createCMDocument(resolvedUri);
+ } catch (final Exception e) {
+ throw new AssertionError(MessageFormat.format("Resolution of resource URI ''{0}'' resulted in a exception:{1}. {2}", schemaId, resolvedUri, e.getMessage()));
+ }
+ }
+
+ /**
+ * Create a new CMDocument from the DTD or XML-Schema at the given URI.
+ *
+ * @param resourceURI
+ * The URI containing the schema or dtd.
+ * @return
+ */
+ private CMDocument createCMDocument(final String resourceURI) {
+ if (resourceURI == null) {
return null;
}
final ContentModelManager modelManager = ContentModelManager.getInstance();
- return modelManager.createCMDocument(resolvedDtdUrl.toString(), null);
+ final CMDocument cmDocument = modelManager.createCMDocument(resourceURI, null);
+ return cmDocument;
}
public InputSource resolveEntity(final String publicId, final String systemId) throws SAXException, IOException {
- final String resolved = URI_RESOLVER.resolve(baseUri, publicId, systemId);
- System.out.println("Resolved " + publicId + " " + systemId + " -> " + resolved);
+ final String resolved = resolveResourceURI(publicId, systemId);
+
if (resolved == null) {
return null;
}
@@ -103,36 +176,19 @@
return result;
}
- public URL resolveSchemaIdentifier(final String schemaIdentifier) {
- if (schemaIdentifier == null) {
- return null;
- }
- final String schemaLocation = URI_RESOLVER.resolve(baseUri, schemaIdentifier, null);
- if (schemaLocation == null) {
- /*
- * TODO this is a common case that should be handled somehow - a hint should be shown: the schema is not
- * available, the schema should be added to the catalog by the user - an inferred schema should be used, to
- * allow to at least display the document in the editor - this is not the right place to either check or
- * handle this
- */
- return null;
- }
- try {
- return new URL(schemaLocation);
- } catch (final MalformedURLException e) {
- throw new AssertionError(MessageFormat.format("Resolution of schema ''{0}'' resulted in a malformed URL: ''{1}''. {2}", schemaIdentifier, schemaLocation, e.getMessage()));
- }
- }
-
- public URL resolveSystemId(final String systemId) {
- final String schemaLocation = URI_RESOLVER.resolve(baseUri, null, systemId);
- if (schemaLocation == null) {
- return null;
- }
- try {
- return new URL(schemaLocation);
- } catch (final MalformedURLException e) {
- throw new AssertionError(MessageFormat.format("Resolution of systemId ''{0}'' resulted in a malformed URL: ''{1}''. {2}", systemId, schemaLocation, e.getMessage()));
- }
+ /**
+ * Resolve the URI for a given Resource with the XML-Catalog.
+ *
+ * @param publicId
+ * The public identifier (DTD) of the resource being referenced, may be null
+ * @param systemId
+ * The system identifier (DTD) or the namespace (XML-Schema) of the resource being referenced, may be
+ * null.
+ * @return A String containing the resolved URI.
+ * @throws IOException
+ */
+ public String resolveResourceURI(final String publicId, final String systemId) throws IOException {
+ final String resolved = URI_RESOLVER.resolve(baseUri, publicId, systemId);
+ return resolved;
}
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/IPosition.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/IPosition.java
index d8850ad..98a04b3 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/IPosition.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/IPosition.java
@@ -4,7 +4,7 @@
* 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:
* John Krasnay - initial API and implementation
* Florian Thienel - NULL object
@@ -18,7 +18,7 @@
* Positions can be invalid if they were removed from their associated Content instance. Invalid positions do not get
* updated on content modifications. They must not be used for anything anymore.
*/
-public interface IPosition {
+public interface IPosition extends Comparable<IPosition> {
static IPosition NULL = new IPosition() {
public int getOffset() {
@@ -33,6 +33,11 @@
public String toString() {
return "NULL";
}
+
+ @Override
+ public int compareTo(final IPosition other) {
+ return -1;
+ }
};
/**
diff --git a/org.eclipse.vex.docbook/plugin.properties b/org.eclipse.vex.docbook/plugin.properties
index 050fe5a..6750db3 100644
--- a/org.eclipse.vex.docbook/plugin.properties
+++ b/org.eclipse.vex.docbook/plugin.properties
@@ -13,9 +13,7 @@
doctype.docbook4_5=DocBook v4.5
doctype.docbook5_0_DTD=DocBook v5.0 (DTD)
-doctype.docbook5_0_XSD1=DocBook v5.0 (http://www.oasis-open.org/docbook/xml/5.0/xsd/docbook.xsd)
-doctype.docbook5_0_XSD2=DocBook v5.0 (http://docbook.org/xml/5.0/xsd/docbook.xsd)
-doctype.docbook5_0_XSD3=DocBook v5.0 (http://docbook.org/ns/docbook)
+doctype.docbook5_0_XSD2=DocBook v5.0 (XML Schema)
style.docbook-plain=DocBook Plain
contentType.name=DocBook XML Document
diff --git a/org.eclipse.vex.docbook/plugin.xml b/org.eclipse.vex.docbook/plugin.xml
index 1079b51..7dae25e 100644
--- a/org.eclipse.vex.docbook/plugin.xml
+++ b/org.eclipse.vex.docbook/plugin.xml
@@ -16,6 +16,14 @@
uri="4.5/docbookx.dtd"
webURL="http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
</public>
+ <system
+ systemId="http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"
+ uri="4.5/docbookx.dtd">
+ </system>
+ <system
+ systemId="http://docbook.org/xml/4.5/docbookx.dtd"
+ uri="4.5/docbookx.dtd">
+ </system>
<uri
name="urn:org:eclipse:vex:styles:docbook:docbook-plain.css"
uri="styles/docbook-plain.css">
@@ -33,33 +41,41 @@
webURL="http://www.oasis-open.org/docbook/xml/5.0/docbook.dtd">
</public>
<uri
- name="http://www.oasis-open.org/docbook/xml/5.0/xsd/docbook.xsd"
- uri="5.0/xsd/docbook.xsd">
- </uri>
- <uri
- name="http://docbook.org/xml/5.0/xsd/docbook.xsd"
- uri="5.0/xsd/docbook.xsd">
- </uri>
- <uri
name="http://docbook.org/ns/docbook"
uri="5.0/xsd/docbook.xsd">
</uri>
+ <system
+ systemId="http://www.oasis-open.org/docbook/xml/5.0/xsd/docbook.xsd"
+ uri="5.0/xsd/docbook.xsd">
+ </system>
+ <system
+ systemId="http://docbook.org/xml/5.0/xsd/docbook.xsd"
+ uri="5.0/xsd/docbook.xsd">
+ </system>
<uri
- name="http://www.oasis-open.org/docbook/xml/5.0/xsd/xlink.xsd"
+ name="http://www.w3.org/1999/xlink"
uri="5.0/xsd/xlink.xsd">
</uri>
- <uri
- name="http://docbook.org/xml/5.0/xsd/xlink.xsd"
+ <system
+ systemId="http://www.oasis-open.org/docbook/xml/5.0/xsd/xlink.xsd"
uri="5.0/xsd/xlink.xsd">
- </uri>
+ </system>
+ <system
+ systemId="http://docbook.org/xml/5.0/xsd/xlink.xsd"
+ uri="5.0/xsd/xlink.xsd">
+ </system>
<uri
- name="http://www.oasis-open.org/docbook/xml/5.0/xsd/xml.xsd"
+ name="http://www.w3.org/XML/1998/namespace"
uri="5.0/xsd/xml.xsd">
</uri>
- <uri
- name="http://docbook.org/xml/5.0/xsd/xml.xsd"
+ <system
+ systemId="http://www.oasis-open.org/docbook/xml/5.0/xsd/xml.xsd"
uri="5.0/xsd/xml.xsd">
- </uri>
+ </system>
+ <system
+ systemId="http://docbook.org/xml/5.0/xsd/xml.xsd"
+ uri="5.0/xsd/xml.xsd">
+ </system>
</catalogContribution>
</extension>
@@ -145,54 +161,13 @@
</doctype>
</extension>
- <extension
- id="docbook5_0_XSD1"
- name="%doctype.docbook5_0_XSD1"
- point="org.eclipse.vex.ui.doctypes">
- <doctype
- publicId="http://www.oasis-open.org/docbook/xml/5.0/xsd/docbook.xsd"
- systemId="5.0/xsd/docbook.xsd">
-
- <rootElement
- name="article">
- </rootElement>
- <rootElement
- name="appendix">
- </rootElement>
- <rootElement
- name="book">
- </rootElement>
- <rootElement
- name="chapter">
- </rootElement>
- <rootElement
- name="sect1">
- </rootElement>
- <rootElement
- name="sect2">
- </rootElement>
- <rootElement
- name="sect3">
- </rootElement>
- <rootElement
- name="sect4">
- </rootElement>
- <rootElement
- name="sect5">
- </rootElement>
- <rootElement
- name="section">
- </rootElement>
- </doctype>
- </extension>
<extension
id="docbook5_0_XSD2"
name="%doctype.docbook5_0_XSD2"
point="org.eclipse.vex.ui.doctypes">
- <doctype
- publicId="http://docbook.org/xml/5.0/xsd/docbook.xsd"
- systemId="5.0/xsd/docbook.xsd">
+ <schema
+ namespaceName="http://docbook.org/ns/docbook">
<rootElement
name="article">
@@ -224,49 +199,9 @@
<rootElement
name="section">
</rootElement>
- </doctype>
+ </schema>
</extension>
- <extension
- id="docbook5_0_XSD2"
- name="%doctype.docbook5_0_XSD3"
- point="org.eclipse.vex.ui.doctypes">
- <doctype
- publicId="http://docbook.org/ns/docbook"
- systemId="5.0/xsd/docbook.xsd">
-
- <rootElement
- name="article">
- </rootElement>
- <rootElement
- name="appendix">
- </rootElement>
- <rootElement
- name="book">
- </rootElement>
- <rootElement
- name="chapter">
- </rootElement>
- <rootElement
- name="sect1">
- </rootElement>
- <rootElement
- name="sect2">
- </rootElement>
- <rootElement
- name="sect3">
- </rootElement>
- <rootElement
- name="sect4">
- </rootElement>
- <rootElement
- name="sect5">
- </rootElement>
- <rootElement
- name="section">
- </rootElement>
- </doctype>
- </extension>
<extension
id="docbook-plain"
@@ -274,11 +209,12 @@
point="org.eclipse.vex.ui.styles">
<style
css="styles/docbook-plain.css">
+ <doctypeRef
+ publicId="docbook5_0_DTD">
+ </doctypeRef>
<doctypeRef publicId="-//OASIS//DTD Simplified DocBook XML V1.1//EN"/>
<doctypeRef publicId="-//OASIS//DTD DocBook XML V4.5//EN"/>
<doctypeRef publicId="-//OASIS//DTD DocBook XML 5.0//EN"/>
- <doctypeRef publicId="http://www.oasis-open.org/docbook/xml/5.0/xsd/docbook.xsd"/>
- <doctypeRef publicId="http://docbook.org/xml/5.0/xsd/docbook.xsd"/>
<doctypeRef publicId="http://docbook.org/ns/docbook"/>
</style>
</extension>
diff --git a/org.eclipse.vex.ui.tests/META-INF/MANIFEST.MF b/org.eclipse.vex.ui.tests/META-INF/MANIFEST.MF
index f666f20..6166a7a 100644
--- a/org.eclipse.vex.ui.tests/META-INF/MANIFEST.MF
+++ b/org.eclipse.vex.ui.tests/META-INF/MANIFEST.MF
@@ -14,8 +14,5 @@
org.w3c.css.sac;bundle-version="[1.3.0,2.0.0)",
org.junit;bundle-version="4.10.0"
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
-Export-Package: org.eclipse.vex.ui.internal.config.tests;x-internal:=true,
- org.eclipse.vex.ui.internal.editor.tests;x-internal:=true,
- org.eclipse.vex.ui.tests
Bundle-Localization: plugin
Bundle-ClassPath: .
diff --git a/org.eclipse.vex.ui.tests/plugin.xml b/org.eclipse.vex.ui.tests/plugin.xml
index 657600e..dd04ca3 100644
--- a/org.eclipse.vex.ui.tests/plugin.xml
+++ b/org.eclipse.vex.ui.tests/plugin.xml
@@ -26,6 +26,14 @@
</doctype>
</extension>
<extension
+ id="test-schema-doctype"
+ name="test schema doctype"
+ point="org.eclipse.vex.ui.doctypes">
+ <schema
+ namespaceName="http://org.eclipse.vex/namespace">
+ </schema>
+ </extension>
+ <extension
id="test-style"
name="test style"
point="org.eclipse.vex.ui.styles">
@@ -36,5 +44,35 @@
</doctypeRef>
</style>
</extension>
+ <extension
+ id="test-style"
+ name="test style"
+ point="org.eclipse.vex.ui.styles">
+ <style
+ css="testdata/test-schema.css">
+ <doctypeRef
+ publicId="http://org.eclipse.vex/namespace">
+ </doctypeRef>
+ </style>
+ </extension>
+ <extension
+ id="test-style-doctype-id"
+ name="test style doctype id"
+ point="org.eclipse.vex.ui.styles">
+ <style
+ css="testdata/test-doctype-id.css">
+ <doctypeRef
+ publicId="test-schema-doctype2">
+ </doctypeRef>
+ </style>
+ </extension>
+ <extension
+ id="test-schema-doctype2"
+ name="test schema doctype2"
+ point="org.eclipse.vex.ui.doctypes">
+ <schema
+ namespaceName="http://org.eclipse.vex/namespace2">
+ </schema>
+ </extension>
</plugin>
diff --git a/org.eclipse.vex.ui.tests/pom.xml b/org.eclipse.vex.ui.tests/pom.xml
index 55d00cf..096360f 100644
--- a/org.eclipse.vex.ui.tests/pom.xml
+++ b/org.eclipse.vex.ui.tests/pom.xml
@@ -21,11 +21,9 @@
<version>${tycho-version}</version>
<configuration>
<useUIHarness>true</useUIHarness>
- <testSuite>org.eclipse.vex.ui.tests</testSuite>
- <testClass>org.eclipse.vex.ui.tests.VexUiTestSuite</testClass>
</configuration>
</plugin>
</plugins>
</build>
-
+
</project>
diff --git a/org.eclipse.vex.ui.tests/src/org/eclipse/vex/ui/internal/config/tests/ConfigurationRegistryTest.java b/org.eclipse.vex.ui.tests/src/org/eclipse/vex/ui/internal/config/tests/ConfigurationRegistryTest.java
index 933f56d..83d6e9b 100644
--- a/org.eclipse.vex.ui.tests/src/org/eclipse/vex/ui/internal/config/tests/ConfigurationRegistryTest.java
+++ b/org.eclipse.vex.ui.tests/src/org/eclipse/vex/ui/internal/config/tests/ConfigurationRegistryTest.java
@@ -1,15 +1,17 @@
/*******************************************************************************
- * Copyright (c) 2010 Florian Thienel and others.
+ * Copyright (c) 2013 Florian Thienel 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:
* Florian Thienel - initial API and implementation
+ * Carsten Hiesserich - additional tests
*******************************************************************************/
package org.eclipse.vex.ui.internal.config.tests;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -20,10 +22,12 @@
import org.eclipse.core.resources.IProject;
import org.eclipse.vex.ui.internal.config.ConfigEvent;
+import org.eclipse.vex.ui.internal.config.ConfigLoaderJob;
import org.eclipse.vex.ui.internal.config.ConfigSource;
import org.eclipse.vex.ui.internal.config.ConfigurationLoader;
import org.eclipse.vex.ui.internal.config.ConfigurationRegistry;
import org.eclipse.vex.ui.internal.config.ConfigurationRegistryImpl;
+import org.eclipse.vex.ui.internal.config.DocumentType;
import org.eclipse.vex.ui.internal.config.IConfigListener;
import org.eclipse.vex.ui.internal.config.PluginProject;
import org.junit.After;
@@ -116,6 +120,46 @@
assertNotNull(registry.getPluginProject(project));
}
+ @Test
+ public void testPluginDoctypeDefinition() throws Exception {
+ final ConfigurationRegistry configurationRegistry = new ConfigurationRegistryImpl(new ConfigLoaderJob());
+ configurationRegistry.loadConfigurations();
+
+ final DocumentType doctype = configurationRegistry.getDocumentType("-//Vex//DTD Test//EN", null);
+ assertNotNull(doctype);
+ assertEquals("test.dtd", doctype.getSystemId());
+ }
+
+ @Test
+ public void testPluginNamespaceDefinition() throws Exception {
+ final ConfigurationRegistry configurationRegistry = new ConfigurationRegistryImpl(new ConfigLoaderJob());
+ configurationRegistry.loadConfigurations();
+
+ final DocumentType doctype = configurationRegistry.getDocumentType("http://org.eclipse.vex/namespace", null);
+ assertNotNull(doctype);
+ assertEquals("test schema doctype", doctype.getName());
+ }
+
+ @Test
+ public void testGetDocumentTypesWithStyles() throws Exception {
+ final ConfigurationRegistry configurationRegistry = new ConfigurationRegistryImpl(new ConfigLoaderJob());
+ configurationRegistry.loadConfigurations();
+
+ final DocumentType[] doctypes = configurationRegistry.getDocumentTypesWithStyles();
+ boolean dtdFound = false;
+ boolean schemaFound = false;
+ for (final DocumentType doctype : doctypes) {
+ if ("test doctype".equals(doctype.getName())) {
+ dtdFound = true;
+ }
+ if ("test schema doctype".equals(doctype.getName())) {
+ schemaFound = true;
+ }
+ }
+ assertTrue("DoctypeWithStyles should return Doctype with DTD ", dtdFound);
+ assertTrue("DoctypeWithStyles should return Docype with namespace ", schemaFound);
+ }
+
private static class MockConfigurationLoader implements ConfigurationLoader {
private final List<ConfigSource> loadedConfigSources;
diff --git a/org.eclipse.vex.ui.tests/src/org/eclipse/vex/ui/internal/config/tests/PreferencesTest.java b/org.eclipse.vex.ui.tests/src/org/eclipse/vex/ui/internal/config/tests/PreferencesTest.java
new file mode 100644
index 0000000..de9b323
--- /dev/null
+++ b/org.eclipse.vex.ui.tests/src/org/eclipse/vex/ui/internal/config/tests/PreferencesTest.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Carsten Hiesserich 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:
+ * Carsten Hiesserich - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.vex.ui.internal.config.tests;
+
+import static org.junit.Assert.assertEquals;
+
+import java.net.URL;
+
+import org.eclipse.vex.ui.internal.VexPlugin;
+import org.eclipse.vex.ui.internal.VexPreferences;
+import org.eclipse.vex.ui.internal.config.ConfigSource;
+import org.eclipse.vex.ui.internal.config.DocumentType;
+import org.eclipse.vex.ui.internal.config.Style;
+import org.junit.Test;
+
+@SuppressWarnings("restriction")
+public class PreferencesTest {
+
+ @Test
+ public void testStylesheetPreference() throws Exception {
+ final VexPreferences preferences = VexPlugin.getDefault().getPreferences();
+ final DocumentType doctype = new DocumentType(new MockConfigSource());
+ doctype.setSimpleId("vex_test_doctype");
+ final Style style = new Style(new MockConfigSource());
+ style.setSimpleId("vex-test-style");
+ preferences.setPreferredStyleId(doctype, style.getUniqueId());
+
+ final String preferredStyleId = preferences.getPreferredStyleId(doctype);
+ assertEquals(style.getUniqueId(), preferredStyleId);
+ }
+
+ private class MockConfigSource extends ConfigSource {
+
+ public MockConfigSource() {
+ super("test_config");
+ }
+
+ @Override
+ public URL getBaseUrl() {
+ return null;
+ }
+
+ }
+}
diff --git a/org.eclipse.vex.ui.tests/src/org/eclipse/vex/ui/internal/config/tests/VexDocumentContentModelTest.java b/org.eclipse.vex.ui.tests/src/org/eclipse/vex/ui/internal/config/tests/VexDocumentContentModelTest.java
new file mode 100644
index 0000000..59dafed
--- /dev/null
+++ b/org.eclipse.vex.ui.tests/src/org/eclipse/vex/ui/internal/config/tests/VexDocumentContentModelTest.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Carsten Hiesserich 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:
+ * Carsten Hiesserich - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.vex.ui.internal.config.tests;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.core.runtime.QualifiedName;
+import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.ui.internal.config.Style;
+import org.eclipse.vex.ui.internal.editor.NoStyleForDoctypeException;
+import org.eclipse.vex.ui.internal.editor.VexDocumentContentModel;
+import org.junit.Before;
+import org.junit.Test;
+
+@SuppressWarnings("restriction")
+public class VexDocumentContentModelTest {
+
+ private VexDocumentContentModel model;
+
+ @Before
+ public void setUp() throws Exception {
+ model = new VexDocumentContentModel();
+ }
+
+ @Test
+ public void resolveDoctypeByPublicId() throws Exception {
+ try {
+ model.initialize(null, "-//Vex//DTD Test//EN", null, new Element(new QualifiedName("http://org.eclipse.vex/namespace", "rootElement")));
+ } catch (final NoStyleForDoctypeException e) {
+ // We are not interested in the StyleSheet here
+ }
+ assertTrue(model.isDtdAssigned());
+ assertNotNull(model.getDocumentType());
+ assertEquals("test doctype", model.getDocumentType().getName());
+ }
+
+ @Test
+ public void resolveDoctypeBySystemId() throws Exception {
+ try {
+ model.initialize(null, "UnknownPublicId", "test.dtd", new Element(new QualifiedName("http://org.eclipse.vex/namespace", "rootElement")));
+ } catch (final NoStyleForDoctypeException e) {
+ // We are not interested in the StyleSheet here
+ }
+ assertTrue(model.isDtdAssigned());
+ assertNotNull(model.getDocumentType());
+ assertEquals("test doctype", model.getDocumentType().getName());
+ }
+
+ @Test
+ public void resolveDoctypeByNamespace() throws Exception {
+ try {
+ model.initialize(null, null, null, new Element(new QualifiedName("http://org.eclipse.vex/namespace", "rootElement")));
+ } catch (final NoStyleForDoctypeException e) {
+ // We are not interested in the StyleSheet here
+ }
+ assertFalse(model.isDtdAssigned());
+ assertNotNull(model.getDocumentType());
+ assertEquals("test schema doctype", model.getDocumentType().getName());
+ }
+
+ @Test
+ public void resolveCSSByPublicId() throws Exception {
+ model.initialize(null, "-//Vex//DTD Test//EN", null, new Element(new QualifiedName("http://org.eclipse.vex/namespace", "rootElement")));
+ assertTrue(model.isDtdAssigned());
+ final Style style = model.getStyle();
+ assertNotNull(style);
+ assertTrue(style.getResourceUri().toString().endsWith("test.css"));
+ }
+
+ @Test
+ public void resolveCSSBySystemId() throws Exception {
+ model.initialize(null, null, "test.dtd", new Element(new QualifiedName("http://org.eclipse.vex/namespace", "rootElement")));
+ assertTrue(model.isDtdAssigned());
+ final Style style = model.getStyle();
+ assertNotNull(style);
+ assertTrue(style.getResourceUri().toString().endsWith("test.css"));
+ }
+
+ @Test
+ public void resolveCSSByPluginId() throws Exception {
+ model.initialize(null, null, null, new Element(new QualifiedName("http://org.eclipse.vex/namespace2", "rootElement")));
+ final Style style = model.getStyle();
+ assertNotNull(style);
+ assertTrue(style.getResourceUri().toString().endsWith("test-doctype-id.css"));
+ }
+
+ @Test
+ public void resolveCSSByNamespace() throws Exception {
+ model.initialize(null, null, null, new Element(new QualifiedName("http://org.eclipse.vex/namespace", "rootElement")));
+ assertFalse(model.isDtdAssigned());
+ final Style style = model.getStyle();
+ assertNotNull(style);
+ assertTrue(style.getResourceUri().toString().endsWith("test-schema.css"));
+ }
+}
diff --git a/org.eclipse.vex.ui.tests/src/org/eclipse/vex/ui/tests/VexUiTestSuite.java b/org.eclipse.vex.ui.tests/src/org/eclipse/vex/ui/tests/VexUiTestSuite.java
deleted file mode 100644
index e2fd051..0000000
--- a/org.eclipse.vex.ui.tests/src/org/eclipse/vex/ui/tests/VexUiTestSuite.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2009, 2013 Holger Voormann 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:
- * Holger Voormann - initial API and implementation
- * Carsten Hiesserich - added OutlineProvider tests
- *******************************************************************************/
-package org.eclipse.vex.ui.tests;
-
-import org.eclipse.vex.ui.internal.config.tests.ConfigLoaderJobTest;
-import org.eclipse.vex.ui.internal.config.tests.ConfigurationRegistryTest;
-import org.eclipse.vex.ui.internal.editor.tests.FindReplaceTargetTest;
-import org.eclipse.vex.ui.internal.editor.tests.HandlerUtilTest;
-import org.eclipse.vex.ui.internal.namespace.tests.EditNamespacesControllerTest;
-import org.eclipse.vex.ui.internal.outline.tests.OutlineFilterTest;
-import org.eclipse.vex.ui.internal.outline.tests.OutlineProviderTest;
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
-
-@RunWith(Suite.class)
-@Suite.SuiteClasses({ ConfigLoaderJobTest.class, ConfigurationRegistryTest.class, EditNamespacesControllerTest.class, FindReplaceTargetTest.class, OutlineProviderTest.class, OutlineFilterTest.class,
- HandlerUtilTest.class })
-public class VexUiTestSuite {
-}
diff --git a/org.eclipse.vex.ui.tests/testdata/test-doctype-id.css b/org.eclipse.vex.ui.tests/testdata/test-doctype-id.css
new file mode 100644
index 0000000..9a83031
--- /dev/null
+++ b/org.eclipse.vex.ui.tests/testdata/test-doctype-id.css
@@ -0,0 +1,53 @@
+
+html {
+ display: block;
+}
+
+body {
+ display: block;
+}
+
+p {
+ display: block;
+}
+
+block {
+ display: block;
+}
+
+pre {
+ display: block;
+ white-space: pre;
+}
+
+
+/* Styles for positioning tests */
+root {
+ border: 3px 7px 11px 13px;
+ padding: 17px 19px 23px 29px;
+}
+
+small {
+ border-width: 1px 2px 3px 4px;
+ border-style: solid;
+ margin: 100px 200px 300px 400px;
+ padding: 10px 20px 30px 40px;
+ display: block;
+}
+
+medium {
+ border-width: 2px 4px 6px 8px;
+ border-style: solid;
+ margin: 200px 400px 600px 800px;
+ padding: 20px 40px 60px 80px;
+ display: block;
+}
+
+large {
+ border-width: 3px 6px 9px 12px;
+ border-style: solid;
+ margin: 300px 600px 900px 1200px;
+ padding: 30px 60px 90px 120px;
+ display: block;
+}
+
diff --git a/org.eclipse.vex.ui.tests/testdata/test-schema.css b/org.eclipse.vex.ui.tests/testdata/test-schema.css
new file mode 100644
index 0000000..9a83031
--- /dev/null
+++ b/org.eclipse.vex.ui.tests/testdata/test-schema.css
@@ -0,0 +1,53 @@
+
+html {
+ display: block;
+}
+
+body {
+ display: block;
+}
+
+p {
+ display: block;
+}
+
+block {
+ display: block;
+}
+
+pre {
+ display: block;
+ white-space: pre;
+}
+
+
+/* Styles for positioning tests */
+root {
+ border: 3px 7px 11px 13px;
+ padding: 17px 19px 23px 29px;
+}
+
+small {
+ border-width: 1px 2px 3px 4px;
+ border-style: solid;
+ margin: 100px 200px 300px 400px;
+ padding: 10px 20px 30px 40px;
+ display: block;
+}
+
+medium {
+ border-width: 2px 4px 6px 8px;
+ border-style: solid;
+ margin: 200px 400px 600px 800px;
+ padding: 20px 40px 60px 80px;
+ display: block;
+}
+
+large {
+ border-width: 3px 6px 9px 12px;
+ border-style: solid;
+ margin: 300px 600px 900px 1200px;
+ padding: 30px 60px 90px 120px;
+ display: block;
+}
+
diff --git a/org.eclipse.vex.ui/schema/doctype.exsd b/org.eclipse.vex.ui/schema/doctype.exsd
index 3846319..1d2aa3b 100644
--- a/org.eclipse.vex.ui/schema/doctype.exsd
+++ b/org.eclipse.vex.ui/schema/doctype.exsd
@@ -1,133 +1,149 @@
-<?xml version='1.0' encoding='UTF-8'?>
-<!-- Schema file written by PDE -->
-<schema targetNamespace="vex-editor" xmlns="http://www.w3.org/2001/XMLSchema">
-<annotation>
- <appinfo>
- <meta.schema plugin="vex-editor" id="doctype" name="Vex DocType"/>
- </appinfo>
- <documentation>
- Registers a new document type with Vex.
- </documentation>
- </annotation>
-
- <element name="extension">
- <annotation>
- <appinfo>
- <meta.element />
- </appinfo>
- </annotation>
- <complexType>
- <sequence>
- <element ref="doctype"/>
- </sequence>
- <attribute name="point" type="string" use="required">
- <annotation>
- <documentation>
-
- </documentation>
- </annotation>
- </attribute>
- <attribute name="id" type="string">
- <annotation>
- <documentation>
-
- </documentation>
- </annotation>
- </attribute>
- <attribute name="name" type="string">
- <annotation>
- <documentation>
-
- </documentation>
- </annotation>
- </attribute>
- </complexType>
- </element>
-
- <element name="doctype">
- <annotation>
- <appinfo>
- <meta.element labelAttribute="publicId"/>
- </appinfo>
- </annotation>
- <complexType>
- <sequence>
- <element ref="rootElement" minOccurs="0" maxOccurs="unbounded"/>
- </sequence>
- <attribute name="publicId" type="string">
- <annotation>
- <documentation>
-
- </documentation>
- </annotation>
- </attribute>
- <attribute name="systemId" type="string">
- <annotation>
- <documentation>
-
- </documentation>
- </annotation>
- </attribute>
- <attribute name="outlineProvider" type="string">
- <annotation>
- <documentation>
-
- </documentation>
- <appinfo>
- <meta.attribute kind="java" basedOn="net.sf.vex.editor.IOutlineProvider"/>
- </appinfo>
- </annotation>
- </attribute>
- </complexType>
- </element>
-
- <element name="rootElement">
- <complexType>
- <attribute name="name" type="string">
- <annotation>
- <documentation>
-
- </documentation>
- </annotation>
- </attribute>
- </complexType>
- </element>
-
- <annotation>
- <appinfo>
- <meta.section type="since"/>
- </appinfo>
- <documentation>
- [Enter the first release in which this extension point appears.]
- </documentation>
- </annotation>
-
- <annotation>
- <appinfo>
- <meta.section type="examples"/>
- </appinfo>
- <documentation>
- [Enter extension point usage example here.]
- </documentation>
- </annotation>
-
- <annotation>
- <appinfo>
- <meta.section type="apiInfo"/>
- </appinfo>
- <documentation>
- [Enter API information here.]
- </documentation>
- </annotation>
-
- <annotation>
- <appinfo>
- <meta.section type="implementation"/>
- </appinfo>
- <documentation>
- [Enter information about supplied implementation of this extension point.]
- </documentation>
- </annotation>
-
-
-</schema>
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="vex-editor" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appinfo>
+ <meta.schema plugin="vex-editor" id="doctype" name="Vex DocType"/>
+ </appinfo>
+ <documentation>
+ Registers a new document type with Vex.
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <annotation>
+ <appinfo>
+ <meta.element />
+ </appinfo>
+ </annotation>
+ <complexType>
+ <choice>
+ <element ref="doctype"/>
+ <element ref="schema"/>
+ </choice>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="doctype">
+ <annotation>
+ <appinfo>
+ <meta.element labelAttribute="publicId"/>
+ </appinfo>
+ </annotation>
+ <complexType>
+ <sequence>
+ <element ref="rootElement" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="publicId" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="systemId" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="outlineProvider" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="java" basedOn="net.sf.vex.editor.IOutlineProvider"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="rootElement">
+ <complexType>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="schema">
+ <complexType>
+ <sequence minOccurs="0" maxOccurs="unbounded">
+ <element ref="rootElement"/>
+ </sequence>
+ <attribute name="namespaceName" type="string" use="required">
+ <annotation>
+ <documentation>
+ The namespace name that is the target of the defined XML-Schema
+ </documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="apiInfo"/>
+ </appinfo>
+ <documentation>
+ [Enter API information here.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="since"/>
+ </appinfo>
+ <documentation>
+ [Enter the first release in which this extension point appears.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="examples"/>
+ </appinfo>
+ <documentation>
+ [Enter extension point usage example here.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="implementation"/>
+ </appinfo>
+ <documentation>
+ [Enter information about supplied implementation of this extension point.]
+ </documentation>
+ </annotation>
+
+
+</schema>
diff --git a/org.eclipse.vex.ui/schema/style.exsd b/org.eclipse.vex.ui/schema/style.exsd
index 26a3933..5ce16ad 100644
--- a/org.eclipse.vex.ui/schema/style.exsd
+++ b/org.eclipse.vex.ui/schema/style.exsd
@@ -1,16 +1,21 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Schema file written by PDE -->
-<schema targetNamespace="vex-editor">
+<schema targetNamespace="vex-editor" xmlns="http://www.w3.org/2001/XMLSchema">
<annotation>
- <appInfo>
+ <appinfo>
<meta.schema plugin="vex-editor" id="style" name="Vex Style"/>
- </appInfo>
+ </appinfo>
<documentation>
- Registers a new document type with Vex.
+ Registers a new CSS Stylesheet type with Vex.
</documentation>
</annotation>
<element name="extension">
+ <annotation>
+ <appinfo>
+ <meta.element />
+ </appinfo>
+ </annotation>
<complexType>
<sequence>
<element ref="style"/>
@@ -49,9 +54,9 @@
<documentation>
</documentation>
- <appInfo>
+ <appinfo>
<meta.attribute kind="resource"/>
- </appInfo>
+ </appinfo>
</annotation>
</attribute>
</complexType>
@@ -62,7 +67,7 @@
<attribute name="publicId" type="string">
<annotation>
<documentation>
-
+ The PublicID (DTD) or namespace (XML-Schema) of the referenced document type.
</documentation>
</annotation>
</attribute>
@@ -70,48 +75,40 @@
</element>
<annotation>
- <appInfo>
- <meta.section type="since"/>
- </appInfo>
- <documentation>
- [Enter the first release in which this extension point appears.]
- </documentation>
- </annotation>
-
- <annotation>
- <appInfo>
- <meta.section type="examples"/>
- </appInfo>
- <documentation>
- [Enter extension point usage example here.]
- </documentation>
- </annotation>
-
- <annotation>
- <appInfo>
+ <appinfo>
<meta.section type="apiInfo"/>
- </appInfo>
+ </appinfo>
<documentation>
[Enter API information here.]
</documentation>
</annotation>
<annotation>
- <appInfo>
+ <appinfo>
+ <meta.section type="since"/>
+ </appinfo>
+ <documentation>
+ [Enter the first release in which this extension point appears.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="examples"/>
+ </appinfo>
+ <documentation>
+ [Enter extension point usage example here.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
<meta.section type="implementation"/>
- </appInfo>
+ </appinfo>
<documentation>
[Enter information about supplied implementation of this extension point.]
</documentation>
</annotation>
- <annotation>
- <appInfo>
- <meta.section type="copyright"/>
- </appInfo>
- <documentation>
-
- </documentation>
- </annotation>
</schema>
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/VexPreferences.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/VexPreferences.java
index a7599d0..056b959 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/VexPreferences.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/VexPreferences.java
@@ -19,7 +19,9 @@
import org.eclipse.vex.core.internal.css.StyleSheet;
import org.eclipse.vex.core.provisional.dom.DocumentContentModel;
import org.eclipse.vex.ui.internal.config.ConfigurationRegistry;
+import org.eclipse.vex.ui.internal.config.DocumentType;
import org.eclipse.vex.ui.internal.config.Style;
+import org.eclipse.vex.ui.internal.editor.VexDocumentContentModel;
import org.osgi.service.prefs.BackingStoreException;
import org.osgi.service.prefs.Preferences;
@@ -49,9 +51,9 @@
this.configurationRegistry = configurationRegistry;
}
- public void setPreferredStyleId(final String publicId, final String styleId) {
+ public void setPreferredStyleId(final DocumentType doctype, final String styleId) {
final Preferences preferences = InstanceScope.INSTANCE.getNode(VexPlugin.ID);
- final String key = getStylePreferenceKey(publicId);
+ final String key = getStylePreferenceKey(doctype.getUniqueId());
preferences.put(key, styleId);
try {
preferences.flush();
@@ -60,9 +62,9 @@
}
}
- public String getPreferredStyleId(final String publicId) {
+ public String getPreferredStyleId(final DocumentType doctype) {
final Preferences preferences = InstanceScope.INSTANCE.getNode(VexPlugin.ID);
- final String preferredStyleId = preferences.get(getStylePreferenceKey(publicId), null);
+ final String preferredStyleId = preferences.get(getStylePreferenceKey(doctype.getUniqueId()), null);
return preferredStyleId;
}
@@ -70,8 +72,8 @@
return publicId + PREFERRED_STYLE_SUFFIX;
}
- public Style getPreferredStyle(final String publicId) {
- return configurationRegistry.getStyle(publicId, getPreferredStyleId(publicId));
+ public Style getPreferredStyle(final DocumentType doctype) {
+ return configurationRegistry.getStyle(doctype, getPreferredStyleId(doctype));
}
public String getIndentationPattern() {
@@ -87,7 +89,13 @@
}
public StyleSheet getStyleSheet(final DocumentContentModel documentContentModel) {
- final Style style = getPreferredStyle(documentContentModel.getMainDocumentTypeIdentifier());
+ Style style = null;
+ if (documentContentModel instanceof VexDocumentContentModel) {
+ // We only support the VexDocumentContentModel
+ // If there will ever be another DocumentContentModel implememntation, it will
+ // have to define it's own method for resolving styles
+ style = getPreferredStyle(((VexDocumentContentModel) documentContentModel).getDocumentType());
+ }
if (style == null) {
return StyleSheet.NULL;
}
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/ConfigLoaderJob.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/ConfigLoaderJob.java
index e80e087..a979bab 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/ConfigLoaderJob.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/ConfigLoaderJob.java
@@ -108,7 +108,7 @@
}
public boolean isLoading() {
- return getState() == Job.RUNNING;
+ return getState() == Job.RUNNING || getState() == Job.WAITING;
}
public void load(final Runnable whenDone) {
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/ConfigurationRegistry.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/ConfigurationRegistry.java
index ea8b278..0b73b9f 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/ConfigurationRegistry.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/ConfigurationRegistry.java
@@ -4,7 +4,7 @@
* 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:
* Florian Thienel - initial API and implementation
*******************************************************************************/
@@ -35,15 +35,17 @@
boolean isLoaded();
/**
- * The document type configuration for the given public identifier, or null if there is no configuration for the
- * given public identifier.
+ * The document type configuration for the given identifier.<br />
+ * This method tries to resolve by PublicId or namespace first. If this does not yield as result, a doctype with a
+ * matching SystemId is returned.
*
- * @param publicId
- * the public identifier
- * @return the document type configuration for the given public identifier, or null if there is no configuration for
- * the given public identifier.
+ * @param id
+ * the public/system identifier or namespace
+ * @param systemId
+ * the system id, only used when resolving the public id fails. May be null.
+ * @return the document type configuration for the identifier, or null if there is no doctype found.
*/
- DocumentType getDocumentType(final String publicId);
+ DocumentType getDocumentType(final String id, final String systemId);
/**
* @return all document type configurations
@@ -56,13 +58,18 @@
DocumentType[] getDocumentTypesWithStyles();
/**
- * All styles for the document type with the given public identifier.
+ * All styles for the given document type. The returned styles are ordered by the way they are resolved:
+ * <ul>
+ * <li>1. document type id</li>
+ * <li>2. Public ID (DTD) or Namespace (XML-Schema)</li>
+ * <li>3. System ID (DTD)</li>
+ * </ul>
*
- * @param publicId
- * the document type's public identifier
- * @return all styles for the document type with the given public identifier
+ * @param doctype
+ * the document type
+ * @return all styles for the given document type
*/
- Style[] getStyles(final String publicId);
+ Style[] getStyles(final DocumentType doctype);
/**
* The style with the given id, or null if there is no style with this id.
@@ -74,16 +81,15 @@
Style getStyle(final String styleId);
/**
- * An arbitrary style for the document type with the given public identifier. If available, the style with the given
- * style id is preferred.
+ * An arbitrary style for the given document type. If available, the style with the given style id is preferred.
*
- * @param publicId
- * the document type's public identifier
+ * @param pdoctype
+ * the document type
* @param preferredStyleId
* the preferred style's id
* @return a style for the given document type, or null if no style is configured for the given document type
*/
- Style getStyle(final String publicId, final String preferredStyleId);
+ Style getStyle(final DocumentType doctype, final String preferredStyleId);
/**
* The representation of the given plug-in project in the workspace.
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/ConfigurationRegistryImpl.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/ConfigurationRegistryImpl.java
index 2317d58..971e8cd 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/ConfigurationRegistryImpl.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/ConfigurationRegistryImpl.java
@@ -187,15 +187,22 @@
configListeners.fireEvent("configLoaded", e); //$NON-NLS-1$
}
- public DocumentType getDocumentType(final String publicId) {
+ public DocumentType getDocumentType(final String id, final String systemId) {
final List<ConfigItem> configItems = getAllConfigItems(DocumentType.EXTENSION_POINT);
+ DocumentType systemDoctype = null;
+ // Try to resolve by PublicId or namespace first
for (final ConfigItem configItem : configItems) {
final DocumentType doctype = (DocumentType) configItem;
- if (doctype.getPublicId().equals(publicId)) {
+ if (id.equals(doctype.getPublicId()) || id.equals(doctype.getNamespaceName())) {
return doctype;
}
+ if (systemId != null && systemId.equals(doctype.getSystemId())) {
+ // Save the doctype resolved by SystemID
+ systemDoctype = doctype;
+ }
}
- return null;
+
+ return systemDoctype; // May be null
}
public DocumentType[] getDocumentTypes() {
@@ -210,21 +217,40 @@
final List<DocumentType> result = new ArrayList<DocumentType>();
for (final ConfigItem configItem : getAllConfigItems(DocumentType.EXTENSION_POINT)) {
final DocumentType doctype = (DocumentType) configItem;
- if (getStyles(doctype.getPublicId()).length > 0) {
+ if (getStyles(doctype).length > 0) {
result.add(doctype);
}
}
return result.toArray(new DocumentType[result.size()]);
}
- public Style[] getStyles(final String publicId) {
- final ArrayList<Style> result = new ArrayList<Style>();
+ public Style[] getStyles(final DocumentType doctype) {
+ final ArrayList<Style> resultId = new ArrayList<Style>();
+ final ArrayList<Style> resultPublic = new ArrayList<Style>();
+ final ArrayList<Style> resultSystem = new ArrayList<Style>();
+ final ArrayList<Style> resultSchema = new ArrayList<Style>();
for (final ConfigItem configItem : getAllConfigItems(Style.EXTENSION_POINT)) {
final Style style = (Style) configItem;
- if (style.appliesTo(publicId)) {
- result.add(style);
+ if (style.appliesTo(doctype.getSimpleId())) {
+ resultId.add(style);
+ }
+ if (!doctype.isBlank(doctype.getPublicId()) && style.appliesTo(doctype.getPublicId())) {
+ resultPublic.add(style);
+ }
+ if (!doctype.isBlank(doctype.getSystemId()) && style.appliesTo(doctype.getSystemId())) {
+ resultSystem.add(style);
+ }
+ if (!doctype.isBlank(doctype.getNamespaceName()) && style.appliesTo(doctype.getNamespaceName())) {
+ resultSchema.add(style);
}
}
+
+ // The resolved stylesheet are returned in a defined order
+ final ArrayList<Style> result = new ArrayList<Style>();
+ result.addAll(resultId);
+ result.addAll(resultPublic);
+ result.addAll(resultSchema);
+ result.addAll(resultSystem);
return result.toArray(new Style[result.size()]);
}
@@ -238,8 +264,8 @@
return null;
}
- public Style getStyle(final String publicId, final String preferredStyleId) {
- final Style[] styles = getStyles(publicId);
+ public Style getStyle(final DocumentType doctype, final String preferredStyleId) {
+ final Style[] styles = getStyles(doctype);
if (styles.length == 0) {
return null;
}
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/ConfigurationView.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/ConfigurationView.java
index 65c289f..7d3bda7 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/ConfigurationView.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/ConfigurationView.java
@@ -77,7 +77,7 @@
return VexPlugin.getDefault().getConfigurationRegistry().getDocumentTypes();
}
if (parentElement instanceof DocumentType) {
- return VexPlugin.getDefault().getConfigurationRegistry().getStyles(((DocumentType) parentElement).getPublicId());
+ return VexPlugin.getDefault().getConfigurationRegistry().getStyles((DocumentType) parentElement);
}
return new Object[0];
}
@@ -87,7 +87,7 @@
return VexPlugin.getDefault().getConfigurationRegistry();
}
if (element instanceof Style) {
- return VexPlugin.getDefault().getConfigurationRegistry().getDocumentType(((Style) element).getDocumentTypes().iterator().next());
+ return VexPlugin.getDefault().getConfigurationRegistry().getDocumentType(((Style) element).getDocumentTypes().iterator().next(), null);
}
return null;
}
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/DoctypeFactory.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/DoctypeFactory.java
index bf7a2ff..4cbed14 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/DoctypeFactory.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/DoctypeFactory.java
@@ -27,9 +27,11 @@
private static final String[] EXTS = new String[] { "dtd" }; //$NON-NLS-1$
private static final String ELT_DOCTYPE = "doctype"; //$NON-NLS-1$
+ private static final String ELT_SCHEMA = "schema"; //$NON-NLS-1$
private static final String ATTR_OUTLINE_PROVIDER = "outlineProvider"; //$NON-NLS-1$
private static final String ATTR_SYSTEM_ID = "systemId"; //$NON-NLS-1$
private static final String ATTR_PUBLIC_ID = "publicId"; //$NON-NLS-1$
+ private static final String ATTR_NAMESPACE_NAME = "namespaceName"; //$NON-NLS-1$
private static final String ELT_ROOT_ELEMENT = "rootElement"; //$NON-NLS-1$
private static final String ATTR_NAME = "name"; //$NON-NLS-1$
@@ -54,13 +56,23 @@
if (configElements.length < 1) {
return null;
}
- final IConfigElement configElement = configElements[0];
- final String publicId = configElement.getAttribute(ATTR_PUBLIC_ID);
- final String systemId = configElement.getAttribute(ATTR_SYSTEM_ID);
final DocumentType doctype = new DocumentType(config);
- doctype.setPublicId(publicId);
- doctype.setSystemId(systemId);
- doctype.setResourceUri(newUri(config.resolve(publicId, systemId)));
+ final IConfigElement configElement = configElements[0];
+ if (configElement.getName() == null) {
+ System.out.println("configElement:" + configElement.getName());
+ }
+ if (configElement.getName().equals(ELT_DOCTYPE)) {
+ final String publicId = configElement.getAttribute(ATTR_PUBLIC_ID);
+ final String systemId = configElement.getAttribute(ATTR_SYSTEM_ID);
+ doctype.setPublicId(publicId);
+ doctype.setSystemId(systemId);
+ doctype.setResourceUri(newUri(config.resolve(publicId, systemId)));
+ } else {
+ final String namespaceName = configElement.getAttribute(ATTR_NAMESPACE_NAME);
+ doctype.setNamespaceName(namespaceName);
+ doctype.setResourceUri(newUri(config.resolve(null, namespaceName)));
+ }
+
doctype.setOutlineProvider(configElement.getAttribute(ATTR_OUTLINE_PROVIDER));
final IConfigElement[] rootElementRefs = configElement.getChildren();
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/DocumentType.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/DocumentType.java
index 9ec9bda..ec7df87 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/DocumentType.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/DocumentType.java
@@ -48,6 +48,30 @@
return systemId;
}
+ /**
+ * Returns the namespace name of the document type.
+ */
+ public String getNamespaceName() {
+ return namespaceName;
+ }
+
+ /**
+ * Return the main type identifier of this document type.
+ */
+ public String getMainId() {
+ if (!isBlank(publicId)) {
+ return publicId;
+ }
+ if (!isBlank(namespaceName)) {
+ return namespaceName;
+ }
+ if (!isBlank(systemId)) {
+ return systemId;
+ }
+
+ return "";
+ }
+
@Override
public String getExtensionPointId() {
return EXTENSION_POINT;
@@ -83,13 +107,24 @@
this.systemId = systemId;
}
+ /**
+ * Sets the namespace name of the document type. This is used when creating new documents but ignored otherwise.
+ *
+ * @param namespaceName
+ * new namespace name for the document type.
+ */
+ public void setNamespaceName(final String namespaceName) {
+ this.namespaceName = namespaceName;
+ }
+
public IValidator getValidator() {
return (IValidator) getConfig().getParsedResource(getResourceUri());
}
@Override
public boolean isValid() {
- return super.isValid() && !isBlank(publicId) && !isBlank(systemId) && getValidator() != null;
+ final boolean doctypeValid = !isBlank(publicId) && !isBlank(systemId) || !isBlank(namespaceName);
+ return super.isValid() && doctypeValid && getValidator() != null;
}
@Override
@@ -121,6 +156,7 @@
private String publicId;
private String systemId;
+ private String namespaceName;
private String outlineProvider;
private String[] rootElements = EMPTY_STRING_ARRAY;
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/DomConfigurationElement.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/DomConfigurationElement.java
index 64eb825..089cc0c 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/DomConfigurationElement.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/DomConfigurationElement.java
@@ -63,7 +63,7 @@
}
public String getName() {
- return element.getLocalName();
+ return element.getTagName();
}
public String getValue() {
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/StylePropertyPage.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/StylePropertyPage.java
index 9000db4..4d0be08 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/StylePropertyPage.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/config/StylePropertyPage.java
@@ -195,7 +195,7 @@
Arrays.sort(documentTypes);
for (final DocumentType documentType : documentTypes) {
if (selectedDoctypes.contains(documentType.getName())) {
- style.addDocumentType(documentType.getPublicId());
+ style.addDocumentType(documentType.getSimpleId());
}
}
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/DocumentInputReader.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/DocumentInputReader.java
new file mode 100644
index 0000000..22fa524
--- /dev/null
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/DocumentInputReader.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Carsten Hiesserich 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:
+ * Carsten Hiesserich - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.vex.ui.internal.editor;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import org.eclipse.jface.text.BadLocationException;
+
+/**
+ * This class wraps a {@link org.eclipse.jface.text.IDocument JFace Document} in an Reader. The Jface document already
+ * contains an encoded String, so we can simply return the chars here.
+ */
+public class DocumentInputReader extends Reader {
+
+ private final org.eclipse.jface.text.IDocument document;
+ private int position;
+ private final int documentLength;
+
+ public DocumentInputReader(final org.eclipse.jface.text.IDocument document) {
+ this.document = document;
+ documentLength = document.getLength();
+ position = 0;
+ }
+
+ @Override
+ public void close() throws IOException {
+ // TODO Auto-generated method stub
+
+ }
+
+ /**
+ * Reads characters into a portion of an array. This method will block until some input is available, an I/O error
+ * occurs, or the end of the stream is reached.
+ *
+ * @param cbuf
+ * - Destination buffer
+ * @param off
+ * - Offset at which to start storing characters
+ * @param length
+ * - Maximum number of characters to read
+ *
+ * @return The number of characters read, or -1 if the end of the stream has been reached
+ */
+ @Override
+ public int read(final char[] cbuf, final int off, final int length) throws IOException {
+
+ int charsRead = 0;
+ while (charsRead < length && position < documentLength) {
+ try {
+ final char c = document.getChar(position++);
+ cbuf[off + charsRead++] = c;
+ } catch (final BadLocationException e) {
+ return -1;
+ }
+ }
+
+ if (charsRead == 0) {
+ return -1;
+ }
+
+ return charsRead;
+ }
+
+}
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/DocumentTypeSelectionPage.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/DocumentTypeSelectionPage.java
index 6e6176a..a53f6fd 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/DocumentTypeSelectionPage.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/DocumentTypeSelectionPage.java
@@ -89,7 +89,7 @@
final String[] typeNames = new String[doctypes.length];
for (int i = 0; i < doctypes.length; i++) {
typeNames[i] = doctypes[i].getName();
- if (doctypes[i].getPublicId().equals(publicId)) {
+ if (doctypes[i].getMainId().equals(publicId)) {
initSelection = i;
}
}
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/VexDocumentContentModel.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/VexDocumentContentModel.java
index 648b391..3079730 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/VexDocumentContentModel.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/VexDocumentContentModel.java
@@ -35,18 +35,29 @@
this.shell = shell;
}
+ /**
+ * This constructor is only menat to be used for unit testing.
+ */
+ public VexDocumentContentModel() {
+ shell = null;
+ }
+
@Override
public void initialize(final String baseUri, final String publicId, final String systemId, final IElement rootElement) {
super.initialize(baseUri, publicId, systemId, rootElement);
final String mainDocumentTypeIdentifier = getMainDocumentTypeIdentifier();
documentType = getRegisteredDocumentType();
- if (documentType == null) {
+ if (documentType == null && shell != null) {
documentType = queryUserForDocumentType();
if (documentType == null) {
throw new NoRegisteredDoctypeException(mainDocumentTypeIdentifier, false);
}
// Reinitialize after the user selected a doctype
- super.initialize(baseUri, documentType.getPublicId(), documentType.getSystemId(), rootElement);
+ if (documentType.getNamespaceName() != null) {
+ setSchemaId(baseUri, documentType.getNamespaceName());
+ } else {
+ super.initialize(baseUri, documentType.getPublicId(), documentType.getSystemId(), null);
+ }
}
// TODO verify documentType URL???
@@ -55,15 +66,21 @@
// final String message = MessageFormat.format(Messages.getString("VexEditor.noUrlForDoctype"), mainDocumentTypeIdentifier);
// throw new RuntimeException(message);
// }
-
- style = VexPlugin.getDefault().getPreferences().getPreferredStyle(documentType.getPublicId());
+ style = VexPlugin.getDefault().getPreferences().getPreferredStyle(getDocumentType());
if (style == null) {
throw new NoStyleForDoctypeException();
}
}
private DocumentType getRegisteredDocumentType() {
- return VexPlugin.getDefault().getConfigurationRegistry().getDocumentType(getMainDocumentTypeIdentifier());
+ if (getMainDocumentTypeIdentifier() == null) {
+ return null;
+ }
+ final DocumentType doctype = VexPlugin.getDefault().getConfigurationRegistry().getDocumentType(getMainDocumentTypeIdentifier(), getSystemId());
+ if (doctype != null) {
+ return doctype;
+ }
+ return null;
}
private DocumentType queryUserForDocumentType() {
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/VexEditor.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/VexEditor.java
index 27464e8..22aa250 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/VexEditor.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/VexEditor.java
@@ -74,6 +74,7 @@
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.contexts.IContextService;
import org.eclipse.ui.dialogs.SaveAsDialog;
+import org.eclipse.ui.editors.text.IStorageDocumentProvider;
import org.eclipse.ui.ide.FileStoreEditorInput;
import org.eclipse.ui.part.EditorPart;
import org.eclipse.ui.part.FileEditorInput;
@@ -505,16 +506,6 @@
}
/**
- * Return a reasonable style for the given doctype.
- *
- * @param publicId
- * Public ID for which to return the style.
- */
- public Style getPreferredStyle(final String publicId) {
- return configurationRegistry.getStyle(publicId, preferences.getPreferredStyleId(publicId));
- }
-
- /**
* Returns the DocumentType associated with this editor.
*/
public DocumentType getDocumentType() {
@@ -742,8 +733,20 @@
}
}
+ String encoding;
+ if (provider instanceof IStorageDocumentProvider) {
+ // Try to get the encoding from the DocumentProvider
+ encoding = ((IStorageDocumentProvider) provider).getEncoding(getEditorInput());
+ } else {
+ encoding = "UTF-8";
+ }
+
+ // A Reader is used here to avoid an in memory copy of the documents content
+ final InputSource is = new InputSource(new DocumentInputReader(jFaceDoc));
+ is.setEncoding(encoding);
+
+ // Set the systemId of the InputSource to resolve relative URIs
final IEditorInput input = getEditorInput();
- final InputSource is = new InputSource(jFaceDoc.get());
if (input instanceof IFileEditorInput) {
final IFile file = ((IFileEditorInput) input).getFile();
is.setSystemId(file.getLocationURI().toString());
@@ -864,7 +867,7 @@
this.style = style;
if (vexWidget != null) {
vexWidget.setStyleSheet(style.getStyleSheet());
- preferences.setPreferredStyleId(document.getPublicID(), style.getUniqueId());
+ preferences.setPreferredStyleId(doctype, style.getUniqueId());
}
vexEditorListeners.fireEvent("styleChanged", new VexEditorEvent(this)); //$NON-NLS-1$
}
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/StyleMenu.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/StyleMenu.java
index ffe13fc..098c2f6 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/StyleMenu.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/StyleMenu.java
@@ -20,6 +20,7 @@
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.vex.ui.internal.VexPlugin;
+import org.eclipse.vex.ui.internal.config.DocumentType;
import org.eclipse.vex.ui.internal.config.Style;
import org.eclipse.vex.ui.internal.editor.VexEditor;
@@ -37,8 +38,8 @@
return;
}
- final String publicId = editor.getDocumentType().getPublicId();
- for (final Style style : VexPlugin.getDefault().getConfigurationRegistry().getStyles(publicId)) {
+ final DocumentType doctype = editor.getDocumentType();
+ for (final Style style : VexPlugin.getDefault().getConfigurationRegistry().getStyles(doctype)) {
final MenuItem menuItem = new MenuItem(menu, SWT.RADIO, index);
menuItem.setText(style.getName());
menuItem.setSelection(style == editor.getStyle());
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/wizards/NewDocumentWizard.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/wizards/NewDocumentWizard.java
index 5b8eea8..2c9fc14 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/wizards/NewDocumentWizard.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/wizards/NewDocumentWizard.java
@@ -74,7 +74,7 @@
try {
final IDocument doc = createDocument(typePage.getDocumentType(), typePage.getRootElementName());
- final Style style = VexPlugin.getDefault().getPreferences().getPreferredStyle(typePage.getDocumentType().getPublicId());
+ final Style style = VexPlugin.getDefault().getPreferences().getPreferredStyle(typePage.getDocumentType());
if (style == null) {
MessageDialog.openError(getShell(), Messages.getString("NewDocumentWizard.noStyles.title"), Messages.getString("NewDocumentWizard.noStyles.message")); //$NON-NLS-1$ //$NON-NLS-2$
return false;
@@ -136,7 +136,7 @@
}
private static IDocument createDocumentWithSchema(final DocumentType documentType, final String rootElementName) {
- final String defaultNamespaceUri = documentType.getPublicId();
+ final String defaultNamespaceUri = documentType.getNamespaceName();
final Document document = new Document(new QualifiedName(defaultNamespaceUri, rootElementName));
final IElement root = document.getRootElement();
diff --git a/org.eclipse.vex.xhtml/styles/xhtml1-plain.css b/org.eclipse.vex.xhtml/styles/xhtml1-plain.css
index 43f820c..d1a71e6 100644
--- a/org.eclipse.vex.xhtml/styles/xhtml1-plain.css
+++ b/org.eclipse.vex.xhtml/styles/xhtml1-plain.css
@@ -1,4 +1,5 @@
a {
+ display: inline;
border-bottom: 1px solid;
color: blue;
}
@@ -19,7 +20,8 @@
/* TODO */
}
-b {
+b {
+ display: inline;
font-weight: bold;
}
@@ -109,6 +111,7 @@
}
em {
+ display: inline;
font-style: italic;
}
@@ -119,7 +122,7 @@
form {
/* TODO */
}
-
+
h1 {
display: block;
font-size: 2em;
@@ -184,6 +187,7 @@
}
i {
+ display: inline;
font-style: italic;
}
@@ -326,6 +330,7 @@
}
small {
+ display: inline;
font-size: 80%;
}
@@ -334,6 +339,7 @@
}
strong {
+ display: inline;
font-weight: bold;
}
@@ -402,6 +408,7 @@
}
tt {
+ display: inline;
font: 12px "Courier New", sans-serif;
}