/* ******************************************************************************
* Copyright (c) 2006-2012 XMind Ltd. and others.
*
* This file is a part of XMind 3. XMind releases 3 and
* above are dual-licensed under the Eclipse Public License (EPL),
* which is available at http://www.eclipse.org/legal/epl-v10.html
* and the GNU Lesser General Public License (LGPL),
* which is available at http://www.gnu.org/licenses/lgpl.html
* See http://www.xmind.net/license.html for details.
*
* Contributors:
* XMind Ltd. - initial API and implementation
*******************************************************************************/
package org.xmind.gef;
import java.util.List;
import org.eclipse.draw2d.FigureCanvas;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Layer;
import org.eclipse.draw2d.LightweightSystem;
import org.eclipse.draw2d.Viewport;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.xmind.gef.dnd.IDndSupport;
import org.xmind.gef.event.PartsEventDispatcher;
import org.xmind.gef.event.ViewerEventDispatcher;
import org.xmind.gef.part.IGraphicalEditPart;
import org.xmind.gef.part.IGraphicalPart;
import org.xmind.gef.part.IGraphicalRootPart;
import org.xmind.gef.part.IPart;
import org.xmind.gef.part.IRootPart;
import org.xmind.gef.tool.ITool;
import org.xmind.gef.tool.SelectTool;
/**
* @author Brian Sun
*/
public class GraphicalViewer extends AbstractViewer
implements IGraphicalViewer {
private static final Point POINT = new Point();
protected class GraphicalSelectionSupport extends SelectionSupport {
public boolean isSelectable(IPart p) {
boolean selectable = super.isSelectable(p);
if (selectable) {
if (p instanceof IGraphicalPart) {
IFigure fig = ((IGraphicalPart) p).getFigure();
if (fig == null || !fig.isShowing())
return false;
}
}
return selectable;
}
protected void partSelectionChanged(List<? extends IPart> parts,
boolean reveal) {
super.partSelectionChanged(parts, reveal);
if (getEditDomain() != null) {
ITool tool = getEditDomain().getTool(GEF.TOOL_SELECT);
if (tool != null && tool instanceof SelectTool) {
((SelectTool) tool).resetSeqSelectStart();
}
IPart focused = findSelectablePart(getFocused());
if (focused == null || !focused.getStatus().isActive()
|| !focused.getStatus().isSelected()) {
setFocused(findSelectedPart(parts));
}
}
}
protected IPart findSelectedPart(List<? extends IPart> parts) {
for (IPart p : parts) {
if (p.getStatus().isActive() && p.getStatus().isSelected())
return p;
}
return null;
}
}
private LightweightSystem lws = createLightweightSystem();
private ILayerManager layerManager = null;
private ViewerEventDispatcher eventDispatcher = createEventDispatcher();
private ZoomManager zoomManager = null;
private Viewport viewport = new Viewport(true);
public GraphicalViewer() {
super();
lws.setEventDispatcher(eventDispatcher);
lws.setContents(viewport);
}
public <T> T getAdapter(Class<T> adapter) {
if (LightweightSystem.class.equals(adapter))
return adapter.cast(getLightweightSystem());
if (ILayerManager.class.equals(adapter))
return adapter.cast(getLayerManager());
if (FigureCanvas.class.equals(adapter))
return adapter.cast(getCanvas());
if (ZoomManager.class.equals(adapter))
return adapter.cast(getZoomManager());
if (IGraphicalPart.class.equals(adapter))
return adapter.cast(getRootPart() instanceof IGraphicalPart
? getRootPart() : null);
if (IFigure.class.equals(adapter))
return adapter.cast(getRootFigure());
if (Viewport.class.equals(adapter))
return adapter.cast(getViewport());
return super.getAdapter(adapter);
}
public IGraphicalPart findGraphicalPart(Object model) {
IPart part = findPart(model);
if (part instanceof IGraphicalPart)
return (IGraphicalPart) part;
return null;
}
public IPart findPart(int x, int y) {
return findPart(convertPoint(x, y));
}
protected Point convertPoint(int controlX, int controlY) {
return computeToLayer(POINT.setLocation(controlX, controlY), true);
}
protected IPart findPart(Point position) {
return findPart(getRootPart(), position);
}
protected IPart findPart(IPart parent, Point position) {
if (parent == null || !(parent instanceof IGraphicalEditPart))
return null;
return (((IGraphicalEditPart) parent).findAt(position,
getPartSearchCondition()));
}
protected LightweightSystem createLightweightSystem() {
return new LightweightSystem();
}
public LightweightSystem getLightweightSystem() {
return lws;
}
protected Viewport getViewport() {
return viewport;
}
public Control createControl(Composite parent) {
return createControl(parent, SWT.DOUBLE_BUFFERED);
}
protected Control internalCreateControl(Composite parent, int style) {
//FIXME
FigureCanvas canvas = new FigureCanvas(parent, style,
getLightweightSystem()) {
@Override
public org.eclipse.swt.graphics.Rectangle computeTrim(int x, int y,
int width, int height) {
org.eclipse.swt.graphics.Rectangle trim = super.computeTrim(x,
y, width, height);
if (!getVerticalBar().isVisible()) {
trim.width = 0;
}
if (!getHorizontalBar().isVisible()) {
trim.height = 0;
}
return trim;
}
};
canvas.setViewport(viewport);
return canvas;
}
/*
* (non-Javadoc)
* @see
* org.xmind.gef.AbstractViewer#hookControl(org.eclipse.swt.widgets.Control)
*/
@Override
protected void hookControl(Control control) {
if (getEditDomain() != null) {
eventDispatcher.activate();
}
super.hookControl(control);
}
public void setRootPart(IRootPart rootPart) {
super.setRootPart(rootPart);
IFigure rootFigure = getRootFigure();
if (rootFigure instanceof Viewport) {
viewport = (Viewport) rootFigure;
} else {
viewport = new Viewport(true);
viewport.setContents(rootFigure);
}
getLightweightSystem().setContents(viewport);
if (getCanvas() != null && !getCanvas().isDisposed()) {
getCanvas().setViewport(viewport);
}
}
protected IFigure getRootFigure() {
if (getRootPart() instanceof IGraphicalPart) {
return ((IGraphicalPart) getRootPart()).getFigure();
}
return null;
}
protected void revalidateContents() {
getCanvas().layout(true);
}
protected ViewerEventDispatcher createEventDispatcher() {
return new PartsEventDispatcher(this);
}
// public ViewerEventDispatcher getEventDispatcher() {
// return eventDispatcher;
// }
public void setEditDomain(EditDomain editDomain) {
if (getControl() != null && !getControl().isDisposed()) {
eventDispatcher.deactivate();
}
super.setEditDomain(editDomain);
if (getEditDomain() != null && getControl() != null
&& !getControl().isDisposed()) {
eventDispatcher.activate();
}
}
public Layer getLayer(Object key) {
return layerManager == null ? null : layerManager.getLayer(key);
}
public ILayerManager getLayerManager() {
return layerManager;
}
public void setLayerManager(ILayerManager layerManager) {
this.layerManager = layerManager;
}
public void updateToolTip() {
if (getControl() != null && !getControl().isDisposed()) {
eventDispatcher.updateToolTip();
}
}
public void hideToolTip() {
if (getControl() != null)
getControl().setToolTipText(null);
}
public FigureCanvas getCanvas() {
return (FigureCanvas) super.getControl();
}
public Dimension getSize() {
return new Dimension(getCanvas().getSize());
}
public Rectangle getClientArea() {
Rectangle area = new Rectangle(getCanvas().getClientArea());
area.setLocation(getScrollPosition());
return area;
}
public Point getCenterPoint() {
return getViewport().getClientArea().getCenter();
}
public void center(Rectangle area) {
center(area.getCenter());
}
/*
* (non-Javadoc)
* @see org.xmind.gef.IGraphicalViewer#center(int, int)
*/
public void center(int x, int y) {
Rectangle clientArea = getViewport().getClientArea();
scrollTo(x - clientArea.width >> 1, y - clientArea.height >> 1);
}
public void center(Point center) {
center(center.x, center.y);
}
public void scrollToX(int x) {
if (usesSmoothScroll()) {
getViewport().setHorizontalLocation(x);
} else {
getCanvas().scrollToX(x);
}
}
public void scrollToY(int y) {
if (usesSmoothScroll()) {
getViewport().setVerticalLocation(y);
} else {
getCanvas().scrollToY(y);
}
}
public void scrollTo(Point p) {
scrollTo(p.x, p.y);
}
public void scrollTo(int x, int y) {
if (usesSmoothScroll()) {
getViewport().setViewLocation(x, y);
} else {
getCanvas().scrollTo(x, y);
}
}
protected boolean usesSmoothScroll() {
return Boolean.TRUE.equals(getProperties().get(VIEWER_SCROLL_SMOOTH));
}
/**
* @see org.xmind.gef.IViewer#scrollDelta(org.eclipse.draw2d.geometry.Dimension)
*/
public void scrollDelta(Dimension d) {
scrollTo(getScrollPosition().translate(d));
}
/**
* @see org.xmind.gef.IGraphicalViewer#scrollDelta(int, int)
*/
public void scrollDelta(int dx, int dy) {
scrollTo(getScrollPosition().translate(dx, dy));
}
/**
* @see org.xmind.gef.IViewer#getScrollPosition()
*/
public Point getScrollPosition() {
return getViewport().getViewLocation();
}
/**
* @see org.xmind.gef.IGraphicalViewer#computeToLayer(org.eclipse.draw2d.geometry.Point,
* boolean)
*/
public Point computeToLayer(Point controlPoint, boolean zoomed) {
Point p = getScrollPosition();
p.translate(controlPoint);
if (zoomed) {
return p.scale(1 / getZoomManager().getScale());
}
return p;
}
/**
* @see org.xmind.gef.IGraphicalViewer#computeToControl(org.eclipse.draw2d.geometry.Point,
* boolean)
*/
public Point computeToControl(Point layerPoint, boolean zoomed) {
POINT.setLocation(layerPoint);
if (zoomed) {
POINT.scale(getZoomManager().getScale());
}
return getScrollPosition().negate().translate(POINT);
}
public Point computeToDisplay(Point layerPoint, boolean zoomed) {
Point p = computeToControl(layerPoint, zoomed);
org.eclipse.swt.graphics.Point loc = getControl().toDisplay(p.x, p.y);
return p.setLocation(loc.x, loc.y);
}
public void ensureVisible(Rectangle box) {
box = getZoomManager().getScaled(box);
Rectangle clientArea = getClientArea();
if (clientArea.contains(box) || box.contains(clientArea))
return;
ensureVisible(box, clientArea, 0);
}
public void ensureControlVisible(Rectangle box) {
Rectangle clientArea = new Rectangle(getCanvas().getClientArea());
if (clientArea.contains(box) || box.contains(clientArea))
return;
ensureVisible(box, clientArea, 0);
}
/**
* @param box
* @param clientArea
* @param margin
*/
protected void ensureVisible(Rectangle box, Rectangle clientArea,
int margin) {
int dx = 0;
int dy = 0;
if (box.width > clientArea.width)
dx = box.getCenter().x - clientArea.getCenter().x;
else if (box.x < clientArea.x)
dx = box.x - clientArea.x - margin;
else if (box.right() > clientArea.right())
dx = box.right() - clientArea.right() + margin;
if (box.height > clientArea.height)
dy = box.getCenter().y - clientArea.getCenter().y;
else if (box.y < clientArea.y)
dy = box.y - clientArea.y - margin;
else if (box.bottom() > clientArea.bottom())
dy = box.bottom() - clientArea.bottom() + margin;
smoothScrollDelta(dx, dy);
}
/**
* @param dx
* @param dy
*/
protected void smoothScrollDelta(int dx, int dy) {
scrollDelta(dx, dy);
}
protected IGraphicalRootPart getGraphicalRootEditPart() {
IRootPart rootPart = getRootPart();
if (rootPart instanceof IGraphicalRootPart) {
return (IGraphicalRootPart) rootPart;
}
return null;
}
protected ISelectionSupport createSelectionSupport() {
return new GraphicalSelectionSupport();
}
protected void inputChanged(Object input, Object oldInput) {
boolean controlAvailable = getControl() != null
&& !getControl().isDisposed();
if (controlAvailable) {
getControl().setRedraw(false);
}
ISelection oldSelection = getSelection();
setSelectionOnInputChanged(StructuredSelection.EMPTY);
double oldScale = getZoomManager().getScale();
if (controlAvailable && getEditDomain() != null) {
eventDispatcher.deactivate();
}
internalInputChanged(input, oldInput);
if (controlAvailable && getEditDomain() != null) {
eventDispatcher.activate();
}
setSelectionOnInputChanged(oldSelection);
if (oldScale >= 0) {
getZoomManager().setScale(oldScale);
}
if (controlAvailable) {
getControl().setRedraw(true);
}
}
protected void setSelectionOnInputChanged(ISelection selection) {
setSelection(selection);
}
protected void internalInputChanged(Object input, Object oldInput) {
super.inputChanged(input, oldInput);
}
// /**
// * @param x
// * @param y
// */
// protected void alternativeScrollTo(int x, int y) {
// int hOffset = verifyScrollBarOffset(getViewport()
// .getHorizontalRangeModel(), x);
// int vOffset = verifyScrollBarOffset(getViewport()
// .getVerticalRangeModel(), y);
//
// int hOffsetOld = getViewport().getViewLocation().x;
// if (hOffset == hOffsetOld) {
// scrollToY(y);
// return;
// }
// int dx = -hOffset + hOffsetOld;
//
// int vOffsetOld = getViewport().getViewLocation().y;
// if (vOffset == vOffsetOld) {
// scrollToX(x);
// return;
// }
// int dy = -vOffset + vOffsetOld;
//
// Rectangle clientArea = getViewport().getBounds()
// .getCropped(getViewport().getInsets());
// Rectangle blit = clientArea.getResized(-Math.abs(dx), -Math.abs(dy));
// Rectangle expose = clientArea.getCopy();
// Rectangle expose2 = clientArea.getCopy();
// Point dest = clientArea.getTopLeft();
// expose.width = Math.abs(dx);
// if (dx < 0) { //Moving left?
// blit.translate(-dx, 0); //Move blit area to the right
// expose.x = dest.x + blit.width;
// } else
// //Moving right
// dest.x += dx; //Move expose area to the right
//
// expose2.height = Math.abs(dy);
// if (dy < 0) { //Moving up?
// blit.translate(0, -dy); //Move blit area down
// expose2.y = dest.y + blit.height; //Move expose area down
// } else
// //Moving down
// dest.y += dy;
//
// // fix for bug 41111
// Control[] children = getCanvas().getChildren();
// boolean[] manualMove = new boolean[children.length];
// for (int i = 0; i < children.length; i++) {
// org.eclipse.swt.graphics.Rectangle bounds = children[i].getBounds();
// manualMove[i] = blit.width <= 0 || blit.height < 0
// || bounds.x > blit.x + blit.width
// || bounds.y > blit.y + blit.height
// || bounds.x + bounds.width < blit.x
// || bounds.y + bounds.height < blit.y;
// }
// getCanvas().scroll(dest.x, dest.y, blit.x, blit.y, blit.width,
// blit.height, true);
//
// for (int i = 0; i < children.length; i++) {
// org.eclipse.swt.graphics.Rectangle bounds = children[i].getBounds();
// if (manualMove[i])
// children[i].setBounds(bounds.x + dx, bounds.y, bounds.width,
// bounds.height);
// }
//
// getViewport().setIgnoreScroll(true);
// getViewport().setHorizontalLocation(hOffset);
// getViewport().setVerticalLocation(vOffset);
// getViewport().setIgnoreScroll(false);
// getCanvas().redraw(expose.x, expose.y, expose.width, expose.height,
// true);
// getCanvas().redraw(expose2.x, expose2.y, expose2.width, expose2.height,
// true);
// }
//
// private int verifyScrollBarOffset(RangeModel model, int value) {
// value = Math.max(model.getMinimum(), value);
// return Math.min(model.getMaximum() - model.getExtent(), value);
// }
public ZoomManager getZoomManager() {
if (zoomManager == null)
zoomManager = new ZoomManager();
return zoomManager;
}
public void setZoomManager(ZoomManager zoomManager) {
this.zoomManager = zoomManager;
}
public void setDndSupport(IDndSupport dndSupport) {
super.setDndSupport(dndSupport);
eventDispatcher.setDndSupport(dndSupport);
}
/*
* (non-Javadoc)
* @see
* org.xmind.gef.AbstractViewer#setCursor(org.eclipse.swt.graphics.Cursor)
*/
@Override
public void setCursor(Cursor cursor) {
eventDispatcher.setOverridingCursor(cursor);
}
}