From a6e4bb3f139c3a4a048b41df713ad13f69dd2fc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20Ha=C3=9Fel?= Date: Mon, 27 Feb 2023 08:43:06 +0100 Subject: [PATCH] implemented Destructible for subscription-handling in components --- .../de/ph87/kindermalen/Destructible.java | 40 +++++++++++++++++++ .../java/de/ph87/kindermalen/Environment.java | 7 ---- .../java/de/ph87/kindermalen/Sidebar.java | 5 ++- .../de/ph87/kindermalen/drawing/Drawing.java | 10 +++-- .../kindermalen/drawing/DrawingPanel.java | 25 ++++++------ .../de/ph87/kindermalen/drawing/Layer.java | 7 +--- .../java/de/ph87/kindermalen/tools/Tools.java | 13 ++---- .../de/ph87/kindermalen/tools/tool/Tool.java | 8 +--- .../kindermalen/tools/tool/ToolPanel.java | 5 +-- .../tools/tool/stamp/StampButtonList.java | 18 +++++---- .../tools/tool/stamp/StampImage.java | 2 +- .../tools/tool/stamp/StampOptions.java | 4 +- .../tools/tool/stamp/StampPanel.java | 9 ++++- .../tools/tool/stamp/StampTool.java | 8 +--- .../java/de/ph87/kindermalen/util/Batch.java | 4 +- .../de/ph87/kindermalen/util/Publisher.java | 4 +- 16 files changed, 97 insertions(+), 72 deletions(-) create mode 100644 src/main/java/de/ph87/kindermalen/Destructible.java diff --git a/src/main/java/de/ph87/kindermalen/Destructible.java b/src/main/java/de/ph87/kindermalen/Destructible.java new file mode 100644 index 0000000..adc3dc9 --- /dev/null +++ b/src/main/java/de/ph87/kindermalen/Destructible.java @@ -0,0 +1,40 @@ +package de.ph87.kindermalen; + +import de.ph87.kindermalen.util.Publisher; +import de.ph87.kindermalen.util.Subscription; + +import javax.swing.*; +import java.awt.*; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +public abstract class Destructible extends JPanel { + + private final List> subscriptions = new ArrayList<>(); + + public void destruct() { + subscriptions.forEach(this::unsubscribe); + synchronized (getTreeLock()) { + for (final Component component : getComponents()) { + if (component instanceof Destructible) { + ((Destructible) component).destruct(); + } + } + } + } + + protected Subscription subscribe(final Publisher publisher, final Consumer next) { + final Subscription subscription = publisher.subscribe(next); + subscriptions.add(subscription); + return subscription; + } + + protected void unsubscribe(final Subscription subscription) { + if (!subscriptions.remove(subscription)) { + throw new RuntimeException(); + } + subscription.unsubscribe(); + } + +} diff --git a/src/main/java/de/ph87/kindermalen/Environment.java b/src/main/java/de/ph87/kindermalen/Environment.java index 70ef63a..d4b0d92 100644 --- a/src/main/java/de/ph87/kindermalen/Environment.java +++ b/src/main/java/de/ph87/kindermalen/Environment.java @@ -3,11 +3,8 @@ package de.ph87.kindermalen; import de.ph87.kindermalen.drawing.Drawing; import de.ph87.kindermalen.tools.Tools; import de.ph87.kindermalen.util.Publisher; -import de.ph87.kindermalen.util.Subscription; import lombok.Getter; -import java.util.function.Consumer; - @Getter public class Environment { @@ -26,8 +23,4 @@ public class Environment { onNewDrawing.publish(drawing); } - public Subscription onNewDrawing(final Consumer next) { - return onNewDrawing.subscribe(next); - } - } diff --git a/src/main/java/de/ph87/kindermalen/Sidebar.java b/src/main/java/de/ph87/kindermalen/Sidebar.java index f0115b2..e995442 100644 --- a/src/main/java/de/ph87/kindermalen/Sidebar.java +++ b/src/main/java/de/ph87/kindermalen/Sidebar.java @@ -13,7 +13,7 @@ import java.awt.*; import static de.ph87.kindermalen.CONFIG.BORDERS; import static de.ph87.kindermalen.util.MyGridBagConstraints.C; -public class Sidebar extends JPanel { +public class Sidebar extends Destructible { private ToolPanel toolPanel = null; @@ -28,7 +28,7 @@ public class Sidebar extends JPanel { final ToolsPanel toolsPanel = new ToolsPanel(environment.getTools()); add(toolsPanel, C(0, 1, 1, 0.1)); - environment.getTools().onToolSelected(this::onToolSelected); + subscribe(environment.getTools().getOnSelect(), this::onToolSelected); } @Override @@ -42,6 +42,7 @@ public class Sidebar extends JPanel { private void onToolSelected(final Tool tool) { if (toolPanel != null) { + toolPanel.destruct(); remove(toolPanel); toolPanel = null; } diff --git a/src/main/java/de/ph87/kindermalen/drawing/Drawing.java b/src/main/java/de/ph87/kindermalen/drawing/Drawing.java index 7ab64d6..320cc39 100644 --- a/src/main/java/de/ph87/kindermalen/drawing/Drawing.java +++ b/src/main/java/de/ph87/kindermalen/drawing/Drawing.java @@ -1,6 +1,7 @@ package de.ph87.kindermalen.drawing; import lombok.Getter; +import lombok.ToString; import lombok.extern.slf4j.Slf4j; import javax.imageio.ImageIO; @@ -12,18 +13,19 @@ import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; @Slf4j +@Getter +@ToString public class Drawing { - @Getter private final int width; - @Getter private final int height; - private final Layer current; - private final ZonedDateTime created = ZonedDateTime.now(); + @ToString.Exclude + private final Layer current; + public Drawing(final int width, final int height) { this.width = width; this.height = height; diff --git a/src/main/java/de/ph87/kindermalen/drawing/DrawingPanel.java b/src/main/java/de/ph87/kindermalen/drawing/DrawingPanel.java index 2a9d8e9..e57b55c 100644 --- a/src/main/java/de/ph87/kindermalen/drawing/DrawingPanel.java +++ b/src/main/java/de/ph87/kindermalen/drawing/DrawingPanel.java @@ -1,5 +1,6 @@ package de.ph87.kindermalen.drawing; +import de.ph87.kindermalen.Destructible; import de.ph87.kindermalen.Environment; import de.ph87.kindermalen.tools.tool.Tool; import de.ph87.kindermalen.util.MouseListener; @@ -7,7 +8,6 @@ import de.ph87.kindermalen.util.Subscription; import de.ph87.kindermalen.util.Vector; import lombok.extern.slf4j.Slf4j; -import javax.swing.*; import java.awt.*; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; @@ -20,13 +20,13 @@ import java.io.File; import java.io.IOException; @Slf4j -public class DrawingPanel extends JPanel { +public class DrawingPanel extends Destructible { private static final File SAVE_DIR = new File("./data/images"); private final Environment environment; - private Subscription toolSubscription = null; + private Subscription toolChangeSubscription = null; private Vector lastPoint = null; @@ -42,14 +42,8 @@ public class DrawingPanel extends JPanel { MouseListener.onRelease(this, this::onRelease); MouseListener.onMove(this, this::onMove); MouseListener.onDrag(this, this::onDrag); - environment.getTools().onToolSelected(tool -> { - repaint(); - if (toolSubscription != null) { - toolSubscription.unsubscribe(); - } - toolSubscription = tool.onChange(ignore -> repaint()); - }); - environment.onNewDrawing(drawing -> repaint()); + subscribe(environment.getTools().getOnSelect(), this::onToolSelect); + subscribe(environment.getOnNewDrawing(), drawing -> repaint()); addComponentListener(new ComponentListener() { @Override @@ -72,6 +66,14 @@ public class DrawingPanel extends JPanel { }); } + private void onToolSelect(final Tool tool) { + repaint(); + if (toolChangeSubscription != null) { + unsubscribe(toolChangeSubscription); + } + toolChangeSubscription = subscribe(tool.getOnChange(), ignore -> repaint()); + } + private void calculateTransform() { final Image image = environment.getDrawing().getImage(); final Rectangle box = fitInside(image.getWidth(null), image.getHeight(null), getWidth(), getHeight(), false); @@ -84,7 +86,6 @@ public class DrawingPanel extends JPanel { } catch (NoninvertibleTransformException ex) { log.error(ex.toString()); } - System.out.printf("%.0f%%\n", 100.0 * scale); } private void onMove(final MouseEvent mouseEvent) { diff --git a/src/main/java/de/ph87/kindermalen/drawing/Layer.java b/src/main/java/de/ph87/kindermalen/drawing/Layer.java index ed29e4d..507d799 100644 --- a/src/main/java/de/ph87/kindermalen/drawing/Layer.java +++ b/src/main/java/de/ph87/kindermalen/drawing/Layer.java @@ -1,14 +1,12 @@ package de.ph87.kindermalen.drawing; import de.ph87.kindermalen.util.Publisher; -import de.ph87.kindermalen.util.Subscription; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.List; -import java.util.function.Consumer; import static de.ph87.kindermalen.util.ImageHelper.COPY; @@ -30,6 +28,7 @@ public class Layer { @Getter private int revision = 0; + @Getter private final Publisher onChange = new Publisher<>(); public Layer(final int width, final int height) { @@ -83,8 +82,4 @@ public class Layer { onChange.publish(current); } - public Subscription onChange(final Consumer next) { - return onChange.subscribe(next); - } - } diff --git a/src/main/java/de/ph87/kindermalen/tools/Tools.java b/src/main/java/de/ph87/kindermalen/tools/Tools.java index 552f82e..b4b67c2 100644 --- a/src/main/java/de/ph87/kindermalen/tools/Tools.java +++ b/src/main/java/de/ph87/kindermalen/tools/Tools.java @@ -3,23 +3,20 @@ package de.ph87.kindermalen.tools; import de.ph87.kindermalen.tools.tool.Tool; import de.ph87.kindermalen.tools.tool.stamp.StampTool; import de.ph87.kindermalen.util.Publisher; -import de.ph87.kindermalen.util.Subscription; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import java.util.List; -import java.util.function.Consumer; @Slf4j +@Getter public class Tools { - @Getter private final List tools = List.of(new StampTool()); - @Getter private Tool tool; - private final Publisher onToolSelected = new Publisher<>(); + private final Publisher onSelect = new Publisher<>(); public Tools() { setTool(tools.get(0)); @@ -28,11 +25,7 @@ public class Tools { public void setTool(final Tool tool) { this.tool = tool; log.info("Tool selected: {}", tool.getName()); - onToolSelected.publish(tool); - } - - public Subscription onToolSelected(final Consumer next) { - return onToolSelected.subscribe(next); + onSelect.publish(tool); } } diff --git a/src/main/java/de/ph87/kindermalen/tools/tool/Tool.java b/src/main/java/de/ph87/kindermalen/tools/tool/Tool.java index aa8e49d..1859ad4 100644 --- a/src/main/java/de/ph87/kindermalen/tools/tool/Tool.java +++ b/src/main/java/de/ph87/kindermalen/tools/tool/Tool.java @@ -2,18 +2,16 @@ package de.ph87.kindermalen.tools.tool; import de.ph87.kindermalen.drawing.Drawing; import de.ph87.kindermalen.util.Publisher; -import de.ph87.kindermalen.util.Subscription; import de.ph87.kindermalen.util.Vector; import lombok.Getter; import java.awt.image.BufferedImage; -import java.util.function.Consumer; +@Getter public abstract class Tool { protected final Publisher onChange = new Publisher<>(); - @Getter private final String name; protected Tool(final String name) { @@ -24,8 +22,4 @@ public abstract class Tool { public abstract BufferedImage getPreview(); - public Subscription onChange(final Consumer next) { - return onChange.subscribe(next); - } - } diff --git a/src/main/java/de/ph87/kindermalen/tools/tool/ToolPanel.java b/src/main/java/de/ph87/kindermalen/tools/tool/ToolPanel.java index 2e1d1b0..98d12a0 100644 --- a/src/main/java/de/ph87/kindermalen/tools/tool/ToolPanel.java +++ b/src/main/java/de/ph87/kindermalen/tools/tool/ToolPanel.java @@ -1,10 +1,9 @@ package de.ph87.kindermalen.tools.tool; +import de.ph87.kindermalen.Destructible; import lombok.extern.slf4j.Slf4j; -import javax.swing.*; - @Slf4j -public abstract class ToolPanel extends JPanel { +public abstract class ToolPanel extends Destructible { } diff --git a/src/main/java/de/ph87/kindermalen/tools/tool/stamp/StampButtonList.java b/src/main/java/de/ph87/kindermalen/tools/tool/stamp/StampButtonList.java index 3a83ea4..4216aee 100644 --- a/src/main/java/de/ph87/kindermalen/tools/tool/stamp/StampButtonList.java +++ b/src/main/java/de/ph87/kindermalen/tools/tool/stamp/StampButtonList.java @@ -1,28 +1,30 @@ package de.ph87.kindermalen.tools.tool.stamp; +import de.ph87.kindermalen.Destructible; import lombok.extern.slf4j.Slf4j; -import javax.swing.*; import java.awt.*; import java.util.Comparator; import java.util.List; @Slf4j -public class StampButtonList extends JPanel { +public class StampButtonList extends Destructible { public StampButtonList(final StampTool stampTool) { final FlowLayout flowLayout = new FlowLayout(FlowLayout.LEADING, 0, 0); setLayout(flowLayout); - stampTool.onListChange(images -> add(stampTool, images)); add(stampTool, stampTool.getImages()); - stampTool.onChange(ignore -> repaint()); + subscribe(stampTool.getOnListChange(), images -> add(stampTool, images)); + subscribe(stampTool.getOnChange(), ignore -> repaint()); } private void add(final StampTool stampTool, final List images) { - removeAll(); - for (final StampImage image : images.stream().sorted(Comparator.comparing(StampImage::getFile)).toList()) { - final StampButton button = new StampButton(stampTool, image); - add(button); + synchronized (getTreeLock()) { + removeAll(); + for (final StampImage image : images.stream().sorted(Comparator.comparing(StampImage::getFile)).toList()) { + final StampButton button = new StampButton(stampTool, image); + add(button); + } } revalidate(); } diff --git a/src/main/java/de/ph87/kindermalen/tools/tool/stamp/StampImage.java b/src/main/java/de/ph87/kindermalen/tools/tool/stamp/StampImage.java index c00c69b..7f32927 100644 --- a/src/main/java/de/ph87/kindermalen/tools/tool/stamp/StampImage.java +++ b/src/main/java/de/ph87/kindermalen/tools/tool/stamp/StampImage.java @@ -32,7 +32,7 @@ public class StampImage { this.file = file; this.original = ImageIO.read(file); getSize(STAMP_BUTTON_ICON_REAL_SIZE); - log.info("Stamp loaded: {}", this); + log.debug("Stamp loaded: {}", this); } public BufferedImage getSize(final int size) { diff --git a/src/main/java/de/ph87/kindermalen/tools/tool/stamp/StampOptions.java b/src/main/java/de/ph87/kindermalen/tools/tool/stamp/StampOptions.java index c142500..866e513 100644 --- a/src/main/java/de/ph87/kindermalen/tools/tool/stamp/StampOptions.java +++ b/src/main/java/de/ph87/kindermalen/tools/tool/stamp/StampOptions.java @@ -1,11 +1,13 @@ package de.ph87.kindermalen.tools.tool.stamp; +import de.ph87.kindermalen.Destructible; + import javax.swing.*; import java.awt.*; import static de.ph87.kindermalen.CONFIG.BORDERS; -public class StampOptions extends JPanel { +public class StampOptions extends Destructible { private final JSlider sizeSlider = new JSlider(10, 1000, 100); diff --git a/src/main/java/de/ph87/kindermalen/tools/tool/stamp/StampPanel.java b/src/main/java/de/ph87/kindermalen/tools/tool/stamp/StampPanel.java index d22e023..8ea4159 100644 --- a/src/main/java/de/ph87/kindermalen/tools/tool/stamp/StampPanel.java +++ b/src/main/java/de/ph87/kindermalen/tools/tool/stamp/StampPanel.java @@ -11,10 +11,17 @@ import static java.awt.GridBagConstraints.HORIZONTAL; @Slf4j public class StampPanel extends ToolPanel { + private final StampButtonList list; + public StampPanel(final StampTool tool) { setLayout(new GridBagLayout()); add(new StampOptions(tool), C(0, 0, 1, 0, HORIZONTAL)); - add(new StampButtonList(tool), C(0, 1, 1, 1)); + list = new StampButtonList(tool); + add(list, C(0, 1, 1, 1)); + } + + public void destruct() { + list.destruct(); } } diff --git a/src/main/java/de/ph87/kindermalen/tools/tool/stamp/StampTool.java b/src/main/java/de/ph87/kindermalen/tools/tool/stamp/StampTool.java index cf656a2..7900bc5 100644 --- a/src/main/java/de/ph87/kindermalen/tools/tool/stamp/StampTool.java +++ b/src/main/java/de/ph87/kindermalen/tools/tool/stamp/StampTool.java @@ -4,7 +4,6 @@ import de.ph87.kindermalen.drawing.Drawing; import de.ph87.kindermalen.tools.tool.Tool; import de.ph87.kindermalen.util.Batch; import de.ph87.kindermalen.util.Publisher; -import de.ph87.kindermalen.util.Subscription; import de.ph87.kindermalen.util.Vector; import lombok.Getter; import lombok.Setter; @@ -16,7 +15,6 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.function.Consumer; import java.util.function.Supplier; import java.util.stream.Stream; @@ -52,7 +50,7 @@ public class StampTool extends Tool { public StampTool() { super("Stempel"); final Stream> runnables = SCAN_FILES(STAMPS_DIR).stream().map(stamp -> () -> load(stamp)); - new Batch<>(runnables.toList()); + new Batch<>("STAMP", runnables.toList()); if (image == null && !images.isEmpty()) { setImage(images.get(0)); } @@ -107,8 +105,4 @@ public class StampTool extends Tool { return prepared; } - public Subscription> onListChange(final Consumer> next) { - return onListChange.subscribe(next); - } - } diff --git a/src/main/java/de/ph87/kindermalen/util/Batch.java b/src/main/java/de/ph87/kindermalen/util/Batch.java index 40852bb..6de87f8 100644 --- a/src/main/java/de/ph87/kindermalen/util/Batch.java +++ b/src/main/java/de/ph87/kindermalen/util/Batch.java @@ -17,11 +17,11 @@ public class Batch { private boolean stop = false; - public Batch(final List> suppliers) { + public Batch(final String name, final List> suppliers) { this.suppliers = new ArrayList<>(suppliers); synchronized (threads) { for (int i = 0; i < Runtime.getRuntime().availableProcessors(); i++) { - final Thread thread = new Thread(this::threadMain, "BATCH-%03d".formatted(i)); + final Thread thread = new Thread(this::threadMain, name + "-%03d".formatted(i)); threads.add(thread); thread.start(); } diff --git a/src/main/java/de/ph87/kindermalen/util/Publisher.java b/src/main/java/de/ph87/kindermalen/util/Publisher.java index d617282..4feae2c 100644 --- a/src/main/java/de/ph87/kindermalen/util/Publisher.java +++ b/src/main/java/de/ph87/kindermalen/util/Publisher.java @@ -37,7 +37,9 @@ public class Publisher { private void unsubscribe(final Subscription subscription) { synchronized (subscriptions) { - subscriptions.remove(subscription); + if (!subscriptions.remove(subscription)) { + throw new RuntimeException(); + } } }