| /* |
| * 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.debugger.ui.tree.render; |
| |
| import com.intellij.debugger.DebuggerContext; |
| import com.intellij.debugger.engine.DebuggerManagerThreadImpl; |
| import com.intellij.debugger.engine.evaluation.EvaluateException; |
| import com.intellij.debugger.engine.evaluation.EvaluationContext; |
| import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; |
| import com.intellij.debugger.settings.ViewsGeneralSettings; |
| import com.intellij.debugger.ui.impl.watch.ArrayElementDescriptorImpl; |
| import com.intellij.debugger.ui.impl.watch.MessageDescriptor; |
| import com.intellij.debugger.ui.impl.watch.NodeManagerImpl; |
| import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl; |
| import com.intellij.debugger.ui.tree.DebuggerTreeNode; |
| import com.intellij.debugger.ui.tree.NodeDescriptor; |
| import com.intellij.debugger.ui.tree.NodeDescriptorFactory; |
| import com.intellij.debugger.ui.tree.ValueDescriptor; |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.roots.LanguageLevelProjectExtension; |
| import com.intellij.openapi.util.DefaultJDOMExternalizer; |
| import com.intellij.openapi.util.InvalidDataException; |
| import com.intellij.openapi.util.WriteExternalException; |
| import com.intellij.pom.java.LanguageLevel; |
| import com.intellij.psi.JavaPsiFacade; |
| import com.intellij.psi.PsiElementFactory; |
| import com.intellij.psi.PsiExpression; |
| import com.intellij.util.IncorrectOperationException; |
| import com.sun.jdi.ArrayReference; |
| import com.sun.jdi.ArrayType; |
| import com.sun.jdi.Type; |
| import com.sun.jdi.Value; |
| import org.jdom.Element; |
| import org.jetbrains.annotations.NonNls; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.ListIterator; |
| |
| /** |
| * User: lex |
| * Date: Sep 18, 2003 |
| * Time: 3:07:19 PM |
| */ |
| public class ArrayRenderer extends NodeRendererImpl{ |
| private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.tree.render.ArrayRenderer"); |
| |
| public static final @NonNls String UNIQUE_ID = "ArrayRenderer"; |
| |
| public int START_INDEX = 0; |
| public int END_INDEX = 100; |
| public int ENTRIES_LIMIT = 101; |
| private final static String MORE_ELEMENTS = "..."; |
| |
| private boolean myForced = false; |
| |
| public ArrayRenderer() { |
| myProperties.setEnabled(true); |
| } |
| |
| public String getUniqueId() { |
| return UNIQUE_ID; |
| } |
| |
| public boolean isEnabled() { |
| return myProperties.isEnabled(); |
| } |
| |
| public void setEnabled(boolean enabled) { |
| myProperties.setEnabled(enabled); |
| } |
| |
| public @NonNls String getName() { |
| return "Array"; |
| } |
| |
| public void setName(String text) { |
| LOG.assertTrue(false); |
| } |
| |
| public ArrayRenderer clone() { |
| return (ArrayRenderer)super.clone(); |
| } |
| |
| public String calcLabel(ValueDescriptor descriptor, EvaluationContext evaluationContext, DescriptorLabelListener listener) throws EvaluateException { |
| return ClassRenderer.calcLabel(descriptor); |
| } |
| |
| public void setForced(boolean forced) { |
| myForced = forced; |
| } |
| |
| public void buildChildren(Value value, ChildrenBuilder builder, EvaluationContext evaluationContext) { |
| DebuggerManagerThreadImpl.assertIsManagerThread(); |
| List<DebuggerTreeNode> children = new ArrayList<DebuggerTreeNode>(); |
| NodeManagerImpl nodeManager = (NodeManagerImpl)builder.getNodeManager(); |
| NodeDescriptorFactory descriptorFactory = builder.getDescriptorManager(); |
| |
| if (!myForced) { |
| builder.initChildrenArrayRenderer(this); |
| } |
| |
| ArrayReference array = (ArrayReference)value; |
| if (array.length() > 0) { |
| int added = 0; |
| |
| if(ENTRIES_LIMIT > END_INDEX - START_INDEX + 1) { |
| ENTRIES_LIMIT = END_INDEX - START_INDEX; |
| } |
| |
| if(ENTRIES_LIMIT <= 0) { |
| ENTRIES_LIMIT = 1; |
| } |
| |
| if(array.length() - 1 >= START_INDEX) { |
| int start = START_INDEX; |
| int end = array.length() - 1 < END_INDEX ? array.length() - 1 : END_INDEX; |
| |
| int idx; |
| |
| for (idx = start; idx <= end; idx++) { |
| DebuggerTreeNode arrayItemNode = nodeManager.createNode(descriptorFactory.getArrayItemDescriptor(builder.getParentDescriptor(), array, idx), evaluationContext); |
| |
| if (arrayItemNode == null) continue; |
| if (ViewsGeneralSettings.getInstance().HIDE_NULL_ARRAY_ELEMENTS) { |
| // need to init value to be able to ask for null |
| ValueDescriptorImpl descriptor = (ValueDescriptorImpl)arrayItemNode.getDescriptor(); |
| descriptor.setContext((EvaluationContextImpl)evaluationContext); |
| if (descriptor.isNull()) continue; |
| } |
| //if(added >= (ENTRIES_LIMIT + 1)/ 2) break; |
| children.add(arrayItemNode); |
| added++; |
| } |
| |
| start = idx; |
| |
| //List<DebuggerTreeNode> childrenTail = new ArrayList<DebuggerTreeNode>(); |
| //for (idx = end; idx >= start; idx--) { |
| // DebuggerTreeNode arrayItemNode = nodeManager.createNode(descriptorFactory.getArrayItemDescriptor(builder.getParentDescriptor(), array, idx), evaluationContext); |
| // |
| // if (arrayItemNode == null) continue; |
| // if (ViewsGeneralSettings.getInstance().HIDE_NULL_ARRAY_ELEMENTS && ((ValueDescriptorImpl)arrayItemNode.getDescriptor()).isNull()) continue; |
| // if(added >= ENTRIES_LIMIT) break; |
| // childrenTail.add(arrayItemNode); |
| // added++; |
| //} |
| |
| //array is printed in the following way |
| // ... |
| // items1...itemENTRIES_LIMIT/2 |
| // ... |
| // itemENTRIES_LIMIT/2+1...itemENTRIES_LIMIT |
| // ... |
| |
| //when itemENTRIES_LIMIT/2+1...itemENTRIES_LIMIT set is empty, we should not add middle "..." node |
| //if(idx >= start && !(ENTRIES_LIMIT == 1 && END_INDEX < array.length())) { |
| // children.add(nodeManager.createMessageNode(new MessageDescriptor(MORE_ELEMENTS, MessageDescriptor.SPECIAL))); |
| //} |
| |
| //for (ListIterator<DebuggerTreeNode> iterator = childrenTail.listIterator(childrenTail.size()); iterator.hasPrevious();) { |
| // DebuggerTreeNode debuggerTreeNode = iterator.previous(); |
| // children.add(debuggerTreeNode); |
| //} |
| } |
| |
| if (added == 0) { |
| if(START_INDEX == 0 && array.length() - 1 <= END_INDEX) { |
| children.add(nodeManager.createMessageNode(MessageDescriptor.ALL_ELEMENTS_IN_RANGE_ARE_NULL.getLabel())); |
| } |
| else { |
| children.add(nodeManager.createMessageNode(MessageDescriptor.ALL_ELEMENTS_IN_VISIBLE_RANGE_ARE_NULL.getLabel())); |
| } |
| } |
| else { |
| //if(START_INDEX > 0) { |
| // children.add(0, nodeManager.createMessageNode(new MessageDescriptor(MORE_ELEMENTS, MessageDescriptor.SPECIAL))); |
| //} |
| |
| if(!myForced && END_INDEX < array.length() - 1) { |
| //children.add(nodeManager.createMessageNode(new MessageDescriptor(MORE_ELEMENTS, MessageDescriptor.SPECIAL))); |
| builder.setRemaining(array.length()-END_INDEX); |
| } |
| } |
| } |
| builder.setChildren(children); |
| } |
| |
| public void readExternal(Element element) throws InvalidDataException { |
| super.readExternal(element); |
| DefaultJDOMExternalizer.readExternal(this, element); |
| } |
| |
| public void writeExternal(Element element) throws WriteExternalException { |
| super.writeExternal(element); |
| DefaultJDOMExternalizer.writeExternal(this, element); |
| } |
| |
| public PsiExpression getChildValueExpression(DebuggerTreeNode node, DebuggerContext context) { |
| LOG.assertTrue(node.getDescriptor() instanceof ArrayElementDescriptorImpl, node.getDescriptor().getClass().getName()); |
| ArrayElementDescriptorImpl descriptor = (ArrayElementDescriptorImpl)node.getDescriptor(); |
| |
| PsiElementFactory elementFactory = JavaPsiFacade.getInstance(node.getProject()).getElementFactory(); |
| try { |
| LanguageLevel languageLevel = LanguageLevelProjectExtension.getInstance(node.getProject()).getLanguageLevel(); |
| return elementFactory.createExpressionFromText("this[" + descriptor.getIndex() + "]", elementFactory.getArrayClass(languageLevel)); |
| } |
| catch (IncorrectOperationException e) { |
| LOG.error(e); |
| return null; |
| } |
| } |
| |
| public boolean isExpandable(Value value, EvaluationContext evaluationContext, NodeDescriptor parentDescriptor) { |
| return value instanceof ArrayReference && ((ArrayReference)value).length() > 0; |
| } |
| |
| public boolean isApplicable(Type type) { |
| return (type instanceof ArrayType); |
| } |
| } |