Bug 572598 - Reset perspective destroys toolbar of shared part

When a perspective is reset, all old stacks are removed. This calls
removeGui on all shared elements. Shared part disconnect from the
placeholders in the stacks to be disposed, see ElementReferenceRenderer.
However, visible toolbars remain in the stacks, therefore the toolbar
are disposed. As a result, the toolbar is no longer visible in other
placeholders.

Before the gui is removed, hideChild is called on the parent renderer.
The LazyStackRenderer should be hiding the toolbar of the active part on
this call anyhow. (And only if it is currently showing the shared part.)
Side effect of this is that the toolbar is moved to the limbo shell, and
is no longer contained in the widgets of the stack. As a result, the
toolbar is also not disposed when the stack is disposed.

Change-Id: Ic1ad9b0d035fcf8262387a00bdd987c7258df925
Signed-off-by: Rolf Theunissen <rolf.theunissen@gmail.com>
Reviewed-on: https://git.eclipse.org/r/c/platform/eclipse.platform.ui/+/179050
Tested-by: Platform Bot <platform-bot@eclipse.org>
diff --git a/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/LazyStackRenderer.java b/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/LazyStackRenderer.java
index 70ae7a7..71de477 100644
--- a/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/LazyStackRenderer.java
+++ b/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/LazyStackRenderer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2020 IBM Corporation and others.
+ * Copyright (c) 2008, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -135,6 +135,13 @@
 		}
 	}
 
+	@Override
+	public void hideChild(MElementContainer<MUIElement> parentElement, MUIElement child) {
+		super.hideChild(parentElement, child);
+
+		hideElementRecursive(child);
+	}
+
 	@Inject
 	@Optional
 	private void subscribePartTopicToolbar(@UIEventTopic(UIEvents.Part.TOPIC_TOOLBAR) Event event) {
@@ -227,9 +234,12 @@
 			return;
 		}
 
+		// Recursively hide placeholder refs if reference is current
 		if (element instanceof MPlaceholder) {
 			MPlaceholder ph = (MPlaceholder) element;
-			element = ph.getRef();
+			if (ph.getRef() != null && ph.getRef().getCurSharedRef() == ph) {
+				hideElementRecursive(ph.getRef());
+			}
 		}
 
 		// Hide any floating windows
@@ -296,7 +306,7 @@
 				refCtrl.requestLayout();
 			}
 
-			element = ref;
+			showElementRecursive(ref);
 		}
 
 		if (element instanceof MPart) {
diff --git a/tests/org.eclipse.e4.ui.tests/src/org/eclipse/e4/ui/workbench/renderers/swt/StackRendererTest.java b/tests/org.eclipse.e4.ui.tests/src/org/eclipse/e4/ui/workbench/renderers/swt/StackRendererTest.java
index 07e018b..36a89e8 100644
--- a/tests/org.eclipse.e4.ui.tests/src/org/eclipse/e4/ui/workbench/renderers/swt/StackRendererTest.java
+++ b/tests/org.eclipse.e4.ui.tests/src/org/eclipse/e4/ui/workbench/renderers/swt/StackRendererTest.java
@@ -18,6 +18,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 import java.lang.reflect.InvocationHandler;
@@ -45,6 +46,7 @@
 import org.eclipse.swt.custom.CTabFolder;
 import org.eclipse.swt.custom.CTabItem;
 import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Widget;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -293,6 +295,44 @@
 		assertFalse(toolbar2.isVisible());
 	}
 
+	@Test
+	public void testBug572598_SharedPartAndToolbarNotDisposed() {
+		MPart part = ems.createModelElement(MPart.class);
+		window.getSharedElements().add(part);
+
+		MToolBar toolbar = ems.createModelElement(MToolBar.class);
+		part.setToolbar(toolbar);
+
+		MPlaceholder ph1 = ems.createModelElement(MPlaceholder.class);
+		ph1.setRef(part);
+		partStack.getChildren().add(ph1);
+		partStack.setSelectedElement(ph1);
+
+		MPartStack partStack2 = ems.createModelElement(MPartStack.class);
+		window.getChildren().add(partStack2);
+		window.setSelectedElement(partStack2);
+
+		MPlaceholder ph2 = ems.createModelElement(MPlaceholder.class);
+		ph2.setRef(part);
+		partStack2.getChildren().add(ph2);
+		partStack2.setSelectedElement(ph2);
+
+		contextRule.createAndRunWorkbench(window);
+
+		assertNotNull(part.getWidget());
+		assertFalse(((Widget) part.getWidget()).isDisposed());
+		assertNotNull(toolbar.getWidget());
+		assertFalse(((Widget) toolbar.getWidget()).isDisposed());
+
+		// Destroy the second partstack; This should not dispose the shared elements
+		partStack2.setToBeRendered(false);
+
+		assertNotNull(part.getWidget());
+		assertFalse(((Widget) part.getWidget()).isDisposed());
+		assertNotNull(toolbar.getWidget());
+		assertFalse(((Widget) toolbar.getWidget()).isDisposed());
+	}
+
 	// helper functions
 
 	/*