/******************************************************************************* * Copyright (c) 2005, 2012 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.bpel.ui; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import org.eclipse.bpel.model.util.BPELUtils; import org.eclipse.bpel.ui.editparts.ProcessEditPart; import org.eclipse.bpel.ui.util.BPELUtil; import org.eclipse.bpel.ui.util.IModelVisitor; import org.eclipse.draw2d.FigureCanvas; import org.eclipse.draw2d.IFigure; 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.gef.EditPart; import org.eclipse.gef.GraphicalEditPart; import org.eclipse.gef.ui.parts.GraphicalViewerImpl; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; /** * We override ScrollingGraphicalViewer so we can install our own root edit part. * The root edit part is responsible for creating the layers, and the BPEL * editor wants many extra layers. * * We extend GraphicalViewerImpl instead of ScrollingGraphicalViewer because this * is the only way that we can override and modify the reveal() behaviour. */ public class ScrollingBPELGraphicalViewer extends GraphicalViewerImpl { private HashMap<Object, Integer> orderMap = null; protected List selectionList = null; protected int indexVisit = 0; protected boolean hasFocus; protected boolean notifyingOfSelectionChange; @Override protected void createDefaultRoot() { setRootEditPart(new GraphicalBPELRootEditPart()); } public class NumeratorVisitor implements IModelVisitor { public boolean visit(Object modelObject) { indexVisit++; orderMap.put(modelObject, Integer.valueOf( indexVisit )); return true; } } private class OrderedSelectionComparator implements Comparator<EditPart> { public int compare(EditPart ep1, EditPart ep2) { int val1 = 0, val2 = 0; Object m1 = ep1.getModel(); Object m2 = ep2.getModel(); if (orderMap.get(m1) != null) val1 = (orderMap.get(m1)).intValue(); if (orderMap.get(m2) != null) val2 = (orderMap.get(m2)).intValue(); if (val1 < val2) return -1; else if (val1 > val2) return 1; return 0; } } /** * @see org.eclipse.gef.ui.parts.AbstractEditPartViewer#appendSelection(org.eclipse.gef.EditPart) */ @Override public void appendSelection(EditPart editpart) { super.appendSelection(editpart); // We want to keep the selection in model order. selectionList = primGetSelectedEditParts(); if (selectionList.size() > 1){ indexVisit = 0; orderMap = new HashMap<Object, Integer>(); BPELUtil.visitModelDepthFirst(BPELUtils.getProcess(editpart.getModel()), new NumeratorVisitor()); Comparator cmp = new OrderedSelectionComparator(); Collections.sort(selectionList, cmp); StructuredSelection newSel = new StructuredSelection(selectionList); setSelection(newSel); } orderMap = null; selectionList = null; } /** * @see org.eclipse.gef.EditPartViewer#createControl(org.eclipse.swt.widgets.Composite) */ @Override public final Control createControl(Composite parent) { final FigureCanvas canvas = new FigureCanvas(parent, getLightweightSystem()); canvas.addFocusListener(new FocusListener() { public void focusGained(FocusEvent e) { hasFocus = true; canvas.redraw(); } public void focusLost(FocusEvent e) { hasFocus = false; canvas.redraw(); }}); super.setControl(canvas); installRootFigure(); return canvas; } /** * Convenience method which types the control as a <code>FigureCanvas</code>. This method * returns <code>null</code> whenever the control is null. * @return <code>null</code> or the Control as a FigureCanvas */ protected FigureCanvas getFigureCanvas() { return (FigureCanvas)getControl(); } public boolean getFigureCanvasFocus() { return hasFocus; } /** * If the figure is a viewport, set the canvas' viewport, otherwise, set its contents. */ private void installRootFigure() { if (getFigureCanvas() == null) return; IFigure rootFigure = getRootFigure(); if (rootFigure instanceof Viewport) getFigureCanvas().setViewport((Viewport)rootFigure); else getFigureCanvas().setContents(rootFigure); } /** * Extends the superclass implementation to scroll the native Canvas control after the * super's implementation has completed. * @see org.eclipse.gef.EditPartViewer#reveal(org.eclipse.gef.EditPart) */ @Override public void reveal(EditPart part) { // New rule: Don't scroll *up* if it would cause any currently visible // part of the edit part to disappear off the bottom. // Likewise, don't scroll down if it would cause any currently visible // part of the edit part to disappear off the top, but this is // unlikely to happen anyway. super.reveal(part); if (part instanceof ProcessEditPart) { // We never want to even try to reveal the process edit part. return; } Viewport port = getFigureCanvas().getViewport(); IFigure target = ((GraphicalEditPart)part).getFigure(); Rectangle exposeRegion = target.getBounds().getExpanded(5, 5); target = target.getParent(); while (target != null && target != port) { target.translateToParent(exposeRegion); target = target.getParent(); } Dimension viewportSize = port.getClientArea().getSize(); Point topLeft = exposeRegion.getTopLeft(); Point bottomRight = exposeRegion. getBottomRight(). translate(viewportSize.negate()); Point finalLocation = Point.min(topLeft, Point.max(bottomRight, port.getViewLocation())); Dimension existingSize = port.getSize(); int oldViewportY = port.getViewLocation().y; int newViewportY = finalLocation.y; int figureY = exposeRegion.y; int figureHeight = exposeRegion.height; int bottomVisibleBefore = Math.min(figureY + figureHeight, oldViewportY + existingSize.height); int bottomVisibleAfter = Math.min(figureY + figureHeight, newViewportY + existingSize.height); if (bottomVisibleAfter < bottomVisibleBefore) { // Truncate it so that we don't lose anything off the bottom of the screen. finalLocation.y = figureY + figureHeight - existingSize.height; } int topVisibleBefore = Math.max(figureY, oldViewportY); int topVisibleAfter = Math.max(figureY, finalLocation.y); if (topVisibleAfter > topVisibleBefore && bottomVisibleAfter < bottomVisibleBefore) { // Moving it would change both the top and bottom. Don't do anything. finalLocation.y = oldViewportY; } getFigureCanvas().scrollSmoothTo(finalLocation.x, finalLocation.y); } /** * @see GraphicalViewerImpl#setRootFigure(IFigure) */ @Override protected void setRootFigure(IFigure figure) { // Warning: The super does more work than the old method did. super.setRootFigure(figure); installRootFigure(); } /** * Scroll vertical. If the argument is true, it scrolls up by 100 pixels, * otherwise it scrolls down by 100 pixels. * * @param up if true scroll up, if false scrolls down. */ public void scrollVertical(boolean up) { Viewport port = getFigureCanvas().getViewport(); Point finalLocation = port.getViewLocation().getCopy(); finalLocation.y += up ? -100: 100; getFigureCanvas().scrollSmoothTo(finalLocation.x, finalLocation.y); } /** * Scroll horizontal. If left is true scrolls left, if false scrolls right. * * @param left if true, it will scroll left. */ public void scrollHorizontal (boolean left) { Viewport port = getFigureCanvas().getViewport(); Point finalLocation = port.getViewLocation().getCopy(); finalLocation.x += left ? -100: 100; getFigureCanvas().scrollSmoothTo(finalLocation.x, finalLocation.y); } /** * See comments in BPELSelectionTool.handleFocusLost(). */ @Override protected void fireSelectionChanged() { try { notifyingOfSelectionChange = true; super.fireSelectionChanged(); } finally { notifyingOfSelectionChange = false; } } /** * Returns true if it is sending an event that updates the * properties view input. * * See comments in BPELSelectionTool.handleFocusLost(). */ // public boolean isUpdatingPropertiesViewInput() { // return updatingPropertiesViewInput; // } /** (non-Javadoc) * @see org.eclipse.gef.ui.parts.AbstractEditPartViewer#setSelection(org.eclipse.jface.viewers.ISelection) */ @Override public void setSelection( ISelection arg0 ) { if (notifyingOfSelectionChange) { return ; } super.setSelection(arg0); } /** * */ @Override public ISelection getSelection() { if (getSelectedEditParts().isEmpty()) { return StructuredSelection.EMPTY; } return new StructuredSelection(getSelectedEditParts()); } }