From 521f51bf6ff943c868fa3374634c4b6feca12e80 Mon Sep 17 00:00:00 2001 From: Denis Fokin Date: Thu, 26 Jul 2018 18:25:00 +0300 Subject: [PATCH] An utility method to use a Graphics copy instead of the original one --- .../openapi/editor/impl/ImmediatePainter.java | 10 +++-- .../openapi/keymap/impl/ui/ActionsTree.java | 11 ++--- .../openapi/wm/impl/ToolWindowsPane.java | 43 ++++++++----------- .../src/com/intellij/ui/BalloonImpl.java | 23 +++++----- .../util/src/com/intellij/util/ui/UIUtil.java | 15 +++++++ .../impl/ui/tree/XDebuggerTreeRenderer.java | 2 + .../ui/impl/TraceTreeCellRenderer.java | 10 ++--- 7 files changed, 61 insertions(+), 53 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ImmediatePainter.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ImmediatePainter.java index ca9c7c3b8d6e..21133f0cf771 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ImmediatePainter.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ImmediatePainter.java @@ -35,6 +35,8 @@ import java.awt.image.VolatileImage; import java.util.ArrayList; import java.util.List; +import static com.intellij.util.ui.UIUtil.useSafely; + /** * @author Pavel Fatin */ @@ -194,10 +196,10 @@ class ImmediatePainter { createOrUpdateImageBuffer(myEditor.getComponent(), bounds.getSize()); - final Graphics imageGraphics = myImage.getGraphics(); - imageGraphics.translate(-bounds.x, -bounds.y); - painter.consume(imageGraphics); - imageGraphics.dispose(); + useSafely(myImage.getGraphics(), imageGraphics -> { + imageGraphics.translate(-bounds.x, -bounds.y); + painter.consume(imageGraphics); + }); graphics.drawImage(myImage, bounds.x, bounds.y, null); } diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ActionsTree.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ActionsTree.java index 7f9f693163d3..dbc41334878e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ActionsTree.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ActionsTree.java @@ -59,6 +59,8 @@ import java.lang.reflect.Method; import java.util.*; import java.util.List; +import static com.intellij.util.ui.UIUtil.useSafely; + public class ActionsTree { private static final Logger LOG = Logger.getInstance(ActionsTree.class); private static final Icon EMPTY_ICON = EmptyIcon.ICON_18; @@ -658,13 +660,8 @@ public class ActionsTree { super.doPaint(g); } - Graphics2D textGraphics = (Graphics2D)g.create(0, 0, myLinkOffset, g.getClipBounds().height); - try { - super.doPaint(textGraphics); - } - finally { - textGraphics.dispose(); - } + useSafely(g.create(0, 0, myLinkOffset, g.getClipBounds().height), + textGraphics -> super.doPaint(textGraphics)); g.translate(myLinkOffset, 0); myLink.setHeight(getHeight()); myLink.doPaint(g); diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowsPane.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowsPane.java index d3b63e6c6d40..1c4354c533dd 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowsPane.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowsPane.java @@ -32,6 +32,8 @@ import java.lang.ref.Reference; import java.util.*; import java.util.List; +import static com.intellij.util.ui.UIUtil.useSafely; + /** * This panel contains all tool stripes and JLayeredPanle at the center area. All tool windows are * located inside this layered pane. @@ -875,32 +877,26 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi if (!myDirtyMode && UISettings.getInstance().getAnimateWindows() && !RemoteDesktopService.isRemoteSession()) { // Prepare top image. This image is scrolling over bottom image. final Image topImage = myLayeredPane.getTopImage(); - final Graphics topGraphics = topImage.getGraphics(); - Rectangle bounds; + Rectangle bounds = myComponent.getBounds(); - try { + useSafely(topImage.getGraphics(), topGraphics -> { myLayeredPane.add(myComponent, JLayeredPane.PALETTE_LAYER); myLayeredPane.moveToFront(myComponent); myLayeredPane.setBoundsInPaletteLayer(myComponent, myInfo.getAnchor(), myInfo.getWeight()); - bounds = myComponent.getBounds(); myComponent.paint(topGraphics); myLayeredPane.remove(myComponent); - } - finally { - topGraphics.dispose(); - } + }); + // Prepare bottom image. final Image bottomImage = myLayeredPane.getBottomImage(); - final Graphics bottomGraphics = bottomImage.getGraphics(); - try { + + useSafely(bottomImage.getGraphics(), bottomGraphics -> { bottomGraphics.setClip(0, 0, bounds.width, bounds.height); bottomGraphics.translate(-bounds.x, -bounds.y); myLayeredPane.paint(bottomGraphics); - } - finally { - bottomGraphics.dispose(); - } + }); + // Start animation. final Surface surface = new Surface(topImage, bottomImage, 1, myInfo.getAnchor(), UISettings.ANIMATION_DURATION); myLayeredPane.add(surface, JLayeredPane.PALETTE_LAYER); @@ -1094,26 +1090,21 @@ public final class ToolWindowsPane extends JBLayeredPane implements UISettingsLi // Prepare top image. This image is scrolling over bottom image. It contains // picture of component is being removed. final Image topImage = myLayeredPane.getTopImage(); - final Graphics topGraphics = topImage.getGraphics(); - try { + useSafely(topImage.getGraphics(), topGraphics -> { myComponent.paint(topGraphics); - } - finally { - topGraphics.dispose(); - } + }); + // Prepare bottom image. This image contains picture of component that is located // under the component to is being removed. final Image bottomImage = myLayeredPane.getBottomImage(); - final Graphics bottomGraphics = bottomImage.getGraphics(); - try { + + useSafely(bottomImage.getGraphics(), bottomGraphics -> { myLayeredPane.remove(myComponent); bottomGraphics.clipRect(0, 0, bounds.width, bounds.height); bottomGraphics.translate(-bounds.x, -bounds.y); myLayeredPane.paint(bottomGraphics); - } - finally { - bottomGraphics.dispose(); - } + }); + // Remove component from the layered pane and start animation. final Surface surface = new Surface(topImage, bottomImage, -1, myInfo.getAnchor(), UISettings.ANIMATION_DURATION); myLayeredPane.add(surface, JLayeredPane.PALETTE_LAYER); diff --git a/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java b/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java index 545022982247..c5b95e86984f 100644 --- a/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java @@ -51,6 +51,8 @@ import java.util.List; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; +import static com.intellij.util.ui.UIUtil.useSafely; + public class BalloonImpl implements Balloon, IdeTooltip.Ui { /** * This key is supposed to be used as client property of content component (with value Boolean.TRUE) to suppress shadow painting @@ -1698,13 +1700,14 @@ public class BalloonImpl implements Balloon, IdeTooltip.Ui { @SuppressWarnings("UndesirableClassUsage") BufferedImage image = UIUtil.createImage(g, getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);//new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB); - Graphics2D imageGraphics = image.createGraphics(); - //noinspection UseJBColor - imageGraphics.setColor(new Color(myFillColor.getRGB())); // create a copy to remove alpha - imageGraphics.fillRect(0, 0, getWidth(), getHeight()); + useSafely(image.createGraphics(), imageGraphics -> { + //noinspection UseJBColor + imageGraphics.setColor(new Color(myFillColor.getRGB())); // create a copy to remove alpha + imageGraphics.fillRect(0, 0, getWidth(), getHeight()); + + super.paintChildren(imageGraphics); + }); - super.paintChildren(imageGraphics); - imageGraphics.dispose(); Graphics2D g2d = (Graphics2D)g.create(); try { if (UIUtil.isJreHiDPI(g2d)) { @@ -1807,10 +1810,10 @@ public class BalloonImpl implements Balloon, IdeTooltip.Ui { if (myImage != null) return; myImage = UIUtil.createImage(myComp, getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB); - Graphics2D imageGraphics = (Graphics2D)myImage.getGraphics(); - myBalloon.myPosition.paintComponent(myBalloon, shapeBounds, imageGraphics, pointTarget); - paintChildrenImpl(imageGraphics); - imageGraphics.dispose(); + useSafely(myImage.getGraphics(), imageGraphics -> { + myBalloon.myPosition.paintComponent(myBalloon, shapeBounds, imageGraphics, pointTarget); + paintChildrenImpl(imageGraphics); + }); } diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java index 09df5a91a024..76a15ff67249 100644 --- a/platform/util/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/src/com/intellij/util/ui/UIUtil.java @@ -4590,4 +4590,19 @@ public class UIUtil { public static boolean isRetina(@NotNull GraphicsDevice device) { return UIUtil.DetectRetinaKit.isOracleMacRetinaDevice(device); } + + /** Employs a common pattern to use {@code Graphics}. This is a non-distractive approach + * all modifications on {@code Graphics} are metter only inside the {@code Consumer} block + * + * @param originGraphics graphics to work with + * @param drawingConsumer you can use the Graphics2D object here safely + */ + public static void useSafely(Graphics originGraphics, Consumer drawingConsumer) { + Graphics2D graphics = ((Graphics2D)originGraphics.create()); + try { + drawingConsumer.consume(graphics); + } finally { + graphics.dispose(); + } + } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/XDebuggerTreeRenderer.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/XDebuggerTreeRenderer.java index 00cf16076596..6aeb4aa6dc8f 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/XDebuggerTreeRenderer.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/XDebuggerTreeRenderer.java @@ -24,6 +24,8 @@ import java.awt.*; import java.awt.event.MouseEvent; import java.lang.reflect.Method; +import static com.intellij.util.ui.UIUtil.useSafely; + /** * @author nik */ diff --git a/plugins/stream-debugger/src/com/intellij/debugger/streams/ui/impl/TraceTreeCellRenderer.java b/plugins/stream-debugger/src/com/intellij/debugger/streams/ui/impl/TraceTreeCellRenderer.java index 55b8dfa74a6d..d9426b71a0b7 100644 --- a/plugins/stream-debugger/src/com/intellij/debugger/streams/ui/impl/TraceTreeCellRenderer.java +++ b/plugins/stream-debugger/src/com/intellij/debugger/streams/ui/impl/TraceTreeCellRenderer.java @@ -25,6 +25,8 @@ import java.awt.*; import java.awt.event.MouseEvent; import java.lang.reflect.Method; +import static com.intellij.util.ui.UIUtil.useSafely; + /** * @author Vitaliy.Bibaev */ @@ -129,13 +131,9 @@ public class TraceTreeCellRenderer extends ColoredTreeCellRenderer { @Override protected void doPaint(Graphics2D g) { if (myHaveLink) { - Graphics2D textGraphics = (Graphics2D)g.create(0, 0, myLinkOffset, g.getClipBounds().height); - try { + useSafely(g.create(0, 0, myLinkOffset, g.getClipBounds().height), textGraphics -> { super.doPaint(textGraphics); - } - finally { - textGraphics.dispose(); - } + }); g.translate(myLinkOffset, 0); myLink.setHeight(getHeight()); myLink.doPaint(g);