Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/css/CssTest.java12
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/css/RuleTest.java29
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/BasicNodeTest.java38
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/ContentTest.java231
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/CopyVisitorTest.java73
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DTDValidatorTest.java25
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DeepCopyTest.java236
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentContentModelTest.java8
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentFragmentTest.java97
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentReaderTest.java6
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentTest.java102
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DummyValidator.java53
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/GapContentTest.java110
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/L1CommentHandlingTest.java86
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/L1ElementHandlingTest.java87
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/L1TextHandlingTest.java90
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/NamespaceTest.java12
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/NodeTest.java178
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/NodeTraversalTest.java79
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/ParentTest.java542
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/RangeTest.java87
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/SchemaValidatorTest.java20
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/LayoutTestSuite.java16
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TableLayoutTest.java8
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TestBlockElementBox.java11
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TestBlocksInInlines.java8
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TestDocumentTextBox.java11
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TestStaticTextBox.java6
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/widget/VexWidgetTest.java36
-rw-r--r--org.eclipse.vex.core.tests/src/org/eclipse/vex/core/tests/VEXCoreTestSuite.java22
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/BackgroundImageProperty.java19
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/BorderSpacingProperty.java4
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/BorderStyleProperty.java4
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/BorderWidthProperty.java4
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/ColorProperty.java4
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/DisplayProperty.java4
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/FontFamilyProperty.java4
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/FontSizeProperty.java4
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/FontStyleProperty.java4
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/FontVariantProperty.java4
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/FontWeightProperty.java4
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/IProperty.java8
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/LengthProperty.java11
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/LineHeightProperty.java4
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/ListStyleTypeProperty.java4
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/Rule.java91
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/StyleSheet.java58
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/TextAlignProperty.java4
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/TextDecorationProperty.java4
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/WhiteSpaceProperty.java4
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/BaseNodeVisitor.java40
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/BaseNodeVisitorWithResult.java52
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Comment.java50
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Content.java108
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/CopyVisitor.java54
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DeepCopy.java94
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DeepCopyVisitor.java92
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Document.java818
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentBuilder.java39
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentContentModel.java4
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentFragment.java180
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentWriter.java34
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Element.java143
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/GapContent.java228
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/INodeVisitor.java (renamed from org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/CommentElement.java)25
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/INodeVisitorWithResult.java32
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/IWhitespacePolicy.java8
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Node.java214
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/NodeTraversal.java62
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Parent.java225
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Position.java19
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Range.java98
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/RootElement.java41
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Text.java29
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/AbstractBlockBox.java76
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/AbstractBox.java26
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/BlockElementBox.java105
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/BlockPseudoElementBox.java5
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/Box.java4
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/BoxFactory.java8
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/CommentBlockElementBox.java18
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/CompositeInlineBox.java2
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/CssBoxFactory.java16
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/DocumentTextBox.java47
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/DrawableBox.java32
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/ElementOrRangeCallback.java3
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/ImageBox.java16
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/InlineElementBox.java162
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/LayoutContext.java12
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/LayoutUtils.java33
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/LineBox.java18
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/ParagraphBox.java11
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/PlaceholderBox.java24
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/RootBox.java4
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/StaticTextBox.java28
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/TableBodyBox.java9
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/TableBox.java18
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/TableRowBox.java7
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/TableRowGroupBox.java14
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/TextBox.java28
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/validator/WTPVEXValidator.java5
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/CssWhitespacePolicy.java10
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/IVexWidget.java8
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/VexWidgetImpl.java86
-rw-r--r--org.eclipse.vex.docbook/src/org/eclipse/vex/docbook/DocBookOutlineProvider.java6
-rw-r--r--org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/VexDocumentContentModel.java4
-rw-r--r--org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/VexEditor.java17
-rw-r--r--org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/AbstractAddColumnHandler.java4
-rw-r--r--org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/AbstractAddRowHandler.java6
-rw-r--r--org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/AddCommentHandler.java3
-rw-r--r--org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/MoveSelectionUpHandler.java12
-rw-r--r--org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/SplitBlockElementHandler.java22
-rw-r--r--org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/SplitItemHandler.java8
-rw-r--r--org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/VexHandlerUtil.java32
-rw-r--r--org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/outline/DefaultOutlineProvider.java2
-rw-r--r--org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/swt/ContentAssist.java2
-rw-r--r--org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/swt/DocumentFragmentTransfer.java133
-rw-r--r--org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/swt/VexWidget.java12
-rw-r--r--org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/wizards/NewDocumentWizard.java6
-rw-r--r--org.eclipse.vex.xhtml/src/org/eclipse/vex/xhtml/XhtmlOutlineProvider.java6
120 files changed, 4716 insertions, 1649 deletions
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 b483199d..367e40cc 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
@@ -15,11 +15,11 @@ import static org.junit.Assert.assertNull;
import java.net.URL;
+import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.vex.core.internal.core.Color;
import org.eclipse.vex.core.internal.core.DisplayDevice;
import org.eclipse.vex.core.internal.dom.Document;
import org.eclipse.vex.core.internal.dom.Element;
-import org.eclipse.vex.core.internal.dom.RootElement;
import org.junit.Before;
import org.junit.Test;
@@ -168,10 +168,9 @@ public class CssTest {
@Test
public void testDefaultInheritance() throws Exception {
- final RootElement simple = new RootElement("simple");
- final Element defaults = new Element("defaults");
+ final Element simple = new Element("simple");
final Document doc = new Document(simple);
- doc.insertElement(1, defaults);
+ final Element defaults = doc.insertElement(1, new QualifiedName(null, "defaults"));
final StyleSheet ss = parseStyleSheetResource("test2.css");
final Styles styles = ss.getStyles(defaults);
@@ -431,10 +430,9 @@ public class CssTest {
@Test
public void testForcedInheritance() throws Exception {
- final RootElement simple = new RootElement("simple");
- final Element inherit = new Element("inherit");
+ final Element simple = new Element("simple");
final Document doc = new Document(simple);
- doc.insertElement(1, inherit);
+ final Element inherit = doc.insertElement(1, new QualifiedName(null, "inherit"));
final StyleSheet ss = parseStyleSheetResource("test2.css");
final Styles styles = ss.getStyles(inherit);
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/css/RuleTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/css/RuleTest.java
index 40ff84e2..54ff2756 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/css/RuleTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/css/RuleTest.java
@@ -18,7 +18,6 @@ import junit.framework.TestCase;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.vex.core.internal.dom.Document;
import org.eclipse.vex.core.internal.dom.Element;
-import org.eclipse.vex.core.internal.dom.RootElement;
/**
* Test rule matching.
@@ -31,12 +30,13 @@ public class RuleTest extends TestCase {
final StyleSheet ss = reader.read(url);
final List<Rule> rules = ss.getRules();
- final RootElement a = new RootElement("a");
- final Element b = new Element("b");
- final Element c = new Element("c");
- final Element d = new Element("d");
- final Element e = new Element("e");
- final Element f = new Element("f");
+ final Element a = new Element("a");
+ final Document doc = new Document(a);
+ final Element b = doc.insertElement(1, new QualifiedName(null, "b"));
+ final Element c = doc.insertElement(2, new QualifiedName(null, "c"));
+ final Element d = doc.insertElement(3, new QualifiedName(null, "d"));
+ final Element e = doc.insertElement(4, new QualifiedName(null, "e"));
+ final Element f = doc.insertElement(5, new QualifiedName(null, "f"));
b.setAttribute("color", "blue");
c.setAttribute("color", "blue red");
@@ -44,13 +44,6 @@ public class RuleTest extends TestCase {
e.setAttribute("color", "red blue");
f.setAttribute("color", "bluered");
- final Document doc = new Document(a);
- doc.insertElement(1, b);
- doc.insertElement(2, c);
- doc.insertElement(3, d);
- doc.insertElement(4, e);
- doc.insertElement(5, f);
-
// /* 0 */ c { }
Rule rule = rules.get(0);
assertFalse(rule.matches(a));
@@ -273,14 +266,12 @@ public class RuleTest extends TestCase {
final StyleSheet ss = reader.read(url);
final List<Rule> rules = ss.getRules();
- final RootElement a = new RootElement("a");
- final Element ns = new Element(new QualifiedName("http://namespace/uri", "b"));
+ final Element a = new Element("a");
+ final Document doc = new Document(a);
+ final Element ns = doc.insertElement(1, new QualifiedName("http://namespace/uri", "b"));
ns.setAttribute("color", "blue");
- final Document doc = new Document(a);
- doc.insertElement(1, ns);
-
// /* 0 */ c { }
Rule rule = rules.get(0);
assertFalse(rule.matches(a));
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/BasicNodeTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/BasicNodeTest.java
new file mode 100644
index 00000000..ba108c5f
--- /dev/null
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/BasicNodeTest.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2012 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.dom;
+
+/**
+ * @author Florian Thienel
+ */
+public class BasicNodeTest extends NodeTest {
+
+ @Override
+ protected Node createNode() {
+ return new Node() {
+ @Override
+ public String getBaseURI() {
+ return null;
+ }
+
+ @Override
+ public void accept(final INodeVisitor visitor) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T> T accept(final INodeVisitorWithResult<T> visitor) {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/ContentTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/ContentTest.java
new file mode 100644
index 00000000..22ff845f
--- /dev/null
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/ContentTest.java
@@ -0,0 +1,231 @@
+/*******************************************************************************
+ * Copyright (c) 2012 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.dom;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public abstract class ContentTest {
+
+ private Content content;
+
+ @Before
+ public void setUp() throws Exception {
+ content = createContent();
+ }
+
+ protected abstract Content createContent();
+
+ @Test
+ public void insertText() throws Exception {
+ final String text = "Hello World";
+
+ assertEquals(0, content.length());
+ content.insertText(0, text);
+ assertEquals(text.length(), content.length());
+ }
+
+ @Test
+ public void insertElementMarker() throws Exception {
+ content.insertElementMarker(0);
+ assertEquals(1, content.length());
+ assertTrue(content.isElementMarker(0));
+ }
+
+ @Test
+ public void mixTextWithElementMarkers() throws Exception {
+ final String text = "Hello World";
+ content.insertText(0, text);
+ content.insertElementMarker(5);
+ assertEquals("Each element marker should count 1 in the length calculation.", text.length() + 1, content.length());
+ }
+
+ @Test
+ public void shouldReturnPlainTextWithoutElementMarkers() throws Exception {
+ final String text = "Hello World";
+ content.insertText(0, text);
+ content.insertElementMarker(5);
+ assertEquals(text, content.getText());
+ }
+
+ @Test
+ public void shouldReturnAPartialCopy() throws Exception {
+ final String text = "Hello World";
+ content.insertText(0, text);
+ final Content partialCopy = content.getContent(new Range(3, 7));
+ assertEquals("lo Wo", partialCopy.getText());
+
+ // make shure, it is a copy
+ content.insertText(6, "New ");
+ assertEquals("Hello New World", content.getText());
+ assertEquals("lo Wo", partialCopy.getText());
+ }
+
+ @Test
+ public void shouldReturnAFullCopy() throws Exception {
+ final String text = "Hello World";
+ content.insertText(0, text);
+ final Content fullCopy = content.getContent();
+ assertEquals(text, fullCopy.getText());
+
+ // make shure, it is a copy
+ content.insertText(6, "New ");
+ assertEquals("Hello New World", content.getText());
+ assertEquals(text, fullCopy.getText());
+ }
+
+ @Test
+ public void insertContent() throws Exception {
+ content.insertText(0, "Hello World");
+ final Content other = createContent();
+ other.insertElementMarker(0);
+ other.insertText(1, "New");
+ other.insertElementMarker(4);
+
+ content.insertContent(6, other);
+ assertEquals(16, content.length());
+ assertEquals("Hello NewWorld", content.getText());
+ assertTrue(content.isElementMarker(6));
+ assertTrue(content.isElementMarker(10));
+ }
+
+ @Test
+ public void removeAndInsertContent() throws Exception {
+ content.insertText(0, "Hello Cut Out World");
+ content.insertElementMarker(6);
+ content.insertElementMarker(14);
+
+ content.remove(new Range(7, 13));
+ assertTrue(content.isElementMarker(6));
+ assertTrue(content.isElementMarker(7));
+
+ content.remove(new Range(6, 7));
+ assertEquals("Hello World", content.getText());
+
+ content.insertText(6, "Cut Out");
+ assertEquals("Hello Cut Out World", content.getText());
+ }
+
+ @Test
+ public void shouldIncreasePositionsOnInsertText() throws Exception {
+ content.insertText(0, "Hello World");
+ final Position helloPosition = content.createPosition(0);
+ final Position worldPosition = content.createPosition(6);
+ assertEquals("Hello", content.getText(new Range(helloPosition.getOffset(), helloPosition.getOffset() + 4)));
+ assertEquals("World", content.getText(new Range(worldPosition.getOffset(), worldPosition.getOffset() + 4)));
+
+ content.insertText(6, "New ");
+ assertEquals(0, helloPosition.getOffset());
+ assertEquals(10, worldPosition.getOffset());
+ assertEquals("Hello", content.getText(new Range(helloPosition.getOffset(), helloPosition.getOffset() + 4)));
+ assertEquals("World", content.getText(new Range(worldPosition.getOffset(), worldPosition.getOffset() + 4)));
+ }
+
+ @Test
+ public void shouldIncreasePositionsOnInsertElementMarker() throws Exception {
+ content.insertText(0, "Hello World");
+ final Position worldStartPosition = content.createPosition(6);
+ final Position worldEndPosition = content.createPosition(10);
+ assertEquals("d", content.getText(new Range(worldEndPosition.getOffset(), worldEndPosition.getOffset())));
+ assertEquals("World", content.getText(new Range(worldStartPosition.getOffset(), worldEndPosition.getOffset())));
+
+ content.insertElementMarker(11);
+ content.insertElementMarker(6);
+ assertEquals(7, worldStartPosition.getOffset());
+ assertEquals(11, worldEndPosition.getOffset());
+ assertEquals("d", content.getText(new Range(worldEndPosition.getOffset(), worldEndPosition.getOffset())));
+ assertEquals("World", content.getText(new Range(worldStartPosition.getOffset(), worldEndPosition.getOffset())));
+ assertTrue(content.isElementMarker(worldStartPosition.getOffset() - 1));
+ assertTrue(content.isElementMarker(worldEndPosition.getOffset() + 1));
+ }
+
+ @Test
+ public void shouldDecreasePositionOnRemove() throws Exception {
+ content.insertText(0, "Hello New World");
+ content.insertElementMarker(8);
+ content.insertElementMarker(6);
+ final Position worldStartPosition = content.createPosition(12);
+ final Position worldEndPosition = content.createPosition(16);
+ assertEquals("d", content.getText(new Range(worldEndPosition.getOffset(), worldEndPosition.getOffset())));
+ assertEquals("World", content.getText(new Range(worldStartPosition.getOffset(), worldEndPosition.getOffset())));
+
+ content.remove(new Range(6, 11));
+ assertEquals("d", content.getText(new Range(worldEndPosition.getOffset(), worldEndPosition.getOffset())));
+ assertEquals("World", content.getText(new Range(worldStartPosition.getOffset(), worldEndPosition.getOffset())));
+ assertEquals(6, worldStartPosition.getOffset());
+ assertEquals(10, worldEndPosition.getOffset());
+ }
+
+ @Test
+ public void shouldMovePositionsWithinRemovedRangeToRangeStart() throws Exception {
+ content.insertText(0, "Hello New World");
+ final Position nPosition = content.createPosition(6);
+ final Position ePosition = content.createPosition(7);
+ final Position wPosition = content.createPosition(8);
+
+ content.remove(new Range(6, 8));
+
+ assertEquals(6, nPosition.getOffset());
+ assertEquals(6, ePosition.getOffset());
+ assertEquals(6, wPosition.getOffset());
+ }
+
+ @Test
+ public void canRemovePosition() throws Exception {
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ final Position position = content.createPosition(1);
+ assertEquals(1, position.getOffset());
+
+ content.removePosition(position);
+ content.insertText(1, "Hello");
+ assertEquals(1, position.getOffset());
+ }
+
+ @Test
+ public void invalidatesPositionsOnRemoval() throws Exception {
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ final Position position = content.createPosition(1);
+ assertTrue(position.isValid());
+ content.removePosition(position);
+ assertFalse(position.isValid());
+ }
+
+ @Test
+ public void rawTextContainsElementMarkers() throws Exception {
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertText(1, "Hello World");
+ content.insertElementMarker(6);
+
+ assertFalse(content.getText().equals(content.getRawText()));
+ assertEquals(content.getText().length() + 3, content.getRawText().length());
+ assertFalse(content.getText().charAt(0) == content.getRawText().charAt(0));
+ assertEquals(content.getText(new Range(1, 5)), content.getRawText(new Range(1, 5)));
+ assertEquals(content.getText().substring(0, 5), content.getRawText(new Range(1, 5)));
+ }
+
+ @Test
+ public void shouldReturnCharacterAtOffset() throws Exception {
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertText(1, "Hello World");
+
+ for (int i = 0; i < content.length(); i++) {
+ assertEquals(content.getRawText().charAt(i), content.charAt(i));
+ }
+ }
+}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/CopyVisitorTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/CopyVisitorTest.java
new file mode 100644
index 00000000..7237f9d9
--- /dev/null
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/CopyVisitorTest.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2012 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.dom;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.util.Collections;
+
+import org.eclipse.core.runtime.QualifiedName;
+import org.junit.Test;
+
+/**
+ * @author Florian Thienel
+ */
+public class CopyVisitorTest {
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void shouldNotCopyDocument() throws Exception {
+ final Document document = new Document(new Element("root"));
+
+ final CopyVisitor copyVisitor = new CopyVisitor();
+ document.accept(copyVisitor);
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void shouldNotCopyDocumentFragment() throws Exception {
+ final GapContent content = new GapContent(1);
+ content.insertText(0, "abc");
+ final DocumentFragment documentFragment = new DocumentFragment(content, Collections.<Node> emptyList());
+
+ final CopyVisitor copyVisitor = new CopyVisitor();
+ documentFragment.accept(copyVisitor);
+ }
+
+ @Test
+ public void givenAnElement_shouldCopyNameAndAttributesAndNamespaceDeclaration() throws Exception {
+ final Element element = new Element("element");
+ element.setAttribute("attribute1", "value1");
+ element.setAttribute("attribute2", "value2");
+ element.declareDefaultNamespace("defaultNamespaceUri");
+ element.declareNamespace("ns1", "additionalNamespaceUri1");
+ element.declareNamespace("ns2", "additionalNamespaceUri2");
+
+ final Element copy = (Element) element.accept(new CopyVisitor());
+
+ assertEquals(new QualifiedName(null, "element"), copy.getQualifiedName());
+ assertEquals(2, copy.getAttributes().size());
+ assertEquals("value1", copy.getAttributeValue(new QualifiedName(null, "attribute1")));
+ assertEquals("value2", copy.getAttributeValue(new QualifiedName(null, "attribute2")));
+ assertEquals("defaultNamespaceUri", copy.getDeclaredDefaultNamespaceURI());
+ assertEquals(2, copy.getNamespacePrefixes().size());
+ assertEquals("ns1", copy.getNamespacePrefix("additionalNamespaceUri1"));
+ assertEquals("ns2", copy.getNamespacePrefix("additionalNamespaceUri2"));
+ }
+
+ @Test
+ public void shouldIgnoreText() throws Exception {
+ final Text text = new Text(null, new GapContent(1), new Range(0, 0));
+
+ final CopyVisitor copyVisitor = new CopyVisitor();
+
+ assertNull(text.accept(copyVisitor));
+ }
+}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DTDValidatorTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DTDValidatorTest.java
index d86f22cb..68101ca7 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DTDValidatorTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DTDValidatorTest.java
@@ -39,7 +39,7 @@ public class DTDValidatorTest extends TestCase {
}
public void testAttributeDefinition() throws Exception {
- final Document doc = new Document(new RootElement("section"));
+ final Document doc = new Document(new Element("section"));
doc.setValidator(validator);
final Element sectionElement = doc.getRootElement();
final AttributeDefinition.Type adType = validator.getAttributeDefinitions(sectionElement).get(0).getType();
@@ -49,7 +49,7 @@ public class DTDValidatorTest extends TestCase {
}
public void testEnumAttribute() throws Exception {
- final Document doc = new Document(new RootElement("section"));
+ final Document doc = new Document(new Element("section"));
doc.setValidator(validator);
final Element sectionElement = doc.getRootElement();
final AttributeDefinition attributeDefinition = validator.getAttributeDefinitions(sectionElement).get(0);
@@ -89,12 +89,13 @@ public class DTDValidatorTest extends TestCase {
public void testSectionElement() {
// <section> <title> a b </title> <para> </para> </section>
// 1 2 3 4 5 6 7
- final Document doc = new Document(new RootElement("section"));
+ final Document doc = new Document(new Element("section"));
doc.setValidator(validator);
- doc.insertElement(1, new Element("title"));
+ doc.insertElement(1, new QualifiedName(null, "title"));
doc.insertText(2, "ab");
- doc.insertElement(5, new Element("para"));
+ doc.insertElement(5, new QualifiedName(null, "para"));
+ assertValidItemsAt(doc, 0);
assertValidItemsAt(doc, 1, "title", "para");
assertValidItemsAt(doc, 2);
assertValidItemsAt(doc, 3);
@@ -105,7 +106,7 @@ public class DTDValidatorTest extends TestCase {
}
public void testOneKindOfChild() {
- final Document doc = new Document(new RootElement("one-kind-of-child"));
+ final Document doc = new Document(new Element("one-kind-of-child"));
doc.setValidator(validator);
assertValidItemsAt(doc, 1, "section");
}
@@ -116,7 +117,11 @@ public class DTDValidatorTest extends TestCase {
expected.add(new QualifiedName(null, expectedItem));
}
- final Set<QualifiedName> validItems = doc.getValidator().getValidItems(doc.getElementAt(offset));
+ Element element = doc.getElementAt(offset);
+ if (offset == element.getStartOffset()) {
+ element = element.getParentElement();
+ }
+ final Set<QualifiedName> validItems = doc.getValidator().getValidItems(element);
assertEquals(expected, validItems);
}
@@ -150,11 +155,11 @@ public class DTDValidatorTest extends TestCase {
}
public void testValidateDocumentWithDTDAndNamespaces() throws Exception {
- final Document doc = new Document(new RootElement(new QualifiedName("http://namespace/uri/is/not/registered", "section")));
+ final Document doc = new Document(new Element(new QualifiedName("http://namespace/uri/is/not/registered", "section")));
doc.setValidator(validator);
- doc.insertElement(1, new Element("title"));
+ doc.insertElement(1, new QualifiedName(null, "title"));
doc.insertText(2, "ab");
- doc.insertElement(5, new Element("para"));
+ doc.insertElement(5, new QualifiedName(null, "para"));
validator.getAttributeDefinitions(doc.getRootElement());
}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DeepCopyTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DeepCopyTest.java
new file mode 100644
index 00000000..768c536e
--- /dev/null
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DeepCopyTest.java
@@ -0,0 +1,236 @@
+/*******************************************************************************
+ * Copyright (c) 2012 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.dom;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.junit.Test;
+
+/**
+ * @author Florian Thienel
+ */
+public class DeepCopyTest {
+
+ @Test
+ public void givenOneElement_shouldCopyElement() throws Exception {
+ final Element element = new Element("element");
+
+ final DeepCopy deepCopy = new DeepCopy(element);
+ final List<Node> copiedNodes = deepCopy.getNodes();
+
+ assertEquals(1, copiedNodes.size());
+ assertTrue("copy should be of same type: " + copiedNodes.get(0), copiedNodes.get(0) instanceof Element);
+ assertNotSame(element, copiedNodes.get(0));
+ }
+
+ @Test
+ public void givenOneElementWithContent_shouldCopyAssociatedContent() throws Exception {
+ final GapContent content = new GapContent(10);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ final Element element = new Element("element");
+ element.associate(content, new Range(0, 1));
+ content.insertText(1, "Hello World");
+
+ final DeepCopy deepCopy = new DeepCopy(element);
+ final Content copiedContent = deepCopy.getContent();
+
+ assertNotNull(copiedContent);
+ assertNotSame(content, copiedContent);
+ assertEquals(content.length(), copiedContent.length());
+ assertEquals(content.getRawText(), copiedContent.getRawText());
+ }
+
+ @Test
+ public void givenOneElementWithHugeContent_shouldOnlyCopyRelevantContent() throws Exception {
+ final GapContent content = new GapContent(10);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ final Element element = new Element("element");
+ element.associate(content, new Range(0, 1));
+ content.insertText(2, "World");
+ content.insertText(1, " New ");
+ content.insertText(0, "Hello");
+
+ final DeepCopy deepCopy = new DeepCopy(element);
+ final Content copiedContent = deepCopy.getContent();
+
+ assertEquals(7, copiedContent.length());
+ assertEquals(" New ", copiedContent.getText());
+ }
+
+ @Test
+ public void givenOneElementWithHugeContent_shouldAssociateCopiedElementWithCopiedContent() throws Exception {
+ final GapContent content = new GapContent(10);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ final Element element = new Element("element");
+ element.associate(content, new Range(0, 1));
+ content.insertText(2, "World");
+ content.insertText(1, " New ");
+ content.insertText(0, "Hello");
+
+ final DeepCopy deepCopy = new DeepCopy(element);
+ final Element copiedElement = (Element) deepCopy.getNodes().get(0);
+
+ assertTrue(copiedElement.isAssociated());
+ assertEquals(element.getText(), copiedElement.getText());
+ }
+
+ @Test
+ public void givenOneParentWithTwoChildren_shouldCopyParentAndChildren() throws Exception {
+ final Element parent = new Element("parent");
+ final Element child1 = new Element("child");
+ child1.setAttribute("order", "1");
+ parent.addChild(child1);
+ final Element child2 = new Element("child");
+ child2.setAttribute("order", "2");
+ parent.addChild(child2);
+
+ final DeepCopy deepCopy = new DeepCopy(parent);
+ final Element copiedParent = (Element) deepCopy.getNodes().get(0);
+ final List<Node> copiedChildNodes = copiedParent.getChildNodes();
+
+ assertEquals(2, copiedChildNodes.size());
+ assertEquals("1", ((Element) copiedChildNodes.get(0)).getAttribute("order").getValue());
+ assertEquals("2", ((Element) copiedChildNodes.get(1)).getAttribute("order").getValue());
+ }
+
+ @Test
+ public void givenOneParentWithTwoChildrenAndContent_shouldCopyParentChildrenAndContent() throws Exception {
+ final Content content = new GapContent(10);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ final Element parent = new Element("parent");
+ parent.associate(content, content.getRange());
+ final Element child1 = new Element("child");
+ child1.associate(content, new Range(1, 2));
+ parent.addChild(child1);
+ final Element child2 = new Element("child");
+ child2.associate(content, new Range(3, 4));
+ parent.addChild(child2);
+ content.insertText(child1.getEndOffset(), "Hello");
+ content.insertText(child2.getStartOffset(), " New ");
+ content.insertText(child2.getEndOffset(), "World");
+
+ final DeepCopy deepCopy = new DeepCopy(parent);
+ final Element copiedParent = (Element) deepCopy.getNodes().get(0);
+ final List<Node> copiedChildNodes = copiedParent.getChildNodes();
+
+ assertEquals(3, copiedChildNodes.size());
+ assertTrue(copiedChildNodes.get(0).isAssociated());
+ assertTrue(copiedChildNodes.get(0) instanceof Element);
+ assertEquals("Hello", copiedChildNodes.get(0).getText());
+ assertTrue(copiedChildNodes.get(1).isAssociated());
+ assertTrue(copiedChildNodes.get(1) instanceof Text);
+ assertEquals(" New ", copiedChildNodes.get(1).getText());
+ assertTrue(copiedChildNodes.get(2).isAssociated());
+ assertTrue(copiedChildNodes.get(2) instanceof Element);
+ assertEquals("World", copiedChildNodes.get(2).getText());
+ }
+
+ @Test
+ public void givenOneParentWithTwoChildrenInHugeContent_shouldCopyOnlyRelevantContent() throws Exception {
+ final Content content = new GapContent(10);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ final Element parent = new Element("parent");
+ parent.associate(content, content.getRange());
+ final Element child1 = new Element("child");
+ child1.associate(content, new Range(1, 2));
+ parent.addChild(child1);
+ final Element child2 = new Element("child");
+ child2.associate(content, new Range(3, 4));
+ parent.addChild(child2);
+ content.insertText(parent.getStartOffset(), "Prefix Content");
+ content.insertText(child1.getEndOffset(), "Hello");
+ content.insertText(child2.getStartOffset(), " New ");
+ content.insertText(child2.getEndOffset(), "World");
+ content.insertText(parent.getEndOffset() + 1, "Suffix Content");
+
+ final DeepCopy deepCopy = new DeepCopy(parent);
+
+ assertEquals(21, deepCopy.getContent().length());
+ }
+
+ @Test
+ public void givenOneParentWithTwoChildrenAndContent_whenGivenRange_shouldOnlyCopyChildrenAndContentWithinRange() throws Exception {
+ final Content content = new GapContent(10);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ final Element parent = new Element("parent");
+ parent.associate(content, content.getRange());
+ final Element child1 = new Element("child");
+ child1.associate(content, new Range(1, 2));
+ parent.addChild(child1);
+ final Element child2 = new Element("child");
+ child2.associate(content, new Range(3, 4));
+ parent.addChild(child2);
+ content.insertText(child1.getStartOffset(), "Prefix Content");
+ content.insertText(child1.getEndOffset(), "Hello");
+ content.insertText(child2.getStartOffset(), " New ");
+ content.insertText(child2.getEndOffset(), "World");
+ content.insertText(parent.getEndOffset(), "Suffix Content");
+
+ final DeepCopy deepCopy = new DeepCopy(parent, new Range(8, 39));
+
+ assertEquals(32, deepCopy.getContent().length());
+ assertEquals("Content\0Hello\0 New \0World\0Suffix", deepCopy.getContent().getRawText());
+ assertEquals(2, deepCopy.getNodes().size());
+ }
+
+ @Test
+ public void givenOneParentWithTwoCommentChildren_shouldCopyParentAndChildren() throws Exception {
+ final Content content = new GapContent(10);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ final Element parent = new Element("parent");
+ parent.associate(content, content.getRange());
+ final Comment child1 = new Comment();
+ child1.associate(content, new Range(1, 2));
+ parent.addChild(child1);
+ final Comment child2 = new Comment();
+ child2.associate(content, new Range(3, 4));
+ parent.addChild(child2);
+ content.insertText(child1.getEndOffset(), "Hello");
+ content.insertText(child2.getEndOffset(), "World");
+
+ final DeepCopy deepCopy = new DeepCopy(parent);
+ final Element copiedParent = (Element) deepCopy.getNodes().get(0);
+ final List<Node> copiedChildNodes = copiedParent.getChildNodes();
+
+ assertEquals(2, copiedChildNodes.size());
+ assertEquals("Hello", copiedChildNodes.get(0).getText());
+ assertEquals("World", copiedChildNodes.get(1).getText());
+ }
+
+}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentContentModelTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentContentModelTest.java
index eb3ee0c0..e8bf5bee 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentContentModelTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentContentModelTest.java
@@ -41,21 +41,21 @@ public class DocumentContentModelTest {
@Test
public void initializeWithPublicId() throws Exception {
- model.initialize(null, "publicId", "systemId", new RootElement(new QualifiedName("schemaId", "rootElement")));
+ model.initialize(null, "publicId", "systemId", new Element(new QualifiedName("schemaId", "rootElement")));
assertEquals("publicId", model.getMainDocumentTypeIdentifier());
assertTrue(model.isDtdAssigned());
}
@Test
public void initializeWithSystemId() throws Exception {
- model.initialize(null, null, "systemId", new RootElement(new QualifiedName("schemaId", "rootElement")));
+ model.initialize(null, null, "systemId", new Element(new QualifiedName("schemaId", "rootElement")));
assertEquals("systemId", model.getMainDocumentTypeIdentifier());
assertTrue(model.isDtdAssigned());
}
@Test
public void initializeWithNamespace() throws Exception {
- model.initialize(null, null, null, new RootElement(new QualifiedName("schemaId", "rootElement")));
+ model.initialize(null, null, null, new Element(new QualifiedName("schemaId", "rootElement")));
assertEquals("schemaId", model.getMainDocumentTypeIdentifier());
assertFalse(model.isDtdAssigned());
}
@@ -94,7 +94,7 @@ public class DocumentContentModelTest {
@Test
public void useBaseUriForResolving() throws Exception {
- model.initialize("file://base/uri/document.xml", null, null, new RootElement(new QualifiedName("schemaId", "rootElement")));
+ model.initialize("file://base/uri/document.xml", null, null, new Element(new QualifiedName("schemaId", "rootElement")));
final InputSource resolvedEntity = model.resolveEntity("UnknownPublicId", "UnknownSystemId.dtd");
assertNotNull(resolvedEntity);
assertEquals("file://base/uri/UnknownSystemId.dtd", resolvedEntity.getSystemId());
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentFragmentTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentFragmentTest.java
new file mode 100644
index 00000000..71d90a5e
--- /dev/null
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentFragmentTest.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Copyright (c) 2012 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.dom;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.core.runtime.AssertionFailedException;
+import org.junit.Test;
+
+/**
+ * @author Florian Thienel
+ */
+public class DocumentFragmentTest {
+
+ @Test(expected = AssertionFailedException.class)
+ public void contentMustNotBeEmpty() throws Exception {
+ final GapContent emptyContent = new GapContent(0);
+ new DocumentFragment(emptyContent, Collections.<Node> emptyList());
+ }
+
+ @Test
+ public void shouldAssociateOnCreation() throws Exception {
+ final GapContent content = new GapContent(3);
+ content.insertText(0, "abc");
+ final DocumentFragment fragment = new DocumentFragment(content, Collections.<Node> emptyList());
+ assertTrue(fragment.isAssociated());
+ assertSame(content, fragment.getContent());
+ }
+
+ @Test
+ public void shoudlContainGivenText() throws Exception {
+ final GapContent content = new GapContent(3);
+ content.insertText(0, "abc");
+ final DocumentFragment fragment = new DocumentFragment(content, Collections.<Node> emptyList());
+ final List<Node> childNodes = fragment.getChildNodes();
+ assertEquals(1, childNodes.size());
+ final Node child = childNodes.get(0);
+ assertTrue(child instanceof Text);
+ }
+
+ @Test
+ public void shouldContainGivenChildren() throws Exception {
+ final GapContent content = new GapContent(4);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ final Element child1 = new Element("child");
+ child1.associate(content, new Range(0, 1));
+ final Element child2 = new Element("child");
+ child2.associate(content, new Range(2, 3));
+
+ final DocumentFragment fragment = new DocumentFragment(content, Arrays.<Node> asList(child1, child2));
+ assertSame(child1, fragment.getChildNodes().get(0));
+ assertSame(child2, fragment.getChildNodes().get(1));
+ }
+
+ @Test
+ public void hasNoOwnElementMarkers() throws Exception {
+ final GapContent content = new GapContent(4);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ final Element child1 = new Element("child");
+ child1.associate(content, new Range(0, 1));
+ final Element child2 = new Element("child");
+ child2.associate(content, new Range(2, 3));
+
+ final DocumentFragment fragment = new DocumentFragment(content, Arrays.<Node> asList(child1, child2));
+ assertEquals(fragment.getStartOffset(), child1.getStartOffset());
+ assertEquals(fragment.getEndOffset(), child2.getEndOffset());
+ }
+
+ @Test
+ public void shouldNotHaveBaseUri() throws Exception {
+ final GapContent content = new GapContent(3);
+ content.insertText(0, "abc");
+ final DocumentFragment fragment = new DocumentFragment(content, Collections.<Node> emptyList());
+ assertNull(fragment.getBaseURI());
+ }
+}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentReaderTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentReaderTest.java
index 3f231c18..e2297c56 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentReaderTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentReaderTest.java
@@ -136,13 +136,13 @@ public class DocumentReaderTest {
final List<Node> rootChildNodes = rootElement.getChildNodes();
assertEquals(4, rootChildNodes.size());
- final CommentElement comment1 = (CommentElement) rootChildNodes.get(0);
+ final Comment comment1 = (Comment) rootChildNodes.get(0);
assertEquals("A comment within the root element.", comment1.getText());
- final CommentElement comment2 = (CommentElement) ((Element) rootChildNodes.get(1)).getChildNodes().get(1);
+ final Comment comment2 = (Comment) ((Element) rootChildNodes.get(1)).getChildNodes().get(1);
assertEquals("A comment within text.", comment2.getText());
- final CommentElement comment3 = (CommentElement) rootChildNodes.get(2);
+ final Comment comment3 = (Comment) rootChildNodes.get(2);
assertEquals("Another comment between two child elements.", comment3.getText());
}
}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentTest.java
new file mode 100644
index 00000000..9db8e31c
--- /dev/null
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DocumentTest.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * Copyright (c) 2012 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.dom;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.eclipse.core.runtime.AssertionFailedException;
+import org.eclipse.core.runtime.QualifiedName;
+import org.junit.Test;
+
+/**
+ * @author Florian Thienel
+ */
+public class DocumentTest {
+
+ @Test
+ public void createDocumentWithRootElement() throws Exception {
+ final Element rootElement = new Element("root");
+ final Document document = new Document(rootElement);
+ assertDocumentConnectedToRootElement(rootElement, document);
+ }
+
+ @Test
+ public void createDocumentWithRootElementAndContent() throws Exception {
+ final GapContent content = new GapContent(10);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ final Element rootElement = new Element("root");
+ rootElement.associate(content, new Range(0, 1));
+ final Document document = new Document(content, rootElement);
+ assertDocumentConnectedToRootElement(rootElement, document);
+ }
+
+ @Test(expected = AssertionFailedException.class)
+ public void rootElementMustAlreadyBeAssociatedIfDocumentCreatedWithContent() throws Exception {
+ final GapContent content = new GapContent(10);
+ final Element rootElement = new Element("root");
+ final Document document = new Document(content, rootElement);
+ assertDocumentConnectedToRootElement(rootElement, document);
+ }
+
+ private static void assertDocumentConnectedToRootElement(final Element rootElement, final Document document) {
+ assertNotNull(document.getContent());
+ assertTrue(document.isAssociated());
+ assertTrue(rootElement.isAssociated());
+ assertSame(document, rootElement.getParent());
+ assertTrue(rootElement.getStartOffset() >= document.getStartOffset());
+ assertTrue(rootElement.getEndOffset() <= document.getEndOffset());
+ }
+
+ @Test
+ public void createFragmentWithTextAndChild() throws Exception {
+ final Document document = new Document(new Element("root"));
+ final Element childElement = document.insertElement(1, new QualifiedName(null, "child"));
+ document.insertText(childElement.getStartOffset(), "Hello ");
+ document.insertText(childElement.getEndOffset(), "Child");
+ document.insertText(childElement.getEndOffset() + 1, " World");
+ final Range range = childElement.getRange().moveBounds(-2, 2);
+ final DocumentFragment fragment = document.getFragment(range);
+ assertEquals(11, fragment.getLength());
+ assertNodesEqual(document.getNodes(range), fragment.getNodes());
+ }
+
+ @Test
+ public void createFragmentWithExactlyOneChild() throws Exception {
+ final Document document = new Document(new Element("root"));
+ final Element childElement = document.insertElement(1, new QualifiedName(null, "child"));
+ document.insertText(childElement.getEndOffset(), "Child");
+ final Range range = childElement.getRange();
+ final DocumentFragment fragment = document.getFragment(range);
+ assertEquals(7, fragment.getLength());
+ assertNodesEqual(document.getNodes(range), fragment.getNodes());
+ }
+
+ private static void assertNodesEqual(final List<? extends Node> expected, final List<? extends Node> actual) {
+ assertEquals(expected.size(), actual.size());
+ for (int i = 0; i < expected.size(); i++) {
+ assertNodeEquals(expected.get(i), actual.get(i));
+ }
+ }
+
+ private static void assertNodeEquals(final Node expected, final Node actual) {
+ assertSame(expected.getClass(), actual.getClass());
+ assertEquals(expected.getText(), actual.getText());
+ if (expected instanceof Parent) {
+ assertNodesEqual(((Parent) expected).getChildNodes(), ((Parent) actual).getChildNodes());
+ }
+ }
+}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DummyValidator.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DummyValidator.java
new file mode 100644
index 00000000..64503c9b
--- /dev/null
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DummyValidator.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2012 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.dom;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.runtime.QualifiedName;
+import org.eclipse.vex.core.internal.validator.AttributeDefinition;
+
+/**
+ * @author Florian Thienel
+ */
+public class DummyValidator implements Validator {
+
+ public AttributeDefinition getAttributeDefinition(final Attribute attribute) {
+ return null;
+ }
+
+ public List<AttributeDefinition> getAttributeDefinitions(final Element element) {
+ return Collections.emptyList();
+ }
+
+ public Set<QualifiedName> getValidRootElements() {
+ return Collections.emptySet();
+ }
+
+ public Set<QualifiedName> getValidItems(final Element element) {
+ return Collections.emptySet();
+ }
+
+ public boolean isValidSequence(final QualifiedName element, final List<QualifiedName> nodes, final boolean partial) {
+ return false;
+ }
+
+ public boolean isValidSequence(final QualifiedName element, final List<QualifiedName> sequence1, final List<QualifiedName> sequence2, final List<QualifiedName> sequence3, final boolean partial) {
+ return false;
+ }
+
+ public Set<String> getRequiredNamespaces() {
+ return Collections.emptySet();
+ }
+
+}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/GapContentTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/GapContentTest.java
index ccddd844..fec60b8e 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/GapContentTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/GapContentTest.java
@@ -11,35 +11,32 @@
package org.eclipse.vex.core.internal.dom;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import org.eclipse.core.runtime.AssertionFailedException;
import org.junit.Test;
/**
* Test the GapContent class
*/
-public class GapContentTest {
+public class GapContentTest extends ContentTest {
- @Test
- public void insertSingleElementMarker() throws Exception {
- final GapContent content = new GapContent(3);
- content.insertElementMarker(0);
- assertEquals(1, content.getLength());
- assertTrue(content.isElementMarker(content.getString(0, content.getLength()).charAt(0)));
+ @Override
+ protected Content createContent() {
+ return new GapContent(100);
}
@Test
- public void insertMultipleElementMarkers() throws Exception {
+ public void useChar0AsElementMarker() throws Exception {
final GapContent elementMarkerContent = new GapContent(4);
elementMarkerContent.insertElementMarker(0);
elementMarkerContent.insertElementMarker(0);
final GapContent stringContent = new GapContent(4);
- stringContent.insertString(0, "\0\0");
+ stringContent.insertText(0, "\0\0");
- assertEquals(stringContent.getLength(), elementMarkerContent.getLength());
- assertEquals(stringContent.getString(0, stringContent.getLength()), elementMarkerContent.getString(0, elementMarkerContent.getLength()));
+ assertEquals(stringContent.length(), elementMarkerContent.length());
+ assertEquals(stringContent.getText(stringContent.getRange()), elementMarkerContent.getText(elementMarkerContent.getRange()));
}
@Test
@@ -51,15 +48,15 @@ public class GapContentTest {
//
final GapContent content = new GapContent(2);
- assertEquals(0, content.getLength());
- content.insertString(0, "a");
- assertEquals(1, content.getLength());
- content.insertString(1, "d");
- assertEquals(2, content.getLength());
- content.insertString(1, "c");
- assertEquals(3, content.getLength());
- content.insertString(1, "b");
- assertEquals(4, content.getLength());
+ assertEquals(0, content.length());
+ content.insertText(0, "a");
+ assertEquals(1, content.length());
+ content.insertText(1, "d");
+ assertEquals(2, content.length());
+ content.insertText(1, "c");
+ assertEquals(3, content.length());
+ content.insertText(1, "b");
+ assertEquals(4, content.length());
final Position pa = content.createPosition(0);
final Position pb = content.createPosition(1);
@@ -68,27 +65,27 @@ public class GapContentTest {
final Position pe = content.createPosition(4);
try {
- content.getString(-1, 1);
+ content.getText(new Range(-1, 0));
fail("expected exception");
- } catch (final IllegalArgumentException ex) {
+ } catch (final AssertionFailedException ex) {
}
try {
- content.getString(4, 1);
+ content.getText(new Range(4, 4));
fail("expected exception");
- } catch (final IllegalArgumentException ex) {
+ } catch (final AssertionFailedException ex) {
}
try {
- content.getString(0, -1);
+ content.getText(new Range(0, -1));
fail("expected exception");
- } catch (final IllegalArgumentException ex) {
+ } catch (final AssertionFailedException ex) {
}
try {
- content.getString(0, 5);
+ content.getText(new Range(0, 4));
fail("expected exception");
- } catch (final IllegalArgumentException ex) {
+ } catch (final AssertionFailedException ex) {
}
try {
@@ -103,29 +100,29 @@ public class GapContentTest {
} catch (final IllegalArgumentException ex) {
}
- assertEquals("a", content.getString(0, 1));
- assertEquals("b", content.getString(1, 1));
- assertEquals("c", content.getString(2, 1));
- assertEquals("d", content.getString(3, 1));
+ assertEquals("a", content.getText(new Range(0, 0)));
+ assertEquals("b", content.getText(new Range(1, 1)));
+ assertEquals("c", content.getText(new Range(2, 2)));
+ assertEquals("d", content.getText(new Range(3, 3)));
- assertEquals("ab", content.getString(0, 2));
- assertEquals("bc", content.getString(1, 2));
- assertEquals("cd", content.getString(2, 2));
+ assertEquals("ab", content.getText(new Range(0, 1)));
+ assertEquals("bc", content.getText(new Range(1, 2)));
+ assertEquals("cd", content.getText(new Range(2, 3)));
- assertEquals("abc", content.getString(0, 3));
- assertEquals("bcd", content.getString(1, 3));
+ assertEquals("abc", content.getText(new Range(0, 2)));
+ assertEquals("bcd", content.getText(new Range(1, 3)));
- assertEquals("abcd", content.getString(0, 4));
+ assertEquals("abcd", content.getText(new Range(0, 3)));
//
// a b x (gap) y c d
// | | | | | | |
// 0 1 2 3 4 5 6
//
- content.insertString(2, "y");
- assertEquals(5, content.getLength());
- content.insertString(2, "x");
- assertEquals(6, content.getLength());
+ content.insertText(2, "y");
+ assertEquals(5, content.length());
+ content.insertText(2, "x");
+ assertEquals(6, content.length());
assertEquals(0, pa.getOffset());
assertEquals(1, pb.getOffset());
@@ -136,9 +133,11 @@ public class GapContentTest {
final Position px = content.createPosition(2);
final Position py = content.createPosition(3);
- content.remove(2, 2);
+ assertEquals("xy", content.getText(new Range(2, 3)));
+
+ content.remove(new Range(2, 3));
- assertEquals(4, content.getLength());
+ assertEquals(4, content.length());
assertEquals(0, pa.getOffset());
assertEquals(1, pb.getOffset());
@@ -148,19 +147,20 @@ public class GapContentTest {
assertEquals(3, pd.getOffset());
assertEquals(4, pe.getOffset());
- assertEquals("a", content.getString(0, 1));
- assertEquals("b", content.getString(1, 1));
- assertEquals("c", content.getString(2, 1));
- assertEquals("d", content.getString(3, 1));
+ assertEquals("a", content.getText(new Range(0, 0)));
+ assertEquals("b", content.getText(new Range(1, 1)));
+ assertEquals("c", content.getText(new Range(2, 2)));
+ assertEquals("d", content.getText(new Range(3, 3)));
- assertEquals("ab", content.getString(0, 2));
- assertEquals("bc", content.getString(1, 2));
- assertEquals("cd", content.getString(2, 2));
+ assertEquals("ab", content.getText(new Range(0, 1)));
+ assertEquals("bc", content.getText(new Range(1, 2)));
+ assertEquals("cd", content.getText(new Range(2, 3)));
- assertEquals("abc", content.getString(0, 3));
- assertEquals("bcd", content.getString(1, 3));
+ assertEquals("abc", content.getText(new Range(0, 2)));
+ assertEquals("bcd", content.getText(new Range(1, 3)));
- assertEquals("abcd", content.getString(0, 4));
+ assertEquals("abcd", content.getText(new Range(0, 3)));
}
+
}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/L1CommentHandlingTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/L1CommentHandlingTest.java
new file mode 100644
index 00000000..fdeaa82e
--- /dev/null
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/L1CommentHandlingTest.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2012 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.dom;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.eclipse.core.runtime.AssertionFailedException;
+import org.eclipse.core.runtime.QualifiedName;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Florian Thienel
+ */
+public class L1CommentHandlingTest {
+
+ private Document document;
+ private Element rootElement;
+ private Element titleElement;
+
+ @Before
+ public void setUp() throws Exception {
+ document = new Document(new Element("root"));
+ rootElement = document.getRootElement();
+ titleElement = document.insertElement(1, new QualifiedName(null, "title"));
+ }
+
+ @Test
+ public void shouldIndicateValidCommentInsertionPoints() throws Exception {
+ assertFalse(document.canInsertComment(rootElement.getStartOffset()));
+ assertTrue(document.canInsertComment(titleElement.getStartOffset()));
+ assertTrue(document.canInsertComment(titleElement.getEndOffset()));
+ assertTrue(document.canInsertComment(rootElement.getEndOffset()));
+ assertFalse(document.canInsertComment(rootElement.getEndOffset() + 1));
+ }
+
+ @Test
+ public void shouldInsertCommentAtValidInsertionPoint() throws Exception {
+ final Comment comment = document.insertComment(titleElement.getStartOffset());
+
+ assertSame(rootElement, comment.getParent());
+ assertTrue(comment.isAssociated());
+ final List<Node> newChildNodes = rootElement.getChildNodes();
+ assertEquals(2, newChildNodes.size());
+ assertSame(newChildNodes.get(0), comment);
+ }
+
+ @Test
+ public void shouldInsertTextIntoComment() throws Exception {
+ // text may only be inserted in the comment and in the title element
+ document.setValidator(new DummyValidator() {
+ @Override
+ public boolean isValidSequence(final QualifiedName element, final List<QualifiedName> nodes, final boolean partial) {
+ return "title".equals(element.getLocalName());
+ }
+
+ @Override
+ public boolean isValidSequence(final QualifiedName element, final List<QualifiedName> sequence1, final List<QualifiedName> sequence2, final List<QualifiedName> sequence3,
+ final boolean partial) {
+ return "title".equals(element.getLocalName());
+ }
+ });
+ final Comment comment = document.insertComment(titleElement.getStartOffset());
+ document.insertText(comment.getEndOffset(), "Hello World");
+
+ assertEquals("Hello World", comment.getText());
+ }
+
+ @Test(expected = AssertionFailedException.class)
+ public void shouldNotInsertCommentAtInvalidInsertionPoint() throws Exception {
+ document.insertComment(rootElement.getStartOffset());
+ }
+}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/L1ElementHandlingTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/L1ElementHandlingTest.java
new file mode 100644
index 00000000..5869743d
--- /dev/null
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/L1ElementHandlingTest.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2012 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.dom;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.eclipse.core.runtime.AssertionFailedException;
+import org.eclipse.core.runtime.QualifiedName;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Florian Thienel
+ */
+public class L1ElementHandlingTest {
+
+ private static final QualifiedName VALID_CHILD = new QualifiedName(null, "validChild");
+ private static final QualifiedName INVALID_CHILD = new QualifiedName(null, "invalidChild");
+
+ private Document document;
+ private Element rootElement;
+
+ @Before
+ public void setUp() throws Exception {
+ document = new Document(new Element("root"));
+ rootElement = document.getRootElement();
+ document.setValidator(new DummyValidator() {
+ @Override
+ public boolean isValidSequence(final QualifiedName element, final List<QualifiedName> nodes, final boolean partial) {
+ return "root".equals(element.getLocalName());
+ }
+
+ @Override
+ public boolean isValidSequence(final QualifiedName element, final List<QualifiedName> sequence1, final List<QualifiedName> sequence2, final List<QualifiedName> sequence3,
+ final boolean partial) {
+ return "root".equals(element.getLocalName()) && "validChild".equals(sequence2.get(0).getLocalName());
+ }
+ });
+ }
+
+ @Test
+ public void shouldIndicateValidInsertionPoint() throws Exception {
+ assertFalse(document.canInsertElement(rootElement.getStartOffset(), VALID_CHILD));
+ assertTrue(document.canInsertElement(rootElement.getEndOffset(), VALID_CHILD));
+ }
+
+ @Test
+ public void insertElementAtValidInsertionPoint() throws Exception {
+ final Content content = document.getContent();
+ final int contentLengthBefore = content.length();
+ final Element newElement = document.insertElement(rootElement.getEndOffset(), VALID_CHILD);
+ assertEquals("validChild", newElement.getLocalName());
+ assertSame(rootElement, newElement.getParent());
+ assertEquals(contentLengthBefore + 2, content.length());
+ assertSame(content, newElement.getContent());
+ assertEquals(new Range(1, 2), newElement.getRange());
+ }
+
+ @Test(expected = DocumentValidationException.class)
+ public void cannotInsertInvalidElement() throws Exception {
+ document.insertElement(rootElement.getEndOffset(), INVALID_CHILD);
+ }
+
+ @Test(expected = AssertionFailedException.class)
+ public void cannotInsertElementBeforeRootElement() throws Exception {
+ document.insertElement(rootElement.getStartOffset(), VALID_CHILD);
+ }
+
+ @Test(expected = AssertionFailedException.class)
+ public void cannotInsertElementAfterRootElement() throws Exception {
+ document.insertElement(rootElement.getEndOffset() + 1, VALID_CHILD);
+ }
+
+}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/L1TextHandlingTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/L1TextHandlingTest.java
new file mode 100644
index 00000000..8d36b451
--- /dev/null
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/L1TextHandlingTest.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2012 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.dom;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.eclipse.core.runtime.AssertionFailedException;
+import org.eclipse.core.runtime.QualifiedName;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Florian Thienel
+ */
+public class L1TextHandlingTest {
+
+ private Document document;
+ private Element titleElement;
+
+ @Before
+ public void setUp() throws Exception {
+ document = new Document(new Element("root"));
+ titleElement = document.insertElement(1, new QualifiedName(null, "title"));
+ document.setValidator(new DummyValidator() {
+ @Override
+ public boolean isValidSequence(final QualifiedName element, final List<QualifiedName> nodes, final boolean partial) {
+ return "title".equals(element.getLocalName());
+ }
+
+ @Override
+ public boolean isValidSequence(final QualifiedName element, final List<QualifiedName> sequence1, final List<QualifiedName> sequence2, final List<QualifiedName> sequence3,
+ final boolean partial) {
+ return "title".equals(element.getLocalName());
+ }
+ });
+ }
+
+ @Test
+ public void shouldIndicateValidTextInsertionPoints() throws Exception {
+ assertFalse("the root element may not contain textual contant", document.canInsertText(titleElement.getStartOffset() - 1));
+ assertFalse("the start offset is the last insertion point of the root element before the title element", document.canInsertText(titleElement.getStartOffset()));
+ assertTrue("append new content before the end offset of the title element", document.canInsertText(titleElement.getEndOffset()));
+ assertFalse("the root element may not contain textual contant", document.canInsertText(titleElement.getEndOffset() + 1));
+ }
+
+ @Test
+ public void insertTextAtValidInsertionPoint() throws Exception {
+ document.insertText(titleElement.getEndOffset(), "Hello World");
+ assertEquals("Hello World", titleElement.getText());
+ }
+
+ @Test(expected = AssertionFailedException.class)
+ public void cannotInsertTextBeforeDocumentStart() throws Exception {
+ document.insertText(-1, "Hello World");
+ }
+
+ @Test(expected = AssertionFailedException.class)
+ public void cannotInsertTextAtDocumentStartOffset() throws Exception {
+ document.insertText(0, "Hello World");
+ }
+
+ @Test(expected = AssertionFailedException.class)
+ public void cannotInsertTextAfterDocumentEndOffset() throws Exception {
+ document.insertText(document.getEndOffset() + 1, "Hello World");
+ }
+
+ @Test(expected = DocumentValidationException.class)
+ public void cannotInsertTextAtInvalidInsertionPoint() throws Exception {
+ // titleElement.startOffset is the last insertion point in root before title; root may not contain text according to the validator
+ document.insertText(titleElement.getStartOffset(), "Hello World");
+ }
+
+ @Test
+ public void shouldConvertControlCharactersToSpaces() throws Exception {
+ document.insertText(titleElement.getEndOffset(), "\0\u001F\n");
+ assertEquals("control characters except \\n are converted to spaces", " \n", titleElement.getText());
+ }
+}
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 f35e6954..9a5b0de2 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
@@ -223,18 +223,6 @@ public class NamespaceTest {
}
@Test
- public void cloneElementsNamespaceDeclarations() throws Exception {
- final Element element = new Element("element");
- element.declareDefaultNamespace("http://namespace/uri/default");
- element.declareNamespace("ns1", "http://namespace/uri/1");
- element.declareNamespace("ns2", "http://namespace/uri/2");
-
- final Element clone = element.clone();
- assertEquals("http://namespace/uri/default", clone.getDeclaredDefaultNamespaceURI());
-
- }
-
- @Test
public void readNamespaceDeclarations() throws Exception {
final Document document = readDocumentFromString("<ns1:a xmlns=\"http://namespace/default\" xmlns:ns1=\"http://namespace/uri/1\"/>");
final Element rootElement = document.getRootElement();
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/NodeTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/NodeTest.java
new file mode 100644
index 00000000..f02d1cf1
--- /dev/null
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/NodeTest.java
@@ -0,0 +1,178 @@
+/*******************************************************************************
+ * Copyright (c) 2012 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.dom;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.core.runtime.AssertionFailedException;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Florian Thienel
+ */
+public abstract class NodeTest {
+
+ private Node node;
+
+ protected abstract Node createNode();
+
+ @Before
+ public void setup() throws Exception {
+ node = createNode();
+ }
+
+ @Test
+ public void shouldProvideNodeThroughSetup() throws Exception {
+ // just to be shure
+ assertNotNull("A subclass of NodeTest must provide a Node instance through createNode().", node);
+ }
+
+ @Test
+ public void canBeAssociatedToContentRegion() throws Exception {
+ final GapContent content = new GapContent(3);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+
+ node.associate(content, new Range(0, 1));
+ assertEquals(0, node.getStartOffset());
+ assertEquals(1, node.getEndOffset());
+
+ content.insertText(1, "Hello");
+ assertEquals(0, node.getStartOffset());
+ assertEquals(6, node.getEndOffset());
+ assertSame(content, node.getContent());
+ }
+
+ @Test
+ public void canBeDissociatedFromContent() throws Exception {
+ final GapContent content = new GapContent(3);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+
+ node.associate(content, new Range(0, 1));
+ node.dissociate();
+
+ content.insertText(1, "Hello");
+ assertNull(node.getContent());
+ }
+
+ @Test
+ public void hasTextualContent() throws Exception {
+ final GapContent content = new GapContent(3);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+
+ node.associate(content, new Range(0, 1));
+ assertEquals("", node.getText());
+
+ content.insertText(1, "Hello");
+ assertEquals("Hello", node.getText());
+ }
+
+ @Test(expected = AssertionFailedException.class)
+ public void cannotHaveTextualContentIfNotAssociatedToContent() throws Exception {
+ node.getText();
+ }
+
+ @Test
+ public void shouldContainStartOffset() throws Exception {
+ final GapContent content = new GapContent(3);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertText(1, "Hello World");
+ node.associate(content, content.getRange());
+ content.insertText(0, "prefix");
+
+ assertFalse(node.containsOffset(node.getStartOffset() - 1));
+ assertTrue(node.containsOffset(node.getStartOffset()));
+ assertTrue(node.containsOffset(node.getStartOffset() + 1));
+ }
+
+ @Test
+ public void shouldContainEndOffset() throws Exception {
+ final GapContent content = new GapContent(3);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertText(1, "Hello World");
+ node.associate(content, content.getRange());
+ content.insertText(content.length(), "suffix");
+
+ assertTrue(node.containsOffset(node.getEndOffset() - 1));
+ assertTrue(node.containsOffset(node.getEndOffset()));
+ assertFalse(node.containsOffset(node.getEndOffset() + 1));
+ }
+
+ @Test
+ public void shouldContainNoOffsetIfNotAssociated() throws Exception {
+ assertFalse(node.containsOffset(0));
+ }
+
+ @Test
+ public void shouldIndicateIfWithinRange() throws Exception {
+ final GapContent content = new GapContent(3);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertText(1, "Hello World");
+ node.associate(content, content.getRange());
+ content.insertText(0, "prefix");
+ content.insertText(content.length(), "suffix");
+
+ assertTrue(node.isInRange(node.getRange().moveBounds(-1, 0)));
+ assertTrue(node.isInRange(node.getRange()));
+ assertFalse(node.isInRange(node.getRange().moveBounds(1, 0)));
+ assertTrue(node.isInRange(node.getRange().moveBounds(0, 1)));
+ assertFalse(node.isInRange(node.getRange().moveBounds(0, -1)));
+ assertTrue(node.isInRange(node.getRange().moveBounds(-1, 1)));
+ assertFalse(node.isInRange(node.getRange().moveBounds(1, -1)));
+ }
+
+ @Test
+ public void shouldHandleLowerStartOffset() throws Exception {
+ final GapContent content = new GapContent(3);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertText(1, "Hello World");
+ node.associate(content, content.getRange());
+ content.insertText(0, "prefix");
+
+ assertEquals("Hello World", node.getText(new Range(node.getStartOffset() - 2, node.getEndOffset())));
+ }
+
+ @Test
+ public void shouldHandleBiggerEndOffset() throws Exception {
+ final GapContent content = new GapContent(3);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertText(1, "Hello World");
+ node.associate(content, content.getRange());
+ content.insertText(content.length(), "suffix");
+
+ assertEquals("Hello World", node.getText(new Range(node.getStartOffset(), node.getEndOffset() + 2)));
+ }
+
+ @Test
+ public void shouldProvideRange() throws Exception {
+ final GapContent content = new GapContent(3);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ content.insertText(1, "Hello World");
+ node.associate(content, content.getRange());
+ final Range range = node.getRange();
+ assertEquals(0, range.getStartOffset());
+ assertEquals(content.length() - 1, range.getEndOffset());
+ }
+}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/NodeTraversalTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/NodeTraversalTest.java
new file mode 100644
index 00000000..36fbed7f
--- /dev/null
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/NodeTraversalTest.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2012 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.dom;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.core.runtime.QualifiedName;
+import org.junit.Test;
+
+/**
+ * @author Florian Thienel
+ */
+public class NodeTraversalTest {
+
+ @Test
+ public void givenOneNode_shouldVisitNode() throws Exception {
+ final Text node = new Text(null, new GapContent(1), new Range(0, 0));
+ final boolean[] nodeWasVisited = new boolean[1];
+ final INodeVisitor nodeVisitor = new BaseNodeVisitor() {
+ @Override
+ public void visit(final Text text) {
+ nodeWasVisited[0] = node == text;
+ }
+ };
+ new NodeTraversal(nodeVisitor).traverse(node);
+ assertTrue(nodeWasVisited[0]);
+ }
+
+ @Test
+ public void givenParentWithChildren_shouldVisitParentAndAllChildren() throws Exception {
+ final Content content = new GapContent(10);
+ final Element parent = createElement(content, 0, "parent");
+ final Element child1 = createElement(content, parent.getEndOffset(), "child");
+ parent.addChild(child1);
+ final Element child2 = createElement(content, parent.getEndOffset(), "child");
+ parent.addChild(child2);
+ content.insertText(child1.getEndOffset(), "Hello");
+ content.insertText(child2.getEndOffset(), "World");
+
+ final Set<Node> visitedNodes = new HashSet<Node>();
+ final INodeVisitor nodeVisitor = new BaseNodeVisitor() {
+ @Override
+ public void visit(final Element element) {
+ visitedNodes.add(element);
+ }
+
+ @Override
+ public void visit(final Text text) {
+ visitedNodes.add(text);
+ }
+ };
+ new NodeTraversal(nodeVisitor).traverse(parent);
+
+ assertTrue(visitedNodes.contains(parent));
+ assertTrue(visitedNodes.contains(child1));
+ assertTrue(visitedNodes.contains(child2));
+ assertEquals(5, visitedNodes.size());
+ }
+
+ private static Element createElement(final Content content, final int insertionOffset, final String localName) {
+ final Element element = new Element(new QualifiedName(null, localName));
+ content.insertElementMarker(insertionOffset);
+ content.insertElementMarker(insertionOffset);
+ element.associate(content, new Range(insertionOffset, insertionOffset + 1));
+ return element;
+ }
+}
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
new file mode 100644
index 00000000..13de0c19
--- /dev/null
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/ParentTest.java
@@ -0,0 +1,542 @@
+package org.eclipse.vex.core.internal.dom;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.AssertionFailedException;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ParentTest {
+
+ private TestParent parent;
+
+ private GapContent content;
+
+ @Before
+ public void setUp() throws Exception {
+ parent = new TestParent();
+
+ content = new GapContent(10);
+ content.insertElementMarker(0);
+ content.insertElementMarker(0);
+ parent.associate(content, new Range(0, 1));
+ }
+
+ @Test
+ public void addChild() throws Exception {
+ assertFalse(parent.hasChildren());
+ assertEquals(0, parent.getChildCount());
+
+ final TestChild child = new TestChild();
+ parent.addChild(child);
+ assertTrue(parent.hasChildren());
+ assertEquals(1, parent.getChildCount());
+ assertSame(child, parent.getChildNode(0));
+ assertSame(child, parent.getChildNodes().get(0));
+ }
+
+ @Test
+ public void insertChild() throws Exception {
+ assertFalse(parent.hasChildren());
+ assertEquals(0, parent.getChildCount());
+
+ parent.addChild(new TestChild());
+ parent.addChild(new TestChild());
+ assertEquals(2, parent.getChildCount());
+
+ final TestChild child = new TestChild();
+ parent.insertChild(1, child);
+ assertEquals(3, parent.getChildCount());
+ assertSame(child, parent.getChildNode(1));
+ assertSame(child, parent.getChildNodes().get(1));
+ }
+
+ @Test
+ public void removeChild() throws Exception {
+ final TestChild child = new TestChild();
+ parent.addChild(new TestChild());
+ parent.addChild(child);
+ parent.addChild(new TestChild());
+ assertTrue(parent.hasChildren());
+ assertEquals(3, parent.getChildCount());
+
+ parent.removeChild(child);
+ assertTrue(parent.hasChildren());
+ assertEquals(2, parent.getChildCount());
+ assertFalse(parent.getChildNodes().contains(child));
+ }
+
+ @Test
+ public void shouldSetParentOnAddedChild() throws Exception {
+ final TestChild child = new TestChild();
+ assertNull(child.getParent());
+
+ parent.addChild(child);
+ assertSame(parent, child.getParent());
+ }
+
+ @Test
+ public void shouldSetParentOnInsertedChild() throws Exception {
+ parent.addChild(new TestChild());
+ parent.addChild(new TestChild());
+
+ final TestChild child = new TestChild();
+ assertNull(child.getParent());
+
+ parent.insertChild(1, child);
+ assertSame(parent, child.getParent());
+ }
+
+ @Test
+ public void shouldResetParentOnRemovedChild() throws Exception {
+ final TestChild child = new TestChild();
+ parent.addChild(child);
+ assertSame(parent, child.getParent());
+
+ parent.removeChild(child);
+ assertNull(child.getParent());
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void shouldReturnUnmodifiableChildNodesList() throws Exception {
+ addTestChild();
+ addTestChild();
+ addTestChild();
+ final List<Node> childNodes = parent.getChildNodes();
+ childNodes.add(new TestChild());
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void shouldReturnUnmodifiableChildNodesIterator() throws Exception {
+ addTestChild();
+ addTestChild();
+ addTestChild();
+ final Iterator<Node> iterator = parent.getChildIterator();
+ iterator.next();
+ iterator.remove();
+ }
+
+ @Test
+ public void shouldProvideTextNodesWithChildNodes() throws Exception {
+ // <p>Hello <c></c>World</p>
+ final TestChild child = addTestChild();
+ content.insertText(child.getStartOffset(), "Hello ");
+ content.insertText(parent.getEndOffset(), "World");
+
+ assertEquals(3, parent.getChildNodes().size());
+ assertTrue(parent.getChildNodes().get(0) instanceof Text);
+ assertSame(child, parent.getChildNodes().get(1));
+ assertTrue(parent.getChildNodes().get(2) instanceof Text);
+ }
+
+ @Test
+ public void shouldNotProvideEmptyTextNodesWithChildNodes() throws Exception {
+ final TestChild child = addTestChild();
+
+ assertEquals(0, parent.getStartOffset());
+ assertEquals(3, parent.getEndOffset());
+ assertEquals(1, child.getStartOffset());
+ assertEquals(2, child.getEndOffset());
+
+ assertEquals(1, parent.getChildNodes().size());
+ assertSame(child, parent.getChildNodes().get(0));
+ }
+
+ @Test
+ public void shouldProvideChildNodesInAGivenRange() throws Exception {
+ addTestChild();
+ final TestChild child2 = addTestChild();
+ final TestChild child3 = addTestChild();
+ addTestChild();
+
+ final List<Node> childNodes = parent.getChildNodes(new Range(child2.getStartOffset(), child3.getEndOffset()));
+ assertEquals(2, childNodes.size());
+ assertSame(child2, childNodes.get(0));
+ assertSame(child3, childNodes.get(1));
+ }
+
+ @Test
+ public void shouldCutTextOnEdges() throws Exception {
+ final TestChild child1 = addTestChild();
+ final TestChild child2 = addTestChild();
+
+ content.insertText(child1.getStartOffset(), "Hello");
+ content.insertText(child2.getStartOffset(), "World!");
+
+ final List<Node> childNodes = parent.getChildNodes(child1.getRange().moveBounds(-2, 2));
+ assertEquals(3, childNodes.size());
+ assertTrue(childNodes.get(0) instanceof Text);
+ assertSame(child1, childNodes.get(1));
+ assertTrue(childNodes.get(2) instanceof Text);
+ assertEquals("lo", childNodes.get(0).getText());
+ assertEquals("", childNodes.get(1).getText());
+ assertEquals("Wo", childNodes.get(2).getText());
+ }
+
+ @Test
+ public void shouldSetParentOnTextNodes() throws Exception {
+ content.insertText(parent.getEndOffset(), "Hello World");
+ assertSame(parent, parent.getChildNodes().get(0).getParent());
+ }
+
+ @Test
+ public void shouldProvideNoChildNodesIfEmpty() throws Exception {
+ assertTrue(parent.getChildNodes().isEmpty());
+ }
+
+ @Test
+ public void shouldProvideAddedChildren() throws Exception {
+ final ArrayList<TestChild> children = new ArrayList<TestChild>();
+ for (int i = 0; i < 4; i++) {
+ children.add(addTestChild());
+ }
+
+ final List<Node> childNodes = parent.getChildNodes();
+
+ assertEquals(4, childNodes.size());
+ for (int i = 0; i < 4; i++) {
+ assertSame(children.get(i), childNodes.get(i));
+ }
+ }
+
+ @Test
+ public void shouldProvideAddedChildrenInRange1To3() throws Exception {
+ final ArrayList<TestChild> children = new ArrayList<TestChild>();
+ for (int i = 0; i < 4; i++) {
+ children.add(addTestChild());
+ }
+
+ final List<Node> childNodes = parent.getChildNodes(new Range(children.get(1).getStartOffset(), children.get(3).getEndOffset()));
+ assertEquals(3, childNodes.size());
+ assertSame(children.get(1), childNodes.get(0));
+ assertSame(children.get(2), childNodes.get(1));
+ assertSame(children.get(3), childNodes.get(2));
+ }
+
+ @Test
+ public void shouldProvideAddedChildrenInRange1To2() throws Exception {
+ final ArrayList<TestChild> children = new ArrayList<TestChild>();
+ for (int i = 0; i < 4; i++) {
+ children.add(addTestChild());
+ }
+
+ final List<Node> childNodes = parent.getChildNodes(new Range(children.get(1).getStartOffset(), children.get(3).getStartOffset()));
+ assertEquals(2, childNodes.size());
+ assertSame(children.get(1), childNodes.get(0));
+ assertSame(children.get(2), childNodes.get(1));
+ }
+
+ @Test
+ public void shouldProvideAddedChildrenInRange2() throws Exception {
+ final ArrayList<TestChild> children = new ArrayList<TestChild>();
+ for (int i = 0; i < 4; i++) {
+ children.add(addTestChild());
+ }
+
+ final List<Node> childNodes = parent.getChildNodes(new Range(children.get(1).getEndOffset(), children.get(3).getStartOffset()));
+ assertEquals(1, childNodes.size());
+ assertSame(children.get(2), childNodes.get(0));
+ }
+
+ @Test
+ public void shouldProvideAddedChildrenInRange2To3() throws Exception {
+ final ArrayList<TestChild> children = new ArrayList<TestChild>();
+ for (int i = 0; i < 4; i++) {
+ children.add(addTestChild());
+ }
+
+ final List<Node> childNodes = parent.getChildNodes(new Range(children.get(1).getEndOffset(), children.get(3).getEndOffset()));
+ assertEquals(2, childNodes.size());
+ assertSame(children.get(2), childNodes.get(0));
+ assertSame(children.get(3), childNodes.get(1));
+ }
+
+ @Test
+ public void shouldProvideAllDissociatedChildren() throws Exception {
+ final ArrayList<TestChild> children = new ArrayList<TestChild>();
+ for (int i = 0; i < 4; i++) {
+ final TestChild child = new TestChild();
+ children.add(child);
+ parent.addChild(child);
+ }
+
+ final List<Node> childNodes = parent.getChildNodes();
+
+ assertEquals(4, childNodes.size());
+ for (int i = 0; i < 4; i++) {
+ assertSame(children.get(i), childNodes.get(i));
+ }
+ }
+
+ @Test
+ public void shouldProvideSingleText() throws Exception {
+ content.insertText(parent.getEndOffset(), "Hello World");
+
+ final List<Node> childNodes = parent.getChildNodes();
+
+ assertEquals(1, childNodes.size());
+ assertTextNodeEquals("Hello World", 1, 11, childNodes.get(0));
+ }
+
+ @Test
+ public void shouldProvideSingleCharacterText() throws Exception {
+ content.insertText(parent.getEndOffset(), "x");
+
+ final List<Node> childNodes = parent.getChildNodes();
+
+ assertEquals(1, childNodes.size());
+ assertTextNodeEquals("x", 1, 1, childNodes.get(0));
+ }
+
+ @Test
+ public void shouldProvideTextBeforeChild() throws Exception {
+ content.insertText(parent.getEndOffset(), "Hello World");
+ addTestChild();
+
+ final List<Node> childNodes = parent.getChildNodes();
+
+ assertEquals(2, childNodes.size());
+ assertTextNodeEquals("Hello World", 1, 11, childNodes.get(0));
+ assertChildNodeEquals("", 12, 13, childNodes.get(1));
+ }
+
+ @Test
+ public void shouldProvideSingleCharacterTextBeforeChild() throws Exception {
+ content.insertText(parent.getEndOffset(), "x");
+ addTestChild();
+
+ final List<Node> childNodes = parent.getChildNodes();
+
+ assertEquals(2, childNodes.size());
+ assertTextNodeEquals("x", 1, 1, childNodes.get(0));
+ assertChildNodeEquals("", 2, 3, childNodes.get(1));
+ }
+
+ @Test
+ public void shouldProvideTextAfterChild() throws Exception {
+ addTestChild();
+ content.insertText(parent.getEndOffset(), "Hello World");
+
+ final List<Node> childNodes = parent.getChildNodes();
+
+ assertEquals(2, childNodes.size());
+ assertChildNodeEquals("", 1, 2, childNodes.get(0));
+ assertTextNodeEquals("Hello World", 3, 13, childNodes.get(1));
+ }
+
+ @Test
+ public void shouldProvideSingleCharacterTextAfterChild() throws Exception {
+ addTestChild();
+ content.insertText(parent.getEndOffset(), "x");
+
+ final List<Node> childNodes = parent.getChildNodes();
+
+ assertEquals(2, childNodes.size());
+ assertChildNodeEquals("", 1, 2, childNodes.get(0));
+ assertTextNodeEquals("x", 3, 3, childNodes.get(1));
+ }
+
+ @Test
+ public void shouldProvideAllChildNodesIncludingText() throws Exception {
+ setUpChildNodes();
+ final List<Node> childNodes = parent.getChildNodes();
+ assertTextNodeEquals("Hello ", 1, 6, childNodes.get(0));
+ assertChildNodeEquals("Child1", 7, 14, childNodes.get(1));
+ assertChildNodeEquals("Child2", 15, 22, childNodes.get(2));
+ assertTextNodeEquals(" World", 23, 28, childNodes.get(3));
+ }
+
+ @Test
+ public void shouldHandleSmallerStartOffset() throws Exception {
+ setUpChildNodes();
+ content.insertText(parent.getStartOffset(), "prefix");
+ final List<Node> childNodes = parent.getChildNodes(parent.getRange().moveBounds(-2, 0));
+ assertTextNodeEquals("Hello ", 7, 12, childNodes.get(0));
+ assertChildNodeEquals("Child1", 13, 20, childNodes.get(1));
+ assertChildNodeEquals("Child2", 21, 28, childNodes.get(2));
+ assertTextNodeEquals(" World", 29, 34, childNodes.get(3));
+ }
+
+ @Test
+ public void shouldHandleBiggerEndOffset() throws Exception {
+ setUpChildNodes();
+ content.insertText(parent.getEndOffset() + 1, "suffix");
+ final List<Node> childNodes = parent.getChildNodes();
+ assertTextNodeEquals("Hello ", 1, 6, childNodes.get(0));
+ assertChildNodeEquals("Child1", 7, 14, childNodes.get(1));
+ assertChildNodeEquals("Child2", 15, 22, childNodes.get(2));
+ assertTextNodeEquals(" World", 23, 28, childNodes.get(3));
+ }
+
+ @Test
+ public void shouldProvideSelfOnOwnBoundaries() throws Exception {
+ assertSame(parent, parent.getChildNodeAt(parent.getStartOffset()));
+ assertSame(parent, parent.getChildNodeAt(parent.getEndOffset()));
+ }
+
+ @Test
+ public void shouldReturnTextWithinBoundaries() throws Exception {
+ content.insertText(parent.getEndOffset(), "Hello World");
+ final Node text = parent.getChildNodes().get(0);
+ assertTextNodeEquals("Hello World", text.getStartOffset(), text.getEndOffset(), parent.getChildNodeAt(text.getStartOffset()));
+ assertTextNodeEquals("Hello World", text.getStartOffset(), text.getEndOffset(), parent.getChildNodeAt(text.getStartOffset() + 1));
+ assertTextNodeEquals("Hello World", text.getStartOffset(), text.getEndOffset(), parent.getChildNodeAt(text.getEndOffset() - 1));
+ assertTextNodeEquals("Hello World", text.getStartOffset(), text.getEndOffset(), parent.getChildNodeAt(text.getEndOffset()));
+ }
+
+ @Test
+ public void shouldReturnTextWithinChildBoundaries() throws Exception {
+ final int offset = parent.getEndOffset();
+ content.insertElementMarker(offset);
+ content.insertElementMarker(offset);
+ final Element child = new Element("child");
+ parent.addChild(child);
+ child.associate(content, new Range(offset, offset + 1));
+ content.insertText(child.getEndOffset(), "Hello World");
+ final Node text = child.getChildNodes().get(0);
+ assertTextNodeEquals("Hello World", text.getStartOffset(), text.getEndOffset(), parent.getChildNodeAt(text.getStartOffset()));
+ assertTextNodeEquals("Hello World", text.getStartOffset(), text.getEndOffset(), parent.getChildNodeAt(text.getStartOffset() + 1));
+ assertTextNodeEquals("Hello World", text.getStartOffset(), text.getEndOffset(), parent.getChildNodeAt(text.getEndOffset() - 1));
+ assertTextNodeEquals("Hello World", text.getStartOffset(), text.getEndOffset(), parent.getChildNodeAt(text.getEndOffset()));
+ }
+
+ @Test(expected = AssertionFailedException.class)
+ public void shouldNotProvideChildNodeBeforeStartOffset() throws Exception {
+ content.insertText(parent.getStartOffset(), "prefix");
+ parent.getChildNodeAt(parent.getStartOffset() - 1);
+
+ }
+
+ @Test(expected = AssertionFailedException.class)
+ public void shouldNotProvideChildNodeAfterEndOffset() throws Exception {
+ content.insertText(parent.getEndOffset() + 1, "suffix");
+ parent.getChildNodeAt(parent.getEndOffset() + 1);
+ }
+
+ @Test
+ public void shouldProvideChildNodesBeforeOffset() throws Exception {
+ final TestChild child1 = addTestChild();
+ final TestChild child2 = addTestChild();
+ final TestChild child3 = addTestChild();
+
+ final List<Node> childNodes12 = parent.getChildNodesBefore(child3.getStartOffset());
+ assertEquals(2, childNodes12.size());
+ assertSame(child1, childNodes12.get(0));
+ assertSame(child2, childNodes12.get(1));
+
+ final List<Node> childNodes123 = parent.getChildNodesBefore(parent.getEndOffset());
+ assertEquals(3, childNodes123.size());
+ assertSame(child1, childNodes123.get(0));
+ assertSame(child2, childNodes123.get(1));
+ assertSame(child3, childNodes123.get(2));
+
+ assertTrue(parent.getChildNodesBefore(parent.getStartOffset()).isEmpty());
+ }
+
+ @Test
+ public void shouldProvideChildNodesAfterOffset() throws Exception {
+ final TestChild child1 = addTestChild();
+ final TestChild child2 = addTestChild();
+ final TestChild child3 = addTestChild();
+
+ final List<Node> childNodes23 = parent.getChildNodesAfter(child1.getEndOffset());
+ assertEquals(2, childNodes23.size());
+ assertSame(child2, childNodes23.get(0));
+ assertSame(child3, childNodes23.get(1));
+
+ final List<Node> childNodes123 = parent.getChildNodesAfter(parent.getStartOffset());
+ assertEquals(3, childNodes123.size());
+ assertSame(child1, childNodes123.get(0));
+ assertSame(child2, childNodes123.get(1));
+ assertSame(child3, childNodes123.get(2));
+
+ assertTrue(parent.getChildNodesAfter(parent.getEndOffset()).isEmpty());
+ }
+
+ @Test
+ public void shouldProvideInsertionIndexForOffset() throws Exception {
+ final TestChild child1 = addTestChild();
+ final TestChild child2 = addTestChild();
+ final TestChild child3 = addTestChild();
+
+ assertEquals(0, parent.getInsertionIndex(child1.getStartOffset()));
+ assertEquals(1, parent.getInsertionIndex(child2.getStartOffset()));
+ assertEquals(2, parent.getInsertionIndex(child3.getStartOffset()));
+ assertEquals(3, parent.getInsertionIndex(parent.getEndOffset()));
+ }
+
+ private static void assertTextNodeEquals(final String text, final int startOffset, final int endOffset, final Node actualNode) {
+ assertTrue(actualNode instanceof Text);
+ assertEquals(text, actualNode.getText());
+ assertEquals(startOffset, actualNode.getStartOffset());
+ assertEquals(endOffset, actualNode.getEndOffset());
+ }
+
+ private static void assertChildNodeEquals(final String text, final int startOffset, final int endOffset, final Node actualNode) {
+ assertTrue(actualNode instanceof TestChild);
+ assertEquals(text, actualNode.getText());
+ assertEquals(startOffset, actualNode.getStartOffset());
+ assertEquals(endOffset, actualNode.getEndOffset());
+ }
+
+ private void setUpChildNodes() {
+ content.insertText(parent.getEndOffset(), "Hello ");
+ final TestChild child1 = addTestChild();
+ content.insertText(child1.getEndOffset(), "Child1");
+ final TestChild child2 = addTestChild();
+ content.insertText(child2.getEndOffset(), "Child2");
+ content.insertText(parent.getEndOffset(), " World");
+ }
+
+ private TestChild addTestChild() {
+ final int offset = parent.getEndOffset();
+ content.insertElementMarker(offset);
+ content.insertElementMarker(offset);
+ final TestChild result = new TestChild();
+ parent.addChild(result);
+ result.associate(content, new Range(offset, offset + 1));
+ return result;
+ }
+
+ private static class TestParent extends Parent {
+ @Override
+ public String getBaseURI() {
+ return null;
+ }
+
+ @Override
+ public void accept(final INodeVisitor visitor) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T> T accept(final INodeVisitorWithResult<T> visitor) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ private static class TestChild extends Node {
+ @Override
+ public String getBaseURI() {
+ return null;
+ }
+
+ @Override
+ public void accept(final INodeVisitor visitor) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T> T accept(final INodeVisitorWithResult<T> visitor) {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/RangeTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/RangeTest.java
new file mode 100644
index 00000000..083ba373
--- /dev/null
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/RangeTest.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2012 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.dom;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.core.runtime.AssertionFailedException;
+import org.junit.Test;
+
+/**
+ * @author Florian Thienel
+ */
+public class RangeTest {
+
+ @Test
+ public void hasStartAndEndOffset() throws Exception {
+ final Range range = new Range(1, 5);
+ assertEquals(1, range.getStartOffset());
+ assertEquals(5, range.getEndOffset());
+ }
+
+ @Test(expected = AssertionFailedException.class)
+ public void shouldNotAcceptEndSmallerThanStart() throws Exception {
+ new Range(5, 1);
+ }
+
+ @Test
+ public void shouldHaveLengthIncludingStartAndEnd() throws Exception {
+ assertEquals(5, new Range(1, 5).length());
+ }
+
+ @Test
+ public void shouldContainSmallerRange() throws Exception {
+ assertTrue(new Range(1, 5).contains(new Range(2, 4)));
+ assertFalse(new Range(2, 4).contains(new Range(1, 5)));
+ }
+
+ @Test
+ public void shouldContainItself() throws Exception {
+ final Range range = new Range(1, 5);
+ assertTrue(range.contains(range));
+ }
+
+ @Test
+ public void canBeTrimmed() throws Exception {
+ assertEquals(new Range(2, 5), new Range(1, 5).trimTo(new Range(2, 6)));
+ assertEquals(new Range(1, 4), new Range(1, 5).trimTo(new Range(0, 4)));
+ }
+
+ @Test
+ public void canMoveBounds() throws Exception {
+ assertEquals(new Range(1, 8), new Range(3, 5).moveBounds(-2, 3));
+ }
+
+ @Test
+ public void containsSingleOffset() throws Exception {
+ final Range range = new Range(1, 5);
+ assertFalse(range.contains(0));
+ assertTrue(range.contains(1));
+ assertTrue(range.contains(2));
+ assertTrue(range.contains(4));
+ assertTrue(range.contains(5));
+ assertFalse(range.contains(6));
+ }
+
+ @Test
+ public void isValueObject() throws Exception {
+ final Range range1a = new Range(1, 5);
+ final Range range1b = new Range(1, 5);
+ final Range range2 = new Range(2, 4);
+
+ assertTrue("equals if values equals", range1a.equals(range1b));
+ assertTrue("equals is symmetric", range1b.equals(range1a));
+ assertTrue("hashCode equals if equal", range1a.hashCode() == range1b.hashCode());
+ assertFalse("not equal if no equal values", range1a.equals(range2));
+ }
+}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/SchemaValidatorTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/SchemaValidatorTest.java
index b4628ca9..41052285 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/SchemaValidatorTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/SchemaValidatorTest.java
@@ -137,10 +137,10 @@ public class SchemaValidatorTest {
@Test
public void validItemsFromSimpleSchema() throws Exception {
final Validator validator = new WTPVEXValidator();
- final Document doc = new Document(new RootElement(P));
+ final Document doc = new Document(new Element(P));
doc.setValidator(validator);
- doc.insertElement(1, new Element(B));
- doc.insertElement(2, new Element(I));
+ doc.insertElement(1, B);
+ doc.insertElement(2, I);
assertValidItems(validator, doc.getRootElement(), B, I); // p
assertValidItems(validator, doc.getElementAt(1), B, I); // b
@@ -162,12 +162,12 @@ public class SchemaValidatorTest {
* needs their parent to find the definition of their content model.
*/
final Validator validator = new WTPVEXValidator();
- final Document doc = new Document(new RootElement(CHAPTER));
+ final Document doc = new Document(new Element(CHAPTER));
doc.setValidator(validator);
- doc.insertElement(1, new Element(TITLE));
- doc.insertElement(3, new Element(P));
- doc.insertElement(4, new Element(B));
- doc.insertElement(5, new Element(I));
+ doc.insertElement(1, TITLE);
+ doc.insertElement(3, P);
+ doc.insertElement(4, B);
+ doc.insertElement(5, I);
assertValidItems(validator, doc.getRootElement(), CHAPTER, TITLE, P); // chapter
assertValidItems(validator, doc.getElementAt(2)); // title
@@ -178,14 +178,14 @@ public class SchemaValidatorTest {
@Test
public void getAllRequiredNamespacesForSimpleSchema() throws Exception {
- final Validator validator = new WTPVEXValidator(new DocumentContentModel(null, null, null, new RootElement(P)));
+ final Validator validator = new WTPVEXValidator(new DocumentContentModel(null, null, null, new Element(P)));
final Set<String> requiredNamespaces = validator.getRequiredNamespaces();
assertEquals(1, requiredNamespaces.size());
}
@Test
public void getAllRequiredNamespacesForComplexSchema() throws Exception {
- final Validator validator = new WTPVEXValidator(new DocumentContentModel(null, null, null, new RootElement(CHAPTER)));
+ final Validator validator = new WTPVEXValidator(new DocumentContentModel(null, null, null, new Element(CHAPTER)));
final Set<String> requiredNamespaces = validator.getRequiredNamespaces();
assertEquals(2, requiredNamespaces.size());
assertTrue(requiredNamespaces.contains(CONTENT_NS));
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/LayoutTestSuite.java
index 18f84434..59cf6f57 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/LayoutTestSuite.java
@@ -27,10 +27,13 @@ import junit.framework.TestSuite;
import org.eclipse.vex.core.internal.css.StyleSheet;
import org.eclipse.vex.core.internal.css.StyleSheetReader;
+import org.eclipse.vex.core.internal.dom.BaseNodeVisitorWithResult;
import org.eclipse.vex.core.internal.dom.Document;
import org.eclipse.vex.core.internal.dom.DocumentContentModel;
import org.eclipse.vex.core.internal.dom.DocumentReader;
+import org.eclipse.vex.core.internal.dom.Element;
import org.eclipse.vex.core.internal.dom.IWhitespacePolicy;
+import org.eclipse.vex.core.internal.dom.Node;
import org.eclipse.vex.core.internal.widget.CssWhitespacePolicy;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
@@ -129,8 +132,8 @@ public class LayoutTestSuite extends TestCase {
}
if (boxSpec.element != null) {
- assertNotNull(box.getElement());
- assertEquals(boxSpec.element, box.getElement().getPrefixedName());
+ assertNotNull(box.getNode());
+ assertEquals(boxSpec.element, getPrefixedNameOfElement(box.getNode()));
}
if (boxSpec.text != null && box instanceof TextBox) {
@@ -164,6 +167,15 @@ public class LayoutTestSuite extends TestCase {
}
+ private static String getPrefixedNameOfElement(final Node node) {
+ return node.accept(new BaseNodeVisitorWithResult<String>("") {
+ @Override
+ public String visit(final Element element) {
+ return element.getPrefixedName();
+ }
+ });
+ }
+
private static class TestCaseBuilder extends DefaultHandler {
private List<TestCase> testCases;
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TableLayoutTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TableLayoutTest.java
index 43ed6b9b..e1cfd53f 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TableLayoutTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TableLayoutTest.java
@@ -16,13 +16,13 @@ import java.util.Stack;
import junit.framework.TestCase;
+import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.vex.core.internal.core.DisplayDevice;
import org.eclipse.vex.core.internal.css.MockDisplayDevice;
import org.eclipse.vex.core.internal.css.StyleSheet;
import org.eclipse.vex.core.internal.css.StyleSheetReader;
import org.eclipse.vex.core.internal.dom.Document;
import org.eclipse.vex.core.internal.dom.Element;
-import org.eclipse.vex.core.internal.dom.RootElement;
public class TableLayoutTest extends TestCase {
@@ -74,14 +74,14 @@ public class TableLayoutTest extends TestCase {
}
private void resetDocument() {
- document = new Document(new RootElement("root"));
+ document = new Document(new Element("root"));
context.setDocument(document);
caretPosition = 1;
rootBox = new RootBox(context, document.getRootElement(), 500);
}
private void insertElement(final String elementName) {
- document.insertElement(caretPosition, new Element(elementName));
+ document.insertElement(caretPosition, new QualifiedName(null, elementName));
caretPosition++;
}
@@ -208,7 +208,7 @@ public class TableLayoutTest extends TestCase {
}
private String contentAsText() {
- return document.getText(0, document.getLength());
+ return document.getText();
}
private void assertCount(final int expected, final Class<? extends Box> blockClass) {
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TestBlockElementBox.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TestBlockElementBox.java
index c040cbe2..30014c25 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TestBlockElementBox.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TestBlockElementBox.java
@@ -14,11 +14,11 @@ import java.net.URL;
import junit.framework.TestCase;
+import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.vex.core.internal.css.StyleSheet;
import org.eclipse.vex.core.internal.css.StyleSheetReader;
import org.eclipse.vex.core.internal.dom.Document;
import org.eclipse.vex.core.internal.dom.Element;
-import org.eclipse.vex.core.internal.dom.RootElement;
public class TestBlockElementBox extends TestCase {
@@ -39,9 +39,9 @@ public class TestBlockElementBox extends TestCase {
}
public void testBeforeAfter() throws Exception {
- final RootElement root = new RootElement("root");
+ final Element root = new Element("root");
final Document doc = new Document(root);
- doc.insertElement(1, new Element("beforeBlock"));
+ doc.insertElement(1, new QualifiedName(null, "beforeBlock"));
context.setDocument(doc);
final RootBox rootBox = new RootBox(context, root, 500);
@@ -54,14 +54,13 @@ public class TestBlockElementBox extends TestCase {
assertEquals(1, children.length);
assertEquals(BlockElementBox.class, children[0].getClass());
beb = (BlockElementBox) children[0];
- assertEquals(root, beb.getElement());
+ assertEquals(root, beb.getNode());
children = beb.getChildren();
assertEquals(1, children.length);
assertEquals(BlockElementBox.class, children[0].getClass());
beb = (BlockElementBox) children[0];
- assertEquals("beforeBlock", beb.getElement().getPrefixedName());
-
+ assertEquals("beforeBlock", ((Element) beb.getNode()).getPrefixedName());
}
}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TestBlocksInInlines.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TestBlocksInInlines.java
index 30197211..33924c56 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TestBlocksInInlines.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/layout/TestBlocksInInlines.java
@@ -14,13 +14,13 @@ import java.net.URL;
import junit.framework.TestCase;
+import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.vex.core.internal.core.DisplayDevice;
import org.eclipse.vex.core.internal.css.MockDisplayDevice;
import org.eclipse.vex.core.internal.css.StyleSheet;
import org.eclipse.vex.core.internal.css.StyleSheetReader;
import org.eclipse.vex.core.internal.dom.Document;
import org.eclipse.vex.core.internal.dom.Element;
-import org.eclipse.vex.core.internal.dom.RootElement;
/**
* Tests proper function of a block-level element within an inline element. These must be layed out as a block child of
@@ -51,14 +51,14 @@ public class TestBlocksInInlines extends TestCase {
}
public void testBlockInInline() throws Exception {
- final RootElement root = new RootElement("root");
+ final Element root = new Element("root");
final Document doc = new Document(root);
context.setDocument(doc);
doc.insertText(1, "one five");
- doc.insertElement(5, new Element("b"));
+ doc.insertElement(5, new QualifiedName(null, "b"));
doc.insertText(6, "two four");
- doc.insertElement(10, new Element("p"));
+ doc.insertElement(10, new QualifiedName(null, "p"));
doc.insertText(11, "three");
final RootBox rootBox = new RootBox(context, root, 500);
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 7e8d8ca9..faa7dcd0 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
@@ -18,7 +18,8 @@ import org.eclipse.vex.core.internal.css.StyleSheet;
import org.eclipse.vex.core.internal.css.StyleSheetReader;
import org.eclipse.vex.core.internal.css.Styles;
import org.eclipse.vex.core.internal.dom.Document;
-import org.eclipse.vex.core.internal.dom.RootElement;
+import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Range;
/**
* Tests the DocumentTestBox class. We focus here on proper offsets, since text splitting is tested thoroughly in
@@ -44,7 +45,7 @@ public class TestDocumentTextBox extends TestCase {
}
public void testSplit() throws Exception {
- final RootElement root = new RootElement("root");
+ final Element root = new Element("root");
final Document doc = new Document(root);
final Styles styles = context.getStyleSheet().getStyles(root);
@@ -84,12 +85,12 @@ public class TestDocumentTextBox extends TestCase {
assertSplit(box, 0, true, "b", "aggy orange trousers");
assertSplit(box, -1, true, "b", "aggy orange trousers");
- doc.delete(1, 22);
+ doc.delete(new Range(1, 21));
}
private void assertSplit(final DocumentTextBox box, final int splitPos, final boolean force, final String left, final String right) {
- final Styles styles = context.getStyleSheet().getStyles(box.getElement());
+ final Styles styles = context.getStyleSheet().getStyles(box.getNode());
final int width = g.getCharWidth();
@@ -121,7 +122,7 @@ public class TestDocumentTextBox extends TestCase {
assertEquals(right.length() * width, rightBox.getWidth());
assertEquals(styles.getLineHeight(), rightBox.getHeight());
assertEquals(midOffset, rightBox.getStartOffset());
- assertEquals(rightOffset - 1, rightBox.getEndOffset());
+ assertEquals(rightOffset, 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 a4b603d8..41e7a86f 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
@@ -19,13 +19,13 @@ import org.eclipse.vex.core.internal.css.MockDisplayDevice;
import org.eclipse.vex.core.internal.css.StyleSheet;
import org.eclipse.vex.core.internal.css.StyleSheetReader;
import org.eclipse.vex.core.internal.css.Styles;
-import org.eclipse.vex.core.internal.dom.RootElement;
+import org.eclipse.vex.core.internal.dom.Element;
public class TestStaticTextBox extends TestCase {
FakeGraphics g;
LayoutContext context;
- RootElement root = new RootElement("root");
+ Element root = new Element("root");
Styles styles;
@Override
@@ -96,7 +96,7 @@ public class TestStaticTextBox extends TestCase {
private void assertSplit(final StaticTextBox box, final int splitPos, final boolean force, final String left, final String right) {
- final Styles styles = context.getStyleSheet().getStyles(box.getElement());
+ final Styles styles = context.getStyleSheet().getStyles(box.getNode());
final int width = g.getCharWidth();
final InlineBox.Pair pair = box.split(context, splitPos * width, force);
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/widget/VexWidgetTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/widget/VexWidgetTest.java
index 861d8fbc..c7cea2f6 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/widget/VexWidgetTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/widget/VexWidgetTest.java
@@ -20,12 +20,10 @@ import java.util.List;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.vex.core.internal.css.StyleSheet;
-import org.eclipse.vex.core.internal.dom.CommentElement;
import org.eclipse.vex.core.internal.dom.Document;
import org.eclipse.vex.core.internal.dom.DocumentFragment;
import org.eclipse.vex.core.internal.dom.Element;
import org.eclipse.vex.core.internal.dom.Node;
-import org.eclipse.vex.core.internal.dom.RootElement;
import org.eclipse.vex.core.internal.dom.Text;
import org.eclipse.vex.core.internal.dom.Validator;
import org.eclipse.vex.core.internal.validator.WTPVEXValidator;
@@ -38,11 +36,11 @@ public class VexWidgetTest {
final VexWidgetImpl widget = new VexWidgetImpl(new MockHostComponent());
widget.setDocument(createDocumentWithDTD(TEST_DTD, "section"), StyleSheet.NULL);
assertCanInsertOnly(widget, "title", "para");
- widget.insertElement(new Element("title"));
+ widget.insertElement(new QualifiedName(null, "title"));
assertCanInsertOnly(widget);
widget.moveBy(1);
assertCanInsertOnly(widget, "para");
- widget.insertElement(new Element("para"));
+ widget.insertElement(new QualifiedName(null, "para"));
widget.moveBy(1);
assertCanInsertOnly(widget, "para");
}
@@ -52,7 +50,7 @@ public class VexWidgetTest {
final VexWidgetImpl widget = new VexWidgetImpl(new MockHostComponent());
widget.setDocument(createDocument(CONTENT_NS, "p"), StyleSheet.NULL);
assertCanInsertOnly(widget, "b", "i");
- widget.insertElement(new Element(new QualifiedName(CONTENT_NS, "b")));
+ widget.insertElement(new QualifiedName(CONTENT_NS, "b"));
assertCanInsertOnly(widget, "b", "i");
widget.moveBy(1);
assertCanInsertOnly(widget, "b", "i");
@@ -63,11 +61,11 @@ public class VexWidgetTest {
final VexWidgetImpl widget = new VexWidgetImpl(new MockHostComponent());
widget.setDocument(createDocument(STRUCTURE_NS, "chapter"), StyleSheet.NULL);
assertCanInsertOnly(widget, "title", "chapter", "p");
- widget.insertElement(new Element(new QualifiedName(STRUCTURE_NS, "title")));
+ widget.insertElement(new QualifiedName(STRUCTURE_NS, "title"));
assertCanInsertOnly(widget);
widget.moveBy(1);
// assertCanInsertOnly(widget, "chapter", "p");
- widget.insertElement(new Element(new QualifiedName(CONTENT_NS, "p")));
+ widget.insertElement(new QualifiedName(CONTENT_NS, "p"));
assertCanInsertOnly(widget, "b", "i");
widget.moveBy(1);
// assertCanInsertOnly(widget, "p");
@@ -78,25 +76,27 @@ public class VexWidgetTest {
public void undoRemoveCommentTag() throws Exception {
final VexWidgetImpl widget = new VexWidgetImpl(new MockHostComponent());
widget.setDocument(createDocument(STRUCTURE_NS, "chapter"), StyleSheet.NULL);
- widget.insertElement(new Element(new QualifiedName(CONTENT_NS, "p")));
- widget.insertText("text before comment");
- widget.insertElement(new CommentElement());
- final Element commentElement = widget.getDocument().getElementAt(widget.getCaretOffset());
- widget.insertText("comment text");
+ widget.insertElement(new QualifiedName(CONTENT_NS, "p"));
+ widget.insertText("1text before comment1");
+ widget.insertComment();
+ final Node comment = widget.getDocument().getChildNodeAt(widget.getCaretOffset());
+ widget.insertText("2comment text2");
widget.moveBy(1);
- widget.insertText("text after comment");
+ widget.insertText("3text after comment3");
final String expectedContentStructure = getContentStructure(widget.getDocument().getRootElement());
widget.doWork(new Runnable() {
public void run() {
- widget.moveTo(commentElement.getStartOffset() + 1, false);
- widget.moveTo(commentElement.getEndOffset(), true);
+ widget.moveTo(comment.getStartOffset() + 1, false);
+ widget.moveTo(comment.getEndOffset() - 1, true);
final DocumentFragment fragment = widget.getSelectedFragment();
widget.deleteSelection();
+
widget.moveBy(-1, false);
- widget.moveBy(2, true);
+ widget.moveBy(1, true);
widget.deleteSelection();
+
widget.insertFragment(fragment);
}
});
@@ -108,14 +108,14 @@ public class VexWidgetTest {
private static Document createDocumentWithDTD(final String dtdIdentifier, final String rootElementName) {
final Validator validator = new WTPVEXValidator(dtdIdentifier);
- final Document document = new Document(new RootElement(rootElementName));
+ final Document document = new Document(new Element(rootElementName));
document.setValidator(validator);
return document;
}
private static Document createDocument(final String rootSchemaIdentifier, final String rootElementName) {
final Validator validator = new WTPVEXValidator();
- final Document document = new Document(new RootElement(new QualifiedName(rootSchemaIdentifier, rootElementName)));
+ final Document document = new Document(new Element(new QualifiedName(rootSchemaIdentifier, rootElementName)));
document.setValidator(validator);
return document;
}
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
index 300a3143..05842478 100644
--- 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
@@ -20,14 +20,25 @@ import org.eclipse.vex.core.internal.css.BatikBehaviorTest;
import org.eclipse.vex.core.internal.css.CssTest;
import org.eclipse.vex.core.internal.css.PropertyTest;
import org.eclipse.vex.core.internal.css.RuleTest;
+import org.eclipse.vex.core.internal.dom.BasicNodeTest;
import org.eclipse.vex.core.internal.dom.BlockElementBoxTest;
+import org.eclipse.vex.core.internal.dom.CopyVisitorTest;
import org.eclipse.vex.core.internal.dom.DTDValidatorTest;
+import org.eclipse.vex.core.internal.dom.DeepCopyTest;
import org.eclipse.vex.core.internal.dom.DocumentContentModelTest;
+import org.eclipse.vex.core.internal.dom.DocumentFragmentTest;
import org.eclipse.vex.core.internal.dom.DocumentReaderTest;
+import org.eclipse.vex.core.internal.dom.DocumentTest;
import org.eclipse.vex.core.internal.dom.DocumentWriterTest;
import org.eclipse.vex.core.internal.dom.GapContentTest;
+import org.eclipse.vex.core.internal.dom.L1CommentHandlingTest;
+import org.eclipse.vex.core.internal.dom.L1ElementHandlingTest;
+import org.eclipse.vex.core.internal.dom.L1TextHandlingTest;
import org.eclipse.vex.core.internal.dom.NamespaceStackTest;
import org.eclipse.vex.core.internal.dom.NamespaceTest;
+import org.eclipse.vex.core.internal.dom.NodeTraversalTest;
+import org.eclipse.vex.core.internal.dom.ParentTest;
+import org.eclipse.vex.core.internal.dom.RangeTest;
import org.eclipse.vex.core.internal.dom.SchemaValidatorTest;
import org.eclipse.vex.core.internal.dom.SpaceNormalizerTest;
import org.eclipse.vex.core.internal.dom.TextWrapperTest;
@@ -53,6 +64,17 @@ public class VEXCoreTestSuite extends TestSuite {
addTest(new JUnit4TestAdapter(SchemaValidatorTest.class));
addTest(new JUnit4TestAdapter(CssTest.class));
addTest(new JUnit4TestAdapter(BatikBehaviorTest.class));
+ addTest(new JUnit4TestAdapter(RangeTest.class));
+ addTest(new JUnit4TestAdapter(BasicNodeTest.class));
+ addTest(new JUnit4TestAdapter(ParentTest.class));
+ addTest(new JUnit4TestAdapter(DocumentTest.class));
+ addTest(new JUnit4TestAdapter(L1TextHandlingTest.class));
+ addTest(new JUnit4TestAdapter(L1CommentHandlingTest.class));
+ addTest(new JUnit4TestAdapter(L1ElementHandlingTest.class));
+ addTest(new JUnit4TestAdapter(DocumentFragmentTest.class));
+ addTest(new JUnit4TestAdapter(NodeTraversalTest.class));
+ addTest(new JUnit4TestAdapter(CopyVisitorTest.class));
+ addTest(new JUnit4TestAdapter(DeepCopyTest.class));
addTestSuite(PropertyTest.class);
addTestSuite(RuleTest.class);
addTestSuite(BlockElementBoxTest.class);
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/BackgroundImageProperty.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/BackgroundImageProperty.java
index 410485c7..c88aaa2c 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/BackgroundImageProperty.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/BackgroundImageProperty.java
@@ -15,7 +15,9 @@ import java.text.MessageFormat;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.vex.core.internal.VEXCorePlugin;
+import org.eclipse.vex.core.internal.dom.BaseNodeVisitorWithResult;
import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
import org.w3c.css.sac.LexicalUnit;
/**
@@ -29,7 +31,7 @@ public class BackgroundImageProperty extends AbstractProperty {
super(CSS.BACKGROUND_IMAGE);
}
- public Object calculate(final LexicalUnit lexicalUnit, final Styles parentStyles, final Styles styles, final Element element) {
+ public Object calculate(final LexicalUnit lexicalUnit, final Styles parentStyles, final Styles styles, final Node node) {
if (lexicalUnit == null) {
return DEFAULT;
}
@@ -37,11 +39,16 @@ public class BackgroundImageProperty extends AbstractProperty {
case LexicalUnit.SAC_STRING_VALUE:
return lexicalUnit.getStringValue();
case LexicalUnit.SAC_ATTR:
- final String attributeValue = element.getAttributeValue(lexicalUnit.getStringValue());
- if (attributeValue != null) {
- return attributeValue;
- }
- return DEFAULT;
+ return node.accept(new BaseNodeVisitorWithResult<Object>(DEFAULT) {
+ @Override
+ public Object visit(final Element element) {
+ final String attributeValue = element.getAttributeValue(lexicalUnit.getStringValue());
+ if (attributeValue != null) {
+ return attributeValue;
+ }
+ return DEFAULT;
+ }
+ });
default:
VEXCorePlugin
.getInstance()
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/BorderSpacingProperty.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/BorderSpacingProperty.java
index f3eb417f..9b26a073 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/BorderSpacingProperty.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/BorderSpacingProperty.java
@@ -11,7 +11,7 @@
package org.eclipse.vex.core.internal.css;
import org.eclipse.vex.core.internal.core.DisplayDevice;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
import org.w3c.css.sac.LexicalUnit;
/**
@@ -57,7 +57,7 @@ public class BorderSpacingProperty extends AbstractProperty {
super(CSS.BORDER_SPACING);
}
- public Object calculate(LexicalUnit lu, final Styles parentStyles, final Styles styles, final Element element) {
+ public Object calculate(LexicalUnit lu, final Styles parentStyles, final Styles styles, final Node node) {
int horizontal = 0;
int vertical = 0;
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/BorderStyleProperty.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/BorderStyleProperty.java
index b6e8a59d..02763027 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/BorderStyleProperty.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/BorderStyleProperty.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipse.vex.core.internal.css;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
import org.w3c.css.sac.LexicalUnit;
/**
@@ -46,7 +46,7 @@ public class BorderStyleProperty extends AbstractProperty {
return false;
}
- public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Element element) {
+ public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Node node) {
if (isBorderStyle(lu)) {
return lu.getStringValue();
} else if (isInherit(lu) && parentStyles != null) {
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/BorderWidthProperty.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/BorderWidthProperty.java
index 1cbd85b5..c8e4558a 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/BorderWidthProperty.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/BorderWidthProperty.java
@@ -11,7 +11,7 @@
package org.eclipse.vex.core.internal.css;
import org.eclipse.vex.core.internal.core.DisplayDevice;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
import org.w3c.css.sac.LexicalUnit;
/**
@@ -87,7 +87,7 @@ public class BorderWidthProperty extends AbstractProperty {
}
}
- public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Element element) {
+ public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Node node) {
return Integer.valueOf(calculateInternal(lu, parentStyles, styles));
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/ColorProperty.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/ColorProperty.java
index 7b33b3be..91b86fb5 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/ColorProperty.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/ColorProperty.java
@@ -14,7 +14,7 @@ import java.util.HashMap;
import java.util.Map;
import org.eclipse.vex.core.internal.core.Color;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
import org.w3c.css.sac.LexicalUnit;
/**
@@ -64,7 +64,7 @@ public class ColorProperty extends AbstractProperty {
super(name);
}
- public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Element element) {
+ public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Node node) {
final boolean inherit = isInherit(lu) || getName().equals(CSS.COLOR);
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/DisplayProperty.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/DisplayProperty.java
index f0075073..e69498e0 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/DisplayProperty.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/DisplayProperty.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipse.vex.core.internal.css;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
import org.w3c.css.sac.LexicalUnit;
/**
@@ -25,7 +25,7 @@ public class DisplayProperty extends AbstractProperty {
super(CSS.DISPLAY);
}
- public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Element element) {
+ public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Node node) {
if (isDisplay(lu)) {
return lu.getStringValue();
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/FontFamilyProperty.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/FontFamilyProperty.java
index b6400b58..8ccf964b 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/FontFamilyProperty.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/FontFamilyProperty.java
@@ -15,7 +15,7 @@ package org.eclipse.vex.core.internal.css;
import java.util.ArrayList;
import java.util.List;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
import org.w3c.css.sac.LexicalUnit;
/**
@@ -30,7 +30,7 @@ public class FontFamilyProperty extends AbstractProperty {
super(CSS.FONT_FAMILY);
}
- public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Element element) {
+ public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Node node) {
if (isFontFamily(lu)) {
return getFontFamilies(lu);
} else {
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/FontSizeProperty.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/FontSizeProperty.java
index e714571e..2c5cbd04 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/FontSizeProperty.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/FontSizeProperty.java
@@ -11,7 +11,7 @@
package org.eclipse.vex.core.internal.css;
import org.eclipse.vex.core.internal.core.DisplayDevice;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
import org.w3c.css.sac.LexicalUnit;
/**
@@ -27,7 +27,7 @@ public class FontSizeProperty extends AbstractProperty {
super(CSS.FONT_SIZE);
}
- public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Element element) {
+ public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Node node) {
return new Float(calculateInternal(lu, parentStyles, styles));
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/FontStyleProperty.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/FontStyleProperty.java
index 2858adeb..d5fb7217 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/FontStyleProperty.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/FontStyleProperty.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipse.vex.core.internal.css;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
import org.w3c.css.sac.LexicalUnit;
/**
@@ -25,7 +25,7 @@ public class FontStyleProperty extends AbstractProperty {
super(CSS.FONT_STYLE);
}
- public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Element element) {
+ public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Node node) {
if (isFontStyle(lu)) {
return lu.getStringValue();
} else {
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/FontVariantProperty.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/FontVariantProperty.java
index 6db1f95c..58e2c782 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/FontVariantProperty.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/FontVariantProperty.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipse.vex.core.internal.css;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
import org.w3c.css.sac.LexicalUnit;
/**
@@ -25,7 +25,7 @@ public class FontVariantProperty extends AbstractProperty {
super(CSS.FONT_VARIANT);
}
- public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Element element) {
+ public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Node node) {
if (isFontVariant(lu)) {
return lu.getStringValue();
} else {
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/FontWeightProperty.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/FontWeightProperty.java
index 6e3c9922..cd4f17b0 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/FontWeightProperty.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/FontWeightProperty.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipse.vex.core.internal.css;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
import org.w3c.css.sac.LexicalUnit;
/**
@@ -28,7 +28,7 @@ public class FontWeightProperty extends AbstractProperty {
super(CSS.FONT_WEIGHT);
}
- public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Element element) {
+ public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Node node) {
return Integer.valueOf(calculateInternal(lu, parentStyles, styles));
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/IProperty.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/IProperty.java
index e643ea70..5849ce0b 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/IProperty.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/IProperty.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipse.vex.core.internal.css;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
import org.w3c.css.sac.LexicalUnit;
/**
@@ -37,9 +37,9 @@ public interface IProperty {
* @param styles
* Styles currently in effect. Often, the calculated value depends on previously calculated styles such
* as font size and color.
- * @param element
- * The current element for which this property is calculated. May be null.
+ * @param node
+ * The current node for which this property is calculated. May be null.
*/
- public Object calculate(LexicalUnit lu, Styles parentStyles, Styles styles, Element element);
+ public Object calculate(LexicalUnit lu, Styles parentStyles, Styles styles, Node node);
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/LengthProperty.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/LengthProperty.java
index 4a590a14..e9107691 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/LengthProperty.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/LengthProperty.java
@@ -17,7 +17,9 @@ import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.vex.core.internal.VEXCorePlugin;
import org.eclipse.vex.core.internal.core.DisplayDevice;
+import org.eclipse.vex.core.internal.dom.BaseNodeVisitorWithResult;
import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
import org.w3c.css.sac.CSSException;
import org.w3c.css.sac.InputSource;
import org.w3c.css.sac.LexicalUnit;
@@ -35,10 +37,15 @@ public class LengthProperty extends AbstractProperty {
this.axis = axis;
}
- public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Element element) {
+ public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Node node) {
final int ppi = getPpi();
if (isAttr(lu)) {
- return calculate(parseAttribute(lu, element), parentStyles, styles, element);
+ return node.accept(new BaseNodeVisitorWithResult<Object>(RelativeLength.createAbsolute(0)) {
+ @Override
+ public Object visit(final Element element) {
+ return calculate(parseAttribute(lu, element), parentStyles, styles, element);
+ }
+ });
}
if (isLength(lu)) {
final int length = getIntLength(lu, styles.getFontSize(), ppi);
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/LineHeightProperty.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/LineHeightProperty.java
index d3a4f844..37514cf8 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/LineHeightProperty.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/LineHeightProperty.java
@@ -11,7 +11,7 @@
package org.eclipse.vex.core.internal.css;
import org.eclipse.vex.core.internal.core.DisplayDevice;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
import org.w3c.css.sac.LexicalUnit;
/**
@@ -32,7 +32,7 @@ public class LineHeightProperty extends AbstractProperty {
* Calculates the value of the property given a LexicalUnit. Returns a RelativeLength that is relative to the
* current font size.
*/
- public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Element element) {
+ public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Node node) {
final int ppi = DisplayDevice.getCurrent().getVerticalPPI();
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/ListStyleTypeProperty.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/ListStyleTypeProperty.java
index 56a188a2..767fd36e 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/ListStyleTypeProperty.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/ListStyleTypeProperty.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipse.vex.core.internal.css;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
import org.w3c.css.sac.LexicalUnit;
/**
@@ -22,7 +22,7 @@ public class ListStyleTypeProperty extends AbstractProperty {
super(CSS.LIST_STYLE_TYPE);
}
- public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Element element) {
+ public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Node node) {
if (isListStyleType(lu)) {
return lu.getStringValue();
} else {
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 47962b3d..0fc348a7 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
@@ -19,9 +19,12 @@ import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
-import org.eclipse.vex.core.internal.dom.CommentElement;
+import org.eclipse.vex.core.internal.dom.BaseNodeVisitorWithResult;
+import org.eclipse.vex.core.internal.dom.Comment;
+import org.eclipse.vex.core.internal.dom.Document;
import org.eclipse.vex.core.internal.dom.Element;
-import org.eclipse.vex.core.internal.dom.RootElement;
+import org.eclipse.vex.core.internal.dom.Node;
+import org.eclipse.vex.core.internal.dom.Parent;
import org.w3c.css.sac.AttributeCondition;
import org.w3c.css.sac.CombinatorCondition;
import org.w3c.css.sac.Condition;
@@ -44,6 +47,8 @@ import org.w3c.css.sac.SiblingSelector;
*/
public class Rule {
+ public static final String COMMENT_RULE_NAME = "COMMENT";
+
private final Selector selector;
private final List<PropertyDecl> propertyDecls = new ArrayList<PropertyDecl>();
@@ -93,11 +98,11 @@ public class Rule {
/**
* Returns true if the given element matches this rule's selector.
*
- * @param element
- * Element to check.
+ * @param node
+ * Node to check.
*/
- public boolean matches(final Element element) {
- return matches(selector, element);
+ public boolean matches(final Node node) {
+ return matches(selector, node);
}
// ==================================================== PRIVATE
@@ -105,9 +110,9 @@ public class Rule {
/**
* Returns true if the given element matches the given selector.
*/
- private static boolean matches(final Selector selector, final Element element) {
+ private static boolean matches(final Selector selector, final Node node) {
- if (element == null) {
+ if (node == null) {
// This can happen when, e.g., with the rule "foo > *".
// Since the root element matches the "*", we check if
// its parent matches "foo", but of course its parent
@@ -125,17 +130,17 @@ public class Rule {
// attributes
final ConditionalSelector cs = (ConditionalSelector) selector;
if (cs.getCondition().getConditionType() == Condition.SAC_PSEUDO_CLASS_CONDITION) {
- if (element instanceof PseudoElement) {
+ if (node instanceof PseudoElement) {
final AttributeCondition ac = (AttributeCondition) cs.getCondition();
- return ac.getValue().equals(element.getLocalName()) && matches(cs.getSimpleSelector(), element.getParent());
- } else if (element instanceof CommentElement) {
+ return ac.getValue().equals(getLocalNameOfElement(node)) && matches(cs.getSimpleSelector(), node.getParent());
+ } else if (node instanceof Comment) {
final AttributeCondition ac = (AttributeCondition) cs.getCondition();
- return CommentElement.CSS_RULE_NAME.equals(ac.getValue()) && matches(cs.getSimpleSelector(), element.getParent());
+ return COMMENT_RULE_NAME.equals(ac.getValue()) && matches(cs.getSimpleSelector(), node.getParent());
} else {
return false;
}
} else {
- return matches(cs.getSimpleSelector(), element) && matchesCondition(cs.getCondition(), element);
+ return matches(cs.getSimpleSelector(), node) && matchesCondition(cs.getCondition(), node);
}
case Selector.SAC_ANY_NODE_SELECTOR:
@@ -145,13 +150,13 @@ public class Rule {
return true;
case Selector.SAC_ROOT_NODE_SELECTOR:
- return element instanceof RootElement;
+ return node.getParent() instanceof Document;
case Selector.SAC_NEGATIVE_SELECTOR:
break; // not yet supported
case Selector.SAC_ELEMENT_NODE_SELECTOR:
- final String elementName = element.getLocalName();
+ final String elementName = getLocalNameOfElement(node);
final String selectorName = ((ElementSelector) selector).getLocalName();
if (selectorName == null) {
// We land here if we have a wildcard selector (*) or
@@ -179,33 +184,33 @@ public class Rule {
case Selector.SAC_PSEUDO_ELEMENT_SELECTOR:
final ElementSelector elementSelector = (ElementSelector) selector;
- return elementSelector.getLocalName().equals(element.getLocalName());
+ return elementSelector.getLocalName().equals(getLocalNameOfElement(node));
case Selector.SAC_DESCENDANT_SELECTOR:
final DescendantSelector ds = (DescendantSelector) selector;
- return matches(ds.getSimpleSelector(), element) && matchesAncestor(ds.getAncestorSelector(), element.getParent());
+ return matches(ds.getSimpleSelector(), node) && matchesAncestor(ds.getAncestorSelector(), node.getParent());
case Selector.SAC_CHILD_SELECTOR:
final DescendantSelector ds2 = (DescendantSelector) selector;
- final Element parent = element.getParent();
- return matches(ds2.getSimpleSelector(), element) && matches(ds2.getAncestorSelector(), parent);
+ final Parent parent = node.getParent();
+ return matches(ds2.getSimpleSelector(), node) && matches(ds2.getAncestorSelector(), parent);
case Selector.SAC_DIRECT_ADJACENT_SELECTOR:
final SiblingSelector ss = (SiblingSelector) selector;
- if (element != null && element.getParent() != null && matches(ss.getSiblingSelector(), element)) {
+ if (node != null && node.getParent() != null && matches(ss.getSiblingSelector(), node)) {
// find next sibling
- final Iterator<Element> i = element.getParent().getChildElements().iterator();
- Element e = null;
- Element f = null;
- while (i.hasNext() && e != element) {
+ final Iterator<Node> i = node.getParent().getChildIterator();
+ Node e = null;
+ Node f = null;
+ while (i.hasNext() && e != node) {
f = e;
e = i.next();
}
- if (e == element) {
+ if (e == node) {
return matches(ss.getSelector(), f);
}
}
@@ -218,21 +223,30 @@ public class Rule {
return false;
}
+ private static String getLocalNameOfElement(final Node node) {
+ return node.accept(new BaseNodeVisitorWithResult<String>("") {
+ @Override
+ public String visit(final Element element) {
+ return element.getLocalName();
+ }
+ });
+ }
+
/**
* Returns true if some ancestor of the given element matches the given selector.
*/
- private static boolean matchesAncestor(final Selector selector, final Element element) {
- Element e = element;
- while (e != null) {
- if (matches(selector, e)) {
+ private static boolean matchesAncestor(final Selector selector, final Node node) {
+ Node n = node;
+ while (n != null) {
+ if (matches(selector, n)) {
return true;
}
- e = e.getParent();
+ n = n.getParent();
}
return false;
}
- private static boolean matchesCondition(final Condition condition, final Element element) {
+ private static boolean matchesCondition(final Condition condition, final Node node) {
AttributeCondition attributeCondition;
String attributeName;
@@ -244,7 +258,7 @@ public class Rule {
case Condition.SAC_ATTRIBUTE_CONDITION:
attributeCondition = (AttributeCondition) condition;
- value = element.getAttributeValue(attributeCondition.getLocalName());
+ value = getAttributeValue(node, attributeCondition.getLocalName());
if (attributeCondition.getValue() != null) {
return attributeCondition.getValue().equals(value);
} else {
@@ -262,7 +276,7 @@ public class Rule {
attributeName = attributeCondition.getLocalName();
}
- value = element.getAttributeValue(attributeName);
+ value = getAttributeValue(node, attributeName);
if (value == null) {
return false;
}
@@ -276,7 +290,7 @@ public class Rule {
case Condition.SAC_AND_CONDITION:
final CombinatorCondition ccon = (CombinatorCondition) condition;
- return matchesCondition(ccon.getFirstCondition(), element) && matchesCondition(ccon.getSecondCondition(), element);
+ return matchesCondition(ccon.getFirstCondition(), node) && matchesCondition(ccon.getSecondCondition(), node);
default:
// TODO: warning: condition not supported
@@ -285,6 +299,15 @@ public class Rule {
return false;
}
+ private static String getAttributeValue(final Node node, final String localName) {
+ return node.accept(new BaseNodeVisitorWithResult<String>() {
+ @Override
+ public String visit(final Element element) {
+ return element.getAttributeValue(localName);
+ }
+ });
+ }
+
/**
* Calculates the specificity for a 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 525f6a52..2f9dda43 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
@@ -28,7 +28,9 @@ import java.util.Map;
import java.util.WeakHashMap;
import org.eclipse.vex.core.internal.core.FontSpec;
+import org.eclipse.vex.core.internal.dom.BaseNodeVisitor;
import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
import org.w3c.css.sac.LexicalUnit;
/**
@@ -85,7 +87,7 @@ public class StyleSheet {
*
* This must be transient to prevent it from being serialized, as WeakHashMaps are not serializable.
*/
- private transient Map<Element, WeakReference<Styles>> styleMap;
+ private transient Map<Node, WeakReference<Styles>> styleMap;
/**
* Class constructor.
@@ -144,13 +146,13 @@ public class StyleSheet {
/**
* Returns the styles for the given element. The styles are cached to ensure reasonable performance.
*
- * @param element
- * Element for which to calculate the styles.
+ * @param node
+ * Node for which to calculate the styles.
*/
- public Styles getStyles(final Element element) {
+ public Styles getStyles(final Node node) {
Styles styles;
- final WeakReference<Styles> ref = getStyleMap().get(element);
+ final WeakReference<Styles> ref = getStyleMap().get(node);
if (ref != null) {
// can't combine these tests, since calling ref.get() twice
@@ -160,39 +162,39 @@ public class StyleSheet {
if (styles != null) {
return styles;
}
- } else if (getStyleMap().containsKey(element)) {
+ } else if (getStyleMap().containsKey(node)) {
// this must be a pseudo-element with no content
return null;
}
- styles = calculateStyles(element);
+ styles = calculateStyles(node);
if (styles == null) {
// Yes, they can be null if element is a PseudoElement with no
// content property
- getStyleMap().put(element, null);
+ getStyleMap().put(node, null);
} else {
- getStyleMap().put(element, new WeakReference<Styles>(styles));
+ getStyleMap().put(node, new WeakReference<Styles>(styles));
}
return styles;
}
- private Styles calculateStyles(final Element element) {
+ private Styles calculateStyles(final Node node) {
final Styles styles = new Styles();
Styles parentStyles = null;
- if (element.getParent() != null) {
- parentStyles = getStyles(element.getParent());
+ if (node != null && node.getParent() != null) {
+ parentStyles = getStyles(node.getParent());
}
- final Map<String, LexicalUnit> decls = getApplicableDeclarations(element);
+ final Map<String, LexicalUnit> decls = getApplicableDeclarations(node);
LexicalUnit lexicalUnit;
// If we're finding a pseudo-element, look at the 'content' property
// first, since most of the time it'll be empty and we'll return null.
- if (element instanceof PseudoElement) {
+ if (node instanceof PseudoElement) {
lexicalUnit = decls.get(CSS.CONTENT);
if (lexicalUnit == null) {
return null;
@@ -207,10 +209,16 @@ public class StyleSheet {
break;
case LexicalUnit.SAC_ATTR:
// content: attr(attributeName)
- final String attributeValue = element.getParent().getAttributeValue(lexicalUnit.getStringValue());
- if (attributeValue != null) {
- content.add(attributeValue);
- }
+ final LexicalUnit currentLexicalUnit = lexicalUnit;
+ node.accept(new BaseNodeVisitor() {
+ @Override
+ public void visit(final Element element) {
+ final String attributeValue = element.getParentElement().getAttributeValue(currentLexicalUnit.getStringValue());
+ if (attributeValue != null) {
+ content.add(attributeValue);
+ }
+ }
+ });
break;
}
lexicalUnit = lexicalUnit.getNextLexicalUnit();
@@ -220,7 +228,7 @@ public class StyleSheet {
for (final IProperty property : CSS_PROPERTIES) {
lexicalUnit = decls.get(property.getName());
- final Object value = property.calculate(lexicalUnit, parentStyles, styles, element);
+ final Object value = property.calculate(lexicalUnit, parentStyles, styles, node);
styles.put(property.getName(), value);
}
@@ -260,8 +268,8 @@ public class StyleSheet {
/**
* Returns all the declarations that apply to the given element.
*/
- private Map<String, LexicalUnit> getApplicableDeclarations(final Element element) {
- final List<PropertyDecl> rawDeclarationsForElement = findAllDeclarationsFor(element);
+ private Map<String, LexicalUnit> getApplicableDeclarations(final Node node) {
+ final List<PropertyDecl> rawDeclarationsForElement = findAllDeclarationsFor(node);
// Sort in cascade order. We can then just stuff them into a
// map and get the right values since higher-priority values
@@ -281,10 +289,10 @@ public class StyleSheet {
return values;
}
- private List<PropertyDecl> findAllDeclarationsFor(final Element element) {
+ private List<PropertyDecl> findAllDeclarationsFor(final Node node) {
final List<PropertyDecl> rawDeclarations = new ArrayList<PropertyDecl>();
for (final Rule rule : rules) {
- if (rule.matches(element)) {
+ if (rule.matches(node)) {
final PropertyDecl[] ruleDecls = rule.getPropertyDecls();
for (final PropertyDecl ruleDecl : ruleDecls) {
rawDeclarations.add(ruleDecl);
@@ -294,9 +302,9 @@ public class StyleSheet {
return rawDeclarations;
}
- private Map<Element, WeakReference<Styles>> getStyleMap() {
+ private Map<Node, WeakReference<Styles>> getStyleMap() {
if (styleMap == null) {
- styleMap = new WeakHashMap<Element, WeakReference<Styles>>();
+ styleMap = new WeakHashMap<Node, WeakReference<Styles>>();
}
return styleMap;
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/TextAlignProperty.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/TextAlignProperty.java
index e0098f71..2c65e84e 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/TextAlignProperty.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/TextAlignProperty.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipse.vex.core.internal.css;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
import org.w3c.css.sac.LexicalUnit;
/**
@@ -25,7 +25,7 @@ public class TextAlignProperty extends AbstractProperty {
super(CSS.TEXT_ALIGN);
}
- public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Element element) {
+ public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Node node) {
if (TextAlignProperty.isTextAlign(lu)) {
return lu.getStringValue();
} else {
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/TextDecorationProperty.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/TextDecorationProperty.java
index 3853db3c..b0327bf7 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/TextDecorationProperty.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/TextDecorationProperty.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipse.vex.core.internal.css;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
import org.w3c.css.sac.LexicalUnit;
/**
@@ -25,7 +25,7 @@ public class TextDecorationProperty extends AbstractProperty {
super(CSS.TEXT_DECORATION);
}
- public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Element element) {
+ public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Node node) {
if (isTextDecoration(lu)) {
return lu.getStringValue();
} else {
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/WhiteSpaceProperty.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/WhiteSpaceProperty.java
index 6058864a..ab27df6f 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/WhiteSpaceProperty.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/css/WhiteSpaceProperty.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipse.vex.core.internal.css;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
import org.w3c.css.sac.LexicalUnit;
/**
@@ -29,7 +29,7 @@ public class WhiteSpaceProperty extends AbstractProperty {
*
*/
- public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Element element) {
+ public Object calculate(final LexicalUnit lu, final Styles parentStyles, final Styles styles, final Node node) {
if (isWhiteSpace(lu)) {
return lu.getStringValue();
} else {
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/BaseNodeVisitor.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/BaseNodeVisitor.java
new file mode 100644
index 00000000..07b35ec6
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/BaseNodeVisitor.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2012 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.dom;
+
+/**
+ * This class provides default implementations for the methods defined by the <code>INodeVisitor</code> interface.
+ *
+ * @see INodeVisitor
+ * @author Florian Thienel
+ */
+public class BaseNodeVisitor implements INodeVisitor {
+
+ public void visit(final Document document) {
+ // ignore
+ }
+
+ public void visit(final DocumentFragment fragment) {
+ // ignore
+ }
+
+ public void visit(final Element element) {
+ // ignore
+ }
+
+ public void visit(final Text text) {
+ // ignore
+ }
+
+ public void visit(final Comment comment) {
+ // ignore
+ }
+}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/BaseNodeVisitorWithResult.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/BaseNodeVisitorWithResult.java
new file mode 100644
index 00000000..ca15eb2a
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/BaseNodeVisitorWithResult.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2012 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.dom;
+
+/**
+ * This class provides default implementations for the methods defined by the <code>INodeVisitorWithResult</code>
+ * interface. An overloaded variant of the constructor allows to define a default value which is returned by the
+ * unimplemented visit methods.
+ *
+ * @see INodeVisitorWithResult
+ * @author Florian Thienel
+ */
+public class BaseNodeVisitorWithResult<T> implements INodeVisitorWithResult<T> {
+
+ private final T defaultValue;
+
+ public BaseNodeVisitorWithResult() {
+ this(null);
+ }
+
+ public BaseNodeVisitorWithResult(final T defaultValue) {
+ this.defaultValue = defaultValue;
+ }
+
+ public T visit(final Document document) {
+ return defaultValue;
+ }
+
+ public T visit(final DocumentFragment fragment) {
+ return defaultValue;
+ }
+
+ public T visit(final Element element) {
+ return defaultValue;
+ }
+
+ public T visit(final Text text) {
+ return defaultValue;
+ }
+
+ public T visit(final Comment comment) {
+ return defaultValue;
+ }
+}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Comment.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Comment.java
new file mode 100644
index 00000000..2d08f63c
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Comment.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2012 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.dom;
+
+/**
+ * @author Florian Thienel
+ */
+public class Comment extends Node {
+
+ @Override
+ public void accept(final INodeVisitor visitor) {
+ visitor.visit(this);
+ }
+
+ @Override
+ public <T> T accept(final INodeVisitorWithResult<T> visitor) {
+ return visitor.visit(this);
+ }
+
+ @Override
+ public String getBaseURI() {
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuffer sb = new StringBuffer();
+
+ sb.append("Comment (");
+ if (isAssociated()) {
+ sb.append(getStartOffset());
+ sb.append(",");
+ sb.append(getEndOffset());
+ } else {
+ sb.append("n/a");
+ }
+ sb.append(")");
+
+ return sb.toString();
+ }
+
+}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Content.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Content.java
index 6bef7b7c..beec629f 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Content.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Content.java
@@ -15,7 +15,7 @@ package org.eclipse.vex.core.internal.dom;
*
* @model
*/
-public interface Content {
+public interface Content extends CharSequence {
/**
* Creates a new Position object at the given initial offset.
@@ -27,6 +27,15 @@ public interface Content {
public Position createPosition(int offset);
/**
+ * Removes the given Position from the list of positions. A removed position is not updated anymore when this
+ * content is modified.
+ *
+ * @param position
+ * the position to remove
+ */
+ public void removePosition(Position position);
+
+ /**
* Insert a string into the content.
*
* @param offset
@@ -35,7 +44,75 @@ public interface Content {
* String to insert.
* @model
*/
- public void insertString(int offset, String s);
+ public void insertText(int offset, String s);
+
+ /**
+ * Get the plain text of a region of this content. The plain text does not contain any information about the element
+ * markers in this content.
+ *
+ * @param startOffset
+ * Offset at which the substring begins.
+ * @param endOffset
+ * Offset at which the substring ends. The number of the returned characters may be less, since the
+ * element markers are removed.
+ * @return the plain text of the given region without element markers
+ */
+ public String getText(final Range range);
+
+ /**
+ * Get the whole plain text of this content. The plain text does not contain any information about the element
+ * markers in this content.
+ *
+ * @return the whole plain text without element markers
+ */
+ public String getText();
+
+ /**
+ * Get the raw text of a region of this content. The plain text does also contain the element markers in this
+ * content.
+ *
+ * @param startOffset
+ * Offset at which the substring begins.
+ * @param endOffset
+ * Offset at which the substring ends.
+ * @return the text of the given region including element markers
+ */
+ public String getRawText(final Range range);
+
+ /**
+ * Get the whole raw text of this content. The raw text does also contain the element markers in this content.
+ *
+ * @return the whole text including element markers
+ */
+ public String getRawText();
+
+ /**
+ * Inserts the given content into this content at the given offset.
+ *
+ * @param offset
+ * Offset at which to insert the given content
+ * @param content
+ * Content to insert
+ */
+ public void insertContent(final int offset, final Content content);
+
+ /**
+ * Get a copy of a region of this content.
+ *
+ * @param startOffset
+ * Offset at which the region to copy begins.
+ * @param endOffset
+ * Offset at which the region to copy ends.
+ * @return the copy of the given region
+ */
+ public Content getContent(final Range range);
+
+ /**
+ * Get a full copy of this content.
+ *
+ * @return a full copy of this content
+ */
+ public Content getContent();
/**
* Insert an element marker into the content.
@@ -47,40 +124,31 @@ public interface Content {
public void insertElementMarker(int offset);
/**
- * Deletes the given range of characters.
+ * Indicates if the character at the given offset is an element marker.
*
* @param offset
- * Offset from which characters should be deleted.
- * @param length
- * Number of characters to delete.
+ * Offset at which to check if an element marker is present.
* @model
*/
- public void remove(int offset, int length);
+ public boolean isElementMarker(int offset);
/**
- * Gets a substring of the content.
+ * Deletes the given range of characters.
*
* @param offset
- * Offset at which the string begins.
+ * Offset from which characters should be deleted.
* @param length
- * Number of characters to return.
+ * Number of characters to delete.
* @model
*/
- public String getString(int offset, int length);
+ public void remove(Range range);
/**
* Return the length of the content.
*
* @model
*/
- public int getLength();
+ public int length();
- /**
- * Indicates if the given character is an element marker.
- *
- * @param c
- * The character to check.
- * @model
- */
- public boolean isElementMarker(char c);
+ public Range getRange();
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/CopyVisitor.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/CopyVisitor.java
new file mode 100644
index 00000000..1d56b354
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/CopyVisitor.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2012 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.dom;
+
+/**
+ * This visitor creates a simple copy of the visited node. I.e. only the node itself, not its content neither its
+ * children are copied. The copy is provided through the getCopy() method.
+ *
+ * @author Florian Thienel
+ */
+public class CopyVisitor implements INodeVisitorWithResult<Node> {
+
+ public Document visit(final Document document) {
+ throw new UnsupportedOperationException("Document cannot be copied");
+ }
+
+ public DocumentFragment visit(final DocumentFragment fragment) {
+ throw new UnsupportedOperationException("DocumentFragment cannot be copied");
+ }
+
+ public Element visit(final Element element) {
+ final Element copyElement = new Element(element.getQualifiedName());
+
+ for (final Attribute attribute : element.getAttributes()) {
+ copyElement.setAttribute(attribute.getQualifiedName(), attribute.getValue());
+ }
+
+ copyElement.declareDefaultNamespace(element.getDeclaredDefaultNamespaceURI());
+
+ for (final String prefix : element.getNamespacePrefixes()) {
+ copyElement.declareNamespace(prefix, element.getNamespaceURI(prefix));
+ }
+
+ return copyElement;
+ }
+
+ public Text visit(final Text text) {
+ // ignore Text nodes because they are created dynamically in Element.getChildNodes()
+ return null;
+ }
+
+ public Comment visit(final Comment comment) {
+ return new Comment();
+ }
+
+}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DeepCopy.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DeepCopy.java
new file mode 100644
index 00000000..3299f844
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DeepCopy.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * Copyright (c) 2012 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.dom;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * This class creates a deep copy of a single Node or the child nodes of a Parent within a given Range. The copy is made
+ * instantly when the constructor of DeepCopy is called.
+ * <p>
+ * DeepCopy means a full copy of all nodes, their children down to the leaf level and the associated content.
+ *
+ * @author Florian Thienel
+ */
+public class DeepCopy {
+
+ private final Content content;
+ private final List<Node> nodes;
+
+ /**
+ * Creates a deep copy of the given node.
+ *
+ * @param node
+ * the node to copy
+ */
+ public DeepCopy(final Node node) {
+ final int delta;
+ if (node.isAssociated()) {
+ final Range range = node.getRange();
+ delta = -range.getStartOffset();
+ content = node.getContent().getContent(range);
+ } else {
+ delta = 0;
+ content = null;
+ }
+ nodes = new ArrayList<Node>();
+
+ copyNodes(Collections.singletonList(node), delta);
+ }
+
+ /**
+ * Creates a deep copy of the child nodes of the given parent within the given range.
+ *
+ * @param parent
+ * the parent
+ * @param range
+ * the range to copy
+ */
+ public DeepCopy(final Parent parent, final Range range) {
+ final int delta;
+ if (parent.isAssociated()) {
+ delta = -range.getStartOffset();
+ content = parent.getContent().getContent(range);
+ } else {
+ delta = 0;
+ content = null;
+ }
+ nodes = new ArrayList<Node>();
+
+ copyNodes(parent.getChildNodes(range), delta);
+ }
+
+ private void copyNodes(final List<Node> sourceNodes, final int delta) {
+ final DeepCopyVisitor deepCopyVisitor = new DeepCopyVisitor(nodes, content, delta);
+ for (final Node sourceNode : sourceNodes) {
+ sourceNode.accept(deepCopyVisitor);
+ }
+ }
+
+ /**
+ * @return the copied nodes on the root level.
+ */
+ public List<Node> getNodes() {
+ return nodes;
+ }
+
+ /**
+ * @return the copied content.
+ */
+ public Content getContent() {
+ return content;
+ }
+
+}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DeepCopyVisitor.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DeepCopyVisitor.java
new file mode 100644
index 00000000..c11d7c74
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DeepCopyVisitor.java
@@ -0,0 +1,92 @@
+package org.eclipse.vex.core.internal.dom;
+
+import java.util.List;
+
+/**
+ * This visitor creates a deep copy of the visited nodes. Deep copy means a full copy of each visited node and its
+ * children down to the leaf level. All copied nodes are associated with a given content. The copied nodes on the root
+ * level are collected in a given List.
+ *
+ * @author Florian Thienel
+ */
+public class DeepCopyVisitor implements INodeVisitor {
+
+ private final CopyVisitor copyVisitor = new CopyVisitor();
+
+ private final List<Node> rootNodes;
+ private final Content content;
+ private final int delta;
+
+ private Parent currentParent = null;
+
+ /**
+ * @param rootNodes
+ * the List to collect the copied nodes on the root level
+ * @param content
+ * the content to associate the copied nodes with
+ * @param delta
+ * the shift for the content association, relative to the beginning of the first node in the source
+ * content
+ */
+ public DeepCopyVisitor(final List<Node> rootNodes, final Content content, final int delta) {
+ this.rootNodes = rootNodes;
+ this.content = content;
+ this.delta = delta;
+ }
+
+ public void visit(final Document document) {
+ throw new UnsupportedOperationException("Document cannot be deep copied");
+ }
+
+ public void visit(final DocumentFragment fragment) {
+ copyChildren(fragment, null);
+ }
+
+ public void visit(final Element element) {
+ final Element copy = copy(element);
+ addToParent(copy);
+ associate(element, copy);
+
+ copyChildren(element, copy);
+ }
+
+ public void visit(final Text text) {
+ // ignore Text nodes because they are created dynamically in Element.getChildNodes()
+ }
+
+ public void visit(final Comment comment) {
+ final Comment copy = copy(comment);
+ addToParent(copy);
+ associate(comment, copy);
+ }
+
+ @SuppressWarnings("unchecked")
+ private <T extends Node> T copy(final T node) {
+ return (T) node.accept(copyVisitor);
+ }
+
+ private void addToParent(final Node node) {
+ if (currentParent == null) {
+ rootNodes.add(node);
+ } else {
+ currentParent.addChild(node);
+ }
+ }
+
+ private void associate(final Node source, final Node copy) {
+ if (source.isAssociated()) {
+ final Range range = source.getRange();
+ copy.associate(content, range.moveBounds(delta));
+ }
+ }
+
+ private void copyChildren(final Parent source, final Parent copy) {
+ final Parent lastParent = currentParent;
+ for (final Node child : source.getChildNodes()) {
+ currentParent = copy;
+ child.accept(this);
+ }
+ currentParent = lastParent;
+ }
+
+}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Document.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Document.java
index 39a2cd20..461c834c 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Document.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Document.java
@@ -11,13 +11,13 @@
*******************************************************************************/
package org.eclipse.vex.core.internal.dom;
-import java.util.ArrayList;
-import java.util.Collections;
+import java.text.MessageFormat;
+import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
+import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.QualifiedName;
-import org.eclipse.osgi.util.NLS;
import org.eclipse.vex.core.internal.core.ListenerList;
import org.eclipse.vex.core.internal.undo.CannotRedoException;
import org.eclipse.vex.core.internal.undo.CannotUndoException;
@@ -25,12 +25,10 @@ import org.eclipse.vex.core.internal.undo.IUndoableEdit;
/**
* Represents an XML document.
- *
*/
-public class Document {
+public class Document extends Parent {
- private final Content content;
- private final RootElement rootElement;
+ private final Element rootElement;
private final ListenerList<DocumentListener, DocumentEvent> listeners = new ListenerList<DocumentListener, DocumentEvent>(DocumentListener.class);
private boolean undoEnabled = true;
@@ -48,19 +46,20 @@ public class Document {
* root element of the document. The document property of this RootElement is set by this constructor.
*
*/
- public Document(final RootElement rootElement) {
- content = new GapContent(100);
+ public Document(final Element rootElement) {
+ final GapContent content = new GapContent(100);
content.insertElementMarker(0);
content.insertElementMarker(0);
+ associate(content, content.getRange());
this.rootElement = rootElement;
- rootElement.setDocument(this);
- rootElement.setContent(content, 0, 1);
+ addChild(rootElement);
+ rootElement.associate(content, content.getRange());
}
/**
* Class constructor. This constructor is used by the document builder and assumes that the content and root element
- * have bee properly set up.
+ * have bee properly set up and is already associated with the given content.
*
* @param content
* Content object used to store the document's content.
@@ -68,539 +67,442 @@ public class Document {
* RootElement of the document.
*
*/
- public Document(final Content content, final RootElement rootElement) {
- this.content = content;
+ public Document(final Content content, final Element rootElement) {
+ Assert.isTrue(content == rootElement.getContent(), "The given root element must already be associated with the given content.");
+ associate(content, content.getRange());
this.rootElement = rootElement;
+ addChild(rootElement);
}
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.vex.core.internal.dom.IVEXDocument#addDocumentListener
- * (org.eclipse.vex.core.internal.dom.DocumentListener)
- */
- public void addDocumentListener(final DocumentListener listener) {
- listeners.add(listener);
+ @Override
+ public int getStartOffset() {
+ return 0;
}
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.vex.core.internal.dom.IVEXDocument#canInsertFragment (int,
- * org.eclipse.vex.core.internal.dom.DocumentFragment)
- */
- public boolean canInsertFragment(final int offset, final DocumentFragment fragment) {
- if (validator == null) {
- return true;
- }
-
- final Element element = getElementAt(offset);
- final List<QualifiedName> seq1 = getNodeNames(element.getStartOffset() + 1, offset);
- final List<QualifiedName> seq2 = fragment.getNodeNames();
- final List<QualifiedName> seq3 = getNodeNames(offset, element.getEndOffset());
-
- return validator.isValidSequence(element.getQualifiedName(), seq1, seq2, seq3, true);
+ @Override
+ public int getEndOffset() {
+ return getContent().length() - 1;
}
- public boolean canInsertText(final int offset) {
- if (validator == null) {
- return true;
- }
-
- final Element element = getElementAt(offset);
- final List<QualifiedName> seq1 = getNodeNames(element.getStartOffset() + 1, offset);
- final List<QualifiedName> seq2 = Collections.singletonList(Validator.PCDATA);
- final List<QualifiedName> seq3 = getNodeNames(offset, element.getEndOffset());
+ @Override
+ public void accept(final INodeVisitor visitor) {
+ visitor.visit(this);
+ }
- return validator.isValidSequence(element.getQualifiedName(), seq1, seq2, seq3, true);
+ @Override
+ public <T> T accept(final INodeVisitorWithResult<T> visitor) {
+ return visitor.visit(this);
}
- public Position createPosition(final int offset) {
- return content.createPosition(offset);
+ @Override
+ public String getBaseURI() {
+ return getDocumentURI();
}
- public void delete(final int startOffset, final int endOffset) throws DocumentValidationException {
+ public void setDocumentURI(final String documentURI) {
+ this.documentURI = documentURI;
+ }
- final Element e1 = getElementAt(startOffset);
- final Element e2 = getElementAt(endOffset);
- if (e1 != e2) {
- throw new IllegalArgumentException("Deletion from " + startOffset + " to " + endOffset + " is unbalanced");
- }
+ public String getDocumentURI() {
+ return documentURI;
+ }
- final Validator validator = getValidator();
- if (validator != null) {
- final List<QualifiedName> seq1 = getNodeNames(e1.getStartOffset() + 1, startOffset);
- final List<QualifiedName> seq2 = getNodeNames(endOffset, e1.getEndOffset());
+ public String getEncoding() {
+ return encoding;
+ }
- if (!validator.isValidSequence(e1.getQualifiedName(), seq1, seq2, null, true)) {
- throw new DocumentValidationException("Unable to delete from " + startOffset + " to " + endOffset);
- }
- }
+ public void setEncoding(final String encoding) {
+ this.encoding = encoding;
+ }
- // Grab the fragment for the undoable edit while it's still here
- final DocumentFragment frag = getFragment(startOffset, endOffset);
+ public String getPublicID() {
+ return publicID;
+ }
- fireBeforeContentDeleted(new DocumentEvent(this, e1, startOffset, endOffset - startOffset, null));
+ public void setPublicID(final String publicID) {
+ this.publicID = publicID;
+ }
- Iterator<Node> iter = e1.getChildNodes().iterator();
- if (e1 instanceof Element) {
- iter = e1.getChildIterator();
- }
- while (iter.hasNext()) {
- final Node child = iter.next();
- if (startOffset <= child.getStartOffset() && child.getEndOffset() < endOffset) {
- iter.remove();
- }
- }
+ public String getSystemID() {
+ return systemID;
+ }
- content.remove(startOffset, endOffset - startOffset);
+ public void setSystemID(final String systemID) {
+ this.systemID = systemID;
+ }
- final IUndoableEdit edit = undoEnabled ? new DeleteEdit(startOffset, endOffset, frag) : null;
+ public Validator getValidator() {
+ return validator;
+ }
- fireContentDeleted(new DocumentEvent(this, e1, startOffset, endOffset - startOffset, edit));
+ public void setValidator(final Validator validator) {
+ this.validator = validator;
}
- public Element findCommonElement(final int offset1, final int offset2) {
- Element element = rootElement;
- for (;;) {
- boolean tryAgain = false;
- final List<Element> children = element.getChildElements();
- for (int i = 0; i < children.size(); i++) {
- if (offset1 > children.get(i).getStartOffset() && offset2 > children.get(i).getStartOffset() && offset1 <= children.get(i).getEndOffset() && offset2 <= children.get(i).getEndOffset()) {
+ public Element getRootElement() {
+ return rootElement;
+ }
- element = children.get(i);
- tryAgain = true;
- break;
- }
- }
- if (!tryAgain) {
- break;
- }
- }
- return element;
+ public boolean isUndoEnabled() {
+ return undoEnabled;
}
- public char getCharacterAt(final int offset) {
- return content.getString(offset, 1).charAt(0);
+ public void setUndoEnabled(final boolean undoEnabled) {
+ this.undoEnabled = undoEnabled;
}
- public Element getElementAt(final int offset) {
- if (offset < 1 || offset >= getLength()) {
- throw new IllegalArgumentException("Illegal offset: " + offset + ". Must be between 1 and n-1");
- }
- Element element = rootElement;
- for (;;) {
- boolean tryAgain = false;
- final List<Element> children = element.getChildElements();
- for (int i = 0; i < children.size(); i++) {
- final Element child = children.get(i);
- if (offset <= child.getStartOffset()) {
- return element;
- } else if (offset <= child.getEndOffset()) {
- element = child;
- tryAgain = true;
- break;
- }
- }
- if (!tryAgain) {
- break;
- }
- }
- return element;
+ public void addDocumentListener(final DocumentListener listener) {
+ listeners.add(listener);
}
- public String getEncoding() {
- return encoding;
+ public void removeDocumentListener(final DocumentListener listener) {
+ listeners.remove(listener);
}
- public void setEncoding(final String encoding) {
- this.encoding = encoding;
+ public int getLength() {
+ return getContent().length();
}
- public DocumentFragment getFragment(final int startOffset, final int endOffset) {
+ public Position createPosition(final int offset) {
+ return getContent().createPosition(offset);
+ }
- assertOffset(startOffset, 0, content.getLength());
- assertOffset(endOffset, 0, content.getLength());
+ private boolean canInsertAt(final Element insertionParent, final int offset, final QualifiedName... nodeNames) {
+ return canInsertAt(insertionParent, offset, Arrays.asList(nodeNames));
+ }
- if (endOffset <= startOffset) {
- throw new IllegalArgumentException("Invalid range (" + startOffset + ", " + endOffset + ")");
+ private boolean canInsertAt(final Element insertionParent, final int offset, final List<QualifiedName> nodeNames) {
+ if (validator == null) {
+ return true;
}
- final Element e1 = getElementAt(startOffset);
- final Element e2 = getElementAt(endOffset);
- if (e1 != e2) {
- throw new IllegalArgumentException("Fragment from " + startOffset + " to " + endOffset + " is unbalanced");
+ if (insertionParent == null) {
+ return false;
}
- final List<Element> children = e1.getChildElements();
+ final List<QualifiedName> prefix = getNodeNames(insertionParent.getChildNodesBefore(offset));
+ final List<QualifiedName> insertionCandidates = nodeNames;
+ final List<QualifiedName> suffix = getNodeNames(insertionParent.getChildNodesAfter(offset));
- final Content newContent = new GapContent(endOffset - startOffset);
- final String s = content.getString(startOffset, endOffset - startOffset);
- newContent.insertString(0, s);
- final List<Element> newChildren = new ArrayList<Element>();
- for (int i = 0; i < children.size(); i++) {
- final Element child = children.get(i);
- if (child.getEndOffset() <= startOffset) {
- continue;
- } else if (child.getStartOffset() >= endOffset) {
- break;
- } else {
- newChildren.add(cloneElement(child, newContent, -startOffset, null));
- }
- }
+ return validator.isValidSequence(insertionParent.getQualifiedName(), prefix, insertionCandidates, suffix, true);
+ }
- return new DocumentFragment(newContent, newChildren);
+ private Element getInsertionParentAt(final int offset) {
+ final Element parent = getElementAt(offset);
+ if (offset == parent.getStartOffset()) {
+ return parent.getParentElement();
+ }
+ return parent;
}
- public int getLength() {
- return content.getLength();
+ private Node getInsertionNodeAt(final int offset) {
+ final Node node = getChildNodeAt(offset);
+ if (offset == node.getStartOffset()) {
+ return node.getParent();
+ }
+ return node;
}
- public List<QualifiedName> getNodeNames(final int startOffset, final int endOffset) {
+ public boolean canInsertText(final int offset) {
+ return canInsertAt(getInsertionParentAt(offset), offset, Validator.PCDATA);
+ }
- final List<Node> nodes = getNodes(startOffset, endOffset);
- final List<QualifiedName> names = new ArrayList<QualifiedName>(nodes.size());
+ public void insertText(final int offset, final String text) throws DocumentValidationException {
+ Assert.isTrue(offset > getStartOffset() && offset <= getEndOffset(), MessageFormat.format("Offset must be in [{0}, {1}]", getStartOffset() + 1, getEndOffset()));
- for (int i = 0; i < nodes.size(); i++) {
- final Node node = nodes.get(i);
- if (node instanceof Element) {
- names.add(((Element) node).getQualifiedName());
- } else {
- names.add(Validator.PCDATA);
+ final String adjustedText = convertControlCharactersToSpaces(text);
+ final Node insertionNode = getInsertionNodeAt(offset);
+ insertionNode.accept(new INodeVisitor() {
+ public void visit(final Document document) {
+ Assert.isTrue(false, "Cannot insert text directly into Document.");
}
- }
- return names;
- }
+ public void visit(final DocumentFragment fragment) {
+ Assert.isTrue(false, "DocumentFragment is never a child of Document.");
+ }
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.vex.core.internal.dom.IVEXDocument#getNodes(int, int)
- */
- public List<Node> getNodes(final int startOffset, final int endOffset) {
- final Element element = getElementAt(startOffset);
- if (element != getElementAt(endOffset)) {
- throw new IllegalArgumentException(NLS.bind("Offsets are unbalanced: {0} is in {1}, {2} is in {3}.",
- new Object[] { startOffset, element.getPrefixedName(), endOffset, getElementAt(endOffset).getPrefixedName() }));
- }
-
- final List<Node> list = new ArrayList<Node>();
- final List<Node> nodes = element.getChildNodes();
- for (int i = 0; i < nodes.size(); i++) {
- final Node node = nodes.get(i);
- if (node.getEndOffset() <= startOffset) {
- continue;
- } else if (node.getStartOffset() >= endOffset) {
- break;
- } else if (node instanceof Element) {
- list.add(node);
- } else {
- final Text text = (Text) node;
- if (text.getStartOffset() < startOffset) {
- text.setContent(text.getContent(), startOffset, text.getEndOffset());
- } else if (text.getEndOffset() > endOffset) {
- text.setContent(text.getContent(), text.getStartOffset(), endOffset);
+ public void visit(final Element element) {
+ if (!canInsertAt(element, offset, Validator.PCDATA)) {
+ throw new DocumentValidationException(MessageFormat.format("Cannot insert text ''{0}'' at offset {1}.", text, offset));
}
- list.add(text);
- }
- }
- return list;
- }
+ fireBeforeContentInserted(new DocumentEvent(Document.this, element, offset, 2, null));
- /**
- * Creates an array of nodes for a given run of content. The returned array includes the given child elements and
- * <code>Text</code> objects where text appears between elements.
- *
- * @param content
- * Content object containing the content
- * @param startOffset
- * start offset of the run
- * @param endOffset
- * end offset of the run
- * @param elements
- * child elements that are within the run
- */
- static List<Node> createNodeList(final Content content, final int startOffset, final int endOffset, final List<Node> elements) {
-
- final List<Node> nodes = new ArrayList<Node>();
- int offset = startOffset;
- for (int i = 0; i < elements.size(); i++) {
- final int start = elements.get(i).getStartOffset();
- if (offset < start) {
- nodes.add(new Text(content, offset, start));
+ getContent().insertText(offset, adjustedText);
+
+ final IUndoableEdit edit = undoEnabled ? new InsertTextEdit(offset, adjustedText) : null;
+ fireContentInserted(new DocumentEvent(Document.this, element, offset, adjustedText.length(), edit));
}
- nodes.add(elements.get(i));
- offset = elements.get(i).getEndOffset() + 1;
- }
- if (offset < endOffset) {
- nodes.add(new Text(content, offset, endOffset));
- }
+ public void visit(final Text text) {
+ getContent().insertText(offset, adjustedText);
+ }
- return nodes;
+ public void visit(final Comment comment) {
+ getContent().insertText(offset, adjustedText);
+ }
+ });
}
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.vex.core.internal.dom.IVEXDocument#getPublicID()
- */
- public String getPublicID() {
- return publicID;
+ private String convertControlCharactersToSpaces(final String text) {
+ final char[] characters = text.toCharArray();
+ for (int i = 0; i < characters.length; i++) {
+ if (Character.isISOControl(characters[i]) && characters[i] != '\n') {
+ characters[i] = ' ';
+ }
+ }
+ return new String(characters);
}
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.vex.core.internal.dom.IVEXDocument#getRawText(int, int)
- */
- public String getRawText(final int startOffset, final int endOffset) {
- return content.getString(startOffset, endOffset - startOffset);
+ public boolean canInsertComment(final int offset) {
+ // TODO Currently comments can only be inserted within the root element.
+ return offset > rootElement.getStartOffset() && offset <= rootElement.getEndOffset();
}
- public Element getRootElement() {
- return rootElement;
- }
+ public Comment insertComment(final int offset) {
+ Assert.isTrue(canInsertComment(offset));
- public String getSystemID() {
- return systemID;
- }
+ final Element parent = getInsertionParentAt(offset);
- public String getText(final int startOffset, final int endOffset) {
- final String raw = content.getString(startOffset, endOffset - startOffset);
- final StringBuffer sb = new StringBuffer(raw.length());
- for (int i = 0; i < raw.length(); i++) {
- final char c = raw.charAt(i);
- if (!content.isElementMarker(c)) {
- sb.append(c);
- }
- }
- return sb.toString();
+ // TODO fire events
+ final Comment comment = new Comment();
+ getContent().insertElementMarker(offset);
+ getContent().insertElementMarker(offset);
+ comment.associate(getContent(), new Range(offset, offset + 1));
+
+ parent.insertChild(parent.getInsertionIndex(offset), comment);
+
+ return comment;
}
- public Validator getValidator() {
- return validator;
+ public boolean canInsertElement(final int offset, final QualifiedName elementName) {
+ return canInsertAt(getInsertionParentAt(offset), offset, elementName);
}
- public void insertElement(final int offset, final Element element) throws DocumentValidationException {
+ public Element insertElement(final int offset, final QualifiedName elementName) throws DocumentValidationException {
+ Assert.isTrue(offset > rootElement.getStartOffset() && offset <= rootElement.getEndOffset(), MessageFormat.format("Offset must be in [{0}, {1}]", getStartOffset() + 1, getEndOffset()));
- if (offset < 1 || offset >= getLength()) {
- throw new IllegalArgumentException("Error inserting element <" + element.getPrefixedName() + ">: offset is " + offset + ", but it must be between 1 and " + (getLength() - 1));
+ final Element parent = getInsertionParentAt(offset);
+ if (!canInsertAt(parent, offset, elementName)) {
+ throw new DocumentValidationException(MessageFormat.format("Cannot insert element {0} at offset {1}.", elementName, offset));
}
- final Validator validator = getValidator();
- if (validator != null) {
- final Element parent = getElementAt(offset);
- final List<QualifiedName> seq1 = getNodeNames(parent.getStartOffset() + 1, offset);
- final List<QualifiedName> seq2 = Collections.singletonList(element.getQualifiedName());
- final List<QualifiedName> seq3 = getNodeNames(offset, parent.getEndOffset());
+ fireBeforeContentInserted(new DocumentEvent(this, parent, offset, 2, null));
- if (!validator.isValidSequence(parent.getQualifiedName(), seq1, seq2, seq3, true)) {
- throw new DocumentValidationException("Cannot insert element " + element.getPrefixedName() + " at offset " + offset);
- }
- }
+ final Element element = new Element(elementName);
+ getContent().insertElementMarker(offset);
+ getContent().insertElementMarker(offset);
+ element.associate(getContent(), new Range(offset, offset + 1));
- // find the parent, and the index into its children at which
- // this element should be inserted
- Element parent = rootElement;
- int childIndex = -1;
- while (childIndex == -1) {
- boolean tryAgain = false;
- final List<Element> children = parent.getChildElements();
- for (int i = 0; i < children.size(); i++) {
- final Element child = children.get(i);
- if (offset <= child.getStartOffset()) {
- childIndex = i;
- break;
- } else if (offset <= child.getEndOffset()) {
- parent = child;
- tryAgain = true;
- break;
- }
- }
- if (!tryAgain && childIndex == -1) {
- childIndex = children.size();
- break;
- }
+ parent.insertChild(parent.getInsertionIndex(offset), element);
+
+ final IUndoableEdit edit = undoEnabled ? new InsertElementEdit(offset, element) : null;
+ fireContentInserted(new DocumentEvent(this, parent, offset, 2, edit));
+
+ return element;
+ }
+
+ /**
+ * @deprecated use Document#insertElement(int, QualifiedName) instead
+ */
+ @Deprecated
+ public void insertElement(final int offset, final Element element) {
+ Assert.isTrue(offset > rootElement.getStartOffset() && offset <= rootElement.getEndOffset(), MessageFormat.format("Offset must be in [{0}, {1}]", getStartOffset() + 1, getEndOffset()));
+
+ final Element parent = getInsertionParentAt(offset);
+ if (!canInsertAt(parent, offset, element.getQualifiedName())) {
+ throw new DocumentValidationException(MessageFormat.format("Cannot insert element {0} at offset {1}.", element.getQualifiedName(), offset));
}
fireBeforeContentInserted(new DocumentEvent(this, parent, offset, 2, null));
- content.insertElementMarker(offset);
- content.insertElementMarker(offset + 1);
+ getContent().insertElementMarker(offset);
+ getContent().insertElementMarker(offset);
+ element.associate(getContent(), new Range(offset, offset + 1));
- element.setContent(content, offset, offset + 1);
- element.setParent(parent);
- parent.insertChild(childIndex, element);
+ parent.insertChild(parent.getInsertionIndex(offset), element);
final IUndoableEdit edit = undoEnabled ? new InsertElementEdit(offset, element) : null;
-
fireContentInserted(new DocumentEvent(this, parent, offset, 2, edit));
}
- public void insertFragment(final int offset, final DocumentFragment fragment) throws DocumentValidationException {
+ public boolean canInsertFragment(final int offset, final DocumentFragment fragment) {
+ return canInsertAt(getInsertionParentAt(offset), offset, fragment.getNodeNames());
+ }
+ public void insertFragment(final int offset, final DocumentFragment fragment) throws DocumentValidationException {
if (offset < 1 || offset >= getLength()) {
throw new IllegalArgumentException("Error inserting document fragment");
}
- final Element parent = getElementAt(offset);
-
- if (validator != null) {
- final List<QualifiedName> seq1 = getNodeNames(parent.getStartOffset() + 1, offset);
- final List<QualifiedName> seq2 = fragment.getNodeNames();
- final List<QualifiedName> seq3 = getNodeNames(offset, parent.getEndOffset());
-
- if (!validator.isValidSequence(parent.getQualifiedName(), seq1, seq2, seq3, true)) {
- throw new DocumentValidationException("Cannot insert document fragment");
- }
+ if (!canInsertAt(getInsertionParentAt(offset), offset, fragment.getNodeNames())) {
+ throw new DocumentValidationException("Cannot insert document fragment");
}
- fireBeforeContentInserted(new DocumentEvent(this, parent, offset, 2, null));
+ final Element parent = getElementAt(offset);
- final Content c = fragment.getContent();
- final String s = c.getString(0, c.getLength());
- content.insertString(offset, s);
+ fireBeforeContentInserted(new DocumentEvent(this, parent, offset, 2, null));
- final List<Element> children = parent.getChildElements();
- int index = 0;
- while (index < children.size() && children.get(index).getEndOffset() < offset) {
- index++;
- }
+ getContent().insertContent(offset, fragment.getContent());
- final List<Element> elements = fragment.getElements();
- for (int i = 0; i < elements.size(); i++) {
- final Element newElement = cloneElement(elements.get(i), content, offset, parent);
- parent.insertChild(index, newElement);
+ final DeepCopy deepCopy = new DeepCopy(fragment);
+ final List<Node> newNodes = deepCopy.getNodes();
+ int index = parent.getInsertionIndex(offset);
+ for (final Node newNode : newNodes) {
+ parent.insertChild(index, newNode);
+ newNode.associate(getContent(), newNode.getRange().moveBounds(offset));
index++;
}
final IUndoableEdit edit = undoEnabled ? new InsertFragmentEdit(offset, fragment) : null;
- fireContentInserted(new DocumentEvent(this, parent, offset, fragment.getContent().getLength(), edit));
+ fireContentInserted(new DocumentEvent(this, parent, offset, fragment.getContent().length(), edit));
}
- public void insertText(final int offset, final String text) throws DocumentValidationException {
+ public void delete(final Range range) throws DocumentValidationException {
+ final Element surroundingElement = getElementAt(range.getStartOffset() - 1);
+ final Element elementAtEndOffset = getElementAt(range.getEndOffset() + 1);
+ if (surroundingElement != elementAtEndOffset) {
+ throw new IllegalArgumentException("Deletion in " + range + " is unbalanced");
+ }
- if (offset < 1 || offset >= getLength()) {
- throw new IllegalArgumentException("Offset must be between 1 and n-1");
+ final Validator validator = getValidator();
+ if (validator != null) {
+ final List<QualifiedName> seq1 = getNodeNames(surroundingElement.getChildNodesBefore(range.getStartOffset()));
+ final List<QualifiedName> seq2 = getNodeNames(surroundingElement.getChildNodesAfter(range.getEndOffset()));
+
+ if (!validator.isValidSequence(surroundingElement.getQualifiedName(), seq1, seq2, null, true)) {
+ throw new DocumentValidationException("Unable to delete " + range);
+ }
}
- final Element parent = getElementAt(offset);
+ // Grab the fragment for the undoable edit while it's still here
+ final DocumentFragment fragment = getFragment(range);
+
+ fireBeforeContentDeleted(new DocumentEvent(this, surroundingElement, range.getStartOffset(), range.length(), null));
- boolean isValid = false;
- if (!content.isElementMarker(getCharacterAt(offset - 1))) {
- isValid = true;
- } else if (!content.isElementMarker(getCharacterAt(offset))) {
- isValid = true;
- } else {
- final Validator validator = getValidator();
- if (validator != null) {
- final List<QualifiedName> seq1 = getNodeNames(parent.getStartOffset() + 1, offset);
- final List<QualifiedName> seq2 = Collections.singletonList(Validator.PCDATA);
- final List<QualifiedName> seq3 = getNodeNames(offset, parent.getEndOffset());
-
- isValid = validator.isValidSequence(parent.getQualifiedName(), seq1, seq2, seq3, true);
- } else {
- isValid = true;
+ final Iterator<Node> iter = surroundingElement.getChildIterator();
+ while (iter.hasNext()) {
+ final Node child = iter.next();
+ if (child.isInRange(range)) {
+ surroundingElement.removeChild(child);
}
}
- if (!isValid) {
- throw new DocumentValidationException("Cannot insert text '" + text + "' at offset " + offset);
+ getContent().remove(range);
+
+ final IUndoableEdit edit = undoEnabled ? new DeleteEdit(range, fragment) : null;
+
+ fireContentDeleted(new DocumentEvent(this, surroundingElement, range.getStartOffset(), range.length(), edit));
+ }
+
+ public char getCharacterAt(final int offset) {
+ final String text = getContent().getText(new Range(offset, offset));
+ if (text.length() == 0) {
+ /*
+ * XXX This is used in VexWidgetImpl.deleteNextChar/deletePreviousChar to find out if there is an element
+ * marker at the given offset. VexWidgetImpl has no access to Content, so there should be a method in
+ * Document to find out if there is an element at a given offset.
+ */
+ return '\0';
}
+ return text.charAt(0);
+ }
- // Convert control chars to spaces
- final StringBuffer sb = new StringBuffer(text);
- for (int i = 0; i < sb.length(); i++) {
- if (Character.isISOControl(sb.charAt(i)) && sb.charAt(i) != '\n') {
- sb.setCharAt(i, ' ');
+ public Element findCommonElement(final int offset1, final int offset2) {
+ Element element = rootElement;
+ for (;;) {
+ boolean tryAgain = false;
+ final List<Element> children = element.getChildElements();
+ for (int i = 0; i < children.size(); i++) {
+ final Element child = children.get(i);
+ if (child.containsOffset(offset1) && child.containsOffset(offset2)) {
+ element = child;
+ tryAgain = true;
+ break;
+ }
+ }
+ if (!tryAgain) {
+ break;
}
}
+ return element;
+ }
- final String s = sb.toString();
+ public Element getElementAt(final int offset) {
+ return getContainerElement(getChildNodeAt(offset));
+ }
- fireBeforeContentInserted(new DocumentEvent(this, parent, offset, 2, null));
+ private static Element getContainerElement(final Node node) {
+ if (node == null) {
+ return null;
+ }
+ if (node instanceof Element) {
+ return (Element) node;
+ }
+ return getContainerElement(node.getParent());
+ }
+
+ public boolean isElementAt(final int offset) {
+ return getContent().isElementMarker(offset);
+ }
+
+ public DocumentFragment getFragment(final Range range) {
+ final Parent parent = getParentOfRange(range);
+ final DeepCopy deepCopy = new DeepCopy(parent, range);
+ return new DocumentFragment(deepCopy.getContent(), deepCopy.getNodes());
+ }
- content.insertString(offset, s);
+ private Parent getParentOfRange(final Range range) {
+ Assert.isTrue(getRange().contains(range));
- final IUndoableEdit edit = undoEnabled ? new InsertTextEdit(offset, s) : null;
+ final Node startNode = getChildNodeAt(range.getStartOffset());
+ final Node endNode = getChildNodeAt(range.getEndOffset());
+ final Parent parent = startNode.getParent();
+ Assert.isTrue(parent == endNode.getParent(), MessageFormat.format("The fragment in {0} is unbalanced.", range));
+ Assert.isNotNull(parent, MessageFormat.format("No balanced parent found for {0}", range));
- fireContentInserted(new DocumentEvent(this, parent, offset, s.length(), edit));
+ return parent;
}
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.vex.core.internal.dom.IVEXDocument#isUndoEnabled()
- */
- public boolean isUndoEnabled() {
- return undoEnabled;
+ public List<Node> getNodes(final Range range) {
+ return getParentOfRange(range).getChildNodes(range);
}
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.vex.core.internal.dom.IVEXDocument#removeDocumentListener
- * (org.eclipse.vex.core.internal.dom.DocumentListener)
- */
- public void removeDocumentListener(final DocumentListener listener) {
- listeners.remove(listener);
+ public void fireAttributeChanged(final DocumentEvent e) {
+ listeners.fireEvent("attributeChanged", e);
}
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.vex.core.internal.dom.IVEXDocument#setPublicID(java .lang.String)
- */
- public void setPublicID(final String publicID) {
- this.publicID = publicID;
+ public void fireNamespaceChanged(final DocumentEvent e) {
+ listeners.fireEvent("namespaceChanged", e);
}
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.vex.core.internal.dom.IVEXDocument#setSystemID(java .lang.String)
- */
- public void setSystemID(final String systemID) {
- this.systemID = systemID;
+ private void fireBeforeContentDeleted(final DocumentEvent e) {
+ listeners.fireEvent("beforeContentDeleted", e);
}
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.vex.core.internal.dom.IVEXDocument#setUndoEnabled (boolean)
- */
- public void setUndoEnabled(final boolean undoEnabled) {
- this.undoEnabled = undoEnabled;
+ private void fireBeforeContentInserted(final DocumentEvent e) {
+ listeners.fireEvent("beforeContentInserted", e);
}
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.vex.core.internal.dom.IVEXDocument#setValidator(org .eclipse.vex.core.internal.dom.Validator)
- */
- public void setValidator(final Validator validator) {
- this.validator = validator;
+ private void fireContentDeleted(final DocumentEvent e) {
+ listeners.fireEvent("contentDeleted", e);
}
- // ==================================================== PRIVATE
+ private void fireContentInserted(final DocumentEvent e) {
+ listeners.fireEvent("contentInserted", e);
+ }
+
+ // TODO move undoable edits int L2
- /**
- * Represents a deletion from a document that can be undone and redone.
- */
private class DeleteEdit implements IUndoableEdit {
- private final int startOffset;
- private final int endOffset;
- private final DocumentFragment frag;
+ private final Range range;
+ private final DocumentFragment fragment;
- public DeleteEdit(final int startOffset, final int endOffset, final DocumentFragment frag) {
- this.startOffset = startOffset;
- this.endOffset = endOffset;
- this.frag = frag;
+ public DeleteEdit(final Range range, final DocumentFragment fragment) {
+ this.range = range;
+ this.fragment = fragment;
}
public boolean combine(final IUndoableEdit edit) {
@@ -610,7 +512,7 @@ public class Document {
public void undo() throws CannotUndoException {
try {
setUndoEnabled(false);
- insertFragment(startOffset, frag);
+ insertFragment(range.getStartOffset(), fragment);
} catch (final DocumentValidationException ex) {
throw new CannotUndoException();
} finally {
@@ -621,7 +523,7 @@ public class Document {
public void redo() throws CannotRedoException {
try {
setUndoEnabled(false);
- delete(startOffset, endOffset);
+ delete(range);
} catch (final DocumentValidationException ex) {
throw new CannotUndoException();
} finally {
@@ -631,17 +533,14 @@ public class Document {
}
- /**
- * Represents an insertion of an element into the document.
- */
private class InsertElementEdit implements IUndoableEdit {
private final int offset;
private final Element element;
- public InsertElementEdit(final int offset, final Element element2) {
+ public InsertElementEdit(final int offset, final Element element) {
this.offset = offset;
- element = element2;
+ this.element = element;
}
public boolean combine(final IUndoableEdit edit) {
@@ -651,7 +550,7 @@ public class Document {
public void undo() throws CannotUndoException {
try {
setUndoEnabled(false);
- delete(offset, offset + 2);
+ delete(new Range(offset, offset + 2));
} catch (final DocumentValidationException ex) {
throw new CannotUndoException();
} finally {
@@ -662,7 +561,7 @@ public class Document {
public void redo() throws CannotRedoException {
try {
setUndoEnabled(false);
- insertElement(offset, element);
+ insertElement(offset, element.getQualifiedName());
} catch (final DocumentValidationException ex) {
throw new CannotUndoException();
} finally {
@@ -672,9 +571,6 @@ public class Document {
}
- /**
- * Represents an insertion of a fragment into the document.
- */
private class InsertFragmentEdit implements IUndoableEdit {
private final int offset;
@@ -692,8 +588,7 @@ public class Document {
public void undo() throws CannotUndoException {
try {
setUndoEnabled(false);
- final int length = frag.getContent().getLength();
- delete(offset, offset + length);
+ delete(frag.getContent().getRange().moveBounds(offset, offset));
} catch (final DocumentValidationException ex) {
throw new CannotUndoException();
} finally {
@@ -714,9 +609,6 @@ public class Document {
}
- /**
- * Represents an insertion of text into the document.
- */
private class InsertTextEdit implements IUndoableEdit {
private final int offset;
@@ -741,7 +633,7 @@ public class Document {
public void undo() throws CannotUndoException {
try {
setUndoEnabled(false);
- delete(offset, offset + text.length());
+ delete(new Range(offset, offset + text.length()));
} catch (final DocumentValidationException ex) {
throw new CannotUndoException();
} finally {
@@ -762,74 +654,4 @@ public class Document {
}
- /**
- * Assert that the given offset is within the given range, throwing IllegalArgumentException if not.
- */
- private static void assertOffset(final int offset, final int min, final int max) {
- if (offset < min || offset > max) {
- throw new IllegalArgumentException("Bad offset " + offset + "must be between " + min + " and " + max);
- }
- }
-
- /**
- * Clone an element tree, pointing to a new Content object.
- *
- * @param original
- * Element to be cloned
- * @param content
- * new Content object to which the clone will point
- * @param shift
- * amount to shift offsets to be valid in the new Content.
- * @param parent
- * parent for the cloned Element
- */
- private Element cloneElement(final Element original, final Content content, final int shift, final Element parent) {
- final Element clone = original.clone();
- clone.setContent(content, original.getStartOffset() + shift, original.getEndOffset() + shift);
- clone.setParent(parent);
-
- final List<Element> children = original.getChildElements();
- for (int i = 0; i < children.size(); i++) {
- final Element cloneChild = cloneElement(children.get(i), content, shift, clone);
- clone.insertChild(i, cloneChild);
- }
-
- return clone;
- }
-
- public void fireAttributeChanged(final DocumentEvent e) {
- listeners.fireEvent("attributeChanged", e);
- }
-
- public void fireNamespaceChanged(final DocumentEvent e) {
- listeners.fireEvent("namespaceChanged", e);
- }
-
- private void fireBeforeContentDeleted(final DocumentEvent e) {
- listeners.fireEvent("beforeContentDeleted", e);
- }
-
- private void fireBeforeContentInserted(final DocumentEvent e) {
- listeners.fireEvent("beforeContentInserted", e);
- }
-
- private void fireContentDeleted(final DocumentEvent e) {
- listeners.fireEvent("contentDeleted", e);
- }
-
- private void fireContentInserted(final DocumentEvent e) {
- listeners.fireEvent("contentInserted", e);
- }
-
- public void setDocumentURI(final String documentURI) {
- this.documentURI = documentURI;
- }
-
- public String getDocumentURI() {
- return documentURI;
- }
-
- public String getBaseURI() {
- return getDocumentURI();
- }
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentBuilder.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentBuilder.java
index b335f478..838a20ec 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentBuilder.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentBuilder.java
@@ -56,7 +56,7 @@ public class DocumentBuilder implements ContentHandler, LexicalHandler {
private final NamespaceStack namespaceStack = new NamespaceStack();
- private RootElement rootElement;
+ private Element rootElement;
private final String baseUri;
private String dtdPublicID;
@@ -105,7 +105,6 @@ public class DocumentBuilder implements ContentHandler, LexicalHandler {
document = new Document(content, rootElement);
document.setPublicID(dtdPublicID);
document.setSystemID(dtdSystemID);
- rootElement.setDocument(document);
}
public void endElement(final String namespaceURI, final String localName, final String qName) {
@@ -115,8 +114,8 @@ public class DocumentBuilder implements ContentHandler, LexicalHandler {
// we must insert the trailing sentinel first, else the insertion
// pushes the end position of the element to after the sentinel
- content.insertElementMarker(content.getLength());
- entry.element.setContent(content, entry.offset, content.getLength() - 1);
+ content.insertElementMarker(content.length());
+ entry.element.associate(content, new Range(entry.offset, content.length() - 1));
if (isBlock(entry.element)) {
trimLeading = true;
@@ -151,7 +150,7 @@ public class DocumentBuilder implements ContentHandler, LexicalHandler {
}
Element element;
if (stack.isEmpty()) {
- rootElement = new RootElement(elementName);
+ rootElement = new Element(elementName);
element = rootElement;
} else {
element = new Element(elementName);
@@ -193,8 +192,8 @@ public class DocumentBuilder implements ContentHandler, LexicalHandler {
appendChars(isBlock(element));
- stack.add(new StackEntry(element, content.getLength(), isPre(element)));
- content.insertElementMarker(content.getLength());
+ stack.add(new StackEntry(element, content.length(), isPre(element)));
+ content.insertElementMarker(content.length());
trimLeading = true;
@@ -225,21 +224,21 @@ public class DocumentBuilder implements ContentHandler, LexicalHandler {
return;
}
- final CommentElement element = new CommentElement();
+ final Comment comment = new Comment();
final Element parent = stack.getLast().element;
- parent.addChild(element);
+ parent.addChild(comment);
- appendChars(isBlock(element));
- final int startOffset = content.getLength();
- content.insertElementMarker(content.getLength());
+ appendChars(isBlock(comment));
+ final int startOffset = content.length();
+ content.insertElementMarker(content.length());
trimLeading = true;
appendPendingCharsFiltered(ch, start, length);
appendChars(true);
- content.insertElementMarker(content.getLength());
- element.setContent(content, startOffset, content.getLength() - 1);
- if (isBlock(element)) {
+ content.insertElementMarker(content.length());
+ comment.associate(content, new Range(startOffset, content.length() - 1));
+ if (isBlock(comment)) {
trimLeading = true;
}
}
@@ -273,7 +272,7 @@ public class DocumentBuilder implements ContentHandler, LexicalHandler {
sb = cleanUpTextContent(trimTrailing);
- content.insertString(content.getLength(), sb.toString());
+ content.insertText(content.length(), sb.toString());
pendingChars.setLength(0);
trimLeading = false;
@@ -318,12 +317,12 @@ public class DocumentBuilder implements ContentHandler, LexicalHandler {
return sb;
}
- private boolean isBlock(final Element element) {
- return policy != null && policy.isBlock(element);
+ private boolean isBlock(final Node node) {
+ return policy != null && policy.isBlock(node);
}
- private boolean isPre(final Element element) {
- return policy != null && policy.isPre(element);
+ private boolean isPre(final Node node) {
+ return policy != null && policy.isPre(node);
}
/**
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentContentModel.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentContentModel.java
index 3ecbc67b..8f7584b0 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentContentModel.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentContentModel.java
@@ -38,11 +38,11 @@ public class DocumentContentModel implements EntityResolver {
public DocumentContentModel() {
}
- public DocumentContentModel(final String baseUri, final String publicId, final String systemId, final RootElement rootElement) {
+ public DocumentContentModel(final String baseUri, final String publicId, final String systemId, final Element rootElement) {
initialize(baseUri, publicId, systemId, rootElement);
}
- public void initialize(final String baseUri, final String publicId, final String systemId, final RootElement rootElement) {
+ public void initialize(final String baseUri, final String publicId, final String systemId, final Element rootElement) {
this.baseUri = baseUri;
this.publicId = publicId;
this.systemId = systemId;
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentFragment.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentFragment.java
index 22452731..40953688 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentFragment.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentFragment.java
@@ -11,189 +11,69 @@
*******************************************************************************/
package org.eclipse.vex.core.internal.dom;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.Serializable;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.List;
+import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.QualifiedName;
/**
* Represents a fragment of an XML document.
*/
-public class DocumentFragment implements Serializable {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * Mime type representing document fragments: "text/x-vex-document-fragment"
- *
- * @model
- */
- public static final String MIME_TYPE = "application/x-vex-document-fragment";
-
- private Content content;
- private List<Element> elements;
+public class DocumentFragment extends Parent {
/**
- * Class constructor.
- *
* @param content
* Content holding the fragment's content.
- * @param elements
+ * @param nodes
* Elements that make up this fragment.
*/
- public DocumentFragment(final Content content, final List<Element> elements) {
- this.content = content;
- this.elements = elements;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.vex.core.internal.dom.IVEXDocumentFragment#getContent ()
- */
- public Content getContent() {
- return content;
+ public DocumentFragment(final Content content, final List<Node> nodes) {
+ Assert.isTrue(content.length() > 0);
+ associate(content, content.getRange());
+ for (final Node node : nodes) {
+ addChild(node);
+ }
}
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.vex.core.internal.dom.IVEXDocumentFragment#getLength ()
- */
public int getLength() {
- return content.getLength();
+ return getContent().length();
}
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.vex.core.internal.dom.IVEXDocumentFragment#getElements ()
- */
public List<Element> getElements() {
+ final List<Element> elements = new ArrayList<Element>();
+ for (final Node node : getNodes()) {
+ node.accept(new BaseNodeVisitor() {
+ @Override
+ public void visit(final Element element) {
+ elements.add(element);
+ }
+ });
+ }
return elements;
}
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.vex.core.internal.dom.IVEXDocumentFragment#getNodeNames ()
- */
public List<QualifiedName> getNodeNames() {
- final List<Node> nodes = getNodes();
- final List<QualifiedName> names = new ArrayList<QualifiedName>(nodes.size());
- for (final Node node : nodes) {
- if (node instanceof Text) {
- names.add(Validator.PCDATA);
- } else {
- names.add(((Element) node).getQualifiedName());
- }
- }
-
- return names;
+ return Node.getNodeNames(getChildNodes());
}
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.vex.core.internal.dom.IVEXDocumentFragment#getNodes()
- */
public List<Node> getNodes() {
- return Document.createNodeList(getContent(), 0, getContent().getLength(), getNodes(getElements()));
+ return getChildNodes();
}
- private List<Node> getNodes(final List<Element> elements) {
- final List<Node> nodes = new ArrayList<Node>();
- for (final Node node : elements) {
- if (node.getNodeType().equals("Element")) {
- nodes.add(node);
- }
- }
- return nodes;
+ @Override
+ public String getBaseURI() {
+ return null;
}
- /*
- * Custom Serialization Methods
- */
-
- private void writeObject(final ObjectOutputStream out) throws IOException {
- out.writeUTF(content.getString(0, content.getLength()));
- out.writeInt(elements.size());
- for (int i = 0; i < elements.size(); i++) {
- writeElement(elements.get(i), out);
- }
- }
-
- private void writeElement(final Element element, final ObjectOutputStream out) throws IOException {
-
- out.writeObject(element.getQualifiedName());
- out.writeInt(element.getStartOffset());
- out.writeInt(element.getEndOffset());
- final Collection<Attribute> attributes = element.getAttributes();
- out.writeInt(attributes.size());
- for (final Attribute attribute : attributes) {
- out.writeObject(attribute.getQualifiedName());
- out.writeObject(attribute.getValue());
- }
- final List<Element> children = element.getChildElements();
- out.writeInt(children.size());
- for (int i = 0; i < children.size(); i++) {
- writeElement(children.get(i), out);
- }
- }
-
- private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
- final String s = in.readUTF();
- content = new GapContent(s.length());
- content.insertString(0, s);
- final int n = in.readInt();
- elements = new ArrayList<Element>(n);
- for (int i = 0; i < n; i++) {
- elements.add(readElement(in));
- }
+ @Override
+ public void accept(final INodeVisitor visitor) {
+ visitor.visit(this);
}
- private Element readElement(final ObjectInputStream in) throws IOException, ClassNotFoundException {
- final QualifiedName elementName = createQualifiedName(in.readObject());
- final int startOffset = in.readInt();
- final int endOffset = in.readInt();
- final Element element = new Element(elementName);
- element.setContent(content, startOffset, endOffset);
-
- final int attrCount = in.readInt();
- for (int i = 0; i < attrCount; i++) {
- final QualifiedName attributeName = createQualifiedName(in.readObject());
- final String value = (String) in.readObject();
- try {
- element.setAttribute(attributeName, value);
- } catch (final DocumentValidationException e) {
- // Should never happen; there ain't no document
- e.printStackTrace();
- }
- }
-
- final int childCount = in.readInt();
- for (int i = 0; i < childCount; i++) {
- final Element child = readElement(in);
- child.setParent(element);
- element.insertChild(i, child);
- }
-
- return element;
+ @Override
+ public <T> T accept(final INodeVisitorWithResult<T> visitor) {
+ return visitor.visit(this);
}
- private static QualifiedName createQualifiedName(final Object object) {
- final String serializedQualifiedName = object.toString();
- final int localNameStartIndex = serializedQualifiedName.lastIndexOf(':') + 1;
- if (localNameStartIndex == 0) {
- return new QualifiedName(null, serializedQualifiedName);
- }
- final String qualifier = serializedQualifiedName.substring(0, localNameStartIndex - 1);
- final String localName = serializedQualifiedName.substring(localNameStartIndex);
- return new QualifiedName(qualifier, localName);
- }
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentWriter.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentWriter.java
index cde09924..724e8fa9 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentWriter.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentWriter.java
@@ -169,16 +169,19 @@ public class DocumentWriter {
pw.print(indent);
pw.println(line);
}
- } else if (node instanceof CommentElement) {
-
- final CommentElement element = (CommentElement) node;
-
+ } else if (node instanceof Comment) {
pw.print(indent);
pw.println("<!-- ");
final String childIndent = indent + this.indent;
- for (final Node child : element.getChildNodes()) {
- writeNode(child, pw, childIndent);
+ // TODO writeText(node.getText(), pw, childIndent);
+ final TextWrapper wrapper = new TextWrapper();
+ wrapper.add(escape(node.getText()));
+ final String[] lines = wrapper.wrap(wrapColumn - childIndent.length());
+
+ for (final String line : lines) {
+ pw.print(childIndent);
+ pw.println(line);
}
pw.print(indent);
@@ -251,14 +254,9 @@ public class DocumentWriter {
if (node instanceof Text) {
pw.print(escape(node.getText()));
- } else if (node instanceof CommentElement) {
-
- final CommentElement element = (CommentElement) node;
-
+ } else if (node instanceof Comment) {
pw.print("<!-- ");
- for (final Node child : element.getChildNodes()) {
- writeNodeNoWrap(child, pw);
- }
+ pw.print(escape(node.getText()));
pw.print(" -->");
} else {
@@ -295,16 +293,10 @@ public class DocumentWriter {
private static void addNode(final Node node, final TextWrapper wrapper) {
if (node instanceof Text) {
wrapper.add(escape(node.getText()));
- } else if (node instanceof CommentElement) {
-
- final CommentElement element = (CommentElement) node;
+ } else if (node instanceof Comment) {
wrapper.addNoSplit("<!-- ");
-
- for (final Node child : element.getChildNodes()) {
- addNode(child, wrapper);
- }
-
+ wrapper.add(escape(node.getText()));
wrapper.add(" -->");
} else {
final Element element = (Element) node;
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 800aacb1..f203ab11 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
@@ -16,7 +16,6 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -30,14 +29,18 @@ import org.eclipse.vex.core.internal.undo.IUndoableEdit;
/**
* Represents a tag in an XML document. Methods are available for managing the element's attributes and children.
*/
-public class Element extends Node implements Cloneable {
+public class Element extends Parent {
+ /**
+ * The xml:base attribute re-defines the base URI for a part of an XML document, according to the XML Base
+ * Recommendation.
+ *
+ * @see http://www.w3.org/TR/xmlbase/
+ */
private static final QualifiedName XML_BASE_ATTRIBUTE = new QualifiedName(Namespace.XML_NAMESPACE_URI, "base");
private final QualifiedName name;
- private Element parent = null;
- private final List<Node> childNodes = new ArrayList<Node>();
private final Map<QualifiedName, Attribute> attributes = new HashMap<QualifiedName, Attribute>();
private final Map<String, String> namespaceDeclarations = new HashMap<String, String>();
@@ -49,31 +52,22 @@ public class Element extends Node implements Cloneable {
name = qualifiedName;
}
- public void addChild(final Element child) {
- childNodes.add(child);
- child.setParent(this);
+ @Override
+ public boolean isKindOf(final Node node) {
+ if (!(node instanceof Element)) {
+ return false;
+ }
+ return getQualifiedName().equals(((Element) node).getQualifiedName());
}
@Override
- public Element clone() {
- try {
- final Element element = new Element(getQualifiedName());
- //add the attributes to the element instance to be cloned
- for (final Map.Entry<QualifiedName, Attribute> attr : attributes.entrySet()) {
- element.setAttribute(attr.getKey(), attr.getValue().getValue());
- }
- for (final Map.Entry<String, String> namespaceDeclaration : namespaceDeclarations.entrySet()) {
- if (namespaceDeclaration.getKey() == null) {
- element.declareDefaultNamespace(namespaceDeclaration.getValue());
- } else {
- element.declareNamespace(namespaceDeclaration.getKey(), namespaceDeclaration.getValue());
- }
- }
- return element;
- } catch (final DocumentValidationException ex) {
- ex.printStackTrace();
- return null;
- }
+ public void accept(final INodeVisitor visitor) {
+ visitor.visit(this);
+ }
+
+ @Override
+ public <T> T accept(final INodeVisitorWithResult<T> visitor) {
+ return visitor.visit(this);
}
public Attribute getAttribute(final String localName) {
@@ -171,39 +165,20 @@ public class Element extends Node implements Cloneable {
return result;
}
- public Iterator<Node> getChildIterator() {
- return childNodes.iterator();
- }
-
public List<Element> getChildElements() {
final List<Node> nodes = getChildNodes();
- final Iterator<Node> iter = nodes.iterator();
final List<Element> elements = new ArrayList<Element>();
- while (iter.hasNext()) {
- final Node node = iter.next();
- if (node.getNodeType().equals("Element")) {
- elements.add((Element) node);
- }
+ for (final Node node : nodes) {
+ node.accept(new BaseNodeVisitor() {
+ @Override
+ public void visit(final Element element) {
+ elements.add(element);
+ }
+ });
}
return elements;
}
- public List<Node> getChildNodes() {
- return Document.createNodeList(getContent(), getStartOffset() + 1, getEndOffset(), childNodes);
- }
-
- public Document getDocument() {
- Element root = this;
- while (root.getParent() != null) {
- root = root.getParent();
- }
- if (root instanceof RootElement) {
- return root.getDocument();
- } else {
- return null;
- }
- }
-
public String getLocalName() {
return name.getLocalName();
}
@@ -224,32 +199,6 @@ public class Element extends Node implements Cloneable {
return prefix + ":" + getLocalName();
}
- public Element getParent() {
- return parent;
- }
-
- @Override
- public String getText() {
- final String s = super.getText();
- final StringBuilder sb = new StringBuilder(s.length());
- for (int i = 0; i < s.length(); i++) {
- final char c = s.charAt(i);
- if (!getContent().isElementMarker(c)) {
- sb.append(c);
- }
- }
- return sb.toString();
- }
-
- /**
- * Inserts the given element as a child at the given child index. Sets the parent attribute of the given element to
- * this element.
- */
- public void insertChild(final int index, final Element child) {
- childNodes.add(index, child);
- child.setParent(this);
- }
-
public boolean isEmpty() {
return getStartOffset() + 1 == getEndOffset();
}
@@ -270,22 +219,38 @@ public class Element extends Node implements Cloneable {
}
sb.append("> (");
- sb.append(getStartPosition());
- sb.append(",");
- sb.append(getEndPosition());
+ if (isAssociated()) {
+ sb.append(getStartOffset());
+ sb.append(",");
+ sb.append(getEndOffset());
+ } else {
+ sb.append("n/a");
+ }
sb.append(")");
return sb.toString();
}
- public void setParent(final Element parent) {
- this.parent = parent;
+ public Element getParentElement() {
+ return getParentElement(this);
+ }
+
+ private static Element getParentElement(final Node node) {
+ final Node parent = node.getParent();
+ if (parent == null) {
+ return null;
+ }
+ if (parent instanceof Element) {
+ return (Element) parent;
+ }
+ return getParentElement(parent);
}
public String getNamespaceURI(final String namespacePrefix) {
if (namespaceDeclarations.containsKey(namespacePrefix)) {
return namespaceDeclarations.get(namespacePrefix);
}
+ final Element parent = getParentElement();
if (parent != null) {
return parent.getNamespaceURI(namespacePrefix);
}
@@ -315,6 +280,7 @@ public class Element extends Node implements Cloneable {
return entry.getKey();
}
}
+ final Element parent = getParentElement();
if (parent != null) {
final String parentPrefix = parent.getNamespacePrefix(namespaceURI);
if (!namespaceDeclarations.containsKey(parentPrefix)) {
@@ -338,6 +304,7 @@ public class Element extends Node implements Cloneable {
public Collection<String> getNamespacePrefixes() {
final HashSet<String> result = new HashSet<String>();
result.addAll(getDeclaredNamespacePrefixes());
+ final Element parent = getParentElement();
if (parent != null) {
result.addAll(parent.getNamespacePrefixes());
}
@@ -386,16 +353,6 @@ public class Element extends Node implements Cloneable {
}
@Override
- public String getNodeType() {
- return "Element";
- }
-
- @Override
- public void setContent(final Content content, final int startOffset, final int endOffset) {
- super.setContent(content, startOffset, endOffset);
- }
-
- @Override
public String getBaseURI() {
final Attribute baseAttribute = getAttribute(XML_BASE_ATTRIBUTE);
if (baseAttribute != null) {
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 de213143..83b72b16 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
@@ -11,8 +11,10 @@
*******************************************************************************/
package org.eclipse.vex.core.internal.dom;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.core.runtime.Assert;
/**
* Implementation of the <code>Content</code> interface that manages changes efficiently. Implements a buffer that keeps
@@ -27,7 +29,7 @@ public class GapContent implements Content {
private char[] content;
private int gapStart;
private int gapEnd;
- private final Map<Position, Position> positions = new HashMap<Position, Position>();
+ private final Set<GapContentPosition> positions = new HashSet<GapContentPosition>();
/**
* Class constructor.
@@ -51,12 +53,22 @@ public class GapContent implements Content {
*/
public Position createPosition(final int offset) {
- assertOffset(offset, 0, getLength());
+ assertOffset(offset, 0, length());
+
+ final GapContentPosition position = new GapContentPosition(offset);
+ positions.add(position);
- final Position pos = new GapContentPosition(offset);
- positions.put(pos, pos);
+ return position;
+ }
- return pos;
+ public void removePosition(final Position position) {
+ if (positions.remove(position)) {
+ /*
+ * This cast is save: if the position can be removed, this instance must have created it, hence it is a
+ * GapContentPosition.
+ */
+ ((GapContentPosition) position).invalidate();
+ }
}
/**
@@ -67,12 +79,11 @@ public class GapContent implements Content {
* @param s
* String to insert.
*/
- public void insertString(final int offset, final String s) {
-
- assertOffset(offset, 0, getLength());
+ public void insertText(final int offset, final String s) {
+ assertOffset(offset, 0, length());
if (s.length() > gapEnd - gapStart) {
- expandContent(getLength() + s.length());
+ expandContent(length() + s.length());
}
//
@@ -82,7 +93,7 @@ public class GapContent implements Content {
//
// This significantly improves document load speed.
//
- final boolean atEnd = offset == getLength() && offset == gapStart;
+ final boolean atEnd = offset == length() && offset == gapStart;
moveGap(offset);
s.getChars(0, s.length(), content, offset);
@@ -91,9 +102,9 @@ public class GapContent implements Content {
if (!atEnd) {
// Update positions
- for (final Position pos : positions.keySet()) {
- if (pos.getOffset() >= offset) {
- pos.setOffset(pos.getOffset() + s.length());
+ for (final GapContentPosition position : positions) {
+ if (position.getOffset() >= offset) {
+ position.setOffset(position.getOffset() + s.length());
}
}
@@ -101,10 +112,27 @@ public class GapContent implements Content {
}
public void insertElementMarker(final int offset) {
- insertString(offset, Character.toString(ELEMENT_MARKER));
+ assertOffset(offset, 0, length());
+
+ insertText(offset, Character.toString(ELEMENT_MARKER));
}
- public boolean isElementMarker(final char c) {
+ public boolean isElementMarker(final int offset) {
+ if (offset < 0 || offset >= length()) {
+ return false;
+ }
+
+ return isElementMarker(content[getIndex(offset)]);
+ }
+
+ private int getIndex(final int offset) {
+ if (offset < gapStart) {
+ return offset;
+ }
+ return offset + gapEnd - gapStart;
+ }
+
+ private boolean isElementMarker(final char c) {
return c == ELEMENT_MARKER;
}
@@ -116,53 +144,144 @@ public class GapContent implements Content {
* @param length
* Number of characters to delete.
*/
- public void remove(final int offset, final int length) {
+ public void remove(final Range range) {
+ assertOffset(range.getStartOffset(), 0, length() - range.length());
+ assertPositive(range.length());
+
+ moveGap(range.getEndOffset() + 1);
+ gapStart -= range.length();
+
+ for (final GapContentPosition position : positions) {
+ if (position.getOffset() > range.getEndOffset()) {
+ position.setOffset(position.getOffset() - range.length());
+ } else if (position.getOffset() >= range.getStartOffset()) {
+ position.setOffset(range.getStartOffset());
+ }
+ }
+ }
+
+ public String getText() {
+ return getText(getRange());
+ }
- assertOffset(offset, 0, getLength() - length);
- assertPositive(length);
+ public String getText(final Range range) {
+ Assert.isTrue(getRange().contains(range));
- moveGap(offset + length);
- gapStart -= length;
+ final int delta = gapEnd - gapStart;
+ final StringBuilder result = new StringBuilder();
+ if (range.getEndOffset() < gapStart) {
+ appendPlainText(result, range);
+ } else if (range.getStartOffset() >= gapStart) {
+ appendPlainText(result, range.moveBounds(delta, delta));
+ } else {
+ appendPlainText(result, new Range(range.getStartOffset(), gapStart - 1));
+ appendPlainText(result, new Range(gapEnd, range.getEndOffset() + delta));
+ }
+ return result.toString();
+ }
- for (final Position pos : positions.keySet()) {
- if (pos.getOffset() >= offset + length) {
- pos.setOffset(pos.getOffset() - length);
- } else if (pos.getOffset() >= offset) {
- pos.setOffset(offset);
+ private void appendPlainText(final StringBuilder stringBuilder, final Range range) {
+ for (int i = range.getStartOffset(); range.contains(i); i++) {
+ final char c = content[i];
+ if (!isElementMarker(c)) {
+ stringBuilder.append(c);
+ }
+ }
+ }
+
+ public String getRawText() {
+ return getRawText(getRange());
+ }
+
+ public String getRawText(final Range range) {
+ Assert.isTrue(getRange().contains(range));
+
+ final int delta = gapEnd - gapStart;
+ final StringBuilder result = new StringBuilder();
+ if (range.getEndOffset() < gapStart) {
+ appendRawText(result, range);
+ } else if (range.getStartOffset() >= gapStart) {
+ appendRawText(result, range.moveBounds(delta, delta));
+ } else {
+ appendRawText(result, new Range(range.getStartOffset(), gapStart - 1));
+ appendRawText(result, new Range(gapEnd, range.getEndOffset() + delta));
+ }
+ return result.toString();
+ }
+
+ private void appendRawText(final StringBuilder stringBuilder, final Range range) {
+ stringBuilder.append(content, range.getStartOffset(), range.length());
+ }
+
+ public void insertContent(final int offset, final Content content) {
+ assertOffset(offset, 0, length());
+
+ copyContent(content, this, content.getRange(), offset);
+ }
+
+ public Content getContent() {
+ return getContent(getRange());
+ }
+
+ public Content getContent(final Range range) {
+ Assert.isTrue(getRange().contains(range));
+
+ final GapContent result = new GapContent(range.length());
+ copyContent(this, result, range, 0);
+ return result;
+ }
+
+ private static void copyContent(final Content source, final Content destination, final Range sourceRange, final int destinationStartOffset) {
+ for (int i = 0; i < sourceRange.length(); i++) {
+ final int sourceOffset = sourceRange.getStartOffset() + i;
+ final int destinationOffset = destinationStartOffset + i;
+ if (source.isElementMarker(sourceOffset)) {
+ destination.insertElementMarker(destinationOffset);
+ } else {
+ destination.insertText(destinationOffset, Character.toString(source.charAt(sourceOffset)));
}
}
}
/**
- * Gets a substring of the content.
- *
- * @param offset
- * Offset at which the string begins.
- * @param length
- * Number of characters to return.
+ * @see CharSequence#length()
+ * @return the length of the raw textual content, including element markers.
*/
- public String getString(final int offset, final int length) {
+ public int length() {
+ return content.length - (gapEnd - gapStart);
+ }
- assertOffset(offset, 0, getLength() - length);
- assertPositive(length);
+ public Range getRange() {
+ return new Range(0, length() - 1);
+ }
- if (offset + length <= gapStart) {
- return new String(content, offset, length);
- } else if (offset >= gapStart) {
- return new String(content, offset - gapStart + gapEnd, length);
+ /**
+ * @see CharSequence#charAt(int)
+ * @param offset
+ * the offset of the character within the raw textual content
+ * @return the character at the given offset (element markers included)
+ */
+ public char charAt(final int offset) {
+ if (offset < gapStart) {
+ return content[offset];
} else {
- final StringBuffer sb = new StringBuffer(length);
- sb.append(content, offset, gapStart - offset);
- sb.append(content, gapEnd, offset + length - gapStart);
- return sb.toString();
+ return content[offset - gapStart + gapEnd];
}
}
/**
- * Return the length of the content.
+ * Get the raw text of a region of this content. The plain text does also contain the element markers in this
+ * content.
+ *
+ * @see CharSequence#subSequence(int, int)
+ * @param startOffset
+ * Offset at which the substring begins.
+ * @param endOffset
+ * Offset at which the substring ends.
+ * @return the text of the given region including element markers
*/
- public int getLength() {
- return content.length - (gapEnd - gapStart);
+ public CharSequence subSequence(final int startOffset, final int endOffset) {
+ return getRawText(new Range(startOffset, endOffset));
}
// ====================================================== PRIVATE
@@ -178,6 +297,8 @@ public class GapContent implements Content {
private int offset;
+ private boolean valid = true;
+
public GapContentPosition(final int offset) {
this.offset = offset;
}
@@ -190,6 +311,14 @@ public class GapContent implements Content {
this.offset = offset;
}
+ public boolean isValid() {
+ return valid;
+ };
+
+ public void invalidate() {
+ valid = false;
+ }
+
@Override
public String toString() {
return Integer.toString(offset);
@@ -201,7 +330,7 @@ public class GapContent implements Content {
*/
private static void assertOffset(final int offset, final int min, final int max) {
if (offset < min || offset > max) {
- throw new IllegalArgumentException("Bad offset " + offset + "must be between " + min + " and " + max);
+ throw new IllegalArgumentException("Bad offset " + offset + " must be between " + min + " and " + max);
}
}
@@ -245,7 +374,7 @@ public class GapContent implements Content {
*/
private void moveGap(final int offset) {
- assertOffset(offset, 0, getLength());
+ assertOffset(offset, 0, length());
if (offset <= gapStart) {
final int length = gapStart - offset;
@@ -259,4 +388,5 @@ public class GapContent implements Content {
gapEnd += length;
}
}
+
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/CommentElement.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/INodeVisitor.java
index b9c77a59..04c2699f 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/CommentElement.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/INodeVisitor.java
@@ -10,24 +10,23 @@
*******************************************************************************/
package org.eclipse.vex.core.internal.dom;
-import org.eclipse.core.runtime.QualifiedName;
-
/**
- * Represents a comment
+ * An incarantion of the <a href="http://en.wikipedia.org/wiki/Visitor_pattern">Visitor pattern</a> which handles the
+ * nodes of the structural part of the DOM.
+ *
+ * @author Florian Thienel
+ *
*/
-public class CommentElement extends Element {
+public interface INodeVisitor {
+
+ void visit(Document document);
- public static final QualifiedName ELEMENT_NAME = new QualifiedName(null, "<!-- COMMENT -->");
+ void visit(DocumentFragment fragment);
- public static final String CSS_RULE_NAME = "COMMENT";
+ void visit(Element element);
- public CommentElement() {
- super(ELEMENT_NAME);
- }
+ void visit(Text text);
- @Override
- public CommentElement clone() {
- return new CommentElement();
- }
+ void visit(Comment comment);
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/INodeVisitorWithResult.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/INodeVisitorWithResult.java
new file mode 100644
index 00000000..d2143a31
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/INodeVisitorWithResult.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2012 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.dom;
+
+/**
+ * An incarantion of the <a href="http://en.wikipedia.org/wiki/Visitor_pattern">Visitor pattern</a> which handles the
+ * nodes of the structural part of the DOM and is able to return a value of a certain type.
+ *
+ * @author Florian Thienel
+ *
+ */
+public interface INodeVisitorWithResult<T> {
+
+ T visit(Document document);
+
+ T visit(DocumentFragment fragment);
+
+ T visit(Element element);
+
+ T visit(Text text);
+
+ T visit(Comment comment);
+
+}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/IWhitespacePolicy.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/IWhitespacePolicy.java
index cfe8ce11..06946607 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/IWhitespacePolicy.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/IWhitespacePolicy.java
@@ -20,11 +20,11 @@ public interface IWhitespacePolicy {
* A NULL object of this type. No blocks and no pre elements.
*/
IWhitespacePolicy NULL = new IWhitespacePolicy() {
- public boolean isBlock(final Element element) {
+ public boolean isBlock(final Node node) {
return false;
}
- public boolean isPre(final Element element) {
+ public boolean isPre(final Node node) {
return false;
}
};
@@ -35,7 +35,7 @@ public interface IWhitespacePolicy {
* @param element
* Element to test.
*/
- boolean isBlock(Element element);
+ boolean isBlock(Node node);
/**
* Returns true if the given element is pre-formatted, that is, all of its contained whitespace should be preserved.
@@ -43,5 +43,5 @@ public interface IWhitespacePolicy {
* @param element
* Element to test.
*/
- boolean isPre(Element element);
+ boolean isPre(Node node);
}
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 f72cda7d..ec4dd246 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
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2008 John Krasnay and others.
+ * Copyright (c) 2004, 2012 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
@@ -10,57 +10,227 @@
*******************************************************************************/
package org.eclipse.vex.core.internal.dom;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.QualifiedName;
+
/**
- * <code>Node</code> represents a component of an XML document. .
- *
+ * This class represents one node within the XML structure, which is also associated to a region of the textual content.
+ * It is the base class for all representatives of the XML structure in the document object model (DOM).
*/
public abstract class Node {
+ private Parent parent;
private Content content;
- private Position startPosition;
- private Position endPosition;
+ private Position startPosition = Position.NULL;
+ private Position endPosition = Position.NULL;
+
+ /**
+ * @see Parent
+ * @return the parent of this node, maybe null if this node has no parent
+ */
+ public Parent getParent() {
+ return parent;
+ }
+
+ /**
+ * @see Parent
+ * @param parent
+ * the parent of this node, maybe null if this node should not have a parent
+ */
+ public void setParent(final Parent parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * Associates this node to a region within the given content.
+ *
+ * @param content
+ * Content object holding the node's content
+ * @param startOffset
+ * offset at which the node's content starts
+ * @param endOffset
+ * offset at which the node's content ends
+ */
+ public void associate(final Content content, final Range range) {
+ if (isAssociated()) {
+ dissociate();
+ }
+ this.content = content;
+ startPosition = content.createPosition(range.getStartOffset());
+ endPosition = content.createPosition(range.getEndOffset());
+ }
+
+ /**
+ * Dissociates this node from its associated content region.
+ */
+ public void dissociate() {
+ Assert.isTrue(isAssociated(), "Node must be associated to a Content region before it can be dissociated.");
+
+ content.removePosition(startPosition);
+ content.removePosition(endPosition);
+ startPosition = Position.NULL;
+ endPosition = Position.NULL;
+ content = null;
+ }
+
+ /**
+ * @return if this node is associated to content
+ */
+ public boolean isAssociated() {
+ return content != null;
+ }
+
+ /**
+ * @return the content to which this node is associated or null if this node is not associated to any content yet
+ */
public Content getContent() {
return content;
}
+ /**
+ * The start offset of this node, which eventually also includes the position of an element marker.
+ *
+ * @return the start offset of this node within the textual content
+ */
+ public int getStartOffset() {
+ Assert.isTrue(isAssociated(), "Node must be associated to a Content region to have a start offset.");
+ return startPosition.getOffset();
+ }
+
+ /**
+ * The end offset of this node, which eventually also includes the position of an element marker.
+ *
+ * @return the end offset of this node within the textual content
+ */
public int getEndOffset() {
+ Assert.isTrue(isAssociated(), "Node must be associated to a Content region to have an end offset.");
return endPosition.getOffset();
}
- public Position getEndPosition() {
- return endPosition;
+ public Range getRange() {
+ return new Range(getStartOffset(), getEndOffset());
}
- public int getStartOffset() {
- return startPosition.getOffset();
+ /**
+ * Indicates whether the given offset is within the boundaries of this node. If this node is not associated with
+ * textual content, this method returns false.
+ *
+ * @param offset
+ * the offset
+ * @return true if the given offset is withing [startOffset; endOffset], or false if not associated
+ */
+ public boolean containsOffset(final int offset) {
+ if (!isAssociated()) {
+ return false;
+ }
+ return getRange().contains(offset);
}
- public Position getStartPosition() {
- return startPosition;
+ /**
+ * Indicates whether this node is fully within the given range. If this node is not associated with textual content,
+ * this method returns false.
+ *
+ * @param startOffset
+ * the range's start offset
+ * @param endOffset
+ * the range's end offst
+ * @return true if this node is fully within the given range
+ */
+ public boolean isInRange(final Range range) {
+ if (!isAssociated()) {
+ return false;
+ }
+ return range.contains(getRange());
}
+ /**
+ * The textual content, not inluding any element markers.
+ *
+ * @return the textual content of this node
+ */
public String getText() {
- return content.getString(getStartOffset(), getEndOffset() - getStartOffset());
+ return getText(getRange());
}
/**
- * Sets the content of this node
+ * The textual content in the given range, not including any element markers.
*
- * @param content
- * Content object holding the node's content
* @param startOffset
- * offset at which the node's content starts
+ * the start offset
* @param endOffset
- * offset at which the node's content ends
+ * the end offset
+ * @return the textual content in the given range
*/
- public void setContent(final Content content, final int startOffset, final int endOffset) {
- this.content = content;
- startPosition = content.createPosition(startOffset);
- endPosition = content.createPosition(endOffset);
+ public String getText(final Range range) {
+ Assert.isTrue(isAssociated(), "Node must be associated to a Content region to have textual content.");
+ return content.getText(range.trimTo(getRange()));
+ }
+
+ public Document getDocument() {
+ return getDocument(this);
+ }
+
+ private static Document getDocument(final Node node) {
+ if (node instanceof Document) {
+ return (Document) node;
+ }
+ final Parent parent = node.getParent();
+ if (parent == null) {
+ return null;
+ }
+ if (parent instanceof Document) {
+ return (Document) parent;
+ }
+ return getDocument(parent);
}
- public abstract String getNodeType();
+ public boolean isKindOf(final Node node) {
+ return false;
+ }
public abstract String getBaseURI();
+
+ /**
+ * Accept the given visitor.
+ *
+ * @see INodeVisitor
+ * @param visitor
+ * the visitor
+ */
+ public abstract void accept(final INodeVisitor visitor);
+
+ /**
+ * Accept the given visitor.
+ *
+ * @see INodeVisitorWithResult
+ * @param visitor
+ * the visitor
+ */
+ public abstract <T> T accept(final INodeVisitorWithResult<T> visitor);
+
+ public static List<QualifiedName> getNodeNames(final Collection<Node> nodes) {
+ final List<QualifiedName> names = new ArrayList<QualifiedName>(nodes.size());
+
+ for (final Node node : nodes) {
+ node.accept(new BaseNodeVisitor() {
+ @Override
+ public void visit(final Text text) {
+ names.add(Validator.PCDATA);
+ }
+
+ @Override
+ public void visit(final Element element) {
+ names.add(element.getQualifiedName());
+ }
+ });
+ }
+
+ return names;
+ }
+
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/NodeTraversal.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/NodeTraversal.java
new file mode 100644
index 00000000..abf6f609
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/NodeTraversal.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2012 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.dom;
+
+/**
+ * @author Florian Thienel
+ */
+public class NodeTraversal {
+
+ private final INodeVisitor nodeVisitor;
+ private final TraversalVisitor traversalVisitor;
+
+ public NodeTraversal(final INodeVisitor nodeVisitor) {
+ this.nodeVisitor = nodeVisitor;
+ traversalVisitor = new TraversalVisitor();
+ }
+
+ public void traverse(final Node... nodes) {
+ for (final Node node : nodes) {
+ node.accept(traversalVisitor);
+ }
+ }
+
+ private class TraversalVisitor implements INodeVisitor {
+
+ public void visit(final Document document) {
+ visitParent(document);
+ }
+
+ public void visit(final DocumentFragment fragment) {
+ visitParent(fragment);
+ }
+
+ public void visit(final Element element) {
+ visitParent(element);
+ }
+
+ private void visitParent(final Parent parent) {
+ parent.accept(nodeVisitor);
+ for (final Node child : parent.getChildNodes()) {
+ child.accept(traversalVisitor);
+ }
+ }
+
+ public void visit(final Text text) {
+ text.accept(nodeVisitor);
+ }
+
+ public void visit(final Comment comment) {
+ comment.accept(nodeVisitor);
+ }
+ }
+
+}
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
new file mode 100644
index 00000000..3eedc391
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Parent.java
@@ -0,0 +1,225 @@
+/*******************************************************************************
+ * Copyright (c) 2012 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.dom;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.Assert;
+
+/**
+ * A Parent node is a Node which can contain other nodes as children. This class defines the tree-like structure of the
+ * DOM. It handles the mergin of the child nodes and the textual content of one node within the structure of the
+ * document.
+ *
+ * @author Florian Thienel
+ */
+public abstract class Parent extends Node {
+
+ private final List<Node> children = new ArrayList<Node>();
+
+ /**
+ * Append the given child node to the end of the list of children. The parent attribute of the child is set to this
+ * node.
+ *
+ * @param child
+ * the new child node
+ */
+ public void addChild(final Node child) {
+ children.add(child);
+ child.setParent(this);
+ }
+
+ /**
+ * Insert the given child node into the list of children at the given index. The children from the child with the
+ * given index until the last child will be moved forward by one position. The parent attribute of the child is set
+ * to this node.
+ *
+ * @param index
+ * the index at which the child should be inserted.
+ * @param child
+ * the child node to insert
+ */
+ public void insertChild(final int index, final Node child) {
+ children.add(index, child);
+ child.setParent(this);
+ }
+
+ public int getInsertionIndex(final int offset) {
+ Assert.isTrue(getStartOffset() < offset && offset <= getEndOffset(), MessageFormat.format("The offset must be within [{0}, {1}].", getStartOffset() + 1, getEndOffset()));
+ int i = 0;
+ for (final Iterator<Node> iterator = children.iterator(); iterator.hasNext(); i++) {
+ final Node child = iterator.next();
+ if (offset <= child.getStartOffset()) {
+ return i;
+ }
+ }
+ return children.size();
+ }
+
+ /**
+ * Remove the given child node from the list of children. The parent attribute of the child will be set to null.
+ *
+ * @param child
+ * the child node to remove
+ */
+ public void removeChild(final Node child) {
+ children.remove(child);
+ child.setParent(null);
+ }
+
+ /**
+ * Returns a list of all child nodes of this parent node, including Text nodes for the textual content.
+ *
+ * @return all child nodes including Text nodes
+ */
+ public List<Node> getChildNodes() {
+ if (!isAssociated()) {
+ return Collections.unmodifiableList(children);
+ }
+
+ return getChildNodes(getRange());
+ }
+
+ /**
+ * Returns a list of all child nodes (including Text nodes) in the given range. The Text nodes are cut at the edges,
+ * all other nodes must be fully contained in the range (i.e. the start tag and the end tag). The returned list is
+ * not modifyable.
+ *
+ * @param startOffset
+ * the start offset of the range
+ * @param endOffset
+ * the end offset of the range
+ * @return all child nodes which are completely within the given range plus the textual content
+ */
+ public List<Node> getChildNodes(final Range range) {
+ final List<Node> result = new ArrayList<Node>();
+
+ final Range trimmedRange = range.trimTo(getRange());
+ int textStart = trimmedRange.getStartOffset();
+ for (final Node child : children) {
+ if (!child.isAssociated()) {
+ result.add(child);
+ } else if (child.isInRange(trimmedRange)) {
+ mergeTextIntoResult(textStart, child.getStartOffset(), result);
+ result.add(child);
+ textStart = child.getEndOffset() + 1;
+ }
+ }
+
+ mergeTextIntoResult(textStart, trimmedRange.getEndOffset(), result);
+ return Collections.unmodifiableList(result);
+ }
+
+ private void mergeTextIntoResult(final int startOffset, final int endOffset, final List<Node> result) {
+ final int textStart = findNextTextStart(startOffset, endOffset);
+ final int textEnd = findNextTextEnd(endOffset, textStart);
+ if (textStart < textEnd) {
+ result.add(new Text(this, getContent(), new Range(textStart, textEnd)));
+ } else if (textStart == textEnd && !getContent().isElementMarker(textStart)) {
+ result.add(new Text(this, getContent(), new Range(textStart, textEnd)));
+ }
+ }
+
+ private int findNextTextStart(int currentOffset, final int maximumOffset) {
+ while (currentOffset < maximumOffset && getContent().isElementMarker(currentOffset)) {
+ currentOffset++;
+ }
+ return currentOffset;
+ }
+
+ private int findNextTextEnd(int currentOffset, final int minimumOffset) {
+ while (currentOffset > minimumOffset && getContent().isElementMarker(currentOffset)) {
+ currentOffset--;
+ }
+ return currentOffset;
+ }
+
+ public List<Node> getChildNodesBefore(final int offset) {
+ if (offset <= getStartOffset()) {
+ return Collections.emptyList();
+ }
+ return getChildNodes(new Range(getStartOffset() + 1, offset));
+ }
+
+ public List<Node> getChildNodesAfter(final int offset) {
+ if (offset >= getEndOffset()) {
+ return Collections.emptyList();
+ }
+ return getChildNodes(new Range(offset, getEndOffset() - 1));
+ }
+
+ /**
+ * An Iterator of all child nodes. The underlying collection is not modifyable.
+ *
+ * @see Parent#getChildNodes()
+ * @see Iterator
+ * @return an Iterator of all child nodes
+ */
+ public Iterator<Node> getChildIterator() {
+ return getChildNodes().iterator();
+ }
+
+ /**
+ * Returns the child node at the given index. This index is based on the list of children without the Text nodes, so
+ * the child node might have a different index in the list returned by getChildNodes().
+ *
+ * @see Parent#getChildNodes()
+ * @return the child node at the given index
+ */
+ public Node getChildNode(final int index) {
+ return children.get(index);
+ }
+
+ /**
+ * Returns the number of child nodes (<b>not</b> including Text nodes) of this parent node.
+ *
+ * @return the number of child nodes
+ */
+ public int getChildCount() {
+ return children.size();
+ }
+
+ /**
+ * Returns the node at the given offset.
+ *
+ * @param offset
+ * the offset
+ * @return the node at the given offset
+ */
+ public Node getChildNodeAt(final int offset) {
+ Assert.isTrue(containsOffset(offset), MessageFormat.format("Offset must be within {0}.", getRange()));
+ final List<Node> childNodes = getChildNodes();
+ for (final Node child : childNodes) {
+ if (child.containsOffset(offset)) {
+ if (child instanceof Parent) {
+ return ((Parent) child).getChildNodeAt(offset);
+ } else {
+ return child;
+ }
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Indicates if this parent node has child nodes. Text nodes are ignored, i.e. this method will return false if this
+ * parent node contains only text.
+ *
+ * @return true if this parent node has child nodes
+ */
+ public boolean hasChildren() {
+ return !children.isEmpty();
+ }
+}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Position.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Position.java
index fa8b3158..c56b9048 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Position.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Position.java
@@ -13,17 +13,30 @@ package org.eclipse.vex.core.internal.dom;
/**
* Represents a logical location in a document. As the document is modified, existing <code>Position</code> objects are
* updated to reflect the appropriate character offset in the document.
+ *
+ * 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 Position {
+ static Position NULL = new Position() {
+ public int getOffset() {
+ return -1;
+ }
+
+ public boolean isValid() {
+ return false;
+ };
+ };
+
/**
* @return the character offset corresponding to the position.
*/
int getOffset();
/**
- * @param offset
- * the character offset corresponding to the position
+ * @return true if this position is still valid and actively maintained by its creator
*/
- void setOffset(int offset);
+ boolean isValid();
+
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Range.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Range.java
new file mode 100644
index 00000000..bc95ccab
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Range.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2012 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.dom;
+
+import java.text.MessageFormat;
+
+import org.eclipse.core.runtime.Assert;
+
+/**
+ * @author Florian Thienel
+ */
+public class Range {
+
+ private final int startOffset;
+ private final int endOffset;
+
+ public Range(final int startOffset, final int endOffset) {
+ Assert.isTrue(startOffset <= endOffset, MessageFormat.format("startOffset {0} must not be greater than endOffset {1}", startOffset, endOffset));
+ this.startOffset = startOffset;
+ this.endOffset = endOffset;
+ }
+
+ public int getStartOffset() {
+ return startOffset;
+ }
+
+ public int getEndOffset() {
+ return endOffset;
+ }
+
+ public int length() {
+ return endOffset - startOffset + 1;
+ }
+
+ public boolean contains(final Range other) {
+ return startOffset <= other.startOffset && endOffset >= other.endOffset;
+ }
+
+ public boolean contains(final int offset) {
+ return startOffset <= offset && offset <= endOffset;
+ }
+
+ public Range trimTo(final Range limit) {
+ return new Range(Math.max(limit.getStartOffset(), startOffset), Math.min(endOffset, limit.getEndOffset()));
+ }
+
+ public Range moveBounds(final int delta) {
+ return moveBounds(delta, delta);
+ }
+
+ public Range moveBounds(final int deltaStart, final int deltaEnd) {
+ return new Range(startOffset + deltaStart, endOffset + deltaEnd);
+ }
+
+ @Override
+ public String toString() {
+ return "Range[" + startOffset + ", " + endOffset + "]";
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + endOffset;
+ result = prime * result + startOffset;
+ return result;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final Range other = (Range) obj;
+ if (endOffset != other.endOffset) {
+ return false;
+ }
+ if (startOffset != other.startOffset) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/RootElement.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/RootElement.java
deleted file mode 100644
index 1f74080c..00000000
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/RootElement.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2004, 2008 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
- *******************************************************************************/
-package org.eclipse.vex.core.internal.dom;
-
-import org.eclipse.core.runtime.QualifiedName;
-
-/**
- * The root element of a document. Keeps track of the document to which it is associated. Any element can find the
- * document to which it is associated by following its parents to this root. This would be done, for example, to notify
- * document listeners that the document has changed when the element changes.
- */
-public class RootElement extends Element {
-
- private Document document;
-
- public RootElement(final String localName) {
- super(localName);
- }
-
- public RootElement(final QualifiedName qualifiedName) {
- super(qualifiedName);
- }
-
- @Override
- public Document getDocument() {
- return document;
- }
-
- public void setDocument(final Document document) {
- this.document = document;
- }
-
-}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Text.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Text.java
index 2ddae8c1..ffed98d4 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Text.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Text.java
@@ -19,6 +19,8 @@ public class Text extends Node {
/**
* Class constructor.
*
+ * @param parent
+ * The parent node containing the text
* @param content
* Content object containing the text
* @param startOffset
@@ -26,17 +28,36 @@ public class Text extends Node {
* @param endOffset
* character offset of the end of the run
*/
- public Text(final Content content, final int startOffset, final int endOffset) {
- setContent(content, startOffset, endOffset);
+ public Text(final Parent parent, final Content content, final Range range) {
+ setParent(parent);
+ associate(content, range);
}
@Override
- public String getNodeType() {
- return "Text";
+ public void accept(final INodeVisitor visitor) {
+ visitor.visit(this);
+ }
+
+ @Override
+ public <T> T accept(final INodeVisitorWithResult<T> visitor) {
+ return visitor.visit(this);
}
@Override
public String getBaseURI() {
return null;
}
+
+ @Override
+ public String toString() {
+ final StringBuffer sb = new StringBuffer();
+
+ sb.append("Text (");
+ sb.append(getStartOffset());
+ sb.append(",");
+ sb.append(getEndOffset());
+ sb.append(")");
+
+ return sb.toString();
+ }
}
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 374621fa..357acf9c 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
@@ -26,8 +26,12 @@ import org.eclipse.vex.core.internal.core.IntRange;
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.internal.dom.BaseNodeVisitorWithResult;
+import org.eclipse.vex.core.internal.dom.Comment;
import org.eclipse.vex.core.internal.dom.Document;
import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
+import org.eclipse.vex.core.internal.dom.Parent;
import org.eclipse.vex.core.internal.dom.Position;
/**
@@ -51,13 +55,12 @@ public abstract class AbstractBlockBox extends AbstractBox implements BlockBox {
* LayoutContext being used.
* @param parent
* Parent box.
- * @param element
- * Element associated with this box. anonymous box.
+ * @param node
+ * Node associated with this box. anonymous box.
*/
- public AbstractBlockBox(final LayoutContext context, final BlockBox parent, final Element element) {
-
+ public AbstractBlockBox(final LayoutContext context, final BlockBox parent, final Node node) {
this.parent = parent;
- this.element = element;
+ element = node;
final Styles styles = context.getStyleSheet().getStyles(element);
final int parentWidth = parent.getWidth();
@@ -91,14 +94,14 @@ public abstract class AbstractBlockBox extends AbstractBox implements BlockBox {
/**
* Walks the box tree and returns the nearest enclosing element.
*/
- protected Element findContainingElement() {
+ protected Parent findContainingParent() {
BlockBox box = this;
- Element element = box.getElement();
- while (element == null) {
+ Node node = box.getNode();
+ while (!(node instanceof Parent)) {
box = box.getParent();
- element = box.getElement();
+ node = box.getNode();
}
- return element;
+ return (Parent) node;
}
/**
@@ -173,13 +176,13 @@ public abstract class AbstractBlockBox extends AbstractBox implements BlockBox {
}
@Override
- public Element getElement() {
+ public Node getNode() {
return element;
}
@Override
public int getEndOffset() {
- final Element element = getElement();
+ final Node element = getNode();
if (element != null) {
return element.getEndOffset();
} else if (getEndPosition() != null) {
@@ -199,8 +202,8 @@ public abstract class AbstractBlockBox extends AbstractBox implements BlockBox {
*/
protected int getEstimatedHeight(final LayoutContext context) {
- final Element element = findContainingElement();
- final Styles styles = context.getStyleSheet().getStyles(element);
+ final Node node = findContainingParent();
+ final Styles styles = context.getStyleSheet().getStyles(node);
final int charCount = getEndOffset() - getStartOffset();
final float fontSize = styles.getFontSize();
@@ -230,8 +233,8 @@ public abstract class AbstractBlockBox extends AbstractBox implements BlockBox {
@Override
public Insets getInsets(final LayoutContext context, final int containerWidth) {
- if (getElement() != null) {
- final Styles styles = context.getStyleSheet().getStyles(getElement());
+ if (getNode() != null) {
+ final Styles styles = context.getStyleSheet().getStyles(getNode());
final int top = marginTop + styles.getBorderTopWidth() + styles.getPaddingTop().get(containerWidth);
@@ -361,9 +364,9 @@ public abstract class AbstractBlockBox extends AbstractBox implements BlockBox {
@Override
public int getStartOffset() {
- final Element element = getElement();
- if (element != null) {
- return element.getStartOffset() + 1;
+ final Node node = getNode();
+ if (node != null) {
+ return node.getStartOffset() + 1;
} else if (getStartPosition() != null) {
return getStartPosition().getOffset();
} else {
@@ -391,7 +394,7 @@ public abstract class AbstractBlockBox extends AbstractBox implements BlockBox {
@Override
public boolean isAnonymous() {
- return getElement() == null;
+ return getNode() == null;
}
/**
@@ -408,7 +411,7 @@ public abstract class AbstractBlockBox extends AbstractBox implements BlockBox {
* ranges.
*/
protected void iterateChildrenByDisplayStyle(final StyleSheet styleSheet, final Set<String> displayStyles, final ElementOrRangeCallback callback) {
- LayoutUtils.iterateChildrenByDisplayStyle(styleSheet, displayStyles, findContainingElement(), getStartOffset(), getEndOffset(), callback);
+ LayoutUtils.iterateChildrenByDisplayStyle(styleSheet, displayStyles, findContainingParent(), getStartOffset(), getEndOffset(), callback);
}
@Override
@@ -418,7 +421,7 @@ public abstract class AbstractBlockBox extends AbstractBox implements BlockBox {
return;
}
- final boolean drawBorders = !context.isElementSelected(getElement());
+ final boolean drawBorders = !context.isNodeSelected(getNode());
this.drawBox(context, x, y, getParent().getWidth(), drawBorders);
@@ -487,10 +490,10 @@ public abstract class AbstractBlockBox extends AbstractBox implements BlockBox {
*/
protected void paintSelectionFrame(final LayoutContext context, final int x, final int y, final boolean selected) {
- final Element element = getElement();
- final Element parent = element == null ? null : element.getParent();
+ final Node node = getNode();
+ final Parent parent = node == null ? null : node.getParent();
- final boolean paintFrame = context.isElementSelected(element) && !context.isElementSelected(parent);
+ final boolean paintFrame = context.isNodeSelected(node) && !context.isNodeSelected(parent);
if (!paintFrame) {
return;
@@ -512,14 +515,15 @@ public abstract class AbstractBlockBox extends AbstractBox implements BlockBox {
final ColorResource oldColor = g.setColor(background);
g.setLineStyle(Graphics.LINE_SOLID);
g.setLineWidth(1);
- final int tabWidth = g.stringWidth(getElement().getPrefixedName()) + fm.getLeading();
+ final String frameName = getSelectionFrameName(node);
+ final int tabWidth = g.stringWidth(frameName) + fm.getLeading();
final int tabHeight = fm.getHeight();
final int tabX = x + getWidth() - tabWidth;
final int tabY = y + getHeight() - tabHeight;
g.drawRect(x, y, getWidth(), getHeight());
g.fillRect(tabX, tabY, tabWidth, tabHeight);
g.setColor(foreground);
- g.drawString(getElement().getPrefixedName(), tabX + fm.getLeading() / 2, tabY);
+ g.drawString(frameName, tabX + fm.getLeading() / 2, tabY);
g.setColor(oldColor);
if (!selected) {
@@ -528,6 +532,20 @@ public abstract class AbstractBlockBox extends AbstractBox implements BlockBox {
}
}
+ protected String getSelectionFrameName(final Node node) {
+ return node.accept(new BaseNodeVisitorWithResult<String>() {
+ @Override
+ public String visit(final Element element) {
+ return element.getPrefixedName();
+ }
+
+ @Override
+ public String visit(final Comment comment) {
+ return "Comment";
+ }
+ });
+ }
+
/** Layout is OK */
public static final byte LAYOUT_OK = 0;
@@ -747,7 +765,7 @@ public abstract class AbstractBlockBox extends AbstractBox implements BlockBox {
Styles styles = null;
if (!isAnonymous()) {
- styles = context.getStyleSheet().getStyles(getElement());
+ styles = context.getStyleSheet().getStyles(getNode());
}
if (styles != null && children.length > 0) {
@@ -809,7 +827,7 @@ public abstract class AbstractBlockBox extends AbstractBox implements BlockBox {
/**
* Element with which we are associated. For anonymous boxes, this is null.
*/
- private Element element;
+ private Node element;
/*
* We cache the top and bottom margins, since they may be affected by our children.
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 bb3ca825..604656c2 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
@@ -18,7 +18,7 @@ import org.eclipse.vex.core.internal.core.Insets;
import org.eclipse.vex.core.internal.core.Rectangle;
import org.eclipse.vex.core.internal.css.CSS;
import org.eclipse.vex.core.internal.css.Styles;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
/**
* Base implementation of the <code>Box</code> interface, implementing some common methods.
@@ -68,9 +68,9 @@ public abstract class AbstractBox implements Box {
/**
* Returns null. Boxes associated with elements must provide an implementation of this method.
*
- * @see org.eclipse.vex.core.internal.layout.Box#getElement()
+ * @see org.eclipse.vex.core.internal.layout.Box#getNode()
*/
- public Element getElement() {
+ public Node getNode() {
return null;
}
@@ -106,11 +106,11 @@ public abstract class AbstractBox implements Box {
* is associated with this box returns all zeros.
*/
public Insets getInsets(final LayoutContext context, final int containerWidth) {
- final Element element = getElement();
- if (element == null) {
+ final Node node = getNode();
+ if (node == null) {
return Insets.ZERO_INSETS;
} else {
- return getInsets(context.getStyleSheet().getStyles(element), containerWidth);
+ return getInsets(context.getStyleSheet().getStyles(node), containerWidth);
}
}
@@ -253,7 +253,7 @@ public abstract class AbstractBox implements Box {
* This is handy when removing the borders when drawing the selection frame.
*/
protected void drawBox(final LayoutContext context, final int x, final int y, final int containerWidth, final boolean drawBorders) {
- this.drawBox(context, getElement(), x, y, containerWidth, drawBorders);
+ this.drawBox(context, getNode(), x, y, containerWidth, drawBorders);
}
/**
@@ -261,7 +261,7 @@ public abstract class AbstractBox implements Box {
*
* @param context
* LayoutContext used for drawing.
- * @param element
+ * @param node
* Element to use when determining styles. This is used by TableBodyBox to specify the corresponding
* table element.
* @param x
@@ -274,14 +274,14 @@ public abstract class AbstractBox implements Box {
* If true, the background is filled and the borders are drawn; otherwise, just the background is filled.
* This is handy when removing the borders when drawing the selection frame.
*/
- protected void drawBox(final LayoutContext context, final Element element, final int x, final int y, final int containerWidth, final boolean drawBorders) {
+ protected void drawBox(final LayoutContext context, final Node node, final int x, final int y, final int containerWidth, final boolean drawBorders) {
- if (element == null) {
+ if (node == null) {
return;
}
final Graphics g = context.getGraphics();
- final Styles styles = context.getStyleSheet().getStyles(element);
+ final Styles styles = context.getStyleSheet().getStyles(node);
boolean hasLeft = true;
boolean hasRight = true;
@@ -292,8 +292,8 @@ public abstract class AbstractBox implements Box {
if (this instanceof InlineElementBox) {
// TODO fix boxes for inline elements
- hasLeft = getStartOffset() == element.getStartOffset() + 1;
- hasRight = getEndOffset() == element.getEndOffset();
+ hasLeft = getStartOffset() == node.getStartOffset() + 1;
+ hasRight = getEndOffset() == node.getEndOffset();
if (hasLeft) {
// left += styles.getMarginLeft().get(0);
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/BlockElementBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/BlockElementBox.java
index 9c58ef98..b92f70c6 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/BlockElementBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/BlockElementBox.java
@@ -13,6 +13,7 @@
package org.eclipse.vex.core.internal.layout;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
import org.eclipse.vex.core.internal.VEXCorePlugin;
@@ -23,6 +24,8 @@ 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.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
+import org.eclipse.vex.core.internal.dom.Parent;
/**
* A block box corresponding to a DOM Element. Block boxes lay their children out stacked top to bottom. Block boxes
@@ -48,11 +51,11 @@ public class BlockElementBox extends AbstractBlockBox {
* LayoutContext used for this layout.
* @param parent
* This box's parent box.
- * @param element
- * Element to which this box corresponds.
+ * @param node
+ * Node to which this box corresponds.
*/
- public BlockElementBox(final LayoutContext context, final BlockBox parent, final Element element) {
- super(context, parent, element);
+ public BlockElementBox(final LayoutContext context, final BlockBox parent, final Node node) {
+ super(context, parent, node);
}
/**
@@ -64,12 +67,12 @@ public class BlockElementBox extends AbstractBlockBox {
@Override
public int getEndOffset() {
- return getElement().getEndOffset();
+ return getNode().getEndOffset();
}
@Override
public int getStartOffset() {
- return getElement().getStartOffset() + 1;
+ return getNode().getStartOffset() + 1;
}
@Override
@@ -92,7 +95,7 @@ public class BlockElementBox extends AbstractBlockBox {
final int repaintStart = super.positionChildren(context);
- final Styles styles = context.getStyleSheet().getStyles(getElement());
+ final Styles styles = context.getStyleSheet().getStyles(getNode());
if (beforeMarker != null) {
final int x = -beforeMarker.getWidth() - Math.round(BULLET_SPACE * styles.getFontSize());
int y = getFirstLineTop(context);
@@ -110,7 +113,7 @@ public class BlockElementBox extends AbstractBlockBox {
@Override
public String toString() {
- return "BlockElementBox: <" + getElement().getPrefixedName() + ">" + "[x=" + getX() + ",y=" + getY() + ",width=" + getWidth() + ",height=" + getHeight() + "]";
+ return "BlockElementBox: <" + getNode() + ">" + "[x=" + getX() + ",y=" + getY() + ",width=" + getWidth() + ",height=" + getHeight() + "]";
}
// ===================================================== PRIVATE
@@ -126,7 +129,7 @@ public class BlockElementBox extends AbstractBlockBox {
start = System.currentTimeMillis();
}
- final Element element = getElement();
+ final Node node = getNode();
final int width = getWidth();
final List<Box> childList = new ArrayList<Box>();
@@ -139,21 +142,23 @@ public class BlockElementBox extends AbstractBlockBox {
// :before content
List<InlineBox> beforeInlines = null;
- genElement = context.getStyleSheet().getBeforeElement(getElement());
- if (genElement != null) {
- genStyles = styleSheet.getStyles(genElement);
- if (genStyles.getDisplay().equals(CSS.INLINE)) {
- beforeInlines = new ArrayList<InlineBox>();
- beforeInlines.addAll(LayoutUtils.createGeneratedInlines(context, genElement));
- } else {
- childList.add(new BlockPseudoElementBox(context, genElement, this, width));
+ if (node instanceof Element) { // TODO replace PseudoElement with a more flexible mechanism
+ genElement = context.getStyleSheet().getBeforeElement((Element) node);
+ if (genElement != null) {
+ genStyles = styleSheet.getStyles(genElement);
+ if (genStyles.getDisplay().equals(CSS.INLINE)) {
+ beforeInlines = new ArrayList<InlineBox>();
+ beforeInlines.addAll(LayoutUtils.createGeneratedInlines(context, genElement));
+ } else {
+ childList.add(new BlockPseudoElementBox(context, genElement, this, width));
+ }
}
}
// background image
- final Styles styles = context.getStyleSheet().getStyles(getElement());
+ final Styles styles = context.getStyleSheet().getStyles(node);
if (styles.hasBackgroundImage() && !styles.getDisplay().equalsIgnoreCase(CSS.NONE)) {
- final InlineBox imageBox = ImageBox.create(getElement(), context, getWidth());
+ final InlineBox imageBox = ImageBox.create(node, context, getWidth());
if (imageBox != null) {
if (beforeInlines == null) {
beforeInlines = new ArrayList<InlineBox>();
@@ -165,19 +170,21 @@ public class BlockElementBox extends AbstractBlockBox {
// :after content
Box afterBlock = null;
List<InlineBox> afterInlines = null;
- genElement = context.getStyleSheet().getAfterElement(getElement());
- if (genElement != null) {
- genStyles = context.getStyleSheet().getStyles(genElement);
- if (genStyles.getDisplay().equals(CSS.INLINE)) {
- afterInlines = new ArrayList<InlineBox>();
- afterInlines.addAll(LayoutUtils.createGeneratedInlines(context, genElement));
- } else {
- afterBlock = new BlockPseudoElementBox(context, genElement, this, width);
+ if (node instanceof Element) {
+ genElement = context.getStyleSheet().getAfterElement((Element) node);
+ if (genElement != null) {
+ genStyles = context.getStyleSheet().getStyles(genElement);
+ if (genStyles.getDisplay().equals(CSS.INLINE)) {
+ afterInlines = new ArrayList<InlineBox>();
+ afterInlines.addAll(LayoutUtils.createGeneratedInlines(context, genElement));
+ } else {
+ afterBlock = new BlockPseudoElementBox(context, genElement, this, width);
+ }
}
}
- final int startOffset = element.getStartOffset() + 1;
- final int endOffset = element.getEndOffset();
+ final int startOffset = node.getStartOffset() + 1;
+ final int endOffset = node.getEndOffset();
final List<Box> blockBoxes = createBlockBoxes(context, startOffset, endOffset, width, beforeInlines, afterInlines);
childList.addAll(blockBoxes);
@@ -192,7 +199,7 @@ public class BlockElementBox extends AbstractBlockBox {
if (VEXCorePlugin.getInstance().isDebugging()) {
final long end = System.currentTimeMillis();
if (end - start > 10) {
- System.out.println("BEB.layout for " + getElement().getPrefixedName() + " took " + (end - start) + "ms");
+ System.out.println("BEB.layout for " + getNode() + " took " + (end - start) + "ms");
}
}
@@ -204,31 +211,31 @@ public class BlockElementBox extends AbstractBlockBox {
*/
private void createListMarker(final LayoutContext context) {
- final Styles styles = context.getStyleSheet().getStyles(getElement());
+ final Styles styles = context.getStyleSheet().getStyles(getNode());
InlineBox markerInline;
final String type = styles.getListStyleType();
if (type.equals(CSS.NONE)) {
return;
} else if (type.equals(CSS.CIRCLE)) {
- markerInline = createCircleBullet(getElement(), styles);
+ markerInline = createCircleBullet(getNode(), styles);
} else if (type.equals(CSS.SQUARE)) {
- markerInline = createSquareBullet(getElement(), styles);
+ markerInline = createSquareBullet(getNode(), styles);
} else if (isEnumeratedListStyleType(type)) {
final String item = getItemNumberString(type);
- markerInline = new StaticTextBox(context, getElement(), item + ".");
+ markerInline = new StaticTextBox(context, getNode(), item + ".");
} else {
- markerInline = createDiscBullet(getElement(), styles);
+ markerInline = createDiscBullet(getNode(), styles);
}
- beforeMarker = ParagraphBox.create(context, getElement(), new InlineBox[] { markerInline }, Integer.MAX_VALUE);
+ beforeMarker = ParagraphBox.create(context, getNode(), new InlineBox[] { markerInline }, Integer.MAX_VALUE);
}
/**
* Returns a Drawable that draws a circle-style list item bullet.
*/
- private static InlineBox createCircleBullet(final Element element, final Styles styles) {
+ private static InlineBox createCircleBullet(final Node node, final Styles styles) {
final int size = Math.round(0.5f * styles.getFontSize());
final int lift = Math.round(0.1f * styles.getFontSize());
final Drawable drawable = new Drawable() {
@@ -242,13 +249,13 @@ public class BlockElementBox extends AbstractBlockBox {
return new Rectangle(0, -size - lift, size, size);
}
};
- return new DrawableBox(drawable, element);
+ return new DrawableBox(drawable, node);
}
/**
* Returns a Drawable that draws a disc-style list item bullet.
*/
- private static InlineBox createDiscBullet(final Element element, final Styles styles) {
+ private static InlineBox createDiscBullet(final Node node, final Styles styles) {
final int size = Math.round(0.5f * styles.getFontSize());
final int lift = Math.round(0.1f * styles.getFontSize());
final Drawable drawable = new Drawable() {
@@ -260,13 +267,13 @@ public class BlockElementBox extends AbstractBlockBox {
return new Rectangle(0, -size - lift, size, size);
}
};
- return new DrawableBox(drawable, element);
+ return new DrawableBox(drawable, node);
}
/**
* Returns a Drawable that draws a square-style list item bullet.
*/
- private static InlineBox createSquareBullet(final Element element, final Styles styles) {
+ private static InlineBox createSquareBullet(final Node node, final Styles styles) {
final int size = Math.round(0.5f * styles.getFontSize());
final int lift = Math.round(0.1f * styles.getFontSize());
final Drawable drawable = new Drawable() {
@@ -280,14 +287,14 @@ public class BlockElementBox extends AbstractBlockBox {
return new Rectangle(0, -size - lift, size, size);
}
};
- return new DrawableBox(drawable, element);
+ return new DrawableBox(drawable, node);
}
/**
* Returns the vertical distance from the top of this box to the top of its first line.
*/
int getFirstLineTop(final LayoutContext context) {
- final Styles styles = context.getStyleSheet().getStyles(getElement());
+ final Styles styles = context.getStyleSheet().getStyles(getNode());
final int top = styles.getBorderTopWidth() + styles.getPaddingTop().get(0);
final Box[] children = getChildren();
if (children != null && children.length > 0 && children[0] instanceof BlockElementBox) {
@@ -302,20 +309,20 @@ public class BlockElementBox extends AbstractBlockBox {
* amongst its siblings starting with 1.
*/
private int getItemNumber() {
- final Element element = getElement();
- final Element parent = element.getParent();
+ final Node node = getNode();
+ final Parent parent = node.getParent();
if (parent == null) {
return 1;
}
int item = 1;
- final List<Element> children = parent.getChildElements();
- for (int i = 0; i < children.size(); i++) {
- if (children.get(i) == element) {
+ for (final Iterator<Node> iterator = parent.getChildIterator(); iterator.hasNext();) {
+ final Node child = iterator.next();
+ if (child == node) {
return item;
}
- if (children.get(i).getQualifiedName().equals(element.getQualifiedName())) {
+ if (child.isKindOf(node)) {
item++;
}
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/BlockPseudoElementBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/BlockPseudoElementBox.java
index f993e745..07653733 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/BlockPseudoElementBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/BlockPseudoElementBox.java
@@ -16,6 +16,7 @@ import java.util.List;
import org.eclipse.vex.core.internal.core.IntRange;
import org.eclipse.vex.core.internal.css.Styles;
import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
/**
* Implements a Block
@@ -63,10 +64,10 @@ public class BlockPseudoElementBox extends AbstractBox implements BlockBox {
}
/**
- * @see org.eclipse.vex.core.internal.layout.Box#getElement()
+ * @see org.eclipse.vex.core.internal.layout.Box#getNode()
*/
@Override
- public Element getElement() {
+ public Node getNode() {
return pseudoElement;
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/Box.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/Box.java
index cb05b3e6..1c06434a 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/Box.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/Box.java
@@ -12,7 +12,7 @@ package org.eclipse.vex.core.internal.layout;
import org.eclipse.vex.core.internal.core.Caret;
import org.eclipse.vex.core.internal.core.Insets;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
/**
* Represents a rectangular area in the layout. The height and width of the box are measured from the inner edges of the
@@ -48,7 +48,7 @@ public interface Box {
* Returns the Element with which this box is associated, or null if there is no such box. The box may directly
* represent the Element, or simply use it for formatting information.
*/
- public Element getElement();
+ public Node getNode();
/**
* Returns the offset of the end of the content that the box covers.
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/BoxFactory.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/BoxFactory.java
index b2b3413a..0a6feffc 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/BoxFactory.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/BoxFactory.java
@@ -12,7 +12,7 @@ package org.eclipse.vex.core.internal.layout;
import java.io.Serializable;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
/**
* Interface to an object that creates boxes from elements. Implementations of this interface must be serializable.
@@ -24,13 +24,13 @@ public interface BoxFactory extends Serializable {
*
* @param context
* CSS styles for the new element
- * @param element
- * Element for which the box should be created.
+ * @param node
+ * Node for which the box should be created.
* @param parent
* Parent box for the new box.
* @param containerWidth
* Width of the box to be created.
*/
- public Box createBox(LayoutContext context, Element element, BlockBox parent, int containerWidth);
+ public Box createBox(LayoutContext context, Node node, BlockBox parent, int containerWidth);
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/CommentBlockElementBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/CommentBlockElementBox.java
index 655763f3..3a72aff7 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/CommentBlockElementBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/CommentBlockElementBox.java
@@ -14,7 +14,7 @@ import java.util.ArrayList;
import java.util.List;
import org.eclipse.vex.core.internal.VEXCorePlugin;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
/**
* @author Florian Thienel
@@ -24,8 +24,8 @@ public class CommentBlockElementBox extends BlockElementBox {
private static final String AFTER_TEXT = "-->";
private static final String BEFORE_TEXT = "<!--";
- public CommentBlockElementBox(final LayoutContext context, final BlockBox parent, final Element element) {
- super(context, parent, element);
+ public CommentBlockElementBox(final LayoutContext context, final BlockBox parent, final Node node) {
+ super(context, parent, node);
}
@Override
@@ -35,28 +35,28 @@ public class CommentBlockElementBox extends BlockElementBox {
start = System.currentTimeMillis();
}
- final Element element = getElement();
+ final Node node = getNode();
final int width = getWidth();
final List<Box> childList = new ArrayList<Box>();
// :before content
final List<InlineBox> beforeInlines = new ArrayList<InlineBox>();
- beforeInlines.add(new StaticTextBox(context, element, BEFORE_TEXT));
+ beforeInlines.add(new StaticTextBox(context, node, BEFORE_TEXT));
// :after content
final List<InlineBox> afterInlines = new ArrayList<InlineBox>();
- afterInlines.add(new StaticTextBox(context, element, AFTER_TEXT));
+ afterInlines.add(new StaticTextBox(context, node, AFTER_TEXT));
- final int startOffset = element.getStartOffset() + 1;
- final int endOffset = element.getEndOffset();
+ final int startOffset = node.getStartOffset() + 1;
+ final int endOffset = node.getEndOffset();
final List<Box> blockBoxes = createBlockBoxes(context, startOffset, endOffset, width, beforeInlines, afterInlines);
childList.addAll(blockBoxes);
if (VEXCorePlugin.getInstance().isDebugging()) {
final long end = System.currentTimeMillis();
if (end - start > 10) {
- System.out.println("CommentBlockElementBox.layout for " + getElement().getPrefixedName() + " took " + (end - start) + "ms");
+ System.out.println("CommentBlockElementBox.layout for " + getNode() + " took " + (end - start) + "ms");
}
}
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 b2d50028..0862e3c9 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
@@ -84,7 +84,7 @@ public abstract class CompositeInlineBox extends AbstractInlineBox {
}
final Graphics g = context.getGraphics();
- final Styles styles = context.getStyleSheet().getStyles(getElement());
+ final Styles styles = context.getStyleSheet().getStyles(getNode());
final FontResource font = g.createFont(styles.getFont());
final FontResource oldFont = g.setFont(font);
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/CssBoxFactory.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/CssBoxFactory.java
index 9298d70e..5e81f794 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/CssBoxFactory.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/CssBoxFactory.java
@@ -12,8 +12,8 @@ package org.eclipse.vex.core.internal.layout;
import org.eclipse.vex.core.internal.css.CSS;
import org.eclipse.vex.core.internal.css.Styles;
-import org.eclipse.vex.core.internal.dom.CommentElement;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Comment;
+import org.eclipse.vex.core.internal.dom.Node;
/**
* Implementation of the BoxFactory interface that returns boxes that represent CSS semantics.
@@ -22,14 +22,14 @@ public class CssBoxFactory implements BoxFactory {
private static final long serialVersionUID = -6882526795866485074L;
- public Box createBox(final LayoutContext context, final Element element, final BlockBox parent, final int containerWidth) {
- final Styles styles = context.getStyleSheet().getStyles(element);
- if (element instanceof CommentElement) {
- return new CommentBlockElementBox(context, parent, element);
+ public Box createBox(final LayoutContext context, final Node node, final BlockBox parent, final int containerWidth) {
+ final Styles styles = context.getStyleSheet().getStyles(node);
+ if (node instanceof Comment) {
+ return new CommentBlockElementBox(context, parent, node);
} else if (styles.getDisplay().equals(CSS.TABLE)) {
- return new TableBox(context, parent, element);
+ return new TableBox(context, parent, node);
} else if (styles.isBlock()) {
- return new BlockElementBox(context, parent, element);
+ return new BlockElementBox(context, parent, node);
} else {
throw new RuntimeException("Unexpected display property: " + styles.getDisplay());
}
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 fc653835..873a9448 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
@@ -14,8 +14,8 @@ import org.eclipse.vex.core.internal.core.ColorResource;
import org.eclipse.vex.core.internal.core.FontResource;
import org.eclipse.vex.core.internal.core.Graphics;
import org.eclipse.vex.core.internal.css.Styles;
-import org.eclipse.vex.core.internal.dom.Document;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
+import org.eclipse.vex.core.internal.dom.Range;
import org.eclipse.vex.core.internal.dom.Text;
/**
@@ -31,12 +31,12 @@ public class DocumentTextBox extends TextBox {
*
* @param context
* LayoutContext in use
- * @param element
- * Element being used
+ * @param node
+ * Node being used
* @param text
*/
- public DocumentTextBox(final LayoutContext context, final Element element, final Text text) {
- this(context, element, text.getStartOffset(), text.getEndOffset());
+ public DocumentTextBox(final LayoutContext context, final Node node, final Text text) {
+ this(context, node, text.getStartOffset(), text.getEndOffset());
}
/**
@@ -44,22 +44,22 @@ public class DocumentTextBox extends TextBox {
*
* @param context
* LayoutContext used to calculate the box's size.
- * @param element
- * Element that directly contains the text.
+ * @param node
+ * Node that directly contains the text.
* @param startOffset
* start offset of the text
* @param endOffset
* end offset of the text
*/
- public DocumentTextBox(final LayoutContext context, final Element element, final int startOffset, final int endOffset) {
- super(element);
+ public DocumentTextBox(final LayoutContext context, final Node node, final int startOffset, final int endOffset) {
+ super(node);
- if (startOffset >= endOffset) {
- throw new IllegalStateException("DocumentTextBox: startOffset (" + startOffset + ") >= endOffset (" + endOffset + ")");
+ if (startOffset > endOffset) {
+ throw new IllegalStateException("DocumentTextBox: startOffset (" + startOffset + ") > endOffset (" + endOffset + ")");
}
- startRelative = startOffset - element.getStartOffset();
- endRelative = endOffset - element.getStartOffset();
+ startRelative = startOffset - node.getStartOffset();
+ endRelative = endOffset - node.getStartOffset();
calculateSize(context);
if (getText().length() < endOffset - startOffset) {
@@ -75,7 +75,7 @@ public class DocumentTextBox extends TextBox {
if (endRelative == -1) {
return -1;
} else {
- return getElement().getStartOffset() + endRelative - 1;
+ return getNode().getStartOffset() + endRelative;
}
}
@@ -87,7 +87,7 @@ public class DocumentTextBox extends TextBox {
if (startRelative == -1) {
return -1;
} else {
- return getElement().getStartOffset() + startRelative;
+ return getNode().getStartOffset() + startRelative;
}
}
@@ -96,8 +96,7 @@ public class DocumentTextBox extends TextBox {
*/
@Override
public String getText() {
- final Document doc = getElement().getDocument();
- return doc.getText(getStartOffset(), getEndOffset() + 1);
+ return getNode().getText(new Range(getStartOffset(), getEndOffset()));
}
/**
@@ -114,7 +113,7 @@ public class DocumentTextBox extends TextBox {
@Override
public void paint(final LayoutContext context, final int x, final int y) {
- final Styles styles = context.getStyleSheet().getStyles(getElement());
+ final Styles styles = context.getStyleSheet().getStyles(getNode());
final Graphics g = context.getGraphics();
final FontResource font = g.createFont(styles.getFont());
@@ -182,7 +181,7 @@ public class DocumentTextBox extends TextBox {
@Override
public Pair splitAt(final LayoutContext context, final int offset) {
- if (offset < 0 || offset > endRelative - startRelative) {
+ if (offset < 0 || offset > endRelative - startRelative + 1) {
throw new IllegalStateException();
}
@@ -192,14 +191,14 @@ public class DocumentTextBox extends TextBox {
if (offset == 0) {
left = null;
} else {
- left = new DocumentTextBox(context, getElement(), getStartOffset(), split);
+ left = new DocumentTextBox(context, getNode(), getStartOffset(), split - 1);
}
InlineBox right;
- if (split == getEndOffset() + 1) {
+ if (split >= getEndOffset()) {
right = null;
} else {
- right = new DocumentTextBox(context, getElement(), split, getEndOffset() + 1);
+ right = new DocumentTextBox(context, getNode(), split, getEndOffset());
}
return new Pair(left, right);
}
@@ -212,7 +211,7 @@ public class DocumentTextBox extends TextBox {
public int viewToModel(final LayoutContext context, final int x, final int y) {
final Graphics g = context.getGraphics();
- final Styles styles = context.getStyleSheet().getStyles(getElement());
+ final Styles styles = context.getStyleSheet().getStyles(getNode());
final FontResource font = g.createFont(styles.getFont());
final FontResource oldFont = g.setFont(font);
final char[] chars = getText().toCharArray();
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 63438da6..9113f7bf 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
@@ -17,7 +17,7 @@ import org.eclipse.vex.core.internal.core.FontResource;
import org.eclipse.vex.core.internal.core.Graphics;
import org.eclipse.vex.core.internal.core.Rectangle;
import org.eclipse.vex.core.internal.css.Styles;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
/**
* An inline box that draws a Drawable object. The drawable is drawn relative to the text baseline, therefore it should
@@ -30,7 +30,7 @@ public class DrawableBox extends AbstractInlineBox {
public static final byte END_MARKER = 2;
private final Drawable drawable;
- private final Element element;
+ private final Node node;
private final byte marker;
/**
@@ -38,11 +38,11 @@ public class DrawableBox extends AbstractInlineBox {
*
* @param drawable
* Drawable to draw.
- * @param element2
- * Element whose styles determine the color of the drawable.
+ * @param node
+ * Node whose styles determine the color of the drawable.
*/
- public DrawableBox(final Drawable drawable, final Element element2) {
- this(drawable, element2, NO_MARKER);
+ public DrawableBox(final Drawable drawable, final Node node) {
+ this(drawable, node, NO_MARKER);
}
/**
@@ -51,14 +51,14 @@ public class DrawableBox extends AbstractInlineBox {
*
* @param drawable
* Drawable to draw.
- * @param element2
- * Element whose styles determine the color of the drawable.
+ * @param node
+ * Node whose styles determine the color of the drawable.
* @param marker
* which marker should be drawn. Must be one of NO_MARKER, START_MARKER, or END_MARKER.
*/
- public DrawableBox(final Drawable drawable, final Element element2, final byte marker) {
+ public DrawableBox(final Drawable drawable, final Node node, final byte marker) {
this.drawable = drawable;
- element = element2;
+ this.node = node;
this.marker = marker;
final Rectangle bounds = drawable.getBounds();
setWidth(bounds.getWidth());
@@ -73,11 +73,11 @@ public class DrawableBox extends AbstractInlineBox {
}
/**
- * Returns the element that controls the styling for this text element.
+ * Returns the node that controls the styling for this text box.
*/
@Override
- public Element getElement() {
- return element;
+ public Node getNode() {
+ return node;
}
public boolean isEOL() {
@@ -100,13 +100,13 @@ public class DrawableBox extends AbstractInlineBox {
public void paint(final LayoutContext context, final int x, final int y) {
final Graphics g = context.getGraphics();
- final Styles styles = context.getStyleSheet().getStyles(element);
+ final Styles styles = context.getStyleSheet().getStyles(node);
boolean drawSelected = false;
if (marker == START_MARKER) {
- drawSelected = getElement().getStartOffset() >= context.getSelectionStart() && getElement().getStartOffset() + 1 <= context.getSelectionEnd();
+ drawSelected = getNode().getStartOffset() >= context.getSelectionStart() && getNode().getStartOffset() + 1 <= context.getSelectionEnd();
} else if (marker == END_MARKER) {
- drawSelected = getElement().getEndOffset() >= context.getSelectionStart() && getElement().getEndOffset() + 1 <= context.getSelectionEnd();
+ drawSelected = getNode().getEndOffset() >= context.getSelectionStart() && getNode().getEndOffset() + 1 <= context.getSelectionEnd();
}
final FontResource font = g.createFont(styles.getFont());
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/ElementOrRangeCallback.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/ElementOrRangeCallback.java
index e5e33490..9b3a5814 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/ElementOrRangeCallback.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/ElementOrRangeCallback.java
@@ -11,9 +11,10 @@
package org.eclipse.vex.core.internal.layout;
import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Parent;
public interface ElementOrRangeCallback {
public void onElement(Element child, String displayStyle);
- public void onRange(Element parent, int startOffset, int endOffset);
+ public void onRange(Parent parent, int startOffset, int endOffset);
} \ No newline at end of file
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 62167cfb..897c8d96 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
@@ -5,18 +5,18 @@ import java.net.URL;
import org.eclipse.vex.core.internal.core.Image;
import org.eclipse.vex.core.internal.core.Point;
import org.eclipse.vex.core.internal.css.Styles;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
public class ImageBox extends AbstractInlineBox {
private final Image image;
- public static ImageBox create(final Element element, final LayoutContext context, final int maxWidth) {
- if (element == null) {
+ public static ImageBox create(final Node node, final LayoutContext context, final int maxWidth) {
+ if (node == null) {
return null;
}
- final Styles styles = context.getStyleSheet().getStyles(element);
- final URL imageUrl = context.resolveUrl(element.getBaseURI(), styles.getBackgroundImage());
+ final Styles styles = context.getStyleSheet().getStyles(node);
+ final URL imageUrl = context.resolveUrl(node.getBaseURI(), styles.getBackgroundImage());
if (imageUrl == null) {
return null;
}
@@ -51,11 +51,11 @@ public class ImageBox extends AbstractInlineBox {
return Math.round(1f * scaled / current * opposite);
}
- public static ImageBox createWithHeight(final Element element, final LayoutContext context, final int maxHeight) {
- if (element == null) {
+ public static ImageBox createWithHeight(final Node node, final LayoutContext context, final int maxHeight) {
+ if (node == null) {
return null;
}
- final URL imageUrl = context.resolveUrl(element.getBaseURI(), context.getStyleSheet().getStyles(element).getBackgroundImage());
+ final URL imageUrl = context.resolveUrl(node.getBaseURI(), context.getStyleSheet().getStyles(node).getBackgroundImage());
if (imageUrl == null) {
return null;
}
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 f7540fec..6fc49d25 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,9 +21,11 @@ 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.Styles;
-import org.eclipse.vex.core.internal.dom.CommentElement;
+import org.eclipse.vex.core.internal.dom.BaseNodeVisitor;
+import org.eclipse.vex.core.internal.dom.Comment;
import org.eclipse.vex.core.internal.dom.Element;
import org.eclipse.vex.core.internal.dom.Node;
+import org.eclipse.vex.core.internal.dom.Range;
import org.eclipse.vex.core.internal.dom.Text;
/**
@@ -33,7 +35,7 @@ public class InlineElementBox extends CompositeInlineBox {
private static final String COMMENT_AFTER_TEXT = "-->";
private static final String COMMENT_BEFORE_TEXT = "<!--";
- private final Element element;
+ private final Node node;
private final InlineBox[] children;
private InlineBox firstContentChild = null;
private InlineBox lastContentChild = null;
@@ -45,22 +47,22 @@ public class InlineElementBox extends CompositeInlineBox {
*
* @param context
* LayoutContext to use.
- * @param element
+ * @param node
* Element that generated this box
* @param startOffset
* Start offset of the range being rendered, which may be arbitrarily before or inside the element.
* @param endOffset
* End offset of the range being rendered, which may be arbitrarily after or inside the element.
*/
- private InlineElementBox(final LayoutContext context, final Element element, final int startOffset, final int endOffset) {
+ private InlineElementBox(final LayoutContext context, final Node node, final int startOffset, final int endOffset) {
- this.element = element;
+ this.node = node;
final List<InlineBox> childList = new ArrayList<InlineBox>();
- final Styles styles = context.getStyleSheet().getStyles(element);
+ final Styles styles = context.getStyleSheet().getStyles(node);
- if (startOffset <= element.getStartOffset()) {
+ if (startOffset <= node.getStartOffset()) {
// space for the left margin/border/padding
final int space = styles.getMarginLeft().get(0) + styles.getBorderLeftWidth() + styles.getPaddingLeft().get(0);
@@ -69,46 +71,46 @@ public class InlineElementBox extends CompositeInlineBox {
childList.add(new SpaceBox(space, 1));
}
- if (element instanceof CommentElement) {
- childList.add(new StaticTextBox(context, element, COMMENT_BEFORE_TEXT));
+ if (node instanceof Comment) {
+ childList.add(new StaticTextBox(context, node, COMMENT_BEFORE_TEXT));
} else {
// :before content
final Element beforeElement;
- beforeElement = context.getStyleSheet().getBeforeElement(element);
+ beforeElement = context.getStyleSheet().getBeforeElement((Element) node);
if (beforeElement != null) {
childList.addAll(LayoutUtils.createGeneratedInlines(context, beforeElement));
}
// left marker
- childList.add(createLeftMarker(element, styles));
+ childList.add(createLeftMarker(node, styles));
}
}
// background image
if (styles.hasBackgroundImage() && !styles.getDisplay().equalsIgnoreCase(CSS.NONE)) {
- final ImageBox imageBox = ImageBox.createWithHeight(getElement(), context, styles.getLineHeight());
+ final ImageBox imageBox = ImageBox.createWithHeight(getNode(), context, styles.getLineHeight());
if (imageBox != null) {
childList.add(imageBox);
}
}
- final InlineBoxes inlines = createInlineBoxes(context, element, startOffset, endOffset);
+ final InlineBoxes inlines = createInlineBoxes(context, node, startOffset, endOffset);
childList.addAll(inlines.boxes);
firstContentChild = inlines.firstContentBox;
lastContentChild = inlines.lastContentBox;
- if (endOffset > element.getEndOffset()) {
+ if (endOffset > node.getEndOffset()) {
- childList.add(new PlaceholderBox(context, element, element.getEndOffset() - element.getStartOffset()));
+ childList.add(new PlaceholderBox(context, node, node.getEndOffset() - node.getStartOffset()));
- if (element instanceof CommentElement) {
- childList.add(new StaticTextBox(context, element, COMMENT_AFTER_TEXT));
+ if (node instanceof Comment) {
+ childList.add(new StaticTextBox(context, node, COMMENT_AFTER_TEXT));
} else {
// trailing marker
- childList.add(createRightMarker(element, styles));
+ childList.add(createRightMarker(node, styles));
// :after content
- final Element afterElement = context.getStyleSheet().getAfterElement(element);
+ final Element afterElement = context.getStyleSheet().getAfterElement((Element) node);
if (afterElement != null) {
childList.addAll(LayoutUtils.createGeneratedInlines(context, afterElement));
}
@@ -131,13 +133,13 @@ public class InlineElementBox extends CompositeInlineBox {
*
* @param context
* LayoutContext used for the layout.
- * @param element
- * Element to which this box applies.
+ * @param node
+ * Node to which this box applies.
* @param children
* Child boxes.
*/
- private InlineElementBox(final LayoutContext context, final Element element, final InlineBox[] children) {
- this.element = element;
+ private InlineElementBox(final LayoutContext context, final Node node, final InlineBox[] children) {
+ this.node = node;
this.children = children;
layout(context);
for (final InlineBox child : children) {
@@ -169,8 +171,8 @@ public class InlineElementBox extends CompositeInlineBox {
* Returns the element associated with this box.
*/
@Override
- public Element getElement() {
- return element;
+ public Node getNode() {
+ return node;
}
/**
@@ -179,7 +181,7 @@ public class InlineElementBox extends CompositeInlineBox {
@Override
public int getEndOffset() {
if (lastContentChild == null) {
- return getElement().getEndOffset();
+ return getNode().getEndOffset();
} else {
return lastContentChild.getEndOffset();
}
@@ -191,7 +193,7 @@ public class InlineElementBox extends CompositeInlineBox {
@Override
public int getStartOffset() {
if (firstContentChild == null) {
- return getElement().getStartOffset();
+ return getNode().getStartOffset();
} else {
return firstContentChild.getStartOffset();
}
@@ -216,11 +218,11 @@ public class InlineElementBox extends CompositeInlineBox {
InlineElementBox right = null;
if (lefts.length > 0 || rights.length == 0) {
- left = new InlineElementBox(context, getElement(), lefts);
+ left = new InlineElementBox(context, getNode(), lefts);
}
if (rights.length > 0) {
- right = new InlineElementBox(context, getElement(), rights);
+ right = new InlineElementBox(context, getNode(), rights);
}
return new Pair(left, right);
@@ -229,18 +231,18 @@ public class InlineElementBox extends CompositeInlineBox {
@Override
public String toString() {
final StringBuffer sb = new StringBuffer();
- if (getStartOffset() == getElement().getStartOffset() + 1) {
+ if (getStartOffset() == getNode().getStartOffset() + 1) {
sb.append("<");
- sb.append(getElement().getPrefixedName());
+ sb.append(getNode());
sb.append(">");
}
final Box[] children = getChildren();
for (final Box element2 : children) {
sb.append(element2);
}
- if (getEndOffset() == getElement().getEndOffset()) {
+ if (getEndOffset() == getNode().getEndOffset()) {
sb.append("</");
- sb.append(getElement().getPrefixedName());
+ sb.append(getNode());
sb.append(">");
}
return sb.toString();
@@ -267,68 +269,70 @@ public class InlineElementBox extends CompositeInlineBox {
*
* @param context
* LayoutContext to be used.
- * @param element2
- * Element containing both offsets
+ * @param node
+ * Parent containing both offsets
* @param startOffset
* The start of the range to convert to inline boxes.
* @param endOffset
* The end of the range to convert to inline boxes.
* @return
*/
- static InlineBoxes createInlineBoxes(final LayoutContext context, final Element element2, final int startOffset, final int endOffset) {
-
+ static InlineBoxes createInlineBoxes(final LayoutContext context, final Node node, final int startOffset, final int endOffset) {
final InlineBoxes result = new InlineBoxes();
- final List<Node> nodes = element2.getChildNodes();
- for (int i = 0; i < nodes.size(); i++) {
-
- final Node node = nodes.get(i);
- InlineBox child;
-
- if (node.getStartOffset() >= endOffset) {
- break;
- } else if (node instanceof Text) {
-
- // This check is different for Text and Element, so we have to
- // do it here and below, too.
- if (node.getEndOffset() <= startOffset) {
- continue;
+ node.accept(new BaseNodeVisitor() {
+ @Override
+ public void visit(final Element element) {
+ for (final Node childNode : element.getChildNodes(new Range(startOffset, endOffset))) {
+ childNode.accept(new BaseNodeVisitor() {
+ @Override
+ public void visit(final Element element) {
+ final InlineBox placeholder = new PlaceholderBox(context, node, element.getStartOffset() - node.getStartOffset());
+ result.boxes.add(placeholder);
+ if (result.firstContentBox == null) {
+ result.firstContentBox = placeholder;
+ }
+ final InlineBox child = new InlineElementBox(context, element, startOffset, endOffset);
+ addChildInlineBox(result, child);
+ }
+
+ @Override
+ public void visit(final Text text) {
+ final int start = Math.max(startOffset, text.getStartOffset());
+ final int end = Math.min(endOffset, text.getEndOffset());
+ final InlineBox child = new DocumentTextBox(context, node, start, end);
+ addChildInlineBox(result, child);
+ }
+ });
}
-
- final int start = Math.max(startOffset, node.getStartOffset());
- final int end = Math.min(endOffset, node.getEndOffset());
- child = new DocumentTextBox(context, element2, start, end);
-
- } else {
-
- if (node.getEndOffset() < startOffset) {
- continue;
- }
-
- final Element childElement = (Element) node;
- final InlineBox placeholder = new PlaceholderBox(context, element2, childElement.getStartOffset() - element2.getStartOffset());
- result.boxes.add(placeholder);
- if (result.firstContentBox == null) {
- result.firstContentBox = placeholder;
- }
- child = new InlineElementBox(context, childElement, startOffset, endOffset);
}
- if (result.firstContentBox == null) {
- result.firstContentBox = child;
+ @Override
+ public void visit(final Comment comment) {
+ // TODO use Range
+ final int start = Math.max(startOffset, comment.getStartOffset());
+ final int end = Math.min(endOffset, comment.getEndOffset());
+ final InlineBox child = new DocumentTextBox(context, node, start, end);
+ addChildInlineBox(result, child);
}
+ });
- result.lastContentBox = child;
+ return result;
+ }
- result.boxes.add(child);
+ private static void addChildInlineBox(final InlineBoxes result, final InlineBox child) {
+ if (result.firstContentBox == null) {
+ result.firstContentBox = child;
}
- return result;
+ result.lastContentBox = child;
+
+ result.boxes.add(child);
}
// ========================================================== PRIVATE
- private static InlineBox createLeftMarker(final Element element, final Styles styles) {
+ private static InlineBox createLeftMarker(final Node node, final Styles styles) {
final int size = Math.round(0.5f * styles.getFontSize());
final int lift = Math.round(0.1f * styles.getFontSize());
final Drawable drawable = new Drawable() {
@@ -345,10 +349,10 @@ public class InlineElementBox extends CompositeInlineBox {
return new Rectangle(0, -size, size, size);
}
};
- return new DrawableBox(drawable, element, DrawableBox.START_MARKER);
+ return new DrawableBox(drawable, node, DrawableBox.START_MARKER);
}
- private static InlineBox createRightMarker(final Element element, final Styles styles) {
+ private static InlineBox createRightMarker(final Node node, final Styles styles) {
final int size = Math.round(0.5f * styles.getFontSize());
final int lift = Math.round(0.1f * styles.getFontSize());
final Drawable drawable = new Drawable() {
@@ -365,12 +369,12 @@ public class InlineElementBox extends CompositeInlineBox {
return new Rectangle(0, -size, size, size);
}
};
- return new DrawableBox(drawable, element, DrawableBox.END_MARKER);
+ return new DrawableBox(drawable, node, DrawableBox.END_MARKER);
}
private void layout(final LayoutContext context) {
final Graphics g = context.getGraphics();
- final Styles styles = context.getStyleSheet().getStyles(element);
+ final Styles styles = context.getStyleSheet().getStyles(node);
final FontResource font = g.createFont(styles.getFont());
final FontResource oldFont = g.setFont(font);
final FontMetrics fm = g.getFontMetrics();
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/LayoutContext.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/LayoutContext.java
index fe9f15ee..3914de85 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/LayoutContext.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/LayoutContext.java
@@ -20,7 +20,7 @@ import org.eclipse.vex.core.internal.VEXCorePlugin;
import org.eclipse.vex.core.internal.core.Graphics;
import org.eclipse.vex.core.internal.css.StyleSheet;
import org.eclipse.vex.core.internal.dom.Document;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
/**
* Encapsulation of all the resources needed to create a box tree. Most operations on a box tree, such as creating the
@@ -79,13 +79,13 @@ public class LayoutContext {
}
/**
- * Helper method that returns true if the given element is in the selected range.
+ * Helper method that returns true if the given node is in the selected range.
*
- * @param element
- * Element to test. May be null, in which case this method returns false.
+ * @param node
+ * Node to test. May be null, in which case this method returns false.
*/
- public boolean isElementSelected(final Element element) {
- return element != null && element.getStartOffset() >= getSelectionStart() && element.getEndOffset() + 1 <= getSelectionEnd();
+ public boolean isNodeSelected(final Node node) {
+ return node != null && node.getStartOffset() >= getSelectionStart() && node.getEndOffset() + 1 <= getSelectionEnd();
}
/**
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/LayoutUtils.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/LayoutUtils.java
index 40bdc780..9879a45d 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/LayoutUtils.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/LayoutUtils.java
@@ -13,6 +13,7 @@ package org.eclipse.vex.core.internal.layout;
import java.util.ArrayList;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -22,6 +23,7 @@ import org.eclipse.vex.core.internal.css.StyleSheet;
import org.eclipse.vex.core.internal.css.Styles;
import org.eclipse.vex.core.internal.dom.Element;
import org.eclipse.vex.core.internal.dom.Node;
+import org.eclipse.vex.core.internal.dom.Parent;
/**
* Tools for layout and rendering of CSS-styled boxes
@@ -90,8 +92,8 @@ public class LayoutUtils {
* LayoutContext to use.
* @param displayStyles
* Display types to be explicitly recognized.
- * @param element
- * Element containing the children over which to iterate.
+ * @param parent
+ * Parent containing the children over which to iterate.
* @param startOffset
* Starting offset of the range containing nodes in which we're interested.
* @param endOffset
@@ -100,19 +102,18 @@ public class LayoutUtils {
* DisplayStyleCallback through which the caller is notified of matching elements and non-matching
* ranges.
*/
- public static void iterateChildrenByDisplayStyle(final StyleSheet styleSheet, final Set<String> displayStyles, final Element element, final int startOffset, final int endOffset,
+ public static void iterateChildrenByDisplayStyle(final StyleSheet styleSheet, final Set<String> displayStyles, final Parent parent, final int startOffset, final int endOffset,
final ElementOrRangeCallback callback) {
final List<Node> nonMatching = new ArrayList<Node>();
- final List<Node> nodes = element.getChildNodes();
- for (int i = 0; i < nodes.size(); i++) {
- if (nodes.get(i).getEndOffset() <= startOffset) {
+ for (final Iterator<Node> iterator = parent.getChildIterator(); iterator.hasNext();) {
+ final Node node = iterator.next();
+ if (node.getEndOffset() <= startOffset) {
continue;
- } else if (nodes.get(i).getStartOffset() >= endOffset) {
+ } else if (node.getStartOffset() >= endOffset) {
break;
} else {
- final Node node = nodes.get(i);
if (node instanceof Element) {
final Element childElement = (Element) node;
@@ -122,9 +123,9 @@ public class LayoutUtils {
final Node firstNode = nonMatching.get(0);
final Node lastNode = nonMatching.get(nonMatching.size() - 1);
if (lastNode instanceof Element) {
- callback.onRange(element, firstNode.getStartOffset(), lastNode.getEndOffset() + 1);
+ callback.onRange(parent, firstNode.getStartOffset(), lastNode.getEndOffset() + 1);
} else {
- callback.onRange(element, firstNode.getStartOffset(), lastNode.getEndOffset());
+ callback.onRange(parent, firstNode.getStartOffset(), lastNode.getEndOffset());
}
nonMatching.clear();
}
@@ -142,9 +143,9 @@ public class LayoutUtils {
final Node firstNode = nonMatching.get(0);
final Node lastNode = nonMatching.get(nonMatching.size() - 1);
if (lastNode instanceof Element) {
- callback.onRange(element, firstNode.getStartOffset(), lastNode.getEndOffset() + 1);
+ callback.onRange(parent, firstNode.getStartOffset(), lastNode.getEndOffset() + 1);
} else {
- callback.onRange(element, firstNode.getStartOffset(), lastNode.getEndOffset());
+ callback.onRange(parent, firstNode.getStartOffset(), lastNode.getEndOffset());
}
}
}
@@ -181,7 +182,7 @@ public class LayoutUtils {
return TABLE_CHILD_STYLES.contains(display);
}
- public static void iterateTableRows(final StyleSheet styleSheet, final Element element, final int startOffset, final int endOffset, final ElementOrRangeCallback callback) {
+ public static void iterateTableRows(final StyleSheet styleSheet, final Parent element, final int startOffset, final int endOffset, final ElementOrRangeCallback callback) {
iterateChildrenByDisplayStyle(styleSheet, NON_ROW_STYLES, element, startOffset, endOffset, new ElementOrRangeCallback() {
public void onElement(final Element child, final String displayStyle) {
@@ -194,7 +195,7 @@ public class LayoutUtils {
}
}
- public void onRange(final Element parent, final int startOffset, final int endOffset) {
+ public void onRange(final Parent parent, final int startOffset, final int endOffset) {
// iterate over rows in range
iterateChildrenByDisplayStyle(styleSheet, ROW_STYLES, element, startOffset, endOffset, callback);
}
@@ -202,11 +203,11 @@ public class LayoutUtils {
}
- public static void iterateTableCells(final StyleSheet styleSheet, final Element element, final int startOffset, final int endOffset, final ElementOrRangeCallback callback) {
+ public static void iterateTableCells(final StyleSheet styleSheet, final Parent element, final int startOffset, final int endOffset, final ElementOrRangeCallback callback) {
iterateChildrenByDisplayStyle(styleSheet, CELL_STYLES, element, startOffset, endOffset, callback);
}
- public static void iterateTableCells(final StyleSheet styleSheet, final Element row, final ElementOrRangeCallback callback) {
+ public static void iterateTableCells(final StyleSheet styleSheet, final Parent row, final ElementOrRangeCallback callback) {
iterateChildrenByDisplayStyle(styleSheet, CELL_STYLES, row, row.getStartOffset(), row.getEndOffset(), callback);
}
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 a2aac3de..d0befaec 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
@@ -10,14 +10,14 @@
*******************************************************************************/
package org.eclipse.vex.core.internal.layout;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
/**
* Represents a line of text and inline images.
*/
public class LineBox extends CompositeInlineBox {
- private final Element element;
+ private final Node node;
private final InlineBox[] children;
private InlineBox firstContentChild = null;
private InlineBox lastContentChild = null;
@@ -31,9 +31,9 @@ public class LineBox extends CompositeInlineBox {
* @param children
* InlineBoxes that make up this line.
*/
- public LineBox(final LayoutContext context, final Element element, final InlineBox[] children) {
+ public LineBox(final LayoutContext context, final Node node, final InlineBox[] children) {
- this.element = element;
+ this.node = node;
this.children = children;
int height = 0;
@@ -70,11 +70,11 @@ public class LineBox extends CompositeInlineBox {
}
/**
- * @see org.eclipse.vex.core.internal.layout.Box#getElement()
+ * @see org.eclipse.vex.core.internal.layout.Box#getNode()
*/
@Override
- public Element getElement() {
- return element;
+ public Node getNode() {
+ return node;
}
/**
@@ -112,11 +112,11 @@ public class LineBox extends CompositeInlineBox {
LineBox right = null;
if (lefts.length > 0) {
- left = new LineBox(context, getElement(), lefts);
+ left = new LineBox(context, getNode(), lefts);
}
if (rights.length > 0) {
- right = new LineBox(context, getElement(), rights);
+ right = new LineBox(context, getNode(), rights);
}
return new Pair(left, right);
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 e9da0708..7f13e7c5 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
@@ -19,6 +19,7 @@ import org.eclipse.vex.core.internal.core.IntRange;
import org.eclipse.vex.core.internal.css.CSS;
import org.eclipse.vex.core.internal.css.Styles;
import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
/**
* A box that wraps inline content into a paragraph.
@@ -69,19 +70,19 @@ public class ParagraphBox extends AbstractBox implements BlockBox {
*
* @param context
* LayoutContext used for this layout
- * @param element
- * Element that controls the styling of this paragraph, in particular text alignment.
+ * @param node
+ * Node that controls the styling of this paragraph, in particular text alignment.
* @param inlines
* Array of InlineBox objects to be wrapped.
* @param width
* width to which the paragraph is to be wrapped.
*/
- public static ParagraphBox create(final LayoutContext context, final Element element, final InlineBox[] inlines, final int width) {
+ public static ParagraphBox create(final LayoutContext context, final Node node, final InlineBox[] inlines, final int width) {
// lines is the list of LineBoxes we are creating
final List<Box> lines = new ArrayList<Box>();
- InlineBox right = new LineBox(context, element, inlines);
+ InlineBox right = new LineBox(context, node, inlines);
while (right != null) {
final InlineBox.Pair pair = right.split(context, width, true);
@@ -91,7 +92,7 @@ public class ParagraphBox extends AbstractBox implements BlockBox {
right = pair.getRight();
}
- final Styles styles = context.getStyleSheet().getStyles(element);
+ final Styles styles = context.getStyleSheet().getStyles(node);
final String textAlign = styles.getTextAlign();
// y-offset of the next line
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 4783999b..dc10d9aa 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
@@ -15,14 +15,14 @@ import org.eclipse.vex.core.internal.core.FontMetrics;
import org.eclipse.vex.core.internal.core.FontResource;
import org.eclipse.vex.core.internal.core.Graphics;
import org.eclipse.vex.core.internal.css.Styles;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
/**
* A zero-width box that represents a single offset in the document.
*/
public class PlaceholderBox extends AbstractInlineBox {
- private final Element element;
+ private final Node node;
private final int relOffset;
private final int textTop;
private final int baseline;
@@ -32,21 +32,21 @@ public class PlaceholderBox extends AbstractInlineBox {
*
* @param context
* LayoutContext in effect.
- * @param element2
- * Element containing this placeholder. the element is used both to determine the size of the box and its
+ * @param node
+ * Node containing this placeholder. The node is used both to determine the size of the box and its
* caret, but also as a base point for relOffset.
* @param relOffset
* Offset of the placeholder, relative to the start of the element.
*/
- public PlaceholderBox(final LayoutContext context, final Element element2, final int relOffset) {
+ public PlaceholderBox(final LayoutContext context, final Node node, final int relOffset) {
- element = element2;
+ this.node = node;
this.relOffset = relOffset;
setWidth(0);
final Graphics g = context.getGraphics();
- final Styles styles = context.getStyleSheet().getStyles(element2);
+ final Styles styles = context.getStyleSheet().getStyles(node);
final FontResource font = g.createFont(styles.getFont());
final FontResource oldFont = g.setFont(font);
final FontMetrics fm = g.getFontMetrics();
@@ -85,11 +85,11 @@ public class PlaceholderBox extends AbstractInlineBox {
}
/**
- * @see org.eclipse.vex.core.internal.layout.Box#getElement()
+ * @see org.eclipse.vex.core.internal.layout.Box#getNode()
*/
@Override
- public Element getElement() {
- return element;
+ public Node getNode() {
+ return node;
}
/**
@@ -97,7 +97,7 @@ public class PlaceholderBox extends AbstractInlineBox {
*/
@Override
public int getEndOffset() {
- return element.getStartOffset() + relOffset;
+ return node.getStartOffset() + relOffset;
}
/**
@@ -105,7 +105,7 @@ public class PlaceholderBox extends AbstractInlineBox {
*/
@Override
public int getStartOffset() {
- return element.getStartOffset() + relOffset;
+ return node.getStartOffset() + relOffset;
}
/**
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/RootBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/RootBox.java
index 56089fa4..ddfb9fdc 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/RootBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/RootBox.java
@@ -65,10 +65,10 @@ public class RootBox extends AbstractBox implements BlockBox {
}
/**
- * @see org.eclipse.vex.core.internal.layout.Box#getElement()
+ * @see org.eclipse.vex.core.internal.layout.Box#getNode()
*/
@Override
- public Element getElement() {
+ public Element getNode() {
return element;
}
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 58f65ca2..b3d784ff 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
@@ -14,7 +14,7 @@ import org.eclipse.vex.core.internal.core.ColorResource;
import org.eclipse.vex.core.internal.core.FontResource;
import org.eclipse.vex.core.internal.core.Graphics;
import org.eclipse.vex.core.internal.css.Styles;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
/**
* A TextBox representing a static string. Represents text which is not editable within the VexWidget, such as
@@ -34,13 +34,13 @@ public class StaticTextBox extends TextBox {
*
* @param context
* LayoutContext used to calculate the box's size.
- * @param element
- * Element used to style the text.
+ * @param node
+ * Node used to style the text.
* @param text
* Static text to display
*/
- public StaticTextBox(final LayoutContext context, final Element element, final String text) {
- this(context, element, text, NO_MARKER);
+ public StaticTextBox(final LayoutContext context, final Node node, final String text) {
+ this(context, node, text, NO_MARKER);
if (text.length() == 0) {
throw new IllegalArgumentException("StaticTextBox cannot have an empty text string.");
}
@@ -53,16 +53,16 @@ public class StaticTextBox extends TextBox {
*
* @param context
* LayoutContext used to calculate the box's size
- * @param element
- * Element used to style the text
+ * @param node
+ * Node used to style the text
* @param text
* Static text to display
* @param marker
* START_MARKER or END_MARKER, depending on whether the text represents the start sentinel or the end
* sentinel of the element
*/
- public StaticTextBox(final LayoutContext context, final Element element, final String text, final byte marker) {
- super(element);
+ public StaticTextBox(final LayoutContext context, final Node node, final String text, final byte marker) {
+ super(node);
this.text = text;
this.marker = marker;
calculateSize(context);
@@ -90,14 +90,14 @@ public class StaticTextBox extends TextBox {
@Override
public void paint(final LayoutContext context, final int x, final int y) {
- final Styles styles = context.getStyleSheet().getStyles(getElement());
+ final Styles styles = context.getStyleSheet().getStyles(getNode());
final Graphics g = context.getGraphics();
boolean drawSelected = false;
if (marker == START_MARKER) {
- drawSelected = getElement().getStartOffset() >= context.getSelectionStart() && getElement().getStartOffset() + 1 <= context.getSelectionEnd();
+ drawSelected = getNode().getStartOffset() >= context.getSelectionStart() && getNode().getStartOffset() + 1 <= context.getSelectionEnd();
} else if (marker == END_MARKER) {
- drawSelected = getElement().getEndOffset() >= context.getSelectionStart() && getElement().getEndOffset() + 1 <= context.getSelectionEnd();
+ drawSelected = getNode().getEndOffset() >= context.getSelectionStart() && getNode().getEndOffset() + 1 <= context.getSelectionEnd();
}
final FontResource font = g.createFont(styles.getFont());
@@ -129,14 +129,14 @@ public class StaticTextBox extends TextBox {
if (offset == 0) {
left = null;
} else {
- left = new StaticTextBox(context, getElement(), getText().substring(0, offset), marker);
+ left = new StaticTextBox(context, getNode(), getText().substring(0, offset), marker);
}
StaticTextBox right;
if (offset == getText().length()) {
right = null;
} else {
- right = new StaticTextBox(context, getElement(), getText().substring(offset), marker);
+ right = new StaticTextBox(context, getNode(), getText().substring(offset), marker);
}
return new Pair(left, right);
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/TableBodyBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/TableBodyBox.java
index 6f1bb626..9669d2aa 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/TableBodyBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/TableBodyBox.java
@@ -20,6 +20,7 @@ import org.eclipse.vex.core.internal.core.Insets;
import org.eclipse.vex.core.internal.css.CSS;
import org.eclipse.vex.core.internal.css.Styles;
import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Parent;
/**
* An anonymous box that contains the table row groups for a table. This box is generated by a TableBox and assumes the
@@ -46,7 +47,7 @@ public class TableBodyBox extends AbstractBlockBox {
children.add(new TableRowGroupBox(context, TableBodyBox.this, child));
}
- public void onRange(final Element parent, final int startOffset, final int endOffset) {
+ public void onRange(final Parent parent, final int startOffset, final int endOffset) {
children.add(new TableRowGroupBox(context, TableBodyBox.this, startOffset, endOffset));
}
});
@@ -59,8 +60,8 @@ public class TableBodyBox extends AbstractBlockBox {
*/
@Override
public Insets getInsets(final LayoutContext context, final int containerWidth) {
- if (getParent().getElement() != null) {
- final Styles styles = context.getStyleSheet().getStyles(getParent().getElement());
+ if (getParent().getNode() != null) {
+ final Styles styles = context.getStyleSheet().getStyles(getParent().getNode());
return AbstractBox.getInsets(styles, containerWidth);
} else {
return Insets.ZERO_INSETS;
@@ -69,7 +70,7 @@ public class TableBodyBox extends AbstractBlockBox {
@Override
public void paint(final LayoutContext context, final int x, final int y) {
- this.drawBox(context, getParent().getElement(), x, y, getParent().getWidth(), true);
+ this.drawBox(context, getParent().getNode(), x, y, getParent().getWidth(), true);
paintChildren(context, x, y);
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/TableBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/TableBox.java
index 6722ae12..1db07cc3 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/TableBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/TableBox.java
@@ -22,6 +22,8 @@ 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.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
+import org.eclipse.vex.core.internal.dom.Parent;
/**
* Box that lays out a table.
@@ -31,11 +33,11 @@ public class TableBox extends AbstractBlockBox {
/**
* Class constructor.
*
- * @param element
+ * @param node
* Element represented by this box.
*/
- public TableBox(final LayoutContext context, final BlockBox parent, final Element element) {
- super(context, parent, element);
+ public TableBox(final LayoutContext context, final BlockBox parent, final Node node) {
+ super(context, parent, node);
}
public TableBox(final LayoutContext context, final BlockBox parent, final int startOffset, final int endOffset) {
@@ -58,7 +60,7 @@ public class TableBox extends AbstractBlockBox {
children.add(new BlockElementBox(context, TableBox.this, child));
}
- public void onRange(final Element parent, final int startOffset, final int endOffset) {
+ public void onRange(final Parent parent, final int startOffset, final int endOffset) {
children.add(new TableBodyBox(context, TableBox.this, startOffset, endOffset));
}
});
@@ -146,7 +148,7 @@ public class TableBox extends AbstractBlockBox {
count++;
}
- public void onRange(final Element parent, final int startOffset, final int endOffset) {
+ public void onRange(final Parent parent, final int startOffset, final int endOffset) {
count++;
}
@@ -158,7 +160,7 @@ public class TableBox extends AbstractBlockBox {
*/
private int computeColumnCount(final LayoutContext context) {
- final Element tableElement = findContainingElement();
+ final Parent tableElement = findContainingParent();
final int[] columnCounts = new int[1]; // work around Java's insistence
// on final
columnCounts[0] = 0;
@@ -171,7 +173,7 @@ public class TableBox extends AbstractBlockBox {
callback.reset();
}
- public void onRange(final Element parent, final int startOffset, final int endOffset) {
+ public void onRange(final Parent parent, final int startOffset, final int endOffset) {
LayoutUtils.iterateTableCells(styleSheet, parent, startOffset, endOffset, callback);
columnCounts[0] = Math.max(columnCounts[0], callback.getCount());
callback.reset();
@@ -196,7 +198,7 @@ public class TableBox extends AbstractBlockBox {
int availableWidth = myWidth;
if (!isAnonymous()) {
- final Styles styles = context.getStyleSheet().getStyles(getElement());
+ final Styles styles = context.getStyleSheet().getStyles(getNode());
horizonalSpacing = styles.getBorderSpacing().getHorizontal();
verticalSpacing = styles.getBorderSpacing().getVertical();
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/TableRowBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/TableRowBox.java
index 238a054c..6659ac88 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/TableRowBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/TableRowBox.java
@@ -17,6 +17,7 @@ import java.util.List;
import org.eclipse.vex.core.internal.core.Caret;
import org.eclipse.vex.core.internal.core.Insets;
import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Parent;
/**
* Box representing a row in a table.
@@ -36,17 +37,17 @@ public class TableRowBox extends AbstractBlockBox {
final List<Box> children = new ArrayList<Box>();
- final Element element = findContainingElement();
+ final Parent parent = findContainingParent();
final int[] widths = getTableBox().getColumnWidths();
- LayoutUtils.iterateTableCells(context.getStyleSheet(), element, getStartOffset(), getEndOffset(), new ElementOrRangeCallback() {
+ LayoutUtils.iterateTableCells(context.getStyleSheet(), parent, getStartOffset(), getEndOffset(), new ElementOrRangeCallback() {
private int column = 0;
public void onElement(final Element child, final String displayStyle) {
children.add(new TableCellBox(context, TableRowBox.this, child, widths[column++]));
}
- public void onRange(final Element parent, final int startOffset, final int endOffset) {
+ public void onRange(final Parent parent, final int startOffset, final int endOffset) {
children.add(new TableCellBox(context, TableRowBox.this, startOffset, endOffset, widths[column++]));
}
});
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/TableRowGroupBox.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/TableRowGroupBox.java
index 2b17fe8e..dbb079f6 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/TableRowGroupBox.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/TableRowGroupBox.java
@@ -20,6 +20,8 @@ import org.eclipse.vex.core.internal.core.Insets;
import org.eclipse.vex.core.internal.css.CSS;
import org.eclipse.vex.core.internal.css.Styles;
import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
+import org.eclipse.vex.core.internal.dom.Parent;
/**
* Container for TableRowBox objects. May correspond to an element with display:table-row-group,
@@ -34,11 +36,11 @@ public class TableRowGroupBox extends AbstractBlockBox {
* LayoutContext to use.
* @param parent
* Parent of this box.
- * @param element
- * Element that generated this box.
+ * @param node
+ * Node that generated this box.
*/
- public TableRowGroupBox(final LayoutContext context, final BlockBox parent, final Element element) {
- super(context, parent, element);
+ public TableRowGroupBox(final LayoutContext context, final BlockBox parent, final Node node) {
+ super(context, parent, node);
}
/**
@@ -73,7 +75,7 @@ public class TableRowGroupBox extends AbstractBlockBox {
children.add(new TableRowBox(context, TableRowGroupBox.this, child));
}
- public void onRange(final Element parent, final int startOffset, final int endOffset) {
+ public void onRange(final Parent parent, final int startOffset, final int endOffset) {
children.add(new TableRowBox(context, TableRowGroupBox.this, startOffset, endOffset));
}
});
@@ -111,7 +113,7 @@ public class TableRowGroupBox extends AbstractBlockBox {
@Override
protected int positionChildren(final LayoutContext context) {
- final Styles styles = context.getStyleSheet().getStyles(findContainingElement());
+ final Styles styles = context.getStyleSheet().getStyles(findContainingParent());
final int spacing = styles.getBorderSpacing().getVertical();
int childY = spacing;
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 f104ca9d..4738dc4e 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
@@ -17,7 +17,7 @@ import org.eclipse.vex.core.internal.core.FontResource;
import org.eclipse.vex.core.internal.core.FontSpec;
import org.eclipse.vex.core.internal.core.Graphics;
import org.eclipse.vex.core.internal.css.Styles;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
/**
* An inline box containing text. The <code>getText</code> and <code>splitAt</code> methods are abstract and must be
@@ -25,7 +25,7 @@ import org.eclipse.vex.core.internal.dom.Element;
*/
public abstract class TextBox extends AbstractInlineBox implements InlineBox {
- private final Element element;
+ private final Node node;
private int baseline;
public static final char NEWLINE_CHAR = 0xa;
@@ -34,11 +34,11 @@ public abstract class TextBox extends AbstractInlineBox implements InlineBox {
/**
* Class constructor.
*
- * @param element
- * Element containing the text. This is used for styling information.
+ * @param node
+ * Node containing the text. This is used for styling information.
*/
- public TextBox(final Element element) {
- this.element = element;
+ public TextBox(final Node node) {
+ this.node = node;
}
/**
@@ -55,7 +55,7 @@ public abstract class TextBox extends AbstractInlineBox implements InlineBox {
}
final Graphics g = context.getGraphics();
- final Styles styles = context.getStyleSheet().getStyles(getElement());
+ 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();
@@ -80,7 +80,7 @@ public abstract class TextBox extends AbstractInlineBox implements InlineBox {
@Override
public Caret getCaret(final LayoutContext context, final int offset) {
final Graphics g = context.getGraphics();
- final Styles styles = context.getStyleSheet().getStyles(element);
+ final Styles styles = context.getStyleSheet().getStyles(node);
final FontResource oldFont = g.getFont();
final FontResource font = g.createFont(styles.getFont());
g.setFont(font);
@@ -92,11 +92,11 @@ public abstract class TextBox extends AbstractInlineBox implements InlineBox {
}
/**
- * Returns the element that controls the styling for this text element.
+ * Returns the node that controls the styling for this text box.
*/
@Override
- public Element getElement() {
- return element;
+ public Node getNode() {
+ return node;
}
/**
@@ -137,11 +137,11 @@ public abstract class TextBox extends AbstractInlineBox implements InlineBox {
final Graphics g = context.getGraphics();
boolean inSelectedBlock = false;
- Element e = getElement();
+ Node e = getNode();
while (e != null) {
final Styles styles = context.getStyleSheet().getStyles(e);
if (styles.isBlock()) {
- if (context.isElementSelected(e)) {
+ if (context.isNodeSelected(e)) {
inSelectedBlock = true;
}
break;
@@ -216,7 +216,7 @@ public abstract class TextBox extends AbstractInlineBox implements InlineBox {
}
final Graphics g = context.getGraphics();
- final Styles styles = context.getStyleSheet().getStyles(element);
+ final Styles styles = context.getStyleSheet().getStyles(node);
final FontResource font = g.createFont(styles.getFont());
final FontResource oldFont = g.setFont(font);
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 6083eabe..5c077d6c 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
@@ -25,7 +25,6 @@ import java.util.Set;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.vex.core.internal.dom.Attribute;
-import org.eclipse.vex.core.internal.dom.CommentElement;
import org.eclipse.vex.core.internal.dom.DocumentContentModel;
import org.eclipse.vex.core.internal.dom.Element;
import org.eclipse.vex.core.internal.dom.Validator;
@@ -55,7 +54,7 @@ public class WTPVEXValidator implements Validator {
@Override
public boolean isIgnorable(final Object o) {
- return CommentElement.ELEMENT_NAME.toString().equals(o);
+ return o == null;
}
};
@@ -180,7 +179,7 @@ public class WTPVEXValidator implements Validator {
if (declarationFromRoot != null) {
return declarationFromRoot;
}
- final CMElementDeclaration parentDeclaration = getElementDeclaration(element.getParent());
+ final CMElementDeclaration parentDeclaration = getElementDeclaration(element.getParentElement());
if (parentDeclaration == null) {
return null;
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/CssWhitespacePolicy.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/CssWhitespacePolicy.java
index 0a38e396..a95f9198 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/CssWhitespacePolicy.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/CssWhitespacePolicy.java
@@ -12,8 +12,8 @@ package org.eclipse.vex.core.internal.widget;
import org.eclipse.vex.core.internal.css.CSS;
import org.eclipse.vex.core.internal.css.StyleSheet;
-import org.eclipse.vex.core.internal.dom.Element;
import org.eclipse.vex.core.internal.dom.IWhitespacePolicy;
+import org.eclipse.vex.core.internal.dom.Node;
/**
* Implementation of WhitespacePolicy using a CSS stylesheet.
@@ -30,12 +30,12 @@ public class CssWhitespacePolicy implements IWhitespacePolicy {
this.styleSheet = styleSheet;
}
- public boolean isBlock(final Element element) {
- return styleSheet.getStyles(element).isBlock();
+ public boolean isBlock(final Node node) {
+ return styleSheet.getStyles(node).isBlock();
}
- public boolean isPre(final Element element) {
- return CSS.PRE.equals(styleSheet.getStyles(element).getWhiteSpace());
+ public boolean isPre(final Node node) {
+ return CSS.PRE.equals(styleSheet.getStyles(node).getWhiteSpace());
}
// ===================================================== PRIVATE
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/IVexWidget.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/IVexWidget.java
index ee530022..acdcc720 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/IVexWidget.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/IVexWidget.java
@@ -13,6 +13,7 @@ package org.eclipse.vex.core.internal.widget;
import java.io.IOException;
import java.net.URL;
+import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.vex.core.internal.core.ElementName;
import org.eclipse.vex.core.internal.css.StyleSheet;
import org.eclipse.vex.core.internal.dom.Document;
@@ -254,6 +255,8 @@ public interface IVexWidget {
*/
public void insertElement(Element element) throws DocumentValidationException;
+ public void insertElement(QualifiedName elementName) throws DocumentValidationException;
+
/**
* Inserts the given text at the current caret position. Any selected content is first deleted.
*
@@ -263,6 +266,11 @@ public interface IVexWidget {
public void insertText(String text) throws DocumentValidationException;
/**
+ * Inserts a comment a the current caret position. Any selected content is first deleted.
+ */
+ public void insertComment() throws DocumentValidationException;
+
+ /**
* Returns the value of the debugging flag.
*/
public boolean isDebugging();
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/VexWidgetImpl.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/VexWidgetImpl.java
index 1b727bda..40e02f1d 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/VexWidgetImpl.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/VexWidgetImpl.java
@@ -41,7 +41,9 @@ import org.eclipse.vex.core.internal.dom.DocumentFragment;
import org.eclipse.vex.core.internal.dom.DocumentListener;
import org.eclipse.vex.core.internal.dom.DocumentValidationException;
import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
import org.eclipse.vex.core.internal.dom.Position;
+import org.eclipse.vex.core.internal.dom.Range;
import org.eclipse.vex.core.internal.dom.Validator;
import org.eclipse.vex.core.internal.layout.BlockBox;
import org.eclipse.vex.core.internal.layout.Box;
@@ -212,9 +214,9 @@ public class VexWidgetImpl implements IVexWidget {
}
final Element parent = getDocument().getElementAt(startOffset);
- final List<QualifiedName> seq1 = doc.getNodeNames(parent.getStartOffset() + 1, startOffset);
+ final List<QualifiedName> seq1 = Node.getNodeNames(parent.getChildNodesBefore(startOffset));
final List<QualifiedName> seq2 = frag.getNodeNames();
- final List<QualifiedName> seq3 = doc.getNodeNames(endOffset, parent.getEndOffset());
+ final List<QualifiedName> seq3 = Node.getNodeNames(parent.getChildNodesAfter(endOffset));
return validator.isValidSequence(parent.getQualifiedName(), seq1, seq2, seq3, true);
}
@@ -241,9 +243,9 @@ public class VexWidgetImpl implements IVexWidget {
}
final Element parent = getDocument().getElementAt(startOffset);
- final List<QualifiedName> seq1 = doc.getNodeNames(parent.getStartOffset() + 1, startOffset);
+ final List<QualifiedName> seq1 = Node.getNodeNames(parent.getChildNodesBefore(startOffset));
final List<QualifiedName> seq2 = Collections.singletonList(Validator.PCDATA);
- final List<QualifiedName> seq3 = doc.getNodeNames(endOffset, parent.getEndOffset());
+ final List<QualifiedName> seq3 = Node.getNodeNames(parent.getChildNodesAfter(endOffset));
return validator.isValidSequence(parent.getQualifiedName(), seq1, seq2, seq3, true);
}
@@ -276,15 +278,15 @@ public class VexWidgetImpl implements IVexWidget {
}
final Element element = doc.getElementAt(getCaretOffset());
- final Element parent = element.getParent();
+ final Element parent = element.getParentElement();
if (parent == null) {
// can't unwrap the root
return false;
}
- final List<QualifiedName> seq1 = doc.getNodeNames(parent.getStartOffset() + 1, element.getStartOffset());
- final List<QualifiedName> seq2 = doc.getNodeNames(element.getStartOffset() + 1, element.getEndOffset());
- final List<QualifiedName> seq3 = doc.getNodeNames(element.getEndOffset() + 1, parent.getEndOffset());
+ final List<QualifiedName> seq1 = Node.getNodeNames(parent.getChildNodesBefore(element.getStartOffset()));
+ final List<QualifiedName> seq2 = Node.getNodeNames(element.getChildNodes());
+ final List<QualifiedName> seq3 = Node.getNodeNames(parent.getChildNodesAfter(element.getEndOffset()));
return validator.isValidSequence(parent.getQualifiedName(), seq1, seq2, seq3, true);
}
@@ -323,7 +325,7 @@ public class VexWidgetImpl implements IVexWidget {
// so just delete the whole element an move on
this.moveTo(offset + 2, true);
deleteSelection();
- } else if (doc.getCharacterAt(offset) != 0) {
+ } else if (!doc.isElementAt(offset)) {
this.moveTo(offset, false);
this.moveTo(offset + 1, true);
deleteSelection();
@@ -359,7 +361,7 @@ public class VexWidgetImpl implements IVexWidget {
deleteSelection();
} else {
offset--;
- if (doc.getCharacterAt(offset) != 0) {
+ if (!doc.isElementAt(offset)) {
this.moveTo(offset, false);
this.moveTo(offset + 1, true);
deleteSelection();
@@ -372,7 +374,7 @@ public class VexWidgetImpl implements IVexWidget {
public void deleteSelection() {
try {
if (hasSelection()) {
- document.delete(getSelectionStart(), getSelectionEnd());
+ document.delete(new Range(getSelectionStart(), getSelectionEnd()));
this.moveTo(getSelectionStart());
}
} catch (final DocumentValidationException ex) {
@@ -538,9 +540,9 @@ public class VexWidgetImpl implements IVexWidget {
final int endOffset = getEndOffset();
final Element parent = doc.getElementAt(startOffset);
- final List<QualifiedName> nodesBefore = doc.getNodeNames(parent.getStartOffset() + 1, startOffset);
- final List<QualifiedName> nodesAfter = doc.getNodeNames(endOffset, parent.getEndOffset());
- final List<QualifiedName> selectedNodes = doc.getNodeNames(startOffset, endOffset);
+ final List<QualifiedName> nodesBefore = Node.getNodeNames(parent.getChildNodesBefore(startOffset));
+ final List<QualifiedName> nodesAfter = Node.getNodeNames(parent.getChildNodesAfter(endOffset));
+ final List<QualifiedName> selectedNodes = Node.getNodeNames(parent.getChildNodes(new Range(startOffset, endOffset)));
final List<QualifiedName> candidates = createCandidatesList(validator, parent, Validator.PCDATA);
filterInvalidSequences(validator, parent, nodesBefore, nodesAfter, candidates);
@@ -616,7 +618,7 @@ public class VexWidgetImpl implements IVexWidget {
}
final Element element = doc.getElementAt(getCaretOffset());
- final Element parent = element.getParent();
+ final Element parent = element.getParentElement();
if (parent == null) {
// can't morph the root
return new ElementName[0];
@@ -625,7 +627,7 @@ public class VexWidgetImpl implements IVexWidget {
final List<QualifiedName> candidates = createCandidatesList(validator, parent, Validator.PCDATA, element.getQualifiedName());
// root out those that can't contain the current content
- final List<QualifiedName> content = doc.getNodeNames(element.getStartOffset() + 1, element.getEndOffset());
+ final List<QualifiedName> content = Node.getNodeNames(element.getChildNodes());
for (final Iterator<QualifiedName> iter = candidates.iterator(); iter.hasNext();) {
final QualifiedName candidate = iter.next();
@@ -653,7 +655,7 @@ public class VexWidgetImpl implements IVexWidget {
public DocumentFragment getSelectedFragment() {
if (hasSelection()) {
- return document.getFragment(getSelectionStart(), getSelectionEnd());
+ return document.getFragment(new Range(getSelectionStart(), getSelectionEnd()));
} else {
return null;
}
@@ -661,7 +663,7 @@ public class VexWidgetImpl implements IVexWidget {
public String getSelectedText() {
if (hasSelection()) {
- return document.getText(getSelectionStart(), getSelectionEnd());
+ return document.getText(new Range(getSelectionStart(), getSelectionEnd()));
} else {
return "";
}
@@ -705,6 +707,29 @@ public class VexWidgetImpl implements IVexWidget {
this.moveTo(getCaretOffset() + frag.getLength());
}
+ public void insertElement(final QualifiedName elementName) throws DocumentValidationException {
+ boolean success = false;
+ try {
+ beginWork();
+
+ DocumentFragment frag = null;
+ if (hasSelection()) {
+ frag = getSelectedFragment();
+ deleteSelection();
+ }
+
+ document.insertElement(getCaretOffset(), elementName);
+ this.moveTo(getCaretOffset() + 1);
+ if (frag != null) {
+ insertFragment(frag);
+ }
+ scrollCaretVisible();
+ success = true;
+ } finally {
+ endWork(success);
+ }
+ }
+
public void insertElement(final Element element) throws DocumentValidationException {
boolean success = false;
@@ -760,6 +785,23 @@ public class VexWidgetImpl implements IVexWidget {
}
}
+ public void insertComment() throws DocumentValidationException {
+ if (hasSelection()) {
+ deleteSelection();
+ }
+
+ boolean success = false;
+ try {
+ beginWork();
+ document.insertComment(getCaretOffset());
+ this.moveTo(getCaretOffset() + 1);
+ scrollCaretVisible();
+ success = true;
+ } finally {
+ endWork(success);
+ }
+ }
+
public void morph(final Element element) throws DocumentValidationException {
final Document doc = getDocument();
@@ -864,7 +906,7 @@ public class VexWidgetImpl implements IVexWidget {
caretColor = new Color(red, green, blue);
break;
}
- element = element.getParent();
+ element = element.getParentElement();
}
}
@@ -1160,7 +1202,7 @@ public class VexWidgetImpl implements IVexWidget {
Element element = doc.getElementAt(getCaretOffset());
Styles styles = getStyleSheet().getStyles(element);
while (!styles.isBlock()) {
- element = element.getParent();
+ element = element.getParentElement();
styles = getStyleSheet().getStyles(element);
}
@@ -1186,7 +1228,7 @@ public class VexWidgetImpl implements IVexWidget {
// let's move just outside
this.moveTo(getCaretOffset() + 1);
- insertElement(new Element(element.getQualifiedName()));
+ insertElement(element.getQualifiedName());
// TODO: clone attributes
if (!atEnd) {
@@ -1321,7 +1363,7 @@ public class VexWidgetImpl implements IVexWidget {
final BlockBox elementBox = (BlockBox) this.findInnermostBox(new IBoxFilter() {
public boolean matches(final Box box) {
- return box instanceof BlockBox && box.getElement() != null && box.getStartOffset() <= element.getStartOffset() + 1 && box.getEndOffset() >= element.getEndOffset();
+ return box instanceof BlockBox && box.getNode() != null && box.getStartOffset() <= element.getStartOffset() + 1 && box.getEndOffset() >= element.getEndOffset();
}
});
diff --git a/org.eclipse.vex.docbook/src/org/eclipse/vex/docbook/DocBookOutlineProvider.java b/org.eclipse.vex.docbook/src/org/eclipse/vex/docbook/DocBookOutlineProvider.java
index 1d156241..94980717 100644
--- a/org.eclipse.vex.docbook/src/org/eclipse/vex/docbook/DocBookOutlineProvider.java
+++ b/org.eclipse.vex.docbook/src/org/eclipse/vex/docbook/DocBookOutlineProvider.java
@@ -43,8 +43,8 @@ public class DocBookOutlineProvider implements IOutlineProvider {
public Element getOutlineElement(final Element child) {
Element element = child;
- while (element.getParent() != null && !isTitledElement(element)) {
- element = element.getParent();
+ while (element.getParentElement() != null && !isTitledElement(element)) {
+ element = element.getParentElement();
}
return element;
@@ -63,7 +63,7 @@ public class DocBookOutlineProvider implements IOutlineProvider {
}
public Object getParent(final Object element) {
- final Element parent = ((Element) element).getParent();
+ final Element parent = ((Element) element).getParentElement();
if (parent == null) {
return element;
} else {
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 7523e417..786c82e4 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
@@ -12,8 +12,8 @@ package org.eclipse.vex.ui.internal.editor;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.vex.core.internal.dom.DocumentContentModel;
+import org.eclipse.vex.core.internal.dom.Element;
import org.eclipse.vex.core.internal.dom.IWhitespacePolicy;
-import org.eclipse.vex.core.internal.dom.RootElement;
import org.eclipse.vex.core.internal.widget.CssWhitespacePolicy;
import org.eclipse.vex.ui.internal.VexPlugin;
import org.eclipse.vex.ui.internal.config.DocumentType;
@@ -37,7 +37,7 @@ public class VexDocumentContentModel extends DocumentContentModel {
}
@Override
- public void initialize(final String baseUri, final String publicId, final String systemId, final RootElement rootElement) {
+ public void initialize(final String baseUri, final String publicId, final String systemId, final Element rootElement) {
super.initialize(baseUri, publicId, systemId, rootElement);
final String mainDocumentTypeIdentifier = getMainDocumentTypeIdentifier();
documentType = getRegisteredDocumentType();
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 72c5e327..19e3bd2c 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
@@ -723,7 +723,7 @@ public class VexEditor extends EditorPart {
Element element = vexWidget.getCurrentElement();
while (element != null) {
path.add(element.getPrefixedName());
- element = element.getParent();
+ element = element.getParentElement();
}
Collections.reverse(path);
final StringBuilder sb = new StringBuilder(path.size() * 15);
@@ -777,20 +777,7 @@ public class VexEditor extends EditorPart {
@Override
protected CharSequence getDocument() {
- return new CharSequence() {
-
- public CharSequence subSequence(final int start, final int end) {
- return document.getRawText(start, end);
- }
-
- public int length() {
- return document.getLength();
- }
-
- public char charAt(final int index) {
- return document.getCharacterAt(index);
- }
- };
+ return document.getContent();
}
@Override
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/AbstractAddColumnHandler.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/AbstractAddColumnHandler.java
index f111dd5c..78bc6263 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/AbstractAddColumnHandler.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/AbstractAddColumnHandler.java
@@ -17,6 +17,7 @@ import java.util.List;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.vex.core.internal.dom.CopyVisitor;
import org.eclipse.vex.core.internal.dom.Element;
import org.eclipse.vex.ui.internal.swt.VexWidget;
@@ -60,13 +61,14 @@ public abstract class AbstractAddColumnHandler extends AbstractHandler {
}
});
+ final CopyVisitor copyVisitor = new CopyVisitor();
int finalOffset = -1;
for (final Element element : cellsToDup) {
if (finalOffset == -1) {
finalOffset = element.getStartOffset() + 1;
}
widget.moveTo(addBefore() ? element.getStartOffset() : element.getEndOffset() + 1);
- widget.insertElement(element.clone());
+ widget.insertElement((Element) element.accept(copyVisitor));
}
if (finalOffset != -1) {
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/AbstractAddRowHandler.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/AbstractAddRowHandler.java
index 2759853c..b37dd2b5 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/AbstractAddRowHandler.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/AbstractAddRowHandler.java
@@ -15,6 +15,7 @@ import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.vex.core.internal.dom.CopyVisitor;
import org.eclipse.vex.core.internal.dom.Element;
import org.eclipse.vex.ui.internal.swt.VexWidget;
@@ -89,15 +90,16 @@ public abstract class AbstractAddRowHandler extends AbstractVexWidgetHandler {
final int finalOffset = insertOffset + innerOffset - outerOffset;
widget.moveTo(insertOffset);
+ final CopyVisitor copyVisitor = new CopyVisitor();
for (final RowCells rowCells : rowCellsToInsert) {
if (rowCells.row instanceof Element) {
- widget.insertElement(((Element) rowCells.row).clone());
+ widget.insertElement((Element) ((Element) rowCells.row).accept(copyVisitor));
}
//cells that are to be inserted.
for (final Object cell : rowCells.cells) {
if (cell instanceof Element) {
- widget.insertElement(((Element) cell).clone());
+ widget.insertElement((Element) ((Element) cell).accept(copyVisitor));
widget.moveBy(+1);
} else {
widget.insertText(" ");
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/AddCommentHandler.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/AddCommentHandler.java
index 2ccb0e5d..44cdc104 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/AddCommentHandler.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/AddCommentHandler.java
@@ -11,7 +11,6 @@
package org.eclipse.vex.ui.internal.handlers;
import org.eclipse.core.commands.ExecutionException;
-import org.eclipse.vex.core.internal.dom.CommentElement;
import org.eclipse.vex.ui.internal.swt.VexWidget;
/**
@@ -21,7 +20,7 @@ public class AddCommentHandler extends AbstractVexWidgetHandler {
@Override
public void execute(final VexWidget widget) throws ExecutionException {
- widget.insertElement(new CommentElement());
+ widget.insertComment();
}
}
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/MoveSelectionUpHandler.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/MoveSelectionUpHandler.java
index 70ebe698..3e8bb9c8 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/MoveSelectionUpHandler.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/MoveSelectionUpHandler.java
@@ -11,7 +11,7 @@
package org.eclipse.vex.ui.internal.handlers;
import org.eclipse.core.commands.ExecutionException;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
import org.eclipse.vex.core.internal.layout.BlockBox;
import org.eclipse.vex.core.internal.layout.Box;
import org.eclipse.vex.core.internal.widget.IBoxFilter;
@@ -33,7 +33,7 @@ public class MoveSelectionUpHandler extends AbstractVexWidgetHandler {
// selection
final Box box = widget.findInnermostBox(new IBoxFilter() {
public boolean matches(final Box box) {
- return box instanceof BlockBox && box.getElement() != null && box.getStartOffset() <= widget.getSelectionStart() && box.getEndOffset() >= widget.getSelectionEnd();
+ return box instanceof BlockBox && box.getNode() != null && box.getStartOffset() <= widget.getSelectionStart() && box.getEndOffset() >= widget.getSelectionEnd();
}
});
@@ -51,10 +51,10 @@ public class MoveSelectionUpHandler extends AbstractVexWidgetHandler {
// box.getStartPosition() + 1, but this would be a VERY large
// change.)
System.out.println("Box is " + box);
- final Element element = box.getElement();
- if (element != null) {
- widget.moveTo(element.getEndOffset());
- widget.moveTo(element.getStartOffset(), true);
+ final Node node = box.getNode();
+ if (node != null) {
+ widget.moveTo(node.getEndOffset());
+ widget.moveTo(node.getStartOffset(), true);
} else {
widget.moveTo(box.getEndOffset());
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/SplitBlockElementHandler.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/SplitBlockElementHandler.java
index e83eea02..07e5cb05 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/SplitBlockElementHandler.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/SplitBlockElementHandler.java
@@ -18,10 +18,11 @@ import org.eclipse.core.commands.ExecutionException;
import org.eclipse.vex.core.internal.VEXCorePlugin;
import org.eclipse.vex.core.internal.css.CSS;
import org.eclipse.vex.core.internal.css.Styles;
+import org.eclipse.vex.core.internal.dom.CopyVisitor;
import org.eclipse.vex.core.internal.dom.Document;
import org.eclipse.vex.core.internal.dom.DocumentFragment;
import org.eclipse.vex.core.internal.dom.Element;
-import org.eclipse.vex.core.internal.dom.RootElement;
+import org.eclipse.vex.core.internal.dom.Node;
import org.eclipse.vex.core.internal.widget.IVexWidget;
import org.eclipse.vex.ui.internal.swt.VexWidget;
@@ -38,8 +39,8 @@ public class SplitBlockElementHandler extends AbstractVexWidgetHandler {
Element element = widget.getCurrentElement();
Styles styles = widget.getStyleSheet().getStyles(element);
while (!styles.isBlock()) {
- element = element.getParent();
- if (element == null || element instanceof RootElement) {
+ element = element.getParentElement();
+ if (element == null || element.getParent() instanceof Document) {
return; // we reached the root element which cannot be split
}
styles = widget.getStyleSheet().getStyles(element);
@@ -52,10 +53,10 @@ public class SplitBlockElementHandler extends AbstractVexWidgetHandler {
*
* @param vexWidget
* IVexWidget containing the document.
- * @param element
- * Element to be split.
+ * @param node
+ * Node to be split.
*/
- protected void splitElement(final IVexWidget vexWidget, final Element element) {
+ protected void splitElement(final IVexWidget vexWidget, final Node node) {
vexWidget.doWork(new Runnable() {
public void run() {
@@ -65,7 +66,7 @@ public class SplitBlockElementHandler extends AbstractVexWidgetHandler {
start = System.currentTimeMillis();
}
- final Styles styles = vexWidget.getStyleSheet().getStyles(element);
+ final Styles styles = vexWidget.getStyleSheet().getStyles(node);
if (styles.getWhiteSpace().equals(CSS.PRE)) {
// can't call vexWidget.insertText() or we'll get an
@@ -90,16 +91,17 @@ public class SplitBlockElementHandler extends AbstractVexWidgetHandler {
frags.add(vexWidget.getSelectedFragment());
vexWidget.deleteSelection();
vexWidget.moveTo(child.getEndOffset() + 1);
- if (child == element) {
+ if (child == node) {
break;
}
- child = child.getParent();
+ child = child.getParentElement();
}
+ final CopyVisitor copyVisitor = new CopyVisitor();
for (int i = children.size() - 1; i >= 0; i--) {
child = children.get(i);
final DocumentFragment frag = frags.get(i);
- vexWidget.insertElement(child.clone());
+ vexWidget.insertElement((Element) child.accept(copyVisitor));
final int offset = vexWidget.getCaretOffset();
if (frag != null) {
vexWidget.insertFragment(frag);
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/SplitItemHandler.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/SplitItemHandler.java
index 39b1ccd0..fdbedfdd 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/SplitItemHandler.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/SplitItemHandler.java
@@ -13,7 +13,7 @@ package org.eclipse.vex.ui.internal.handlers;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.vex.core.internal.css.CSS;
import org.eclipse.vex.core.internal.css.StyleSheet;
-import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
import org.eclipse.vex.core.internal.layout.Box;
import org.eclipse.vex.core.internal.layout.TableRowBox;
import org.eclipse.vex.core.internal.widget.IBoxFilter;
@@ -38,8 +38,8 @@ public class SplitItemHandler extends SplitBlockElementHandler {
if (box instanceof TableRowBox) {
return true;
} else {
- final Element element = box.getElement();
- return element != null && ss.getStyles(element).getDisplay().equals(CSS.LIST_ITEM);
+ final Node node = box.getNode();
+ return node != null && ss.getStyles(node).getDisplay().equals(CSS.LIST_ITEM);
}
}
});
@@ -48,7 +48,7 @@ public class SplitItemHandler extends SplitBlockElementHandler {
new AddRowBelowHandler().execute(widget);
// VexHandlerUtil.duplicateTableRow(vexWidget, (TableRowBox) item);
} else if (item != null) {
- splitElement(widget, item.getElement());
+ splitElement(widget, item.getNode());
}
}
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/VexHandlerUtil.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/VexHandlerUtil.java
index 751d0043..fb24915c 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/VexHandlerUtil.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/VexHandlerUtil.java
@@ -22,9 +22,11 @@ import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.vex.core.internal.core.IntRange;
import org.eclipse.vex.core.internal.css.CSS;
import org.eclipse.vex.core.internal.css.StyleSheet;
+import org.eclipse.vex.core.internal.dom.CopyVisitor;
import org.eclipse.vex.core.internal.dom.Document;
import org.eclipse.vex.core.internal.dom.Element;
import org.eclipse.vex.core.internal.dom.Node;
+import org.eclipse.vex.core.internal.dom.Parent;
import org.eclipse.vex.core.internal.layout.BlockBox;
import org.eclipse.vex.core.internal.layout.Box;
import org.eclipse.vex.core.internal.layout.ElementOrRangeCallback;
@@ -105,6 +107,7 @@ public final class VexHandlerUtil {
final int offset = vexWidget.getCaretOffset();
+ final CopyVisitor copyVisitor = new CopyVisitor();
boolean firstCellIsAnonymous = false;
final Box[] cells = tr.getChildren();
for (int i = 0; i < cells.length; i++) {
@@ -114,7 +117,7 @@ public final class VexHandlerUtil {
firstCellIsAnonymous = true;
}
} else {
- vexWidget.insertElement(cells[i].getElement().clone());
+ vexWidget.insertElement((Element) cells[i].getNode().accept(copyVisitor));
vexWidget.moveBy(+1);
}
}
@@ -146,7 +149,8 @@ public final class VexHandlerUtil {
if (!tr.isAnonymous()) {
vexWidget.moveBy(+1); // Move past sentinel in current row
- vexWidget.insertElement(tr.getElement().clone());
+ final CopyVisitor copyVisitor = new CopyVisitor();
+ vexWidget.insertElement((Element) tr.getNode().accept(copyVisitor));
}
cloneTableCells(vexWidget, tr, true);
@@ -191,7 +195,7 @@ public final class VexHandlerUtil {
i++;
}
- public void onRange(final Element parent, final int startOffset, final int endOffset) {
+ public void onRange(final Parent parent, final int startOffset, final int endOffset) {
i++;
}
});
@@ -214,7 +218,7 @@ public final class VexHandlerUtil {
if (ss.getStyles(element).getDisplay().equals(CSS.TABLE_ROW)) {
return element;
}
- element = element.getParent();
+ element = element.getParentElement();
}
return null;
@@ -235,15 +239,15 @@ public final class VexHandlerUtil {
} else {
final Box box = vexWidget.findInnermostBox(new IBoxFilter() {
public boolean matches(final Box box) {
- return box instanceof BlockBox && box.getElement() != null;
+ return box instanceof BlockBox && box.getNode() != null;
}
});
- if (box.getElement() == vexWidget.getDocument().getRootElement()) {
+ if (box.getNode() == vexWidget.getDocument().getRootElement()) {
return -1;
}
- startOffset = box.getElement().getStartOffset();
+ startOffset = box.getNode().getStartOffset();
}
int previousSiblingStart = -1;
@@ -348,7 +352,7 @@ public final class VexHandlerUtil {
cellIndex++;
}
- public void onRange(final Element parent, final int startOffset, final int endOffset) {
+ public void onRange(final Parent parent, final int startOffset, final int endOffset) {
callback.onCell(row, new IntRange(startOffset, endOffset), rowIndex[0], cellIndex);
cellIndex++;
}
@@ -359,7 +363,7 @@ public final class VexHandlerUtil {
rowIndex[0]++;
}
- public void onRange(final Element parent, final int startOffset, final int endOffset) {
+ public void onRange(final Parent parent, final int startOffset, final int endOffset) {
final IntRange row = new IntRange(startOffset, endOffset);
callback.startRow(row, rowIndex[0]);
@@ -372,7 +376,7 @@ public final class VexHandlerUtil {
cellIndex++;
}
- public void onRange(final Element parent, final int startOffset, final int endOffset) {
+ public void onRange(final Parent parent, final int startOffset, final int endOffset) {
callback.onCell(row, new IntRange(startOffset, endOffset), rowIndex[0], cellIndex);
cellIndex++;
}
@@ -458,14 +462,14 @@ public final class VexHandlerUtil {
Element table = doc.getElementAt(offset);
while (table != null && !LayoutUtils.isTableChild(ss, table)) {
- table = table.getParent();
+ table = table.getParentElement();
}
while (table != null && LayoutUtils.isTableChild(ss, table)) {
- table = table.getParent();
+ table = table.getParentElement();
}
- if (table == null || table.getParent() == null) {
+ if (table == null || table.getParentElement() == null) {
return;
}
@@ -479,7 +483,7 @@ public final class VexHandlerUtil {
tableChildren.add(child);
}
- public void onRange(final Element parent, final int startOffset, final int endOffset) {
+ public void onRange(final Parent parent, final int startOffset, final int endOffset) {
if (!found[0]) {
tableChildren.clear();
}
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/outline/DefaultOutlineProvider.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/outline/DefaultOutlineProvider.java
index 66604eed..f3ae7a1f 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/outline/DefaultOutlineProvider.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/outline/DefaultOutlineProvider.java
@@ -66,7 +66,7 @@ public class DefaultOutlineProvider implements IOutlineProvider {
}
// root?
- final Element parent = element.getParent();
+ final Element parent = element.getParentElement();
if (parent == null) {
return element;
}
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/swt/ContentAssist.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/swt/ContentAssist.java
index 666c29ea..9efde08e 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/swt/ContentAssist.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/swt/ContentAssist.java
@@ -343,7 +343,7 @@ public class ContentAssist extends PopupDialog {
actions[i] = new AbstractVexAction(widget, names[i], names[i].toString(), Icon.ELEMENT) {
@Override
public void execute(final VexWidget vexWidget) {
- getWidget().insertElement(new Element(qualifiedName));
+ getWidget().insertElement(qualifiedName);
}
};
}
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/swt/DocumentFragmentTransfer.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/swt/DocumentFragmentTransfer.java
index 3252b5c8..2e09f8fd 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/swt/DocumentFragmentTransfer.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/swt/DocumentFragmentTransfer.java
@@ -15,16 +15,30 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.swt.dnd.ByteArrayTransfer;
import org.eclipse.swt.dnd.TransferData;
+import org.eclipse.vex.core.internal.dom.Attribute;
+import org.eclipse.vex.core.internal.dom.BaseNodeVisitor;
+import org.eclipse.vex.core.internal.dom.Content;
import org.eclipse.vex.core.internal.dom.DocumentFragment;
+import org.eclipse.vex.core.internal.dom.DocumentValidationException;
+import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.GapContent;
+import org.eclipse.vex.core.internal.dom.Node;
+import org.eclipse.vex.core.internal.dom.Range;
/**
* Transfer object that handles Vex DocumentFragments.
*/
public class DocumentFragmentTransfer extends ByteArrayTransfer {
+ private static final String MIME_TYPE = "application/x-vex-document-fragment";
+
/**
* Returns the singleton instance of the DocumentFragmentTransfer.
*/
@@ -58,7 +72,7 @@ public class DocumentFragmentTransfer extends ByteArrayTransfer {
// pMedium
final ByteArrayOutputStream out = new ByteArrayOutputStream();
final ObjectOutputStream oos = new ObjectOutputStream(out);
- oos.writeObject(frag);
+ writeFragment(frag, oos);
final byte[] buffer = out.toByteArray();
oos.close();
super.javaToNative(buffer, transferData);
@@ -79,7 +93,7 @@ public class DocumentFragmentTransfer extends ByteArrayTransfer {
try {
final ByteArrayInputStream in = new ByteArrayInputStream(buffer);
final ObjectInputStream ois = new ObjectInputStream(in);
- final Object object = ois.readObject();
+ final Object object = readFragment(ois);
ois.close();
return object;
} catch (final ClassNotFoundException ex) {
@@ -94,11 +108,122 @@ public class DocumentFragmentTransfer extends ByteArrayTransfer {
// =================================================== PRIVATE
- private static final String[] typeNames = { DocumentFragment.MIME_TYPE };
- private static final int[] typeIds = { ByteArrayTransfer.registerType(DocumentFragment.MIME_TYPE) };
+ private static final String[] typeNames = { MIME_TYPE };
+ private static final int[] typeIds = { ByteArrayTransfer.registerType(MIME_TYPE) };
private static DocumentFragmentTransfer instance;
private DocumentFragmentTransfer() {
}
+
+ private void writeFragment(final DocumentFragment fragment, final ObjectOutputStream out) throws IOException {
+ writeContent(fragment.getContent(), out);
+ for (final Node node : fragment.getNodes()) {
+ node.accept(new BaseNodeVisitor() {
+ @Override
+ public void visit(final Element element) {
+ try {
+ writeElement(element, out);
+ } catch (final IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+ }
+
+ private static void writeContent(final Content content, final ObjectOutputStream out) throws IOException {
+ final int contentLength = content.length();
+ out.write(contentLength);
+ for (int i = 0; i < contentLength; i++) {
+ if (content.isElementMarker(i)) {
+ out.writeUTF("\0"); // This internal representation of element markers has nothing to do with the internal representation in GapContent.
+ } else {
+ out.writeUTF(content.getText(new Range(i, i)));
+ }
+ }
+ }
+
+ private static void writeElement(final Element element, final ObjectOutputStream out) throws IOException {
+ out.writeObject(element.getQualifiedName());
+ out.writeInt(element.getStartOffset());
+ out.writeInt(element.getEndOffset());
+ final Collection<Attribute> attributes = element.getAttributes();
+ out.writeInt(attributes.size());
+ for (final Attribute attribute : attributes) {
+ out.writeObject(attribute.getQualifiedName());
+ out.writeObject(attribute.getValue());
+ }
+ final List<Element> children = element.getChildElements();
+ out.writeInt(children.size());
+ for (int i = 0; i < children.size(); i++) {
+ writeElement(children.get(i), out);
+ }
+ }
+
+ private DocumentFragment readFragment(final ObjectInputStream in) throws IOException, ClassNotFoundException {
+ final Content content = readContent(in);
+ final int n = in.readInt();
+ final ArrayList<Node> nodes = new ArrayList<Node>(n);
+ for (int i = 0; i < n; i++) {
+ nodes.add(readElement(in, content));
+ }
+ return new DocumentFragment(content, nodes);
+ }
+
+ private static Content readContent(final ObjectInputStream in) throws IOException {
+ final int contentLength = in.readInt();
+ final Content result = new GapContent(contentLength);
+ for (int i = 0; i < contentLength; i++) {
+ final String input = in.readUTF();
+ if ("\0".equals(input)) { // This internal representation of element markers has nothing to do with the internal representation in GapContent.
+ result.insertElementMarker(i);
+ } else {
+ result.insertText(i, input);
+ }
+ }
+ return result;
+ }
+
+ private static Element readElement(final ObjectInputStream in, final Content content) throws IOException, ClassNotFoundException {
+ final QualifiedName elementName = createQualifiedName(in.readObject());
+ final int startOffset = in.readInt();
+ final int endOffset = in.readInt();
+ final Element element = new Element(elementName);
+ element.associate(content, new Range(startOffset, endOffset));
+
+ final int attrCount = in.readInt();
+ for (int i = 0; i < attrCount; i++) {
+ final QualifiedName attributeName = createQualifiedName(in.readObject());
+ final String value = (String) in.readObject();
+ try {
+ element.setAttribute(attributeName, value);
+ } catch (final DocumentValidationException e) {
+ // Should never happen; there ain't no document
+ e.printStackTrace();
+ }
+ }
+
+ final int childCount = in.readInt();
+ for (int i = 0; i < childCount; i++) {
+ final Element child = readElement(in, content);
+ child.setParent(element);
+ element.insertChild(i, child);
+ }
+
+ return element;
+ }
+
+ private static QualifiedName createQualifiedName(final Object object) {
+ final String serializedQualifiedName = object.toString();
+ final int localNameStartIndex = serializedQualifiedName.lastIndexOf(':') + 1;
+ if (localNameStartIndex == 0) {
+ return new QualifiedName(null, serializedQualifiedName);
+ }
+ final String qualifier = serializedQualifiedName.substring(0, localNameStartIndex - 1);
+ final String localName = serializedQualifiedName.substring(localNameStartIndex);
+ return new QualifiedName(qualifier, localName);
+ }
+
}
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/swt/VexWidget.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/swt/VexWidget.java
index a3efdd01..a095dd0a 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/swt/VexWidget.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/swt/VexWidget.java
@@ -22,6 +22,7 @@ import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
@@ -63,6 +64,7 @@ import org.eclipse.vex.core.internal.dom.DocumentFragment;
import org.eclipse.vex.core.internal.dom.DocumentValidationException;
import org.eclipse.vex.core.internal.dom.Element;
import org.eclipse.vex.core.internal.dom.Node;
+import org.eclipse.vex.core.internal.dom.Range;
import org.eclipse.vex.core.internal.layout.Box;
import org.eclipse.vex.core.internal.layout.BoxFactory;
import org.eclipse.vex.core.internal.widget.HostComponent;
@@ -277,10 +279,18 @@ public class VexWidget extends Canvas implements IVexWidget, ISelectionProvider
impl.insertElement(element);
}
+ public void insertElement(final QualifiedName elementName) throws DocumentValidationException {
+ impl.insertElement(elementName);
+ }
+
public void insertText(final String text) throws DocumentValidationException {
impl.insertText(text);
}
+ public void insertComment() throws DocumentValidationException {
+ impl.insertComment();
+ }
+
public boolean isDebugging() {
return impl.isDebugging();
}
@@ -503,7 +513,7 @@ public class VexWidget extends Canvas implements IVexWidget, ISelectionProvider
public void fireSelectionChanged() {
if (hasSelection()) {
- final List<Node> nodes = getDocument().getNodes(getSelectionStart(), getSelectionEnd());
+ final List<Node> nodes = getDocument().getNodes(new Range(getSelectionStart(), getSelectionEnd()));
selection = new StructuredSelection(nodes);
} else {
selection = new StructuredSelection(getCurrentElement());
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 950ba299..0da73cfc 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
@@ -34,7 +34,7 @@ import org.eclipse.ui.wizards.newresource.BasicNewResourceWizard;
import org.eclipse.vex.core.internal.dom.Document;
import org.eclipse.vex.core.internal.dom.DocumentContentModel;
import org.eclipse.vex.core.internal.dom.DocumentWriter;
-import org.eclipse.vex.core.internal.dom.RootElement;
+import org.eclipse.vex.core.internal.dom.Element;
import org.eclipse.vex.core.internal.validator.WTPVEXValidator;
import org.eclipse.vex.core.internal.widget.CssWhitespacePolicy;
import org.eclipse.vex.ui.internal.VexPlugin;
@@ -128,7 +128,7 @@ public class NewDocumentWizard extends BasicNewResourceWizard {
}
private static Document createDocumentWithDTD(final DocumentType documentType, final String rootElementName) {
- final RootElement root = new RootElement(rootElementName);
+ final Element root = new Element(rootElementName);
final Document result = new Document(root);
result.setPublicID(documentType.getPublicId());
result.setSystemID(documentType.getSystemId());
@@ -137,7 +137,7 @@ public class NewDocumentWizard extends BasicNewResourceWizard {
private static Document createDocumentWithSchema(final DocumentType documentType, final String rootElementName) {
final String defaultNamespaceUri = documentType.getPublicId();
- final RootElement root = new RootElement(new QualifiedName(defaultNamespaceUri, rootElementName));
+ final Element root = new Element(new QualifiedName(defaultNamespaceUri, rootElementName));
root.declareDefaultNamespace(defaultNamespaceUri);
final WTPVEXValidator validator = new WTPVEXValidator(new DocumentContentModel(null, null, null, root));
diff --git a/org.eclipse.vex.xhtml/src/org/eclipse/vex/xhtml/XhtmlOutlineProvider.java b/org.eclipse.vex.xhtml/src/org/eclipse/vex/xhtml/XhtmlOutlineProvider.java
index bbba6e12..6525085d 100644
--- a/org.eclipse.vex.xhtml/src/org/eclipse/vex/xhtml/XhtmlOutlineProvider.java
+++ b/org.eclipse.vex.xhtml/src/org/eclipse/vex/xhtml/XhtmlOutlineProvider.java
@@ -50,7 +50,7 @@ public class XhtmlOutlineProvider implements IOutlineProvider {
return element;
}
- element = element.getParent();
+ element = element.getParentElement();
}
return element;
}
@@ -70,7 +70,7 @@ public class XhtmlOutlineProvider implements IOutlineProvider {
}
public Object getParent(final Object element) {
- final Element parent = ((Element) element).getParent();
+ final Element parent = ((Element) element).getParentElement();
if (parent == null) {
return element;
} else {
@@ -123,7 +123,7 @@ public class XhtmlOutlineProvider implements IOutlineProvider {
// between this element and the next element at the same level
final int level = Integer.parseInt(element.getLocalName().substring(1));
final String childName = "h" + (level + 1);
- final List<Element> childElements = element.getParent().getChildElements();
+ final List<Element> childElements = element.getParentElement().getChildElements();
boolean foundSelf = false;
for (final Element child : childElements) {
if (child == element) {

Back to the top