ui inspector improved

This commit is contained in:
Alexey Pegov
2011-12-08 17:20:25 +04:00
parent 67d2c0c697
commit 095c3f4f36
@@ -15,6 +15,10 @@
*/
package com.intellij.internal.inspector;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.notification.NotificationsManager;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.ToggleAction;
@@ -25,16 +29,20 @@ import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.HashMap;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.tree.TreeUtil;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.plaf.ColorUIResource;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.tree.*;
import java.awt.*;
import java.awt.event.*;
import java.lang.reflect.InvocationTargetException;
@@ -42,6 +50,7 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Vector;
/**
* User: spLeaner
@@ -62,6 +71,12 @@ public class UiInspectorAction extends ToggleAction implements DumbAware {
myInspector = new UiInspector();
Toolkit.getDefaultToolkit().addAWTEventListener(myInspector, AWTEvent.MOUSE_EVENT_MASK);
}
UiInspectorNotification[] existing =
NotificationsManager.getNotificationsManager().getNotificationsOfType(UiInspectorNotification.class, null);
if (existing.length == 0) {
Notifications.Bus.notify(new UiInspectorNotification(), null);
}
}
else {
if (myInspector != null) {
@@ -71,41 +86,36 @@ public class UiInspectorAction extends ToggleAction implements DumbAware {
}
}
}
private static class UiInspectorNotification extends Notification {
private UiInspectorNotification() {
super(Notifications.SYSTEM_MESSAGES_GROUP_ID, "UI Inspector", "Control-Alt-Click to view component info!",
NotificationType.INFORMATION);
}
}
private static class InspectorWindow extends JFrame {
private InspectorTable myInspectorTable;
private UiInspector myUiInspector;
private JComponent myComponent;
private boolean myHighlighted = false;
private boolean myHighlighted = true;
private HighlightComponent myHighlightComponent;
private HierarchyTree myHierarchyTree;
private final JPanel myWrapperPanel;
private InspectorWindow(@NotNull final JComponent component, UiInspector uiInspector) throws HeadlessException {
myComponent = component;
myUiInspector = uiInspector;
getRootPane().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
setLayout(new BorderLayout());
final String simpleName = component.getClass().getSimpleName();
setTitle(simpleName.length() == 0 ? component.getClass().getName() : simpleName);
JToolBar bar = new JToolBar(JToolBar.HORIZONTAL);
JToolBar bar = new JToolBar(SwingConstants.HORIZONTAL);
bar.setFloatable(false);
bar.add(new AbstractAction("Show parent", IconLoader.getIcon("/nodes/parentsIntroduction.png")) {
public void actionPerformed(ActionEvent e) {
Container parent = component.getParent();
if (parent instanceof JComponent) {
myUiInspector.showInspector((JComponent) parent);
}
}
@Override
public boolean isEnabled() {
return myComponent.getParent() != null;
}
});
bar.add(new AbstractAction("Highlight", IconLoader.getIcon("/toolbar/unknown.png")) {
public void actionPerformed(ActionEvent e) {
myHighlighted = !myHighlighted;
@@ -122,7 +132,7 @@ public class UiInspectorAction extends ToggleAction implements DumbAware {
bar.add(new AbstractAction("Refresh", IconLoader.getIcon("/vcs/refresh.png")) {
public void actionPerformed(ActionEvent e) {
myInspectorTable.refresh();
getCurrentTable().refresh();
}
@Override
@@ -133,9 +143,31 @@ public class UiInspectorAction extends ToggleAction implements DumbAware {
add(bar, BorderLayout.NORTH);
myWrapperPanel = new JPanel(new BorderLayout());
add(new JLabel(component.getClass().getName()), BorderLayout.SOUTH);
myInspectorTable = new InspectorTable(component);
add(myInspectorTable, BorderLayout.CENTER);
myHierarchyTree = new HierarchyTree(component) {
@Override
public void onComponentChanged(Component c) {
highlight(myComponent, true);
switchInfo(c);
if (myHighlighted) highlight(c, false);
}
};
myWrapperPanel.add(myInspectorTable, BorderLayout.CENTER);
JSplitPane splitPane = new JSplitPane();
splitPane.setDividerLocation(0.5);
splitPane.setRightComponent(myWrapperPanel);
JScrollPane pane = new JScrollPane(myHierarchyTree);
splitPane.setLeftComponent(pane);
add(splitPane, BorderLayout.CENTER);
myHierarchyTree.expandPath();
addWindowListener(new WindowAdapter() {
@Override
@@ -157,6 +189,18 @@ public class UiInspectorAction extends ToggleAction implements DumbAware {
getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "CLOSE");
}
private InspectorTable getCurrentTable() {
return myInspectorTable;
}
private void switchInfo(Component c) {
myInspectorTable = new InspectorTable(c);
myWrapperPanel.removeAll();
myWrapperPanel.add(myInspectorTable, BorderLayout.CENTER);
myWrapperPanel.revalidate();
myWrapperPanel.repaint();
}
public void close() {
highlight(myComponent, true);
myComponent = null;
@@ -193,7 +237,150 @@ public class UiInspectorAction extends ToggleAction implements DumbAware {
return myComponent;
}
}
private static class ComponentTreeCellRenderer extends JLabel implements TreeCellRenderer {
private ComponentTreeCellRenderer() {
setOpaque(true);
setFont(UIUtil.getLabelFont().deriveFont(11f));
setBorder(BorderFactory.createEmptyBorder(0, 3, 0, 3));
}
@Override
public Component getTreeCellRendererComponent(JTree tree,
Object value,
boolean selected,
boolean expanded,
boolean leaf,
int row,
boolean hasFocus) {
Color foreground = selected ? UIUtil.getTreeSelectionForeground() : UIUtil.getTreeForeground();
Color background = selected ? UIUtil.getTreeSelectionBackground() : null;
if (value instanceof HierarchyTree.ComponentNode) {
HierarchyTree.ComponentNode componentNode = (HierarchyTree.ComponentNode)value;
Component component = componentNode.getOwnComponent();
String name = component.getClass().getSimpleName();
if (name.length() == 0) {
name = component.getClass().getSuperclass().getSimpleName();
}
if (!selected) {
if (!component.isVisible()) {
foreground = Color.GRAY;
} else if (component.getWidth() == 0 || component.getHeight() == 0) {
foreground = new Color(128, 10, 0);
}
if (componentNode.getToSelect() == componentNode.getOwnComponent()) {
background = new Color(31, 128, 8, 58);
}
}
setText(name);
}
setForeground(foreground);
setBackground(background);
return this;
}
}
private abstract static class HierarchyTree extends JTree implements TreeSelectionListener {
private final JComponent myComponent;
private HierarchyTree(JComponent c) {
myComponent = c;
setModel(buildModel(c));
setCellRenderer(new ComponentTreeCellRenderer());
getSelectionModel().addTreeSelectionListener(this);
}
public void expandPath() {
TreeUtil.expandAll(this);
int count = getRowCount();
ComponentNode node = new ComponentNode(myComponent, myComponent.getParent());
for (int i = 0; i < count; i++) {
TreePath row = getPathForRow(i);
if (row.getLastPathComponent().equals(node)) {
setSelectionPath(row);
scrollPathToVisible(getSelectionPath());
break;
}
}
}
@Override
public void valueChanged(TreeSelectionEvent e) {
TreePath path = e.getNewLeadSelectionPath();
Object component = path.getLastPathComponent();
if (component instanceof ComponentNode) {
Component c = ((ComponentNode)component).getOwnComponent();
onComponentChanged(c);
}
}
private static TreeModel buildModel(JComponent c) {
return new DefaultTreeModel(new ComponentNode(c, null));
}
public abstract void onComponentChanged(Component c);
private static class ComponentNode extends DefaultMutableTreeNode {
private final Component myParent;
private final Component myToSelect;
private ComponentNode(Object userObject, Component parent) {
super(userObject);
myParent = parent == null ? SwingUtilities.getWindowAncestor((Component) userObject) : parent;
myToSelect = (Component)userObject;
children = prepareChildren(myToSelect, parent);
}
public Component getOwnComponent() {
return myParent;
}
public Component getToSelect() {
return myToSelect;
}
@Override
public String toString() {
return myParent.getClass().getName();
}
@Override
public boolean equals(Object obj) {
return obj instanceof ComponentNode && ((ComponentNode)obj).getOwnComponent() == getOwnComponent();
}
@SuppressWarnings("UseOfObsoleteCollectionType")
private static Vector prepareChildren(Component toSelect, Component parent) {
Vector<ComponentNode> result = new Vector<ComponentNode>();
if (parent == null) {
Container root = toSelect.getParent();
while (true) {
Container _superRoot = root.getParent();
if (_superRoot == null) break;
root = _superRoot;
}
for (Component component : root.getComponents()) {
result.add(new ComponentNode(toSelect, component));
}
} else {
if (parent instanceof Container) {
for (Component component : ((Container)parent).getComponents()) {
result.add(new ComponentNode(toSelect, component));
}
}
}
return result;
}
}
}
private static class HighlightComponent extends JComponent {
private Color myColor;
@@ -226,7 +413,7 @@ public class UiInspectorAction extends ToggleAction implements DumbAware {
private InspectorTableModel myModel;
private DimensionsComponent myDimensionComponent;
private InspectorTable(@NotNull final JComponent component) {
private InspectorTable(@NotNull final Component component) {
setLayout(new BorderLayout());
myModel = new InspectorTableModel(component);
@@ -258,13 +445,13 @@ public class UiInspectorAction extends ToggleAction implements DumbAware {
}
private static class DimensionsComponent extends JComponent {
private JComponent myComponent;
private Component myComponent;
private int myWidth;
private int myHeight;
private Border myBorder;
private Insets myInsets;
private DimensionsComponent(@NotNull final JComponent component) {
private DimensionsComponent(@NotNull final Component component) {
myComponent = component;
setOpaque(true);
setBackground(Color.WHITE);
@@ -278,8 +465,10 @@ public class UiInspectorAction extends ToggleAction implements DumbAware {
public void update() {
myWidth = myComponent.getWidth();
myHeight = myComponent.getHeight();
myBorder = myComponent.getBorder();
myInsets = myComponent.getInsets();
if (myComponent instanceof JComponent) {
myBorder = ((JComponent)myComponent).getBorder();
myInsets = ((JComponent)myComponent).getInsets();
}
}
@Override
@@ -485,17 +674,17 @@ public class UiInspectorAction extends ToggleAction implements DumbAware {
"isShowing", "isEnabled", "isLightweight", "isFocusable", "isFocusOwner"
};
private JComponent myComponent;
private Component myComponent;
private List<PropertyBean> myProperties = new ArrayList<PropertyBean>();
public InspectorTableModel(@NotNull final JComponent c) {
public InspectorTableModel(@NotNull final Component c) {
myComponent = c;
fillTable();
}
private void fillTable() {
final Class<? extends JComponent> cls = myComponent.getClass();
final Class<? extends Component> cls = myComponent.getClass();
for (final String methodName: JCOMPONENT_METHODS) {
try {
final Method method = cls.getMethod(methodName);