/* ******************************************************************************
* 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.service;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import org.eclipse.draw2d.FigureCanvas;
import org.eclipse.draw2d.FreeformFigure;
import org.eclipse.draw2d.Layer;
import org.eclipse.draw2d.Viewport;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.xmind.gef.GEF;
import org.xmind.gef.IGraphicalViewer;
/**
* @author Frank Shaka
*
*/
public class CenterPreservationService extends GraphicalViewerService implements
Listener, PropertyChangeListener {
protected static final Rectangle TEMP_AREA = new Rectangle();
private boolean centerOnContents;
private Display display = null;
protected Viewport viewport = null;
protected Point centerPoint = new Point();
private boolean mousePressing = false;
private boolean keyPressing = false;
private boolean resizedDuringMousePress = false;
private boolean resizedDuringKeyPress = false;
/**
*
*/
public CenterPreservationService(IGraphicalViewer viewer) {
this(viewer, false);
}
/**
* Constructs a new center preservation service. The parameter
* <code>centerOnContents</code> enables/disables the ability to take the
* center of the contents layer as the new center point.
*
* @param viewer
* @param centerOnContents
*/
public CenterPreservationService(IGraphicalViewer viewer,
boolean centerOnContents) {
super(viewer);
this.centerOnContents = centerOnContents;
}
/*
* (non-Javadoc)
*
* @see
* org.xmind.gef.service.AbstractViewerService#hookControl(org.eclipse.swt
* .widgets.Control)
*/
@Override
protected void hookControl(Control control) {
super.hookControl(control);
FigureCanvas canvas = (FigureCanvas) control;
if (canvas != null && !canvas.isDisposed()) {
canvas.addListener(SWT.Resize, this);
canvas.addListener(SWT.FocusIn, this);
canvas.addListener(SWT.FocusOut, this);
canvas.addListener(SWT.Paint, this);
viewport = canvas.getViewport();
if (viewport != null) {
viewport.addPropertyChangeListener(
Viewport.PROPERTY_VIEW_LOCATION, this);
}
display = canvas.getDisplay();
if (display != null) {
display.addFilter(SWT.MouseDown, this);
display.addFilter(SWT.MouseUp, this);
display.addFilter(SWT.KeyDown, this);
display.addFilter(SWT.KeyUp, this);
}
}
mousePressing = false;
keyPressing = false;
resizedDuringMousePress = false;
resizedDuringKeyPress = false;
updateCenterPoint();
}
/*
* (non-Javadoc)
*
* @see
* org.xmind.gef.service.AbstractViewerService#unhookControl(org.eclipse
* .swt.widgets.Control)
*/
@Override
protected void unhookControl(Control control) {
FigureCanvas canvas = (FigureCanvas) control;
if (canvas != null && !canvas.isDisposed()) {
canvas.removeListener(SWT.Resize, this);
canvas.removeListener(SWT.FocusIn, this);
canvas.removeListener(SWT.Paint, this);
}
if (viewport != null) {
viewport.removePropertyChangeListener(
Viewport.PROPERTY_VIEW_LOCATION, this);
}
if (display != null && !display.isDisposed()) {
display.removeFilter(SWT.MouseDown, this);
display.removeFilter(SWT.MouseUp, this);
display.removeFilter(SWT.KeyDown, this);
display.removeFilter(SWT.KeyUp, this);
}
mousePressing = false;
keyPressing = false;
resizedDuringMousePress = false;
resizedDuringKeyPress = false;
super.unhookControl(control);
}
/*
* (non-Javadoc)
*
* @see org.xmind.gef.service.AbstractViewerService#activate()
*/
@Override
protected void activate() {
}
/*
* (non-Javadoc)
*
* @see org.xmind.gef.service.AbstractViewerService#deactivate()
*/
@Override
protected void deactivate() {
}
/*
* (non-Javadoc)
*
* @seejava.beans.PropertyChangeListener#propertyChange(java.beans.
* PropertyChangeEvent)
*/
public void propertyChange(PropertyChangeEvent evt) {
if (!isActive())
return;
if ((mousePressing && resizedDuringMousePress)
|| (keyPressing && resizedDuringKeyPress))
return;
updateCenterPoint();
}
private void updateCenterPoint() {
if (!isActive() || viewport == null)
return;
if (centerOnContents) {
Layer layer = getViewer().getLayer(GEF.LAYER_CONTENTS);
Rectangle bounds;
if (layer instanceof FreeformFigure) {
bounds = ((FreeformFigure) layer).getFreeformExtent();
} else {
bounds = layer.getBounds();
}
centerPoint.setLocation(bounds.x + bounds.width / 2, bounds.y
+ bounds.height / 2);
} else {
Rectangle r = viewport.getClientArea(TEMP_AREA);
centerPoint.setLocation(r.x + r.width / 2, r.y + r.height / 2);
}
}
private void centerViewportOnResize() {
if (!isActive() || viewport == null)
return;
Rectangle r = viewport.getClientArea(TEMP_AREA);
viewport.setViewLocation(centerPoint.x - r.width / 2, centerPoint.y
- r.height / 2);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.
* Event)
*/
public void handleEvent(Event event) {
if (!isActive())
return;
if (event.type == SWT.Resize) {
if (needsCenterWhenResizing()) {
centerViewportOnResize();
}
} else if (event.type == SWT.FocusIn || event.type == SWT.Paint) {
// Fix bug:
FigureCanvas fc = (FigureCanvas) event.widget;
org.eclipse.swt.graphics.Rectangle clientArea = fc.getClientArea();
if (clientArea.width > 0 || clientArea.height > 0) {
centerViewportOnResize();
fc.removeListener(event.type, this);
}
} else if (event.type == SWT.MouseDown) {
mousePressing = true;
} else if (event.type == SWT.KeyDown) {
keyPressing = true;
} else if (event.type == SWT.MouseUp) {
mousePressing = false;
if (resizedDuringMousePress) {
resizedDuringMousePress = false;
centerViewportOnResize();
}
} else if (event.type == SWT.KeyUp) {
keyPressing = false;
if (resizedDuringKeyPress) {
resizedDuringKeyPress = false;
centerViewportOnResize();
}
}
}
// If resizing occurs while mouse or key is pressed,
// don't center until mouse or key is released
private boolean needsCenterWhenResizing() {
if (!mousePressing && !keyPressing)
return true;
if (mousePressing)
resizedDuringMousePress = true;
if (keyPressing)
resizedDuringKeyPress = true;
return false;
}
}