/* ******************************************************************************
* 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.ui.internal.tools;
import org.eclipse.core.runtime.Assert;
import org.eclipse.draw2d.Cursors;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Label;
import org.eclipse.draw2d.Layer;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.xmind.core.Core;
import org.xmind.gef.GEF;
import org.xmind.gef.Request;
import org.xmind.gef.event.MouseDragEvent;
import org.xmind.gef.event.MouseEvent;
import org.xmind.gef.part.IGraphicalEditPart;
import org.xmind.gef.part.IPart;
import org.xmind.ui.internal.MindMapMessages;
import org.xmind.ui.mindmap.ITopicPart;
import org.xmind.ui.mindmap.MindMapUI;
import org.xmind.ui.resources.ColorUtils;
import org.xmind.ui.texteditor.FloatingTextEditor;
import org.xmind.ui.tools.TitleEditTool;
public class TopicTitleEditTool extends TitleEditTool {
private static class DragHandle extends Figure {
private Color triangleColor = ColorUtils.getColor("#606060"); //$NON-NLS-1$
public DragHandle() {
setForegroundColor(ColorUtils.getColor("#009900")); //$NON-NLS-1$
setBackgroundColor(ColorUtils.getColor("#33cc33")); //$NON-NLS-1$
}
protected void paintFigure(Graphics graphics) {
super.paintFigure(graphics);
graphics.setAntialias(SWT.ON);
graphics.setAlpha(0xd0);
Rectangle r = getBounds();
graphics.fillRectangle(r.x, r.y, r.width, r.height);
int cy = r.y + r.height / 2;
int cx = r.x + r.width / 2;
graphics.setBackgroundColor(triangleColor);
graphics.fillPolygon(new int[] { cx - 2, cy - 1, cx - 2, cy - 8,
cx + 2, cy - 5 });
graphics.fillPolygon(new int[] { cx - 2, cy + 5, cx + 2, cy + 8,
cx + 2, cy + 1 });
graphics.drawRectangle(r.x, r.y, r.width - 1, r.height - 1);
}
public boolean containsPoint(int x, int y) {
Rectangle r = getBounds();
return y >= r.y - 2 && y < r.y + r.height + 2 && x >= r.x - 2
&& x < r.x + r.width + 2;
}
}
private static final int HANDLE_WIDTH = 8;
private IFigure widthHandle;
private boolean locatingHandle = false;
private boolean mouseDownOnHandle = false;
private boolean draggingHandle = false;
private boolean widthChanged = false;
private int width = -1;
public String getType() {
return MindMapUI.TOOL_EDIT_TOPIC_TITLE;
}
/*
* (non-Javadoc)
* @see
* org.xmind.gef.tool.EditTool#canEdit(org.xmind.gef.part.IGraphicalEditPart
* )
*/
@Override
protected boolean canEdit(IGraphicalEditPart target) {
return target instanceof ITopicPart;
}
public void setSource(IGraphicalEditPart source) {
Assert.isTrue(source instanceof ITopicPart);
super.setSource(source);
}
protected void hookEditorControl(FloatingTextEditor editor,
ITextViewer textViewer) {
super.hookEditorControl(editor, textViewer);
widthHandle = createHandle();
if (widthHandle != null) {
editor.getControl().addControlListener(new ControlListener() {
public void controlResized(ControlEvent e) {
locateHandle((Control) e.widget);
}
public void controlMoved(ControlEvent e) {
locateHandle((Control) e.widget);
}
});
locateHandle(editor.getControl());
}
}
private void locateHandle(final Control control) {
if (widthHandle == null)
return;
if (locatingHandle)
return;
locatingHandle = true;
Display.getCurrent().asyncExec(new Runnable() {
public void run() {
try {
if (widthHandle == null || getTargetViewer() == null
|| getTargetViewer().getControl() == null
|| getTargetViewer().getControl().isDisposed()
|| control.isDisposed())
return;
if (width < 0 && control.getBounds().width > 500) {
widthChanged = true;
getHelper().setPrefWidth(500);
}
Rectangle bounds = new Rectangle(control.getBounds());
Point loc = getTargetViewer()
.computeToLayer(bounds.getLocation(), false);
widthHandle.setBounds(new Rectangle(loc.x + bounds.width,
loc.y, HANDLE_WIDTH, bounds.height));
} finally {
locatingHandle = false;
}
}
});
}
private IFigure createHandle() {
Layer layer = getTargetViewer().getLayer(GEF.LAYER_FEEDBACK);
if (layer == null)
return null;
DragHandle handle = new DragHandle();
layer.add(handle);
return handle;
}
private boolean handleContains(IFigure handle, Point p) {
return handle.containsPoint(getScaled(p));
}
protected boolean shouldFinishOnMouseDown(MouseEvent me) {
if (widthHandle != null) {
if (handleContains(widthHandle, me.cursorLocation)) {
mouseDownOnHandle = true;
return false;
}
}
mouseDownOnHandle = false;
return super.shouldFinishOnMouseDown(me);
}
@Override
protected boolean openEditor(FloatingTextEditor editor,
IDocument document) {
boolean opened = super.openEditor(editor, document);
mouseDownOnHandle = false;
draggingHandle = false;
widthChanged = false;
return opened;
}
@Override
protected void hookEditor(FloatingTextEditor editor) {
super.hookEditor(editor);
width = ((ITopicPart) getSource()).getTopic().getTitleWidth();
if (getHelper() != null) {
getHelper().setPrefWidth(width);
}
}
@Override
protected void unhookEditor(FloatingTextEditor editor) {
super.unhookEditor(editor);
if (widthHandle != null) {
if (widthHandle.getParent() != null) {
widthHandle.getParent().remove(widthHandle);
}
widthHandle = null;
}
}
@Override
protected void closeEditor(FloatingTextEditor editor, boolean finish) {
super.closeEditor(editor, finish);
mouseDownOnHandle = false;
draggingHandle = false;
}
protected boolean handleMouseDrag(MouseDragEvent me) {
if (mouseDownOnHandle) {
draggingHandle = true;
}
if (draggingHandle) {
Point p = getScaled(me.cursorLocation);
Point leftTop = getTargetViewer().computeToLayer(
new Point(getEditor().getControl().getLocation()), false);
width = Math.max(20, (int) ((p.x - leftTop.x) / getScale()));
getHelper().setPrefWidth(width);
getHelper().refreshEditor();
return true;
}
return super.handleMouseDrag(me);
}
protected boolean handleMouseEntered(MouseEvent me) {
if (mouseDownOnHandle || draggingHandle)
return true;
return super.handleMouseEntered(me);
}
protected boolean handleMouseUp(MouseEvent me) {
if (!widthChanged && draggingHandle) {
widthChanged = true;
}
draggingHandle = false;
mouseDownOnHandle = false;
return super.handleMouseUp(me);
}
protected Request createTextRequest(IPart source, IDocument document) {
Request request = super.createTextRequest(source, document);
if (widthChanged) {
request.setParameter(
MindMapUI.PARAM_PROPERTY_PREFIX + Core.TitleWidth,
getHelper().getPrefWidth());
}
return request;
}
protected boolean shouldIgnoreTextChange(IPart source, IDocument document,
String oldText) {
return !widthChanged
&& super.shouldIgnoreTextChange(source, document, oldText);
}
private double getScale() {
return getTargetViewer().getZoomManager().getScale();
}
private Point getScaled(Point p) {
return getTargetViewer().getZoomManager().getScaled(p);
}
public IFigure findToolTip(IPart source, Point position) {
if (!mouseDownOnHandle && !draggingHandle && (widthHandle != null
&& handleContains(widthHandle, position))) {
return new Label(MindMapMessages.ModifyWrapWidth_toolTip0);
}
return super.getToolTip(source, position);
}
public Cursor getCurrentCursor(Point pos, IPart host) {
if (mouseDownOnHandle || draggingHandle
|| (widthHandle != null && handleContains(widthHandle, pos))) {
return Cursors.SIZEWE;
}
return super.getCurrentCursor(pos, host);
}
}