/******************************************************************************* * 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.editpolicies; import java.util.List; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.gef.GraphicalEditPart; import org.eclipse.jst.pagedesigner.css2.layout.FlowBox; import org.eclipse.jst.pagedesigner.css2.layout.ICSSFigure; import org.eclipse.jst.pagedesigner.parts.DocumentEditPart; import org.eclipse.jst.pagedesigner.parts.ElementEditPart; import org.eclipse.wst.xml.core.internal.contentmodel.CMElementDeclaration; import org.eclipse.wst.xml.core.internal.contentmodel.modelquery.ModelQuery; import org.eclipse.wst.xml.core.internal.modelquery.ModelQueryUtil; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; /** * @author mengbo */ public final class LocationHelper { /** * @param host * @param p * @param result * @param tagName * @param skip * @return true if insertion point is found */ public static boolean findInsertLocation(GraphicalEditPart host, Point p, GraphicalEditPart[] result, String tagName, Node skip) { if (isHostInsideSkip(host, skip)) return false; while (isValidHost(host) && !canHostContainTag(host, tagName)) { if (host.getParent() instanceof GraphicalEditPart) host = (GraphicalEditPart) host.getParent(); else host = null; } if (!isValidHost(host)) return false; // ok, next we try to find a insertion point inside host result[0] = host; List children = host.getChildren(); if (children.isEmpty()) { result[1] = null; return true; } // TODO: never read GraphicalEditPart ref = null; for (int i = 0, size = children.size(); i < size; i++) { GraphicalEditPart child = (GraphicalEditPart) children.get(i); Rectangle rect = getAbsoluteBounds(child); if (rect.contains(p)) { IFigure figure = child.getFigure(); if (figure instanceof ICSSFigure) { List frags = ((ICSSFigure) figure).getFragmentsForRead(); if (frags.size() > 1) // more than one frags, so is a zig // zag. { // check whether is before the first box. FlowBox box = (FlowBox) frags.get(0); Rectangle rect1 = getAbsoluteBounds(figure, box); if (rect1.x > p.x && rect1.y + rect1.height > p.y) { // p is at left/above the first box. so we think p // is before this child result[1] = child; return true; } // check whether is after the last box box = (FlowBox) frags.get(frags.size() - 1); rect1 = getAbsoluteBounds(figure, box); if (rect1.x < p.x && rect1.y < p.y) { continue; } } } // ok, treat as the point in a rect figure, see which side is // closer. if (p.x > rect.x + rect.width / 2) { continue; } result[1] = child; return true; } else if (rect.x + rect.width < p.x || rect.y + rect.height < p.y) { // p is at right or below rect. so the point is "after" the // rect. continue; } else { // ok, p is "before" rect. result[1] = child; return true; } } // we search through all. result[1] = null; return true; } /** * @param figure * @param box * @return the bounding rectangle */ public static Rectangle getAbsoluteBounds(IFigure figure, FlowBox box) { Rectangle r = new Rectangle(box.getX(), box.getY(), box.getWidth(), box .getHeight()); figure.translateToAbsolute(r); return r; } /** * @param child * @return the bounding rectangle */ public static Rectangle getAbsoluteBounds(GraphicalEditPart child) { Rectangle bounds = child.getFigure().getBounds().getCopy(); child.getFigure().translateToAbsolute(bounds); return bounds; } /** * @param host * @param tagName * @return */ private static boolean canHostContainTag(GraphicalEditPart host, String tagName) { if (host == null) return false; Node node = (Node) host.getModel(); if (node.getNodeType() == Node.ELEMENT_NODE) { ModelQuery modelQuery = getModelQuery(node); if (modelQuery != null) { CMElementDeclaration elementDecl = modelQuery .getCMElementDeclaration((Element) node); if (elementDecl == null) { return true; } if (elementDecl.getContentType() == CMElementDeclaration.EMPTY) return false; } } return true; } /** * @param host * @return */ private static boolean isValidHost(GraphicalEditPart host) { return host != null && (host instanceof ElementEditPart || host instanceof DocumentEditPart); } /** * @param host * @param skip * @return */ private static boolean isHostInsideSkip(GraphicalEditPart host, Node skip) { if (skip == null) return false; // XXX: not done. return false; } private static ModelQuery getModelQuery(Node node) { Document doc = node.getOwnerDocument(); if (node.getNodeType() == Node.DOCUMENT_NODE) { doc = (Document) node; } return ModelQueryUtil.getModelQuery(doc); } private LocationHelper() { // util class, no external instantiation } }