Commit d042461d authored by Arseny Chernyaev's avatar Arseny Chernyaev
Browse files

provide ability to reuse basic parts of IDEA memory view

parent 4de802f6
Branches unavailable Tags unavailable
No related merge requests found
Showing with 718 additions and 936 deletions
+718 -936
......@@ -9,9 +9,9 @@ import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
import com.intellij.debugger.impl.*;
import com.intellij.debugger.jdi.StackFrameProxyImpl;
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
import com.intellij.debugger.memory.component.InstancesTracker;
import com.intellij.debugger.memory.component.MemoryViewDebugProcessData;
import com.intellij.debugger.memory.component.MemoryViewManager;
import com.intellij.xdebugger.memory.component.InstancesTracker;
import com.intellij.xdebugger.memory.component.MemoryViewManager;
import com.intellij.debugger.memory.ui.ClassesFilteredView;
import com.intellij.debugger.settings.DebuggerSettings;
import com.intellij.debugger.ui.AlternativeSourceNotificationProvider;
......
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.debugger.memory.action;
import com.intellij.xdebugger.memory.ui.ClassesTable;
import com.intellij.debugger.memory.ui.JavaTypeInfo;
import com.intellij.xdebugger.memory.ui.TypeInfo;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.sun.jdi.ReferenceType;
import org.jetbrains.annotations.Nullable;
public class ActionUtil {
public static TypeInfo getSelectedTypeInfo(AnActionEvent e) {
return e.getData(ClassesTable.SELECTED_CLASS_KEY);
}
@Nullable
public static ReferenceType getSelectedClass(AnActionEvent e) {
TypeInfo typeInfo = getSelectedTypeInfo(e);
return extractReferenceType(typeInfo);
}
@Nullable
private static ReferenceType extractReferenceType(@Nullable TypeInfo typeInfo) {
return typeInfo != null ? ((JavaTypeInfo) typeInfo).getReferenceType() : null;
}
}
......@@ -15,11 +15,11 @@
*/
package com.intellij.debugger.memory.action;
import com.intellij.debugger.memory.ui.ClassesTable;
import com.intellij.debugger.memory.ui.JavaTypeInfo;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.Project;
import com.sun.jdi.ReferenceType;
import com.intellij.xdebugger.memory.ui.TypeInfo;
import org.jetbrains.annotations.Nullable;
public abstract class ClassesActionBase extends AnAction {
......@@ -41,7 +41,7 @@ public abstract class ClassesActionBase extends AnAction {
protected abstract void perform(AnActionEvent e);
@Nullable
protected ReferenceType getSelectedClass(AnActionEvent e) {
return e.getData(ClassesTable.SELECTED_CLASS_KEY);
protected TypeInfo getSelectedClass(AnActionEvent e) {
return new JavaTypeInfo(ActionUtil.getSelectedClass(e));
}
}
......@@ -18,7 +18,7 @@ package com.intellij.debugger.memory.action;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.ToggleAction;
import com.intellij.openapi.project.Project;
import com.intellij.debugger.memory.component.InstancesTracker;
import com.intellij.xdebugger.memory.component.InstancesTracker;
public class EnableBackgroundTrackingAction extends ToggleAction {
......
......@@ -47,8 +47,8 @@ public class JumpToTypeSourceAction extends ClassesActionBase {
}
@Nullable
private PsiClass getPsiClass(AnActionEvent e) {
final ReferenceType selectedClass = getSelectedClass(e);
private static PsiClass getPsiClass(AnActionEvent e) {
final ReferenceType selectedClass = ActionUtil.getSelectedClass(e);
final Project project = e.getProject();
if (selectedClass == null || project == null) {
return null;
......
......@@ -18,7 +18,7 @@ package com.intellij.debugger.memory.action;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.ToggleAction;
import com.intellij.openapi.project.Project;
import com.intellij.debugger.memory.component.MemoryViewManager;
import com.intellij.xdebugger.memory.component.MemoryViewManager;
public class ShowClassesWithInstanceAction extends ToggleAction {
@Override
......
......@@ -15,16 +15,16 @@
*/
package com.intellij.debugger.memory.action;
import com.intellij.xdebugger.memory.ui.TypeInfo;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.Presentation;
import com.sun.jdi.ReferenceType;
abstract class ShowInstancesAction extends ClassesActionBase {
@Override
public void update(AnActionEvent e) {
final Presentation presentation = e.getPresentation();
final ReferenceType ref = getSelectedClass(e);
final boolean enabled = isEnabled(e) && ref != null && ref.virtualMachine().canGetInstanceInfo();
final TypeInfo ref = getSelectedClass(e);
final boolean enabled = isEnabled(e) && ref != null && ref.canGetInstanceInfo();
presentation.setEnabled(enabled);
if (enabled) {
presentation.setText(String.format("%s (%d)", getLabel(), getInstancesCount(e)));
......
......@@ -15,6 +15,7 @@
*/
package com.intellij.debugger.memory.action;
import com.intellij.debugger.memory.ui.JavaReferenceInfo;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
......@@ -28,6 +29,7 @@ import com.intellij.debugger.memory.ui.InstancesWindow;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class ShowInstancesByClassAction extends DebuggerTreeAction {
@Override
......@@ -52,7 +54,7 @@ public class ShowInstancesByClassAction extends DebuggerTreeAction {
final ReferenceType referenceType = ref.referenceType();
new InstancesWindow(debugSession, l -> {
final List<ObjectReference> instances = referenceType.instances(l);
return instances == null ? Collections.emptyList() : instances;
return instances == null ? Collections.emptyList() : instances.stream().map(JavaReferenceInfo::new).collect(Collectors.toList());
}, referenceType.name()).show();
}
}
......
......@@ -15,12 +15,12 @@
*/
package com.intellij.debugger.memory.action;
import com.intellij.xdebugger.memory.ui.TypeInfo;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.Project;
import com.intellij.xdebugger.XDebugSession;
import com.intellij.xdebugger.XDebuggerManager;
import com.sun.jdi.ReferenceType;
import com.intellij.debugger.memory.ui.ClassesTable;
import com.intellij.xdebugger.memory.ui.ClassesTable;
import com.intellij.debugger.memory.ui.InstancesWindow;
public class ShowInstancesFromClassesViewAction extends ShowInstancesAction {
......@@ -29,11 +29,11 @@ public class ShowInstancesFromClassesViewAction extends ShowInstancesAction {
@Override
protected void perform(AnActionEvent e) {
final Project project = e.getProject();
final ReferenceType selectedClass = getSelectedClass(e);
final TypeInfo selectedClass = getSelectedClass(e);
if (project != null && selectedClass != null) {
final XDebugSession debugSession = XDebuggerManager.getInstance(project).getCurrentSession();
if (debugSession != null) {
new InstancesWindow(debugSession, limit -> selectedClass.instances(limit), selectedClass.name()).show();
new InstancesWindow(debugSession, selectedClass::getInstances, selectedClass.name()).show();
}
}
}
......@@ -46,7 +46,7 @@ public class ShowInstancesFromClassesViewAction extends ShowInstancesAction {
@Override
protected int getInstancesCount(AnActionEvent e) {
ClassesTable.ReferenceCountProvider countProvider = e.getData(ClassesTable.REF_COUNT_PROVIDER_KEY);
ReferenceType selectedClass = getSelectedClass(e);
TypeInfo selectedClass = getSelectedClass(e);
if (countProvider == null || selectedClass == null) {
return -1;
}
......
......@@ -15,9 +15,11 @@
*/
package com.intellij.debugger.memory.action;
import com.intellij.debugger.memory.ui.ClassesTable;
import com.intellij.debugger.memory.ui.ClassesFilteredView;
import com.intellij.xdebugger.memory.ui.ClassesTable;
import com.intellij.debugger.memory.ui.InstancesWindow;
import com.intellij.debugger.memory.utils.InstancesProvider;
import com.intellij.xdebugger.memory.ui.TypeInfo;
import com.intellij.xdebugger.memory.utils.InstancesProvider;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.Project;
import com.intellij.xdebugger.XDebugSession;
......@@ -29,8 +31,8 @@ public class ShowNewInstancesAction extends ShowInstancesAction {
@Override
protected boolean isEnabled(AnActionEvent e) {
final ReferenceType selectedClass = getSelectedClass(e);
final InstancesProvider provider = e.getData(ClassesTable.NEW_INSTANCES_PROVIDER_KEY);
final ReferenceType selectedClass = ActionUtil.getSelectedClass(e);
final InstancesProvider provider = e.getData(ClassesFilteredView.NEW_INSTANCES_PROVIDER_KEY);
final int count = getInstancesCount(e);
return super.isEnabled(e) && selectedClass != null && provider != null && count > 0;
}
......@@ -43,7 +45,7 @@ public class ShowNewInstancesAction extends ShowInstancesAction {
@Override
protected int getInstancesCount(AnActionEvent e) {
ClassesTable.ReferenceCountProvider countProvider = e.getData(ClassesTable.REF_COUNT_PROVIDER_KEY);
ReferenceType selectedClass = getSelectedClass(e);
TypeInfo selectedClass = ActionUtil.getSelectedTypeInfo(e);
if (countProvider == null || selectedClass == null) {
return -1;
}
......@@ -55,8 +57,8 @@ public class ShowNewInstancesAction extends ShowInstancesAction {
protected void perform(AnActionEvent e) {
final Project project = e.getProject();
final ReferenceType selectedClass = getSelectedClass(e);
final InstancesProvider provider = e.getData(ClassesTable.NEW_INSTANCES_PROVIDER_KEY);
final ReferenceType selectedClass = ActionUtil.getSelectedClass(e);
final InstancesProvider provider = e.getData(ClassesFilteredView.NEW_INSTANCES_PROVIDER_KEY);
final XDebugSession session = project != null
? XDebuggerManager.getInstance(project).getCurrentSession()
: null;
......
......@@ -17,7 +17,7 @@ package com.intellij.debugger.memory.action;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.ToggleAction;
import com.intellij.debugger.memory.component.MemoryViewManager;
import com.intellij.xdebugger.memory.component.MemoryViewManager;
public class ShowTrackedAction extends ToggleAction {
@Override
......
......@@ -15,21 +15,20 @@
*/
package com.intellij.debugger.memory.action.tracking;
import com.intellij.debugger.memory.component.InstancesTracker;
import com.intellij.debugger.memory.tracking.TrackingType;
import com.intellij.debugger.memory.ui.ClassesTable;
import com.intellij.debugger.memory.action.ActionUtil;
import com.intellij.xdebugger.memory.component.InstancesTracker;
import com.intellij.xdebugger.memory.tracking.TrackingType;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.ToggleAction;
import com.intellij.openapi.project.Project;
import com.sun.jdi.ArrayType;
import com.sun.jdi.ReferenceType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class TrackInstancesToggleAction extends ToggleAction {
@Override
public void update(@NotNull AnActionEvent e) {
ReferenceType selectedClass = getSelectedClass(e);
ReferenceType selectedClass = ActionUtil.getSelectedClass(e);
if (selectedClass instanceof ArrayType) {
e.getPresentation().setEnabled(false);
}
......@@ -40,7 +39,7 @@ public class TrackInstancesToggleAction extends ToggleAction {
@Override
public boolean isSelected(AnActionEvent e) {
ReferenceType selectedClass = getSelectedClass(e);
ReferenceType selectedClass = ActionUtil.getSelectedClass(e);
final Project project = e.getProject();
if (project != null && selectedClass != null && !project.isDisposed()) {
InstancesTracker tracker = InstancesTracker.getInstance(project);
......@@ -52,7 +51,7 @@ public class TrackInstancesToggleAction extends ToggleAction {
@Override
public void setSelected(AnActionEvent e, boolean state) {
final ReferenceType selectedClass = getSelectedClass(e);
final ReferenceType selectedClass = ActionUtil.getSelectedClass(e);
final Project project = e.getProject();
if (selectedClass != null && project != null && !project.isDisposed()) {
InstancesTracker tracker = InstancesTracker.getInstance(project);
......@@ -68,8 +67,5 @@ public class TrackInstancesToggleAction extends ToggleAction {
}
}
@Nullable
private static ReferenceType getSelectedClass(AnActionEvent e) {
return e.getData(ClassesTable.SELECTED_CLASS_KEY);
}
}
/*
* Copyright 2000-2016 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.memory.event;
import com.intellij.debugger.memory.component.MemoryViewManagerState;
import org.jetbrains.annotations.NotNull;
import java.util.EventListener;
@FunctionalInterface
public interface MemoryViewManagerListener extends EventListener {
void stateChanged(@NotNull MemoryViewManagerState state);
}
......@@ -10,9 +10,9 @@ import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.engine.events.DebuggerCommandImpl;
import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
import com.intellij.debugger.impl.DebuggerUtilsEx;
import com.intellij.debugger.memory.component.InstancesTracker;
import com.intellij.debugger.memory.component.MemoryViewDebugProcessData;
import com.intellij.debugger.memory.event.InstancesTrackerListener;
import com.intellij.xdebugger.memory.component.InstancesTracker;
import com.intellij.xdebugger.memory.event.InstancesTrackerListener;
import com.intellij.debugger.memory.utils.StackFrameItem;
import com.intellij.debugger.settings.DebuggerSettings;
import com.intellij.debugger.ui.breakpoints.JavaLineBreakpointType;
......@@ -207,8 +207,7 @@ public class ConstructorInstancesTracker implements TrackerForNewInstances, Disp
}
@Override
public boolean processLocatableEvent(SuspendContextCommandImpl action, LocatableEvent event)
throws EventProcessingException {
public boolean processLocatableEvent(SuspendContextCommandImpl action, LocatableEvent event) {
if (myIsDeleted) {
event.request().disable();
}
......
......@@ -15,16 +15,12 @@
*/
package com.intellij.debugger.memory.tracking;
import com.sun.jdi.ObjectReference;
import com.intellij.xdebugger.memory.tracking.TrackerForNewInstancesBase;
import org.jetbrains.annotations.NotNull;
import com.sun.jdi.ObjectReference;
import java.util.List;
public interface TrackerForNewInstances {
public interface TrackerForNewInstances extends TrackerForNewInstancesBase {
@NotNull
List<ObjectReference> getNewInstances();
int getCount();
boolean isReady();
}
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.debugger.memory.ui;
import com.intellij.debugger.DebuggerManager;
import com.intellij.debugger.engine.DebugProcessImpl;
import com.intellij.debugger.engine.DebuggerUtils;
import com.intellij.debugger.engine.JavaValue;
import com.intellij.debugger.engine.SuspendContextImpl;
import com.intellij.debugger.engine.evaluation.EvaluationContext;
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
import com.intellij.debugger.memory.filtering.FilteringResult;
import com.intellij.debugger.memory.filtering.FilteringTask;
import com.intellij.debugger.memory.filtering.FilteringTaskCallback;
import com.intellij.debugger.memory.utils.*;
import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
import com.intellij.debugger.ui.impl.watch.MessageDescriptor;
import com.intellij.debugger.ui.impl.watch.NodeManagerImpl;
import com.intellij.debugger.ui.tree.NodeDescriptor;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.ui.DoubleClickListener;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.JBPanel;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.update.UiNotifyConnector;
import com.intellij.xdebugger.XDebugSession;
import com.intellij.xdebugger.XDebugSessionListener;
import com.intellij.xdebugger.XExpression;
import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider;
import com.intellij.xdebugger.frame.XValueChildrenList;
import com.intellij.xdebugger.impl.ui.XDebuggerExpressionEditor;
import com.intellij.xdebugger.memory.ui.InstancesTree;
import com.intellij.xdebugger.memory.ui.InstancesViewBase;
import com.intellij.xdebugger.memory.utils.InstancesProvider;
import org.jetbrains.annotations.NotNull;
import com.sun.jdi.ObjectReference;
import com.sun.jdi.Value;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.stream.Collectors;
class InstancesView extends InstancesViewBase {
private static final Logger LOG = Logger.getInstance(InstancesView.class);
private static final int MAX_TREE_NODE_COUNT = 2000;
private static final int FILTERING_CHUNK_SIZE = 50;
private static final int FILTERING_BUTTON_ADDITIONAL_WIDTH = 30;
private static final int BORDER_LAYOUT_DEFAULT_GAP = 5;
private static final int DEFAULT_INSTANCES_LIMIT = 500000;
private static final int MAX_DURATION_TO_UPDATE_TREE_SECONDS = 3;
private static final int FILTERING_PROGRESS_UPDATING_MIN_DELAY_MILLIS = 17; // ~ 60 fps
private final InstancesTree myInstancesTree;
private final XDebuggerExpressionEditor myFilterConditionEditor;
private final MyNodeManager myNodeManager;
private final Consumer<String> myWarningMessageConsumer;
private final JButton myFilterButton = new JButton("Filter");
private final FilteringProgressView myProgress = new FilteringProgressView();
private final Object myFilteringTaskLock = new Object();
private boolean myIsAndroidVM = false;
private final DebugProcessImpl myDebugProcess;
private final String myClassName;
private volatile MyFilteringWorker myFilteringTask = null;
public InstancesView(@NotNull XDebugSession session, InstancesProvider instancesProvider, String className, Consumer<String> warningMessageConsumer) {
super(new BorderLayout(0, JBUI.scale(BORDER_LAYOUT_DEFAULT_GAP)), session, instancesProvider);
myClassName = className;
myDebugProcess = (DebugProcessImpl) (DebuggerManager.getInstance(session.getProject()).getDebugProcess(session.getDebugProcess().getProcessHandler()));
myNodeManager = new MyNodeManager(session.getProject());
myWarningMessageConsumer = warningMessageConsumer;
final XDebuggerEditorsProvider editorsProvider = session.getDebugProcess().getEditorsProvider();
myFilterConditionEditor = new ExpressionEditorWithHistory(session.getProject(), className,
editorsProvider, this);
final Dimension filteringButtonSize = myFilterConditionEditor.getEditorComponent().getPreferredSize();
filteringButtonSize.width = JBUI.scale(FILTERING_BUTTON_ADDITIONAL_WIDTH) +
getFilterButton().getPreferredSize().width;
getFilterButton().setPreferredSize(filteringButtonSize);
final JBPanel filteringPane = new JBPanel(new BorderLayout(JBUI.scale(BORDER_LAYOUT_DEFAULT_GAP), 0));
final JBLabel sideEffectsWarning = new JBLabel("Warning: filtering may have side effects", SwingConstants.RIGHT);
sideEffectsWarning.setBorder(JBUI.Borders.emptyTop(1));
sideEffectsWarning.setComponentStyle(UIUtil.ComponentStyle.SMALL);
sideEffectsWarning.setFontColor(UIUtil.FontColor.BRIGHTER);
filteringPane.add(new JBLabel("Condition:"), BorderLayout.WEST);
filteringPane.add(myFilterConditionEditor.getComponent(), BorderLayout.CENTER);
filteringPane.add(getFilterButton(), BorderLayout.EAST);
filteringPane.add(sideEffectsWarning, BorderLayout.SOUTH);
getProgress().addStopActionListener(this::cancelFilteringTask);
myInstancesTree = new InstancesTree(session.getProject(), editorsProvider, getValueMarkers(session), this::updateInstances);
getFilterButton().addActionListener(e -> {
final String expression = myFilterConditionEditor.getExpression().getExpression();
if (!expression.isEmpty()) {
myFilterConditionEditor.saveTextInHistory();
}
getFilterButton().setEnabled(false);
myInstancesTree.rebuildTree(InstancesTree.RebuildPolicy.RELOAD_INSTANCES);
});
final StackFrameList list = new StackFrameList(myDebugProcess);
list.addListSelectionListener(e -> list.navigateToSelectedValue(false));
new DoubleClickListener() {
@Override
protected boolean onDoubleClick(MouseEvent event) {
list.navigateToSelectedValue(true);
return true;
}
}.installOn(list);
final InstancesWithStackFrameView instancesWithStackFrame = new InstancesWithStackFrameView(session,
myInstancesTree, list, className);
add(filteringPane, BorderLayout.NORTH);
add(instancesWithStackFrame.getComponent(), BorderLayout.CENTER);
final JComponent focusedComponent = myFilterConditionEditor.getEditorComponent();
UiNotifyConnector.doWhenFirstShown(focusedComponent, () ->
IdeFocusManager.findInstanceByComponent(focusedComponent)
.requestFocus(focusedComponent, true));
session.addSessionListener(new XDebugSessionListener() {
@Override
public void sessionPaused() {
ApplicationManager.getApplication().invokeLater(() -> cancelFilteringTask());
}
@Override
public void sessionResumed() {
ApplicationManager.getApplication().invokeLater(() -> getProgress().setVisible(true));
}
});
}
@Override
protected InstancesTree getInstancesTree() {
return myInstancesTree;
}
@Override
public void dispose() {
cancelFilteringTask();
Disposer.dispose(myInstancesTree);
}
private void updateInstances() {
cancelFilteringTask();
myDebugProcess.getManagerThread().schedule(new DebuggerContextCommandImpl(myDebugProcess.getDebuggerContext()) {
@Override
public Priority getPriority() {
return Priority.LOWEST;
}
@Override
public void threadAction(@NotNull SuspendContextImpl suspendContext) {
myIsAndroidVM = DebuggerUtils.isAndroidVM(myDebugProcess.getVirtualMachineProxy().getVirtualMachine());
final int limit = myIsAndroidVM
? AndroidUtil.ANDROID_INSTANCES_LIMIT
: DEFAULT_INSTANCES_LIMIT;
List<ObjectReference> instances = getInstancesProvider().getInstances(limit + 1).stream().map(referenceInfo -> ((JavaReferenceInfo) referenceInfo).getObjectReference()).collect(Collectors.toList());
final EvaluationContextImpl evaluationContext = myDebugProcess
.getDebuggerContext().createEvaluationContext();
if (instances.size() > limit) {
myWarningMessageConsumer.accept(String.format("Not all instances will be loaded (only %d)", limit));
instances = instances.subList(0, limit);
}
if (evaluationContext != null) {
synchronized (myFilteringTaskLock) {
List<ObjectReference> finalInstances = instances;
ApplicationManager.getApplication().runReadAction(() -> {
myFilteringTask = new MyFilteringWorker(finalInstances, myFilterConditionEditor.getExpression(), evaluationContext);
myFilteringTask.execute();
});
}
}
}
});
}
private void cancelFilteringTask() {
if (myFilteringTask != null) {
synchronized (myFilteringTaskLock) {
if (myFilteringTask != null) {
myFilteringTask.cancel();
myFilteringTask = null;
}
}
}
}
public JButton getFilterButton() {
return myFilterButton;
}
public FilteringProgressView getProgress() {
return myProgress;
}
private final static class MyNodeManager extends NodeManagerImpl {
MyNodeManager(Project project) {
super(project, null);
}
@NotNull
@Override
public DebuggerTreeNodeImpl createNode(final NodeDescriptor descriptor, EvaluationContext evaluationContext) {
return new DebuggerTreeNodeImpl(null, descriptor);
}
@Override
public DebuggerTreeNodeImpl createMessageNode(MessageDescriptor descriptor) {
return new DebuggerTreeNodeImpl(null, descriptor);
}
@NotNull
@Override
public DebuggerTreeNodeImpl createMessageNode(String message) {
return new DebuggerTreeNodeImpl(null, new MessageDescriptor(message));
}
}
private class MyFilteringCallback implements FilteringTaskCallback {
private final ErrorsValueGroup myErrorsGroup = new ErrorsValueGroup();
private final EvaluationContextImpl myEvaluationContext;
private long myFilteringStartedTime;
private int myProceedCount = 0;
private int myMatchedCount = 0;
private int myErrorsCount = 0;
private long myLastTreeUpdatingTime;
private long myLastProgressUpdatingTime;
public MyFilteringCallback(@NotNull EvaluationContextImpl evaluationContext) {
myEvaluationContext = evaluationContext;
}
private XValueChildrenList myChildren = new XValueChildrenList();
@Override
public void started(int total) {
myFilteringStartedTime = System.nanoTime();
myLastTreeUpdatingTime = myFilteringStartedTime;
myLastProgressUpdatingTime = System.nanoTime();
ApplicationManager.getApplication().invokeLater(() -> getProgress().start(total));
}
@NotNull
@Override
public Action matched(@NotNull Value ref) {
final JavaValue val = new InstanceJavaValue(new InstanceValueDescriptor(myDebugProcess.getProject(), ref),
myEvaluationContext, myNodeManager);
myMatchedCount++;
myProceedCount++;
myChildren.add(val);
updateProgress();
updateTree();
return myMatchedCount < MAX_TREE_NODE_COUNT ? Action.CONTINUE : Action.STOP;
}
@NotNull
@Override
public Action notMatched(@NotNull Value ref) {
myProceedCount++;
updateProgress();
return Action.CONTINUE;
}
@NotNull
@Override
public Action error(@NotNull Value ref, @NotNull String description) {
final JavaValue val = new InstanceJavaValue(new InstanceValueDescriptor(myDebugProcess.getProject(), ref),
myEvaluationContext, myNodeManager);
myErrorsGroup.addErrorValue(description, val);
myProceedCount++;
myErrorsCount++;
updateProgress();
return Action.CONTINUE;
}
@Override
public void completed(@NotNull FilteringResult reason) {
if (!myErrorsGroup.isEmpty()) {
myChildren.addBottomGroup(myErrorsGroup);
}
final long duration = System.nanoTime() - myFilteringStartedTime;
LOG.info(String.format("Filtering completed in %d ms for %d instances",
TimeUnit.NANOSECONDS.toMillis(duration),
myProceedCount));
final int proceed = myProceedCount;
final int matched = myMatchedCount;
final int errors = myErrorsCount;
final XValueChildrenList childrenList = myChildren;
ApplicationManager.getApplication().invokeLater(() -> {
getProgress().updateProgress(proceed, matched, errors);
myInstancesTree.addChildren(childrenList, true);
getFilterButton().setEnabled(true);
getProgress().complete(reason);
});
}
private void updateProgress() {
final long now = System.nanoTime();
if (now - myLastProgressUpdatingTime > TimeUnit.MILLISECONDS.toNanos(FILTERING_PROGRESS_UPDATING_MIN_DELAY_MILLIS)) {
final int proceed = myProceedCount;
final int matched = myMatchedCount;
final int errors = myErrorsCount;
ApplicationManager.getApplication().invokeLater(() -> getProgress().updateProgress(proceed, matched, errors));
myLastProgressUpdatingTime = now;
}
}
private void updateTree() {
final long now = System.nanoTime();
final int newChildrenCount = myChildren.size();
if (newChildrenCount >= FILTERING_CHUNK_SIZE ||
(newChildrenCount > 0 && now - myLastTreeUpdatingTime > TimeUnit.SECONDS.toNanos(MAX_DURATION_TO_UPDATE_TREE_SECONDS))) {
final XValueChildrenList children = myChildren;
ApplicationManager.getApplication().invokeLater(() -> myInstancesTree.addChildren(children, false));
myChildren = new XValueChildrenList();
myLastTreeUpdatingTime = System.nanoTime();
}
}
}
private static class MyValuesList implements FilteringTask.ValuesList {
private final List<ObjectReference> myRefs;
public MyValuesList(List<ObjectReference> refs) {
myRefs = refs;
}
@Override
public int size() {
return myRefs.size();
}
@Override
public ObjectReference get(int index) {
return myRefs.get(index);
}
}
private class MyFilteringWorker extends SwingWorker<Void, Void> {
private final FilteringTask myTask;
MyFilteringWorker(@NotNull List<ObjectReference> refs,
@NotNull XExpression expression,
@NotNull EvaluationContextImpl evaluationContext) {
myTask = new FilteringTask(myClassName, myDebugProcess, expression, new MyValuesList(refs),
new MyFilteringCallback(evaluationContext));
}
@Override
protected Void doInBackground() {
try {
myTask.run();
} catch (Throwable e) {
LOG.error(e);
}
return null;
}
public void cancel() {
myTask.cancel();
super.cancel(false);
}
}
}
......@@ -16,11 +16,14 @@
package com.intellij.debugger.memory.ui;
import com.intellij.debugger.DebuggerManager;
import com.intellij.debugger.memory.component.InstancesTracker;
import com.intellij.debugger.memory.component.MemoryViewDebugProcessData;
import com.intellij.debugger.memory.event.InstancesTrackerListener;
import com.intellij.debugger.memory.tracking.TrackingType;
import com.intellij.xdebugger.memory.component.InstancesTracker;
import com.intellij.xdebugger.memory.event.InstancesTrackerListener;
import com.intellij.xdebugger.memory.tracking.TrackingType;
import com.intellij.debugger.memory.utils.StackFrameItem;
import com.intellij.debugger.ui.impl.watch.NodeDescriptorProvider;
import com.intellij.debugger.ui.tree.NodeDescriptor;
import com.intellij.debugger.ui.tree.ValueDescriptor;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
......@@ -30,10 +33,16 @@ import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.components.labels.ActionLink;
import com.intellij.xdebugger.XDebugSession;
import com.intellij.xdebugger.frame.XValue;
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
import com.intellij.xdebugger.memory.ui.InstancesTree;
import com.sun.jdi.ObjectReference;
import com.sun.jdi.Value;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.tree.TreePath;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
......@@ -109,7 +118,7 @@ class InstancesWithStackFrameView {
DebuggerManager.getInstance(project).getDebugProcess(debugSession.getDebugProcess().getProcessHandler())
.getUserData(MemoryViewDebugProcessData.KEY);
tree.addTreeSelectionListener(e -> {
ObjectReference ref = tree.getSelectedReference();
ObjectReference ref = getSelectedReference(tree);
if (ref != null && data != null) {
List<StackFrameItem> stack = data.getTrackedStacks().getStack(ref);
if (stack != null) {
......@@ -128,6 +137,27 @@ class InstancesWithStackFrameView {
list.setFrameItems(Collections.emptyList());
});
}
@Nullable
private static ObjectReference getSelectedReference(InstancesTree tree) {
TreePath selectionPath = tree.getSelectionPath();
Object selectedItem = selectionPath != null ? selectionPath.getLastPathComponent() : null;
if (selectedItem instanceof XValueNodeImpl) {
XValueNodeImpl xValueNode = (XValueNodeImpl)selectedItem;
XValue valueContainer = xValueNode.getValueContainer();
if (valueContainer instanceof NodeDescriptorProvider) {
NodeDescriptor descriptor = ((NodeDescriptorProvider)valueContainer).getDescriptor();
if (descriptor instanceof ValueDescriptor) {
Value value = ((ValueDescriptor)descriptor).getValue();
if (value instanceof ObjectReference) return (ObjectReference)value;
}
}
}
return null;
}
JComponent getComponent() {
return mySplitter;
......
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.debugger.memory.ui;
import com.intellij.xdebugger.memory.ui.ReferenceInfo;
import com.sun.jdi.ObjectReference;
public class JavaReferenceInfo implements ReferenceInfo {
private final ObjectReference objectReference;
public JavaReferenceInfo(ObjectReference objectReference) {
this.objectReference = objectReference;
}
public ObjectReference getObjectReference() {
return objectReference;
}
@Override
public int hashCode() {
return objectReference.hashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof JavaReferenceInfo)) {
return false;
}
return ((JavaReferenceInfo)obj).objectReference.equals(objectReference);
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment