/* * Copyright 2004-2010 Information & Software Engineering Group (188/1) * Institute of Software Technology and Interactive Systems * Vienna University of Technology, Austria * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.ifs.tuwien.ac.at/dm/somtoolbox/license.html * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package at.tuwien.ifs.somtoolbox.apps.viewer; import java.awt.Cursor; import java.awt.event.InputEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.util.Collection; import java.util.HashSet; import edu.umd.cs.piccolo.PCanvas; import edu.umd.cs.piccolo.PLayer; import edu.umd.cs.piccolo.PNode; import edu.umd.cs.piccolo.event.PInputEventFilter; import edu.umd.cs.piccolox.event.PNotification; import edu.umd.cs.piccolox.event.PNotificationCenter; import edu.umd.cs.piccolox.event.PSelectionEventHandler; import edu.umd.cs.piccolox.swing.PScrollPane; import at.tuwien.ifs.somtoolbox.apps.viewer.handlers.ClusterSelectionEventHandler; import at.tuwien.ifs.somtoolbox.apps.viewer.handlers.LineSelectionEventHandler; import at.tuwien.ifs.somtoolbox.apps.viewer.handlers.MyMapInputEventHandler; import at.tuwien.ifs.somtoolbox.apps.viewer.handlers.MyRectangleSelectionEventHandler; import at.tuwien.ifs.somtoolbox.apps.viewer.handlers.MyWheelZoomEventHandler; /** * A generic scrollable pane that holds a {@link PNode} and handles line and rectangle selection events via registered * listeners. This class makes use of the <a href="http://www.cs.umd.edu/hcil/jazz/" target="_blank">Piccolo * framework</a>. * * @author Michael Dittenbach * @author Rudolf Mayer * @version $Id: GenericPNodeScrollPane.java 3590 2010-05-21 10:43:45Z mayer $ */ public class GenericPNodeScrollPane extends PScrollPane { private static final long serialVersionUID = 1L; protected PCanvas canvas = new MyPCanvas(); protected MyRectangleSelectionEventHandler rectangleSelectionEventHandler; protected ClusterSelectionEventHandler clusterSelectionEventHandler; protected LineSelectionEventHandler lineSelectionEventHandler; protected PNode node = null; protected PNode lineSelection = new PNode(); protected UnitSelectionListener[] connectedSelectionHandlers = null; protected HashSet<UnitSelectionListener> connectedSelectionHandlersSet = new HashSet<UnitSelectionListener>(); protected Point2D lastSelectedPoint; protected CommonSOMViewerStateData state; protected final ToolTipPNode tooltipNode = new ToolTipPNode(); public GenericPNodeScrollPane(CommonSOMViewerStateData state, PNode node) { super(); this.state = state; this.node = node; init(); } protected GenericPNodeScrollPane() { super(); setViewportView(canvas); } protected void init() { setViewportView(canvas); setAutoscrolls(false); initPNodeSpecific(); // create MouseLstener for cursor changes, etc. canvas.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON3) { setCursor(new Cursor(Cursor.MOVE_CURSOR)); } if (e.getButton() == MouseEvent.BUTTON2) { centerAndFitMapToScreen(); } } @Override public void mouseReleased(MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON3) { setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); } } }); // slightly modify event handler for panning: use right/third mouse button, instead of left/first canvas.getPanEventHandler().setEventFilter(new PInputEventFilter(InputEvent.BUTTON3_MASK)); // create event handler for zooming canvas.removeInputEventListener(getCanvas().getZoomEventHandler()); canvas.addInputEventListener(new MyWheelZoomEventHandler()); // create event handler for selection this.initSelectionHandlers(); // redraw interface if necessary validate(); } private void initPNodeSpecific() { canvas.getLayer().addChild(node); // create tooltip object and add event listener // node.addChild(tooltipNode); canvas.getLayer().addChild(tooltipNode); canvas.getLayer().addChild(lineSelection); getCanvas().addInputEventListener(new MyMapInputEventHandler(tooltipNode, node)); } public void selectionChanged(PNotification notification) { if (connectedSelectionHandlers != null) { PSelectionEventHandler handler = (PSelectionEventHandler) notification.getObject(); Collection<?> coll = handler.getSelection(); boolean newSelection = false; if (!handler.getMousePressedCanvasPoint().equals(lastSelectedPoint)) { lastSelectedPoint = (Point2D) handler.getMousePressedCanvasPoint().clone(); newSelection = true; } for (UnitSelectionListener connectedSelectionHandler : connectedSelectionHandlers) { connectedSelectionHandler.unitSelectionChanged(coll.toArray(), newSelection); } } } /** set the line selection handler. */ public void setLine() { ((MyPCanvas) canvas).setSelectionEventHandler(this.lineSelectionEventHandler); PNotificationCenter.defaultCenter().addListener(this, "selectionChanged", PSelectionEventHandler.SELECTION_CHANGED_NOTIFICATION, this.lineSelectionEventHandler); } /** set the rectangle selection handler. */ public void setRectangle() { ((MyPCanvas) canvas).setSelectionEventHandler(this.rectangleSelectionEventHandler); PNotificationCenter.defaultCenter().addListener(this, "selectionChanged", PSelectionEventHandler.SELECTION_CHANGED_NOTIFICATION, this.rectangleSelectionEventHandler); } /** set the cluster selection handler. */ public void setCluster() { ((MyPCanvas) canvas).setSelectionEventHandler(this.clusterSelectionEventHandler); PNotificationCenter.defaultCenter().addListener(this, "selectionChanged", PSelectionEventHandler.SELECTION_CHANGED_NOTIFICATION, this.clusterSelectionEventHandler); } public PCanvas getCanvas() { return canvas; } /** * initialize both selection handlers and set rectangle selection as default. also initializes handler for selecting * and moving a cluster label. */ public void initSelectionHandlers() { PLayer layer = this.getCanvas().getLayer(); PNode child = layer.getChild(0); // this.lineSelectionEventHandler = new LineSelectionEventHandler(layer, child); this.lineSelectionEventHandler = new LineSelectionEventHandler(lineSelection, child); this.rectangleSelectionEventHandler = new MyRectangleSelectionEventHandler(layer, child); if (child instanceof MapPNode) { // e.g. in the ComponentPlaneClusteringFrame, we do not have a MapPNode, just a // PNode this.clusterSelectionEventHandler = new ClusterSelectionEventHandler(layer, child); } this.setRectangle(); } public void centerAndFitMapToScreen(int animationDuration) { canvas.getCamera().animateViewToCenterBounds(new Rectangle2D.Double(0, 0, node.getWidth(), node.getHeight()), true, animationDuration); } public void connectSelectionHandlerTo(UnitSelectionListener panel) { connectedSelectionHandlersSet.add(panel); connectedSelectionHandlers = connectedSelectionHandlersSet.toArray(new UnitSelectionListener[connectedSelectionHandlersSet.size()]); } // @Override // public Dimension getMinimumSize() { // return getPreferredSize(); // } // // @Override // public Dimension getPreferredSize() { // Container parentContainer = getParent().getParent().getParent().getParent().getParent(); // return new Dimension(parentContainer.getWidth() - state.controlElementsWidth, parentContainer.getHeight()); // } public void centerAndFitMapToScreen() { centerAndFitMapToScreen(2000); } public void setPNode(PNode newPNode) { canvas.getLayer().removeAllChildren(); this.node = newPNode; initPNodeSpecific(); } }