diff --git a/ui/org.eclipse.tools.layout.spy/META-INF/MANIFEST.MF b/ui/org.eclipse.tools.layout.spy/META-INF/MANIFEST.MF
index 5b7a4afec87..f638829d595 100644
--- a/ui/org.eclipse.tools.layout.spy/META-INF/MANIFEST.MF
+++ b/ui/org.eclipse.tools.layout.spy/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %name
Bundle-SymbolicName: org.eclipse.tools.layout.spy;singleton:=true
-Bundle-Version: 1.3.100.qualifier
+Bundle-Version: 1.3.200.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-Localization: plugin
Require-Bundle: org.eclipse.jface.databinding;bundle-version="1.9.0",
@@ -10,7 +10,8 @@ Require-Bundle: org.eclipse.jface.databinding;bundle-version="1.9.0",
org.eclipse.jdt.annotation;resolution:=optional,
org.eclipse.core.databinding.property;bundle-version="1.6.0",
org.eclipse.ui;bundle-version="3.208.0"
-Import-Package: org.eclipse.core.runtime;version="[3.7.0,4)",
+Import-Package: jakarta.annotation;version="[2.0.0,4.0.0)",
+ org.eclipse.core.runtime;version="[3.7.0,4)",
org.eclipse.osgi.util,
org.osgi.framework;version="[1.10.0,2.0.0)"
Bundle-Vendor: %provider-name
diff --git a/ui/org.eclipse.tools.layout.spy/plugin.xml b/ui/org.eclipse.tools.layout.spy/plugin.xml
index 010e111a288..6b1af40ce67 100644
--- a/ui/org.eclipse.tools.layout.spy/plugin.xml
+++ b/ui/org.eclipse.tools.layout.spy/plugin.xml
@@ -53,5 +53,14 @@
commandId="org.eclipse.tools.layout.spy.commands.layoutSpyCommand">
+
+
+
+
diff --git a/ui/org.eclipse.tools.layout.spy/src/org/eclipse/tools/layout/spy/internal/dialogs/LayoutSpyDialog.java b/ui/org.eclipse.tools.layout.spy/src/org/eclipse/tools/layout/spy/internal/dialogs/LayoutSpyDialog.java
index 3156419e582..b4ff1b23236 100644
--- a/ui/org.eclipse.tools.layout.spy/src/org/eclipse/tools/layout/spy/internal/dialogs/LayoutSpyDialog.java
+++ b/ui/org.eclipse.tools.layout.spy/src/org/eclipse/tools/layout/spy/internal/dialogs/LayoutSpyDialog.java
@@ -79,7 +79,10 @@ public class LayoutSpyDialog {
* Value used to indicate an unknown hint value
*/
private static final int UNKNOWN = -2;
+ /** The shell owned by the standalone dialog, or {@code null} when hosted in a part. */
private Shell shell;
+ /** The composite the spy contents are built into (the owned shell or a hosting part). */
+ private Composite container;
// Controls
private TableViewer childList;
@@ -118,12 +121,35 @@ public Color getForeground(Object element) {
}
/**
- * Creates the dialog but does not make it visible.
+ * Creates the layout spy in its own shell but does not make it visible. Used
+ * by the standalone command so the spy can still be opened on top of blocking
+ * dialogs.
*
* @param parentShell
* the parent shell
*/
public LayoutSpyDialog(Shell parentShell) {
+ shell = new Shell(parentShell, SWT.SHELL_TRIM);
+ shell.setText(Messages.LayoutSpyDialog_shell_text);
+ createContents(shell);
+ openComposite(parentShell);
+ }
+
+ /**
+ * Creates the layout spy inside the given composite, for example a part
+ * hosted in the PDE spy window. The spy does not own the surrounding shell in
+ * this case.
+ *
+ * @param parent
+ * the composite the spy contents are built into
+ */
+ public LayoutSpyDialog(Composite parent) {
+ createContents(parent);
+ }
+
+ private void createContents(Composite container) {
+ this.container = container;
+
overlay = new Shell(SWT.ON_TOP | SWT.NO_TRIM);
{
overlay.addPaintListener(this::paintOverlay);
@@ -132,10 +158,7 @@ public LayoutSpyDialog(Shell parentShell) {
overlay.setRegion(region);
}
- shell = new Shell(parentShell, SWT.SHELL_TRIM);
- shell.setText(Messages.LayoutSpyDialog_shell_text);
-
- resources = new LocalResourceManager(JFaceResources.getResources(), shell);
+ resources = new LocalResourceManager(JFaceResources.getResources(), container);
Bundle bundle = FrameworkUtil.getBundle(LayoutSpyDialog.class);
final URL fullPathString = FileLocator.find(bundle, IPath.fromOSString("icons/up_nav.svg"), null);
@@ -143,7 +166,7 @@ public LayoutSpyDialog(Shell parentShell) {
upImage = resources.create(imageDesc);
- Composite infoRegion = new Composite(shell, SWT.NONE);
+ Composite infoRegion = new Composite(container, SWT.NONE);
{
Composite headerRegion = new Composite(infoRegion, SWT.NONE);
{
@@ -167,20 +190,20 @@ public LayoutSpyDialog(Shell parentShell) {
GridLayoutFactory.fillDefaults().numColumns(2).equalWidth(true).generateLayout(infoRegion);
}
- diagnostics = new Text(shell, SWT.READ_ONLY | SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
+ diagnostics = new Text(container, SWT.READ_ONLY | SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
GridDataFactory.fillDefaults().hint(300, 300).grab(true, true).applyTo(diagnostics);
- Button showOverlayButton = new Button(shell, SWT.CHECK);
+ Button showOverlayButton = new Button(container, SWT.CHECK);
showOverlayButton.setText(Messages.LayoutSpyDialog_button_show_overlay);
- showColoringButton = new Button(shell, SWT.CHECK);
+ showColoringButton = new Button(container, SWT.CHECK);
showColoringButton.setText(Messages.LayoutSpyDialog_button_show_coloring);
showColoringButton.addSelectionListener(widgetSelectedAdapter(e-> {
LayoutIssuesDebugFilter.activate(showColoringButton.getSelection(), true, 0);
}));
showColoringButton.addDisposeListener((e -> LayoutIssuesDebugFilter.activate(false, true, 0)));
- Composite buttonBar = new Composite(shell, SWT.NONE);
+ Composite buttonBar = new Composite(container, SWT.NONE);
{
selectWidgetButton = new Button(buttonBar, SWT.PUSH);
selectWidgetButton.setText(Messages.LayoutSpyDialog_button_select_control);
@@ -193,10 +216,10 @@ public LayoutSpyDialog(Shell parentShell) {
}
GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(buttonBar);
- GridLayoutFactory.fillDefaults().margins(LayoutConstants.getMargins()).generateLayout(shell);
+ GridLayoutFactory.fillDefaults().margins(LayoutConstants.getMargins()).generateLayout(container);
// Attach listeners
- shell.addDisposeListener(event -> disposed());
+ container.addDisposeListener(event -> disposed());
selectWidgetButton.addListener(SWT.Selection, event -> selectControl());
goUpButton.addListener(SWT.Selection, event -> goUp());
goDownButton.addListener(SWT.Selection, event -> goDown());
@@ -220,17 +243,15 @@ protected List calculate() {
}
};
childList.setInput(listContents);
- ISideEffectFactory sideEffectFactory = WidgetSideEffects.createFactory(shell);
+ ISideEffectFactory sideEffectFactory = WidgetSideEffects.createFactory(container);
sideEffectFactory.create(this::computeParentInfo, details::setText);
sideEffectFactory.create(this::computeChildInfo, diagnostics::setText);
sideEffectFactory.create(this::updateOverlay);
// ignore controls to the layout spy from coloring
- shell.setData(LayoutIssuesDebugFilter.IGNORE_BY_LAYOUT_ISSUES_DEBUG_FILTER);
- setChildrenColoring(shell);
-
- openComposite(parentShell);
+ container.setData(LayoutIssuesDebugFilter.IGNORE_BY_LAYOUT_ISSUES_DEBUG_FILTER);
+ setChildrenColoring(container);
}
private void setChildrenColoring(Control control) {
@@ -394,13 +415,13 @@ protected void paintOverlay(PaintEvent e) {
*/
private void selectControl() {
this.controlSelectorOpen.setValue(true);
- this.shell.setVisible(false);
+ this.container.getShell().setVisible(false);
new ControlSelector((@Nullable Control control) -> {
if (control != null) {
openControl(control);
}
this.controlSelectorOpen.setValue(false);
- this.shell.setVisible(true);
+ this.container.getShell().setVisible(true);
});
}
diff --git a/ui/org.eclipse.tools.layout.spy/src/org/eclipse/tools/layout/spy/internal/parts/LayoutSpyPart.java b/ui/org.eclipse.tools.layout.spy/src/org/eclipse/tools/layout/spy/internal/parts/LayoutSpyPart.java
new file mode 100644
index 00000000000..2b80517e379
--- /dev/null
+++ b/ui/org.eclipse.tools.layout.spy/src/org/eclipse/tools/layout/spy/internal/parts/LayoutSpyPart.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2026 Vogella GmbH and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Lars Vogel - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tools.layout.spy.internal.parts;
+
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.tools.layout.spy.internal.dialogs.LayoutSpyDialog;
+
+import jakarta.annotation.PostConstruct;
+
+/**
+ * Hosts the layout spy as a part in the PDE spy window. The standalone command
+ * remains available so the spy can still be opened on top of blocking dialogs.
+ */
+public class LayoutSpyPart {
+
+ @PostConstruct
+ public void createControls(Composite parent) {
+ new LayoutSpyDialog(parent);
+ }
+}