From 9b782ca58bf102fb1e7c8b7cc81c463d43b35d52 Mon Sep 17 00:00:00 2001
From: Alexander Diewald <diewald@fortiss.org>
Date: Wed, 2 Oct 2019 18:29:25 +0200
Subject: [PATCH] Clone the ZoomComboContributionItem

Issue-Ref: 3672
Issue-Url: https://af3-developer.fortiss.org/issues/3672
Signed-off-by: Alexander Diewald <diewald@fortiss.org>
---
 .../fortiss/tooling/base/ui/editor/.ratings   |   2 +-
 .../ZoomComboContributionItemFixed.java       | 265 +++++++++++++++++-
 2 files changed, 254 insertions(+), 13 deletions(-)

diff --git a/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/editor/.ratings b/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/editor/.ratings
index d12fd5381..500101b9b 100644
--- a/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/editor/.ratings
+++ b/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/editor/.ratings
@@ -11,4 +11,4 @@ SourceEditorBase.java 662b921019fed964cd47838e8758194b66fa3a63 GREEN
 SourceEditorConfigurationBase.java e8b810c0d974c475f0a8e6f21aa5b6fd9e17c33a GREEN
 SourceEditorUndoRedo.java 08127a8e0afb4f9c2f4c21294ca3220282c25bf0 GREEN
 TreeViewerEditorBase.java 1c59689ff57c4f3cc180d85f13021fc03461ecb0 GREEN
-ZoomComboContributionItemFixed.java 274593bfb24461c39e70e048de6242e8a1660265 YELLOW
+ZoomComboContributionItemFixed.java 9460fd22bb746efa5ef84d3ba2e3a309ba5dbd0c RED
diff --git a/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/editor/ZoomComboContributionItemFixed.java b/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/editor/ZoomComboContributionItemFixed.java
index 274593bfb..9460fd22b 100644
--- a/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/editor/ZoomComboContributionItemFixed.java
+++ b/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/editor/ZoomComboContributionItemFixed.java
@@ -15,39 +15,280 @@
 +--------------------------------------------------------------------------*/
 package org.fortiss.tooling.base.ui.editor;
 
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.gef.editparts.ZoomListener;
+import org.eclipse.gef.editparts.ZoomManager;
 import org.eclipse.gef.ui.actions.ZoomComboContributionItem;
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.custom.CCombo;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.ui.IPartListener;
 import org.eclipse.ui.IPartService;
+import org.eclipse.ui.IWorkbenchPart;
 
 /**
- * Overwrites {@link ZoomComboContributionItem} to fix the height adjustment of the zoom combo box.
- * 
- * @author diewald
+ * Copy of ZoomComboContributionItem with a CCombo.
  */
+@SuppressWarnings("javadoc")
 public class ZoomComboContributionItemFixed extends ZoomComboContributionItem {
 
-	/** See {@link ZoomComboContributionItem#ZoomComboContributionItem(IPartService)}. */
+	private boolean forceSetText;
+	private CCombo combo;
+	private String[] initStrings;
+	private ToolItem toolitem;
+	private ZoomManager zoomManager;
+	private IPartService service;
+	private IPartListener partListener;
+
+	/**
+	 * Constructor for ComboToolItem.
+	 * 
+	 * @param partService
+	 *            used to add a PartListener
+	 */
 	public ZoomComboContributionItemFixed(IPartService partService) {
-		super(partService);
+		this(partService, "8888%");//$NON-NLS-1$
 	}
 
-	/** See {@link ZoomComboContributionItem#ZoomComboContributionItem(IPartService, String)}. */
+	/**
+	 * Constructor for ComboToolItem.
+	 * 
+	 * @param partService
+	 *            used to add a PartListener
+	 * @param initString
+	 *            the initial string displayed in the combo
+	 */
 	public ZoomComboContributionItemFixed(IPartService partService, String initString) {
-		super(partService, initString);
+		this(partService, new String[] {initString});
 	}
 
-	/** See {@link ZoomComboContributionItem#ZoomComboContributionItem(IPartService, String[])}. */
+	/**
+	 * Constructor for ComboToolItem.
+	 * 
+	 * @param partService
+	 *            used to add a PartListener
+	 * @param initStrings
+	 *            the initial string displayed in the combo
+	 */
 	public ZoomComboContributionItemFixed(IPartService partService, String[] initStrings) {
 		super(partService, initStrings);
+		this.initStrings = initStrings;
+		service = partService;
+		Assert.isNotNull(partService);
+		partService.addPartListener(partListener = new IPartListener() {
+			@Override
+			public void partActivated(IWorkbenchPart part) {
+				setZoomManager((ZoomManager)part.getAdapter(ZoomManager.class));
+			}
+
+			@Override
+			public void partBroughtToTop(IWorkbenchPart p) {
+			}
+
+			@Override
+			public void partClosed(IWorkbenchPart p) {
+			}
+
+			@Override
+			public void partDeactivated(IWorkbenchPart p) {
+			}
+
+			@Override
+			public void partOpened(IWorkbenchPart p) {
+			}
+		});
+	}
+
+	private void refresh(boolean repopulateCombo) {
+		if(combo == null || combo.isDisposed())
+			return;
+		// $TODO GTK workaround
+		try {
+			if(zoomManager == null) {
+				combo.setEnabled(false);
+				combo.setText(""); //$NON-NLS-1$
+			} else {
+				if(repopulateCombo)
+					combo.setItems(getZoomManager().getZoomLevelsAsText());
+				String zoom = getZoomManager().getZoomAsText();
+				int index = combo.indexOf(zoom);
+				if(index == -1 || forceSetText)
+					combo.setText(zoom);
+				else
+					combo.select(index);
+				combo.setEnabled(true);
+			}
+		} catch(SWTException exception) {
+			if(!SWT.getPlatform().equals("gtk")) //$NON-NLS-1$
+				throw exception;
+		}
+	}
+
+	/**
+	 * Computes the width required by control
+	 * 
+	 * @param control
+	 *            The control to compute width
+	 * @return int The width required
+	 */
+	@Override
+	protected int computeWidth(Control control) {
+		return control.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x;
 	}
 
-	/** {@inheritDoc} */
+	/**
+	 * Creates and returns the control for this contribution item under the
+	 * given parent composite.
+	 * 
+	 * @param parent
+	 *            the parent composite
+	 * @return the new control
+	 */
 	@Override
 	protected Control createControl(Composite parent) {
-		Control control = super.createControl(parent);
-		parent.setSize(control.computeSize(SWT.DEFAULT, SWT.DEFAULT));
-		return control;
+		combo = new CCombo(parent, SWT.DROP_DOWN);
+		combo.addSelectionListener(new SelectionListener() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				handleWidgetSelected(e);
+			}
+
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {
+				handleWidgetDefaultSelected(e);
+			}
+		});
+		combo.addFocusListener(new FocusListener() {
+			@Override
+			public void focusGained(FocusEvent e) {
+				// do nothing
+			}
+
+			@Override
+			public void focusLost(FocusEvent e) {
+				refresh(false);
+			}
+		});
+
+		// Initialize width of combo
+		combo.setItems(initStrings);
+		toolitem.setWidth(computeWidth(combo));
+		combo.setSize(combo.computeSize(SWT.DEFAULT, SWT.DEFAULT, true));
+		parent.setSize(combo.computeSize(parent.getSize().x, SWT.DEFAULT, true));
+		return combo;
 	}
+
+	/**
+	 * @see org.eclipse.jface.action.ContributionItem#dispose()
+	 */
+	@Override
+	public void dispose() {
+		if(partListener == null)
+			return;
+		service.removePartListener(partListener);
+		if(zoomManager != null) {
+			zoomManager.removeZoomListener(this);
+			zoomManager = null;
+		}
+		combo = null;
+		partListener = null;
+	}
+
+	/**
+	 * The control item implementation of this <code>IContributionItem</code>
+	 * method calls the <code>createControl</code> framework method to create a
+	 * control under the given parent, and then creates a new tool item to hold
+	 * it. Subclasses must implement <code>createControl</code> rather than
+	 * overriding this method.
+	 * 
+	 * @param parent
+	 *            The ToolBar to add the new control to
+	 * @param index
+	 *            Index
+	 */
+	@Override
+	public void fill(ToolBar parent, int index) {
+		toolitem = new ToolItem(parent, SWT.SEPARATOR, index);
+		Control control = createControl(parent);
+		toolitem.setControl(control);
+	}
+
+	/**
+	 * Returns the zoomManager.
+	 * 
+	 * @return ZoomManager
+	 */
+	@Override
+	public ZoomManager getZoomManager() {
+		return zoomManager;
+	}
+
+	/**
+	 * Sets the ZoomManager
+	 * 
+	 * @param zm
+	 *            The ZoomManager
+	 */
+	@Override
+	public void setZoomManager(ZoomManager zm) {
+		if(zoomManager == zm)
+			return;
+		if(zoomManager != null)
+			zoomManager.removeZoomListener(this);
+
+		zoomManager = zm;
+		refresh(true);
+
+		if(zoomManager != null)
+			zoomManager.addZoomListener(this);
+	}
+
+	/**
+	 * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(SelectionEvent)
+	 */
+	private void handleWidgetDefaultSelected(SelectionEvent event) {
+		if(zoomManager != null) {
+			if(combo.getSelectionIndex() >= 0)
+				zoomManager.setZoomAsText(combo.getItem(combo.getSelectionIndex()));
+			else
+				zoomManager.setZoomAsText(combo.getText());
+		}
+		/*
+		 * There are several cases where invoking setZoomAsText (above) will not
+		 * result in zoomChanged being fired (the method below), such as when
+		 * the user types "asdf" as the zoom level and hits enter, or when they
+		 * type in 1%, which is below the minimum limit, and the current zoom is
+		 * already at the minimum level. Hence, there is no guarantee that
+		 * refresh() will always be invoked. But we need to invoke it to clear
+		 * out the invalid text and show the current zoom level. Hence, an
+		 * (often redundant) invocation to refresh() is made below.
+		 */
+		refresh(false);
+	}
+
+	/**
+	 * @see org.eclipse.swt.events.SelectionListener#widgetSelected(SelectionEvent)
+	 */
+	private void handleWidgetSelected(SelectionEvent event) {
+		forceSetText = true;
+		handleWidgetDefaultSelected(event);
+		forceSetText = false;
+	}
+
+	/**
+	 * @see ZoomListener#zoomChanged(double)
+	 */
+	@Override
+	public void zoomChanged(double zoom) {
+		refresh(false);
+	}
+
 }
-- 
GitLab