Bug 574833: Fix not disposed GC in ShortedLabel Change-Id: Ibdcff18944b5aa6223add0cff86e2d58a60ca1ff
diff --git a/ecommons/org.eclipse.statet.ecommons.uimisc/src/org/eclipse/statet/ecommons/ui/components/ShortedLabel.java b/ecommons/org.eclipse.statet.ecommons.uimisc/src/org/eclipse/statet/ecommons/ui/components/ShortedLabel.java index 5d79876..e463072 100644 --- a/ecommons/org.eclipse.statet.ecommons.uimisc/src/org/eclipse/statet/ecommons/ui/components/ShortedLabel.java +++ b/ecommons/org.eclipse.statet.ecommons.uimisc/src/org/eclipse/statet/ecommons/ui/components/ShortedLabel.java
@@ -14,6 +14,8 @@ package org.eclipse.statet.ecommons.ui.components; +import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert; + import java.util.regex.Pattern; import org.eclipse.swt.SWT; @@ -24,6 +26,8 @@ import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; +import org.eclipse.statet.jcommons.lang.NonNullByDefault; + /** * Replacement for CLabel. @@ -33,20 +37,22 @@ * - Better algorithm (faster and prettier). * - Hover text. */ +@NonNullByDefault public class ShortedLabel { - private static final Pattern fLineBreakPattern = Pattern.compile("\\r[\\n]?|\\n"); //$NON-NLS-1$ + private static final Pattern LINEBREAK_PATTERN= Pattern.compile("\\r[\\n]?|\\n"); //$NON-NLS-1$ - private String fText; - private String fCheckedText; - private final Label fLabel; - private String fLineBreakReplacement = " "; //$NON-NLS-1$ + private String text; + private String checkedText; + + private final Label label; + private String lineBreakReplacement= " "; //$NON-NLS-1$ public ShortedLabel(final Composite parent, final int style) { - fLabel = new Label(parent, style); - fLabel.addListener(SWT.Resize, new Listener() { + this.label= new Label(parent, style); + this.label.addListener(SWT.Resize, new Listener() { @Override public void handleEvent(final Event event) { updateShortening(); @@ -55,7 +61,7 @@ } public Label getControl() { - return fLabel; + return this.label; } public void setText(final String label) { @@ -63,89 +69,102 @@ throw new NullPointerException(); } - if (label.equals(fText)) { + if (label.equals(this.text)) { return; } - fText = label; + this.text= label; updateChecking(); updateShortening(); } public void setLineBreakReplacement(final String s) { - assert (s != null); - - fLineBreakReplacement = s; - if (fText != null) { + this.lineBreakReplacement= nonNullAssert(s); + if (this.text != null) { updateChecking(); } } private void updateChecking() { - fCheckedText = fLineBreakPattern.matcher(fText).replaceAll(fLineBreakReplacement); + this.checkedText= LINEBREAK_PATTERN.matcher(this.text).replaceAll(this.lineBreakReplacement); } private void updateShortening() { - final String text = new Shorter(fLabel).shorten(fCheckedText); - fLabel.setText(text); - fLabel.setToolTipText((text == fCheckedText) ? null : fText); + final Shorter shorter= new Shorter(this.label); + try { + final String text= shorter.shorten(this.checkedText); + this.label.setText(text); + this.label.setToolTipText((text == this.checkedText) ? null : this.text); + } + finally { + shorter.dispose(); + } } private static class Shorter { - private static final String ELLIPSIS = " ... "; //$NON-NLS-1$ - private static final int DRAW_FLAGS = SWT.DRAW_TAB; + private static final String ELLIPSIS= " ... "; //$NON-NLS-1$ + private static final int DRAW_FLAGS= SWT.DRAW_TAB; - Control fControl; - GC fGC; - int fMaxWidth; + private final Control control; + private GC gc; + private int maxWidth; - String fText; + private String text; public Shorter(final Control control) { - fControl = control; + this.control= control; } + public void dispose() { + final var gc= this.gc; + if (gc != null) { + this.gc= null; + gc.dispose(); + } + } + + public String shorten(final String text) { if (text == null || text.isEmpty()) { return text; } - if (fGC == null) { - fGC = new GC(fControl); - fMaxWidth = fControl.getBounds().width; + if (this.gc == null) { + this.gc= new GC(this.control); + this.maxWidth= this.control.getBounds().width; } - if (fGC.textExtent(text, DRAW_FLAGS).x <= fMaxWidth) { + if (this.gc.textExtent(text, DRAW_FLAGS).x <= this.maxWidth) { return text; } - fText = text; - final String shortedText = doShorten(); - fText = null; + this.text= text; + final String shortedText= doShorten(); + this.text= null; return shortedText; } private String doShorten() { - final double avgCharWidth = fGC.getFontMetrics().getAverageCharacterWidth(); - final int textLength = fText.length(); + final double avgCharWidth= this.gc.getFontMetrics().getAverageCharacterWidth(); + final int textLength= this.text.length(); - final int ellipsisWidth = fGC.textExtent(ELLIPSIS, DRAW_FLAGS).x; + final int ellipsisWidth= this.gc.textExtent(ELLIPSIS, DRAW_FLAGS).x; - int max2 = (fMaxWidth-ellipsisWidth) * 42 / 100; + int max2= (this.maxWidth-ellipsisWidth) * 42 / 100; if (max2 < avgCharWidth * 3) { - max2 = 0; + max2= 0; } - int e = Math.max(textLength - (int)(max2 / avgCharWidth), 0); - int w2 = measurePart2(e); + int e= Math.max(textLength - (int)(max2 / avgCharWidth), 0); + int w2= measurePart2(e); while (w2 > max2 && e < textLength) { - w2 = measurePart2(e++); + w2= measurePart2(e++); } while (e > 0) { - final int test = measurePart2(e-1); + final int test= measurePart2(e-1); if (test <= max2) { e--; - w2 = test; + w2= test; continue; } else { @@ -153,17 +172,17 @@ } } - final int max1 = fMaxWidth-ellipsisWidth-w2; - int s = Math.min((int)(max2 / avgCharWidth), textLength); - int w1 = measurePart1(s); + final int max1= this.maxWidth-ellipsisWidth-w2; + int s= Math.min((int)(max2 / avgCharWidth), textLength); + int w1= measurePart1(s); while (w1 > max1 && s > 3) { - w1 = measurePart1(s--); + w1= measurePart1(s--); } while (s < textLength) { - final int test = measurePart1(s+1); + final int test= measurePart1(s + 1); if (test <= max1) { s++; - w1 = test; + w1= test; continue; } else { @@ -171,15 +190,15 @@ } } - return fText.substring(0, s)+ELLIPSIS+fText.substring(e, textLength); + return this.text.substring(0, s) + ELLIPSIS + this.text.substring(e, textLength); } private int measurePart1(final int end) { - return fGC.textExtent(fText.substring(0, end), DRAW_FLAGS).x; + return this.gc.textExtent(this.text.substring(0, end), DRAW_FLAGS).x; } private int measurePart2(final int start) { - return fGC.textExtent(fText.substring(start), DRAW_FLAGS).x; + return this.gc.textExtent(this.text.substring(start), DRAW_FLAGS).x; } }