mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[rd debugger] show image popup on frontend for image values, IDEA-378972
^IDEA-378972 fixed GitOrigin-RevId: 4d039ac4cb9ab2be5ce2019abf995d202e6679d8
This commit is contained in:
committed by
intellij-monorepo-bot
parent
5b7c197709
commit
e2ee08973d
Generated
+1
@@ -946,6 +946,7 @@
|
||||
<module fileurl="file://$PROJECT_DIR$/images/intellij.platform.images.iml" filepath="$PROJECT_DIR$/images/intellij.platform.images.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/build-scripts/icons/intellij.platform.images.build.iml" filepath="$PROJECT_DIR$/platform/build-scripts/icons/intellij.platform.images.build.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/images/intellij.platform.images.copyright/intellij.platform.images.copyright.iml" filepath="$PROJECT_DIR$/images/intellij.platform.images.copyright/intellij.platform.images.copyright.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/images/intellij.platform.images.xdebugger/intellij.platform.images.xdebugger.iml" filepath="$PROJECT_DIR$/images/intellij.platform.images.xdebugger/intellij.platform.images.xdebugger.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/indexing-api/intellij.platform.indexing.iml" filepath="$PROJECT_DIR$/platform/indexing-api/intellij.platform.indexing.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/indexing-impl/intellij.platform.indexing.impl.iml" filepath="$PROJECT_DIR$/platform/indexing-impl/intellij.platform.indexing.impl.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/indexing-tests/intellij.platform.indexing.tests.iml" filepath="$PROJECT_DIR$/platform/indexing-tests/intellij.platform.indexing.tests.iml" />
|
||||
|
||||
@@ -264,6 +264,7 @@ idea/customization/base
|
||||
idea/customization/min
|
||||
images
|
||||
images/intellij.platform.images.copyright
|
||||
images/intellij.platform.images.xdebugger
|
||||
java/codeserver/core
|
||||
java/codeserver/highlighting
|
||||
java/compiler
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
### auto-generated section `build intellij.platform.images.xdebugger` start
|
||||
load("@rules_jvm//:jvm.bzl", "jvm_library", "resourcegroup")
|
||||
|
||||
resourcegroup(
|
||||
name = "xdebugger_resources",
|
||||
srcs = glob(["resources/**/*"]),
|
||||
strip_prefix = "resources"
|
||||
)
|
||||
|
||||
jvm_library(
|
||||
name = "xdebugger",
|
||||
module_name = "intellij.platform.images.xdebugger",
|
||||
visibility = ["//visibility:public"],
|
||||
srcs = glob(["src/**/*.kt", "src/**/*.java", "src/**/*.form"], allow_empty = True),
|
||||
resources = [":xdebugger_resources"],
|
||||
deps = [
|
||||
"//images",
|
||||
"//platform/projectModel-api:projectModel",
|
||||
"//platform/util",
|
||||
"//platform/core-api:core",
|
||||
"//platform/xdebugger-impl/frontend",
|
||||
"//platform/ide-core",
|
||||
]
|
||||
)
|
||||
### auto-generated section `build intellij.platform.images.xdebugger` end
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module" module-name="intellij.platform.images" />
|
||||
<orderEntry type="module" module-name="intellij.platform.projectModel" />
|
||||
<orderEntry type="module" module-name="intellij.platform.util" />
|
||||
<orderEntry type="module" module-name="intellij.platform.core" />
|
||||
<orderEntry type="module" module-name="intellij.platform.debugger.impl.frontend" />
|
||||
<orderEntry type="module" module-name="intellij.platform.ide.core" />
|
||||
</component>
|
||||
</module>
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<idea-plugin>
|
||||
<dependencies>
|
||||
<plugin id="com.intellij.platform.images"/>
|
||||
<module name="intellij.platform.debugger.impl.frontend"/>
|
||||
</dependencies>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<xdebugger.imageEditorUIProvider implementation="com.intellij.platform.images.xdebugger.ImageEditorUIProviderImpl"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.images.xdebugger;
|
||||
|
||||
import com.intellij.platform.debugger.impl.frontend.frame.ImageEditorUIProvider;
|
||||
import org.intellij.images.editor.impl.ImageEditorManagerImpl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
||||
class ImageEditorUIProviderImpl implements ImageEditorUIProvider {
|
||||
@Override
|
||||
public @NotNull JComponent createImageEditorUI(byte @NotNull [] imageData) {
|
||||
var icon = new ImageIcon(imageData);
|
||||
|
||||
var w = icon.getIconWidth();
|
||||
var h = icon.getIconHeight();
|
||||
var image = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration()
|
||||
.createCompatibleImage(w, h, Transparency.TRANSLUCENT);
|
||||
var g = image.createGraphics();
|
||||
try {
|
||||
icon.paintIcon(null, g, 0, 0);
|
||||
}
|
||||
finally {
|
||||
g.dispose();
|
||||
}
|
||||
return ImageEditorManagerImpl.createImageEditorUI(image);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
- name: lib/modules/intellij.platform.images.xdebugger.jar
|
||||
contentModules:
|
||||
- name: intellij.platform.images.xdebugger
|
||||
- name: lib/platform-images.jar
|
||||
modules:
|
||||
- name: intellij.platform.images
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
<content>
|
||||
<module name="intellij.platform.images.copyright"/>
|
||||
<module name="intellij.platform.images.xdebugger"/>
|
||||
</content>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
|
||||
@@ -51,7 +51,6 @@ jvm_library(
|
||||
"@lib//:jb-jdi",
|
||||
"//libraries/stream",
|
||||
"//platform/statistics",
|
||||
"//images",
|
||||
"//platform/core-ui",
|
||||
"//libraries/fastutil",
|
||||
"//platform/platform-util-io-impl:ide-util-io-impl",
|
||||
@@ -74,6 +73,7 @@ jvm_library(
|
||||
"//platform/xdebugger-impl/rpc",
|
||||
"//fleet/rpc",
|
||||
"//platform/kernel/rpc",
|
||||
"//platform/remote-topics/shared:rpc-topics",
|
||||
]
|
||||
)
|
||||
|
||||
@@ -118,8 +118,6 @@ jvm_library(
|
||||
"//libraries/stream",
|
||||
"//platform/statistics",
|
||||
"//platform/statistics:statistics_test_lib",
|
||||
"//images",
|
||||
"//images:images_test_lib",
|
||||
"//platform/core-ui",
|
||||
"//libraries/fastutil",
|
||||
"//platform/platform-util-io-impl:ide-util-io-impl",
|
||||
@@ -144,6 +142,7 @@ jvm_library(
|
||||
"//fleet/rpc",
|
||||
"//platform/kernel/rpc",
|
||||
"//platform/testFramework/common",
|
||||
"//platform/remote-topics/shared:rpc-topics",
|
||||
]
|
||||
)
|
||||
### auto-generated section `build intellij.java.debugger.impl` end
|
||||
|
||||
@@ -79,7 +79,6 @@
|
||||
<orderEntry type="library" name="jb-jdi" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.libraries.stream" />
|
||||
<orderEntry type="module" module-name="intellij.platform.statistics" />
|
||||
<orderEntry type="module" module-name="intellij.platform.images" />
|
||||
<orderEntry type="module" module-name="intellij.platform.core.ui" />
|
||||
<orderEntry type="module" module-name="intellij.libraries.fastutil" />
|
||||
<orderEntry type="module" module-name="intellij.platform.ide.util.io.impl" />
|
||||
@@ -103,6 +102,7 @@
|
||||
<orderEntry type="module" module-name="fleet.rpc" />
|
||||
<orderEntry type="module" module-name="intellij.platform.rpc" />
|
||||
<orderEntry type="module" module-name="intellij.platform.testFramework.common" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.rpc.topics" />
|
||||
</component>
|
||||
<component name="copyright">
|
||||
<Base>
|
||||
|
||||
@@ -150,6 +150,7 @@
|
||||
<debugger.compoundRendererProvider implementation="com.intellij.debugger.ui.tree.render.UnboxableTypeRenderer$FloatRenderer"/>
|
||||
<debugger.compoundRendererProvider implementation="com.intellij.debugger.ui.tree.render.UnboxableTypeRenderer$DoubleRenderer"/>
|
||||
<debugger.compoundRendererProvider implementation="com.intellij.debugger.ui.tree.render.ColorObjectRenderer"/>
|
||||
<debugger.compoundRendererProvider implementation="com.intellij.debugger.ui.tree.render.ImageObjectRenderer"/>
|
||||
<debugger.compoundRendererProvider implementation="com.intellij.debugger.ui.tree.render.IconObjectRenderer"/>
|
||||
<debugger.compoundRendererProvider implementation="com.intellij.debugger.ui.tree.render.GraphicsObjectRenderer"/>
|
||||
<debugger.compoundRendererProvider implementation="com.intellij.debugger.ui.tree.render.BinaryRenderer"/>
|
||||
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.debugger.ui.tree.render;
|
||||
|
||||
import com.intellij.debugger.engine.JavaValue;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
|
||||
import com.intellij.debugger.impl.DebuggerUtilsImpl;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.platform.debugger.impl.shared.ShowImagePopupUtil;
|
||||
import com.intellij.rt.debugger.ImageSerializer;
|
||||
import com.intellij.xdebugger.XDebuggerManager;
|
||||
import com.intellij.xdebugger.frame.XFullValueEvaluator;
|
||||
import com.intellij.xdebugger.impl.XDebuggerManagerImpl;
|
||||
import com.sun.jdi.StringReference;
|
||||
import com.sun.jdi.Value;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
|
||||
abstract class AbstractImageRenderer extends CompoundRendererProvider {
|
||||
private static final Logger LOG = Logger.getInstance(AbstractImageRenderer.class);
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(Project project) {
|
||||
if (!super.isApplicable(project)) return false;
|
||||
|
||||
var manager = (XDebuggerManagerImpl)XDebuggerManager.getInstance(project);
|
||||
return manager.getFrontendCapabilities().getCanShowImages();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
static byte @Nullable [] getImageBytes(EvaluationContextImpl evaluationContext, Value obj, String methodName) {
|
||||
try {
|
||||
EvaluationContextImpl copyContext = evaluationContext.createEvaluationContext(obj);
|
||||
StringReference bytes =
|
||||
(StringReference)DebuggerUtilsImpl.invokeHelperMethod(copyContext, ImageSerializer.class, methodName, Collections.singletonList(obj));
|
||||
if (bytes != null) {
|
||||
return bytes.value().getBytes(StandardCharsets.ISO_8859_1);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
DebuggerUtilsImpl.logError("Exception while getting image data", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected XFullValueEvaluator createImagePopupEvaluator(@NotNull @Nls String message,
|
||||
@NotNull EvaluationContextImpl evaluationContext,
|
||||
Value imageObj,
|
||||
String getBytesMethodName) {
|
||||
return new JavaValue.JavaFullValueEvaluator(message, evaluationContext) {
|
||||
{
|
||||
setShowValuePopup(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evaluate(@NotNull XFullValueEvaluationCallback callback) {
|
||||
if (callback.isObsolete()) return;
|
||||
|
||||
var imageData = getImageBytes(getEvaluationContext(), imageObj, getBytesMethodName);
|
||||
|
||||
ShowImagePopupUtil.showOnFrontend(getEvaluationContext().getProject(), imageData);
|
||||
callback.evaluated("");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+3
-14
@@ -6,9 +6,7 @@ import com.intellij.debugger.engine.DebuggerUtils;
|
||||
import com.intellij.debugger.engine.FullValueEvaluatorProvider;
|
||||
import com.sun.jdi.*;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
public final class GraphicsObjectRenderer extends CompoundRendererProvider {
|
||||
public final class GraphicsObjectRenderer extends AbstractImageRenderer {
|
||||
@Override
|
||||
protected String getName() {
|
||||
return "Graphics";
|
||||
@@ -19,11 +17,6 @@ public final class GraphicsObjectRenderer extends CompoundRendererProvider {
|
||||
return "sun.java2d.SunGraphics2D";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FullValueEvaluatorProvider getFullValueEvaluatorProvider() {
|
||||
return (evaluationContext, valueDescriptor) -> {
|
||||
@@ -45,12 +38,8 @@ public final class GraphicsObjectRenderer extends CompoundRendererProvider {
|
||||
if (!(type instanceof ReferenceType) || !DebuggerUtils.instanceOf(type, "java.awt.Image")) {
|
||||
return null;
|
||||
}
|
||||
return new ImageObjectRenderer.IconPopupEvaluator(JavaDebuggerBundle.message("message.node.show.image"), evaluationContext) {
|
||||
@Override
|
||||
protected Icon getData() {
|
||||
return ImageObjectRenderer.getIcon(getEvaluationContext(), bufImgValue, "imageToBytes");
|
||||
}
|
||||
};
|
||||
return createImagePopupEvaluator(JavaDebuggerBundle.message("message.node.show.image"), evaluationContext,
|
||||
bufImgValue, "imageToBytes");
|
||||
}
|
||||
catch (Exception ignored) {
|
||||
}
|
||||
|
||||
+11
-13
@@ -10,11 +10,13 @@ import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
|
||||
import com.intellij.debugger.impl.DebuggerUtilsImpl;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.sun.jdi.Value;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
final class IconObjectRenderer extends CompoundRendererProvider {
|
||||
final class IconObjectRenderer extends AbstractImageRenderer {
|
||||
@Override
|
||||
protected String getName() {
|
||||
return "Icon";
|
||||
@@ -25,11 +27,6 @@ final class IconObjectRenderer extends CompoundRendererProvider {
|
||||
return "javax.swing.Icon";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ValueIconRenderer getIconRenderer() {
|
||||
return (descriptor, evaluationContext, listener) -> {
|
||||
@@ -42,7 +39,7 @@ final class IconObjectRenderer extends CompoundRendererProvider {
|
||||
@Override
|
||||
public void contextAction(@NotNull SuspendContextImpl suspendContext) {
|
||||
String getterName = AllIcons.Debugger.Value.getIconHeight() <= 16 ? "iconToBytesPreviewNormal" : "iconToBytesPreviewRetina";
|
||||
descriptor.setValueIcon(ImageObjectRenderer.getIcon(evalContext, descriptor.getValue(), getterName));
|
||||
descriptor.setValueIcon(getImageIcon(evalContext, descriptor.getValue(), getterName));
|
||||
listener.labelChanged();
|
||||
}
|
||||
});
|
||||
@@ -53,12 +50,13 @@ final class IconObjectRenderer extends CompoundRendererProvider {
|
||||
@Override
|
||||
protected FullValueEvaluatorProvider getFullValueEvaluatorProvider() {
|
||||
return (evaluationContext, valueDescriptor) -> {
|
||||
return new ImageObjectRenderer.IconPopupEvaluator(JavaDebuggerBundle.message("message.node.show.icon"), evaluationContext) {
|
||||
@Override
|
||||
protected Icon getData() {
|
||||
return ImageObjectRenderer.getIcon(getEvaluationContext(), valueDescriptor.getValue(), "iconToBytes");
|
||||
}
|
||||
};
|
||||
return createImagePopupEvaluator(JavaDebuggerBundle.message("message.node.show.icon"), evaluationContext,
|
||||
valueDescriptor.getValue(), "iconToBytes");
|
||||
};
|
||||
}
|
||||
|
||||
static @Nullable ImageIcon getImageIcon(EvaluationContextImpl evaluationContext, Value obj, String methodName) {
|
||||
byte[] data = getImageBytes(evaluationContext, obj, methodName);
|
||||
return data != null ? new ImageIcon(data) : null;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-80
@@ -1,30 +1,10 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.debugger.ui.tree.render;
|
||||
|
||||
import com.intellij.CommonBundle;
|
||||
import com.intellij.debugger.JavaDebuggerBundle;
|
||||
import com.intellij.debugger.engine.FullValueEvaluatorProvider;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateException;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
|
||||
import com.intellij.debugger.impl.DebuggerUtilsImpl;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.rt.debugger.ImageSerializer;
|
||||
import com.sun.jdi.StringReference;
|
||||
import com.sun.jdi.Value;
|
||||
import org.intellij.images.editor.impl.ImageEditorManagerImpl;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
|
||||
final class ImageObjectRenderer extends CompoundRendererProvider {
|
||||
private static final Logger LOG = Logger.getInstance(ImageObjectRenderer.class);
|
||||
|
||||
final class ImageObjectRenderer extends AbstractImageRenderer {
|
||||
@Override
|
||||
protected String getName() {
|
||||
return "Image";
|
||||
@@ -35,67 +15,10 @@ final class ImageObjectRenderer extends CompoundRendererProvider {
|
||||
return "java.awt.Image";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FullValueEvaluatorProvider getFullValueEvaluatorProvider() {
|
||||
return (evaluationContext, valueDescriptor) ->
|
||||
new IconPopupEvaluator(JavaDebuggerBundle.message("message.node.show.image"), evaluationContext) {
|
||||
@Override
|
||||
protected Icon getData() {
|
||||
return getIcon(getEvaluationContext(), valueDescriptor.getValue(), "imageToBytes");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static JComponent createIconViewer(@Nullable Icon icon) {
|
||||
if (icon == null) return new JLabel(CommonBundle.message("label.no.data"), SwingConstants.CENTER);
|
||||
final int w = icon.getIconWidth();
|
||||
final int h = icon.getIconHeight();
|
||||
final BufferedImage image = GraphicsEnvironment.getLocalGraphicsEnvironment()
|
||||
.getDefaultScreenDevice().getDefaultConfiguration().createCompatibleImage(w, h, Transparency.TRANSLUCENT);
|
||||
final Graphics2D g = image.createGraphics();
|
||||
icon.paintIcon(null, g, 0, 0);
|
||||
g.dispose();
|
||||
|
||||
return ImageEditorManagerImpl.createImageEditorUI(image);
|
||||
}
|
||||
|
||||
static @Nullable ImageIcon getIcon(EvaluationContextImpl evaluationContext, Value obj, String methodName) {
|
||||
try {
|
||||
byte[] data = getImageBytes(evaluationContext, obj, methodName);
|
||||
if (data != null) {
|
||||
return new ImageIcon(data);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.info("Exception while getting image data", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static byte @Nullable [] getImageBytes(EvaluationContextImpl evaluationContext, Value obj, String methodName)
|
||||
throws EvaluateException {
|
||||
EvaluationContextImpl copyContext = evaluationContext.createEvaluationContext(obj);
|
||||
StringReference bytes =
|
||||
(StringReference)DebuggerUtilsImpl.invokeHelperMethod(copyContext, ImageSerializer.class, methodName, Collections.singletonList(obj));
|
||||
if (bytes != null) {
|
||||
return bytes.value().getBytes(StandardCharsets.ISO_8859_1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
abstract static class IconPopupEvaluator extends CustomPopupFullValueEvaluator<Icon> {
|
||||
IconPopupEvaluator(@NotNull @Nls String linkText, @NotNull EvaluationContextImpl evaluationContext) {
|
||||
super(linkText, evaluationContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JComponent createComponent(Icon data) {
|
||||
return createIconViewer(data);
|
||||
}
|
||||
createImagePopupEvaluator(JavaDebuggerBundle.message("message.node.show.image"), evaluationContext,
|
||||
valueDescriptor.getValue(), "imageToBytes");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<module value="com.intellij.modules.java"/>
|
||||
|
||||
<depends optional="true" config-file="images-integration.xml">com.intellij.platform.images</depends>
|
||||
<depends optional="true">com.intellij.platform.images</depends>
|
||||
<depends optional="true" config-file="community-integration.xml">com.intellij.modules.idea.community</depends>
|
||||
|
||||
<xi:include href="/idea/JavaActions.xml"/>
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<idea-plugin>
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<debugger.compoundRendererProvider implementation="com.intellij.debugger.ui.tree.render.ImageObjectRenderer"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
@@ -14,6 +14,7 @@ internal object PlatformApi {
|
||||
"intellij.platform.uast.ide", // IDEA
|
||||
"intellij.platform.images", // plugin
|
||||
"intellij.platform.images.copyright", // plugin
|
||||
"intellij.platform.images.xdebugger", // plugin
|
||||
"intellij.platform.images.build", // build scripts
|
||||
)
|
||||
|
||||
|
||||
+12
@@ -7,6 +7,7 @@ import com.intellij.openapi.application.EDT
|
||||
import com.intellij.openapi.editor.impl.EditorId
|
||||
import com.intellij.openapi.editor.impl.findEditorOrNull
|
||||
import com.intellij.platform.debugger.impl.rpc.*
|
||||
import com.intellij.platform.debugger.impl.rpc.XFrontendDebuggerCapabilities
|
||||
import com.intellij.platform.execution.impl.backend.createProcessHandlerDto
|
||||
import com.intellij.platform.project.ProjectId
|
||||
import com.intellij.platform.project.findProject
|
||||
@@ -31,6 +32,17 @@ import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
internal class BackendXDebuggerManagerApi : XDebuggerManagerApi {
|
||||
override suspend fun initialize(projectId: ProjectId, capabilities: XFrontendDebuggerCapabilities) {
|
||||
val project = projectId.findProject()
|
||||
val manager = XDebuggerManager.getInstance(project) as XDebuggerManagerImpl
|
||||
val old = manager.frontendCapabilities
|
||||
val new = XFrontendDebuggerCapabilities(
|
||||
// _any_ of clients can show images
|
||||
canShowImages = old.canShowImages || capabilities.canShowImages,
|
||||
)
|
||||
manager.frontendCapabilities = new
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
override suspend fun currentSession(projectId: ProjectId): Flow<XDebugSessionId?> {
|
||||
val project = projectId.findProject()
|
||||
|
||||
+3
@@ -10,6 +10,8 @@
|
||||
<extensionPoints>
|
||||
<extensionPoint name="xdebugger.customQuickEvaluateActionProvider"
|
||||
interface="com.intellij.platform.debugger.impl.frontend.actions.CustomQuickEvaluateActionProvider" dynamic="true"/>
|
||||
<extensionPoint name="xdebugger.imageEditorUIProvider"
|
||||
interface="com.intellij.platform.debugger.impl.frontend.frame.ImageEditorUIProvider" dynamic="true"/>
|
||||
</extensionPoints>
|
||||
<actions resource-bundle="messages.FrontendDebuggerImplBundle">
|
||||
<action id="QuickEvaluateExpression" class="com.intellij.platform.debugger.impl.frontend.actions.QuickEvaluateAction"/>
|
||||
@@ -26,5 +28,6 @@
|
||||
<postStartupActivity implementation="com.intellij.platform.debugger.impl.frontend.FrontendXDebuggerInitializationProjectActivity"/>
|
||||
<xdebugger.managerProxy implementation="com.intellij.platform.debugger.impl.frontend.FrontendXDebugManagerProxy" order="first"/>
|
||||
<platform.rpc.projectRemoteTopicListener implementation="com.intellij.platform.debugger.impl.frontend.ShowBreakpointsDialogRemoteTopicListener"/>
|
||||
<platform.rpc.projectRemoteTopicListener implementation="com.intellij.platform.debugger.impl.frontend.frame.ShowImagePopupRemoteTopicListener"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
|
||||
+11
-4
@@ -13,10 +13,8 @@ import com.intellij.openapi.wm.ToolWindowManager
|
||||
import com.intellij.openapi.wm.ex.ToolWindowManagerListener
|
||||
import com.intellij.platform.debugger.impl.frontend.editor.BreakpointPromoterEditorListener
|
||||
import com.intellij.platform.debugger.impl.frontend.evaluate.quick.common.ValueLookupManager
|
||||
import com.intellij.platform.debugger.impl.rpc.XDebugSessionDto
|
||||
import com.intellij.platform.debugger.impl.rpc.XDebuggerManagerApi
|
||||
import com.intellij.platform.debugger.impl.rpc.XDebuggerManagerSessionEvent
|
||||
import com.intellij.platform.debugger.impl.rpc.XDebuggerValueLookupHintsRemoteApi
|
||||
import com.intellij.platform.debugger.impl.frontend.frame.ImageEditorUIUtil
|
||||
import com.intellij.platform.debugger.impl.rpc.*
|
||||
import com.intellij.platform.project.projectId
|
||||
import com.intellij.ui.content.ContentManagerEvent
|
||||
import com.intellij.ui.content.ContentManagerListener
|
||||
@@ -64,6 +62,9 @@ class FrontendXDebuggerManager(private val project: Project, private val cs: Cor
|
||||
internal val sessions get() = sessionsFlow.value
|
||||
|
||||
init {
|
||||
initCapabilities()
|
||||
// TODO: make sure that capabilities are send before anything else
|
||||
|
||||
cs.launch {
|
||||
for (event in synchronousExecutor) {
|
||||
event()
|
||||
@@ -81,6 +82,12 @@ class FrontendXDebuggerManager(private val project: Project, private val cs: Cor
|
||||
}
|
||||
}
|
||||
|
||||
private fun initCapabilities() = cs.launch {
|
||||
XDebuggerManagerApi.getInstance().initialize(project.projectId(), XFrontendDebuggerCapabilities(
|
||||
canShowImages = ImageEditorUIUtil.canCreateImageEditor(),
|
||||
))
|
||||
}
|
||||
|
||||
private fun initSessions() = cs.launch {
|
||||
// When the registry flag is not set, we would prefer to have XDebugSessionProxy.Monolith in a listener
|
||||
// see com.intellij.xdebugger.impl.MonolithListenerAdapter
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.debugger.impl.frontend.frame
|
||||
|
||||
import com.intellij.CommonBundle
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.runInEdt
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.wm.WindowManager
|
||||
import com.intellij.platform.debugger.impl.shared.ShowImagePopupUtil
|
||||
import com.intellij.platform.rpc.topics.ProjectRemoteTopic
|
||||
import com.intellij.platform.rpc.topics.ProjectRemoteTopicListener
|
||||
import com.intellij.ui.awt.RelativePoint
|
||||
import com.intellij.xdebugger.impl.ui.DebuggerUIUtil
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import java.awt.Dimension
|
||||
import java.awt.Point
|
||||
import javax.swing.JComponent
|
||||
import javax.swing.JLabel
|
||||
import javax.swing.SwingConstants
|
||||
|
||||
@ApiStatus.Internal
|
||||
interface ImageEditorUIProvider {
|
||||
fun createImageEditorUI(imageData: ByteArray): JComponent
|
||||
}
|
||||
|
||||
@ApiStatus.Internal // might be public in theory
|
||||
object ImageEditorUIUtil {
|
||||
private val EP_NAME = ExtensionPointName<ImageEditorUIProvider>("com.intellij.xdebugger.imageEditorUIProvider")
|
||||
|
||||
fun canCreateImageEditor(): Boolean = EP_NAME.hasAnyExtensions()
|
||||
|
||||
fun createImageEditorUI(imageData: ByteArray): JComponent? = EP_NAME.extensionList.firstOrNull()?.createImageEditorUI(imageData)
|
||||
}
|
||||
|
||||
private class ShowImagePopupRemoteTopicListener : ProjectRemoteTopicListener<ShowImagePopupUtil.Request> {
|
||||
override val topic: ProjectRemoteTopic<ShowImagePopupUtil.Request> = ShowImagePopupUtil.REMOTE_TOPIC
|
||||
|
||||
override fun handleEvent(project: Project, event: ShowImagePopupUtil.Request) {
|
||||
runInEdt {
|
||||
val frame = WindowManager.getInstance().getFrame(project)
|
||||
if (frame == null) return@runInEdt
|
||||
val popupSize = Dimension(frame.size.width / 2, frame.size.height / 2)
|
||||
|
||||
val imageData = event.imageData
|
||||
val content =
|
||||
if (imageData != null) ImageEditorUIUtil.createImageEditorUI(imageData) ?: return@runInEdt
|
||||
else JLabel(CommonBundle.message("label.no.data"), SwingConstants.CENTER)
|
||||
|
||||
val popup = DebuggerUIUtil.createValuePopup(project, content, null)
|
||||
if (content is Disposable) {
|
||||
Disposer.register(popup, content)
|
||||
}
|
||||
|
||||
popup.setSize(popupSize)
|
||||
popup.show(RelativePoint(frame, Point(popupSize.width / 2, popupSize.height / 2)))
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
@@ -19,6 +19,8 @@ import org.jetbrains.annotations.ApiStatus
|
||||
@ApiStatus.Internal
|
||||
@Rpc
|
||||
interface XDebuggerManagerApi : RemoteApi<Unit> {
|
||||
suspend fun initialize(projectId: ProjectId, capabilities: XFrontendDebuggerCapabilities)
|
||||
|
||||
suspend fun currentSession(projectId: ProjectId): Flow<XDebugSessionId?>
|
||||
|
||||
suspend fun sessions(projectId: ProjectId): XDebugSessionsList
|
||||
@@ -41,6 +43,12 @@ interface XDebuggerManagerApi : RemoteApi<Unit> {
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
@Serializable
|
||||
data class XFrontendDebuggerCapabilities(
|
||||
val canShowImages: Boolean,
|
||||
)
|
||||
|
||||
@ApiStatus.Internal
|
||||
@Serializable
|
||||
data class XBreakpointsSetDto(
|
||||
|
||||
@@ -24,6 +24,7 @@ jvm_library(
|
||||
"//platform/platform-impl/rpc",
|
||||
"//platform/project/shared:project",
|
||||
"//platform/editor-ui-api:editor-ui",
|
||||
"//platform/remote-topics/shared:rpc-topics",
|
||||
]
|
||||
)
|
||||
### auto-generated section `build intellij.platform.debugger.impl.shared` end
|
||||
@@ -0,0 +1,3 @@
|
||||
*f:com.intellij.platform.debugger.impl.shared.ShowImagePopupUtil
|
||||
- sf:INSTANCE:com.intellij.platform.debugger.impl.shared.ShowImagePopupUtil
|
||||
- sf:showOnFrontend(com.intellij.openapi.project.Project,B[]):V
|
||||
@@ -43,5 +43,6 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.ide.rpc" />
|
||||
<orderEntry type="module" module-name="intellij.platform.project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.editor.ui" />
|
||||
<orderEntry type="module" module-name="intellij.platform.rpc.topics" />
|
||||
</component>
|
||||
</module>
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.debugger.impl.shared
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.platform.rpc.topics.ProjectRemoteTopic
|
||||
import com.intellij.platform.rpc.topics.sendToClient
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Experimental
|
||||
object ShowImagePopupUtil {
|
||||
@ApiStatus.Internal
|
||||
@Serializable
|
||||
class Request(val imageData: ByteArray?)
|
||||
|
||||
@ApiStatus.Internal
|
||||
val REMOTE_TOPIC: ProjectRemoteTopic<Request> = ProjectRemoteTopic("xdebugger.show.image.popup", Request.serializer())
|
||||
|
||||
@JvmStatic
|
||||
fun showOnFrontend(project: Project, imageData: ByteArray?) {
|
||||
REMOTE_TOPIC.sendToClient(project, Request(imageData))
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,7 @@ import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.ui.popup.Balloon;
|
||||
import com.intellij.openapi.wm.IdeGlassPaneUtil;
|
||||
import com.intellij.openapi.wm.ToolWindowId;
|
||||
import com.intellij.platform.debugger.impl.rpc.XFrontendDebuggerCapabilities;
|
||||
import com.intellij.ui.ExperimentalUI;
|
||||
import com.intellij.ui.HintHint;
|
||||
import com.intellij.ui.awt.RelativePoint;
|
||||
@@ -95,6 +96,11 @@ public final class XDebuggerManagerImpl extends XDebuggerManager implements Pers
|
||||
|
||||
private InlayRunToCursorEditorListener myNewRunToCursorListener = null;
|
||||
|
||||
private @NotNull XFrontendDebuggerCapabilities myFrontendCapabilities =
|
||||
new XFrontendDebuggerCapabilities(
|
||||
false
|
||||
);
|
||||
|
||||
XDebuggerManagerImpl(@NotNull Project project, @NotNull CoroutineScope coroutineScope) {
|
||||
myProject = project;
|
||||
myCoroutineScope = coroutineScope;
|
||||
@@ -368,6 +374,15 @@ public final class XDebuggerManagerImpl extends XDebuggerManager implements Pers
|
||||
|
||||
private static final TooltipGroup RUN_TO_CURSOR_TOOLTIP_GROUP = new TooltipGroup("RUN_TO_CURSOR_TOOLTIP_GROUP", 0);
|
||||
|
||||
@ApiStatus.Internal
|
||||
public void setFrontendCapabilities(@NotNull XFrontendDebuggerCapabilities capabilities) {
|
||||
myFrontendCapabilities = capabilities;
|
||||
}
|
||||
|
||||
public @NotNull XFrontendDebuggerCapabilities getFrontendCapabilities() {
|
||||
return myFrontendCapabilities;
|
||||
}
|
||||
|
||||
public static @NotNull NotificationGroup getNotificationGroup() {
|
||||
return NotificationGroupManager.getInstance().getNotificationGroup("Debugger messages");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user