mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-127197 Remote debug: easy way to change library used to display sources
This commit is contained in:
@@ -23,6 +23,7 @@ import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
|
||||
import com.intellij.debugger.impl.*;
|
||||
import com.intellij.debugger.jdi.StackFrameProxyImpl;
|
||||
import com.intellij.debugger.settings.DebuggerSettings;
|
||||
import com.intellij.debugger.ui.AlternativeSourceNotificationProvider;
|
||||
import com.intellij.debugger.ui.DebuggerContentInfo;
|
||||
import com.intellij.debugger.ui.breakpoints.Breakpoint;
|
||||
import com.intellij.debugger.ui.impl.ThreadsPanel;
|
||||
@@ -43,6 +44,8 @@ import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.ui.EditorNotifications;
|
||||
import com.intellij.ui.content.Content;
|
||||
import com.intellij.ui.content.ContentManagerAdapter;
|
||||
import com.intellij.ui.content.ContentManagerEvent;
|
||||
@@ -154,17 +157,29 @@ public class JavaDebugProcess extends XDebugProcess {
|
||||
@Override
|
||||
public void sessionPaused() {
|
||||
saveNodeHistory();
|
||||
showAlternativeNotification(session.getCurrentStackFrame());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stackFrameChanged() {
|
||||
XStackFrame frame = session.getCurrentStackFrame();
|
||||
if (frame instanceof JavaStackFrame) {
|
||||
showAlternativeNotification(frame);
|
||||
StackFrameProxyImpl frameProxy = ((JavaStackFrame)frame).getStackFrameProxy();
|
||||
DebuggerContextUtil.setStackFrame(javaSession.getContextManager(), frameProxy);
|
||||
saveNodeHistory(frameProxy);
|
||||
}
|
||||
}
|
||||
|
||||
private void showAlternativeNotification(XStackFrame frame) {
|
||||
XSourcePosition position = frame.getSourcePosition();
|
||||
if (position != null) {
|
||||
VirtualFile file = position.getFile();
|
||||
if (!AlternativeSourceNotificationProvider.fileProcessed(file)) {
|
||||
EditorNotifications.getInstance(session.getProject()).updateNotifications(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -700,6 +700,13 @@ public abstract class DebuggerUtilsEx extends DebuggerUtils {
|
||||
return new JavaXSourcePosition(position, file);
|
||||
}
|
||||
|
||||
private static final Key<VirtualFile> ALTERNATIVE_SOURCE_KEY = new Key<VirtualFile>("DEBUGGER_ALTERNATIVE_SOURCE");
|
||||
|
||||
public static void setAlternativeSource(VirtualFile source, VirtualFile dest) {
|
||||
ALTERNATIVE_SOURCE_KEY.set(source, dest);
|
||||
ALTERNATIVE_SOURCE_KEY.set(dest, null);
|
||||
}
|
||||
|
||||
private static class JavaXSourcePosition implements XSourcePosition, ExecutionPointHighlighter.HighlighterProvider {
|
||||
private final SourcePosition mySourcePosition;
|
||||
@NotNull private final VirtualFile myFile;
|
||||
@@ -722,6 +729,10 @@ public abstract class DebuggerUtilsEx extends DebuggerUtils {
|
||||
@NotNull
|
||||
@Override
|
||||
public VirtualFile getFile() {
|
||||
VirtualFile file = ALTERNATIVE_SOURCE_KEY.get(myFile);
|
||||
if (file != null) {
|
||||
return file;
|
||||
}
|
||||
return myFile;
|
||||
}
|
||||
|
||||
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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;
|
||||
|
||||
import com.intellij.debugger.DebuggerBundle;
|
||||
import com.intellij.debugger.impl.DebuggerUtilsEx;
|
||||
import com.intellij.ide.highlighter.JavaClassFileType;
|
||||
import com.intellij.openapi.fileEditor.FileEditor;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleUtilCore;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ProjectFileIndex;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.ui.ComboBox;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.ui.EditorNotificationPanel;
|
||||
import com.intellij.ui.EditorNotifications;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.xdebugger.XDebugSession;
|
||||
import com.intellij.xdebugger.XDebuggerManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* @author egor
|
||||
*/
|
||||
public class AlternativeSourceNotificationProvider extends EditorNotifications.Provider<EditorNotificationPanel> {
|
||||
private static final Key<EditorNotificationPanel> KEY = Key.create("AlternativeSource");
|
||||
private static final Key<Boolean> FILE_PROCESSED_KEY = Key.create("AlternativeSourceCheckDone");
|
||||
private final Project myProject;
|
||||
|
||||
public AlternativeSourceNotificationProvider(Project project) {
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Key<EditorNotificationPanel> getKey() {
|
||||
return KEY;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public EditorNotificationPanel createNotificationPanel(@NotNull VirtualFile file, @NotNull FileEditor fileEditor) {
|
||||
if (XDebuggerManager.getInstance(myProject).getCurrentSession() == null) {
|
||||
FILE_PROCESSED_KEY.set(file, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (file.getFileType() == JavaClassFileType.INSTANCE) return null;
|
||||
|
||||
final PsiFile psiFile = PsiManager.getInstance(myProject).findFile(file);
|
||||
if (psiFile == null) return null;
|
||||
|
||||
if (!(psiFile instanceof PsiJavaFile)) return null;
|
||||
|
||||
PsiClass[] classes = ((PsiJavaFile)psiFile).getClasses();
|
||||
if (classes.length == 0) return null;
|
||||
|
||||
PsiClass baseClass = classes[0];
|
||||
String name = baseClass.getQualifiedName();
|
||||
|
||||
if (name == null) return null;
|
||||
|
||||
if (DumbService.getInstance(myProject).isDumb()) return null;
|
||||
|
||||
PsiClass[] alternatives = JavaPsiFacade.getInstance(myProject).findClasses(name, GlobalSearchScope.allScope(myProject));
|
||||
|
||||
FILE_PROCESSED_KEY.set(file, true);
|
||||
|
||||
if (alternatives.length > 1) {
|
||||
ArrayList<PsiClass> alts = ContainerUtil.newArrayList(alternatives);
|
||||
for (PsiClass cls : alts) {
|
||||
if (cls.equals(baseClass) || cls.getNavigationElement().equals(baseClass)) {
|
||||
alts.remove(cls);
|
||||
break;
|
||||
}
|
||||
}
|
||||
alts.add(0, baseClass);
|
||||
|
||||
ComboBoxClassElement[] elems = ContainerUtil.map2Array(alts,
|
||||
ComboBoxClassElement.class,
|
||||
new Function<PsiClass, ComboBoxClassElement>() {
|
||||
@Override
|
||||
public ComboBoxClassElement fun(PsiClass psiClass) {
|
||||
return new ComboBoxClassElement(psiClass);
|
||||
}
|
||||
});
|
||||
|
||||
return new AlternativeSourceNotificationPanel(elems, baseClass, myProject, file);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class ComboBoxClassElement {
|
||||
private final PsiClass myClass;
|
||||
private String myText;
|
||||
|
||||
public ComboBoxClassElement(PsiClass aClass) {
|
||||
myClass = aClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (myText == null) {
|
||||
Module module = ModuleUtilCore.findModuleForPsiElement(myClass);
|
||||
if (module != null) {
|
||||
myText = module.getName();
|
||||
}
|
||||
else {
|
||||
VirtualFile virtualFile = myClass.getContainingFile().getVirtualFile();
|
||||
final ProjectFileIndex index = ProjectRootManager.getInstance(myClass.getProject()).getFileIndex();
|
||||
VirtualFile root = index.getSourceRootForFile(virtualFile);
|
||||
if (root == null) {
|
||||
root = index.getClassRootForFile(virtualFile);
|
||||
}
|
||||
if (root != null) {
|
||||
myText = root.getName();
|
||||
}
|
||||
else {
|
||||
myText = virtualFile.getPath();
|
||||
}
|
||||
}
|
||||
}
|
||||
return myText;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean fileProcessed(VirtualFile file) {
|
||||
return FILE_PROCESSED_KEY.get(file) != null;
|
||||
}
|
||||
|
||||
private static class AlternativeSourceNotificationPanel extends EditorNotificationPanel {
|
||||
public AlternativeSourceNotificationPanel(ComboBoxClassElement[] alternatives,
|
||||
final PsiClass aClass,
|
||||
final Project project,
|
||||
final VirtualFile file) {
|
||||
setText(DebuggerBundle.message("editor.notification.alternative.source", aClass.getQualifiedName()));
|
||||
final ComboBox switcher = new ComboBox(alternatives);
|
||||
switcher.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
FileEditorManager.getInstance(project).closeFile(file);
|
||||
PsiClass item = ((ComboBoxClassElement)switcher.getSelectedItem()).myClass;
|
||||
item = (PsiClass)item.getNavigationElement(); // go through compiled
|
||||
DebuggerUtilsEx.setAlternativeSource(file, item.getContainingFile().getVirtualFile());
|
||||
item.navigate(true);
|
||||
XDebugSession session = XDebuggerManager.getInstance(project).getCurrentSession();
|
||||
if (session != null) {
|
||||
session.updateExecutionPosition();
|
||||
}
|
||||
}
|
||||
});
|
||||
myLinksPanel.add(switcher);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -460,4 +460,5 @@ action.kill.process.description=Forcibly terminate debugged application
|
||||
evaluation.error.unknown.method.return.type=Cannot resolve method return type: {0}
|
||||
rule.name.group.by.class=Group by class
|
||||
rule.name.group.by.package=Group by package
|
||||
error.context.has.changed=Context has changed, operation is not possible
|
||||
error.context.has.changed=Context has changed, operation is not possible
|
||||
editor.notification.alternative.source=Alternative source available for the class {0}
|
||||
|
||||
@@ -267,6 +267,7 @@
|
||||
|
||||
<editorNotificationProvider implementation="com.intellij.codeInsight.daemon.impl.AttachSourcesNotificationProvider"/>
|
||||
<editorNotificationProvider implementation="com.intellij.codeInsight.daemon.impl.SetupSDKNotificationProvider"/>
|
||||
<editorNotificationProvider implementation="com.intellij.debugger.ui.AlternativeSourceNotificationProvider"/>
|
||||
|
||||
<attachSourcesProvider implementation="com.intellij.jarFinder.InternetAttachSourceProvider"/>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user