| /* |
| * Copyright 2000-2013 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.debugger.ui.impl; |
| |
| import com.intellij.debugger.engine.evaluation.EvaluateException; |
| import com.intellij.debugger.impl.DebuggerContextImpl; |
| import com.intellij.debugger.impl.DebuggerUtilsEx; |
| import com.intellij.debugger.ui.impl.watch.*; |
| import com.intellij.debugger.ui.tree.ValueDescriptor; |
| import com.intellij.icons.AllIcons; |
| import com.intellij.ide.highlighter.JavaHighlightingColors; |
| import com.intellij.openapi.editor.colors.EditorColorsScheme; |
| import com.intellij.openapi.editor.markup.TextAttributes; |
| import com.intellij.openapi.util.text.StringUtil; |
| import com.intellij.ui.*; |
| import com.intellij.util.PlatformIcons; |
| import com.intellij.xdebugger.impl.ui.DebuggerUIUtil; |
| import com.intellij.xdebugger.impl.ui.XDebuggerUIConstants; |
| import com.intellij.xdebugger.impl.ui.tree.ValueMarkup; |
| import org.jetbrains.annotations.Nullable; |
| |
| import javax.swing.*; |
| import java.awt.*; |
| |
| public class DebuggerTreeRenderer extends ColoredTreeCellRenderer { |
| |
| private static final SimpleTextAttributes DEFAULT_ATTRIBUTES = new SimpleTextAttributes(Font.PLAIN, null); |
| private static final SimpleTextAttributes SPECIAL_NODE_ATTRIBUTES = new SimpleTextAttributes(Font.PLAIN, new JBColor(Color.lightGray, Gray._130)); |
| private static final SimpleTextAttributes OBJECT_ID_HIGHLIGHT_ATTRIBUTES = new SimpleTextAttributes(Font.PLAIN, new JBColor(Color.lightGray, Gray._130)); |
| |
| public void customizeCellRenderer(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { |
| final DebuggerTreeNodeImpl node = (DebuggerTreeNodeImpl) value; |
| |
| if (node != null) { |
| final SimpleColoredText text = node.getText(); |
| if (text != null) { |
| text.appendToComponent(this); |
| } |
| setIcon(node.getIcon()); |
| } |
| } |
| |
| @Nullable |
| public static Icon getDescriptorIcon(NodeDescriptorImpl descriptor) { |
| Icon nodeIcon = null; |
| if (descriptor instanceof ThreadGroupDescriptorImpl) { |
| nodeIcon = (((ThreadGroupDescriptorImpl)descriptor).isCurrent() ? AllIcons.Debugger.ThreadGroupCurrent : AllIcons.Debugger.ThreadGroup); |
| } |
| else if (descriptor instanceof ThreadDescriptorImpl) { |
| ThreadDescriptorImpl threadDescriptor = (ThreadDescriptorImpl)descriptor; |
| nodeIcon = threadDescriptor.getIcon(); |
| } |
| else if (descriptor instanceof StackFrameDescriptorImpl) { |
| StackFrameDescriptorImpl stackDescriptor = (StackFrameDescriptorImpl)descriptor; |
| nodeIcon = stackDescriptor.getIcon(); |
| } |
| else if (descriptor instanceof ValueDescriptorImpl) { |
| nodeIcon = getValueIcon((ValueDescriptorImpl)descriptor); |
| } |
| else if (descriptor instanceof MessageDescriptor) { |
| MessageDescriptor messageDescriptor = (MessageDescriptor)descriptor; |
| if (messageDescriptor.getKind() == MessageDescriptor.ERROR) { |
| nodeIcon = XDebuggerUIConstants.ERROR_MESSAGE_ICON; |
| } |
| else if (messageDescriptor.getKind() == MessageDescriptor.INFORMATION) { |
| nodeIcon = XDebuggerUIConstants.INFORMATION_MESSAGE_ICON; |
| } |
| else if (messageDescriptor.getKind() == MessageDescriptor.SPECIAL) { |
| nodeIcon = null; |
| } |
| } |
| else if (descriptor instanceof StaticDescriptorImpl) { |
| nodeIcon = AllIcons.Nodes.Static; |
| } |
| |
| return nodeIcon; |
| } |
| |
| public static Icon getValueIcon(ValueDescriptorImpl valueDescriptor) { |
| Icon nodeIcon; |
| if (valueDescriptor instanceof FieldDescriptorImpl && ((FieldDescriptorImpl)valueDescriptor).isStatic()) { |
| nodeIcon = PlatformIcons.FIELD_ICON; |
| } |
| else if (valueDescriptor.isArray()) { |
| nodeIcon = AllIcons.Debugger.Db_array; |
| } |
| else if (valueDescriptor.isPrimitive()) { |
| nodeIcon = AllIcons.Debugger.Db_primitive; |
| } |
| else { |
| if (valueDescriptor instanceof WatchItemDescriptor) { |
| nodeIcon = AllIcons.Debugger.Watch; |
| } |
| else { |
| nodeIcon = AllIcons.Debugger.Value; |
| } |
| } |
| final Icon valueIcon = valueDescriptor.getValueIcon(); |
| if (nodeIcon != null && valueIcon != null) { |
| final RowIcon composite = new RowIcon(2); |
| composite.setIcon(nodeIcon, 0); |
| composite.setIcon(valueIcon, 1); |
| nodeIcon = composite; |
| } |
| return nodeIcon; |
| } |
| |
| public static SimpleColoredText getDescriptorText(DebuggerContextImpl debuggerContext, |
| NodeDescriptorImpl descriptor, |
| EditorColorsScheme colorsScheme, |
| boolean multiline) { |
| return getDescriptorText(debuggerContext, descriptor, colorsScheme, multiline, true); |
| } |
| |
| public static SimpleColoredText getDescriptorText(final DebuggerContextImpl debuggerContext, NodeDescriptorImpl descriptor, boolean multiline) { |
| return getDescriptorText(debuggerContext, descriptor, DebuggerUIUtil.getColorScheme(null), multiline, true); |
| } |
| |
| public static SimpleColoredText getDescriptorTitle(final DebuggerContextImpl debuggerContext, NodeDescriptorImpl descriptor) { |
| return getDescriptorText(debuggerContext, descriptor, DebuggerUIUtil.getColorScheme(null), false, false); |
| } |
| |
| private static SimpleColoredText getDescriptorText(DebuggerContextImpl debuggerContext, |
| NodeDescriptorImpl descriptor, |
| EditorColorsScheme colorScheme, |
| boolean multiline, |
| boolean appendValue) { |
| SimpleColoredText descriptorText = new SimpleColoredText(); |
| |
| String text; |
| String nodeName; |
| |
| if (descriptor == null) { |
| text = ""; |
| nodeName = null; |
| } |
| else { |
| text = descriptor.getLabel(); |
| nodeName = descriptor.getName(); |
| } |
| |
| if(text.equals(XDebuggerUIConstants.COLLECTING_DATA_MESSAGE)) { |
| descriptorText.append(XDebuggerUIConstants.COLLECTING_DATA_MESSAGE, XDebuggerUIConstants.COLLECTING_DATA_HIGHLIGHT_ATTRIBUTES); |
| return descriptorText; |
| } |
| |
| if (descriptor instanceof ValueDescriptor) { |
| final ValueMarkup markup = ((ValueDescriptor)descriptor).getMarkup(debuggerContext.getDebugProcess()); |
| if (markup != null) { |
| descriptorText.append("[" + markup.getText() + "] ", new SimpleTextAttributes(SimpleTextAttributes.STYLE_BOLD, markup.getColor())); |
| } |
| } |
| |
| String[] strings = breakString(text, nodeName); |
| |
| if (strings[0] != null) { |
| if (descriptor instanceof MessageDescriptor && ((MessageDescriptor)descriptor).getKind() == MessageDescriptor.SPECIAL) { |
| descriptorText.append(strings[0], SPECIAL_NODE_ATTRIBUTES); |
| } |
| else { |
| descriptorText.append(strings[0], DEFAULT_ATTRIBUTES); |
| } |
| } |
| if (strings[1] != null) { |
| descriptorText.append(strings[1], XDebuggerUIConstants.VALUE_NAME_ATTRIBUTES); |
| } |
| if (strings[2] != null) { |
| if (descriptor instanceof ValueDescriptorImpl) { |
| if(multiline && strings[2].indexOf('\n') >=0) { |
| strings = breakString(strings[2], "="); |
| if(strings[2] != null) { |
| strings[2] = strings[0] + strings[1] + "\n" + strings[2]; |
| } |
| } |
| |
| |
| ValueDescriptorImpl valueDescriptor = (ValueDescriptorImpl)descriptor; |
| String valueLabel = valueDescriptor.getValueLabel(); |
| |
| strings = breakString(strings[2], valueLabel); |
| if (strings[0] != null) { |
| descriptorText.append(strings[0], DEFAULT_ATTRIBUTES); |
| } |
| if (appendValue && strings[1] != null) { |
| if(valueLabel != null && StringUtil.startsWithChar(valueLabel, '{') && valueLabel.indexOf('}') > 0 && !StringUtil.endsWithChar(valueLabel, '}')) { |
| int idx = valueLabel.indexOf('}'); |
| String objectId = valueLabel.substring(0, idx + 1); |
| valueLabel = valueLabel.substring(idx + 1); |
| descriptorText.append(objectId, OBJECT_ID_HIGHLIGHT_ATTRIBUTES); |
| } |
| |
| valueLabel = DebuggerUtilsEx.truncateString(valueLabel); |
| |
| final SimpleTextAttributes valueLabelAttribs; |
| if (valueDescriptor.isDirty()) { |
| valueLabelAttribs = XDebuggerUIConstants.CHANGED_VALUE_ATTRIBUTES; |
| } |
| else { |
| TextAttributes attributes = null; |
| if (valueDescriptor.isNull()){ |
| attributes = colorScheme.getAttributes(JavaHighlightingColors.KEYWORD); |
| } |
| else if (valueDescriptor.isString()) { |
| attributes = colorScheme.getAttributes(JavaHighlightingColors.STRING); |
| } |
| valueLabelAttribs = attributes != null? SimpleTextAttributes.fromTextAttributes(attributes) : DEFAULT_ATTRIBUTES; |
| } |
| |
| final EvaluateException exception = descriptor.getEvaluateException(); |
| if(exception != null) { |
| final String errorMessage = exception.getMessage(); |
| if(valueLabel.endsWith(errorMessage)) { |
| appendValueTextWithEscapesRendering(descriptorText, valueLabel.substring(0, valueLabel.length() - errorMessage.length()), valueLabelAttribs, colorScheme); |
| descriptorText.append(errorMessage, XDebuggerUIConstants.EXCEPTION_ATTRIBUTES); |
| } |
| else { |
| appendValueTextWithEscapesRendering(descriptorText, valueLabel, valueLabelAttribs, colorScheme); |
| descriptorText.append(errorMessage, XDebuggerUIConstants.EXCEPTION_ATTRIBUTES); |
| } |
| } |
| else { |
| if(valueLabel.equals(XDebuggerUIConstants.COLLECTING_DATA_MESSAGE)) { |
| descriptorText.append(XDebuggerUIConstants.COLLECTING_DATA_MESSAGE, XDebuggerUIConstants.COLLECTING_DATA_HIGHLIGHT_ATTRIBUTES); |
| } |
| else { |
| appendValueTextWithEscapesRendering(descriptorText, valueLabel, valueLabelAttribs, colorScheme); |
| } |
| } |
| } |
| } |
| else { |
| descriptorText.append(strings[2], DEFAULT_ATTRIBUTES); |
| } |
| } |
| |
| return descriptorText; |
| } |
| |
| private static void appendValueTextWithEscapesRendering(SimpleColoredText descriptorText, |
| String valueText, |
| SimpleTextAttributes attribs, |
| EditorColorsScheme colorScheme) { |
| SimpleTextAttributes escapeAttribs = null; |
| final StringBuilder buf = new StringBuilder(); |
| boolean slashFound = false; |
| for (int idx= 0; idx < valueText.length(); idx++) { |
| final char ch = valueText.charAt(idx); |
| if (slashFound) { |
| slashFound = false; |
| if (ch == '\\' || ch == '\"' || ch == 'b'|| ch == 't'|| ch == 'n'|| ch == 'f'|| ch == 'r' ) { |
| if (buf.length() > 0) { |
| descriptorText.append(buf.toString(), attribs); |
| buf.setLength(0); |
| } |
| |
| if (escapeAttribs == null) { // lazy init |
| TextAttributes fromHighlighter = colorScheme.getAttributes(JavaHighlightingColors.VALID_STRING_ESCAPE); |
| if (fromHighlighter != null) { |
| escapeAttribs = SimpleTextAttributes.fromTextAttributes(fromHighlighter); |
| } |
| else { |
| escapeAttribs = DEFAULT_ATTRIBUTES.derive(SimpleTextAttributes.STYLE_BOLD, JBColor.GRAY, null, null); |
| } |
| } |
| |
| if (ch != '\\' && ch != '\"') { |
| descriptorText.append("\\", escapeAttribs); |
| } |
| descriptorText.append(String.valueOf(ch), escapeAttribs); |
| } |
| else { |
| buf.append('\\').append(ch); |
| } |
| } |
| else { |
| if (ch == '\\') { |
| slashFound = true; |
| } |
| else { |
| buf.append(ch); |
| } |
| } |
| } |
| if (buf.length() > 0) { |
| descriptorText.append(buf.toString(), attribs); |
| } |
| } |
| |
| private static String[] breakString(String source, String substr) { |
| if (substr != null && substr.length() > 0) { |
| int index = Math.max(source.indexOf(substr), 0); |
| String prefix = (index > 0) ? source.substring(0, index) : null; |
| index += substr.length(); |
| String suffix = (index < source.length() - 1) ? source.substring(index) : null; |
| return new String[]{prefix, substr, suffix}; |
| } |
| return new String[]{source, null, null}; |
| } |
| } |