| /******************************************************************************* |
| * Copyright (c) 2006 Sybase, Inc. 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: |
| * Sybase, Inc. - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jst.pagedesigner.validation.caret; |
| |
| import java.util.Arrays; |
| import java.util.List; |
| |
| import org.eclipse.gef.EditPart; |
| import org.eclipse.jst.pagedesigner.IHTMLConstants; |
| import org.eclipse.jst.pagedesigner.dom.EditModelQuery; |
| import org.eclipse.jst.pagedesigner.dom.EditValidateUtil; |
| import org.w3c.dom.Node; |
| |
| /** |
| * This rule constains the operation within a table: 1. The inputing position |
| * can only be in 'td' 2. Table structure must be valid. |
| * |
| * @author mengbo |
| */ |
| public class IETablePositionRule extends DefaultPositionRule { |
| // We will introduce validation based on DtD later, this is not final |
| // solution. |
| private final String[] CONTAINER = { IHTMLConstants.TAG_THEAD, |
| IHTMLConstants.TAG_TBODY, IHTMLConstants.TAG_TFOOT }; |
| |
| /** |
| * @param actionData |
| */ |
| public IETablePositionRule(ActionData actionData) { |
| super(actionData); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jst.pagedesigner.caret.IPositionRule#hasEditableArea(org.eclipse.jst.pagedesigner.caret.Target) |
| */ |
| public boolean hasEditableArea(Target target) { |
| if (EditModelQuery.isChild(IHTMLConstants.TAG_TABLE, target.getNode(), |
| true)) { |
| if (target.getPart() == null) { |
| return false; |
| } |
| Node node = target.getNode(); |
| // The target must be in a valid table structure. |
| String name = node.getLocalName(); |
| if (node.hasChildNodes()) { |
| // for constrained container, depends on its children. |
| if (name != null |
| && (IHTMLConstants.TAG_TABLE.equalsIgnoreCase(name) || // |
| Arrays.asList(CONTAINER).contains( |
| name.toLowerCase()) || // |
| IHTMLConstants.TAG_TR.equalsIgnoreCase(name))) { |
| List children = target.getPart().getChildren(); |
| for (int i = 0, n = children.size(); i < n; i++) { |
| if (hasEditableArea(new Target((EditPart) children |
| .get(i)))) { |
| return true; |
| } |
| } |
| return false; |
| } |
| } else { |
| if (!isEditable(new Target(node))) { |
| return false; |
| } |
| } |
| } |
| return super.hasEditableArea(target); |
| } |
| |
| /** |
| * Used to valid the structure of table, later will use dtd to do that. |
| * @param container |
| * @return true if the table is valid |
| */ |
| public boolean isInValidTable(Node container) { |
| boolean result = false; |
| try { |
| if (EditValidateUtil.validNode(container)) { |
| if (EditModelQuery.isText(container)) { |
| container = container.getParentNode(); |
| } |
| String name = container.getLocalName(); |
| if (EditModelQuery.isChild(IHTMLConstants.TAG_TABLE, container, |
| true)) { |
| List ancestors = EditModelQuery.getAncestors(container, |
| IHTMLConstants.TAG_TABLE, true); |
| int offset = ancestors.size(); |
| // remove 'table' |
| Node temp = (Node) ancestors.remove(offset - 1); |
| if (temp == container) { |
| return true; |
| } |
| offset--; |
| result = checkValidTrTd(ancestors, container); |
| if (!result) { |
| // thead->tr->td |
| temp = (Node) ancestors.get(offset - 1); |
| name = temp.getNodeName(); |
| if (Arrays.asList(CONTAINER).contains( |
| name.toLowerCase())) { |
| if (temp == container) { |
| result = true; |
| } else { |
| // remove 'thead' |
| ancestors.remove(offset - 1); |
| offset--; |
| result = checkValidTrTd(ancestors, container); |
| } |
| } |
| } |
| } |
| } |
| return result; |
| } catch (Exception e) { |
| // The exception means the structure is not a valid table, don't |
| // need to report. |
| return false; |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jst.pagedesigner.caret.IPositionRule#isEditable(org.eclipse.jst.pagedesigner.caret.Target) |
| */ |
| public boolean isEditable(Target target) { |
| if (EditModelQuery.isChild(IHTMLConstants.TAG_TABLE, target.getNode(), |
| false)) { |
| if (isInValidTable(target.getNode())) { |
| List ancestors = EditModelQuery.getAncestors(target.getNode(), |
| IHTMLConstants.TAG_TABLE, true); |
| if (ancestors.size() >= 3) { |
| if (IHTMLConstants.TAG_TH |
| .equalsIgnoreCase(((Node) ancestors.get(ancestors |
| .size() - 3)).getNodeName()) |
| || // |
| IHTMLConstants.TAG_TD |
| .equalsIgnoreCase(((Node) ancestors |
| .get(ancestors.size() - 3)) |
| .getNodeName())) { |
| return true; |
| } else if (ancestors.size() >= 4 // |
| && (IHTMLConstants.TAG_TH |
| .equalsIgnoreCase(((Node) ancestors |
| .get(ancestors.size() - 4)) |
| .getNodeName()) || // |
| IHTMLConstants.TAG_TD |
| .equalsIgnoreCase(((Node) ancestors |
| .get(ancestors.size() - 4)) |
| .getNodeName()))) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| return super.isEditable(target); |
| } |
| |
| private boolean checkValidTrTd(List ancestors, Node node) { |
| int offset = ancestors.size(); |
| if (IHTMLConstants.TAG_TR.equalsIgnoreCase(((Node) ancestors |
| .get(offset - 1)).getLocalName())) { |
| if (ancestors.get(offset - 1) == node) { |
| return true; |
| } else if (IHTMLConstants.TAG_TH.equalsIgnoreCase(((Node) ancestors |
| .get(offset - 2)).getLocalName()) |
| || // |
| IHTMLConstants.TAG_TD.equalsIgnoreCase(((Node) ancestors |
| .get(offset - 2)).getLocalName())) { |
| return true; |
| } |
| } |
| return false; |
| } |
| } |