| /* |
| * Copyright 2000-2009 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.intellij.ui.debugger.extensions; |
| |
| import com.intellij.icons.AllIcons; |
| import com.intellij.openapi.actionSystem.*; |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.ui.Splitter; |
| import com.intellij.ui.ColoredListCellRenderer; |
| import com.intellij.ui.ScrollPaneFactory; |
| import com.intellij.ui.SimpleColoredText; |
| import com.intellij.ui.SimpleTextAttributes; |
| import com.intellij.ui.components.JBList; |
| import com.intellij.ui.debugger.UiDebuggerExtension; |
| |
| import javax.swing.*; |
| import javax.swing.event.ListSelectionEvent; |
| import javax.swing.event.ListSelectionListener; |
| import javax.swing.text.DefaultCaret; |
| import java.awt.*; |
| import java.beans.PropertyChangeEvent; |
| import java.beans.PropertyChangeListener; |
| import java.io.PrintWriter; |
| import java.io.StringWriter; |
| import java.util.ArrayList; |
| |
| public class FocusDebugger implements UiDebuggerExtension, PropertyChangeListener, ListSelectionListener { |
| |
| private static final Logger LOG = Logger.getInstance("#com.intellij.ui.debugger.extensions.FocusDebugger"); |
| |
| private JComponent myComponent; |
| |
| private JList myLog; |
| private DefaultListModel myLogModel; |
| private JEditorPane myAllocation; |
| |
| @Override |
| public JComponent getComponent() { |
| if (myComponent == null) { |
| myComponent = init(); |
| } |
| |
| return myComponent; |
| } |
| |
| private JComponent init() { |
| final JPanel result = new JPanel(new BorderLayout()); |
| |
| myLogModel = new DefaultListModel(); |
| myLog = new JBList(myLogModel); |
| myLog.setCellRenderer(new FocusElementRenderer()); |
| |
| |
| myAllocation = new JEditorPane(); |
| final DefaultCaret caret = new DefaultCaret(); |
| myAllocation.setCaret(caret); |
| caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE); |
| myAllocation.setEditable(false); |
| |
| |
| final Splitter splitter = new Splitter(true); |
| splitter.setFirstComponent(ScrollPaneFactory.createScrollPane(myLog)); |
| splitter.setSecondComponent(ScrollPaneFactory.createScrollPane(myAllocation)); |
| |
| myLog.addListSelectionListener(this); |
| |
| KeyboardFocusManager.getCurrentKeyboardFocusManager().addPropertyChangeListener(this); |
| |
| result.add(splitter, BorderLayout.CENTER); |
| |
| |
| final DefaultActionGroup group = new DefaultActionGroup(); |
| group.add(new ClearAction()); |
| |
| result.add(ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, group, true).getComponent(), BorderLayout.NORTH); |
| |
| return result; |
| } |
| |
| class ClearAction extends AnAction { |
| ClearAction() { |
| super("Clear", "", AllIcons.Actions.Cross); |
| } |
| |
| @Override |
| public void actionPerformed(AnActionEvent e) { |
| myLogModel.clear(); |
| } |
| } |
| |
| @Override |
| public void valueChanged(ListSelectionEvent e) { |
| if (myLog.getSelectedIndex() == -1) { |
| myAllocation.setText(null); |
| } else { |
| FocusElement element = (FocusElement)myLog.getSelectedValue(); |
| final StringWriter s = new StringWriter(); |
| final PrintWriter writer = new PrintWriter(s); |
| element.getAllocation().printStackTrace(writer); |
| myAllocation.setText(s.toString()); |
| } |
| } |
| |
| private boolean isInsideDebuggerDialog(Component c) { |
| final Window debuggerWindow = SwingUtilities.getWindowAncestor(myComponent); |
| if (!(debuggerWindow instanceof Dialog)) return false; |
| |
| return c == debuggerWindow || SwingUtilities.getWindowAncestor(c) == debuggerWindow; |
| } |
| |
| @Override |
| public void propertyChange(PropertyChangeEvent evt) { |
| final Object newValue = evt.getNewValue(); |
| final Object oldValue = evt.getOldValue(); |
| |
| boolean affectsDebugger = false; |
| |
| if (newValue instanceof Component && isInsideDebuggerDialog((Component)newValue)) { |
| affectsDebugger |= true; |
| } |
| |
| if (oldValue instanceof Component && isInsideDebuggerDialog((Component)oldValue)) { |
| affectsDebugger |= true; |
| } |
| |
| |
| |
| final SimpleColoredText text = new SimpleColoredText(); |
| text.append(evt.getPropertyName(), maybeGrayOut(new SimpleTextAttributes(SimpleTextAttributes.STYLE_UNDERLINE, null), affectsDebugger)); |
| text.append(" newValue=", maybeGrayOut(SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES, affectsDebugger)); |
| text.append(evt.getNewValue() + "", maybeGrayOut(SimpleTextAttributes.REGULAR_ATTRIBUTES, affectsDebugger)); |
| text.append(" oldValue=" + evt.getOldValue(), maybeGrayOut(SimpleTextAttributes.REGULAR_ATTRIBUTES, affectsDebugger)); |
| |
| |
| myLogModel.addElement(new FocusElement(text, new Throwable())); |
| SwingUtilities.invokeLater(new Runnable() { |
| @Override |
| public void run() { |
| if (myLog != null && myLog.isShowing()) { |
| final int h = myLog.getFixedCellHeight(); |
| myLog.scrollRectToVisible(new Rectangle(0, myLog.getPreferredSize().height - h, myLog.getWidth(), h)); |
| if (myLog.getModel().getSize() > 0) { |
| myLog.setSelectedIndex(myLog.getModel().getSize() - 1); |
| } |
| } |
| } |
| }); |
| } |
| |
| private SimpleTextAttributes maybeGrayOut(SimpleTextAttributes attr, boolean greyOut) { |
| return greyOut ? attr.derive(attr.getStyle(), Color.gray, attr.getBgColor(), attr.getWaveColor()) : attr; |
| } |
| |
| static class FocusElementRenderer extends ColoredListCellRenderer { |
| @Override |
| protected void customizeCellRenderer(JList list, Object value, int index, boolean selected, boolean hasFocus) { |
| clear(); |
| final FocusElement element = (FocusElement)value; |
| final SimpleColoredText text = element.getText(); |
| final ArrayList<String> strings = text.getTexts(); |
| final ArrayList<SimpleTextAttributes> attributes = element.getText().getAttributes(); |
| for (int i = 0; i < strings.size(); i++) { |
| append(strings.get(i), attributes.get(i)); |
| } |
| } |
| } |
| |
| static class FocusElement { |
| private final SimpleColoredText myText; |
| private final Throwable myAllocation; |
| |
| FocusElement(SimpleColoredText text, Throwable allocation) { |
| myText = text; |
| myAllocation = allocation; |
| } |
| |
| public SimpleColoredText getText() { |
| return myText; |
| } |
| |
| public Throwable getAllocation() { |
| return myAllocation; |
| } |
| } |
| |
| |
| @Override |
| public String getName() { |
| return "Focus"; |
| } |
| |
| @Override |
| public void disposeUiResources() { |
| myComponent = null; |
| KeyboardFocusManager.getCurrentKeyboardFocusManager().removePropertyChangeListener(this); |
| } |
| } |