/* ******************************************************************************
* 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 static org.xmind.ui.mindmap.MindMapUI.REQ_ADD_ATTACHMENT;
import static org.xmind.ui.mindmap.MindMapUI.REQ_CREATE_BOUNDARY;
import static org.xmind.ui.mindmap.MindMapUI.REQ_CREATE_RELATIONSHIP;
import static org.xmind.ui.mindmap.MindMapUI.REQ_CREATE_SUMMARY;
import static org.xmind.ui.mindmap.MindMapUI.REQ_DRILLDOWN;
import static org.xmind.ui.mindmap.MindMapUI.REQ_DRILLUP;
import static org.xmind.ui.mindmap.MindMapUI.REQ_EDIT_LABEL;
import static org.xmind.ui.mindmap.MindMapUI.REQ_MODIFY_HYPERLINK;
import static org.xmind.ui.mindmap.MindMapUI.REQ_SELECT_CENTRAL;
import static org.xmind.ui.mindmap.MindMapUI.TOOL_CREATE_BOUNDARY;
import static org.xmind.ui.mindmap.MindMapUI.TOOL_CREATE_RELATIONSHIP;
import static org.xmind.ui.mindmap.MindMapUI.TOOL_CREATE_SUMMARY;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.draw2d.FreeformFigure;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.draw2d.Viewport;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.util.SafeRunnable;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MenuEvent;
import org.eclipse.swt.events.MenuListener;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.internal.WorkbenchMessages;
import org.xmind.core.Core;
import org.xmind.core.IFileEntry;
import org.xmind.core.IImage;
import org.xmind.core.IManifest;
import org.xmind.core.ISheet;
import org.xmind.core.ITopic;
import org.xmind.core.ITopicExtension;
import org.xmind.core.ITopicExtensionElement;
import org.xmind.core.IWorkbook;
import org.xmind.core.marker.IMarker;
import org.xmind.core.marker.IMarkerGroup;
import org.xmind.core.marker.IMarkerRef;
import org.xmind.core.marker.IMarkerSheet;
import org.xmind.core.util.FileUtils;
import org.xmind.core.util.HyperlinkUtils;
import org.xmind.gef.GEF;
import org.xmind.gef.IGraphicalViewer;
import org.xmind.gef.IViewer;
import org.xmind.gef.Request;
import org.xmind.gef.draw2d.IOriginBased;
import org.xmind.gef.event.DragDropEvent;
import org.xmind.gef.event.KeyEvent;
import org.xmind.gef.event.MouseDragEvent;
import org.xmind.gef.event.MouseEvent;
import org.xmind.gef.graphicalpolicy.IStructure;
import org.xmind.gef.part.IGraphicalEditPart;
import org.xmind.gef.part.IGraphicalPart;
import org.xmind.gef.part.IPart;
import org.xmind.gef.service.IBendPointsFeedback;
import org.xmind.gef.service.IFeedback;
import org.xmind.gef.service.IRevealService;
import org.xmind.gef.service.IRevealServiceListener;
import org.xmind.gef.service.RevealEvent;
import org.xmind.gef.service.ZoomingAndPanningRevealService;
import org.xmind.gef.tool.AbstractTool;
import org.xmind.gef.tool.IDragDropHandler;
import org.xmind.gef.tool.ISourceTool;
import org.xmind.gef.tool.ITool;
import org.xmind.gef.tool.SelectTool;
import org.xmind.ui.branch.IBranchDoubleClickSupport;
import org.xmind.ui.branch.IBranchMoveSupport;
import org.xmind.ui.commands.DeleteMarkerCommand;
import org.xmind.ui.internal.MindMapUIPlugin;
import org.xmind.ui.internal.actions.ReplaceMarkerAction;
import org.xmind.ui.internal.actions.ViewerAction;
import org.xmind.ui.internal.editor.IMESupport;
import org.xmind.ui.internal.mindmap.BoundaryPart;
import org.xmind.ui.internal.mindmap.IconTipPart;
import org.xmind.ui.internal.mindmap.InfoItemIconPart;
import org.xmind.ui.internal.protocols.FilePathParser;
import org.xmind.ui.internal.protocols.FileProtocol;
import org.xmind.ui.mindmap.IBranchPart;
import org.xmind.ui.mindmap.IBranchRangePart;
import org.xmind.ui.mindmap.IDrillDownTraceService;
import org.xmind.ui.mindmap.IIconTipPart;
import org.xmind.ui.mindmap.IImagePart;
import org.xmind.ui.mindmap.IInfoItemPart;
import org.xmind.ui.mindmap.ILabelPart;
import org.xmind.ui.mindmap.ILegendItemPart;
import org.xmind.ui.mindmap.ILegendPart;
import org.xmind.ui.mindmap.IMarkerPart;
import org.xmind.ui.mindmap.IMindMap;
import org.xmind.ui.mindmap.IMindMapImages;
import org.xmind.ui.mindmap.INumberingPart;
import org.xmind.ui.mindmap.IPlusMinusPart;
import org.xmind.ui.mindmap.IRelationshipPart;
import org.xmind.ui.mindmap.ISheetPart;
import org.xmind.ui.mindmap.ITopicPart;
import org.xmind.ui.mindmap.MindMap;
import org.xmind.ui.mindmap.MindMapUI;
import org.xmind.ui.util.Logger;
import org.xmind.ui.util.MindMapUtils;
import org.xmind.ui.viewers.SWTUtils;
public class MindMapSelectTool extends SelectTool {
private static final int DRAG_DETECT_DELTA = 3;
private IBranchPart movingSourceBranch = null;
private boolean isDragDetect = false;
public MindMapSelectTool() {
setContextId(MindMapUI.CONTEXT_MINDMAP_EDIT);
}
public String getType() {
return GEF.TOOL_SELECT;
}
public boolean handleMouseDown(MouseEvent me) {
isDragDetect = false;
if (me.target instanceof IPlusMinusPart) {
if (me.target.getParent() instanceof IBranchPart) {
IBranchPart branch = (IBranchPart) me.target.getParent();
handleMouseDownOnPlusMinus(me, branch);
return true;
}
} else if (me.target instanceof IconTipPart) {
if (!me.leftOrRight) {
if (handleMouseDownOnIconTip(me)) {
return true;
}
}
}
return super.handleMouseDown(me);
}
private boolean handleMouseDownOnIconTip(MouseEvent me) {
IconTipPart iconTip = (IconTipPart) me.target;
if (iconTip.getPopupMenu() == null) {
getStatus().setStatus(GEF.ST_MOUSE_PRESSED, true);
getStatus().setStatus(GEF.ST_MOUSE_RIGHT, !me.leftOrRight);
selectSingle(iconTip.getTopicPart());
return true;
}
return false;
}
protected void handleMouseDownOnPlusMinus(MouseEvent me,
IBranchPart branch) {
getStatus().setStatus(GEF.ST_MOUSE_PRESSED, true);
getStatus().setStatus(GEF.ST_MOUSE_RIGHT, !me.leftOrRight);
ITopicPart topic = branch.getTopicPart();
if (topic != null)
selectSingle(topic);
sendFoldedRequest(branch);
me.consume();
}
protected void sendFoldedRequest(IBranchPart branch) {
String reqType = branch.getTopic().isFolded() ? GEF.REQ_EXTEND
: GEF.REQ_COLLAPSE;
Request request = new Request(reqType);
request.setViewer(getTargetViewer());
request.setPrimaryTarget(branch);
request.setParameter(MindMapUI.PARAM_WITH_ANIMATION, Boolean.TRUE);
getDomain().handleRequest(request);
}
public boolean handleMouseUp(final MouseEvent me) {
if (me.target instanceof IconTipPart) {
if (me.leftOrRight) {
handleMouseUpOnIconTip(me);
return true;
}
} else if (me.target instanceof IMarkerPart) {
if (me.leftOrRight) {
showMarkerMenu((IMarkerPart) me.target);
return true;
}
} else if (me.target instanceof InfoItemIconPart) {
if (me.leftOrRight) {
handleMouseUpOnInforItem(me);
return true;
}
}
return super.handleMouseUp(me);
}
private void handleMouseUpOnInforItem(MouseEvent me) {
getStatus().setStatus(GEF.ST_NO_DRAGGING, false);
getStatus().setStatus(GEF.ST_MOUSE_PRESSED, false);
InfoItemIconPart inforItem = (InfoItemIconPart) me.target;
selectSingle(inforItem.getTopicPart());
final IAction action = inforItem.getAction();
if (action != null) {
setToSelectOnMouseUp(null);
Display.getCurrent().asyncExec(new Runnable() {
public void run() {
SafeRunner.run(new SafeRunnable() {
public void run() throws Exception {
action.run();
}
});
}
});
}
}
protected void handleMouseUpOnIconTip(final MouseEvent me) {
getStatus().setStatus(GEF.ST_NO_DRAGGING, false);
getStatus().setStatus(GEF.ST_MOUSE_PRESSED, false);
IconTipPart iconTip = (IconTipPart) me.target;
selectSingle(iconTip.getTopicPart());
final IAction action = iconTip.getAction();
if (action != null) {
setToSelectOnMouseUp(null);
Display.getCurrent().asyncExec(new Runnable() {
public void run() {
SafeRunner.run(new SafeRunnable() {
public void run() throws Exception {
action.run();
}
});
}
});
}
}
protected boolean handleMouseDoubleClick(MouseEvent me) {
if (me.leftOrRight) {
if (me.target == null
|| me.target == getTargetViewer().getRootPart()
|| me.target instanceof ISheetPart) {
IBranchPart branch = findBranch(getTargetViewer().getRootPart(),
me.cursorLocation);
if (branch == null || !handleDoubleClickOnBranch(branch,
me.cursorLocation)) {
handleCreateFloatingTopicRequest(me.cursorLocation);
}
me.consume();
return true;
}
}
return super.handleMouseDoubleClick(me);
}
private IBranchPart findBranch(IPart part, Point pos) {
if (!part.getStatus().isActive())
return null;
if (part instanceof IBranchPart) {
IBranchPart branch = (IBranchPart) part;
if (branch.getFigure().isVisible()
&& branch.getFigure().containsPoint(pos)) {
if (branch.canSearchChild()) {
for (IBranchPart sub : branch.getSubBranches()) {
IBranchPart b = findBranch(sub, pos);
if (b != null)
return b;
}
for (IBranchPart sub : branch.getCalloutBranches()) {
IBranchPart b = findBranch(sub, pos);
if (b != null)
return b;
}
for (IBranchPart sub : branch.getSummaryBranches()) {
IBranchPart b = findBranch(sub, pos);
if (b != null)
return b;
}
}
return branch;
}
} else {
if (!(part instanceof IGraphicalPart)
|| ((IGraphicalPart) part).getFigure().isVisible()) {
for (IPart child : part.getChildren()) {
IBranchPart branch = findBranch(child, pos);
if (branch != null)
return branch;
}
}
}
return null;
}
private boolean handleDoubleClickOnBranch(IBranchPart branch, Point pos) {
do {
IStructure structure = branch.getBranchPolicy()
.getStructure(branch);
if (structure instanceof IBranchDoubleClickSupport) {
if (((IBranchDoubleClickSupport) structure)
.handleDoubleClick(branch, pos))
return true;
}
branch = branch.getParentBranch();
} while (branch != null);
return false;
}
protected boolean handleKeyDown(final KeyEvent ke) {
boolean handled = super.handleKeyDown(ke);
if (!handled) {
int keyCode = ke.keyCode;
int stateMask = ke.getState();
Request navScrollRequest = createNavScrollRequest(stateMask,
keyCode);
if (navScrollRequest != null) {
return handleNavScroll(navScrollRequest);
}
IPart p = getTargetViewer().getFocusedPart();
if (p != null && SWTUtils.matchKey(stateMask, keyCode, 0, ' ')
&& handleQuickOpen(p))
return true;
if (SWTUtils.matchKey(stateMask, keyCode, 0, SWT.ESC)
&& hideQuickOpen())
return true;
if (p != null && p.hasRole(GEF.ROLE_EDITABLE)) {
if (MindMapUtils.isTopicTextChar(ke.character)) {
int ignoreCount = getTargetViewer().getProperties()
.getInteger(IMESupport.PROP_IGNORE_KEY_DOWN, 0);
if (ignoreCount > 0) {
getTargetViewer().getProperties().set(
IMESupport.PROP_IGNORE_KEY_DOWN,
ignoreCount - 1);
} else {
Request req = new Request(GEF.REQ_EDIT);
req.setDomain(getDomain());
req.setViewer(getTargetViewer());
fillTargets(req, getTargetViewer(), false);
if (req.hasTargets()) {
startEditing(p, req);
if (ke.character != ' ') {
final ITool activeTool = getDomain()
.getActiveTool();
if (activeTool != this) {
// Display.getCurrent().asyncExec(
// new Runnable() {
// public void run() {
activeTool.keyDown(ke, getTargetViewer());
// }
// });
}
}
return true;
}
}
}
}
}
return handled;
}
protected boolean hideQuickOpen() {
if (QuickOpenHelper.getInstance().isOpen()) {
QuickOpenHelper.getInstance().hide();
return true;
}
return false;
}
protected boolean handleQuickOpen(IPart part) {
if (QuickOpenHelper.getInstance().canShow()) {
if (QuickOpenHelper.getInstance().isOpen()) {
QuickOpenHelper.getInstance().hide();
return true;
} else {
String filepath = getQuickOpenFilePaths(part);
if (filepath != null) {
QuickOpenHelper.getInstance().show(filepath);
return true;
}
}
}
return false;
}
/**
* @param p
* @return
*/
private String getQuickOpenFilePaths(IPart p) {
if (p instanceof ITopicPart) {
ITopic topic = ((ITopicPart) p).getTopic();
String uri = topic.getHyperlink();
if (uri != null) {
String path = uriToFilePath(topic, uri);
if (path != null)
return path;
}
} else if (p instanceof IImagePart) {
ITopic topic = ((IImagePart) p).getTopic();
String imagePath = getImagePath(topic);
if (imagePath != null)
return imagePath;
}
return null;
}
protected String uriToFilePath(ITopic topic, String uri) {
if (HyperlinkUtils.isInternalURL(uri))
return null;
if (HyperlinkUtils.isAttachmentURL(uri))
return getAttachmentAbsolutePath(topic, uri);
String path = FilePathParser.toPath(uri);
if (path == null)
return null;
return FileProtocol.getAbsolutePath(topic, path);
}
/**
* @param topic
* @return
*/
private String getImagePath(ITopic topic) {
IImage image = topic.getImage();
if (image == null)
return null;
String uri = image.getSource();
if (uri == null)
return null;
return uriToFilePath(topic, uri);
}
protected String getAttachmentAbsolutePath(ITopic topic, String uri) {
String path = HyperlinkUtils.toAttachmentPath(uri);
if (path == null)
return null;
IWorkbook workbook = topic.getOwnedWorkbook();
if (workbook == null)
return null;
String hiberLoc = Core.getWorkspace()
.getAbsolutePath(".temp-attachments"); //$NON-NLS-1$
if (hiberLoc == null)
return null;
File hiberDir = new File(hiberLoc);
if (!hiberDir.isDirectory())
return null;
IManifest manifest = workbook.getManifest();
IFileEntry fileEntry = manifest.getFileEntry(path);
try {
InputStream is = fileEntry.openInputStream();
OutputStream os = new FileOutputStream(hiberLoc);
FileUtils.transfer(is, os);
} catch (IOException e) {
Logger.log(e,
"Failed to transfer attachment to temp-attachments dir."); //$NON-NLS-1$
return null;
}
File attFile = new File(hiberDir, path);
if (!attFile.exists())
return null;
return attFile.getAbsolutePath();
}
protected boolean handleMouseDrag(MouseDragEvent me) {
if (!isDragDetect) {
isDragDetect = shouldDragDetect(me);
}
if (!isDragDetect) {
return false;
}
movingSourceBranch = null;
return super.handleMouseDrag(me);
}
private boolean shouldDragDetect(MouseDragEvent me) {
if (me == null) {
return false;
}
int delta = Math.abs(me.cursorLocation.x - me.startingLocation.x)
+ Math.abs(me.cursorLocation.y - me.startingLocation.y);
return delta >= DRAG_DETECT_DELTA;
}
protected boolean canMove(IPart host, MouseDragEvent me) {
boolean canMove = super.canMove(host, me);
if (!canMove) {
IBranchPart branch = findBranch(host, me.startingLocation);
if (branch != null) {
return canMoveInBranch(branch, me);
}
}
return canMove;
}
private boolean canMoveInBranch(IBranchPart branch, MouseDragEvent me) {
do {
IStructure structure = branch.getBranchPolicy()
.getStructure(branch);
if (structure instanceof IBranchMoveSupport) {
boolean canMove = ((IBranchMoveSupport) structure)
.canMove(branch, me);
if (canMove) {
movingSourceBranch = branch;
}
return canMove;
}
branch = branch.getParentBranch();
} while (branch != null);
return false;
}
protected String getMoveTool(IPart source, MouseDragEvent me) {
if (movingSourceBranch != null) {
return ((IBranchMoveSupport) movingSourceBranch.getBranchPolicy()
.getStructure(movingSourceBranch))
.getMoveTool(movingSourceBranch, me);
}
if (source instanceof ITopicPart) {
return MindMapUI.TOOL_MOVE_TOPIC;
} else if (source instanceof IRelationshipPart) {
return MindMapUI.TOOL_MOVE_RELATIONSHIP;
} else if (source instanceof IBranchRangePart) {
return MindMapUI.TOOL_RESIZE_RANGE;
} else if (source instanceof IMarkerPart) {
return MindMapUI.TOOL_MOVE_MARKER;
} else if (source instanceof IImagePart) {
IImagePart imagePart = (IImagePart) source;
Object feedback = imagePart.getAdapter(IFeedback.class);
if (feedback instanceof IBendPointsFeedback) {
int orientation = ((IBendPointsFeedback) feedback)
.getOrientation(me.startingLocation);
if (orientation == PositionConstants.NONE) {
return MindMapUI.TOOL_MOVE_IMAGE;
}
}
return MindMapUI.TOOL_RESIZE_IMAGE;
} else if (source instanceof ILegendPart
|| source instanceof ILegendItemPart) {
return MindMapUI.TOOL_MOVE_LEGEND;
}
return super.getMoveTool(source, me);
}
protected void changeToMoveTool(String moveToolType, ITool moveTool,
IPart dragSource, MouseDragEvent me) {
if (GEF.TOOL_MOVE.equals(moveToolType)) {
if (!canMove(dragSource, me))
return;
if (!dragSource.getStatus().isSelected())
selectSingle(dragSource);
getTargetViewer().setFocused(dragSource);
}
if (movingSourceBranch != null) {
super.changeToMoveTool(moveToolType, moveTool, movingSourceBranch,
me);
} else {
super.changeToMoveTool(moveToolType, moveTool, dragSource, me);
}
movingSourceBranch = null;
}
// protected IPart findSequenceEnd(IPart current, int direction) {
// return MindMapUtils.findNaviPart(current, direction);
// }
protected List<IPart> getSequenceParts(IPart start, IPart end) {
return MindMapUtils.getSequenceTopics(start, end);
}
protected Request fillTargets(Request request, IViewer viewer,
boolean includeRootPartIfEmpty) {
return super.fillTargets(request, viewer, includeRootPartIfEmpty)
.setParameter(MindMapUI.PARAM_WITH_ANIMATION, Boolean.TRUE);
}
protected void handleNonTargetedRequest(Request request) {
IViewer viewer = request.getTargetViewer();
if (viewer != null) {
String requestType = request.getType();
if (MindMapUI.REQ_CREATE_FLOAT.equals(requestType)) {
handleCreateFloatingTopic(request, viewer);
return;
} else if (MindMapUI.REQ_SELECT_BROTHERS.equals(requestType)) {
handleSelectBrothers(request);
return;
} else if (MindMapUI.REQ_SELECT_CHILDREN.equals(requestType)) {
handleSelectChildren(request);
return;
} else if (MindMapUI.REQ_SELECT_CENTRAL.equals(requestType)) {
handleSelectCentral(request);
return;
} else if (GEF.REQ_EXTEND_ALL.equals(requestType)//
|| GEF.REQ_COLLAPSE_ALL.equals(requestType)) {
request = createExtendOrCollapseAllRequest(request, viewer);
} else if (REQ_SELECT_CENTRAL.equals(requestType)) {
handleSelectCentral(viewer);
return;
} else if (REQ_MODIFY_HYPERLINK.equals(requestType)) {
request = createModifyHyperlinkRequest(request, viewer);
} else if (REQ_ADD_ATTACHMENT.equals(requestType)) {
request = createAddAttachmentRequest(request, viewer);
} else if (REQ_CREATE_RELATIONSHIP.equals(requestType)) {
handleCreateRelationship(requestType, viewer);
return;
} else if (REQ_CREATE_BOUNDARY.equals(requestType)) {
request = createCreateBoundaryRequest(request, viewer);
} else if (REQ_CREATE_SUMMARY.equals(requestType)) {
request = createCreateSummaryRequest(request, viewer);
} else if (REQ_EDIT_LABEL.equals(requestType)) {
handleEditLabelRequest(request, viewer);
return;
} else if (REQ_DRILLDOWN.equals(requestType)) {
handleDrillDown(viewer);
return;
} else if (REQ_DRILLUP.equals(requestType)) {
handleDrillUp(viewer);
return;
} else if (GEF.REQ_TRAVERSE.equals(requestType)) {
handleTraverse(viewer);
return;
}
if (request == null)
return;
if (request.hasTargets()) {
handleTargetedRequest(request);
return;
}
}
super.handleNonTargetedRequest(request);
}
/**
* @param request
* @param viewer
*/
private void handleCreateFloatingTopic(Request request, IViewer viewer) {
changeActiveTool(MindMapUI.TOOL_CREATE_FLOAT);
getDomain().handleRequest(request);
}
private void handleSelectCentral(Request request) {
IViewer viewer = request.getTargetViewer();
if (viewer == null)
return;
ITopicPart centralTopic = (ITopicPart) viewer
.getAdapter(ITopicPart.class);
if (centralTopic == null)
return;
select(Arrays.asList(centralTopic), centralTopic);
new CenteredRevealHelper(viewer).start(centralTopic);
}
private class CenteredRevealHelper implements IRevealServiceListener {
private ZoomingAndPanningRevealService service;
private boolean oldCentered;
/**
*
*/
public CenteredRevealHelper(IViewer viewer) {
Object service = viewer.getService(IRevealService.class);
if (service != null
&& service instanceof ZoomingAndPanningRevealService) {
this.service = (ZoomingAndPanningRevealService) service;
this.oldCentered = this.service.isCentered();
} else {
this.service = null;
this.oldCentered = false;
}
}
public void start(IGraphicalPart part) {
if (this.service != null) {
this.service.setCentered(true);
this.service.reveal(new StructuredSelection(part));
this.service.addRevealServiceListener(this);
}
}
/*
* (non-Javadoc)
* @see
* org.xmind.gef.service.IRevealServiceListener#revealingStarted(org
* .xmind.gef.service.RevealEvent)
*/
public void revealingStarted(RevealEvent event) {
}
/*
* (non-Javadoc)
* @see
* org.xmind.gef.service.IRevealServiceListener#revealingCanceled(org
* .xmind.gef.service.RevealEvent)
*/
public void revealingCanceled(RevealEvent event) {
restore();
}
/*
* (non-Javadoc)
* @see
* org.xmind.gef.service.IRevealServiceListener#revealingFinished(org
* .xmind.gef.service.RevealEvent)
*/
public void revealingFinished(RevealEvent event) {
restore();
}
void restore() {
this.service.removeRevealServiceListener(this);
this.service.setCentered(this.oldCentered);
}
}
private void handleSelectBrothers(Request request) {
List<IPart> parts = getSelectedParts(request.getTargetViewer());
List<ITopicPart> toSelect = new ArrayList<ITopicPart>();
for (IPart p : parts) {
IBranchPart branch = MindMapUtils.findBranch(p);
if (branch != null) {
collectBrothers(branch, toSelect);
}
}
if (!toSelect.isEmpty()) {
select(toSelect, toSelect.get(0));
}
}
private void collectBrothers(IBranchPart branch,
List<ITopicPart> toSelect) {
IBranchPart parent = branch.getParentBranch();
if (parent != null) {
for (IBranchPart child : parent.getSubBranches()) {
toSelect.add(child.getTopicPart());
}
for (IBranchPart child : parent.getCalloutBranches()) {
toSelect.add(child.getTopicPart());
}
}
}
private void handleSelectChildren(Request request) {
List<IPart> parts = getSelectedParts(request.getTargetViewer());
List<ITopicPart> toSelect = new ArrayList<ITopicPart>();
for (IPart p : parts) {
IBranchPart branch = MindMapUtils.findBranch(p);
if (branch != null) {
collectChildren(branch, toSelect);
}
}
if (!toSelect.isEmpty()) {
select(toSelect, toSelect.get(0));
}
}
private void collectChildren(IBranchPart branch,
List<ITopicPart> toSelect) {
for (IBranchPart child : branch.getSubBranches()) {
toSelect.add(child.getTopicPart());
}
for (IBranchPart child : branch.getCalloutBranches()) {
toSelect.add(child.getTopicPart());
}
}
private void handleTraverse(IViewer viewer) {
IPart focusedPart = viewer.getFocusedPart();
if (focusedPart != null && focusedPart instanceof IGraphicalEditPart
&& focusedPart.getStatus().isActive()
&& focusedPart.hasRole(GEF.ROLE_TRAVERSABLE)) {
IGraphicalEditPart source = (IGraphicalEditPart) focusedPart;
ITool tool = getTool(GEF.TOOL_TRAVERSE);
if (tool != null) {
if (tool instanceof ISourceTool) {
((ISourceTool) tool).setSource(source);
}
changeActiveTool(GEF.TOOL_TRAVERSE);
}
}
}
protected void handleTargetedRequest(Request request) {
String requestType = request.getType();
if (MindMapUI.REQ_EDIT_LABEL.equals(requestType)) {
handleEditRequest(request);
return;
}
if (REQ_DRILLDOWN.equals(requestType)) {
handleDrillDown(request.getTargetViewer(), request.getTargets());
return;
} else if (MindMapUI.REQ_SHOW_LEGEND.equals(requestType)) {
if (request.getPrimaryTarget() instanceof ISheetPart) {
ISheetPart sheet = (ISheetPart) request.getPrimaryTarget();
if (!sheet.getSheet().getLegend().hasPosition()) {
createLegend(request);
return;
}
}
}
super.handleTargetedRequest(request);
}
protected void navigateTo(List<IPart> toSelect, IPart toFocus,
boolean sequential) {
List<IBranchPart> branchesToExpand = findBranchesNeedsExpand(toSelect);
if (branchesToExpand != null && !branchesToExpand.isEmpty()) {
expand(branchesToExpand);
}
if (!canNavigateTo(toSelect))
return;
super.navigateTo(toSelect, toFocus, sequential);
}
protected boolean canNavigateTo(List<IPart> toSelect) {
for (IPart p : toSelect) {
if (p instanceof IGraphicalPart) {
IFigure figure = ((IGraphicalPart) p).getFigure();
if (!figure.isVisible())
return false;
}
}
return true;
}
protected List<IBranchPart> findBranchesNeedsExpand(List<IPart> parts) {
List<IBranchPart> branches = null;
for (IPart p : parts) {
IBranchPart branch = MindMapUtils.findBranch(p);
if (branch != null) {
IBranchPart toExpand = findBranchNeedsExpand(branch);
if (toExpand != null) {
if (branches == null)
branches = new ArrayList<IBranchPart>();
branches.add(toExpand);
}
}
}
return branches;
}
private IBranchPart findBranchNeedsExpand(IBranchPart branch) {
IBranchPart parent = branch.getParentBranch();
if (parent != null) {
if (parent.isFolded())
return parent;
return findBranchNeedsExpand(parent);
}
return null;
}
protected void expand(List<IBranchPart> branches) {
getDomain().handleRequest(new Request(GEF.REQ_EXTEND)
.setViewer(getTargetViewer()).setTargets(branches));
}
protected Request createAddAttachmentRequest(Request request,
IViewer viewer) {
List<ITopicPart> topics = MindMapUtils
.getTopicParts(getSelectedParts(viewer));
if (topics.isEmpty())
return request;
FileDialog dialog = new FileDialog(viewer.getControl().getShell(),
SWT.OPEN | SWT.MULTI);
String ret = dialog.open();
if (ret == null)
return request;
String parentPath = dialog.getFilterPath();
String[] fileNames = dialog.getFileNames();
List<String> paths = new ArrayList<String>(fileNames.length);
for (String fileName : fileNames) {
if (fileName.contains(".")) { //$NON-NLS-1$
MindMapUIPlugin.getDefault().getUsageDataCollector()
.increase(String.format("AttachmentFormatCount:%s", //$NON-NLS-1$
fileName.toLowerCase().substring(
fileName.lastIndexOf('.') + 1)));
} else {
MindMapUIPlugin.getDefault().getUsageDataCollector()
.increase("AttachmentFormatCount:BlankFormat"); //$NON-NLS-1$
}
String path = new File(parentPath, fileName).getAbsolutePath();
paths.add(path);
}
request.setTargets(topics);
request.setParameter(GEF.PARAM_PATH, paths.toArray(new String[0]));
return request;
}
protected Request createModifyHyperlinkRequest(Request request,
IViewer viewer) {
List<ITopicPart> topics = MindMapUtils
.getTopicParts(getSelectedParts(viewer));
if (topics.isEmpty())
return null;
if (request.hasParameter(GEF.PARAM_TEXT))
return request.setTargets(topics);
// Shell parentShell = viewer.getControl().getShell();
// HyperlinkDialog dialog = new HyperlinkDialog(parentShell,
// new StructuredSelection(topics));
// int retCode = dialog.open();
//
// if (retCode == HyperlinkDialog.OK) {
// return request.setTargets(topics).setParameter(GEF.PARAM_TEXT,
// dialog.getValue());
// } else if (retCode == HyperlinkDialog.REMOVE) {
// return request.setTargets(topics)
// .setParameter(GEF.PARAM_TEXT, null);
// }
return null;
}
protected void handleSelectCentral(IViewer viewer) {
ITopic centralTopic = (ITopic) viewer.getAdapter(ITopic.class);
if (centralTopic != null) {
viewer.setSelection(new StructuredSelection(centralTopic));
}
}
protected Request createExtendOrCollapseAllRequest(Request request,
IViewer viewer) {
List<IPart> selectedParts = getSelectedParts(viewer);
if (isSheetSelected(selectedParts, viewer)) {
ISheetPart sheet = (ISheetPart) viewer.getAdapter(ISheetPart.class);
if (sheet == null)
return request;
IBranchPart centralBranch = sheet.getCentralBranch();
if (centralBranch == null)
return request;
selectedParts = new ArrayList<IPart>();
selectedParts.add(centralBranch);
selectedParts.addAll(sheet.getFloatingBranches());
}
request.setParameter(MindMapUI.PARAM_WITH_ANIMATION, Boolean.TRUE);
request.setTargets(selectedParts);
return request;
}
protected boolean isSheetSelected(List<IPart> parts, IViewer viewer) {
if (parts.isEmpty())
return true;
for (IPart p : parts) {
if (p instanceof ISheetPart || p == viewer.getRootPart())
return true;
}
return false;
}
protected void handleCreateFloatingTopicRequest(Point location) {
if (location == null)
return;
ISheetPart sheet = (ISheetPart) getTargetViewer()
.getAdapter(ISheetPart.class);
if (sheet == null)
return;
Point position = new Point();
IFigure figure = sheet.getFigure();
if (figure instanceof IOriginBased) {
Point origin = ((IOriginBased) figure).getOrigin();
position.setLocation(location.x - origin.x, location.y - origin.y);
}
Request request = new Request(MindMapUI.REQ_CREATE_FLOAT);
request.setDomain(getDomain());
request.setViewer(getTargetViewer());
request.setPrimaryTarget(sheet);
request.setParameter(GEF.PARAM_POSITION, position);
request.setParameter(MindMapUI.PARAM_WITH_ANIMATION, Boolean.TRUE);
getDomain().handleRequest(request);
}
protected boolean isSelectableOnSelectAll(IPart child) {
if (!(child instanceof ITopicPart))
return false;
return super.isSelectableOnSelectAll(child);
}
protected void handleCreateRelationship(String reqType, IViewer viewer) {
ITool next = getTool(TOOL_CREATE_RELATIONSHIP);
if (next instanceof AbstractTool) {
((AbstractTool) next).setTargetViewer(viewer);
}
changeActiveTool(TOOL_CREATE_RELATIONSHIP);
}
protected Request createCreateBoundaryRequest(Request request,
IViewer viewer) {
List<IPart> selectedParts = getSelectedParts(viewer);
List<ITopic> topics = MindMapUtils.getTopics(selectedParts);
if (!topics.isEmpty()) {
List<IPart> parts = MindMapUtils.getParts(topics, viewer);
request.setTargets(parts);
request.setParameter(MindMapUI.PARAM_WITH_ANIMATION, Boolean.TRUE);
return request;
}
ITool next = getTool(TOOL_CREATE_BOUNDARY);
if (next instanceof AbstractTool) {
((AbstractTool) next).setTargetViewer(viewer);
}
changeActiveTool(TOOL_CREATE_BOUNDARY);
return null;
}
private Request createCreateSummaryRequest(Request request,
IViewer viewer) {
List<IPart> selectedParts = getSelectedParts(getTargetViewer());
List<ITopic> topics = MindMapUtils.getTopics(selectedParts);
if (!topics.isEmpty()) {
List<IPart> parts = MindMapUtils.getParts(topics,
getTargetViewer());
request.setTargets(parts);
request.setParameter(MindMapUI.PARAM_WITH_ANIMATION, Boolean.TRUE);
return request;
}
ITool next = getTool(TOOL_CREATE_SUMMARY);
if (next instanceof AbstractTool) {
((AbstractTool) next).setTargetViewer(viewer);
}
changeActiveTool(TOOL_CREATE_SUMMARY);
return null;
}
protected void handleDrillDown(IViewer viewer) {
ISheet sheet = (ISheet) viewer.getAdapter(ISheet.class);
if (sheet == null)
return;
ISelection selection = viewer.getSelection();
if (selection instanceof IStructuredSelection) {
Object obj = ((IStructuredSelection) selection).getFirstElement();
if (obj instanceof ITopic) {
ITopic rootTopic = (ITopic) obj;
drillDown(viewer, sheet, rootTopic);
}
}
}
private void handleDrillDown(IViewer viewer, List<IPart> sources) {
if (sources.isEmpty())
return;
ISheet sheet = (ISheet) viewer.getAdapter(ISheet.class);
if (sheet == null)
return;
IPart p = sources.get(0);
Object m = MindMapUtils.getRealModel(p);
if (m instanceof ITopic) {
drillDown(viewer, sheet, (ITopic) m);
if (viewer.getEditDomain() != null) {
viewer.getEditDomain()
.handleRequest(MindMapUI.REQ_SELECT_CENTRAL, viewer);
}
}
}
private void drillDown(IViewer viewer, ISheet sheet, ITopic newRoot) {
IMindMap newInput = new MindMap(sheet, newRoot);
initTopicRightNumber(newRoot);
viewer.setInput(newInput);
}
private void initTopicRightNumber(ITopic newRoot) {
if (newRoot == null)
return;
String structureClass = newRoot.getStructureClass();
if ("org.xmind.ui.map.unbalanced".equals(structureClass) //$NON-NLS-1$
|| structureClass == null) {
ITopicExtension extension = newRoot
.createExtension("org.xmind.ui.map.unbalanced"); //$NON-NLS-1$
ITopicExtensionElement element = extension.getContent()
.getCreatedChild("right-number"); //$NON-NLS-1$
String rightNum = element.getTextContent();
if (rightNum == null) {
int size = newRoot.getChildren(ITopic.ATTACHED).size();
if (size > 3)
size = size / 2;
element.setTextContent(String.valueOf(size));
}
}
}
protected void handleDrillUp(IViewer viewer) {
ISheet sheet = (ISheet) viewer.getAdapter(ISheet.class);
if (sheet != null) {
IDrillDownTraceService traceService = (IDrillDownTraceService) viewer
.getService(IDrillDownTraceService.class);
if (traceService != null) {
ITopic newRoot = traceService.getPreviousCentralTopic();
drillDown(viewer, sheet, newRoot);
}
}
}
private void createLegend(Request request) {
changeActiveTool(MindMapUI.TOOL_CREATE_LEGEND);
}
protected void handleEditLabelRequest(Request request, IViewer viewer) {
request = fillTargets(request, viewer, false);
List<IPart> targets = new ArrayList<IPart>(request.getTargets());
for (int i = 0; i < targets.size(); i++) {
IPart p = targets.get(i);
if (p instanceof IIconTipPart) {
targets.set(i, ((IIconTipPart) p).getTopicPart());
} else if (p instanceof IMarkerPart) {
targets.set(i, ((IMarkerPart) p).getTopicPart());
} else if (p instanceof IImagePart) {
targets.set(i, ((IImagePart) p).getTopicPart());
} else if (p instanceof INumberingPart) {
targets.set(i, ((INumberingPart) p).getTopicPart());
} else if (p instanceof IInfoItemPart) {
targets.set(i, ((IInfoItemPart) p).getTopicPart());
}
}
request.setTargets(targets);
handleEditRequest(request);
}
protected String getEditTool(IPart source, Request request) {
String requestType = request == null ? null : request.getType();
if (source instanceof ITopicPart) {
if (MindMapUI.REQ_EDIT_LABEL.equals(requestType)) {
return MindMapUI.TOOL_EDIT_LABEL;
} else {
return MindMapUI.TOOL_EDIT_TOPIC_TITLE;
}
} else if (source instanceof ILegendItemPart) {
return MindMapUI.TOOL_EDIT_LEGEND_ITEM;
}
return super.getEditTool(source, request);
}
protected Request createEditRequestOnDoubleClick(IPart source,
MouseEvent me) {
if (source instanceof ILabelPart) {
ILabelPart label = (ILabelPart) source;
IBranchPart branch = label.getOwnedBranch();
if (branch != null) {
ITopicPart topic = branch.getTopicPart();
if (topic != null) {
return new Request(MindMapUI.REQ_EDIT_LABEL)
.setPrimaryTarget(topic).setDomain(getDomain())
.setViewer(getTargetViewer());
}
}
} else if (source instanceof ILegendItemPart) {
ILegendItemPart item = (ILegendItemPart) source;
return new Request(MindMapUI.REQ_EDIT_LEGEND_ITEM)
.setPrimaryTarget(item).setDomain(getDomain())
.setViewer(getTargetViewer());
}
return super.createEditRequestOnDoubleClick(source, me);
}
protected boolean handleDragStarted(DragDropEvent de) {
ITool dndTool = getTool(GEF.TOOL_DND);
if (dndTool != null) {
changeActiveTool(GEF.TOOL_DND);
if (getDomain().getActiveTool() == dndTool
&& dndTool instanceof IDragDropHandler) {
((IDragDropHandler) dndTool).dragStarted(de, getTargetViewer());
}
return true;
}
return super.handleDragStarted(de);
}
protected void showMarkerMenu(IMarkerPart target) {
if (getTargetViewer() == null
|| getTargetViewer().getEditDomain() == null
|| getTargetViewer().getEditDomain().getCommandStack() == null
|| "PresentationViewer" //$NON-NLS-1$
.equals(getTargetViewer().getClass().getSimpleName()))
return;
MenuManager menuManager = new MenuManager();
fillMarkerGroup(menuManager, target.getMarkerRef(), getTargetViewer());
final Menu menu = menuManager
.createContextMenu(getTargetViewer().getControl());
Point p = getTargetViewer().computeToDisplay(
target.getFigure().getBounds().getBottomLeft(), true);
menu.setLocation(p.x, p.y);
menu.addMenuListener(new MenuListener() {
public void menuShown(MenuEvent e) {
}
public void menuHidden(MenuEvent e) {
e.display.asyncExec(new Runnable() {
public void run() {
menu.dispose();
}
});
}
});
menu.getDisplay().asyncExec(new Runnable() {
public void run() {
menu.setVisible(true);
}
});
}
/**
* @param menuManager
* @param markerRef
* @param targetViewer
*/
private static void fillMarkerGroup(MenuManager menuManager,
final IMarkerRef markerRef, IGraphicalViewer targetViewer) {
final Set<String> addedMarkerIds = new HashSet<String>();
fillMarkerGroup(menuManager, markerRef, targetViewer,
markerRef.getOwnedWorkbook().getMarkerSheet(), addedMarkerIds);
fillMarkerGroup(menuManager, markerRef, targetViewer,
MindMapUI.getResourceManager().getUserMarkerSheet(),
addedMarkerIds);
menuManager.add(new Separator());
ViewerAction deleteAction = new ViewerAction(targetViewer) {
@Override
public void run() {
executeCommand(new DeleteMarkerCommand(markerRef));
}
};
deleteAction.setText(WorkbenchMessages.Workbench_delete);
deleteAction.setToolTipText(WorkbenchMessages.Workbench_deleteToolTip);
deleteAction.setImageDescriptor(
MindMapUI.getImages().get(IMindMapImages.DELETE, true));
deleteAction.setDisabledImageDescriptor(
MindMapUI.getImages().get(IMindMapImages.DELETE, false));
menuManager.add(deleteAction);
}
private static void fillMarkerGroup(MenuManager menuManager,
IMarkerRef sourceMarkerRef, IGraphicalViewer targetViewer,
IMarkerSheet markerSheet, Set<String> addedMarkerIds) {
IMarker sourceMarker = markerSheet
.findMarker(sourceMarkerRef.getMarkerId());
if (sourceMarker == null)
return;
IMarkerGroup group = sourceMarker.getParent();
if (group == null)
return;
List<IMarker> visibleMarkers = new ArrayList<IMarker>();
for (IMarker marker : group.getMarkers())
if (!marker.isHidden())
visibleMarkers.add(marker);
for (IMarker targetMarker : visibleMarkers) {
if (addedMarkerIds.contains(targetMarker.getId()))
continue;
menuManager.add(new ReplaceMarkerAction(targetViewer,
sourceMarkerRef, targetMarker));
addedMarkerIds.add(targetMarker.getId());
}
}
protected Request createNavScrollRequest(int state, int key) {
if (state != (SWT.MOD1 | SWT.MOD3))
return null;
Request request;
if (key == SWT.ARROW_UP) {
request = new Request(GEF.REQ_NAV_UP);
} else if (key == SWT.ARROW_DOWN) {
request = new Request(GEF.REQ_NAV_DOWN);
} else if (key == SWT.ARROW_LEFT) {
request = new Request(GEF.REQ_NAV_LEFT);
} else if (key == SWT.ARROW_RIGHT) {
request = new Request(GEF.REQ_NAV_RIGHT);
} else {
return null;
}
request.setViewer(getTargetViewer());
request.setDomain(getDomain());
return request;
}
@Override
protected boolean handleNavRequest(Request request, boolean sequential) {
IViewer viewer = request.getTargetViewer();
ISelection oldSelection = viewer == null ? null : viewer.getSelection();
boolean handled = super.handleNavRequest(request, sequential);
ISelection newSelection = viewer == null ? null : viewer.getSelection();
if (!sequential
&& (!handled || isSelectionEqual(oldSelection, newSelection))) {
return handleNavScroll(request);
}
return handled;
}
@SuppressWarnings("unchecked")
private boolean isSelectionEqual(ISelection oldSelection,
ISelection newSelection) {
if (oldSelection instanceof IStructuredSelection
&& newSelection instanceof IStructuredSelection) {
Set<Object> oldElements = new HashSet<Object>(
((IStructuredSelection) oldSelection).toList());
Set<Object> newElements = new HashSet<Object>(
((IStructuredSelection) newSelection).toList());
return oldElements.equals(newElements);
}
return oldSelection == newSelection
|| (oldSelection != null && oldSelection.equals(newSelection));
}
private boolean handleNavScroll(Request request) {
String type = request.getType();
IViewer viewer = request.getTargetViewer();
if (viewer == null)
return false;
Viewport viewport = (Viewport) viewer.getAdapter(Viewport.class);
if (viewport == null)
return false;
IFigure contents = viewport.getContents();
Rectangle contentsBounds = contents instanceof FreeformFigure
? ((FreeformFigure) contents).getFreeformExtent()
: contents.getBounds();
contentsBounds = contentsBounds.getExpanded(60, 60)
.intersect(contents.getBounds());
Rectangle clientArea = viewport.getClientArea();
Point center = ((IGraphicalViewer) viewer).getCenterPoint().getCopy();
int d = 0;
if (GEF.REQ_NAV_LEFT.equals(type)) {
d = Math.min(MindMapUI.NAV_SCROLL_STEP,
Math.abs(contentsBounds.x - clientArea.x));
center.translate(-d, 0);
} else if (GEF.REQ_NAV_UP.equals(type)) {
d = Math.min(MindMapUI.NAV_SCROLL_STEP,
Math.abs(contentsBounds.y - clientArea.y));
center.translate(0, -d);
} else if (GEF.REQ_NAV_RIGHT.equals(type)) {
d = Math.min(MindMapUI.NAV_SCROLL_STEP,
Math.abs(contentsBounds.right() - clientArea.right()));
center.translate(-d, 0);
} else if (GEF.REQ_NAV_DOWN.equals(type)) {
d = Math.min(MindMapUI.NAV_SCROLL_STEP,
Math.abs(contentsBounds.bottom() - clientArea.bottom()));
center.translate(0, -d);
} else {
return false;
}
if (d == 0)
return false;
((IGraphicalViewer) viewer).center(center);
return true;
}
@Override
protected void handleEditRequest(Request request) {
IPart source = request.getPrimaryTarget();
if (source instanceof BoundaryPart) {
BoundaryPart boundary = (BoundaryPart) source;
if (boundary.isPolygonShape(boundary.getFigure())) {
return;
}
}
super.handleEditRequest(request);
}
}