implemented Destructible for subscription-handling in components
This commit is contained in:
parent
6fff359ab1
commit
a6e4bb3f13
40
src/main/java/de/ph87/kindermalen/Destructible.java
Normal file
40
src/main/java/de/ph87/kindermalen/Destructible.java
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
}
|
||||
|
||||
@ -1,29 +1,31 @@
|
||||
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) {
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user