/* ****************************************************************************** * 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.tool; import org.eclipse.core.runtime.Assert; import org.eclipse.jface.viewers.StructuredSelection; import org.xmind.gef.GEF; import org.xmind.gef.Request; import org.xmind.gef.part.IGraphicalEditPart; import org.xmind.gef.part.IPart; import org.xmind.gef.status.IStatusListener; import org.xmind.gef.status.StatusEvent; public class TraverseTool extends GraphicalTool implements ISourceTool, IStatusListener { private IGraphicalEditPart source; private IPart lastSource = null; private IPart lastTarget = null; private IPart[] traversables = null; private int currentIndex = -1; private boolean smartMode = false; private boolean oldSourceSelected = false; private boolean oldSourceFocused = false; private boolean oldSourcePreselected = false; public String getType() { return GEF.TOOL_TRAVERSE; } protected void onActivated(ITool prevTool) { super.onActivated(prevTool); Assert.isTrue(getSource() != null); getTargetViewer().setSelection(new StructuredSelection(getSource()), true); start(); } protected void start() { Request request = new Request(GEF.REQ_GET_TRAVERSABLES); request.setPrimaryTarget(getSource()); request.setDomain(getDomain()); request.setViewer(getTargetViewer()); getSource().handleRequest(request, GEF.ROLE_TRAVERSABLE); Object result = request.getResult(GEF.RESULT_TRAVERSE); if (result != null && result instanceof IPart[] && ((IPart[]) result).length > 0) { traversables = (IPart[]) result; if (traversables.length == 0) { cancel(); } else if (traversables.length == 1) { traverseTo(traversables[0]); } else { if (getStatus().isStatus(GEF.ST_MODIFIER_MASK)) { getStatus().addStatusListener(this); smartMode = true; } else { smartMode = false; } showFeedback(); } } else { finish(); } } protected void handleSingleRequest(Request request) { String reqType = request.getType(); if (GEF.REQ_TRAVERSE.equals(reqType)) { assistTraverseNext(); } else if (GEF.REQ_FINISH.equals(reqType)) { if (traversables != null && currentIndex >= 0) { traverseTo(traversables[currentIndex]); } else { cancel(); } } else if (GEF.REQ_CANCEL.equals(reqType)) { cancel(); } else { if (traversables != null && currentIndex >= 0) { traverseTo(traversables[currentIndex]); } else { cancel(); } getDomain().handleRequest(request); } } private void showFeedback() { showSourceFeedback(getSource()); for (IPart p : traversables) { showAssistFeedback(p); } int lastIndex = findLastSource(); lastSource = null; lastTarget = null; if (lastIndex >= 0) { currentIndex = lastIndex; } else { currentIndex = 0; } showTargetFeedback(traversables[currentIndex]); } private int findLastSource() { if (getSource() == lastTarget && lastSource != null) { for (int i = 0; i < traversables.length; i++) { if (traversables[i] == lastSource) return i; } } return -1; } protected void showSourceFeedback(IGraphicalEditPart source) { oldSourceSelected = source.getStatus().isSelected(); oldSourceFocused = source.getStatus().isFocused(); oldSourcePreselected = source.getStatus().isPreSelected(); source.getStatus().deSelect(); source.getStatus().dePreSelect(); source.getStatus().lostFocus(); } protected void hideSourceFeedback(IGraphicalEditPart source) { if (oldSourceSelected) source.getStatus().select(); else source.getStatus().deSelect(); if (oldSourceFocused) source.getStatus().setFocus(); else source.getStatus().lostFocus(); if (oldSourcePreselected) source.getStatus().preSelect(); else source.getStatus().dePreSelect(); } protected void showAssistFeedback(IPart part) { part.getStatus().preSelect(); } protected void hideAssistFeedback(IPart part) { part.getStatus().dePreSelect(); } protected void showTargetFeedback(IPart part) { part.getStatus().select(); } protected void hideTargetFeedback(IPart part) { part.getStatus().deSelect(); } private void assistTraverseNext() { if (currentIndex >= 0) { hideTargetFeedback(traversables[currentIndex]); } currentIndex++; if (currentIndex >= traversables.length) currentIndex = 0; showTargetFeedback(traversables[currentIndex]); } protected void traverseTo(IPart target) { eraseFeedback(); lastSource = getSource(); lastTarget = target; getTargetViewer().setSelection(new StructuredSelection(target), true); finish(); } protected void onDeactivated(ITool nextTool) { getStatus().removeStatusListener(this); super.onDeactivated(nextTool); } public IGraphicalEditPart getSource() { return source; } public void setSource(IGraphicalEditPart source) { Assert.isTrue(source == null || source.getStatus().isActive()); Assert.isTrue(source == null || source.hasRole(GEF.ROLE_TRAVERSABLE)); this.source = source; } public void statusChanged(StatusEvent event) { if (smartMode && (event.key & GEF.ST_MODIFIER_MASK) != 0) { if (currentIndex >= 0) { traverseTo(traversables[currentIndex]); } else { cancel(); } } } protected void eraseFeedback() { if (traversables != null) { for (IPart p : traversables) { hideAssistFeedback(p); hideTargetFeedback(p); } traversables = null; } currentIndex = -1; hideSourceFeedback(getSource()); } protected void finish() { setSource(null); changeActiveTool(GEF.TOOL_DEFAULT); } protected void cancel() { eraseFeedback(); finish(); } }