diff --git a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchPage.java b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchPage.java index 1a86593f618..11073f4f801 100644 --- a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchPage.java +++ b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchPage.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2020 IBM Corporation and others. + * Copyright (c) 2000, 2026 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -3908,8 +3908,19 @@ private Perspective getPerspective(MPerspective mperspective) { PerspectiveDescriptor perspectiveDesc = (PerspectiveDescriptor) getPerspectiveDesc( mperspective.getElementId()); if (perspectiveDesc == null) { - fixedPerspective = true; - perspectiveDesc = fixOrphanPerspective(mperspective); + if (mperspective.getContributorURI() != null) { + PerspectiveRegistry reg = (PerspectiveRegistry) PlatformUI.getWorkbench().getPerspectiveRegistry(); + // Registers an E4 perspective that is contributed directly via the application + // model (e.g. via a model fragment), without renaming it or marking it as a + // local copy. Unlike PerspectiveRegistry#addPerspective(MPerspective), + // this method does not add the perspective to the application snippets. + reg.createDescriptor(mperspective); + perspectiveDesc = (PerspectiveDescriptor) getPerspectiveDesc(mperspective.getElementId()); + sortedPerspectives.add(perspectiveDesc); + } else { + fixedPerspective = true; + perspectiveDesc = fixOrphanPerspective(mperspective); + } } Perspective p = new Perspective(perspectiveDesc, mperspective, this); modelToPerspectiveMapping.put(mperspective, p); diff --git a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/registry/PerspectiveRegistry.java b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/registry/PerspectiveRegistry.java index cf4ee48d141..14644316d95 100644 --- a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/registry/PerspectiveRegistry.java +++ b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/registry/PerspectiveRegistry.java @@ -114,7 +114,7 @@ public void addPerspective(MPerspective perspective) { createDescriptor(perspective); } - private void createDescriptor(MPerspective perspective) { + public void createDescriptor(MPerspective perspective) { String label = perspective.getLocalizedLabel(); String originalId = getOriginalId(perspective); PerspectiveDescriptor originalDescriptor = descriptors.get(originalId); @@ -319,7 +319,7 @@ private String getOriginalId(MPerspective p) { p.getContributorURI())); } int index = id.lastIndexOf('.'); - // Custom perspectives store the user defined names in their labels + // Custom perspectives store the user defined names in their labels. String trimE4 = label.trim(); String trimE3 = label.replace(' ', '_').trim(); if (id.endsWith(label)) { diff --git a/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/api/IWorkbenchPageTest.java b/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/api/IWorkbenchPageTest.java index 613947887ab..62dbe09bb39 100644 --- a/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/api/IWorkbenchPageTest.java +++ b/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/api/IWorkbenchPageTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2019 IBM Corporation and others. + * Copyright (c) 2000, 2026 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -48,7 +48,10 @@ import org.eclipse.core.runtime.ILogListener; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; +import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective; +import org.eclipse.e4.ui.model.application.ui.advanced.MPerspectiveStack; import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.workbench.modeling.EModelService; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.swt.events.ShellEvent; @@ -80,7 +83,9 @@ import org.eclipse.ui.ide.IDE; import org.eclipse.ui.internal.WorkbenchPage; import org.eclipse.ui.internal.WorkbenchPlugin; +import org.eclipse.ui.internal.WorkbenchWindow; import org.eclipse.ui.internal.registry.IActionSetDescriptor; +import org.eclipse.ui.internal.registry.PerspectiveDescriptor; import org.eclipse.ui.internal.util.Util; import org.eclipse.ui.navigator.resources.ProjectExplorer; import org.eclipse.ui.part.FileEditorInput; @@ -3349,6 +3354,43 @@ public void testGetViewStackWithSecondaryId() throws PartInitException { assertEquals(part, stack[0]); } + @Test + public void testE4PerspectiveNotConvertedToLocalCopy() { + IWorkbenchWindow window = openTestWindow(); + EModelService modelService = window.getService(EModelService.class); + + WorkbenchWindow workbenchWindow = (WorkbenchWindow) window; + List stacks = modelService.findElements(workbenchWindow.getModel(), null, + MPerspectiveStack.class); + assertFalse("Perspective stack should exist in the window model", stacks.isEmpty()); + MPerspectiveStack perspectiveStack = stacks.get(0); + + String e4Id = "org.eclipse.ui.tests.internal.e4.perspective.model"; + String e4Label = "E4ModelPerspective"; + + assertNull("e4 perspective ID should not be in perspective registry", + PlatformUI.getWorkbench().getPerspectiveRegistry().findPerspectiveWithId(e4Id)); + + MPerspective e4Perspective = modelService.createModelElement(MPerspective.class); + e4Perspective.setElementId(e4Id); + e4Perspective.setLabel(e4Label); + e4Perspective.setContributorURI("platform:/plugin/org.eclipse.ui.tests"); + + perspectiveStack.getChildren().add(e4Perspective); + perspectiveStack.setSelectedElement(e4Perspective); + processEvents(); + + assertEquals("Element ID should not have changed", e4Id, e4Perspective.getElementId()); + + IPerspectiveDescriptor descriptor = PlatformUI.getWorkbench().getPerspectiveRegistry() + .findPerspectiveWithId(e4Id); + assertNotNull(descriptor); + + assertFalse(((PerspectiveDescriptor) descriptor).hasCustomDefinition()); + + PlatformUI.getWorkbench().getPerspectiveRegistry().deletePerspective(descriptor); + } + private static class ShellStateListener implements ShellListener { private final AtomicBoolean shellIsActive; diff --git a/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/internal/InternalTestSuite.java b/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/internal/InternalTestSuite.java index 6c9b079ba52..bb9e013a2a5 100644 --- a/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/internal/InternalTestSuite.java +++ b/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/internal/InternalTestSuite.java @@ -30,7 +30,6 @@ import org.eclipse.ui.tests.markers.MarkerViewUtilTest; import org.eclipse.ui.tests.markers.ResourceMappingMarkersTest; import org.eclipse.ui.tests.markers.ScopeAreaTest; - import org.junit.platform.suite.api.SelectClasses; import org.junit.platform.suite.api.Suite;