remove dependency to layout box model

Signed-off-by: Florian Thienel <florian@thienel.org>
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/AbstractNavigateTableCellHandler.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/AbstractNavigateTableCellHandler.java
index 09a4a62..f06433d 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/AbstractNavigateTableCellHandler.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/AbstractNavigateTableCellHandler.java
@@ -10,10 +10,16 @@
  *******************************************************************************/
 package org.eclipse.vex.ui.internal.handlers;
 
+import java.util.NoSuchElementException;
+
 import org.eclipse.core.commands.ExecutionException;
-import org.eclipse.vex.core.internal.layout.Box;
-import org.eclipse.vex.core.internal.layout.TableRowBox;
-import org.eclipse.vex.core.internal.widget.IBoxFilter;
+import org.eclipse.vex.core.IFilter;
+import org.eclipse.vex.core.internal.css.CSS;
+import org.eclipse.vex.core.internal.css.StyleSheet;
+import org.eclipse.vex.core.provisional.dom.IAxis;
+import org.eclipse.vex.core.provisional.dom.IElement;
+import org.eclipse.vex.core.provisional.dom.INode;
+import org.eclipse.vex.core.provisional.dom.IParent;
 import org.eclipse.vex.ui.internal.swt.VexWidget;
 
 /**
@@ -25,20 +31,16 @@
 
 	@Override
 	public void execute(final VexWidget widget) throws ExecutionException {
-		final IBoxFilter filter = new IBoxFilter() {
-			public boolean matches(final Box box) {
-				return box instanceof TableRowBox;
-			}
-		};
-		final TableRowBox row = (TableRowBox) widget.findInnermostBox(filter);
-
-		// not in a table row?
-		if (row == null) {
+		final IAxis<? extends IParent> parentTableRows = widget.getCurrentElement().ancestors().matching(displayedAsTableRow(widget.getStyleSheet()));
+		final IElement tableRow;
+		try {
+			tableRow = (IElement) parentTableRows.first();
+		} catch (final NoSuchElementException e) {
 			return;
 		}
 
 		final int offset = widget.getCaretOffset();
-		navigate(widget, row, offset);
+		navigate(widget, tableRow, offset);
 	}
 
 	/**
@@ -46,11 +48,19 @@
 	 * 
 	 * @param widget
 	 *            the Vex widget containing the document
-	 * @param row
+	 * @param tableRow
 	 *            the current row
 	 * @param offset
 	 *            the current offset
 	 */
-	protected abstract void navigate(VexWidget widget, TableRowBox row, int offset);
+	protected abstract void navigate(VexWidget widget, IElement tableRow, int offset);
+
+	private static IFilter<INode> displayedAsTableRow(final StyleSheet stylesheet) {
+		return new IFilter<INode>() {
+			public boolean matches(final INode node) {
+				return stylesheet.getStyles(node).getDisplay().equals(CSS.TABLE_ROW);
+			}
+		};
+	}
 
 }
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 9a80710..c557ffc 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,11 +11,12 @@
 package org.eclipse.vex.ui.internal.handlers;
 
 import org.eclipse.core.commands.ExecutionException;
-import org.eclipse.vex.core.internal.layout.BlockBox;
-import org.eclipse.vex.core.internal.layout.Box;
-import org.eclipse.vex.core.internal.widget.IBoxFilter;
+import org.eclipse.vex.core.IFilter;
+import org.eclipse.vex.core.internal.css.StyleSheet;
 import org.eclipse.vex.core.provisional.dom.ContentRange;
+import org.eclipse.vex.core.provisional.dom.IAxis;
 import org.eclipse.vex.core.provisional.dom.INode;
+import org.eclipse.vex.core.provisional.dom.IParent;
 import org.eclipse.vex.ui.internal.swt.VexWidget;
 
 /**
@@ -27,39 +28,18 @@
 
 	@Override
 	public void execute(final VexWidget widget) throws ExecutionException {
-		// First we determine whether we should expand the selection
-		// to contain an entire block box.
+		final ContentRange selectedRange = widget.getSelectedRange();
+		final IAxis<? extends IParent> parentsContainingSelection = widget.getCurrentElement().ancestors().matching(containingRange(selectedRange));
 
-		// Find the lowest block box that completely contains the selection
-		final Box box = widget.findInnermostBox(new IBoxFilter() {
-			public boolean matches(final Box box) {
-				final ContentRange selectedRange = widget.getSelectedRange();
-				return box instanceof BlockBox && box.getNode() != null && new ContentRange(box.getStartOffset(), box.getEndOffset()).contains(selectedRange);
-			}
-		});
-
-		final Box[] children = box.getChildren();
-		if (children.length > 0 && children[0] instanceof BlockBox) {
-			// The found box contains other block children, so we do NOT have to
-			// expand the selection
-		} else {
-			// Expand selection to the containing box
-
-			// (Note: This "if" is caused by the fact that getStartOffset is
-			// treated differently between elements and boxes. Boxes own their
-			// startOffset, while elements don't own theirs. Perhaps we should
-			// fix this by having box.getStartOffset() return
-			// box.getStartPosition() + 1, but this would be a VERY large
-			// change.)
-			System.out.println("Box is " + box);
-			final INode node = box.getNode();
-			if (node != null) {
-				widget.moveTo(node.getEndOffset() + 1);
-				widget.moveTo(node.getStartOffset(), true);
-
+		// expand the selection until a parent has other block-children
+		final StyleSheet stylesheet = widget.getStyleSheet();
+		for (final IParent parent : parentsContainingSelection) {
+			final IAxis<? extends INode> blockChildren = parent.children().matching(displayedAsBlock(stylesheet));
+			if (blockChildren.isEmpty()) {
+				widget.moveTo(parent.getStartOffset(), false);
+				widget.moveTo(parent.getEndOffset(), true);
 			} else {
-				widget.moveTo(box.getEndOffset() + 1);
-				widget.moveTo(box.getStartOffset(), true);
+				break;
 			}
 		}
 
@@ -76,4 +56,19 @@
 		// });
 	}
 
+	private static IFilter<INode> containingRange(final ContentRange range) {
+		return new IFilter<INode>() {
+			public boolean matches(final INode node) {
+				return node.getRange().contains(range);
+			}
+		};
+	}
+
+	private static IFilter<INode> displayedAsBlock(final StyleSheet stylesheet) {
+		return new IFilter<INode>() {
+			public boolean matches(final INode node) {
+				return stylesheet.getStyles(node).isBlock();
+			}
+		};
+	}
 }
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/NextTableCellHandler.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/NextTableCellHandler.java
index 6d36957..4f16f0b 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/NextTableCellHandler.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/NextTableCellHandler.java
@@ -11,8 +11,9 @@
  *******************************************************************************/
 package org.eclipse.vex.ui.internal.handlers;
 
-import org.eclipse.vex.core.internal.layout.Box;
-import org.eclipse.vex.core.internal.layout.TableRowBox;
+import java.util.NoSuchElementException;
+
+import org.eclipse.vex.core.provisional.dom.IElement;
 import org.eclipse.vex.ui.internal.swt.VexWidget;
 
 /**
@@ -23,11 +24,9 @@
 public class NextTableCellHandler extends AbstractNavigateTableCellHandler {
 
 	@Override
-	protected void navigate(final VexWidget widget, final TableRowBox row, final int offset) {
-		final Box[] cells = row.getChildren();
-
+	protected void navigate(final VexWidget widget, final IElement tableRow, final int offset) {
 		// in this row
-		for (final Box cell : cells) {
+		for (final IElement cell : tableRow.childElements()) {
 			if (cell.getStartOffset() > offset) {
 				widget.moveTo(cell.getStartOffset());
 				widget.moveTo(cell.getEndOffset(), true);
@@ -36,14 +35,13 @@
 		}
 
 		// in other row
-		final Box[] rows = row.getParent().getChildren();
-		for (final Box boxRow : rows) {
-			if (boxRow.getStartOffset() > offset) {
-				final Box[] rowCells = boxRow.getChildren();
-				if (rowCells.length > 0) {
-					final Box cell = rowCells[0];
-					widget.moveTo(cell.getStartOffset());
-					widget.moveTo(cell.getEndOffset(), true);
+		for (final IElement siblingRow : tableRow.getParentElement().childElements()) {
+			if (siblingRow.getStartOffset() > offset) {
+				final IElement firstCell = firstCellOf(siblingRow);
+
+				if (firstCell != null) {
+					widget.moveTo(firstCell.getStartOffset());
+					widget.moveTo(firstCell.getEndOffset(), true);
 				} else {
 					System.out.println("TODO - dup row into new empty row");
 				}
@@ -52,8 +50,15 @@
 		}
 
 		// We didn't find a "next row", so let's dup the current one
-		VexHandlerUtil.duplicateTableRow(widget, row);
+		VexHandlerUtil.duplicateTableRow(widget, tableRow);
+	}
 
+	private static IElement firstCellOf(final IElement tableRow) {
+		try {
+			return tableRow.childElements().first();
+		} catch (final NoSuchElementException e) {
+			return null;
+		}
 	}
 
 }
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/PreviousTableCellHandler.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/PreviousTableCellHandler.java
index 70dfdfa..26b7a87 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/PreviousTableCellHandler.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/handlers/PreviousTableCellHandler.java
@@ -10,8 +10,9 @@
  *******************************************************************************/
 package org.eclipse.vex.ui.internal.handlers;
 
-import org.eclipse.vex.core.internal.layout.Box;
-import org.eclipse.vex.core.internal.layout.TableRowBox;
+import java.util.NoSuchElementException;
+
+import org.eclipse.vex.core.provisional.dom.IElement;
 import org.eclipse.vex.ui.internal.swt.VexWidget;
 
 /**
@@ -22,31 +23,45 @@
 public class PreviousTableCellHandler extends AbstractNavigateTableCellHandler {
 
 	@Override
-	protected void navigate(final VexWidget widget, final TableRowBox row, final int offset) {
-		Box[] cells = row.getChildren();
+	protected void navigate(final VexWidget widget, final IElement tableRow, final int offset) {
+		IElement siblingCell = null;
+		for (final IElement cell : tableRow.childElements()) {
+			if (cell.getStartOffset() >= offset) {
+				break;
+			}
+			siblingCell = cell;
+		}
 
 		// in this row
-		for (int i = cells.length - 1; i >= 0; i--) {
-			if (cells[i].getEndOffset() < offset) {
-				widget.moveTo(cells[i].getStartOffset());
-				widget.moveTo(cells[i].getEndOffset(), true);
-				return;
+		if (siblingCell != null) {
+			widget.moveTo(siblingCell.getStartOffset());
+			widget.moveTo(siblingCell.getEndOffset(), true);
+			return;
+		}
+
+		IElement siblingRow = null;
+		for (final IElement row : tableRow.getParentElement().childElements()) {
+			if (row.getStartOffset() >= offset) {
+				break;
 			}
+			siblingRow = row;
 		}
 
 		// in other row
-		final Box[] rows = row.getParent().getChildren();
-		for (int i = rows.length - 1; i >= 0; i--) {
-			if (rows[i].getEndOffset() < offset) {
-				cells = rows[i].getChildren();
-				if (cells.length > 0) {
-					final Box cell = cells[cells.length - 1];
-					widget.moveTo(cell.getStartOffset());
-					widget.moveTo(cell.getEndOffset(), true);
-				}
-				return;
+		if (siblingRow != null) {
+			final IElement lastCell = lastCellOf(siblingRow);
+			if (lastCell != null) {
+				widget.moveTo(lastCell.getStartOffset());
+				widget.moveTo(lastCell.getEndOffset(), true);
 			}
 		}
 	}
 
+	private static IElement lastCellOf(final IElement tableRow) {
+		try {
+			return tableRow.childElements().last();
+		} catch (final NoSuchElementException e) {
+			return null;
+		}
+	}
 }
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 84e069e..b9f67e3 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
@@ -10,13 +10,15 @@
  *******************************************************************************/
 package org.eclipse.vex.ui.internal.handlers;
 
+import java.util.NoSuchElementException;
+
 import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.vex.core.IFilter;
 import org.eclipse.vex.core.internal.css.CSS;
 import org.eclipse.vex.core.internal.css.StyleSheet;
-import org.eclipse.vex.core.internal.layout.Box;
-import org.eclipse.vex.core.internal.layout.TableRowBox;
-import org.eclipse.vex.core.internal.widget.IBoxFilter;
+import org.eclipse.vex.core.provisional.dom.IAxis;
 import org.eclipse.vex.core.provisional.dom.INode;
+import org.eclipse.vex.core.provisional.dom.IParent;
 import org.eclipse.vex.ui.internal.swt.VexWidget;
 
 /**
@@ -29,27 +31,36 @@
 
 	@Override
 	public void execute(final VexWidget widget) throws ExecutionException {
-		final StyleSheet ss = widget.getStyleSheet();
+		final StyleSheet stylesheet = widget.getStyleSheet();
+		final IAxis<? extends IParent> parentTableRowOrListItems = widget.getCurrentElement().ancestors().matching(displayedAsTableRowOrListItem(stylesheet));
 
-		// Item is either a TableRowBox or a BlockElementBox representing
-		// a list item
-		final Box item = widget.findInnermostBox(new IBoxFilter() {
-			public boolean matches(final Box box) {
-				if (box instanceof TableRowBox) {
-					return true;
-				} else {
-					final INode node = box.getNode();
-					return node != null && ss.getStyles(node).getDisplay().equals(CSS.LIST_ITEM);
-				}
-			}
-		});
+		final IParent firstTableRowOrListItem;
+		try {
+			firstTableRowOrListItem = parentTableRowOrListItems.first();
+		} catch (final NoSuchElementException e) {
+			return;
+		}
 
-		if (item instanceof TableRowBox) {
+		final String displayStyle = stylesheet.getStyles(firstTableRowOrListItem).getDisplay();
+		if (displayStyle.equals(CSS.TABLE_ROW)) {
 			new AddRowBelowHandler().execute(widget);
-			// VexHandlerUtil.duplicateTableRow(vexWidget, (TableRowBox) item);
-		} else if (item != null) {
-			splitElement(widget, item.getNode());
+		} else if (displayStyle.equals(CSS.LIST_ITEM)) {
+			splitElement(widget, firstTableRowOrListItem);
 		}
 	}
 
+	private final IFilter<INode> displayedAsTableRowOrListItem(final StyleSheet stylesheet) {
+		return new IFilter<INode>() {
+			public boolean matches(final INode node) {
+				final String displayStyle = stylesheet.getStyles(node).getDisplay();
+				if (displayStyle.equals(CSS.TABLE_ROW)) {
+					return true;
+				}
+				if (displayStyle.equals(CSS.LIST_ITEM)) {
+					return true;
+				}
+				return false;
+			}
+		};
+	}
 }
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 87287b6..329da03 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,10 +22,8 @@
 import org.eclipse.vex.core.internal.css.CSS;
 import org.eclipse.vex.core.internal.css.StyleSheet;
 import org.eclipse.vex.core.internal.dom.CopyOfElement;
-import org.eclipse.vex.core.internal.layout.Box;
 import org.eclipse.vex.core.internal.layout.ElementOrRangeCallback;
 import org.eclipse.vex.core.internal.layout.LayoutUtils;
-import org.eclipse.vex.core.internal.layout.TableRowBox;
 import org.eclipse.vex.core.internal.widget.IVexWidget;
 import org.eclipse.vex.core.provisional.dom.ContentRange;
 import org.eclipse.vex.core.provisional.dom.IDocument;
@@ -93,38 +91,25 @@
 	 * 
 	 * @param vexWidget
 	 *            IVexWidget to modify.
-	 * @param tr
+	 * @param tableRow
 	 *            TableRowBox whose cells are to be cloned.
 	 * @param moveToFirstCell
 	 *            TODO
 	 */
-	public static void cloneTableCells(final IVexWidget vexWidget, final TableRowBox tr, final boolean moveToFirstCell) {
+	public static void cloneTableCells(final IVexWidget vexWidget, final IElement tableRow, final boolean moveToFirstCell) {
 		vexWidget.doWork(new Runnable() {
 			public void run() {
-
-				final int offset = vexWidget.getCaretOffset();
-
-				boolean firstCellIsAnonymous = false;
-				final Box[] cells = tr.getChildren();
-				for (int i = 0; i < cells.length; i++) {
-					if (cells[i].isAnonymous()) {
-						vexWidget.insertText(" ");
-						if (i == 0) {
-							firstCellIsAnonymous = true;
-						}
-					} else {
-						final IElement element = (IElement) cells[i].getNode();
-						final IElement newElement = vexWidget.insertElement(element.getQualifiedName());
-						newElement.accept(new CopyOfElement(element));
-						vexWidget.moveBy(+1);
+				int firstCellOffset = -1;
+				for (final IElement cell : tableRow.childElements()) {
+					final IElement newElement = vexWidget.insertElement(cell.getQualifiedName());
+					newElement.accept(new CopyOfElement(cell));
+					if (firstCellOffset == -1) {
+						firstCellOffset = newElement.getEndOffset();
 					}
 				}
 
-				if (moveToFirstCell) {
-					vexWidget.moveTo(offset + 1);
-					if (firstCellIsAnonymous) {
-						vexWidget.moveBy(-1, true);
-					}
+				if (moveToFirstCell && firstCellOffset != -1) {
+					vexWidget.moveTo(firstCellOffset);
 				}
 			}
 		});
@@ -136,23 +121,17 @@
 	 * 
 	 * @param vexWidget
 	 *            IVexWidget with which we're working
-	 * @param tr
+	 * @param tableRow
 	 *            TableRowBox to be duplicated.
 	 */
-	public static void duplicateTableRow(final IVexWidget vexWidget, final TableRowBox tr) {
+	public static void duplicateTableRow(final IVexWidget vexWidget, final IElement tableRow) {
 		vexWidget.doWork(new Runnable() {
 			public void run() {
-
-				vexWidget.moveTo(tr.getEndOffset());
-
-				if (!tr.isAnonymous()) {
-					vexWidget.moveBy(+1); // Move past sentinel in current row
-					final IElement element = (IElement) tr.getNode();
-					final IElement newElement = vexWidget.insertElement(element.getQualifiedName());
-					newElement.accept(new CopyOfElement(element));
-				}
-
-				cloneTableCells(vexWidget, tr, true);
+				vexWidget.moveTo(tableRow.getEndOffset());
+				vexWidget.moveBy(+1); // Move past sentinel in current row
+				final IElement newElement = vexWidget.insertElement(tableRow.getQualifiedName());
+				newElement.accept(new CopyOfElement(tableRow));
+				cloneTableCells(vexWidget, tableRow, true);
 			}
 		});
 	}