| /* |
| * Copyright 2000-2014 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.tree.render; |
| |
| import com.intellij.debugger.DebuggerBundle; |
| import com.intellij.debugger.DebuggerContext; |
| import com.intellij.debugger.engine.DebugProcessImpl; |
| import com.intellij.debugger.engine.DebuggerUtils; |
| import com.intellij.debugger.engine.evaluation.EvaluateException; |
| import com.intellij.debugger.engine.evaluation.EvaluationContext; |
| import com.intellij.debugger.impl.DebuggerUtilsEx; |
| import com.intellij.debugger.ui.tree.DebuggerTreeNode; |
| import com.intellij.debugger.ui.tree.NodeDescriptor; |
| import com.intellij.debugger.ui.tree.ValueDescriptor; |
| import com.intellij.openapi.util.InvalidDataException; |
| import com.intellij.openapi.util.JDOMExternalizerUtil; |
| import com.intellij.openapi.util.WriteExternalException; |
| import com.intellij.psi.CommonClassNames; |
| import com.intellij.psi.PsiExpression; |
| import com.intellij.ui.classFilter.ClassFilter; |
| import com.intellij.xdebugger.impl.ui.XDebuggerUIConstants; |
| import com.sun.jdi.*; |
| import org.jdom.Element; |
| import org.jetbrains.annotations.NonNls; |
| |
| import java.util.List; |
| |
| import static com.intellij.psi.CommonClassNames.JAVA_LANG_STRING; |
| |
| public class ToStringRenderer extends NodeRendererImpl { |
| public static final @NonNls String UNIQUE_ID = "ToStringRenderer"; |
| |
| private boolean USE_CLASS_FILTERS = false; |
| private ClassFilter[] myClassFilters = ClassFilter.EMPTY_ARRAY; |
| |
| public ToStringRenderer() { |
| setEnabled(true); |
| } |
| |
| public String getUniqueId() { |
| return UNIQUE_ID; |
| } |
| |
| public @NonNls String getName() { |
| return "toString"; |
| } |
| |
| public void setName(String name) { |
| // prohibit change |
| } |
| |
| public ToStringRenderer clone() { |
| final ToStringRenderer cloned = (ToStringRenderer)super.clone(); |
| final ClassFilter[] classFilters = (myClassFilters.length > 0)? new ClassFilter[myClassFilters.length] : ClassFilter.EMPTY_ARRAY; |
| for (int idx = 0; idx < classFilters.length; idx++) { |
| classFilters[idx] = myClassFilters[idx].clone(); |
| } |
| cloned.myClassFilters = classFilters; |
| return cloned; |
| } |
| |
| public String calcLabel(final ValueDescriptor valueDescriptor, EvaluationContext evaluationContext, final DescriptorLabelListener labelListener) |
| throws EvaluateException { |
| final Value value = valueDescriptor.getValue(); |
| BatchEvaluator.getBatchEvaluator(evaluationContext.getDebugProcess()).invoke(new ToStringCommand(evaluationContext, value) { |
| public void evaluationResult(String message) { |
| valueDescriptor.setValueLabel( |
| // no need to add quotes and escape characters here, XValueTextRendererImpl handles the presentation |
| message == null? "" : /*"\"" + DebuggerUtils.convertToPresentationString(*/DebuggerUtilsEx.truncateString(message)/*) + "\""*/ |
| ); |
| labelListener.labelChanged(); |
| } |
| |
| public void evaluationError(String message) { |
| final String msg = value != null? message + " " + DebuggerBundle.message("evaluation.error.cannot.evaluate.tostring", value.type().name()) : message; |
| valueDescriptor.setValueLabelFailed(new EvaluateException(msg, null)); |
| labelListener.labelChanged(); |
| } |
| }); |
| return XDebuggerUIConstants.COLLECTING_DATA_MESSAGE; |
| } |
| |
| public boolean isUseClassFilters() { |
| return USE_CLASS_FILTERS; |
| } |
| |
| public void setUseClassFilters(boolean value) { |
| USE_CLASS_FILTERS = value; |
| } |
| |
| public boolean isApplicable(Type type) { |
| if(!(type instanceof ReferenceType)) { |
| return false; |
| } |
| |
| if(JAVA_LANG_STRING.equals(type.name())) { |
| return false; // do not render 'String' objects for performance reasons |
| } |
| |
| if(!overridesToString(type)) { |
| return false; |
| } |
| |
| if (USE_CLASS_FILTERS) { |
| if (!isFiltered(type)) { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| @SuppressWarnings({"HardCodedStringLiteral"}) |
| private static boolean overridesToString(Type type) { |
| if(type instanceof ClassType) { |
| final List<Method> methods = ((ClassType)type).methodsByName("toString", "()Ljava/lang/String;"); |
| for (Method method : methods) { |
| if (!(method.declaringType().name()).equals(CommonClassNames.JAVA_LANG_OBJECT)) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| public void buildChildren(Value value, ChildrenBuilder builder, EvaluationContext evaluationContext) { |
| final DebugProcessImpl debugProcess = (DebugProcessImpl)evaluationContext.getDebugProcess(); |
| debugProcess.getDefaultRenderer(value).buildChildren(value, builder, evaluationContext); |
| } |
| |
| public PsiExpression getChildValueExpression(DebuggerTreeNode node, DebuggerContext context) throws EvaluateException { |
| final Value parentValue = ((ValueDescriptor)node.getParent().getDescriptor()).getValue(); |
| final DebugProcessImpl debugProcess = (DebugProcessImpl)context.getDebugProcess(); |
| return debugProcess.getDefaultRenderer(parentValue).getChildValueExpression(node, context); |
| } |
| |
| public boolean isExpandable(Value value, EvaluationContext evaluationContext, NodeDescriptor parentDescriptor) { |
| final DebugProcessImpl debugProcess = (DebugProcessImpl)evaluationContext.getDebugProcess(); |
| return debugProcess.getDefaultRenderer(value).isExpandable(value, evaluationContext, parentDescriptor); |
| } |
| |
| @SuppressWarnings({"HardCodedStringLiteral"}) |
| public void readExternal(Element element) throws InvalidDataException { |
| super.readExternal(element); |
| final String value = JDOMExternalizerUtil.readField(element, "USE_CLASS_FILTERS"); |
| USE_CLASS_FILTERS = "true".equalsIgnoreCase(value); |
| myClassFilters = DebuggerUtilsEx.readFilters(element.getChildren("filter")); |
| } |
| |
| @SuppressWarnings({"HardCodedStringLiteral"}) |
| public void writeExternal(Element element) throws WriteExternalException { |
| super.writeExternal(element); |
| JDOMExternalizerUtil.writeField(element, "USE_CLASS_FILTERS", USE_CLASS_FILTERS? "true" : "false"); |
| DebuggerUtilsEx.writeFilters(element, "filter", myClassFilters); |
| } |
| |
| public ClassFilter[] getClassFilters() { |
| return myClassFilters; |
| } |
| |
| public void setClassFilters(ClassFilter[] classFilters) { |
| myClassFilters = classFilters != null? classFilters : ClassFilter.EMPTY_ARRAY; |
| } |
| |
| private boolean isFiltered(Type t) { |
| if (t instanceof ReferenceType) { |
| for (ClassFilter classFilter : myClassFilters) { |
| if (classFilter.isEnabled() && DebuggerUtils.getSuperType(t, classFilter.getPattern()) != null) { |
| return true; |
| } |
| } |
| } |
| return DebuggerUtilsEx.isFiltered(t.name(), myClassFilters); |
| } |
| } |