diff --git a/platform/platform-impl/src/com/intellij/internal/inspector/UiInspectorAction.java b/platform/platform-impl/src/com/intellij/internal/inspector/UiInspectorAction.java index 23f9328eaea8..2041b59898ea 100644 --- a/platform/platform-impl/src/com/intellij/internal/inspector/UiInspectorAction.java +++ b/platform/platform-impl/src/com/intellij/internal/inspector/UiInspectorAction.java @@ -27,16 +27,15 @@ import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.StripeTable; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.ui.JBColor; +import com.intellij.ui.*; import com.intellij.ui.components.JBScrollPane; +import com.intellij.ui.speedSearch.SpeedSearchUtil; +import com.intellij.util.ExceptionUtil; import com.intellij.util.ObjectUtils; import com.intellij.util.ReflectionUtil; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.WeakKeyWeakValueHashMap; -import com.intellij.util.ui.ColorIcon; -import com.intellij.util.ui.JBUI; -import com.intellij.util.ui.PlatformColors; -import com.intellij.util.ui.UIUtil; +import com.intellij.util.ui.*; import com.intellij.util.ui.tree.TreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -50,18 +49,23 @@ 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 javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeModel; +import javax.swing.tree.TreePath; import java.awt.*; import java.awt.event.*; -import java.util.*; +import java.util.Arrays; import java.util.List; +import java.util.Map; +import java.util.Vector; /** * User: spLeaner */ public class UiInspectorAction extends ToggleAction implements DumbAware { - private UiInspector myInspector = null; + private UiInspector myInspector; @Override public boolean isSelected(AnActionEvent e) { @@ -73,7 +77,6 @@ public class UiInspectorAction extends ToggleAction implements DumbAware { if (state) { if (myInspector == null) { myInspector = new UiInspector(); - Toolkit.getDefaultToolkit().addAWTEventListener(myInspector, AWTEvent.MOUSE_EVENT_MASK); } UiInspectorNotification[] existing = @@ -83,10 +86,10 @@ public class UiInspectorAction extends ToggleAction implements DumbAware { } } else { - if (myInspector != null) { - Toolkit.getDefaultToolkit().removeAWTEventListener(myInspector); - Disposer.dispose(myInspector); - myInspector = null; + UiInspector inspector = myInspector; + myInspector = null; + if (inspector != null) { + Disposer.dispose(inspector); } } } @@ -100,18 +103,16 @@ public class UiInspectorAction extends ToggleAction implements DumbAware { private static class InspectorWindow extends JDialog { private InspectorTable myInspectorTable; - private UiInspector myUiInspector; private Component myComponent; private HighlightComponent myHighlightComponent; private HierarchyTree myHierarchyTree; private final JPanel myWrapperPanel; - private InspectorWindow(@NotNull Component component, UiInspector uiInspector) throws HeadlessException { + private InspectorWindow(@NotNull Component component) throws HeadlessException { super(findWindow(component)); Window window = findWindow(component); setModal(window instanceof JDialog && ((JDialog)window).isModal()); myComponent = component; - myUiInspector = uiInspector; getRootPane().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); @@ -247,33 +248,28 @@ public class UiInspectorAction extends ToggleAction implements DumbAware { } - private static class ComponentTreeCellRenderer extends JLabel implements TreeCellRenderer { - private ComponentTreeCellRenderer() { - setOpaque(true); + private static class ComponentTreeCellRenderer extends ColoredTreeCellRenderer { + ComponentTreeCellRenderer() { setFont(JBUI.Fonts.label(11)); 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) { + public void customizeCellRenderer(@NotNull 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(); + Class clazz0 = component.getClass(); + Class clazz = clazz0.isAnonymousClass() ? clazz0.getSuperclass() : clazz0; String name = component.getName(); - if (StringUtil.isEmpty(name)) { - name = component.getClass().getSimpleName(); - if (name.isEmpty()) { - name = component.getClass().getSuperclass().getSimpleName(); - } - } if (!selected) { if (!component.isVisible()) { @@ -292,13 +288,24 @@ public class UiInspectorAction extends ToggleAction implements DumbAware { background = new Color(31, 128, 8, 58); } } - setText(name); + append(clazz.getSimpleName()); + if (StringUtil.isNotEmpty(name)) { + append(" \"" + name + "\""); + } + append(": " + RectangleRenderer.toString(component.getBounds()), SimpleTextAttributes.GRAYED_ATTRIBUTES); + if (component.isOpaque()) { + append(", opaque", SimpleTextAttributes.GRAYED_ATTRIBUTES); + } + if (component.isDoubleBuffered()) { + append(", double-buffered", SimpleTextAttributes.GRAYED_ATTRIBUTES); + } + setIcon(new TwoColorsIcon(11, component.getForeground(), component.getBackground())); } setForeground(foreground); setBackground(background); - - return this; + + SpeedSearchUtil.applySpeedSearchHighlighting(tree, this, false, selected); } } @@ -310,6 +317,7 @@ public class UiInspectorAction extends ToggleAction implements DumbAware { setModel(buildModel(c)); setCellRenderer(new ComponentTreeCellRenderer()); getSelectionModel().addTreeSelectionListener(this); + new TreeSpeedSearch(this); } public void expandPath() { @@ -433,7 +441,8 @@ public class UiInspectorAction extends ToggleAction implements DumbAware { setLayout(new BorderLayout()); myModel = new InspectorTableModel(component); - final StripeTable table = new StripeTable(myModel); + StripeTable table = new StripeTable(myModel); + new TableSpeedSearch(table); TableColumnModel columnModel = table.getColumnModel(); TableColumn propertyColumn = columnModel.getColumn(0); @@ -644,14 +653,19 @@ public class UiInspectorAction extends ToggleAction implements DumbAware { private static class RectangleRenderer extends JLabel implements Renderer { public JComponent setValue(@NotNull final Rectangle value) { - setText(String.valueOf(value.x) + ":" + value.y + ", " + value.width + " x " + value.height); + setText(toString(value)); return this; } + + @NotNull + static String toString(@NotNull Rectangle r) { + return r.width + "x" + r.height + "@" + r.x + ":" + r.y; + } } private static class ColorRenderer extends JLabel implements Renderer { public JComponent setValue(@NotNull final Color value) { - setText("r:" + value.getRed() + ", g:" + value.getGreen() + ", b:" + value.getBlue()); + setText("r:" + value.getRed() + ", g:" + value.getGreen() + ", b:" + value.getBlue() + ", a:" + value.getAlpha()); setIcon(new ColorIcon(13, 11, value, true)); return this; } @@ -692,16 +706,16 @@ public class UiInspectorAction extends ToggleAction implements DumbAware { final String propertyName; final Object propertyValue; - PropertyBean(String propertyName, Object propertyValue) { - this.propertyName = propertyName; - this.propertyValue = propertyValue; + PropertyBean(String name, Object value) { + propertyName = name; + propertyValue = value; } } private static class InspectorTableModel extends AbstractTableModel { - private final List PROPERTIES = Arrays.asList( - "getClass", "ui", "getLocation", "getLocationOnScreen", + final List PROPERTIES = Arrays.asList( + "ui", "getLocation", "getLocationOnScreen", "getSize", "isOpaque", "getBorder", "getForeground", "getBackground", "getFont", "getMinimumSize", "getMaximumSize", "getPreferredSize", @@ -709,38 +723,41 @@ public class UiInspectorAction extends ToggleAction implements DumbAware { "getText", "isEditable", "getIcon", "getTooltipText", "getToolTipText", "getVisibleRect", "getLayout", - "isShowing", "isEnabled", "isVisible", "isFocusable", - "isFocusCycleRoot", "isFocusOwner", + "isShowing", "isEnabled", "isVisible", "isDoubleBuffered", + "isFocusable", "isFocusCycleRoot", "isFocusOwner", "isValid", "isDisplayable", "isLightweight" ); - private Component myComponent; - private List myProperties = new ArrayList(); + final Component myComponent; + final List myProperties = ContainerUtil.newArrayList(); - public InspectorTableModel(@NotNull final Component c) { + InspectorTableModel(@NotNull Component c) { myComponent = c; fillTable(); } - private void fillTable() { - Class cls = myComponent.getClass(); + void fillTable() { + Class clazz0 = myComponent.getClass(); + Class clazz = clazz0.isAnonymousClass() ? clazz0.getSuperclass() : clazz0; + myProperties.add(new PropertyBean("class", clazz.getName())); for (String name: PROPERTIES) { String propertyName = ObjectUtils.notNull(StringUtil.getPropertyName(name), name); Object propertyValue; try { - propertyValue = cls.getMethod(name).invoke(myComponent); + try { + propertyValue = clazz.getMethod(name).invoke(myComponent); + } + catch (Exception e) { + propertyValue = ReflectionUtil.findField(clazz, null, name).get(myComponent); + } + myProperties.add(new PropertyBean(propertyName, propertyValue)); } catch (Exception ignored) { - try { - propertyValue = ReflectionUtil.findField(cls, null, name).get(myComponent); - } - catch (Exception ignored2) { - continue; - } } - myProperties.add(new PropertyBean(propertyName, propertyValue)); } + Object addedAt = myComponent instanceof JComponent ? ((JComponent)myComponent).getClientProperty("uiInspector.addedAt") : null; + myProperties.add(new PropertyBean("added-at", addedAt)); } @Nullable @@ -784,7 +801,12 @@ public class UiInspectorAction extends ToggleAction implements DumbAware { private static class UiInspector implements AWTEventListener, Disposable { Map myComponentToInspector = new WeakKeyWeakValueHashMap(); + public UiInspector() { + Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.MOUSE_EVENT_MASK | AWTEvent.CONTAINER_EVENT_MASK); + } + public void dispose() { + Toolkit.getDefaultToolkit().removeAWTEventListener(this); for (InspectorWindow w : myComponentToInspector.values()) { w.close(); } @@ -800,7 +822,7 @@ public class UiInspectorAction extends ToggleAction implements DumbAware { window.toFront(); } else { - window = new InspectorWindow(c, this); + window = new InspectorWindow(c); myComponentToInspector.put(c, window); window.pack(); window.setVisible(true); @@ -810,30 +832,48 @@ public class UiInspectorAction extends ToggleAction implements DumbAware { public void eventDispatched(AWTEvent event) { if (event instanceof MouseEvent) { - final MouseEvent me = (MouseEvent)event; - if (me.isAltDown() && me.isControlDown()) { - switch (me.getID()) { - case MouseEvent.MOUSE_CLICKED: - if (me.getClickCount() == 1 && !me.isPopupTrigger()) { - Object source = me.getSource(); - if (source instanceof Component) { - showInspector((Component)source); - } - else { - Component owner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); - if (owner != null) { - showInspector(owner); - } - } - me.consume(); - } + processMouseEvent((MouseEvent)event); + } + else if (event instanceof ContainerEvent) { + processContainerEvent((ContainerEvent)event); + } + } - break; - default: - break; - } + private void processMouseEvent(MouseEvent me) { + if (me.isAltDown() && me.isControlDown()) { + switch (me.getID()) { + case MouseEvent.MOUSE_CLICKED: + if (me.getClickCount() == 1 && !me.isPopupTrigger()) { + Object source = me.getSource(); + if (source instanceof Component) { + showInspector((Component)source); + } + else { + Component owner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); + if (owner != null) { + showInspector(owner); + } + } + me.consume(); + } + + break; + default: + break; } } } + + private static void processContainerEvent(ContainerEvent event) { + Component child = event.getID() == ContainerEvent.COMPONENT_ADDED ? event.getChild() : null; + if (child instanceof JComponent && !(event.getSource() instanceof CellRendererPane)) { + String text = ExceptionUtil.getThrowableText(new Throwable()); + int first = text.indexOf("at com.intellij", text.indexOf("at java.awt")); + int last = text.indexOf("at java.awt.EventQueue"); + if (last == -1) last = text.length(); + String val = last > first && first > 0 ? text.substring(first, last): null; + ((JComponent)child).putClientProperty("uiInspector.addedAt", val); + } + } } }