1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.hierarchyviewer.scene; 18 19 import java.awt.Color; 20 import java.awt.Font; 21 import java.awt.GradientPaint; 22 import java.awt.Graphics2D; 23 import java.awt.Rectangle; 24 import java.awt.geom.Point2D; 25 26 import org.netbeans.api.visual.action.ActionFactory; 27 import org.netbeans.api.visual.action.WidgetAction; 28 import org.netbeans.api.visual.anchor.AnchorFactory; 29 import org.netbeans.api.visual.border.BorderFactory; 30 import org.netbeans.api.visual.graph.GraphScene; 31 import org.netbeans.api.visual.layout.LayoutFactory; 32 import org.netbeans.api.visual.model.ObjectState; 33 import org.netbeans.api.visual.widget.ConnectionWidget; 34 import org.netbeans.api.visual.widget.LabelWidget; 35 import org.netbeans.api.visual.widget.LayerWidget; 36 import org.netbeans.api.visual.widget.Widget; 37 38 public class ViewHierarchyScene extends GraphScene<ViewNode, String> { 39 private ViewNode root; 40 private LayerWidget widgetLayer; 41 private LayerWidget connectionLayer; 42 43 private WidgetAction moveAction = ActionFactory.createMoveAction(); 44 ViewHierarchyScene()45 public ViewHierarchyScene() { 46 widgetLayer = new LayerWidget(this); 47 connectionLayer = new LayerWidget(this); 48 49 addChild(widgetLayer); 50 addChild(connectionLayer); 51 } 52 getRoot()53 public ViewNode getRoot() { 54 return root; 55 } 56 setRoot(ViewNode root)57 void setRoot(ViewNode root) { 58 this.root = root; 59 } 60 61 @Override attachNodeWidget(ViewNode node)62 protected Widget attachNodeWidget(ViewNode node) { 63 Widget widget = createBox(node, node.name, node.id); 64 widget.getActions().addAction(createSelectAction()); 65 widget.getActions().addAction(moveAction); 66 widgetLayer.addChild(widget); 67 return widget; 68 } 69 createBox(ViewNode node, String nodeName, String id)70 private Widget createBox(ViewNode node, String nodeName, String id) { 71 final String shortName = getShortName(nodeName); 72 node.setShortName(shortName); 73 74 GradientWidget box = new GradientWidget(this, node); 75 box.setLayout(LayoutFactory.createVerticalFlowLayout()); 76 box.setBorder(BorderFactory.createLineBorder(2, Color.BLACK)); 77 box.setOpaque(true); 78 79 LabelWidget label = new LabelWidget(this); 80 label.setFont(getDefaultFont().deriveFont(Font.PLAIN, 12.0f)); 81 label.setLabel(shortName); 82 label.setBorder(BorderFactory.createEmptyBorder(6, 6, 0, 6)); 83 label.setAlignment(LabelWidget.Alignment.CENTER); 84 85 box.addChild(label); 86 87 label = new LabelWidget(this); 88 label.setFont(getDefaultFont().deriveFont(Font.PLAIN, 10.0f)); 89 label.setLabel(getAddress(nodeName)); 90 label.setBorder(BorderFactory.createEmptyBorder(3, 6, 0, 6)); 91 label.setAlignment(LabelWidget.Alignment.CENTER); 92 93 box.addressWidget = label; 94 95 box.addChild(label); 96 97 label = new LabelWidget(this); 98 label.setFont(getDefaultFont().deriveFont(Font.PLAIN, 10.0f)); 99 label.setLabel(id); 100 label.setBorder(BorderFactory.createEmptyBorder(3, 6, 6, 6)); 101 label.setAlignment(LabelWidget.Alignment.CENTER); 102 103 box.addChild(label); 104 105 return box; 106 } 107 getAddress(String name)108 private static String getAddress(String name) { 109 String[] nameAndHashcode = name.split("@"); 110 return "@" + nameAndHashcode[1]; 111 } 112 getShortName(String name)113 private static String getShortName(String name) { 114 String[] nameAndHashcode = name.split("@"); 115 String[] packages = nameAndHashcode[0].split("\\."); 116 return packages[packages.length - 1]; 117 } 118 119 @Override attachEdgeWidget(String edge)120 protected Widget attachEdgeWidget(String edge) { 121 ConnectionWidget connectionWidget = new ConnectionWidget(this); 122 connectionLayer.addChild(connectionWidget); 123 return connectionWidget; 124 } 125 126 @Override attachEdgeSourceAnchor(String edge, ViewNode oldSourceNode, ViewNode sourceNode)127 protected void attachEdgeSourceAnchor(String edge, ViewNode oldSourceNode, ViewNode sourceNode) { 128 final ConnectionWidget connection = (ConnectionWidget) findWidget(edge); 129 final Widget source = findWidget(sourceNode); 130 connection.bringToBack(); 131 source.bringToFront(); 132 connection.setSourceAnchor(AnchorFactory.createRectangularAnchor(source)); 133 } 134 135 @Override attachEdgeTargetAnchor(String edge, ViewNode oldTargetNode, ViewNode targetNode)136 protected void attachEdgeTargetAnchor(String edge, ViewNode oldTargetNode, ViewNode targetNode) { 137 final ConnectionWidget connection = (ConnectionWidget) findWidget(edge); 138 final Widget target = findWidget(targetNode); 139 connection.bringToBack(); 140 target.bringToFront(); 141 connection.setTargetAnchor(AnchorFactory.createRectangularAnchor(target)); 142 } 143 144 private static class GradientWidget extends Widget implements ViewNode.StateListener { 145 public static final GradientPaint BLUE_EXPERIENCE = new GradientPaint( 146 new Point2D.Double(0, 0), 147 new Color(168, 204, 241), 148 new Point2D.Double(0, 1), 149 new Color(44, 61, 146)); 150 public static final GradientPaint MAC_OSX_SELECTED = new GradientPaint( 151 new Point2D.Double(0, 0), 152 new Color(81, 141, 236), 153 new Point2D.Double(0, 1), 154 new Color(36, 96, 192)); 155 public static final GradientPaint MAC_OSX = new GradientPaint( 156 new Point2D.Double(0, 0), 157 new Color(167, 210, 250), 158 new Point2D.Double(0, 1), 159 new Color(99, 147, 206)); 160 public static final GradientPaint AERITH = new GradientPaint( 161 new Point2D.Double(0, 0), 162 Color.WHITE, 163 new Point2D.Double(0, 1), 164 new Color(64, 110, 161)); 165 public static final GradientPaint GRAY = new GradientPaint( 166 new Point2D.Double(0, 0), 167 new Color(226, 226, 226), 168 new Point2D.Double(0, 1), 169 new Color(250, 248, 248)); 170 public static final GradientPaint RED_XP = new GradientPaint( 171 new Point2D.Double(0, 0), 172 new Color(236, 81, 81), 173 new Point2D.Double(0, 1), 174 new Color(192, 36, 36)); 175 public static final GradientPaint NIGHT_GRAY = new GradientPaint( 176 new Point2D.Double(0, 0), 177 new Color(102, 111, 127), 178 new Point2D.Double(0, 1), 179 new Color(38, 45, 61)); 180 public static final GradientPaint NIGHT_GRAY_LIGHT = new GradientPaint( 181 new Point2D.Double(0, 0), 182 new Color(129, 138, 155), 183 new Point2D.Double(0, 1), 184 new Color(58, 66, 82)); 185 public static final GradientPaint NIGHT_GRAY_VERY_LIGHT = new GradientPaint( 186 new Point2D.Double(0, 0), 187 new Color(129, 138, 155, 60), 188 new Point2D.Double(0, 1), 189 new Color(58, 66, 82, 60)); 190 191 private static Color UNSELECTED = Color.BLACK; 192 private static Color SELECTED = Color.WHITE; 193 194 private final ViewNode node; 195 196 private LabelWidget addressWidget; 197 198 private boolean isSelected = false; 199 private final GradientPaint selectedGradient = MAC_OSX_SELECTED; 200 private final GradientPaint filteredGradient = RED_XP; 201 private final GradientPaint focusGradient = NIGHT_GRAY_VERY_LIGHT; 202 GradientWidget(ViewHierarchyScene scene, ViewNode node)203 public GradientWidget(ViewHierarchyScene scene, ViewNode node) { 204 super(scene); 205 this.node = node; 206 node.setStateListener(this); 207 } 208 209 @Override notifyStateChanged(ObjectState previous, ObjectState state)210 protected void notifyStateChanged(ObjectState previous, ObjectState state) { 211 super.notifyStateChanged(previous, state); 212 isSelected = state.isSelected() || state.isFocused() || state.isWidgetFocused(); 213 214 pickChildrenColor(); 215 } 216 pickChildrenColor()217 private void pickChildrenColor() { 218 for (Widget child : getChildren()) { 219 child.setForeground(isSelected || node.filtered ? SELECTED : UNSELECTED); 220 } 221 222 repaint(); 223 } 224 225 @Override paintBackground()226 protected void paintBackground() { 227 super.paintBackground(); 228 229 Graphics2D g2 = getGraphics(); 230 Rectangle bounds = getBounds(); 231 232 if (!isSelected) { 233 if (!node.filtered) { 234 if (!node.hasFocus) { 235 g2.setColor(Color.WHITE); 236 } else { 237 g2.setPaint(new GradientPaint(bounds.x, bounds.y, 238 focusGradient.getColor1(), bounds.x, bounds.x + bounds.height, 239 focusGradient.getColor2())); 240 } 241 } else { 242 g2.setPaint(new GradientPaint(bounds.x, bounds.y, filteredGradient.getColor1(), 243 bounds.x, bounds.x + bounds.height, filteredGradient.getColor2())); 244 } 245 } else { 246 g2.setPaint(new GradientPaint(bounds.x, bounds.y, selectedGradient.getColor1(), 247 bounds.x, bounds.x + bounds.height, selectedGradient.getColor2())); 248 } 249 g2.fillRect(bounds.x, bounds.y, bounds.width, bounds.height); 250 } 251 nodeStateChanged(ViewNode node)252 public void nodeStateChanged(ViewNode node) { 253 pickChildrenColor(); 254 } 255 nodeIndexChanged(ViewNode node)256 public void nodeIndexChanged(ViewNode node) { 257 if (addressWidget != null) { 258 addressWidget.setLabel("#" + node.index + addressWidget.getLabel()); 259 } 260 } 261 } 262 } 263