blob: 7454cfab889013b609edaac2624676eab82e07da [file] [log] [blame]
/*
* 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);
}
}