Bug 400276 - Errors when removing or moving multiple parts from/between stacks

Fix StackRenderer to handle the case from an ADD_MANY where a
collection of new parts may have been added to a part stack.  Fix
CleanupAddon to handle REMOVE_MANY.

Also fixed two other locations to do with ADD_MANY/REMOVE_MANY.
  * Workbench to handle REMOVE_MANY for multiple perspectives
  * MinMaxAddon to also handle REMOVE_MANY of multiple stacks
    from the trim bars
Added references to UIEvents to ADD_MANY/REMOVE_MANY to hint
for developers to consider ADD/ADD_MANY and REMOVE/REMOVE_MANY.
diff --git a/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/cleanupaddon/CleanupAddon.java b/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/cleanupaddon/CleanupAddon.java
index 93f07e9..56fcc60 100644
--- a/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/cleanupaddon/CleanupAddon.java
+++ b/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/cleanupaddon/CleanupAddon.java
@@ -55,8 +55,7 @@
 	private EventHandler childrenHandler = new EventHandler() {
 		public void handleEvent(Event event) {
 			Object changedObj = event.getProperty(UIEvents.EventTags.ELEMENT);
-			String eventType = (String) event.getProperty(UIEvents.EventTags.TYPE);
-			if (UIEvents.EventTypes.REMOVE.equals(eventType)) {
+			if (UIEvents.isREMOVE(event)) {
 				final MElementContainer<?> container = (MElementContainer<?>) changedObj;
 				MUIElement containerParent = container.getParent();
 
diff --git a/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/minmax/MinMaxAddon.java b/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/minmax/MinMaxAddon.java
index 137457e..97c05bd 100644
--- a/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/minmax/MinMaxAddon.java
+++ b/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/minmax/MinMaxAddon.java
@@ -407,26 +407,28 @@
 					|| modelService.getTopLevelWindowFor(changedElement) == null)
 				return;
 
-			String eventType = (String) event.getProperty(UIEvents.EventTags.TYPE);
-			if (UIEvents.EventTypes.REMOVE.equals(eventType)) {
-				MUIElement removed = (MUIElement) event.getProperty(UIEvents.EventTags.OLD_VALUE);
-				String perspectiveId = removed.getElementId();
-				MWindow window = modelService.getTopLevelWindowFor(changedElement);
-				MTrimBar bar = modelService.getTrim((MTrimmedWindow) window, SideValue.TOP);
+			if (UIEvents.isREMOVE(event)) {
+				for (Object removedElement : UIEvents.asIterable(event,
+						UIEvents.EventTags.OLD_VALUE)) {
+					MUIElement removed = (MUIElement) removedElement;
+					String perspectiveId = removed.getElementId();
+					MWindow window = modelService.getTopLevelWindowFor(changedElement);
+					MTrimBar bar = modelService.getTrim((MTrimmedWindow) window, SideValue.TOP);
 
-				// gather up any minimized stacks for this perspective...
-				List<MToolControl> toRemove = new ArrayList<MToolControl>();
-				for (MUIElement child : bar.getChildren()) {
-					String trimElementId = child.getElementId();
-					if (child instanceof MToolControl && trimElementId.contains(perspectiveId)) {
-						toRemove.add((MToolControl) child);
+					// gather up any minimized stacks for this perspective...
+					List<MToolControl> toRemove = new ArrayList<MToolControl>();
+					for (MUIElement child : bar.getChildren()) {
+						String trimElementId = child.getElementId();
+						if (child instanceof MToolControl && trimElementId.contains(perspectiveId)) {
+							toRemove.add((MToolControl) child);
+						}
 					}
-				}
 
-				// ...and remove them
-				for (MToolControl minStack : toRemove) {
-					minStack.setToBeRendered(false);
-					bar.getChildren().remove(minStack);
+					// ...and remove them
+					for (MToolControl minStack : toRemove) {
+						minStack.setToBeRendered(false);
+						bar.getChildren().remove(minStack);
+					}
 				}
 			}
 		}
diff --git a/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/StackRenderer.java b/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/StackRenderer.java
index a67d495..eb092f5 100644
--- a/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/StackRenderer.java
+++ b/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/StackRenderer.java
@@ -764,8 +764,9 @@
 			createFlags |= SWT.CLOSE;
 		}
 
-		// Create the tab
-		int index = calcIndexFor(stack, element);
+		// Create the tab; we may have more visible tabs than currently shown
+		// (e.g., a result of calling partStack.getChildren().addAll(partList))
+		int index = Math.min(calcIndexFor(stack, element), ctf.getItemCount());
 		cti = new CTabItem(ctf, createFlags, index);
 
 		cti.setData(OWNING_ME, element);
diff --git a/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/workbench/UIEvents.java b/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/workbench/UIEvents.java
index 2bd62a5..0e3f266 100644
--- a/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/workbench/UIEvents.java
+++ b/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/workbench/UIEvents.java
@@ -65,21 +65,29 @@
 		 */
 		public static final String SET = "SET"; //$NON-NLS-1$
 		/**
-		 * Add event: value added is {@link EventTags#NEW_VALUE}
+		 * Add event: value added is {@link EventTags#NEW_VALUE}.
+		 * 
+		 * @see UIEvents#isADD(Event)
 		 */
 		public static final String ADD = "ADD"; //$NON-NLS-1$
 		/**
 		 * Add many items: values added are {@link EventTags#NEW_VALUE}
+		 * 
+		 * @see UIEvents#isADD(Event)
 		 */
 		public static final String ADD_MANY = "ADD_MANY";//$NON-NLS-1$
 		/**
 		 * Remove event: value removed is {@link EventTags#OLD_VALUE}
+		 * 
+		 * @see UIEvents#isREMOVE(Event)
 		 */
 		public static final String REMOVE = "REMOVE"; //$NON-NLS-1$
 		/**
 		 * Remove many event: the values removed are the {@link EventTags#OLD_VALUE} (a collection).
 		 * The former positions of the removed values are provided as an integer array in
 		 * {@link EventTags#POSITION}.
+		 * 
+		 * @see UIEvents#isREMOVE(Event)
 		 */
 		public static final String REMOVE_MANY = "REMOVE_MANY"; //$NON-NLS-1$
 		/**
@@ -94,6 +102,8 @@
 	 *            An OSGI event representing a UIEvent
 	 * @return true if it is an add event (i.e., {@link EventTypes#ADD} or
 	 *         {@link EventTypes#ADD_MANY}), or false otherwise.
+	 * @see UIEvents.EventTags#NEW_VALUE
+	 * @see #asIterable(Event, String)
 	 */
 	public static boolean isADD(Event event) {
 		Object type = event.getProperty(UIEvents.EventTags.TYPE);
@@ -105,6 +115,8 @@
 	 *            An OSGI event representing a UIEvent
 	 * @return true if it is a remove event (i.e., {@link EventTypes#REMOVE} or
 	 *         {@link EventTypes#REMOVE_MANY}), or false otherwise.
+	 * @see UIEvents.EventTags#OLD_VALUE
+	 * @see #asIterable(Event, String)
 	 */
 	public static boolean isREMOVE(Event event) {
 		Object type = event.getProperty(UIEvents.EventTags.TYPE);
diff --git a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/Workbench.java b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/Workbench.java
index 9763f83..a6694f6 100644
--- a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/Workbench.java
+++ b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/Workbench.java
@@ -1733,15 +1733,17 @@
 		eventBroker.subscribe(UIEvents.ElementContainer.TOPIC_CHILDREN, new EventHandler() {
 			public void handleEvent(org.osgi.service.event.Event event) {
 				if (application == event.getProperty(UIEvents.EventTags.ELEMENT)) {
-					if (UIEvents.EventTypes.REMOVE.equals(event
-							.getProperty(UIEvents.EventTags.TYPE))) {
-						MWindow window = (MWindow) event.getProperty(UIEvents.EventTags.OLD_VALUE);
-						IEclipseContext windowContext = window.getContext();
-						if (windowContext != null) {
-							IWorkbenchWindow wwindow = (IWorkbenchWindow) windowContext
-									.get(IWorkbenchWindow.class.getName());
-							if (wwindow != null) {
-								fireWindowClosed(wwindow);
+					if (UIEvents.isREMOVE(event)) {
+						for (Object removed : UIEvents.asIterable(event,
+								UIEvents.EventTags.OLD_VALUE)) {
+							MWindow window = (MWindow) removed;
+							IEclipseContext windowContext = window.getContext();
+							if (windowContext != null) {
+								IWorkbenchWindow wwindow = (IWorkbenchWindow) windowContext
+										.get(IWorkbenchWindow.class.getName());
+								if (wwindow != null) {
+									fireWindowClosed(wwindow);
+								}
 							}
 						}
 					}