mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
ui inspector improved
This commit is contained in:
+216
-27
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user