implemented Destructible for subscription-handling in components

This commit is contained in:
Patrick Haßel 2023-02-27 08:43:06 +01:00
parent 6fff359ab1
commit a6e4bb3f13
16 changed files with 97 additions and 72 deletions

View File

@ -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<Subscription<?>> 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 <T> Subscription<T> subscribe(final Publisher<T> publisher, final Consumer<T> next) {
final Subscription<T> subscription = publisher.subscribe(next);
subscriptions.add(subscription);
return subscription;
}
protected void unsubscribe(final Subscription<?> subscription) {
if (!subscriptions.remove(subscription)) {
throw new RuntimeException();
}
subscription.unsubscribe();
}
}

View File

@ -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<Drawing> onNewDrawing(final Consumer<Drawing> next) {
return onNewDrawing.subscribe(next);
}
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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<Tool> toolSubscription = null;
private Subscription<Tool> 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) {

View File

@ -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<BufferedImage> onChange = new Publisher<>();
public Layer(final int width, final int height) {
@ -83,8 +82,4 @@ public class Layer {
onChange.publish(current);
}
public Subscription<BufferedImage> onChange(final Consumer<BufferedImage> next) {
return onChange.subscribe(next);
}
}

View File

@ -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<Tool> tools = List.of(new StampTool());
@Getter
private Tool tool;
private final Publisher<Tool> onToolSelected = new Publisher<>();
private final Publisher<Tool> 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<Tool> onToolSelected(final Consumer<Tool> next) {
return onToolSelected.subscribe(next);
onSelect.publish(tool);
}
}

View File

@ -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<Tool> 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<Tool> onChange(final Consumer<Tool> next) {
return onChange.subscribe(next);
}
}

View File

@ -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 {
}

View File

@ -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<StampImage> 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();
}

View File

@ -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) {

View File

@ -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);

View File

@ -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();
}
}

View File

@ -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<Supplier<StampImage>> 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<List<StampImage>> onListChange(final Consumer<List<StampImage>> next) {
return onListChange.subscribe(next);
}
}

View File

@ -17,11 +17,11 @@ public class Batch<T> {
private boolean stop = false;
public Batch(final List<Supplier<T>> suppliers) {
public Batch(final String name, final List<Supplier<T>> 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();
}

View File

@ -37,7 +37,9 @@ public class Publisher<T> {
private void unsubscribe(final Subscription<T> subscription) {
synchronized (subscriptions) {
subscriptions.remove(subscription);
if (!subscriptions.remove(subscription)) {
throw new RuntimeException();
}
}
}