From a8805fc001ad3c2b101a6f506f384b1009625343 Mon Sep 17 00:00:00 2001 From: Dirk Fauth Date: Mon, 29 Jul 2024 07:27:59 +0200 Subject: [PATCH] Fixes #94 - GC not reliably closed everywhere Signed-off-by: Dirk Fauth --- .../nattable/export/image/ImageExporter.java | 12 +- .../nattable/painter/cell/GraphicsUtils.java | 156 ++++++++++-------- .../nattable/resize/MaxCellBoundsHelper.java | 30 ++-- .../nattable/style/editor/ColorPicker.java | 11 +- .../nattable/ui/action/CellDragMode.java | 27 +-- .../nattable/ui/action/ColumnDragMode.java | 55 +++--- .../nattable/ui/action/RowDragMode.java | 55 +++--- 7 files changed, 188 insertions(+), 158 deletions(-) diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/export/image/ImageExporter.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/export/image/ImageExporter.java index f78bc1ac0..05368539c 100644 --- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/export/image/ImageExporter.java +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/export/image/ImageExporter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2020 Original authors and others. + * Copyright (c) 2017, 2024 Original authors and others. * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -128,13 +128,13 @@ public void exportTable(Shell shell, final Image image = new Image(shell.getDisplay(), width, height); GC gc = new GC(image); - Rectangle layerBounds = new Rectangle(0, 0, width, height); - layer.getLayerPainter().paintLayer(layer, gc, 0, 0, layerBounds, configRegistry); + try { + Rectangle layerBounds = new Rectangle(0, 0, width, height); + layer.getLayerPainter().paintLayer(layer, gc, 0, 0, layerBounds, configRegistry); - ImageLoader imageLoader = new ImageLoader(); - imageLoader.data = new ImageData[] { image.getImageData() }; + ImageLoader imageLoader = new ImageLoader(); + imageLoader.data = new ImageData[] { image.getImageData() }; - try { if (this.outputStreamProvider instanceof FileOutputStreamProvider) { final FileOutputStreamProvider fileOutputStreamProvider = (FileOutputStreamProvider) this.outputStreamProvider; final String selectedFilterExt = DEFAULT_FILTER_EXTENSIONS[fileOutputStreamProvider.getExtensionFilterIndex()]; diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/painter/cell/GraphicsUtils.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/painter/cell/GraphicsUtils.java index 95f7c60ea..a118b2836 100644 --- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/painter/cell/GraphicsUtils.java +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/painter/cell/GraphicsUtils.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2020 Original authors and others. + * Copyright (c) 2012, 2024 Original authors and others. * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -117,52 +117,57 @@ public static void drawVerticalText(String string, int x, int y, // Create a GC so we can draw the image GC stringGc = new GC(stringImage); - // Set attributes from the original GC to the new GC - stringGc.setAntialias(gc.getAntialias()); - stringGc.setTextAntialias(gc.getTextAntialias()); - stringGc.setForeground(gc.getForeground()); - stringGc.setBackground(gc.getBackground()); - stringGc.setFont(gc.getFont()); - - // Fill the image with the specified background color - // to avoid white spaces if the text does not fill the - // whole image (e.g. on new lines) - stringGc.fillRectangle(0, 0, pt.x, pt.y); - - // Draw the text onto the image - stringGc.drawText(string, 0, 0); - - // draw underline and/or strikethrough - if (underline || strikethrough) { - // check and draw underline and strikethrough separately so it is - // possible to combine both - if (underline) { - // y = start y of text + font height - // - half of the font descent so the underline is between the - // baseline and the bottom - int underlineY = pt.y - - (stringGc.getFontMetrics().getDescent() / 2); - stringGc.drawLine(0, underlineY, pt.x, underlineY); - } + try { + // Set attributes from the original GC to the new GC + stringGc.setAntialias(gc.getAntialias()); + stringGc.setTextAntialias(gc.getTextAntialias()); + stringGc.setForeground(gc.getForeground()); + stringGc.setBackground(gc.getBackground()); + stringGc.setFont(gc.getFont()); + + // Fill the image with the specified background color + // to avoid white spaces if the text does not fill the + // whole image (e.g. on new lines) + stringGc.fillRectangle(0, 0, pt.x, pt.y); + + // Draw the text onto the image + stringGc.drawText(string, 0, 0); + + // draw underline and/or strikethrough + if (underline || strikethrough) { + // check and draw underline and strikethrough separately so it + // is + // possible to combine both + if (underline) { + // y = start y of text + font height + // - half of the font descent so the underline is between + // the + // baseline and the bottom + int underlineY = pt.y + - (stringGc.getFontMetrics().getDescent() / 2); + stringGc.drawLine(0, underlineY, pt.x, underlineY); + } - if (strikethrough) { - // y = start y of text + half of font height + ascent so lower - // case characters are - // also strikethrough - int strikeY = (pt.y / 2) - + (stringGc.getFontMetrics().getLeading() / 2); - stringGc.drawLine(0, strikeY, pt.x, strikeY); + if (strikethrough) { + // y = start y of text + half of font height + ascent so + // lower + // case characters are + // also strikethrough + int strikeY = (pt.y / 2) + + (stringGc.getFontMetrics().getLeading() / 2); + stringGc.drawLine(0, strikeY, pt.x, strikeY); + } } - } - - // Draw the image vertically onto the original GC - drawVerticalImage(stringImage, x, y, paintBackground, gc, style); - // Dispose the new GC - stringGc.dispose(); + // Draw the image vertically onto the original GC + drawVerticalImage(stringImage, x, y, paintBackground, gc, style); + } finally { + // Dispose the new GC + stringGc.dispose(); - // Dispose the image - stringImage.dispose(); + // Dispose the image + stringImage.dispose(); + } } /** @@ -296,36 +301,41 @@ public static Image createRotatedText(String text, Font font, // Create a GC to calculate font's dimensions GC gc = new GC(display); - gc.setFont(font); - - // Determine string's dimensions - Point pt = gc.textExtent(text); - - // Dispose that gc - gc.dispose(); - - // Create an image the same size as the string - Image stringImage = new Image(display, pt.x, pt.y); - // Create a gc for the image - gc = new GC(stringImage); - gc.setFont(font); - gc.setForeground(foreground); - gc.setBackground(background); - - // Draw the text onto the image - gc.drawText(text, 0, 0); - - // Draw the image vertically onto the original GC - Image image = createRotatedImage(stringImage, style); - - // Dispose the new GC - gc.dispose(); - - // Dispose the horizontal image - stringImage.dispose(); - - // Return the rotated image - return image; + Image stringImage = null; + try { + gc.setFont(font); + + // Determine string's dimensions + Point pt = gc.textExtent(text); + + // Dispose that gc + gc.dispose(); + + // Create an image the same size as the string + stringImage = new Image(display, pt.x, pt.y); + // Create a gc for the image + gc = new GC(stringImage); + gc.setFont(font); + gc.setForeground(foreground); + gc.setBackground(background); + + // Draw the text onto the image + gc.drawText(text, 0, 0); + + // Draw the image vertically onto the original GC + Image image = createRotatedImage(stringImage, style); + + // Return the rotated image + return image; + } finally { + // Dispose the new GC + gc.dispose(); + + // Dispose the horizontal image + if (stringImage != null) { + stringImage.dispose(); + } + } } /** diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/resize/MaxCellBoundsHelper.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/resize/MaxCellBoundsHelper.java index 04c62da62..9f42c9f4c 100644 --- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/resize/MaxCellBoundsHelper.java +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/resize/MaxCellBoundsHelper.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2020 Original authors and others. + * Copyright (c) 2012, 2024 Original authors and others. * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -60,13 +60,15 @@ public static int[] getPreferredColumnWidths( GC gc = gcFactory.createGC(); if (gc != null) { - int[] columnWidths = new int[columnPositions.length]; - for (int i = 0; i < columnPositions.length; i++) { - columnWidths[i] = getPreferredColumnWidth(layer, columnPositions[i], configRegistry, gc); + try { + int[] columnWidths = new int[columnPositions.length]; + for (int i = 0; i < columnPositions.length; i++) { + columnWidths[i] = getPreferredColumnWidth(layer, columnPositions[i], configRegistry, gc); + } + return columnWidths; + } finally { + gc.dispose(); } - gc.dispose(); - - return columnWidths; } else { return new int[0]; } @@ -154,13 +156,15 @@ public static int[] getPreferredRowHeights( GC gc = gcFactory.createGC(); if (gc != null) { - int[] rowHeights = new int[rowPositions.length]; - for (int i = 0; i < rowPositions.length; i++) { - rowHeights[i] = getPreferredRowHeight(layer, rowPositions[i], configRegistry, gc); + try { + int[] rowHeights = new int[rowPositions.length]; + for (int i = 0; i < rowPositions.length; i++) { + rowHeights[i] = getPreferredRowHeight(layer, rowPositions[i], configRegistry, gc); + } + return rowHeights; + } finally { + gc.dispose(); } - gc.dispose(); - - return rowHeights; } else { return new int[0]; } diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/style/editor/ColorPicker.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/style/editor/ColorPicker.java index c46b1a5b1..b29dd9d28 100644 --- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/style/editor/ColorPicker.java +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/style/editor/ColorPicker.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2020 Original authors and others. + * Copyright (c) 2012, 2024 Original authors and others. * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -62,9 +62,12 @@ private Image getColorImage(Color color) { Display display = Display.getCurrent(); this.image = new Image(display, new Rectangle(10, 10, 70, 20)); GC gc = new GC(this.image); - gc.setBackground(color); - gc.fillRectangle(this.image.getBounds()); - gc.dispose(); + try { + gc.setBackground(color); + gc.fillRectangle(this.image.getBounds()); + } finally { + gc.dispose(); + } return this.image; } diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/ui/action/CellDragMode.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/ui/action/CellDragMode.java index 79ee3e27e..eec686d50 100644 --- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/ui/action/CellDragMode.java +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/ui/action/CellDragMode.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2020 Original authors and others. + * Copyright (c) 2012, 2024 Original authors and others. * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -84,18 +84,21 @@ private void setCellImage(NatTable natTable) { Image image = new Image(natTable.getDisplay(), cellBounds.width, cellBounds.height); GC gc = new GC(image); - IConfigRegistry configRegistry = natTable.getConfigRegistry(); - ICellPainter cellPainter = cell.getLayer().getCellPainter(columnPosition, rowPosition, cell, configRegistry); - if (cellPainter != null) { - cellPainter.paintCell(cell, gc, new Rectangle(0, 0, cellBounds.width, cellBounds.height), configRegistry); + try { + IConfigRegistry configRegistry = natTable.getConfigRegistry(); + ICellPainter cellPainter = cell.getLayer().getCellPainter(columnPosition, rowPosition, cell, configRegistry); + if (cellPainter != null) { + cellPainter.paintCell(cell, gc, new Rectangle(0, 0, cellBounds.width, cellBounds.height), configRegistry); + } + + ImageData imageData = image.getImageData(); + imageData.alpha = 150; + + this.cellImage = new Image(natTable.getDisplay(), imageData); + } finally { + gc.dispose(); + image.dispose(); } - gc.dispose(); - - ImageData imageData = image.getImageData(); - image.dispose(); - imageData.alpha = 150; - - this.cellImage = new Image(natTable.getDisplay(), imageData); } } diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/ui/action/ColumnDragMode.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/ui/action/ColumnDragMode.java index 33f0055f6..dd6eed8ae 100644 --- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/ui/action/ColumnDragMode.java +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/ui/action/ColumnDragMode.java @@ -86,37 +86,42 @@ private void setColumnImage(NatTable natTable) { Image image = null; GC gc = null; - for (int rowPosition = 0; rowPosition < natTable.getRowCount(); rowPosition++) { - cell = natTable.getCellByPosition(columnPosition, rowPosition); - - if (cell != null) { - Rectangle cellBounds = cell.getBounds(); - this.xOffset = this.currentEvent.x - cellBounds.x; - - if (image == null && gc == null) { - image = new Image(natTable.getDisplay(), cellBounds.width, natTable.getHeight()); - gc = new GC(image); - } - - ICellPainter cellPainter = cell.getLayer().getCellPainter(columnPosition, rowPosition, cell, configRegistry); - if (cellPainter != null) { - cellPainter.paintCell(cell, gc, new Rectangle(0, y, cellBounds.width, cellBounds.height), configRegistry); - y += cellBounds.height; + try { + for (int rowPosition = 0; rowPosition < natTable.getRowCount(); rowPosition++) { + cell = natTable.getCellByPosition(columnPosition, rowPosition); + + if (cell != null) { + Rectangle cellBounds = cell.getBounds(); + this.xOffset = this.currentEvent.x - cellBounds.x; + + if (image == null && gc == null) { + image = new Image(natTable.getDisplay(), cellBounds.width, natTable.getHeight()); + gc = new GC(image); + } + + ICellPainter cellPainter = cell.getLayer().getCellPainter(columnPosition, rowPosition, cell, configRegistry); + if (cellPainter != null) { + cellPainter.paintCell(cell, gc, new Rectangle(0, y, cellBounds.width, cellBounds.height), configRegistry); + y += cellBounds.height; + } } } - } - if (gc != null) { - gc.dispose(); - } + if (image != null) { + ImageData imageData = image.getImageData(); + imageData.alpha = 150; - if (image != null) { + this.columnImage = new Image(natTable.getDisplay(), imageData); + } - ImageData imageData = image.getImageData(); - image.dispose(); - imageData.alpha = 150; + } finally { + if (gc != null) { + gc.dispose(); + } - this.columnImage = new Image(natTable.getDisplay(), imageData); + if (image != null) { + image.dispose(); + } } } diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/ui/action/RowDragMode.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/ui/action/RowDragMode.java index 3cc852064..76f850f7c 100644 --- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/ui/action/RowDragMode.java +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/ui/action/RowDragMode.java @@ -86,36 +86,41 @@ private void setRowImage(NatTable natTable) { Image image = null; GC gc = null; - for (int columnPosition = 0; columnPosition < natTable.getColumnCount(); columnPosition++) { - cell = natTable.getCellByPosition(columnPosition, rowPosition); - - if (cell != null) { - Rectangle cellBounds = cell.getBounds(); - this.yOffset = this.currentEvent.y - cellBounds.y; - - if (image == null && gc == null) { - image = new Image(natTable.getDisplay(), natTable.getWidth(), cellBounds.height); - gc = new GC(image); - } - - ICellPainter cellPainter = cell.getLayer().getCellPainter(columnPosition, rowPosition, cell, configRegistry); - if (cellPainter != null) { - cellPainter.paintCell(cell, gc, new Rectangle(x, 0, cellBounds.width, cellBounds.height), configRegistry); - x += cellBounds.width; + try { + for (int columnPosition = 0; columnPosition < natTable.getColumnCount(); columnPosition++) { + cell = natTable.getCellByPosition(columnPosition, rowPosition); + + if (cell != null) { + Rectangle cellBounds = cell.getBounds(); + this.yOffset = this.currentEvent.y - cellBounds.y; + + if (image == null && gc == null) { + image = new Image(natTable.getDisplay(), natTable.getWidth(), cellBounds.height); + gc = new GC(image); + } + + ICellPainter cellPainter = cell.getLayer().getCellPainter(columnPosition, rowPosition, cell, configRegistry); + if (cellPainter != null) { + cellPainter.paintCell(cell, gc, new Rectangle(x, 0, cellBounds.width, cellBounds.height), configRegistry); + x += cellBounds.width; + } } } - } - if (gc != null) { - gc.dispose(); - } + if (image != null) { + ImageData imageData = image.getImageData(); + imageData.alpha = 150; - if (image != null) { - ImageData imageData = image.getImageData(); - image.dispose(); - imageData.alpha = 150; + this.rowImage = new Image(natTable.getDisplay(), imageData); + } + } finally { + if (gc != null) { + gc.dispose(); + } - this.rowImage = new Image(natTable.getDisplay(), imageData); + if (image != null) { + image.dispose(); + } } }