Bug 317207 - View tabs have no context menu - can't make it a fast view
(orientation impl)
diff --git a/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/minmax/Messages.java b/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/minmax/Messages.java
index 84d3eae..af5c3b1 100644
--- a/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/minmax/Messages.java
+++ b/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/minmax/Messages.java
@@ -21,6 +21,8 @@
 	public static String TrimStack_SharedAreaTooltip;
 	public static String TrimStack_CloseText;
 	public static String TrimStack_RestoreText;
+	public static String TrimStack_Horizontal;
+	public static String TrimStack_Vertical;
 
 	private static final String BUNDLE_NAME = "org.eclipse.e4.ui.workbench.addons.minmax.messages";//$NON-NLS-1$
 
diff --git a/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/minmax/TrimPaneLayout.java b/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/minmax/TrimPaneLayout.java
index 0c7c1ac..3f0e373 100644
--- a/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/minmax/TrimPaneLayout.java
+++ b/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/minmax/TrimPaneLayout.java
@@ -11,6 +11,7 @@
 
 package org.eclipse.e4.ui.workbench.addons.minmax;
 
+import org.eclipse.e4.ui.model.application.ui.menu.MToolControl;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.MouseEvent;
 import org.eclipse.swt.events.MouseListener;
@@ -42,8 +43,10 @@
 
 	int trackState = SWT.NONE;
 	protected Point curPos;
+	private MToolControl toolControl;
 
-	public TrimPaneLayout(int barSide) {
+	public TrimPaneLayout(MToolControl toolControl, int barSide) {
+		this.toolControl = toolControl;
 		this.fixedCorner = barSide;
 	}
 
@@ -140,6 +143,14 @@
 
 			public void mouseUp(MouseEvent e) {
 				composite.setCapture(false);
+
+				// Persist the current size
+				Point size = composite.getSize();
+				toolControl.getPersistedState()
+						.put(TrimStack.STATE_XSIZE, Integer.toString(size.x));
+				toolControl.getPersistedState()
+						.put(TrimStack.STATE_YSIZE, Integer.toString(size.y));
+
 				trackState = NOT_SIZING;
 			}
 
diff --git a/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/minmax/TrimStack.java b/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/minmax/TrimStack.java
index b3558c6..ed41b58 100644
--- a/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/minmax/TrimStack.java
+++ b/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/minmax/TrimStack.java
@@ -80,9 +80,9 @@
 
 	private static final String RESTORE_ICON_URI = "platform:/plugin/org.eclipse.e4.ui.workbench.addons.swt/icons/full/etool16/fastview_restore.gif"; //$NON-NLS-1$
 
-	private static final String STATE_XSIZE = "XSize"; //$NON-NLS-1$
+	static final String STATE_XSIZE = "XSize"; //$NON-NLS-1$
 
-	private static final String STATE_YSIZE = "YSize"; //$NON-NLS-1$
+	static final String STATE_YSIZE = "YSize"; //$NON-NLS-1$
 
 	private Image layoutImage;
 
@@ -474,16 +474,74 @@
 		trimStackTB = new ToolBar(parent, orientation | SWT.FLAT | SWT.WRAP);
 		trimStackTB.addListener(SWT.MenuDetect, new Listener() {
 			public void handleEvent(Event event) {
+				// Clear any existing items
+				while (trimStackMenu.getItemCount() > 0)
+					trimStackMenu.getItem(0).dispose();
+
 				// remap the coordinate relative to the control
 				Point point = trimStackTB.getDisplay().map(null, trimStackTB,
 						new Point(event.x, event.y));
 				// get the selected item in question
 				selectedToolItem = trimStackTB.getItem(point);
+
+				if (selectedToolItem == null)
+					return;
+
+				final MPart menuPart = selectedToolItem.getData() instanceof MPart ? (MPart) selectedToolItem
+						.getData() : null;
+				if (menuPart == null)
+					return;
+
+				MenuItem closeItem = new MenuItem(trimStackMenu, SWT.NONE);
+				closeItem.setText(Messages.TrimStack_CloseText);
+				closeItem.addListener(SWT.Selection, new Listener() {
+					public void handleEvent(Event event) {
+						partService.hidePart(menuPart);
+					}
+				});
+
+				MenuItem horizontalItem = new MenuItem(trimStackMenu, SWT.CHECK);
+				horizontalItem.setText(Messages.TrimStack_Horizontal);
+				horizontalItem.setSelection(menuPart.getTags().contains(
+						IPresentationEngine.ORIENTATION_HORIZONTAL));
+				horizontalItem.addListener(SWT.Selection, new Listener() {
+					public void handleEvent(Event event) {
+						if (menuPart.getTags().contains(IPresentationEngine.ORIENTATION_HORIZONTAL)) {
+							menuPart.getTags().remove(IPresentationEngine.ORIENTATION_HORIZONTAL);
+						} else {
+							menuPart.getTags().remove(IPresentationEngine.ORIENTATION_VERTICAL);
+							menuPart.getTags().add(IPresentationEngine.ORIENTATION_HORIZONTAL);
+						}
+						if (isShowing) {
+							setPaneLocation(hostPane);
+						}
+					}
+				});
+
+				MenuItem verticalItem = new MenuItem(trimStackMenu, SWT.CHECK);
+				verticalItem.setText(Messages.TrimStack_Vertical);
+				verticalItem.setSelection(menuPart.getTags().contains(
+						IPresentationEngine.ORIENTATION_VERTICAL));
+				verticalItem.addListener(SWT.Selection, new Listener() {
+					public void handleEvent(Event event) {
+						if (menuPart.getTags().contains(IPresentationEngine.ORIENTATION_VERTICAL)) {
+							menuPart.getTags().remove(IPresentationEngine.ORIENTATION_VERTICAL);
+						} else {
+							menuPart.getTags().remove(IPresentationEngine.ORIENTATION_HORIZONTAL);
+							menuPart.getTags().add(IPresentationEngine.ORIENTATION_VERTICAL);
+						}
+						if (isShowing) {
+							setPaneLocation(hostPane);
+						}
+					}
+				});
 			}
 		});
 
-		if (minimizedElement instanceof MPartStack)
-			createPopupMenu();
+		if (minimizedElement instanceof MPartStack) {
+			trimStackMenu = new Menu(trimStackTB);
+			trimStackTB.setMenu(trimStackMenu);
+		}
 
 		ToolItem restoreBtn = new ToolItem(trimStackTB, SWT.PUSH);
 		restoreBtn.setToolTipText(Messages.TrimStack_RestoreText);
@@ -652,22 +710,6 @@
 		hostPane = null;
 	}
 
-	/**
-	 * Create the popup menu that will appear when a minimized part has been selected by the cursor.
-	 */
-	private void createPopupMenu() {
-		trimStackMenu = new Menu(trimStackTB);
-		trimStackTB.setMenu(trimStackMenu);
-
-		MenuItem closeItem = new MenuItem(trimStackMenu, SWT.NONE);
-		closeItem.setText(Messages.TrimStack_CloseText);
-		closeItem.addListener(SWT.Selection, new Listener() {
-			public void handleEvent(Event event) {
-				partService.hidePart((MPart) selectedToolItem.getData());
-			}
-		});
-	}
-
 	public void showStack(boolean show) {
 		Control ctf = (Control) minimizedElement.getWidget();
 		Composite clientArea = getShellClientComposite();
@@ -696,11 +738,6 @@
 
 			if (hostPane != null && hostPane.isVisible()) {
 				hostPane.setVisible(false);
-
-				// capture the current shell's bounds
-				Point size = hostPane.getSize();
-				toolControl.getPersistedState().put(STATE_XSIZE, Integer.toString(size.x));
-				toolControl.getPersistedState().put(STATE_YSIZE, Integer.toString(size.y));
 			}
 
 			fixToolItemSelection(null);
@@ -727,7 +764,27 @@
 
 		Rectangle caRect = getShellClientComposite().getBounds();
 
-		Point paneSize = hostPane.getSize();
+		// NOTE: always starts in the persisted (or default) size
+		Point paneSize = getHostPane().getSize();
+
+		// Ensure it's not clipped
+		if (paneSize.x > caRect.width)
+			paneSize.x = caRect.width;
+		if (paneSize.y > caRect.height)
+			paneSize.y = caRect.height;
+
+		if (minimizedElement instanceof MPartStack) {
+			MPartStack stack = (MPartStack) minimizedElement;
+			MUIElement stackSel = stack.getSelectedElement();
+			if (stackSel instanceof MPlaceholder)
+				stackSel = ((MPlaceholder) stackSel).getRef();
+			if (stackSel instanceof MPart) {
+				if (stackSel.getTags().contains(IPresentationEngine.ORIENTATION_HORIZONTAL))
+					paneSize.x = caRect.width;
+				if (stackSel.getTags().contains(IPresentationEngine.ORIENTATION_VERTICAL))
+					paneSize.y = caRect.height;
+			}
+		}
 		Point loc = new Point(0, 0);
 
 		if (isFixed(SWT.LEFT))
@@ -740,16 +797,13 @@
 		else
 			loc.y = (caRect.y + caRect.height) - paneSize.y;
 
+		someShell.setSize(paneSize);
 		someShell.setLocation(loc);
 	}
 
-	private Composite getHostPane() {
-		if (hostPane != null)
-			return hostPane;
-
-		// Create one
-		hostPane = new Composite(trimStackTB.getShell(), SWT.NONE);
-		hostPane.setData(ShellActivationListener.DIALOG_IGNORE_KEY, Boolean.TRUE);
+	private void setHostSize() {
+		if (hostPane == null || hostPane.isDisposed())
+			return;
 
 		int xSize = 600;
 		String xSizeStr = toolControl.getPersistedState().get(STATE_XSIZE);
@@ -760,11 +814,24 @@
 		if (ySizeStr != null)
 			ySize = Integer.parseInt(ySizeStr);
 		hostPane.setSize(xSize, ySize);
+	}
+
+	private Composite getHostPane() {
+		if (hostPane != null) {
+			setHostSize(); // Always start with the persisted size
+			return hostPane;
+		}
+
+		// Create one
+		hostPane = new Composite(trimStackTB.getShell(), SWT.NONE);
+		hostPane.setData(ShellActivationListener.DIALOG_IGNORE_KEY, Boolean.TRUE);
+		setHostSize();
+
 		hostPane.addListener(SWT.Traverse, escapeListener);
 
 		// Set a special layout that allows resizing
 		fixedSides = getFixedSides();
-		hostPane.setLayout(new TrimPaneLayout(fixedSides));
+		hostPane.setLayout(new TrimPaneLayout(toolControl, fixedSides));
 
 		return hostPane;
 	}
diff --git a/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/minmax/messages.properties b/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/minmax/messages.properties
index 7295b0b..2a270b4 100644
--- a/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/minmax/messages.properties
+++ b/bundles/org.eclipse.e4.ui.workbench.addons.swt/src/org/eclipse/e4/ui/workbench/addons/minmax/messages.properties
@@ -12,3 +12,5 @@
 TrimStack_SharedAreaTooltip = Shared Area
 TrimStack_CloseText = &Close
 TrimStack_RestoreText = Restore
+TrimStack_Horizontal = Horizontal
+TrimStack_Vertical = Vertical
diff --git a/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/workbench/IPresentationEngine.java b/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/workbench/IPresentationEngine.java
index db6f769..917d6fa 100644
--- a/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/workbench/IPresentationEngine.java
+++ b/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/workbench/IPresentationEngine.java
@@ -74,6 +74,22 @@
 	public static String MINIMIZED_BY_ZOOM = "MinimizedByZoom"; //$NON-NLS-1$
 
 	/**
+	 * This tag can be applied to an element as a hint to the renderers that the element would
+	 * prefer to be horizontal. For an MPart this could be used both as a hint to how to show the
+	 * view when it's in the trim but could also be used when picking a stack to add a newly opening
+	 * part to. It could also be used for example to control where the tabs appear on an MPartStack.
+	 */
+	public static String ORIENTATION_HORIZONTAL = "Horizontal"; //$NON-NLS-1$
+
+	/**
+	 * This tag can be applied to an element as a hint to the renderers that the element would
+	 * prefer to be vertical. For an MPart this could be used both as a hint to how to show the view
+	 * when it's in the trim but could also be used when picking a stack to add a newly opening part
+	 * to. It could also be used for example to control where the tabs appear on an MPartStack.
+	 */
+	public static String ORIENTATION_VERTICAL = "Vertical"; //$NON-NLS-1$
+
+	/**
 	 * This key should be used to add an optional String to an element that is a URI to the elements
 	 * disabled icon. This is used, for example, by Toolbar Items which, in Eclipse SDK, provide a
 	 * unique icon for disabled tool items that look better than the OS default graying on the