Bug 538878: Update and adapt to Eclipse 2018-09

  - Fix and update ExpandableRowComposite (Eclipse 4.7)

Change-Id: I1ea9860d1d670fa60ada7f1956b911f6a6246d04
diff --git a/r/_build/org.eclipse.statet.r-feature/feature.xml b/r/_build/org.eclipse.statet.r-feature/feature.xml
index 84b9898..6ab035b 100644
--- a/r/_build/org.eclipse.statet.r-feature/feature.xml
+++ b/r/_build/org.eclipse.statet.r-feature/feature.xml
@@ -20,7 +20,7 @@
    </license>
 
    <requires>
-      <import feature="org.eclipse.jdt" version="3.8.0" match="greaterOrEqual" />
+      <import feature="org.eclipse.jdt" version="3.15.0" match="greaterOrEqual" />
       
       <import feature="org.eclipse.statet.rj.core" version="3.0.0" match="equivalent" />
       <import feature="org.eclipse.statet.rj.eclient.core" version="3.0.0" match="equivalent" />
diff --git a/r/org.eclipse.statet.ide.core/META-INF/MANIFEST.MF b/r/org.eclipse.statet.ide.core/META-INF/MANIFEST.MF
index 769270a..1324ad3 100644
--- a/r/org.eclipse.statet.ide.core/META-INF/MANIFEST.MF
+++ b/r/org.eclipse.statet.ide.core/META-INF/MANIFEST.MF
@@ -8,7 +8,7 @@
 Bundle-Activator: org.eclipse.statet.internal.ide.core.BaseCorePlugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Require-Bundle: org.eclipse.statet.ecommons.runtime.core;bundle-version="4.0.0";visibility:=reexport,
- org.eclipse.core.runtime;bundle-version="3.12.0";visibility:=reexport,
+ org.eclipse.core.runtime;bundle-version="3.15.0";visibility:=reexport,
  org.eclipse.statet.ecommons.preferences.core;bundle-version="4.0.0",
  org.eclipse.core.resources;visibility:=reexport,
  org.eclipse.core.filesystem;visibility:=reexport,
diff --git a/r/org.eclipse.statet.nico.core/META-INF/MANIFEST.MF b/r/org.eclipse.statet.nico.core/META-INF/MANIFEST.MF
index 370272c..7e7475c 100644
--- a/r/org.eclipse.statet.nico.core/META-INF/MANIFEST.MF
+++ b/r/org.eclipse.statet.nico.core/META-INF/MANIFEST.MF
@@ -8,7 +8,7 @@
 Bundle-Activator: org.eclipse.statet.internal.nico.core.NicoCorePlugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Require-Bundle: org.eclipse.statet.ecommons.runtime.core;bundle-version="4.0.0";visibility:=reexport,
- org.eclipse.core.runtime;bundle-version="3.11.0";visibility:=reexport,
+ org.eclipse.core.runtime;bundle-version="3.15.0";visibility:=reexport,
  org.eclipse.statet.ecommons.preferences.core;bundle-version="1.0.0",
  org.eclipse.core.expressions,
  org.eclipse.core.filesystem;visibility:=reexport,
diff --git a/r/org.eclipse.statet.r.debug.core/META-INF/MANIFEST.MF b/r/org.eclipse.statet.r.debug.core/META-INF/MANIFEST.MF
index 00a66ff..7b72f95 100644
--- a/r/org.eclipse.statet.r.debug.core/META-INF/MANIFEST.MF
+++ b/r/org.eclipse.statet.r.debug.core/META-INF/MANIFEST.MF
@@ -8,7 +8,7 @@
 Bundle-Activator: org.eclipse.statet.internal.r.debug.core.RDebugCorePlugin
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Require-Bundle: org.eclipse.core.runtime;bundle-version="3.11.0",
+Require-Bundle: org.eclipse.core.runtime;bundle-version="3.15.0",
  org.eclipse.debug.core,
  org.eclipse.statet.ltk.core,
  org.eclipse.statet.ide.core;bundle-version="[4.0.0,4.1.0)",
diff --git a/r/org.eclipse.statet.r.debug.ui/META-INF/MANIFEST.MF b/r/org.eclipse.statet.r.debug.ui/META-INF/MANIFEST.MF
index d3c340d..3286711 100644
--- a/r/org.eclipse.statet.r.debug.ui/META-INF/MANIFEST.MF
+++ b/r/org.eclipse.statet.r.debug.ui/META-INF/MANIFEST.MF
@@ -8,7 +8,7 @@
 Bundle-Activator: org.eclipse.statet.internal.r.debug.ui.RDebugUIPlugin
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Require-Bundle: org.eclipse.core.runtime;bundle-version="3.11.0",
+Require-Bundle: org.eclipse.core.runtime;bundle-version="3.15.0",
  org.eclipse.jface.text,
  org.eclipse.ui.ide,
  org.eclipse.statet.ltk.ui;bundle-version="[4.0.0,4.1.0)",
diff --git a/r/org.eclipse.statet.r.ui/src/org/eclipse/statet/internal/r/ui/datafilterview/ExpandableRowComposite.java b/r/org.eclipse.statet.r.ui/src/org/eclipse/statet/internal/r/ui/datafilterview/ExpandableRowComposite.java
index eb253e8..33666a0 100644
--- a/r/org.eclipse.statet.r.ui/src/org/eclipse/statet/internal/r/ui/datafilterview/ExpandableRowComposite.java
+++ b/r/org.eclipse.statet.r.ui/src/org/eclipse/statet/internal/r/ui/datafilterview/ExpandableRowComposite.java
@@ -17,11 +17,16 @@
  #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
  #=============================================================================*/
 
+// org.eclipse.ui.forms.widgets.ExpandableComposite
+// a2318aea7aeb731a6b1cadf0e85dd1e1287f4dd1
+//     removed textClient
+//     without changed layout for wrapping controls (2016-2017)
+
 package org.eclipse.statet.internal.r.ui.datafilterview;
 
 import org.eclipse.core.runtime.Assert;
-import org.eclipse.core.runtime.ListenerList;
 import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.action.LegacyActionTools;
 import org.eclipse.osgi.service.environment.Constants;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.FocusEvent;
@@ -29,7 +34,6 @@
 import org.eclipse.swt.events.KeyAdapter;
 import org.eclipse.swt.events.KeyEvent;
 import org.eclipse.swt.events.PaintEvent;
-import org.eclipse.swt.events.PaintListener;
 import org.eclipse.swt.events.TraverseEvent;
 import org.eclipse.swt.events.TraverseListener;
 import org.eclipse.swt.graphics.Color;
@@ -49,16 +53,21 @@
 import org.eclipse.swt.widgets.Layout;
 import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.Shell;
 import org.eclipse.ui.forms.events.ExpansionEvent;
 import org.eclipse.ui.forms.events.HyperlinkAdapter;
 import org.eclipse.ui.forms.events.HyperlinkEvent;
 import org.eclipse.ui.forms.events.IExpansionListener;
+import org.eclipse.ui.forms.widgets.FormToolkit;
 import org.eclipse.ui.forms.widgets.Hyperlink;
 import org.eclipse.ui.forms.widgets.ILayoutExtension;
 import org.eclipse.ui.forms.widgets.Section;
+import org.eclipse.ui.forms.widgets.SharedScrolledComposite;
 import org.eclipse.ui.forms.widgets.SizeCache;
 import org.eclipse.ui.forms.widgets.Twistie;
-import org.eclipse.ui.internal.forms.widgets.FormUtil;
+
+import org.eclipse.statet.jcommons.collections.CopyOnWriteIdentityListSet;
+import org.eclipse.statet.jcommons.collections.ImIdentityList;
 
 import org.eclipse.statet.ecommons.ui.SharedUIResources;
 
@@ -67,7 +76,7 @@
  * This composite is capable of expanding or collapsing a single client that is
  * its direct child. The composite renders an expansion toggle affordance
  * (according to the chosen style), and a title that also acts as a hyperlink
- * (can be selected and is traversable). The client is layed out below the title
+ * (can be selected and is traversable). The client is laid out below the title
  * when expanded, or hidden when collapsed.
  * <p>
  * The widget can be instantiated as-is, or subclassed to modify some aspects of
@@ -80,12 +89,11 @@
  * 
  * <p>
  * While expandable composite recognize that different styles can be used to
- * render the title bar, and even defines the constants for these styles (<code>TITLE_BAR</code>
- * and <code>SHORT_TITLE_BAR</code> the actual painting is done in the
- * subclasses.
+ * render the title bar, and even defines the constants for these styles
+ * (<code>TITLE_BAR</code> and <code>SHORT_TITLE_BAR</code>) the actual painting
+ * is done in the subclasses.
  * 
  * @see Section
- * @since 3.0
  */
 public class ExpandableRowComposite extends Canvas {
 	
@@ -140,7 +148,7 @@
 	/**
 	 * If this style is used, computed size of the composite will take the
 	 * client width into consideration only in the expanded state. Otherwise,
-	 * client width will always be taken into acount.
+	 * client width will always be taken into account.
 	 */
 	public static final int COMPACT= 1 << 5;
 	
@@ -159,7 +167,7 @@
 	
 	/**
 	 * If this style is used, a short version of the title bar decoration will
-	 * be painted behind the text. This style is useful when a more descrete
+	 * be painted behind the text. This style is useful when a more discrete
 	 * option is needed for the title bar.
 	 * 
 	 * @since 3.1
@@ -242,11 +250,9 @@
 	
 	private Label imageLabel;
 	
-	private Control textClient;
-	
 	private Control client;
 	
-	private final ListenerList listeners= new ListenerList();
+	private final CopyOnWriteIdentityListSet<IExpansionListener> listeners= new CopyOnWriteIdentityListSet<>();
 	
 	private Color titleBarForeground;
 	
@@ -266,7 +272,6 @@
 		
 		private void initCache(final boolean shouldFlush) {
 			this.toggleCache.setControl(ExpandableRowComposite.this.toggle);
-			this.textClientCache.setControl(ExpandableRowComposite.this.textClient);
 			this.textLabelCache.setControl(ExpandableRowComposite.this.textLabel);
 			this.descriptionCache.setControl(getDescriptionControl());
 			this.clientCache.setControl(ExpandableRowComposite.this.client);
@@ -294,56 +299,34 @@
 			}
 			int x= ExpandableRowComposite.this.marginWidth + thmargin;
 			int y= ExpandableRowComposite.this.marginHeight + tvmargin;
-			Point tsize= NULL_SIZE;
-			Point tcsize= NULL_SIZE;
+			Point toggleSize= NULL_SIZE;
 			if (ExpandableRowComposite.this.toggle != null) {
-				tsize= this.toggleCache.computeSize(SWT.DEFAULT, SWT.DEFAULT);
+				toggleSize= this.toggleCache.computeSize(SWT.DEFAULT, SWT.DEFAULT);
 			}
-			Point isize= NULL_SIZE;
+			Point imageSize= NULL_SIZE;
 			if (ExpandableRowComposite.this.imageLabel != null) {
-				isize= ExpandableRowComposite.this.imageLabel.computeSize(16, 16);
+				imageSize= ExpandableRowComposite.this.imageLabel.computeSize(16, 16);
 			}
-			int twidth= clientArea.width - ExpandableRowComposite.this.marginWidth - ExpandableRowComposite.this.marginWidth - thmargin - thmargin;
-			if (tsize.x > 0) {
-				twidth-= tsize.x + IGAP;
+			int toggleWidth= clientArea.width - ExpandableRowComposite.this.marginWidth - ExpandableRowComposite.this.marginWidth - thmargin - thmargin;
+			if (toggleSize.x > 0) {
+				toggleWidth-= toggleSize.x + IGAP;
 			}
-			if (isize.x > 0) {
-				twidth-= isize.x;
+			if (imageSize.x > 0) {
+				toggleWidth-= imageSize.x;
 			}
-			if (ExpandableRowComposite.this.textClient != null) {
-				tcsize= this.textClientCache.computeSize(SWT.DEFAULT, SWT.DEFAULT);
-			}
+			
 			Point size= NULL_SIZE;
 			if (ExpandableRowComposite.this.textLabel != null) {
-				if (tcsize.x > 0 && FormUtil.isWrapControl(ExpandableRowComposite.this.textClient)) {
-					size= this.textLabelCache.computeSize(SWT.DEFAULT, SWT.DEFAULT);
-					if (twidth < size.x + IGAP + tcsize.x) {
-						twidth-= IGAP;
-						if (ExpandableRowComposite.this.textLabel instanceof Label) {
-							final GC gc= new GC(ExpandableRowComposite.this.textLabel);
-							size= FormUtil.computeWrapSize(gc, ((Label)ExpandableRowComposite.this.textLabel).getText(), Math.round(twidth*(size.x/(float)(size.x+tcsize.x))));
-							gc.dispose();
-						}
-						else {
-							size= this.textLabelCache.computeSize(Math.round(twidth*(size.x/(float)(size.x+tcsize.x))), SWT.DEFAULT);
-						}
-						tcsize= this.textClientCache.computeSize(twidth-size.x, SWT.DEFAULT);
+				size= this.textLabelCache.computeSize(toggleWidth, SWT.DEFAULT);
+				
+				if (ExpandableRowComposite.this.textLabel instanceof Label) {
+					final Point defSize= this.textLabelCache.computeSize(SWT.DEFAULT,
+							SWT.DEFAULT);
+					if (defSize.y == size.y) {
+						// One line - pick the smaller of the two widths
+						size.x= Math.min(defSize.x, size.x);
 					}
 				}
-				else {
-					if (tcsize.x > 0) {
-						twidth-= tcsize.x + IGAP;
-					}
-					size= this.textLabelCache.computeSize(twidth, SWT.DEFAULT);
-				}
-			}
-			if (ExpandableRowComposite.this.textLabel instanceof Label) {
-				final Point defSize= this.textLabelCache.computeSize(SWT.DEFAULT,
-						SWT.DEFAULT);
-				if (defSize.y == size.y) {
-					// One line - pick the smaller of the two widths
-					size.x= Math.min(defSize.x, size.x);
-				}
 			}
 			int theaderHeight;
 			{	final GC gc= new GC(ExpandableRowComposite.this);
@@ -352,38 +335,27 @@
 				theaderHeight= fm.getHeight();
 				gc.dispose();
 				
-				if (isize.y > theaderHeight) {
-					theaderHeight= isize.y;
+				if (imageSize.y > theaderHeight) {
+					theaderHeight= imageSize.y;
 				}
 			}
 			if (ExpandableRowComposite.this.toggle != null) {
-				if (ExpandableRowComposite.this.textClient != null
-						&& (ExpandableRowComposite.this.expansionStyle & LEFT_TEXT_CLIENT_ALIGNMENT) != 0) {
-					theaderHeight= Math.max(theaderHeight, tcsize.y);
-				}
-				int ty= theaderHeight / 2 - tsize.y / 2 + 1;
+				int ty= theaderHeight / 2 - toggleSize.y / 2 + 1;
 				ty= Math.max(ty, 0);
 				ty+= ExpandableRowComposite.this.marginHeight + tvmargin;
 				ExpandableRowComposite.this.toggle.setLocation(x, ty);
-				ExpandableRowComposite.this.toggle.setSize(tsize);
-				x+= tsize.x + IGAP;
+				ExpandableRowComposite.this.toggle.setSize(toggleSize);
+				x+= toggleSize.x + IGAP;
 			}
 			if (ExpandableRowComposite.this.imageLabel != null) {
-				final int iy= theaderHeight / 2 - isize.y / 2;
-				ExpandableRowComposite.this.imageLabel.setBounds(x, iy, isize.x, isize.y);
+				final int iy= theaderHeight / 2 - imageSize.y / 2;
+				ExpandableRowComposite.this.imageLabel.setBounds(x, iy, imageSize.x, imageSize.y);
 			}
 			if (ExpandableRowComposite.this.textLabel != null) {
 				int ty= theaderHeight / 2 - size.y / 2;
 				int tx= x;
 				if (ExpandableRowComposite.this.imageLabel != null) {
-					tx+= isize.x + IGAP;
-				}
-				if (ExpandableRowComposite.this.textClient != null
-						&& (ExpandableRowComposite.this.expansionStyle & LEFT_TEXT_CLIENT_ALIGNMENT) != 0) {
-					if (size.y < tcsize.y) {
-						ty= tcsize.y / 2 - size.y / 2 + ExpandableRowComposite.this.marginHeight
-								+ tvmargin;
-					}
+					tx+= imageSize.x + IGAP;
 				}
 				if (Constants.WS_GTK.equals(Platform.getWS())) {
 					size.x+= 1; // See Bug 342610
@@ -391,71 +363,49 @@
 				
 				this.textLabelCache.setBounds(tx, ty, size.x, size.y);
 			}
-			if (ExpandableRowComposite.this.textClient != null) {
-				int tcx;
-				if ((ExpandableRowComposite.this.expansionStyle & LEFT_TEXT_CLIENT_ALIGNMENT) != 0) {
-					tcx= x + size.x + IGAP;
-				} else {
-					tcx= clientArea.width - tcsize.x - ExpandableRowComposite.this.marginWidth - thmargin;
-				}
-				this.textClientCache.setBounds(tcx, y, tcsize.x, tcsize.y);
-			}
 			int tbarHeight= theaderHeight;
 			if (size.y > tbarHeight) {
 				tbarHeight= size.y;
 			}
-			if (tcsize.y > tbarHeight) {
-				tbarHeight= tcsize.y;
-			}
 			y+= tbarHeight;
 			if (hasTitleBar()) {
 				y+= tvmargin;
 			}
-			if (getSeparatorControl() != null) {
+			final Control separatorControl= getSeparatorControl();
+			if (separatorControl != null) {
 				y+= VSPACE;
-				getSeparatorControl().setBounds(ExpandableRowComposite.this.marginWidth, y,
+				separatorControl.setBounds(ExpandableRowComposite.this.marginWidth, y,
 						clientArea.width - ExpandableRowComposite.this.marginWidth - ExpandableRowComposite.this.marginWidth,
 						SEPARATOR_HEIGHT);
 				y+= SEPARATOR_HEIGHT;
-				if (ExpandableRowComposite.this.expanded) {
-					y+= VSPACE;
-				}
 			}
-			if (ExpandableRowComposite.this.expanded) {
+			if (ExpandableRowComposite.this.expanded
+					&& ExpandableRowComposite.this.client != null) {
 				int areaWidth= clientArea.width - ExpandableRowComposite.this.marginWidth - thmargin;
 				int cx= ExpandableRowComposite.this.marginWidth + thmargin;
 				if ((ExpandableRowComposite.this.expansionStyle & CLIENT_INDENT) != 0) {
 					cx= x;
 				}
 				areaWidth-= cx;
-				if (ExpandableRowComposite.this.client != null) {
-					Point dsize= null;
-					final Control desc= getDescriptionControl();
-					if (desc != null) {
-						dsize= this.descriptionCache.computeSize(areaWidth,
-								SWT.DEFAULT);
-						y+= ExpandableRowComposite.this.descriptionVerticalSpacing;
-						this.descriptionCache.setBounds(cx, y, areaWidth, dsize.y);
-						y+= dsize.y + ExpandableRowComposite.this.clientVerticalSpacing;
-					} else {
-						y+= ExpandableRowComposite.this.clientVerticalSpacing;
-						if (getSeparatorControl() != null) {
-							y-= VSPACE;
-						}
+				if (getDescriptionControl() != null) {
+					if (ExpandableRowComposite.this.expanded) {
+						y+= VSPACE;
 					}
-					final int cwidth= areaWidth;
-					final int cheight= clientArea.height - ExpandableRowComposite.this.marginHeight
-							- ExpandableRowComposite.this.marginHeight - y;
-					this.clientCache.setBounds(cx, y, cwidth, cheight);
+					final Point dsize= this.descriptionCache.computeSize(areaWidth, SWT.DEFAULT);
+					y+= ExpandableRowComposite.this.descriptionVerticalSpacing;
+					this.descriptionCache.setBounds(cx, y, areaWidth, dsize.y);
+					y+= dsize.y + ExpandableRowComposite.this.clientVerticalSpacing;
 				}
+				y+= ExpandableRowComposite.this.clientVerticalSpacing;
+				final int cwidth= areaWidth;
+				final int cheight= clientArea.height - ExpandableRowComposite.this.marginHeight -
+						ExpandableRowComposite.this.marginHeight - y;
+				this.clientCache.setBounds(cx, y, cwidth, cheight);
 			}
 			
 			ExpandableRowComposite.this.titleHeaderRegion.x= ExpandableRowComposite.this.marginWidth;
 			ExpandableRowComposite.this.titleHeaderRegion.y= ExpandableRowComposite.this.marginHeight;
 			ExpandableRowComposite.this.titleHeaderRegion.width= clientArea.width - ExpandableRowComposite.this.marginWidth - ExpandableRowComposite.this.marginWidth;
-			if (tcsize.x > 0) {
-				ExpandableRowComposite.this.titleHeaderRegion.width-= tcsize.x + IGAP;
-			}
 			ExpandableRowComposite.this.titleHeaderRegion.height= theaderHeight;
 		}
 		
@@ -465,18 +415,18 @@
 			initCache(changed);
 			
 			int width= 0, height= 0;
-			Point tsize= NULL_SIZE;
-			int twidth= 0;
+			Point toggleSize= NULL_SIZE;
+			int toggleWidth= 0;
 			if (ExpandableRowComposite.this.toggle != null) {
-				tsize= this.toggleCache.computeSize(SWT.DEFAULT, SWT.DEFAULT);
-				twidth= tsize.x + IGAP;
+				toggleSize= this.toggleCache.computeSize(SWT.DEFAULT, SWT.DEFAULT);
+				toggleWidth= toggleSize.x + IGAP;
 			}
 			int thmargin= 0;
 			int tvmargin= 0;
 			
-			Point isize= NULL_SIZE;
+			Point imageSize= NULL_SIZE;
 			if (ExpandableRowComposite.this.imageLabel != null) {
-				isize= ExpandableRowComposite.this.imageLabel.computeSize(16, 16);
+				imageSize= ExpandableRowComposite.this.imageLabel.computeSize(16, 16);
 			}
 			
 			if (hasTitleBar()) {
@@ -485,79 +435,48 @@
 			}
 			int innerwHint= wHint;
 			if (innerwHint != SWT.DEFAULT) {
-				innerwHint-= twidth + ExpandableRowComposite.this.marginWidth + ExpandableRowComposite.this.marginWidth + thmargin + thmargin;
-				if (isize.x > 0) {
-					innerwHint-= isize.x + IGAP;
+				innerwHint-= toggleWidth + ExpandableRowComposite.this.marginWidth + ExpandableRowComposite.this.marginWidth + thmargin + thmargin;
+				if (imageSize.x > 0) {
+					innerwHint-= imageSize.x + IGAP;
 				}
 			}
 			
 			int innertHint= innerwHint;
 			
-			Point tcsize= NULL_SIZE;
-			if (ExpandableRowComposite.this.textClient != null) {
-				tcsize= this.textClientCache.computeSize(SWT.DEFAULT, SWT.DEFAULT);
-			}
 			Point size= NULL_SIZE;
-			
 			if (ExpandableRowComposite.this.textLabel != null) {
-				if (tcsize.x > 0 && FormUtil.isWrapControl(ExpandableRowComposite.this.textClient)) {
-					size= this.textLabelCache.computeSize(SWT.DEFAULT, SWT.DEFAULT);
-					if (innertHint != SWT.DEFAULT && innertHint < size.x + IGAP + tcsize.x) {
-						innertHint-= IGAP;
-						if (ExpandableRowComposite.this.textLabel instanceof Label) {
-							final GC gc= new GC(ExpandableRowComposite.this.textLabel);
-							size= FormUtil.computeWrapSize(gc, ((Label)ExpandableRowComposite.this.textLabel).getText(), Math.round(innertHint*(size.x/(float)(size.x+tcsize.x))));
-							gc.dispose();
-						}
-						else {
-							size= this.textLabelCache.computeSize(Math.round(innertHint*(size.x/(float)(size.x+tcsize.x))), SWT.DEFAULT);
-						}
-						tcsize= this.textClientCache.computeSize(innertHint-size.x, SWT.DEFAULT);
+				size= this.textLabelCache.computeSize(innertHint, SWT.DEFAULT);
+				
+				if (ExpandableRowComposite.this.textLabel instanceof Label) {
+					final Point defSize= this.textLabelCache.computeSize(SWT.DEFAULT, SWT.DEFAULT);
+					if (defSize.y == size.y) {
+						// One line - pick the smaller of the two widths
+						size.x= Math.min(defSize.x, size.x);
 					}
-				} else {
-					if (innertHint != SWT.DEFAULT && tcsize.x > 0) {
-						innertHint-= IGAP + tcsize.x;
-					}
-					size= this.textLabelCache.computeSize(innertHint, SWT.DEFAULT);
-				}
-			}
-			if (ExpandableRowComposite.this.textLabel instanceof Label) {
-				final Point defSize= this.textLabelCache.computeSize(SWT.DEFAULT, SWT.DEFAULT);
-				if (defSize.y == size.y) {
-					// One line - pick the smaller of the two widths
-					size.x= Math.min(defSize.x, size.x);
 				}
 			}
 			
-			if (twidth > 0) {
-				width+= twidth;
+			if (toggleWidth > 0) {
+				width+= toggleWidth;
 			}
-			if (isize.x > 0) {
-				width+= isize.x + IGAP;
+			if (imageSize.x > 0) {
+				width+= imageSize.x + IGAP;
 			}
 			if (size.x > 0) {
 				width+= size.x;
 			}
-			if (tcsize.x > 0) {
-				width+= tcsize.x + IGAP;
+			if (toggleSize.y > height) {
+				height= toggleSize.y;
 			}
-			if (tsize.y > height) {
-				height= tsize.y;
-			}
-			if (isize.y > height) {
-				height= isize.y;
+			if (imageSize.y > height) {
+				height= imageSize.y;
 			}
 			if (size.y > height) {
 				height= size.y;
 			}
-			if (tcsize.y > height) {
-				height= tcsize.y;
-			}
-			if (getSeparatorControl() != null) {
+			final Control separatorControl= getSeparatorControl();
+			if (separatorControl != null) {
 				height+= VSPACE + SEPARATOR_HEIGHT;
-				if (ExpandableRowComposite.this.expanded && ExpandableRowComposite.this.client != null) {
-					height+= VSPACE;
-				}
 			}
 			
 			if (wHint < width && size.x > 50) {
@@ -566,46 +485,38 @@
 			
 			// if (hasTitleBar())
 			// height+= VSPACE;
-			if ((ExpandableRowComposite.this.expanded || (ExpandableRowComposite.this.expansionStyle & COMPACT) == 0) && ExpandableRowComposite.this.client != null) {
+			if ((ExpandableRowComposite.this.expanded || (ExpandableRowComposite.this.expansionStyle & COMPACT) == 0)
+					&& ExpandableRowComposite.this.client != null) {
 				int cwHint= wHint;
 				int clientIndent= 0;
 				if ((ExpandableRowComposite.this.expansionStyle & CLIENT_INDENT) != 0) {
-					clientIndent= twidth;
+					clientIndent= toggleWidth;
 				}
 				
 				if (cwHint != SWT.DEFAULT) {
 					cwHint-= ExpandableRowComposite.this.marginWidth + ExpandableRowComposite.this.marginWidth + thmargin + thmargin;
-					if ((ExpandableRowComposite.this.expansionStyle & CLIENT_INDENT) != 0) {
-						if (tcsize.x > 0) {
-							cwHint-= twidth;
-						}
-					}
 				}
-				Point dsize= null;
-				final Point csize= this.clientCache.computeSize(FormUtil.getWidthHint(cwHint, ExpandableRowComposite.this.client), SWT.DEFAULT);
+				final Point csize= this.clientCache.computeSize(cwHint, SWT.DEFAULT);
 				if (getDescriptionControl() != null) {
 					int dwHint= cwHint;
 					if (dwHint == SWT.DEFAULT) {
 						dwHint= csize.x;
 						if ((ExpandableRowComposite.this.expansionStyle & CLIENT_INDENT) != 0) {
-							dwHint-= twidth;
+							dwHint-= toggleWidth;
 						}
 					}
-					dsize= this.descriptionCache.computeSize(dwHint, SWT.DEFAULT);
-				}
-				if (dsize != null) {
+					final Point dsize= this.descriptionCache.computeSize(dwHint, SWT.DEFAULT);
 					width= Math.max(width, dsize.x + clientIndent);
 					if (ExpandableRowComposite.this.expanded) {
-						height+= ExpandableRowComposite.this.descriptionVerticalSpacing + dsize.y + ExpandableRowComposite.this.clientVerticalSpacing;
-					}
-				} else {
-					height+= ExpandableRowComposite.this.clientVerticalSpacing;
-					if (getSeparatorControl() != null) {
-						height-= VSPACE;
+						if (separatorControl != null) {
+							height+= VSPACE;
+						}
+						height+= ExpandableRowComposite.this.descriptionVerticalSpacing + dsize.y;
 					}
 				}
 				width= Math.max(width, csize.x + clientIndent);
 				if (ExpandableRowComposite.this.expanded) {
+					height+= ExpandableRowComposite.this.clientVerticalSpacing;
 					height+= csize.y;
 				}
 			}
@@ -659,12 +570,7 @@
 		}
 		super.setLayout(new ExpandableLayout());
 		if (hasTitleBar()) {
-			addPaintListener(new PaintListener() {
-				@Override
-				public void paintControl(final PaintEvent e) {
-					onPaint(e);
-				}
-			});
+			addPaintListener(this::onPaint);
 		}
 		if ((expansionStyle & TWISTIE) != 0) {
 			this.toggle= new Toggle(this, SWT.NULL);
@@ -758,7 +664,8 @@
 						if (!isVisible() || !isEnabled()) {
 							return;
 						}
-						if (FormUtil.mnemonicMatch(getText(), e.character)) {
+						if (e.character != 0
+								&& e.character == LegacyActionTools.extractMnemonic(getText())) {
 							e.doit= false;
 							if (!isFixedStyle()) {
 							    programmaticToggleState();
@@ -770,53 +677,51 @@
 			});
 		}
 		{	// Complete Title header
-			final Listener listener= new Listener() {
-				@Override
-				public void handleEvent(final Event event) {
-					int x= event.x;
-					int y= event.y;
-					if (event.widget != ExpandableRowComposite.this) {
-						final Point p= ((Control) event.widget).getLocation();
-						x+= p.x;
-						y+= p.y;
-					}
-					switch (event.type) {
-					case SWT.MouseDown:
-						if (ExpandableRowComposite.this.titleHeaderRegion.contains(x, y)) {
-							ExpandableRowComposite.this.toggle.setFocus();
+			final Listener listener=
+					(final Event event) -> {
+						int x= event.x;
+						int y= event.y;
+						if (event.widget != ExpandableRowComposite.this) {
+							final Point p= ((Control) event.widget).getLocation();
+							x+= p.x;
+							y+= p.y;
 						}
-						break;
-					case SWT.MouseUp:
-						if (ExpandableRowComposite.this.titleHeaderRegion.contains(x, y) && event.button == 1) {
-//							textLabel.setCursor(FormsResources.getBusyCursor());
-							programmaticToggleState();
-//							textLabel.setCursor(null);
-						}
-						break;
-					case SWT.MouseEnter:
-					case SWT.MouseMove:
-					case SWT.MouseExit:
-						if (ExpandableRowComposite.this.toggle.getHover()) {
-							if (!ExpandableRowComposite.this.titleHeaderRegion.contains(x, y)) {
-								ExpandableRowComposite.this.toggle.setHover(false);
-								ExpandableRowComposite.this.toggle.redraw();
-							}
-						}
-						else { // !toggle.getHover()
+						switch (event.type) {
+						case SWT.MouseDown:
 							if (ExpandableRowComposite.this.titleHeaderRegion.contains(x, y)) {
-								ExpandableRowComposite.this.toggle.setHover(true);
-								ExpandableRowComposite.this.toggle.redraw();
+								ExpandableRowComposite.this.toggle.setFocus();
 							}
+							break;
+						case SWT.MouseUp:
+							if (ExpandableRowComposite.this.titleHeaderRegion.contains(x, y) && event.button == 1) {
+	//							textLabel.setCursor(FormsResources.getBusyCursor());
+								programmaticToggleState();
+	//							textLabel.setCursor(null);
+							}
+							break;
+						case SWT.MouseEnter:
+						case SWT.MouseMove:
+						case SWT.MouseExit:
+							if (ExpandableRowComposite.this.toggle.getHover()) {
+								if (!ExpandableRowComposite.this.titleHeaderRegion.contains(x, y)) {
+									ExpandableRowComposite.this.toggle.setHover(false);
+									ExpandableRowComposite.this.toggle.redraw();
+								}
+							}
+							else { // !toggle.getHover()
+								if (ExpandableRowComposite.this.titleHeaderRegion.contains(x, y)) {
+									ExpandableRowComposite.this.toggle.setHover(true);
+									ExpandableRowComposite.this.toggle.redraw();
+								}
+							}
+							break;
+	//					case SWT.Paint:
+	//						if (toggle != null && (getExpansionStyle() & NO_TITLE_FOCUS_BOX) == 0) {
+	//							paintTitleFocus(event.gc);
+	//						}
+	//						break;
 						}
-						break;
-//					case SWT.Paint:
-//						if (toggle != null && (getExpansionStyle() & NO_TITLE_FOCUS_BOX) == 0) {
-//							paintTitleFocus(event.gc);
-//						}
-//						break;
-					}
-				}
-			};
+					};
 			addListener(SWT.MouseDown, listener);
 			addListener(SWT.MouseUp, listener);
 			addListener(SWT.MouseEnter, listener);
@@ -1035,6 +940,21 @@
 		}
 	}
 	
+	@Override
+	public void setToolTipText(final String string) {
+		super.setToolTipText(string);
+		// Also set on label, otherwise it's just on the background without text.
+		if (this.toggle != null) {
+			this.toggle.setToolTipText(string);
+		}
+		if (this.imageLabel != null) {
+			this.imageLabel.setToolTipText(string);
+		}
+		if (this.textLabel != null) {
+			this.textLabel.setToolTipText(string);
+		}
+	}
+	
 	/**
 	 * Tests the expanded state of the composite.
 	 * 
@@ -1081,7 +1001,7 @@
 			if (this.client != null) {
 				this.client.setVisible(expanded);
 			}
-			layout();
+			reflow();
 		}
 	}
 	
@@ -1099,7 +1019,7 @@
 	 * Removes the expansion listener.
 	 * 
 	 * @param listener
-	 *            the listner to remove
+	 *            the listener to remove
 	 */
 	public void removeExpansionListener(final IExpansionListener listener) {
 		this.listeners.remove(listener);
@@ -1170,56 +1090,6 @@
 	}
 	
 	/**
-	 * Returns the text client control.
-	 * 
-	 * @return Returns the text client control if specified, or
-	 *         <code>null</code> if not.
-	 */
-	public Control getTextClient() {
-		return this.textClient;
-	}
-	
-	/**
-	 * Sets the text client control. Text client is a control that is a child of
-	 * the expandable composite and is placed to the right of the text. It can
-	 * be used to place small image hyperlinks. If more than one control is
-	 * needed, use Composite to hold them. Care should be taken that the height
-	 * of the control is comparable to the height of the text.
-	 * 
-	 * @param textClient
-	 *            the textClient to set or <code>null</code> if not needed any
-	 *            more.
-	 */
-	public void setTextClient(final Control textClient) {
-		if (this.textClient != null) {
-			this.textClient.dispose();
-		}
-		this.textClient= textClient;
-	}
-	
-	/**
-	 * Returns the difference in height between the text and the text client (if
-	 * set). This difference can cause vertical alignment problems when two
-	 * expandable composites are placed side by side, one with and one without
-	 * the text client. Use this method obtain the value to add to either
-	 * <code>descriptionVerticalSpacing</code> (if you have description) or
-	 * <code>clientVerticalSpacing</code> to correct the alignment of the
-	 * expandable without the text client.
-	 * 
-	 * @return the difference in height between the text and the text client or
-	 *         0 if no corrective action is needed.
-	 * @since 3.3
-	 */
-	public int getTextClientHeightDifference() {
-		if (this.textClient == null || this.textLabel == null) {
-			return 0;
-		}
-		final int theight= this.textLabel.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
-		final int tcheight= this.textClient.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
-		return Math.max(tcheight - theight, 0);
-	}
-	
-	/**
 	 * Tests if this expandable composite renders a title bar around the text.
 	 * 
 	 * @return <code>true</code> for <code>TITLE_BAR</code> or
@@ -1238,9 +1108,7 @@
 	 *            the title bar foreground
 	 */
 	public void setTitleBarForeground(final Color color) {
-		if (hasTitleBar()) {
-			this.titleBarForeground= color;
-		}
+		this.titleBarForeground= color;
 		if (this.textLabel != null) {
 			this.textLabel.setForeground(color);
 		}
@@ -1263,19 +1131,17 @@
 		internalSetExpanded(newState);
 		fireExpanding(newState, false);
 		if (newState) {
-			FormUtil.ensureVisible(this);
+			FormToolkit.ensureVisible(this);
 		}
 	}
 	
 	private void fireExpanding(final boolean state, final boolean before) {
-		final int size= this.listeners.size();
-		if (size == 0) {
+		final ImIdentityList<IExpansionListener> listenerList= this.listeners.toList();
+		if (listenerList.isEmpty()) {
 			return;
 		}
 		final ExpansionEvent e= new ExpansionEvent(this, state);
-		final Object [] listenerList= this.listeners.getListeners();
-		for (int i= 0; i < size; i++) {
-			final IExpansionListener listener= (IExpansionListener) listenerList[i];
+		for (final IExpansionListener listener : listenerList) {
 			if (before) {
 				listener.expansionStateChanging(e);
 			}
@@ -1329,6 +1195,41 @@
 		}
 	}
 	
+	void reflow() {
+		Composite c = this;
+		while (c != null) {
+			c.setRedraw(false);
+			c = c.getParent();
+			if (c instanceof SharedScrolledComposite || c instanceof Shell) {
+				break;
+			}
+		}
+		try {
+			c = this;
+			while (c != null) {
+				c.requestLayout();
+				c = c.getParent();
+				if (c instanceof SharedScrolledComposite) {
+					((SharedScrolledComposite) c).reflow(true);
+					break;
+				}
+				if (c instanceof Shell) {
+					break;
+				}
+			}
+		}
+		finally {
+			c = this;
+			while (c != null) {
+				c.setRedraw(true);
+				c = c.getParent();
+				if (c instanceof SharedScrolledComposite || c instanceof Shell) {
+					break;
+				}
+			}
+		}
+	}
+	
 	private void updateLabelTrim() {
 //		if (textLabel.computeSize(SWT.DEFAULT, SWT.DEFAULT).x > textLabel.getSize().x) {
 //			textLabel.setToolTipText(((Label) textLabel).getText());