/* * 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.visualization.comparison; import java.util.ArrayList; import java.util.logging.Logger; import edu.umd.cs.piccolo.PNode; import at.tuwien.ifs.somtoolbox.apps.viewer.ArrowPNode; import at.tuwien.ifs.somtoolbox.apps.viewer.GeneralUnitPNode; import at.tuwien.ifs.somtoolbox.apps.viewer.MapPNode; import at.tuwien.ifs.somtoolbox.apps.viewer.SOMPane; import at.tuwien.ifs.somtoolbox.apps.viewer.UnitSelectionListener; /** * @author Doris Baum * @version $Id: QuiverPNode.java 3883 2010-11-02 17:13:23Z frank $ */ public class QuiverPNode extends PNode implements UnitSelectionListener { private static final long serialVersionUID = 1L; // private boolean arrowVisibility = false; private boolean outlierArrows = true; private boolean adjacentArrows = true; private boolean stableArrows = true; private boolean clusterArrows = false; private boolean cumulative = false; private Object[] unitSelection = new Object[0]; private SOMPane sompane = null; public QuiverPNode(SOMPane sompane) { this.sompane = sompane; setPickable(false); } public void dropArrows() { this.removeAllChildren(); } public void computeArrows() { // reset all the units on the source map to reference no arrows sompane.getMap().resetArrows(); // have variables for easier reference MapPNode map = sompane.getMap(); MapPNode map2 = sompane.getSecondMap(); double secMapXOffset = sompane.getSecMapXOffset(); double secMapYOffset = sompane.getSecMapYOffset(); // start with a fresh and shiny PNode this.removeAllChildren(); try { // (re)calculate the shifts between the two SOMs ArrayList<Shift> allShifts = null; // if we're using a cluster view of the arrows if (clusterArrows) { allShifts = sompane.getSOMComparision().calculateClusterShifts(map, map2); // if we're using the "normal" view } else { allShifts = sompane.getSOMComparision().calculateShifts(cumulative); } // make arrows for the data shifts ArrowPNode currentArrow = null; Shift currentShift = null; for (int i = 0; i < allShifts.size(); i++) { // shift info from ArrayList currentShift = allShifts.get(i); // Calculate coordinates for the arrow currentArrow = new ArrowPNode((currentShift.getX1() + 0.5) * map.getUnitWidth(), (currentShift.getY1() + 0.5) * map.getUnitHeight(), secMapXOffset + (currentShift.getX2() + 0.5) * map2.getUnitWidth(), secMapYOffset + (currentShift.getY2() + 0.5) * map2.getUnitHeight()); currentArrow.setPickable(false); // / set type (and thus color) of arrow currentArrow.setType(currentShift.getType()); // set width of arrow if (sompane.getSOMComparision().isAbsolute() || clusterArrows) { currentArrow.setProportionalWidth(currentShift.getProportion()); } else { currentArrow.setProportionalWidth(currentShift.getPercent()); } this.addChild(currentArrow); // tell the arrow source unit that it is source of this new arrow map.getUnit(currentShift.getX1(), currentShift.getY1()).addArrow(currentArrow); } // determine which of the new arrows should be visible this.updateArrowTypeVisibility(); this.updateArrowSelectionVisibility(); if (sompane.isShiftArrowsVisibility()) { this.updateClusterBorders(); } } catch (Exception e) { Logger.getLogger("at.tuwien.ifs.somtoolbox").severe(e.getMessage()); e.printStackTrace(); } } public void updateArrowTypeVisibility() { for (int i = 0; i < this.getChildrenCount(); i++) { ArrowPNode curArrow = (ArrowPNode) this.getChild(i); if (stableArrows && curArrow.getType() == ArrowPNode.STABLE || adjacentArrows && curArrow.getType() == ArrowPNode.ADJACENT || outlierArrows && curArrow.getType() == ArrowPNode.OUTLIER || clusterArrows && curArrow.getType() == ArrowPNode.CLUSTER) { curArrow.setTypeVisibility(true); } else { curArrow.setTypeVisibility(false); } } this.repaint(); } public void updateArrowSelectionVisibility() { // if there are units selected if (unitSelection.length > 0) { // ... first make all arrows invisible this.setAllArrowsSelectionVisibility(false); GeneralUnitPNode currentSelectedUnit = null; // go through all selected units for (Object element : unitSelection) { if (element instanceof GeneralUnitPNode) { // get the current selected unit currentSelectedUnit = (GeneralUnitPNode) element; // go through the list of arrows on this node and make each one visible for (ArrowPNode arrowPNode : currentSelectedUnit.getArrows()) { arrowPNode.setSelectionVisibility(true); } } } } else { // if nothing is selected, just make all arrows visible this.setAllArrowsSelectionVisibility(true); } this.repaint(); } private void setAllArrowsSelectionVisibility(boolean vis) { for (int i = 0; i < this.getChildrenCount(); i++) { ((ArrowPNode) this.getChild(i)).setSelectionVisibility(vis); } } @Override public void unitSelectionChanged(Object[] selection, boolean newSelection) { unitSelection = selection; this.updateArrowSelectionVisibility(); } public void updateClusterBorders() { MapPNode map = sompane.getMap(); MapPNode map2 = sompane.getSecondMap(); // angela:showClusters - true->false geändert, damit die linien nicht immer dünner werden // tritt auf wenn nicht jedes mal der baum neu berechnet wird boolean clusterremove = false; if (sompane.isShiftArrowsVisibility() && clusterArrows) { map.showClusters(sompane.getSOMComparision().getClusterNo(), false); if (map2 != null) { map2.showClusters(sompane.getSOMComparision().getClusterNo(), false); } else { clusterremove = true; } } else { clusterremove = true; } if (clusterremove) { map.setClusteringElements(null); if (map2 != null) { map2.setClusteringElements(null); } } map.repaint(); if (map2 != null) { map2.repaint(); } } public boolean clusterArrowsOn() { return clusterArrows; } public void enableClusterArrows(boolean clusterArrows) { if (this.clusterArrows != clusterArrows) { this.clusterArrows = clusterArrows; this.computeArrows(); } } public void setMultiMatch(boolean multiMatch) { if (sompane.getSOMComparision().isMultiMatch() != multiMatch) { sompane.getSOMComparision().setMultiMatch(multiMatch); this.computeArrows(); } } public boolean isCumulative() { return cumulative; } public void setCumulative(boolean cumulative) { if (this.cumulative != cumulative) { this.cumulative = cumulative; this.computeArrows(); } } public boolean outlierArrowsOn() { return outlierArrows; } public void enableOutlierArrows(boolean outlierArrows) { this.outlierArrows = outlierArrows; this.updateArrowTypeVisibility(); } public boolean stableArrowsOn() { return stableArrows; } public void enableStableArrows(boolean stableArrows) { this.stableArrows = stableArrows; this.updateArrowTypeVisibility(); } public boolean adjacentArrowsOn() { return adjacentArrows; } public void enableAdjacentArrows(boolean adjacentArrows) { this.adjacentArrows = adjacentArrows; this.updateArrowTypeVisibility(); } }