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