/*******************************************************************************
* Copyright (c) 2004, 2010 MAKE Technologies 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:
* MAKE Technologies Inc - initial API and implementation
* Mariot Chauvin <mariot.chauvin@obeo.fr> - Improvements and bug fixes
* Pascal Gelinas <pascal.gelinas @nuecho.com> - Improvements and bug fixes
*******************************************************************************/
package org.eclipse.swtbot.eclipse.gef.finder.widgets;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Stack;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.draw2d.ScrollBar;
import org.eclipse.draw2d.ScrollPane;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.requests.DirectEditRequest;
import org.eclipse.swtbot.swt.finder.finders.UIThreadRunnable;
import org.eclipse.swtbot.swt.finder.results.Result;
import org.eclipse.swtbot.swt.finder.results.VoidResult;
import org.hamcrest.Matcher;
/**
* represent an edit part of a graphical viewer.
*
* @author David Green
* @see SWTBotGefEditor
*/
public class SWTBotGefEditPart {
protected final EditPart part;
protected final SWTBotGefViewer viewer;
/**
* @param veiwer viewer
* @param parent the parent, or null if this is the root edit part
* @param part the GEF part
*/
SWTBotGefEditPart(final SWTBotGefViewer viewer, final EditPart part) {
this.viewer = viewer;
this.part = part;
}
/**
* get the parent, or null if this is the root edit part.
*/
public SWTBotGefEditPart parent() {
return UIThreadRunnable.syncExec(new Result<SWTBotGefEditPart>() {
public SWTBotGefEditPart run() {
return viewer.createEditPart(part.getParent());
}
});
}
/**
* Get the children of this edit part.
*
* @return the edit part's children
*/
@SuppressWarnings("unchecked")
public List<SWTBotGefEditPart> children() {
return UIThreadRunnable.syncExec(new Result<List<SWTBotGefEditPart>>() {
public List<SWTBotGefEditPart> run() {
List<SWTBotGefEditPart> children = new ArrayList<SWTBotGefEditPart>();
for (org.eclipse.gef.EditPart child : ((List<org.eclipse.gef.EditPart>) part.getChildren())) {
children.add(viewer.createEditPart(child));
}
return children;
}
});
}
/**
* find descendants that match.
*
* @param matcher the matcher that matches against {@link org.eclipse.gef.EditPart}
* @return a list of matches or an empty list if there are none
*/
@SuppressWarnings("unchecked")
public List<SWTBotGefEditPart> descendants(final Matcher<? extends EditPart> matcher) {
return UIThreadRunnable.syncExec(new Result<List<SWTBotGefEditPart>>() {
public List<SWTBotGefEditPart> run() {
List<SWTBotGefEditPart> descendants = new ArrayList<SWTBotGefEditPart>();
Stack<SWTBotGefEditPart> parts = new Stack<SWTBotGefEditPart>();
parts.push(SWTBotGefEditPart.this);
while (!parts.isEmpty()) {
SWTBotGefEditPart part = parts.pop();
for (org.eclipse.gef.EditPart child : ((List<org.eclipse.gef.EditPart>) part.part.getChildren())) {
SWTBotGefEditPart childPart = viewer.createEditPart(child);
if (matcher.matches(child)) {
descendants.add(childPart);
}
parts.push(childPart);
}
}
return descendants;
}
});
}
/**
* get the underlying wrapped {@link EditPart} instance
*
* @return the wrapped {@link EditPart}.
*/
public EditPart part() {
return part;
}
/**
* focus on this edit part
*/
public void focus() {
UIThreadRunnable.syncExec(new VoidResult() {
public void run() {
viewer.graphicalViewer.setFocus(part);
}
});
}
/**
* select this edit part as a single selection
*/
public SWTBotGefEditPart select() {
viewer.select(this);
return this;
}
/**
* click on the edit part.
*/
public SWTBotGefEditPart click() {
final Rectangle bounds = getBounds();
return click(bounds.getTopLeft());
}
/**
* click on the edit part at the specified location
*/
public SWTBotGefEditPart click(final Point location) {
viewer.getCanvas().mouseEnterLeftClickAndExit(location.x, location.y);
return this;
}
/**
* double click on the edit part.
*/
public SWTBotGefEditPart doubleClick() {
final Rectangle bounds = getBounds();
viewer.getCanvas().mouseMoveDoubleClick(bounds.x, bounds.y);
return this;
}
/* this method is not finished. She will become public when finished, but API is not guaranteed */
private void scrollUp() {
final IFigure figure = ((GraphicalEditPart) part).getFigure();
for (final Object child : figure.getChildren()) {
if (child instanceof ScrollPane) {
Collection<ScrollBar> scrollbars = getScrollBars((ScrollPane) child);
Point pointToClick = scrollbars.iterator().next().getBounds().getCenter();
viewer.getCanvas().mouseMoveLeftClick(pointToClick.x, pointToClick.y);
}
}
}
/* this method is not finished. She will become public when finished, but API is not guaranteed */
private Collection<ScrollBar> getScrollBars(final ScrollPane scrollPane) {
Set<ScrollBar> scrollbars = new HashSet<ScrollBar>();
for (final Object child :scrollPane.getChildren()) {
if (child instanceof ScrollBar) {
scrollbars.add((ScrollBar) child);
}
}
return scrollbars;
}
/**
* Resize the current edit part from the corner orientation to the new size. The direction is specified using using
* {@link PositionConstants#NORTH}, {@link PositionConstants#NORTH_EAST}, etc.
*
* @param direction the direction
* @param width the new width
* @param height the new height
*/
public void resize(int direction, int width, int height) {
Rectangle bounds = getBounds();
int fromX = 0 ;
int fromY = 0;
int toX = 0;
int toY = 0;
switch(direction) {
case PositionConstants.NORTH:
fromX = bounds.x + bounds.width / 2;
fromY = bounds.y;
toX= bounds.x + bounds.width / 2;
toY= bounds.y + bounds.height - height;
break;
case PositionConstants.SOUTH:
fromX = bounds.x + bounds.width / 2;
fromY = bounds.y + bounds.height;
toX=bounds.x + bounds.width / 2;
toY=bounds.y +height;
break;
case PositionConstants.EAST:
fromX = bounds.x;
fromY = bounds.y + bounds.height/2;
toX = bounds.x + bounds.width - width;
toY = bounds.y + bounds.height/2;
break;
case PositionConstants.WEST:
fromX = bounds.x + bounds.width;
fromY = bounds.y + bounds.height/2;
toX = bounds.x + width;
toY = bounds.y + bounds.height/2;
break;
case PositionConstants.NORTH_EAST:
fromX = bounds.x;
fromY = bounds.y;
toX = bounds.x + bounds.width - width;
toY= bounds.y + bounds.height - height;
break;
case PositionConstants.NORTH_WEST:
fromX = bounds.x + bounds.width;
fromY = bounds.y;
toX = bounds.x + width;
toY= bounds.y + bounds.height - height;
break;
case PositionConstants.SOUTH_EAST:
fromX = bounds.x;
fromY = bounds.y + bounds.height;
toX = bounds.x + bounds.width - width;
toY = bounds.y +height;
break;
case PositionConstants.SOUTH_WEST:
fromX = bounds.x + bounds.width;
fromY = bounds.y + bounds.height;
toX = bounds.x + width;
toY = bounds.y +height;
break;
default:
throw new IllegalArgumentException("direction given is not a valid one");
}
viewer.drag(fromX, fromY, toX, toY);
}
private Rectangle getBounds() {
final IFigure figure = ((GraphicalEditPart) part).getFigure();
final Rectangle bounds = figure.getBounds().getCopy();
figure.translateToAbsolute(bounds);
return bounds;
}
public SWTBotGefEditPart activateDirectEdit() {
return activateDirectEdit(null);
}
public SWTBotGefEditPart activateDirectEdit(final Object feature) {
UIThreadRunnable.asyncExec(new VoidResult() {
public void run() {
DirectEditRequest request = new DirectEditRequest();
if (feature != null)
request.setDirectEditFeature(feature);
part().performRequest(request);
}
});
return this;
}
/**
* provide a description of this edit part that is useful for debugging purposes.
*/
public String toString() {
StringWriter writer = new StringWriter();
PrintWriter out = new PrintWriter(writer);
describe(out, 0);
out.close();
return writer.toString();
}
private void describe(PrintWriter out, int indent) {
out.print(indent(indent));
out.print(part.getClass().getName());
List<SWTBotGefEditPart> children = children();
out.print(" children=" + children.size());
out.println();
for (SWTBotGefEditPart child : children) {
child.describe(out, indent + 1);
}
}
private String indent(int size) {
if (size == 0) {
return "";
}
StringBuilder buf = new StringBuilder(size);
for (int x = 0; x < size; ++x) {
buf.append("\t");
}
return buf.toString();
}
@SuppressWarnings("unchecked")
public List<SWTBotGefConnectionEditPart> sourceConnections() {
return UIThreadRunnable.syncExec(new Result<List<SWTBotGefConnectionEditPart>>() {
public List<SWTBotGefConnectionEditPart> run() {
List<SWTBotGefConnectionEditPart> connections = new ArrayList<SWTBotGefConnectionEditPart>();
List<org.eclipse.gef.ConnectionEditPart> sourceConnections = ((GraphicalEditPart) part).getSourceConnections();
for (org.eclipse.gef.ConnectionEditPart c : sourceConnections) {
connections.add(viewer.createEditPart(c));
}
return connections;
}
});
}
@SuppressWarnings("unchecked")
public List<SWTBotGefConnectionEditPart> targetConnections() {
return UIThreadRunnable.syncExec(new Result<List<SWTBotGefConnectionEditPart>>() {
public List<SWTBotGefConnectionEditPart> run() {
List<SWTBotGefConnectionEditPart> connections = new ArrayList<SWTBotGefConnectionEditPart>();
List<org.eclipse.gef.ConnectionEditPart> targetConnections = ((GraphicalEditPart) part).getTargetConnections();
for (org.eclipse.gef.ConnectionEditPart c : targetConnections) {
connections.add(viewer.createEditPart(c));
}
return connections;
}
});
}
}