| /* |
| * 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.impl.watch; |
| |
| import com.intellij.debugger.engine.StackFrameContext; |
| import com.intellij.debugger.engine.evaluation.EvaluateException; |
| import com.intellij.debugger.engine.evaluation.TextWithImports; |
| import com.intellij.debugger.engine.jdi.LocalVariableProxy; |
| import com.intellij.debugger.engine.jdi.StackFrameProxy; |
| import com.intellij.debugger.engine.jdi.ThreadReferenceProxy; |
| import com.intellij.debugger.impl.descriptors.data.*; |
| import com.intellij.debugger.jdi.LocalVariableProxyImpl; |
| import com.intellij.debugger.jdi.StackFrameProxyImpl; |
| import com.intellij.debugger.jdi.ThreadGroupReferenceProxyImpl; |
| import com.intellij.debugger.jdi.ThreadReferenceProxyImpl; |
| import com.intellij.debugger.ui.tree.NodeDescriptor; |
| import com.intellij.debugger.ui.tree.NodeDescriptorFactory; |
| import com.intellij.debugger.ui.tree.UserExpressionDescriptor; |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.project.Project; |
| import com.sun.jdi.*; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import java.util.HashMap; |
| |
| public class NodeDescriptorFactoryImpl implements NodeDescriptorFactory { |
| private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.impl.watch.NodeDescriptorFactoryImpl"); |
| private DescriptorTree myCurrentHistoryTree = new DescriptorTree(true); |
| |
| private DescriptorTreeSearcher myDescriptorSearcher; |
| private DescriptorTreeSearcher myDisplayDescriptorSearcher; |
| |
| protected final Project myProject; |
| |
| public NodeDescriptorFactoryImpl(Project project) { |
| myProject = project; |
| myDescriptorSearcher = new DescriptorTreeSearcher(new MarkedDescriptorTree()); |
| myDisplayDescriptorSearcher = new DisplayDescriptorTreeSearcher(new MarkedDescriptorTree()); |
| } |
| |
| public void dispose() { |
| myCurrentHistoryTree.clear(); |
| myDescriptorSearcher.clear(); |
| myDisplayDescriptorSearcher.clear(); |
| } |
| |
| public <T extends NodeDescriptor> T getDescriptor(NodeDescriptor parent, DescriptorData<T> key) { |
| final T descriptor = key.createDescriptor(myProject); |
| |
| final T oldDescriptor = findDescriptor(parent, descriptor, key); |
| |
| if(oldDescriptor != null && oldDescriptor.getClass() == descriptor.getClass()) { |
| descriptor.setAncestor(oldDescriptor); |
| } |
| else { |
| T displayDescriptor = findDisplayDescriptor(parent, descriptor, key.getDisplayKey()); |
| if(displayDescriptor != null) { |
| descriptor.displayAs(displayDescriptor); |
| } |
| } |
| |
| myCurrentHistoryTree.addChild(parent, descriptor); |
| |
| return descriptor; |
| } |
| |
| @Nullable |
| protected <T extends NodeDescriptor>T findDisplayDescriptor(NodeDescriptor parent, T descriptor, DisplayKey<T> key) { |
| return myDisplayDescriptorSearcher.search(parent, descriptor, key); |
| } |
| |
| @Nullable |
| protected <T extends NodeDescriptor> T findDescriptor(NodeDescriptor parent, T descriptor, DescriptorData<T> key) { |
| return myDescriptorSearcher.search(parent, descriptor, key); |
| } |
| |
| public DescriptorTree getCurrentHistoryTree() { |
| return myCurrentHistoryTree; |
| } |
| |
| public void deriveHistoryTree(DescriptorTree tree, final StackFrameContext context) { |
| deriveHistoryTree(tree, context.getFrameProxy()); |
| } |
| |
| public void deriveHistoryTree(DescriptorTree tree, final StackFrameProxy frameProxy) { |
| |
| final MarkedDescriptorTree descriptorTree = new MarkedDescriptorTree(); |
| final MarkedDescriptorTree displayDescriptorTree = new MarkedDescriptorTree(); |
| |
| tree.dfst(new DescriptorTree.DFSTWalker() { |
| @Override |
| public void visit(NodeDescriptor parent, NodeDescriptor child) { |
| final DescriptorData<NodeDescriptor> descriptorData = DescriptorData.getDescriptorData(child); |
| descriptorTree.addChild(parent, child, descriptorData); |
| displayDescriptorTree.addChild(parent, child, descriptorData.getDisplayKey()); |
| } |
| }); |
| |
| myDescriptorSearcher = new DescriptorTreeSearcher(descriptorTree); |
| myDisplayDescriptorSearcher = new DisplayDescriptorTreeSearcher(displayDescriptorTree); |
| |
| myCurrentHistoryTree = createDescriptorTree(frameProxy, tree); |
| } |
| |
| private static DescriptorTree createDescriptorTree(final StackFrameProxy frameProxy, final DescriptorTree fromTree) { |
| int frameCount = -1; |
| int frameIndex = -1; |
| if (frameProxy != null) { |
| try { |
| final ThreadReferenceProxy threadReferenceProxy = frameProxy.threadProxy(); |
| frameCount = threadReferenceProxy.frameCount(); |
| frameIndex = frameProxy.getFrameIndex(); |
| } |
| catch (EvaluateException e) { |
| // ignored |
| } |
| } |
| final boolean isInitial = !fromTree.frameIdEquals(frameCount, frameIndex); |
| DescriptorTree descriptorTree = new DescriptorTree(isInitial); |
| descriptorTree.setFrameId(frameCount, frameIndex); |
| return descriptorTree; |
| } |
| |
| @Override |
| public ArrayElementDescriptorImpl getArrayItemDescriptor(NodeDescriptor parent, ArrayReference array, int index) { |
| return getDescriptor(parent, new ArrayItemData(array, index)); |
| } |
| |
| @Override |
| public FieldDescriptorImpl getFieldDescriptor(NodeDescriptor parent, ObjectReference objRef, Field field) { |
| final DescriptorData<FieldDescriptorImpl> descriptorData; |
| if (objRef == null ) { |
| if (!field.isStatic()) { |
| LOG.error("Object reference is null for non-static field: " + field); |
| } |
| descriptorData = new StaticFieldData(field); |
| } |
| else { |
| descriptorData = new FieldData(objRef, field); |
| } |
| return getDescriptor(parent, descriptorData); |
| } |
| |
| @Override |
| public LocalVariableDescriptorImpl getLocalVariableDescriptor(NodeDescriptor parent, LocalVariableProxy local) { |
| return getDescriptor(parent, new LocalData((LocalVariableProxyImpl)local)); |
| } |
| |
| public ArgumentValueDescriptorImpl getArgumentValueDescriptor(NodeDescriptor parent, int index, Value value, final String name) { |
| return getDescriptor(parent, new ArgValueData(index, value, name)); |
| } |
| |
| public StackFrameDescriptorImpl getStackFrameDescriptor(@Nullable NodeDescriptorImpl parent, @NotNull StackFrameProxyImpl frameProxy) { |
| return getDescriptor(parent, new StackFrameData(frameProxy)); |
| } |
| |
| public StaticDescriptorImpl getStaticDescriptor(NodeDescriptorImpl parent, ReferenceType refType) {//static is unique |
| return getDescriptor(parent, new StaticData(refType)); |
| } |
| |
| public ValueDescriptorImpl getThisDescriptor(NodeDescriptorImpl parent, Value value) { |
| return getDescriptor(parent, new ThisData()); |
| } |
| |
| public ValueDescriptorImpl getMethodReturnValueDescriptor(NodeDescriptorImpl parent, Method method, Value value) { |
| return getDescriptor(parent, new MethodReturnValueData(method, value)); |
| } |
| |
| public ValueDescriptorImpl getThrownExceptionObjectDescriptor(NodeDescriptorImpl parent, ObjectReference exceptionObject) { |
| return getDescriptor(parent, new ThrownExceptionValueData(exceptionObject)); |
| } |
| |
| public ThreadDescriptorImpl getThreadDescriptor(NodeDescriptorImpl parent, ThreadReferenceProxyImpl thread) { |
| return getDescriptor(parent, new ThreadData(thread)); |
| } |
| |
| public ThreadGroupDescriptorImpl getThreadGroupDescriptor(NodeDescriptorImpl parent, ThreadGroupReferenceProxyImpl group) { |
| return getDescriptor(parent, new ThreadGroupData(group)); |
| } |
| |
| @Override |
| public UserExpressionDescriptor getUserExpressionDescriptor(NodeDescriptor parent, final DescriptorData<UserExpressionDescriptor> data) { |
| return getDescriptor(parent, data); |
| } |
| |
| public WatchItemDescriptor getWatchItemDescriptor(NodeDescriptor parent, TextWithImports text, @Nullable Value value){ |
| return getDescriptor(parent, new WatchItemData(text, value)); |
| } |
| |
| private static class DescriptorTreeSearcher { |
| private final MarkedDescriptorTree myDescriptorTree; |
| |
| private final HashMap<NodeDescriptor, NodeDescriptor> mySearchedDescriptors = new HashMap<NodeDescriptor, NodeDescriptor>(); |
| |
| public DescriptorTreeSearcher(MarkedDescriptorTree descriptorTree) { |
| myDescriptorTree = descriptorTree; |
| } |
| |
| @Nullable |
| public <T extends NodeDescriptor> T search(NodeDescriptor parent, T descriptor, DescriptorKey<T> key) { |
| final T result; |
| if(parent == null) { |
| result = myDescriptorTree.getChild(null, key); |
| } |
| else { |
| final NodeDescriptor parentDescriptor = getSearched(parent); |
| result = parentDescriptor != null ? myDescriptorTree.getChild(parentDescriptor, key) : null; |
| } |
| if(result != null) { |
| mySearchedDescriptors.put(descriptor, result); |
| } |
| return result; |
| } |
| |
| protected NodeDescriptor getSearched(NodeDescriptor parent) { |
| return mySearchedDescriptors.get(parent); |
| } |
| |
| public void clear() { |
| mySearchedDescriptors.clear(); |
| myDescriptorTree.clear(); |
| } |
| } |
| |
| private class DisplayDescriptorTreeSearcher extends DescriptorTreeSearcher { |
| public DisplayDescriptorTreeSearcher(MarkedDescriptorTree descriptorTree) { |
| super(descriptorTree); |
| } |
| |
| @Override |
| protected NodeDescriptor getSearched(NodeDescriptor parent) { |
| NodeDescriptor searched = super.getSearched(parent); |
| if(searched == null) { |
| return myDescriptorSearcher.getSearched(parent); |
| } |
| return searched; |
| } |
| } |
| } |