blob: b6e09fe85dd97eeabd867b12e348dc8073cfc1c7 [file] [log] [blame]
/*******************************************************************************
* 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
}
}